Skip to main content
Glama

mcp-acp-bridge

An ACP server that fronts any MCP-speaking coding agent.

The bridge hosts an MCP server for the agent and speaks ACP to an editor or client. Because every tool call the agent makes passes through it, the bridge can hold each one and ask the client for approval first — turning tool calls into real permission prompts in whatever UI is driving.

client (T3 Code, Zed, …) ──ACP──► bridge ──MCP──► agent (agy, claude, codex, …)
                                    │
                                    └─ spawns and supervises the agent process

Status: the full chain works. An ACP client drives the bridge, the bridge spawns a real agent, the agent's MCP tool call is held, and it surfaces to the client as session/request_permission — answered with allow or deny, either outcome reaching the agent legibly. Verified end-to-end against Claude Code.

Not yet done: session/load (resume), command allow/block lists, and broker-provided file and shell tools. See docs/design.md.

Try it

npm install
npm test              # unit tests, no agent required
npm run test:live     # drives the real `claude` CLI against the gateway
npm run test:bridge   # full chain: ACP client -> bridge -> agent -> approval
npm run test:bridge deny

The only native dependency, node-pty, is optional — it is needed just for the PTY agents (agy-dual, agy-dual-gated). If its build fails (no C++ toolchain, e.g. on a minimal Linux box), npm install keeps going and the bridge still runs the non-PTY agents (claude, codex, gemini) — those never load it. Only starting a PTY agent without it errors, and says so.

test:live needs the claude CLI on PATH and authenticated. It hands Claude Code a per-session MCP endpoint, asks it to call a tool, and shows the interception:

[tool] requested magic_word
[gate] DENY magic_word {}
[tool] denied magic_word (denied by test policy)
[claude] said: The tool call was denied. The error returned was exactly:
         `Error: permission denied: denied by test policy`

Why

Some coding agents emit no structured output. Google's Antigravity CLI (agy) is the motivating case: it has no ACP mode (upstream request), and in headless mode it prints plain text and auto-denies any permission it cannot prompt for. Driving it from a GUI therefore means either scraping a TUI or giving up on approvals.

This bridge takes a third path. It ignores what the agent says and intercepts what the agent does: MCP tool calls are already structured, already observable, and — crucially — already interceptable. An MCP server is not a listener, it is a gate.

Nothing about the approach is agent-specific. Any agent that can be pointed at an MCP server works.

What it does and does not see

MCP is a tool channel, not an agent-output channel.

ACP output

Source

Fidelity

tool_call, tool_call_update

intercepted MCP calls

exact

session/request_permission

one per intercepted call

exact

agent_message_chunk

the agent's stdout

per-agent

turn boundaries

process lifecycle

exact

An agent's built-in file and shell tools do not traverse MCP, so they raise no tool_call. That is a visibility gap, not a correctness one — clients that checkpoint the workspace (T3 Code diffs it on turn boundaries) still record what changed. What is lost is live per-action progress, not the record.

Which agents the bridge can drive, how each finds the MCP endpoint, and how much each can be gated (claude fully, codex partially, agy observed-only) is in docs/agents.md — read it before adding an agent.

Choosing a mode

Modes differ in what stops for review. Pick by what you are willing to have happen without being asked.

Mode

Turns

Tool calls

Shell

agy-dual

over MCP

not reviewed

runs unreviewed

agy-dual-gated

over MCP

not reviewed

reviewed, with the command shown

agy-gated

over MCP

reviewed

no shell in an empty workspace

agy-sandboxed

headless

not reviewed

OS sandbox, permissions skipped

What an unreviewed shell means

agy-dual grants the agent's shell tool outright, and a granted shell is not bounded by the deny list. Those rules are per-tool: write_file(/home/you/.ssh) constrains the agent's file tool, and a shell command is not that tool.

This is measured, not theoretical. Observed 2026-08-19 on agy 1.1.15, with the default deny rules in place, from a single prompt:

find . -maxdepth 0 -exec sh -c 'echo CANARY > /home/you/bridge-canary.txt' \;

The file was written, outside the workspace, with no prompt. The same request under agy-dual-gated arrives as a permission card carrying that command text; refused, nothing is written.

Two things can make this look contained, and neither is a boundary. Writes relative to $HOME land in the throwaway per-session home and vanish with it, so a $HOME canary disappears where an absolute path does not; and an agent usually has no reason to leave its workspace at all.

Antigravity's own sandboxing is moving, and a later release may well close this. Treat the date and version above as the scope of the claim rather than a standing property of agy, and re-run the canary if it matters to you — one prompt, and the answer is a file that either exists or does not.

In practice the realistic risk is an accident — a wrong path, an overreaching cleanup — rather than anything deliberate, and running an agent on your own machine is ordinary. agy-dual is a reasonable default for a workspace you can restore. What it is not is a place to keep credentials you would mind losing.

If this matters to you

Use both. They fail in different directions, which is the point.

Run the bridge in an OS sandbox. This is the only real boundary: it bounds what the process can reach at all, whatever tool it reaches with and whatever path it names. On Linux, bwrap or firejail with the workspace bound in and $HOME left out; a container or VM does the same job more heavily. On macOS, a container, or sandbox-exec for a rough equivalent. What a sandbox will not do is tell you what is about to happen — it silently refuses, and the agent usually reports a confusing failure.

And use agy-dual-gated. Review is what a sandbox cannot give you: the command arrives as text you can read before it runs, so a mistake is visible rather than merely blocked. What review cannot give you is a guarantee, since it rests on a deny rule matching the tool the agent chose.

Together, the sandbox bounds the damage and the gate shows you the intent. Either alone leaves a real gap: a sandbox with an unreviewed shell will let the agent thrash destructively inside your workspace without ever asking, and review without a sandbox depends on the agent taking the route you gated.

One thing not to confuse with any of this: agy's own --sandbox flag, used by the agy-sandboxed profile, is described by agy as terminal restrictions. In testing it did not stop file reads outside the workspace, with or without the flag. It is not an OS sandbox and should not be relied on as one.

A supervisor to answer the reviews

Review shows you the command, but a person cannot sit on every prompt. A supervisor is a decider that sits in front of the human on the same seam: it may approve, reject, or pass to the human, and every way it can fail — unavailable, malformed verdict, timed out — resolves to pass, never to allow. Four ways to supply one:

Flag

The supervisor is…

--supervisor <cmd>

a command run per decision; its stdout is the verdict

--supervisor-mcp

a client that claims a seat over MCP and answers pending decisions

--supervisor-acp [port]

the same seat over ACP, for a supervisor that is itself an agent (it polls a queue)

--supervisor-acp-push [port]

an agent the bridge asks — each deferred decision is sent as a supervisor/review request whose reply is the verdict

This is how one agent supervises another — a larger model watching a smaller one's tool calls — without a person on every card. The ACP modes gate on a token the bridge prints to its console, since the supervised agent can reach the same loopback port. Design, the fail-closed guarantees, and the precedence between modes: docs/supervisor.md.

MCP revision support

Both the current and the incoming revisions are supported, because the bridge never keys anything on MCP transport state:

Revision

Handshake

Session

2025-03-26

initialize / initialized

Mcp-Session-Id header, optional

2026-07-28 (RC)

none

removed; request metadata inline in _meta

ACP sessions are correlated by a path-scoped endpoint URL, one per agent run, so both revisions behave identically. See docs/design.md.

License

MIT. See LICENSE.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/s243a/mcp-acp-bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server