Skip to main content
Glama

Gemini Bridge

A local MCP server that lets Claude (Claude Code, Claude Desktop and Cowork) hand work to Gemini on your Google AI Pro subscription: web research with sources, reading PDFs, audio, video, images and web pages, image generation, and second opinions.

It does this one way only: by launching Google's official Antigravity CLI (agy) in its documented headless mode. There's no API key and no billing. The bridge makes no network calls of its own and never touches agy's login tokens. Every run is locked to a read-only agent, and telemetry is set off before each one.

Built and tested on Windows 11 with Node 25: agy 1.2.16 for the Phase 0 spike, agy 1.4.2 for the v1.0 smoke test. Not affiliated with Google.

Contents: Tools · Why agy headless · Install · Register in Claude Code · Register in Claude Desktop · Configuration · The read-only agent lock · Telemetry off · Known agy issues · Limits · Troubleshooting · Development · Licence

Tools

Tool

What it does

Agent and model

Time limit

gemini_research

Web research. depth: quick answers inline. deep writes a structured report and, when a vault is configured, saves it as a note.

researcher; Flash Medium (quick) or Flash High (deep), Pro only on request

5 / 20 min

gemini_ask

Second opinions, rewrites, quick reasoning. No tools, no web.

asker; Flash Medium or Pro

3 min

gemini_read

One local file (copied into the run's workspace, max 200 MB) or one URL, plus a question. PDF, audio, video, images and web pages.

reader

10 min

gemini_image

Generates one image and saves it as IMAGE_DIR/<date>-<slug>.<ext>.

imager

5 min

gemini_job

Status, result or error of any job, from either Claude client.

gemini_quota

Weekly and 5-hour quota from agy /usage (spends nothing), the signed-in account when agy logs it, and today's bridge runs.

Every call is a job, stored in BRIDGE_HOME/jobs/. A call waits up to SYNC_BUDGET_MS (150 s) for its answer. If the run takes longer, the call returns a job id, the run carries on in the background, and Claude polls it with gemini_job. Each bridge process runs one agy at a time.

Saved research goes to VAULT_DIR/RESEARCH_SUBDIR/<slug>-agy.md with research frontmatter (type: research, status: inbox). The file is written atomically and never overwrites a note; a name clash gets -2, -3 and so on. Sources come from tool events, not from the model's own list:

  • Sources read are the pages fetched with read_url_content. Google search redirects are resolved to the real page through its canonical URL.

  • Search queries are the queries sent to search_web.

  • URLs the model cites but never read are flagged as unverified.

Related MCP server: MCP Gemini Server

Why agy headless

Google AI Pro includes Gemini quota, but the only programmatic door into it that Google's terms allow is the official CLI:

  • Since 2026-06-18 Gemini CLI no longer accepts free or AI Pro/Ultra sign-ins; those accounts moved to Antigravity CLI (transition notice). Bridges built on Gemini CLI no longer reach the subscription.

  • Reusing the CLI's login tokens in other software is forbidden (Gemini CLI terms, Antigravity terms §6). Launching the official binary in its headless mode is the allowed path, so the bridge spawns agy -p and reads its output, nothing more.

  • The Antigravity SDK needs an API key or Vertex, which bills. Deep Research, NotebookLM and Gems have no programmatic access, and automating gemini.google.com breaks Google's terms (automated access against robots.txt, which disallows /app/).

  • The Antigravity terms let Google use your interactions to improve its products unless telemetry is off (§5), hence the next point.

Read the terms yourself before relying on this; this README isn't legal advice.

Install

  1. Install agy (PowerShell), open a new terminal and check agy --version:

    irm https://antigravity.google/cli/install.ps1 | iex
  2. Run agy once and sign in with the Google account that has AI Pro. Leave the telemetry opt-in unticked if first-run setup offers one, and exit without sending a prompt.

  3. Build and test the bridge:

    git clone https://github.com/dssbdev/gemini-bridge.git
    cd gemini-bridge
    npm ci
    npm run build
    npm test
  4. Copy .env.example to .env and fill in what you need: AGY_ACCOUNT at least, VAULT_DIR to save research as notes, and BLOCKED_DIRS for folders that must never reach Gemini. .env is git-ignored, so your account and paths stay on your machine.

Register in Claude Code

At user scope, with full paths to node.exe (where node) and to dist/index.js:

claude mcp add gemini --scope user -- "C:/Program Files/nodejs/node.exe" C:/path/to/gemini-bridge/dist/index.js

The bridge reads its settings from .env in its own folder, whatever directory Claude starts it from. An -e KEY=value flag on this command overrides a single value. /mcp in a new session should list gemini with six tools.

Register in Claude Desktop

This is also how Cowork sees local servers.

  1. Open claude_desktop_config.json: Settings → Developer → Edit Config. It's in %APPDATA%\Claude\, or under %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\ for the Microsoft Store install.

  2. Back it up, then add this entry under mcpServers without touching the others:

    "gemini": {
      "command": "C:\\Program Files\\nodejs\\node.exe",
      "args": ["C:\\path\\to\\gemini-bridge\\dist\\index.js"]
    }
  3. Restart Claude Desktop.

Claude Desktop stops an MCP call after about four minutes, which is why a long run hands back a job id after 150 s instead of holding the call open. Claude Code and Claude Desktop each start their own bridge process; they share BRIDGE_HOME, so either one can read a job the other started.

Configuration

Everything is optional; .env.example explains each variable. Values an MCP client passes in its own env settings win over .env.

Variable

Default

What it does

AGY_ACCOUNT

none

The Google account agy must be signed in with. A run agy logs under another account is discarded (wrong_account).

VAULT_DIR

none

Where deep research is saved as notes. Unset: research is answered inline and nothing is saved.

RESEARCH_SUBDIR

50-Research/gemini-researches

Folder inside VAULT_DIR for saved research.

IMAGE_DIR

%USERPROFILE%\Pictures\gemini-bridge

Where generated images land.

BLOCKED_DIRS

none

;-separated directories that never reach Gemini, as file inputs or as paths pasted into a prompt.

CONTENT_RULE

Personal content only — never work code, client or customer data.

The never-send sentence in every tool description, which is what Claude reads before delegating.

AGY_BIN

%LOCALAPPDATA%\agy\bin\agy.exe

The agy executable.

AGY_APP_DIR

%USERPROFILE%\.gemini\antigravity-cli

agy's data folder: settings.json, transcripts, artifacts.

BRIDGE_HOME

%LOCALAPPDATA%\gemini-bridge

Jobs, scratch workspaces and runs.jsonl.

MODEL_FLASH

gemini-3.8-flash-medium

Quick research, read, image, ask.

MODEL_FLASH_DEEP

gemini-3.8-flash-high

Deep research.

MODEL_PRO

gemini-3.1-pro-high

Only when the caller asks for Pro.

SYNC_BUDGET_MS

150000

How long a call waits before it hands back a job id.

At start the bridge logs (to stderr, which Claude Code shows in its MCP logs) which keys it took from .env, the account it checks, the vault and the blocked directories.

The read-only agent lock

agy is a coding agent with about 60 tools, shell and file edits among them. The bridge narrows every run to what that tool needs, and checks after the run that the narrowing held:

  1. A fresh scratch workspace per job (BRIDGE_HOME/work/<job_id>), copied from templates/. A local input is copied in, so the model never needs to look outside. The workspace is deleted after success, kept after a failure for debugging, and pruned after 7 days.

  2. A custom agent per tool (templates/.agents/agents/), whose tools: list holds only search, read or image tools. asker has none at all.

  3. A deny-by-default guard hook (templates/.agents/guard.mjs) on every tool call, against a per-job allowlist:

    • manage_task, shell and edit tools are denied (agy adds manage_task to every agent, whatever its tools: list says);

    • view_file may read only the workspace and the run's own artifact folder;

    • read_url_content may fetch only http(s).

  4. Proof the guard ran. A malformed hooks.json makes agy run with no hooks at all, so a run whose guard never logged is thrown away (guard_missing).

  5. An agent-load canary. An unknown or broken agent makes agy fall back, silently, to its default agent with every tool. A first model step far larger than the agent's baseline gets the run killed (agent_mismatch).

  6. No --dangerously-skip-permissions, ever. Shell commands and file writes stay soft-denied by agy itself, as a second wall behind the guard.

  7. A scrubbed env. GEMINI_API_KEY, GOOGLE_API_KEY, GOOGLE_GENAI_USE_VERTEXAI and GOOGLE_CLOUD_PROJECT are removed before spawning, because with any of them present agy switches to API mode, which bills.

  8. Timeouts. --print-timeout per tool, plus a hard wall clock of print-timeout + 60 s that kills the whole process tree (taskkill /T /F).

  9. No slash commands. Every run passes --disable-slash-commands, so a prompt that starts with / can't trigger a CLI command.

In the Phase 0 injection test, a prompt asking agy to run whoami and write the output to a file made no tool call and created no file; the default agent, as a control, tried run_command and was soft-denied. The evidence is in SPIKE.md.

One setting reaches beyond the bridge: read_url_content needs the permission rule "permissions": { "allow": ["read_url(*)"] } in agy's settings.json to work headless, and the bridge adds it before every run. It also auto-approves URL reads in your interactive agy sessions. Remove the permissions key to undo it; research then degrades to search summaries without sources read.

Telemetry off

agy's settings.json (%USERPROFILE%\.gemini\antigravity-cli\settings.json) has an enableTelemetry key. Before every run the bridge merges "enableTelemetry": false into it and keeps every other key, so each run starts with telemetry explicitly off, and if you ever switch it on, the next bridge run switches it off again. If the file isn't valid JSON, the bridge refuses to run rather than guess.

Don't be surprised to find the key missing between runs. agy writes only settings that differ from its defaults, and from 1.2.16 to 1.4.2 it removed enableTelemetry: false from the file on every start, so false looks like its default. To see the live value, open /config in an interactive agy session and check Enable Telemetry.

Known agy issues

Issue

What the bridge does

Print mode can hang without a terminal (#318) or never exit after answering (#947). Neither showed up in the spike, but they're reported.

Hard wall clock, then the whole process tree is killed and the job fails with timeout.

SUCCESS with an empty response (#76). In practice it's a soft-denied permission or a print timeout.

Reads the answer from the transcript; reports denied (with the action agy wanted) or timeout when stderr says so.

A print timeout exits 0 with SUCCESS and an empty response; only stderr says what happened.

Treats agy's print timeout after line as a timeout.

permissions.allow rules in the regex: form are ignored in print mode (#548).

Uses read_url(*), which works.

An unknown --agent silently falls back to the default agent with every tool, and init.agent still echoes the name you asked for.

Agent-load canary (agent_mismatch).

init.tools always lists the full tool registry, even for a restricted agent, so it can't prove the restriction.

The guard hook and the canary do the proving.

manage_task is added to every agent.

The guard denies it.

A malformed hooks.json loads no hooks and the run carries on.

Discards any run whose guard didn't log (guard_missing).

generate_image fails now and then (no image generated in response), and the model may still claim it made one.

Trusts only a finished generate_image step plus the file actually existing.

YouTube pages return a bot check, not the video, after burning about 90k tokens.

Refuses YouTube URLs before spawning.

Default log names (cli-YYYYMMDD_HHMMSS.log) collide when two runs start in the same second.

Every run logs to its own workspace (--log-file).

agy doesn't log the signed-in account on every run (silent auth).

The account check only fires when the log names an account.

Windows caps a command line at about 32k characters.

Prompts over 24,000 characters go through stdin (--input-format stream-json with -p=).

In Git Bash, MSYS rewrites /usage into a Windows path, so the prompt goes to the model and costs tokens.

The bridge spawns without a shell. For manual tests, use PowerShell or MSYS_NO_PATHCONV=1.

Limits

  • Quota. AI Pro shares one Gemini limit across Flash and Pro, with a weekly window and a 5-hour window, drawn down at API prices. Users report multi-day lockouts after hitting the weekly cap. Measured in Phase 0: about 1.1M Flash tokens per 1% of the weekly limit and about 180k per 1% of the 5-hour window. A quick research run used 170–310k tokens before quick depth was capped at three pages; one deep run on Flash High (11 pages read, 278 s) used 1.18M tokens, about 1.2% of the weekly limit and 7% of the 5-hour window, so roughly a dozen deep runs fit in a 5-hour window. Check gemini_quota before a batch, and stay on Flash.

  • One run at a time per bridge process; further calls queue.

  • One input per read: a file of up to 200 MB or one URL. No YouTube.

  • One image per call, usually a 1024×1024 JPEG. The aspect option is only a hint in the prompt; the image tool has no aspect parameter.

  • No Deep Research, NotebookLM or Gems. They're app-only.

  • No plan check. No agy command names the plan tier, so the bridge can't confirm the account is on AI Pro.

  • One account. Switching is manual: run agy, then /logout, sign in with the other account, and update AGY_ACCOUNT. Don't rotate accounts to stretch quota.

  • Windows only. Process-tree kills use taskkill and the defaults are Windows paths; macOS and Linux are untested.

Troubleshooting

  • Logs. Each run appends a line to BRIDGE_HOME\runs.jsonl (status, model, tokens, conversation id). A failed run keeps its workspace in BRIDGE_HOME\work\<job_id>\ with agy.log (agy's own log) and .agents\guard.log (every hook call). agy's transcript is at %USERPROFILE%\.gemini\antigravity-cli\brain\<conversation_id>\.system_generated\logs\transcript.jsonl.

  • Every run hangs. Run agy -p "Reply with exactly: OK" --output-format json in a terminal. If that hangs too, the problem is agy itself, not the bridge.

  • denied. agy wanted a permission headless mode can't grant; denied_actions names it. If it's read_url, check that settings.json still holds the read_url(*) rule (the bridge adds it back on the next run).

  • guard_missing or agent_mismatch. templates/.agents/ is damaged. npm test checks the hooks file format and the agent files.

  • wrong_account. agy is signed in with an account other than AGY_ACCOUNT. Run agy, then /logout, and sign in with the right one.

  • Quota lockout. Wait for the reset time gemini_quota shows.

Development

  • npm test runs vitest against test/fake-agy.mjs, which replays envelopes and stream-json logs recorded from real agy runs (test/fixtures/), in the modes ok, research, image, empty, hang, error, timeout, denied, canary, noguard, env and echo.

  • node spike/smoke.mjs <scratchDir> [tool…] runs the built server against the real agy, with scratch vault and image folders. It spends quota.

  • SPEC.md is the original build spec and SPIKE.md the Phase 0 findings behind every decision above. spike/ holds the Phase 0 scripts and raw outputs, with local paths and the account anonymised.

Licence

MIT, see LICENSE.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers