Prerequisites
gcloud auth loginandgcloud auth application-default login(Terraform needs ADC).- Project
bob-mcp-project-2026, billing on, Compute + Secret Manager APIs enabled. - Service account
mcp-broker-sawithsecretAccessorontailscale-auth-keyandgithub-oauth-client-secret(created out-of-band). - Secret Manager: a valid one-time, pre-authorized, non-ephemeral Tailscale auth key
in
tailscale-auth-key(see gcp-mcp-standalone/runbooks/rotate-tailscale-key). - A Cloudflare Tunnel for
bobsmcp.uk→localhost:8002; its token saved on the Mac:printf '%s' 'TOKEN' > ~/.cf-tunnel-token && chmod 600 ~/.cf-tunnel-token(never paste the token into a chat or shell history you don't control). - Your Mac on the same Tailscale tailnet (Ansible rides it).
terraform.tfvarsholds onlygcp_project_id— no secrets.
Steps
terraform plan -out=tfplan→ review →terraform apply tfplan. Creates instance + deny-all firewall; first boot fetches the Tailscale key from Secret Manager and joins the mesh. Note: any change tometadata_startup_scriptforces VM replacement.- Confirm join: node
gcp-mcp-brokeractive in the Tailscale admin console (ortailscale statuson the Mac). If it registered asgcp-mcp-broker-1, an old machine entry existed — delete it and rename the new node. - Deploy:
ansible-playbook -i ansible/inventory.ini ansible/install.yml -e cloudflare_tunnel_token="$(cat ~/.cf-tunnel-token)"Secret-bearing tasks areno_log; do not run with-von a shared terminal anyway.
Verification
- On box:
docker compose ps(broker Up),systemctl is-active cloudflared(active),sudo ss -tlnp | grep 8002shows127.0.0.1:8002only. - Public:
curl -I https://bobsmcp.uk→ 401 (alive, auth required);/.well-known/oauth-protected-resource/proxy/notion_api→ 200; port probe against the public IP (nc -z <ip> 8002/22) fails. - Client connects at
https://bobsmcp.uk/proxy/<connector>(NOT the bare root).
Rollback
terraform destroy removes instance + firewall. Delete the machine from the Tailscale
admin console (nodes are non-ephemeral). The Cloudflare tunnel survives for the next
deploy; delete it in Zero Trust only if retiring the environment. VM replacement loses
data/ (inbound + connector OAuth token DBs) and the generated .env — claude.ai must
re-register and connectors must be re-authorized afterwards.
Compiled from
wiki/projects/gcp-mcp-standalone/runbooks/deploy.md · git is the source of truth