Let Claude Code or Cursor work on a private GCP VM
An AI coding agent that can run shell commands on your Mac can already work on a
Compute Engine VM with no external IP: it runs ssh, scp and
rsync through Identity-Aware Proxy, the same way you do. Claude Code, Cursor,
Codex CLI, Gemini CLI and VS Code's agent mode all fit that description, so for most work you
do not need an MCP server. This guide covers the setup, what to write in the agent's
instructions, and how to limit what it can do on the VM.
By Ostgate · Updated
An AI agent on a GCP VM: it runs ssh through IAP
A VM without an external IP is reachable from your Mac through IAP TCP forwarding. Anything
that runs ssh in your shell can use that path, and an agent's shell tool is no
different. With gcloud installed, the agent can run one command per call:
gcloud compute ssh example-vm --zone=europe-west1-b --project=acme-prod --tunnel-through-iap --command='uptime; df -h /'
With a host in ~/.ssh/config whose ProxyCommand opens the IAP
tunnel, the commands are plain OpenSSH, and file copies work the same way:
ssh example-vm 'journalctl -u nginx --since "1 hour ago" --no-pager | tail -n 50' scp example-vm:/etc/nginx/nginx.conf ./nginx.conf rsync -avP ./build/ example-vm:~/app/
The second form suits agents better, because each ssh call is short, the output
is only the remote command's output, and rsync works without extra flags. Setting up such
a host with gcloud is covered in VS Code Remote-SSH to a GCP VM through
IAP, and copying files in scp and rsync to a
GCP VM.
Set up the VM and your Mac
- Allow IAP to reach the VM: a firewall rule from
35.235.240.0/20ontcp:22, androles/iap.for your account (see the IAP firewall rule).tunnelResourceAccessor - Get your SSH key accepted by the VM through OS Login, in your OS Login profile. A key in the instance's or project's SSH keys metadata also works, but it gives root on the VM. SSH without an external IP walks through both.
- Add the host to
~/.ssh/config, withgcloudin theProxyCommandor with Ostgate's managed block (below). - Connect once yourself in Terminal. The first connection asks you to accept the VM's host
key, and an agent cannot answer that prompt. If your key has a passphrase, load it into
ssh-agentnow for the same reason. - Try a non-interactive command the way the agent will run it:
ssh -o BatchMode=yes example-vm 'hostname; whoami'
BatchMode=yes makes ssh fail with a message instead of waiting for a
password or a host key answer, so the agent sees an error it can report.
What to tell the agent
Put the access rules where the agent reads its project instructions:
CLAUDE.md for Claude Code, AGENTS.md for Codex CLI and other agents
that read it, a rule file under .cursor/rules/ for Cursor, and
GEMINI.md for Gemini CLI. Cursor reads .mdc files there and also
reads AGENTS.md. Adjust the host and the limits to your case:
## Remote VM - The staging VM is reachable as `example-vm` (ssh, scp and rsync go through IAP). - Run one command per call: `ssh -o BatchMode=yes example-vm ''`. - Never open an interactive session (no bare `ssh example-vm`, no `vim`, no `top`). - Start with read-only commands: `systemctl status`, `journalctl --no-pager`, `ls`, `cat`, `df`. - Before any command that changes the VM (restarts, package installs, file edits, anything with `sudo`), show me the exact command and wait for my approval. - Copy files with `scp` or `rsync`; never pipe secrets or `.env` files into the chat. - If ssh fails, report the error text; do not change ~/.ssh/config or firewall rules.
An agent can still misread or skip these lines. Claude Code, Cursor, Codex CLI and Gemini CLI
can be set to ask before each shell command; keep that on for ssh until you trust the
pattern, and rely on the limits in the next section for the rest.
Limit what the agent can do on the VM
The agent works with your access. On the VM it is your Linux user, with whatever that user may do, and on Google Cloud it is your account. Narrow both:
- Use OS Login with only
roles/compute.osLogin, which logs you in without root.roles/compute.osAdminLoginadds root, and so does a metadata SSH key. Use an account without Owner, Editor or Compute Instance Admin on the project, because those roles can add metadata keys or turn OS Login off on a VM. - Point the agent at a staging VM first, not at a production one.
- The
gcloudroute gives the agent your fullgcloudcredentials, so it can run anygcloudcommand you can. Create a separategcloudconfiguration signed in as a restricted account for agent work, or use a route that keeps the Google token away from the shell, such as Ostgate's ssh config. With OS Login,sshthrough IAP needs only the tunnel role,roles/compute.osLoginand your key. - IAP checks every connection against IAM. If Data Access audit logs are turned on for IAP, each tunnel your agent opens is logged under your account, the same as yours.
Is there an MCP server for SSH into GCP VMs?
Google runs an official Compute Engine MCP server at
https://compute.. Its tools manage VMs: list, create,
start, stop, reset and delete instances, change a machine type, and read disks, templates and
reservations. As of 15 October 2026, none of the tools in Google's MCP reference
runs a command or reads a file inside a VM.
An agent can use both: start a stopped VM through the MCP server, then do the work inside
it over ssh. Third-party SSH MCP servers exist too; they help an
assistant that has no shell of its own, such as a desktop chat app.
With Ostgate instead of gcloud
Ostgate is a native macOS app that opens IAP tunnels itself, with no gcloud on
the Mac. In Settings › SSH Integration, click Install. Ostgate adds one managed
block to ~/.ssh/config that covers every instance, addressed as
INSTANCE.ZONE.PROJECT.gcp:
ssh -o BatchMode=yes example-vm.europe-west1-b.acme-prod.gcp 'systemctl status nginx --no-pager' rsync -avP ./build/ example-vm.europe-west1-b.acme-prod.gcp:~/app/
The block's ProxyCommand calls Ostgate by its full path, so it works from an
agent started in any terminal or editor, with Ostgate's window closed. The helper uses your
signed-in Ostgate accounts and tries them in turn, those with the project pinned first, until
IAP lets one through. If you keep an admin account signed in next to a restricted one, the
agent's ssh can get through IAP with either, so sign the admin account out for
agent work. ssh still logs in with your own keys from ~/.ssh; the
optional OS Login username field adds a User line so the agent does not
need to know it.
The Access setting on Ostgate's tunnels does not apply here: ssh starts
the helper itself and no local port is opened. It matters when the agent connects to a
tunnel's port, for example psql on 127.0.0.1:5432. The default,
Ostgate only, refuses the agent's client; My processes admits programs running
as your macOS user, which includes anything the agent starts.
Questions
Is there an MCP server for SSH into GCP VMs?
Google's Compute Engine MCP server manages VMs: it lists, creates, starts, stops, resets and deletes them, but none of its tools runs a command inside a VM. Third-party SSH MCP servers exist. An agent that can run shell commands does not need one: it runs ssh through IAP like you do.
Can Claude Code connect to a GCE VM without an external IP?
Yes. Claude Code runs commands in your Mac's shell, so it can use gcloud compute ssh with --tunnel-through-iap, or a host in ~/.ssh/config whose ProxyCommand opens an IAP tunnel. The VM needs the usual IAP setup: a firewall rule from 35.235.240.0/20 on tcp:22 and roles/iap.tunnelResourceAccessor for your account.
Does Ostgate have to be open for the agent's ssh to work?
No window has to be open. ssh starts Ostgate's helper for each connection, and the helper uses the Google accounts signed in to Ostgate. With no signed-in account, ssh reports that Ostgate needs a sign-in. Connections work while the trial or licence is active.
Why does the agent's ssh command hang?
Usually ssh is waiting for an answer nobody can type: the host key question on the first connection, or a key passphrase. Connect once yourself in Terminal to accept the host key, and have the agent pass -o BatchMode=yes so ssh fails with a message instead of waiting.
Give your agent private VMs without gcloud. Ostgate runs on Apple Silicon Macs with macOS 15 or later, and is paid after a 7-day trial with no sign-up. See Use ssh from Terminal in the docs.