Installing and Connecting GCP MCP to OpenCode
OpenCode uses a project-level opencode.json (or .opencode/config.json depending on version) for MCP server definitions, with a schema close enough to Claude Code's .mcp.json that migrating a config between the two is mostly a key-rename exercise — but not identical, and the differences matter for debugging.
{
"mcp": {
"gcp-bigquery": {
"type": "local",
"command": ["./toolbox", "--tools-file", "./tools.yaml", "--stdio"],
"environment": {
"GOOGLE_APPLICATION_CREDENTIALS": "{env:HOME}/.gcp/mcp-agent-key.json"
}
},
"gcp-run-logs": {
"type": "local",
"command": ["npx", "-y", "gcp-mcp-server", "--services", "run,logging,storage"],
"environment": {
"GOOGLE_CLOUD_PROJECT": "analytics-project-prod",
"GOOGLE_APPLICATION_CREDENTIALS": "{env:HOME}/.gcp/mcp-agent-key.json"
}
}
}
}
The type: "local" key and command as an array (rather than separate command/args fields) is the detail that trips people up copying configs from Claude Code documentation — OpenCode expects the full invocation as one array. Get this wrong and the server fails to start with a fairly unhelpful "spawn ENOENT" error that doesn't point at the actual schema mismatch.
Verify connectivity with OpenCode's /mcp equivalent — as of recent OpenCode releases this is /tools in the TUI, which lists connected servers and their exposed tool names:
opencode
/tools
If a server doesn't appear, run the exact command array manually in a terminal first — this isolates whether the failure is OpenCode's process spawning or the underlying binary/auth:
./toolbox --tools-file ./tools.yaml --stdio
Auth setup is identical to any other MCP client — ADC or a service account key, referenced via GOOGLE_APPLICATION_CREDENTIALS. OpenCode doesn't add any GCP-specific auth layer, which is a plus: one less place credentials can silently diverge from what gcloud itself uses.
gcloud auth application-default login
gcloud config set project analytics-project-prod
Tips
- Double-check whether your OpenCode version usesmcpor a nestedexperimental.mcpconfig key — this shifted between releases in 2025, and stale documentation online references the older path.
- Test the exactcommandarray outside OpenCode before assuming an MCP integration problem — most "OpenCode can't connect to GCP" issues are actually the underlying binary failing to start.
- OpenCode's environment variable interpolation syntax ({env:VAR}) differs from Claude Code's (${VAR}) — copying a.mcp.jsonenv block verbatim will silently pass a literal string instead of the resolved value.
Querying BigQuery Datasets and Listing GCS Objects from OpenCode
Once connected, the query pattern in OpenCode mirrors Claude Code's — describe the goal, let the agent inspect schema, dry-run, then execute — but OpenCode's tool-calling transcript display in the TUI is more compact by default, so it's worth explicitly asking for the dry-run numbers to be shown rather than assuming you'll see them scroll by.
Prompt example:
"Using gcp-bigquery, list the tables in the raw_events dataset,
then show me the schema for the sessions table. I want to build
a query counting sessions by device_category for the last 7 days."
-- What a correct agent-generated query looks like against that schema
SELECT
device_category,
COUNT(*) AS session_count
FROM `analytics-project-prod.raw_events.sessions`
WHERE session_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY device_category
ORDER BY session_count DESC;
Ask explicitly for the dry-run byte estimate as a separate step if OpenCode's tool doesn't surface it automatically in the response — some genai-toolbox configurations return only the query result unless dryRun: true is passed as an argument, and OpenCode's default tool-calling behavior doesn't always set that flag without a specific instruction:
Prompt example:
"Before running that query, call execute-sql with dryRun set
to true first and tell me the bytes it would scan."
GCS object listing works the same way through the gcp-run-logs server (assuming it's configured with storage scope) or a dedicated GCS MCP tool:
Prompt example:
"List objects in gs://analytics-exports/2026/08/ with prefix
'user-report-', limit 15, sorted newest first. Don't read any
object contents yet, just show me what's there."
gsutil ls -l gs://analytics-exports/2026/08/user-report-* | \
sort -k2 -r | head -15
One practical difference from Claude Code worth flagging: OpenCode's context management is more aggressive about summarizing tool results in long sessions, which means a large BigQuery result set or a long GCS listing can get compressed in ways that lose specific row values you actually wanted preserved. For anything you need exact figures from, ask the agent to write the raw result to a file rather than just report it in chat.
Prompt example:
"Run that query and write the full result set to
./scratch/session-counts-2026-08.csv instead of just
summarizing it in the response."
Tips
- Explicitly request dry-run confirmation on every BigQuery query in OpenCode — don't assume the default tool-call behavior enforces it the way a purpose-built wrapper might.
- For results you need to keep exact, ask the agent to write them to a file — OpenCode's context summarization on long sessions can lossy-compress numeric detail from chat responses.
- Cross-check a first BigQuery result againstbq queryrun manually at least once per new query pattern, until you trust the specific schema/prompt combination.
Practical Example: Debugging a Failing Cloud Run Deployment in OpenCode
Walk through a real scenario: payments-worker fails its health check after a deploy and OpenCode is being used to diagnose it end to end.
Prompt (step 1):
"List the last 3 revisions of payments-worker in us-central1 and
tell me which ones are currently receiving traffic."
gcloud run revisions list --service=payments-worker \
--region=us-central1 --format=json --limit=3
The output shows payments-worker-00112-def at 0% traffic (failed health check, GCP kept the previous revision serving) and payments-worker-00111-ghi still at 100%.
Prompt (step 2):
"Pull startup and ERROR logs for revision 00112-def only, from
the last hour."
gcloud logging read \
'resource.type="cloud_run_revision"
AND resource.labels.service_name="payments-worker"
AND resource.labels.revision_name="payments-worker-00112-def"
AND (severity>=ERROR OR textPayload:"Starting")' \
--freshness=1h --format=json --limit=50
The logs show a repeated pattern: Failed to connect to redis://10.x.x.x:6379: connection refused, and the container exiting shortly after. That's a strong lead — either the Redis instance moved, a firewall rule changed, or the VPC connector config on the new revision differs.
Prompt (step 3):
"Compare the VPC connector and network settings between revision
00111-ghi (working) and 00112-def (failing)."
gcloud run revisions describe payments-worker-00111-ghi \
--region=us-central1 --format="yaml(spec.template.metadata.annotations)" \
| grep -i vpc
gcloud run revisions describe payments-worker-00112-def \
--region=us-central1 --format="yaml(spec.template.metadata.annotations)" \
| grep -i vpc
The diff reveals the new revision's Terraform deploy dropped the run.googleapis.com/vpc-access-connector annotation — someone's config change removed the connector reference, so the new revision can no longer reach the private Redis instance inside the VPC. That's a config regression, not an application bug, and OpenCode surfaced it in three bounded tool calls instead of a half-hour manual dig through the console.
Prompt (step 4):
"That confirms it — the VPC connector annotation is missing.
Don't try to fix the Terraform, just write up a summary of the
root cause and the exact annotation that needs to be restored."
Deliberately stopping the agent at "write up a summary" rather than "fix and redeploy" here is the right call — infra config changes on a payments service warrant a human review of the actual Terraform diff, not an autonomous gcloud run services update.
Tips
- Anchor Cloud Run debugging prompts on specific revision IDs at every step — comparing "the failing one" to "the working one" by name, not by re-describing the whole service each time, keeps the investigation tight.
- When logs point to a networking issue (connection refused, timeout), pivot the next prompt to config diffing immediately — it's almost always faster than more log reading.
- Stop the agent short of applying infra fixes on production services — have it produce the diagnosis and the exact change needed, then apply it through your normal change-review process.
Known Limitations for GCP MCP in OpenCode
OpenCode is a fast-moving project and its MCP client implementation has real gaps worth knowing before you build a workflow around it.
Tool result size handling is less mature than Claude Code's. Large BigQuery result sets or verbose Cloud Run YAML dumps get truncated more aggressively, and the truncation isn't always flagged clearly in the transcript — you can end up reasoning over an incomplete result without OpenCode surfacing that it cut something off. Mitigate by asking for aggregated queries (counts, sums) rather than raw row dumps, and writing large outputs to files as shown above.
No built-in cost-guard equivalent. Some Claude Code-oriented MCP wrappers add a soft "confirm before expensive calls" layer at the client level; OpenCode as of recent versions doesn't add this — the discipline has to come entirely from your tools.yaml server-side dry-run defaults and your prompting habits, not from the client.
Multi-server tool name collisions are less gracefully handled. If you run gcp-bigquery and a second BigQuery-capable server side by side (say, testing genai-toolbox against a community alternative), OpenCode's tool namespacing occasionally produces ambiguous tool names in the model's context, and it's picked the wrong server's version of a similarly-named tool in observed sessions. Run one BigQuery-capable MCP server at a time per project config.
Session persistence across long GCP debugging sessions is inconsistent. Long investigative sessions (the Cloud Run debugging example above extended across a dozen more turns) have occasionally lost earlier tool-call context in OpenCode's session compaction, requiring you to re-paste key findings (the revision IDs, the specific error string) partway through. This is a known rough edge, not a config mistake on your part — Claude Code's session handling is currently more robust for long multi-tool investigations.
Community GCP MCP servers vary wildly in maintenance status. Unlike Claude Code's larger install base pulling more scrutiny onto popular servers, some GCP MCP servers that show up first in a search have gone unmaintained for 8+ months. Check the repo's commit history before adopting one for anything beyond a quick experiment.
Tips
- Ask for aggregated results (counts, sums, top-N) instead of raw row exports whenever a BigQuery query might return more than ~50 rows — it sidesteps OpenCode's less mature truncation handling.
- Run exactly one MCP server per cloud data source (one BigQuery server, not two) to avoid tool-name ambiguity in multi-server configs.
- For investigations spanning many turns, periodically ask OpenCode to restate the key facts gathered so far — cheap insurance against session compaction dropping earlier context.
Tips
Tips
- Validate the exactcommandarray outside OpenCode before debugging "connection failed" as an MCP problem — it's very often a spawn/path issue instead.
- Prefer aggregated BigQuery queries and file-written results over raw chat output for anything you need to trust exactly, given OpenCode's more aggressive context summarization.
- Check community GCP MCP server maintenance status (recent commits, open issue response time) before adopting one — this ecosystem has more unmaintained forks than the GitHub/GitLab MCP space.