antigravity-mcp
# antigravity-mcp
**Delegate background subagent jobs to the Antigravity IDE's local agent engine — from Claude Code, Codex, Cursor, or any other MCP client.**
[](https://github.com/Kio-pon/antigravity-mcp/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
If you have the Antigravity IDE open and signed in, you already have a local agent engine with a catalog of frontier models sitting idle. This is an [MCP](https://modelcontextprotocol.io) server that exposes that engine as a handful of tools, so the model you actually drive your work with can hand jobs off to it and keep going.
Your orchestrator stays the architect. The subagents do the legwork.
```
┌─────────────────────────────────────────────────┐
│ Your MCP client │
│ (Claude Code · Codex · Cursor · anything else) │
│ plans the work, reviews every result │
└───────────────────────┬─────────────────────────┘
│ MCP · JSON-RPC 2.0 over stdio
▼
┌─────────────────────────────────────────────────┐
│ antigravity-mcp │
│ returns a job_id immediately, never blocks │
│ bounded worker pool · job history on disk │
└───────────────────────┬─────────────────────────┘
│ tried in order
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Antigravity │ │ Gemini REST │ │ Explicit │
│ language │ │ API │ │ failure │
│ server │ │ │ │ │
│ no API key │ │ needs a key │ │ never faked │
└───────────────┘ └───────────────┘ └───────────────┘
```
## Why
Orchestrating models are expensive and serial. Plenty of real work isn't worth their attention: scanning forty files to answer one architectural question, generating the fifth round of near-identical fixtures, or reading a dependency tree you already understand. Hand those to a fast local worker, keep planning while it runs, and collect the result when you need it.
Because jobs run on the IDE's own authenticated session, **no API key is needed** when the IDE is open.
## Install
```bash
pip install git+https://github.com/Kio-pon/antigravity-mcp.git
```
Or clone it — there are no dependencies, so a checkout runs as-is on a bare interpreter:
```bash
git clone https://github.com/Kio-pon/antigravity-mcp.git
```
## Register with your MCP client
<details open>
<summary><b>Claude Code</b></summary>
```bash
claude mcp add antigravity-agents -- antigravity-mcp
```
From a clone instead of an install:
```bash
claude mcp add antigravity-agents -- python3 /path/to/antigravity-mcp/src/antigravity_mcp/__main__.py
```
</details>
<details>
<summary><b>Codex</b></summary>
Add to `~/.codex/config.toml`:
```toml
[mcp_servers.antigravity-agents]
command = "antigravity-mcp"
```
</details>
<details>
<summary><b>Cursor, Windsurf, and other <code>mcp.json</code> clients</b></summary>
```json
{
"mcpServers": {
"antigravity-agents": {
"command": "antigravity-mcp",
"env": {
"ANTIGRAVITY_MAX_CONCURRENT_JOBS": "3"
}
}
}
}
```
</details>
Ready-made config files live in [`examples/`](examples/).
The strict policy build intentionally starts with **no network authority**. A
trusted host integration must install an operator-approved execution scope before
calling `list_available_models`, `get_active_workspace`, or either dispatch tool.
Opening an IDE, passing `workspace_path`, or restoring a job does not create that
authority. Until that integration is configured, these tools fail closed; do not
replace it with a client-side endpoint, token, or environment-variable shortcut.
## Tools
| Tool | Arguments | What it does |
| :--- | :--- | :--- |
| `dispatch_gemini_agent` | `task`, `workspace_path?`, `context_files?`, `model?`, `system_instruction?` | Validates workspace/context, then queues a job and returns a `job_id`. |
| `check_agent_job` | `job_id` | Status, elapsed time, progress log, and output. |
| `list_active_jobs` | `limit?` | Recent and in-flight jobs. |
| `cancel_agent_job` | `job_id` | Cooperatively stops a running job. |
| `gemini_code_search` | `query`, `context_files`, `workspace_path?` | Validates workspace/context, then scans the captured files synchronously. |
| `list_available_models` | — | The live model catalog from your IDE session. |
### Picking a model
The catalog is whatever your Antigravity account currently has, and it changes as models ship — so nothing is hardcoded. Call `list_available_models` to see it, then pass either an exact label or a loose description:
```
"Gemini 3.8 Flash (High)" exact label
"gemini 3.7 flash medium" version + family + effort tier
"flash" best available flash — highest effort, newest version
"opus" best available Opus
```
Matching is token-based and strict about what you *do* specify: every word and version number you give has to appear in the model's label. `"gemini-3.5-flash"` will not quietly resolve to a 3.7 model just because both are flash — it raises and lists what actually exists. Leave a dimension out and it is a wildcard, resolved to the highest effort tier and newest version that fits.
## How a session usually goes
```
1. dispatch_gemini_agent → job_id, returned instantly
2. …carry on with your own work…
3. check_agent_job → output when it's ready
4. review before applying anything to files
```
Step 4 is the point of the whole design. A subagent's output is a proposal, not a commit.
## Execution backends
Two backends, tried in order:
1. **Local Antigravity language server** — the default. Connects over loopback HTTPS and reuses the IDE's signed-in session. No API key.
2. **Gemini REST API** — used when local execution is disabled and `GEMINI_API_KEY` or `GOOGLE_API_KEY` is set, after the same workspace gate succeeds.
### Strict workspace gate (Phase 1)
### Policy-first authority lifecycle
An approved scope belongs to trusted server startup code, not to MCP tool input.
It declares literal loopback Language Server bindings with a process-creation
identity, approved workspace roots, and narrowly selected capabilities. The
server re-observes the pinned process/listener and credential before every RPC.
Workspace validation first captures a particular workspace, context-file identity
and execution intent; only that trusted flow issues the short-lived authorization
needed for a job. A public-looking evidence object, a saved job, or a copied
permit is not authority and is rejected by the scope's per-scope issuance
registry.
The installed `antigravity-mcp` console command intentionally supplies no scope
and therefore keeps network-capable tools disabled. A separately reviewed
embedding host may construct an in-memory `ApprovedExecutionScope` from its own
operator-approved binding and call `antigravity_mcp.server.main(execution_scope=scope)`
or `MCPServer(execution_scope=scope)`. This package does not accept an endpoint,
PID, workspace, capability, token, or scope revision from environment variables,
MCP arguments, client metadata, or persisted jobs as a substitute for that host
integration.
Replacing or revoking a scope invalidates its outstanding probes, snapshots and
grants. Authority is bounded (default 30 minutes and 1,024 live handles) and is
released when the job becomes terminal. This registry is owned and locked by the
scope instance; it is not a process-global cache. It is a Python in-process trust
boundary, not a defense against arbitrary code already executing inside the MCP
server process.
### Trusted Windows broker contract (offline implementation)
`antigravity_mcp.windows_broker` defines a narrow contract for a future,
separately reviewed Windows launcher/broker. It is **not** connected to the MCP
console or a live IDE in this package release. Its default provider refuses all
operations. A real host must independently authenticate an operator-approved
launch plan and an IPC peer, launch the disposable IDE, and verify the artifact,
process-creation identity, literal-loopback listener ownership, exact Workspace
identity, and endpoint credential before supplying a runtime binding.
The broker keeps the credential in host memory and returns only opaque,
single-use, expiring grants bound to one authenticated MCP process identity,
one approved Workspace/context/intent, one endpoint binding, and one local
operation. REST is not a broker capability. Replacing/revoking the broker scope,
restarting the broker, a changed process/listener/token/Workspace binding, or an
expired grant makes later sends fail closed. A send already initiated cannot be
recalled; process/listener inspection and connection establishment are not
atomic.
The planned production transport is a Windows named pipe whose server obtains
the peer token/SID from the operating system; a PID/SID supplied inside an MCP
message is never sufficient. The current provider protocol is intentionally
testable with a deterministic fake, but the fake is not installed or selected by
production code. There is no environment-variable, command-line, persisted-job,
or MCP-argument fallback for launch plans, endpoint credentials, or grants.
The legacy Windows direct ownership verifier is disabled: it must not read an
arbitrary process command line/token and send Local RPC merely because embedding
code supplied a PID/port. Until a broker-backed verifier with the required host
controls exists, Windows local execution remains fail-closed.
`antigravity_mcp.windows_boundary` supplies a fail-closed, standard-library
Windows observer for a *pre-approved* PID: it compares the process creation
identity and canonical executable path, hashes the executable, and reads the
Windows IPv4 listener table to require the pinned literal-loopback listener to
be owned by that PID. It never launches an IDE, opens a socket, discovers a
candidate, reads a credential, or issues a broker grant. Its bounded JSON codec
is only input validation for a future pipe protocol; it is not a named-pipe
server and does not authenticate an IPC peer. A production pipe endpoint still
needs a reviewed ACL, OS-observed peer token/SID verification, an
integrity-protected launch-plan source, a Job Object child lifecycle, and
disposable-Windows verification. Process/listener observation and a later
connection remain non-atomic, so any such host must revalidate immediately
before send and still document the remaining TOCTOU window.
REST generation requires a separately approved `rest` capability and is disabled
by the default scope. Local authority does not imply REST authority. TLS hostname
and certificate validation stay enabled, redirects are rejected, and the
transport ignores proxy settings. These controls do not make process/socket
ownership checks atomic with opening a connection; a PID, socket or workspace can
still change after the final preflight or while an already-started request is in
flight.
Both execution tools require one verifiable IDE endpoint with exactly one workspace.
`workspace_path`, when supplied, must be an absolute directory that exactly matches
that workspace after canonicalization. Parent/child matches are rejected. Without
it, discovery must identify one unique workspace/endpoint. Unknown discovery
results, multiple matching endpoints, missing workspaces and mismatches stop
execution before a job is created. HTTP 404/405 from the workspace RPC remains
unknown, just like timeouts, authentication failures and malformed responses.
An endpoint is excluded only with independent evidence, such as a command-line
flag identifying an extension-service port, or a verified unrelated workspace.
Execution discovery returns candidates together with explicit completeness and
uncertainty information. Partial process/socket inventories cannot silently become
complete lists. Linux PID stat errors remain unknown unless process absence or
an unrelated executable can be established independently.
Dispatch may omit context files; code search still requires at least one file.
Every supplied file must be readable UTF-8, regular, and inside the workspace after
symlink/junction resolution. Relative context paths are resolved against that
workspace, never a backend's current directory. Missing, unreadable or changed
files and context exceeding 500,000 characters are rejected rather than partially
included. The validated text is captured once and shared by both backends.
After a queued job gets a slot, its binding is checked again. Local execution checks
again before `StartCascade` and before sending the task; REST checks immediately
before HTTP dispatch. A failed recheck marks the existing job failed without
sending its task, and never triggers a REST fallback. Old injected executors that
cannot accept the validated snapshot and workspace are rejected before job creation.
Direct calls through the legacy `GeminiExecutor` alias use the same gate.
Workers wait for submission acknowledgement before entering an executor. A submit
exception aborts that acknowledgement, marks the job failed, and wakes any worker
already waiting so it exits. Job transitions use a per-job lock: pending can become
running, failed or cancelled; running can become completed, failed or cancelled.
Terminal states cannot become running again. Local/REST transport initiation uses
a reservation under the same lock, so a terminal transition and a new send are
serialized. A Condition lets terminal transitions wait without holding the state
lock during network I/O, while the terminal reservation blocks additional sends. A request
that already began cannot be recalled; cancellation/failure may wait for the
transport-initiation call to return; the existing RPC/HTTP timeouts still apply.
This intentionally changes compatibility: REST-only execution with no verifiable
IDE workspace is refused, even with an API key or `ANTIGRAVITY_DISABLE_LOCAL=1`.
Disabling local execution does not disable workspace discovery/validation.
These checks are **not a filesystem sandbox**. Workspace instructions in prompts
and the existing post-run trajectory audit do not prevent an IDE agent from
accessing other paths. The IDE RPC provides no atomic validate-and-send operation:
an external workspace change can still occur after the final check or during a
running task. Phase 1 detects changes visible at preflight, not changes after it.
If neither is reachable the job fails with an error saying so. There is
deliberately no further tier that returns a stand-in result: a plausible answer
no model actually produced is worse than an error, because nothing downstream
can tell the two apart.
## Configuration
All optional.
| Variable | Default | Purpose |
| :--- | :--- | :--- |
| `ANTIGRAVITY_MAX_CONCURRENT_JOBS` | `3` | Jobs running at once. Every job drives a live session on the *same* language server process, so this is a real resource ceiling, not a formality. Extra jobs queue. |
| `ANTIGRAVITY_JOB_TIMEOUT` | `1800` | Seconds before a job is abandoned. Completion is detected, not waited out — a short single-shot answer returns in seconds — so a generous ceiling only bounds a genuinely stuck agent. |
| `ANTIGRAVITY_MAX_CONCURRENT_REQUESTS` | `16` | Tool calls handled in parallel. |
| `ANTIGRAVITY_STATE_DIR` | platform state dir | Where job history is kept. |
| `ANTIGRAVITY_DISABLE_LOCAL` | unset | Skip local execution; the workspace gate still requires a verified IDE workspace. |
| `ANTIGRAVITY_LOG_LEVEL` | `INFO` | Server log level on stderr. |
| `GEMINI_API_KEY` / `GOOGLE_API_KEY` | unset | Enables the REST fallback. |
Job history is written to `$XDG_STATE_HOME/antigravity-mcp/jobs.json` on Linux, `~/Library/Application Support/antigravity-mcp/` on macOS, and `%LOCALAPPDATA%\antigravity-mcp\` on Windows — never into the install tree. It survives across sessions, which is what makes a `job_id` from yesterday still mean something today.
## The optional skill
[`skills/antigravity-agent/`](skills/antigravity-agent/) is a Claude Code skill that teaches the orchestrator *when* delegating is worth it, so you don't have to say it every time. Install it with:
```bash
cp -r skills/antigravity-agent ~/.claude/skills/
```
## Protocol support
The server implements the current **2026-07-28** specification and the
handshake-based revisions before it, deciding per request which one a client is
speaking. Modern clients declare their version in each request's `_meta`; legacy
clients open with `initialize`. Both work against the same process with no
configuration, and `server/discover` reports every version on offer.
Because stdio has no HTTP status codes to drive fallback, `server/discover` is
also how a client tells a modern server from a legacy one — so it is answered
before anything else.
## Compatibility
> [!IMPORTANT]
> The local backend speaks private IDE IPC — `StartCascade`, `SendUserCascadeMessage`, `GetUserStatus`, `GetCascadeTrajectory` over loopback Connect-RPC. These are internal endpoints with **no cross-version stability guarantee**. An IDE update can change them.
| | Status |
| :--- | :--- |
| MCP specification | **2026-07-28** (current), plus 2025-06-18, 2025-03-26, 2024-11-05 |
| Antigravity IDE | Verified against **v1.107.0** (`linux_x64`). Antigravity 2.0, the separate agent-first app, is **untested** |
| Linux | Verified — process discovery via `/proc` and `ss` |
| macOS | Implemented via `lsof` and `ps -axww`, **not yet verified on real hardware** |
| Windows | Implemented via `netstat` and WMI, **not yet verified on real hardware** |
| Python | 3.9+ |
Running it on macOS or Windows? A quick issue saying whether discovery found your language server would be genuinely useful — that's the one part that cannot be tested without the hardware.
## Development
```bash
git clone https://github.com/Kio-pon/antigravity-mcp.git
cd antigravity-mcp
pip install -e ".[dev]"
pytest
```
The default suite is hermetic — no IDE, no network, no API key — driving the real request path with a stub executor in place of a language server. To also run the live round-trip against a real one, open the IDE and set `ANTIGRAVITY_LIVE_TESTS=1`.
See [CONTRIBUTING.md](CONTRIBUTING.md).
## License
[MIT](LICENSE).
Not affiliated with, endorsed by, or supported by Google or the Antigravity IDE team.
TDQS
Scored across 7 tools
Each tool maps to a distinct action: workspace inspection, model listing, async dispatch, job status/list/cancel, and synchronous code search. The only mild overlap is between check_agent_job and list_active_jobs (both about job state) and between dispatch_gemini_agent and gemini_code_search (both invoke Gemini), but descriptions clearly separate single-job inspection from enumeration and async background work from synchronous analysis.
Six of seven tools follow a clean verb_noun snake_case pattern (get_active_workspace, dispatch_gemini_agent, list_available_models, check_agent_job, list_active_jobs, cancel_agent_job). gemini_code_search deviates by leading with a noun/namespace, a minor inconsistency but still readable and predictable.
Seven tools is well-scoped for an IDE orchestration server, with each tool earning its place across discovery, dispatch, and job management. Nothing feels redundant or padded.
The subagent lifecycle is fully covered (dispatch, check, list, cancel) alongside workspace discovery, model enumeration, and synchronous code analysis. Minor gaps exist—no retry/resume of a job, no follow-up message to a running agent, and no explicit wait-for-completion primitive—but agents can poll with check_agent_job.