Skip to content
Merged
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ You also need `python` and `uv` installed.
| :----------------------| :----------:| :--------------------------------------------------------:| :--------------------------------------------------------:| :--------------------------------------------------------:| :--------------------------------------------------------:|
| **Type** | Extension | [Plugin](https://antigravity.google/docs/plugins) | [Plugin](https://code.claude.com/docs/en/plugins-reference) | [Plugin](https://developers.openai.com/codex/plugins) | [Plugin](https://docs.github.com/copilot/how-tos/copilot-cli/customize-copilot/plugins-creating) |
| **Install** | ✅ | ✅ | ✅ | 🟢 | ✅ |
| **MCP Setup** | ✅ | ✅ | 🟢 | 🟢 | 🔴 |
| **MCP Setup** | ✅ | ✅ | 🟢 | 🟢 | |
| **SRE Skills** | ✅ | ✅ | 🟢 | 🟢 | ✅ |
| **GKE Investigation** | ✅ | ✅ | 🟢 | 🟢 | 🟢 |

Expand Down
6 changes: 6 additions & 0 deletions skills/gcp-mcp-setup/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this skill will be documented in this file.

## [0.0.10] - 2026-07-03
### Added
- **GitHub Copilot CLI support**: `setup_onemcp.py` now accepts a `--harness {gemini,antigravity,copilot}` flag and writes the correct MCP config format and path per harness (`~/.copilot/mcp-config.json` using Copilot's `type/url/tools` wire format).
- **Harness registry**: Introduced `HARNESS_REGISTRY` in `setup_onemcp.py`. Adding a new harness only requires a new registry entry and a corresponding builder function.
- **Harness-agnostic MCP verification**: `verify_setup.py` now accepts `--harness {gemini,antigravity,copilot}` and dispatches to the correct CLI command (`gemini -p "/mcp list"`, `agy -p "/mcp list"`, or `copilot mcp list`) via a `HARNESS_MCP_LIST_CMD` registry. Also scans `~/.copilot/mcp-config.json` when checking configured servers.

## [0.0.9] - 2026-05-28
### Added
- **Antigravity CLI Support**: Added automated configuration support for the modern `agy` CLI and Antigravity Editor.
Expand Down
5 changes: 5 additions & 0 deletions skills/gcp-mcp-setup/EVAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
- Prompt: "What does "ConnectionPoolExhausted: Unable to acquire aconnection from the pool within the timeout." error mean?"
- Test: Should use MCP to search for this in the DKP knowledge base.

## Copilot CLI Setup

- Prompt: "Please install OneMCP on my project my-gcp-project using Copilot CLI"
- Test: Should run `setup_onemcp.py my-gcp-project --global --harness copilot` and write to `~/.copilot/mcp-config.json` using the `type/url/tools` format.

## Good Skill Structure

<!-- Note: this should be available on EVERY skill, so this is the wrong place.-->
Expand Down
21 changes: 10 additions & 11 deletions skills/gcp-mcp-setup/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
name: gcp-mcp-setup
description: 🐉 [SRE] Use when the user wants to set up Google Managed MCP (OneMCP) servers for their Gemini CLI environment. Automates enabling services, MCP servers, generating API keys, and configuring ~/.gemini/settings.json.
description: 🐉 [SRE] Use when the user wants to set up Google Managed MCP (OneMCP) servers for their CLI environment. Automates enabling services, MCP servers, generating API keys, and configuring the MCP settings file for the active harness (Gemini, Antigravity, or Copilot CLI).
metadata:
author: Riccardo
version: 0.0.9
version: 0.0.10
status: published
---

Expand All @@ -23,16 +23,15 @@ Use this skill when the user asks to "install OneMCP", "setup OneMCP", or "confi
2. **Setup Script Execution**: Run the provided script to enable APIs, MCP services, and generate the required API Key.
- By default, it installs a **Lean SRE toolset** (Logging, Monitoring, GKE, Run, Resource Manager, Developer Knowledge).
- Use the `--all` flag to include optional services (Error Reporting, Databases, Vertex AI).
- Script: `skills/gcp-mcp-setup/scripts/setup_onemcp.py <PROJECT_ID> [--local | --global] [--all] [--google-maps-key YOUR_KEY]`
3. **Configure Settings**: The script automatically writes the `mcpServers` configuration to the correct location depending on which harness/CLI you are running:
- **If your harness is Gemini CLI**: The configuration is injected directly into `.gemini/settings.json` (if `--local` is provided) or `~/.gemini/settings.json` (if `--global` is provided).
- **If your harness is Antigravity CLI (agy)**: The configuration is written to both `.gemini/antigravity/mcp_config.json` and `.gemini/config/mcp_config.json` (if `--local` is provided) or the global equivalents under `~/.gemini/` (if `--global` is provided).
- Use `--harness` to target a specific CLI harness (`gemini`, `antigravity`, or `copilot`). Defaults to `gemini+antigravity`.
- Script: `skills/gcp-mcp-setup/scripts/setup_onemcp.py <PROJECT_ID> [--local | --global] [--harness {gemini,antigravity,copilot}] [--all] [--google-maps-key YOUR_KEY]`
3. **Configure Settings**: The script automatically writes the `mcpServers` configuration to the correct location depending on the target harness:
- **Gemini CLI**: `.gemini/settings.json` (local) or `~/.gemini/settings.json` (global).
- **Antigravity CLI (agy)**: `.gemini/antigravity/mcp_config.json` and `.gemini/config/mcp_config.json` (local) or the global equivalents under `~/.gemini/`.
- **GitHub Copilot CLI**: `~/.copilot/mcp-config.json` (always global — no workspace-level config yet).
4. **Verification & Diagnostics:**
- Script: `skills/gcp-mcp-setup/scripts/verify_setup.py`
- This script checks the configured settings across both Gemini and Antigravity paths, and tests actual endpoint connectivity.
- For direct endpoint diagnostics, use the curl-based tool:
- Script: `skills/gcp-mcp-setup/scripts/test_mcp_endpoint.sh [ENDPOINT_URL]`
- Example: `./skills/gcp-mcp-setup/scripts/test_mcp_endpoint.sh https://monitoring.googleapis.com/mcp`
- Script: `skills/gcp-mcp-setup/scripts/verify_setup.py [--harness {gemini,antigravity,copilot}]`
- This script checks identity consistency (gcloud vs ADC), runs the harness-specific MCP list command, and confirms all expected google-* servers are registered.

## Examples

Expand Down
119 changes: 80 additions & 39 deletions skills/gcp-mcp-setup/scripts/setup_onemcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
"""
OneMCP Setup Script
This script sets the gcloud project, installs beta components, enables required services
and MCP servers.
and MCP servers.

By default, it installs a lean SRE toolset (Logging, Monitoring, GKE, Run, RM, ErrorReporting, DK).
Use --all to include databases (SQL, Spanner, Firestore, BigQuery) and Vertex AI.

Use --harness to target a specific CLI harness (gemini, antigravity, copilot).
Defaults to gemini+antigravity when omitted.

# Thanks to Romin Irani guidance: https://github.com/rominirani/google-mcp-servers/blob/main/demos/README.md
"""

Expand All @@ -34,37 +37,89 @@

def run_command(command, check=True):
print(f"Running: {' '.join(command)}")
result = subprocess.run(command, text=True, capture_output=True)
result = subprocess.run(command, text=True, capture_output=True, shell=(sys.platform == "win32"))
if check and result.returncode != 0:
print(f"Command failed with error: {result.stderr}", file=sys.stderr)
sys.exit(result.returncode)
return result

def get_gemini_mcp_format(url, *, project_id=None, api_key=None):
"""Returns an MCP server entry in the Gemini/Antigravity mcp format."""
if api_key:
return {'httpUrl': url, 'serverUrl': url, 'headers': {'X-Goog-Api-Key': api_key}}
return {
'httpUrl': url,
'serverUrl': url,
'authProviderType': 'google_credentials',
'oauth': {'scopes': ['https://www.googleapis.com/auth/cloud-platform']},
'headers': {'X-goog-user-project': project_id},
}

def get_copilot_mcp_format(url, *, project_id=None, api_key=None):
"""Returns an MCP server entry in the Copilot CLI mcp format."""
headers = {'X-Goog-Api-Key': api_key} if api_key else {'X-goog-user-project': project_id}
return {'type': 'http', 'url': url, 'headers': headers, 'tools': ['*']}

# Harness registry: defines config file paths and format builder per harness.
# Add a new entry here to support additional CLI harnesses.
HARNESS_REGISTRY = {
"gemini": {
"global": ["~/.gemini/settings.json"],
"local": [".gemini/settings.json"],
"builder": get_gemini_mcp_format,
},
"antigravity": {
"global": ["~/.gemini/antigravity/mcp_config.json", "~/.gemini/config/mcp_config.json"],
"local": [".gemini/antigravity/mcp_config.json", ".gemini/config/mcp_config.json"],
"builder": get_gemini_mcp_format,
},
"copilot": {
# Copilot CLI has no workspace-level MCP config yet; --local falls back to global.
"global": ["~/.copilot/mcp-config.json"],
"local": ["~/.copilot/mcp-config.json"],
"builder": get_copilot_mcp_format,
},
}

def main():
parser = argparse.ArgumentParser(
description="Set up Google Managed MCP (OneMCP) for Gemini CLI."
description="Set up Google Managed MCP (OneMCP) for your CLI harness."
)
parser.add_argument("project_id", help="The Google Cloud Project ID to use.")

group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--local", action="store_true", help="Update the local .gemini/settings.json file.")
group.add_argument("--global", action="store_true", dest="global_config", help="Update the global ~/.gemini/settings.json file.")

group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--local", action="store_true", help="Update the local config file (workspace-scoped).")
group.add_argument("--global", action="store_true", dest="global_config", help="Update the global config file (user-scoped).")

parser.add_argument(
"--harness",
choices=list(HARNESS_REGISTRY.keys()),
default=None,
help="Target CLI harness to configure. Defaults to gemini+antigravity (legacy behaviour).",
)
parser.add_argument("--all", action="store_true", help="Enable all supported OneMCP servers, including databases and Vertex AI.")
parser.add_argument("--google-maps-key", dest="google_maps_key", help="The Google Maps API Key to enable mapstools MCP.")

args = parser.parse_args()
project_id = args.project_id
scope = "local" if args.local else "global"

# Resolve target config files from the registry.
# No --harness = legacy behaviour: write to both gemini and antigravity paths.
if args.harness:
harnesses = [args.harness]
if args.harness == "copilot" and args.local:
print("Note: Copilot CLI has no workspace-level MCP config. Writing to global ~/.copilot/mcp-config.json.")
else:
harnesses = ["gemini", "antigravity"]

target_files = []
if args.local:
target_files.append((os.path.join(os.getcwd(), ".gemini", "settings.json"), "gemini"))
target_files.append((os.path.join(os.getcwd(), ".gemini", "antigravity", "mcp_config.json"), "antigravity"))
target_files.append((os.path.join(os.getcwd(), ".gemini", "config", "mcp_config.json"), "antigravity"))
else:
target_files.append((os.path.expanduser("~/.gemini/settings.json"), "gemini"))
target_files.append((os.path.expanduser("~/.gemini/antigravity/mcp_config.json"), "antigravity"))
target_files.append((os.path.expanduser("~/.gemini/config/mcp_config.json"), "antigravity"))
for harness in harnesses:
config = HARNESS_REGISTRY[harness]
builder = config["builder"]
for path in config[scope]:
resolved = os.path.expanduser(path) if path.startswith("~") else os.path.join(os.getcwd(), path)
target_files.append((resolved, builder))

# Core SRE Services (Default)
base_services = [
Expand Down Expand Up @@ -135,36 +190,23 @@ def main():
'bigquery.googleapis.com': ('google-bigquery', 'https://bigquery.googleapis.com/mcp'),
}

def build_mcp_servers(target_type):
def build_mcp_servers(builder):
servers = {}
for service in base_services:
if service == 'developerknowledge.googleapis.com':
cfg = {
'httpUrl': 'https://developerknowledge.googleapis.com/mcp',
'serverUrl': 'https://developerknowledge.googleapis.com/mcp',
'headers': {'X-Goog-Api-Key': dev_key}
}
servers['google-developer-knowledge'] = cfg
servers['google-developer-knowledge'] = builder(
'https://developerknowledge.googleapis.com/mcp', api_key=dev_key
)
elif service == 'mapstools.googleapis.com':
cfg = {
'httpUrl': 'https://mapstools.googleapis.com/mcp',
'serverUrl': 'https://mapstools.googleapis.com/mcp',
'headers': {'X-Goog-Api-Key': args.google_maps_key}
}
servers['google-maps'] = cfg
servers['google-maps'] = builder(
'https://mapstools.googleapis.com/mcp', api_key=args.google_maps_key
)
elif service in mcp_config_map:
key, url = mcp_config_map[service]
cfg = {
'httpUrl': url,
'serverUrl': url,
'authProviderType': 'google_credentials',
'oauth': {'scopes': ['https://www.googleapis.com/auth/cloud-platform']},
'headers': {'X-goog-user-project': project_id}
}
servers[key] = cfg
servers[key] = builder(url, project_id=project_id)
return servers

for config_file, target_type in target_files:
for config_file, builder in target_files:
print(f"Updating {config_file}...")
os.makedirs(os.path.dirname(config_file), exist_ok=True)

Expand All @@ -179,8 +221,7 @@ def build_mcp_servers(target_type):
if 'mcpServers' not in data:
data['mcpServers'] = {}

# Merge tailored servers
data['mcpServers'].update(build_mcp_servers(target_type))
data['mcpServers'].update(build_mcp_servers(builder))

with open(config_file, 'w') as f:
json.dump(data, f, indent=2)
Expand Down
Loading
Loading