Skip to main content
Glama
phenasdev

devin-mcp-bridge

by phenasdev

devin-mcp-bridge

Lets Claude Code delegate work to Devin.

Claude Code  ──MCP/stdio──▶  devin-mcp-bridge  ──ACP/stdio──▶  devin acp

Devin ships an ACP agent (devin acp), which is what makes it usable from Zed. Claude Code speaks MCP, not ACP. This process sits in the middle: it is an ACP client toward Devin (spawning the agent, answering its filesystem and permission requests) and an MCP server toward Claude Code.

Tools

Tool

Purpose

devin_task({ task, cwd? })

Send a task to Devin, return its full response. Session persists per cwd, so follow-up calls keep context.

devin_reset({ cwd? })

Kill the agent and drop its context. Next devin_task starts fresh.

Install

git clone https://github.com/phenasdev/devin-mcp-bridge.git
cd devin-mcp-bridge
npm install
npm run smoke          # boots the server, lists tools — no Devin needed
npm run smoke:call     # full turn against a fake ACP agent
npm run smoke:sandbox  # verifies symlinks cannot escape the session root

Register with Claude Code, using an absolute path to your clone:

# this project only
claude mcp add devin -- node "$PWD/src/devin-mcp.mjs"

# every project
claude mcp add -s user devin -- node "$PWD/src/devin-mcp.mjs"

Verify with /mcp inside Claude Code. Tool names appear as mcp__devin__devin_task.

Security

Devin runs autonomously and, over ACP, asks this process for permission and for filesystem access. Two controls exist, both on by default:

  • DEVIN_MCP_PERMISSION=once (default) — grant only one-shot permissions; never allow_always, which would remove the decision for the rest of the session. all approves everything including persistent grants. deny refuses everything.

  • DEVIN_MCP_SANDBOX_FS=1 (default) — fs/read_text_file and fs/write_text_file are confined to the session root; paths resolving outside it, including through symlinks, are rejected. Set 0 to disable. This path check is not an OS sandbox and cannot prevent a concurrent filesystem race.

When the bridge refuses a request, the turn result carries a [bridge] ... refused block naming the operation and path. Without it a sandbox rejection reaches Claude Code as a bare [tool failed], indistinguishable from a genuine Devin error.

There is no human in the loop on permission decisions — Claude Code sees one tool call, while Devin may perform many actions behind it. Before pointing this at a repo you care about, prefer a disposable worktree or a container, and keep the sandbox on.

Config

Env var

Default

Meaning

DEVIN_MCP_AGENT_CMD

devin

Agent binary. Set to npx to bridge a different ACP agent.

DEVIN_MCP_AGENT_ARGS

acp

Space-separated args.

DEVIN_MCP_PERMISSION

once

once | all | deny

DEVIN_MCP_SANDBOX_FS

1

0 disables the path guard.

DEVIN_MCP_TIMEOUT_MS

900000

Per-turn cap; the turn is cancelled on expiry.

Because the agent command is configurable, the same bridge works for any ACP agent — e.g. DEVIN_MCP_AGENT_CMD=npx DEVIN_MCP_AGENT_ARGS="-y @zed-industries/claude-code-acp".

Debugging

Agent stderr is inherited, so claude --debug shows both the bridge's [devin-mcp] log lines and Devin's own output. claude mcp list shows connection status.

Layout

  • src/devin-mcp.mjs — the bridge; ACP client + MCP server in one process.

  • scripts/fake-agent.mjs — minimal ACP agent used by the smoke test, so the wiring can be exercised without opening a real Devin session. It also probes the fs sandbox.

  • scripts/smoke.mjs — MCP handshake, tools/list, and optionally one full turn.