gcp-mcp-standalone/docs/superpowers/ (specs 2026-07-06-gcp-tailscale-connectors-design.md).
Key points
- GCP (
/proxy/gcp) — 7 tools:list_instances,get_instance,get_serial_output,list_log_entries,stop_instance,start_instance,reset_instance. Credential: keyless — short-lived token from the GCE metadata server (169.254.169.254) asmcp-broker-sa. Power comes from custom rolemcpBrokerOps(view + power-cycle ONLY; no create/delete/setMetadata) +roles/logging.viewer. Project/zone pinned server-side (GCP_PROJECT/GCP_ZONEin.env), never tool params. - Tailscale (
/proxy/tailscale) — 3 tools:list_devices,get_device,expire_device_key. Credential: scoped OAuth client (devices:core read-only), client-credentials grant, short-lived tokens fetched on demand; secret in Secret Managertailscale-oauth-client-secret, restored on rebuild by Ansible. - Why read-only Tailscale: write scopes on Tailscale OAuth clients are tag-bound and
cannot touch untagged personal devices — so write bought nothing.
expire_device_keyis implemented but returns a sanitized 403 until a write-scoped credential replaces the read-only one. - Security model (two independent layers): the credential cannot exceed the custom role/scope, and the tools implement only the verbs above. Worst realistic abuse (e.g. prompt injection in a chat with broker tools): VM power-cycled, infra metadata/logs disclosed. Nothing can be created, deleted, or reconfigured.
Details
Code: BobMck/mcp-broker branch connectors, src/connectors/{gcp,tailscale}/
(15 unit tests; suite 995 green). Infra: main.tf (role + bindings, incl. the
iam.serviceAccountUser self-grant required to start a VM that runs as an SA),
ansible/install.yml (env injection, no_log), ansible/templates/settings.yaml.j2
(connector + allowed_connectors registration). Verified live 2026-07-07: instance
list, device list, and log query all succeed from inside the broker container.
Related
Sources
wiki/projects/gcp-mcp-standalone/connectors-gcp-tailscale.md · git is the source of truth