Skip to main content
Glama
choruzo
by choruzo
README.md
# claude-opencode-mcp

> **claude-opencode-mcp-v2** is a port of [putuandy/claude-opencode-mcp](https://github.com/putuandy/claude-opencode-mcp)
> (MIT) to the **OpenCode 2.x HTTP API** (`/api/*`, tested on 2.0.22). It does not work with OpenCode 1.x.
> Differences: one shared server for all workspaces, SSE-based completion, diffs from the server, agents named
> `researcher` / `reviewer` / `coder` / `tester` (the old `deepseek-*` names are still accepted).
> See [docs/v2-migration.md](docs/v2-migration.md) and [research/FINDINGS.md](research/FINDINGS.md). Status: alpha.


[![CI](https://github.com/putuandy/claude-opencode-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/putuandy/claude-opencode-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)

An MCP server that lets **Claude Code delegate software-engineering tasks to
OpenCode agents** — with the model and provider you choose — while keeping every agent inside the
same workspace/worktree.

```text
Claude Code (orchestrator)
     │  MCP
     ▼
claude-opencode-mcp (this bridge)
     │  workspace + task + agent
     ▼
OpenCode (agent runtime: tools, sessions, permissions)
     │
     ▼
your model provider (anything configured in OpenCode)
     │
     ▼
your repository — the same working tree Claude Code is using
```

Claude Code stays in charge: it decomposes the work, picks agents, reviews the
results and integrates changes. OpenCode does the repository exploration,
editing and test execution. The bridge is deliberately thin.

- [Features](#features)
- [Requirements](#requirements)
- [Install](#install)
- [Claude Code setup](#claude-code-setup)
- [OpenCode setup](#opencode-setup)
- [Choose a model per agent](#choose-a-model-per-agent)
- [Quick start](#quick-start)
- [Tools](#tools)
- [Agents](#agents)
- [Workspace model](#workspace-model)
- [Security](#security)
- [Configuration](#configuration)
- [Sessions](#sessions)
- [Troubleshooting](#troubleshooting)
- [Development](#development)
- [Documentation](#documentation)
- [License](#license)

## Features

- **Seven focused MCP tools** — `delegate_task`, `create_session`,
  `send_message`, `get_session`, `get_diff`, `abort_session`, `list_agents`.
- **Same worktree** — the delegated OpenCode server runs with your project as
  its working directory; the agent reads and edits the real files.
- **Persistent sessions** — follow-up messages keep the agent's context across
  separate MCP calls.
- **Four agent profiles** — researcher, reviewer, coder, tester, each with
  permissions enforced by OpenCode (not by prompt wording).
- **Workspace boundaries** — canonical paths, allowed roots, path-traversal
  rejection, and a per-run probe that proves the server is serving the right
  directory.
- **Safety defaults** — `.env`/credential protection, `git commit`/`git push`
  denied, external directories denied, no `ask` rules that could hang a
  headless run.
- **Structured results** — every tool returns JSON with stable error codes, and
  `get_diff` gives Claude Code the exact changes a coding session made.
- **Reliability** — timeouts, cancellation, health checks, crash detection,
  graceful shutdown, request IDs and a rotating log file.

## Requirements

| Component | Version |
| --- | --- |
| Node.js | 20 or newer |
| [Claude Code](https://docs.claude.com/en/docs/claude-code) | recent 2.x |
| [OpenCode](https://opencode.ai) | **2.x** (tested against 2.0.22; 1.x is not supported) |
| Model provider | Any provider configured in OpenCode. None is assumed: your OpenCode default model, or one you set per agent |

## Install

The package is published on npm (alpha channel):

```bash
npm install -g claude-opencode-mcp-v2@alpha
```

or run it on demand with `npx -y claude-opencode-mcp-v2@alpha` (recommended for
`.mcp.json`). It installs two executables, `claude-opencode-mcp-v2` (the MCP
server) and `claude-opencode-v2` (same binary).

The bridge finds OpenCode in `PATH`, in `node_modules/.bin`, in
`~/.opencode/bin`, or at an explicit `OPENCODE_BIN` / `opencode.binary`.

### From source

```bash
git clone https://github.com/choruzo/claude-opencode-mcp-v2.git
cd claude-opencode-mcp-v2
npm install
npm run build
npm install -g .
```

## Claude Code setup

### Option A — project `.mcp.json` (recommended)

Create `.mcp.json` in your project root:

```json
{
  "mcpServers": {
    "opencode": {
      "command": "npx",
      "args": ["-y", "claude-opencode-mcp-v2@alpha"],
      "type": "stdio",
      "timeout": 600000
    }
  }
}
```

`timeout` is milliseconds and is a **per-tool-call** wall-clock limit. Delegated
runs are long; without it Claude Code falls back to `MCP_TOOL_TIMEOUT`.
Claude Code also moves main-conversation tool calls to a background task after
two minutes, which is fine — the result arrives when the run finishes.

### Option B — `claude mcp add`

```bash
claude mcp add opencode --scope project -- npx -y claude-opencode-mcp-v2@alpha
```

Or for one machine only:

```bash
claude mcp add opencode --scope user -- npx -y claude-opencode-mcp-v2@alpha
```

Verify:

```bash
claude mcp list        # opencode ... ✔ Connected
```

Inside Claude Code, `/mcp` shows the server and its seven tools.

> The bridge reads `CLAUDE_PROJECT_DIR`, which Claude Code sets for stdio MCP
> servers, so delegation defaults to the project you launched Claude Code in.

## OpenCode setup

The bridge starts and stops its own headless OpenCode server, so you do not need
to run `opencode serve` yourself. You only need OpenCode 2.x installed and at
least one provider authenticated.

1. **Install OpenCode 2.x** and check the version

   ```bash
   opencode --version     # 2.x
   ```

2. **Authenticate a provider** (once), or define it in your OpenCode config

   ```bash
   opencode auth login
   ```

3. **List the models you can use** — the ids you will put in the bridge config
   are `provider/model`:

   ```bash
   opencode models
   # nan/deepseek-v4-flash
   # nan/glm5.3-flash
   # ...
   ```

4. **(Optional) validate the project**

   ```bash
   cd my-project
   claude-opencode-v2 init
   ```

   `init` only creates `.claude-opencode/` and validates the environment; it
   never modifies source code and is not required for delegation.

> The OpenCode server started by the bridge also loads **your global OpenCode
> config** (`~/.config/opencode`), including its MCP servers and providers.

If you prefer to control OpenCode yourself, start `opencode serve` and point
the bridge at it with `opencode.url` (plus `opencode.password` or
`OPENCODE_SERVER_PASSWORD`, user `opencode`); see
[docs/configuration.md](docs/configuration.md#connecting-to-an-existing-opencode-server).

## Choose a model per agent

Nothing is assumed: if you configure nothing, every agent uses **your own default
model in OpenCode**. To pick models, create `~/.config/claude-opencode-mcp/config.json`
(all projects) or `.claude-opencode/config.json` in a project:

```json
{
  "agents": {
    "researcher": { "model": "nan/deepseek-v4-flash" },
    "reviewer":   { "model": "nan/deepseek-v4-flash" },
    "tester":     { "model": "nan/deepseek-v4-flash" },
    "coder":      { "model": "nan/glm5.3-flash" }
  }
}
```

Use the exact `provider/model` ids from `opencode models`. Order of precedence:
the `model` argument of a tool call, then `agents.<name>.model`, then
`defaults.model`, then your OpenCode default. A bare id (no `provider/`) is looked up
in OpenCode's catalog and must match exactly one provider. Full reference:
[docs/configuration.md](docs/configuration.md) and
[docs/agent-configuration.md](docs/agent-configuration.md).

## Quick start

Restart Claude Code, then ask:

> Use the `opencode` MCP server to have `researcher` map this
> repository: entry points, main modules, and where authentication lives.

Then something that edits:

> Have `coder` add input validation to `src/api/users.ts`, run the
> tests, and report what changed. Then show me the diff with `get_diff`.

And a full workflow:

> Ask the agents to inspect the authentication system, identify potential issues,
> implement a fix, and review the changes.

Claude Code typically orchestrates: `researcher` → `coder`
→ `reviewer` → `tester`, calling `get_diff` between steps.

## Tools

All tools return JSON in `content[0].text` (mirrored in `structuredContent`).
Errors return `isError: true` with `{ "error": { "code", "message", ... } }`.

### `delegate_task`

Run one task in a fresh session and wait for the agent's answer.

```json
{
  "task": "Review the authentication implementation for bugs and security issues.",
  "agent": "reviewer",
  "cwd": "/Users/andy/projects/my-app",
  "paths": ["src/auth", "src/middleware", "tests/auth"],
  "model": "deepseek/deepseek-v4-pro",
  "timeout": 600000,
  "allow_edits": false
}
```

Returns `{ status, session_id, agent, cwd, model, summary, findings,
files_changed, duration_ms, truncated, error? }`.

- `paths` are exploration hints, not a boundary — the agent may inspect the
  whole workspace.
- `allow_edits` / `allow_bash` grant or revoke edits and shell commands for the
  run (safe permission profiles; sensitive files and git history stay
  protected).
- `findings` are parsed from a `## Findings` section:
  `- [severity: high] Title (path/to/file:42) — detail`.

### `create_session`

```json
{ "cwd": "/abs/path", "agent": "researcher", "model": null, "title": "auth investigation", "allow_edits": true }
```

Returns `{ session_id, cwd, agent, model, title, status, can_edit, can_run_bash, created_at }`.
Permission overrides set here persist for the session.

### `send_message`

Continue a session; the agent keeps its context and permission level.

```json
{ "session_id": "ses_...", "message": "Now implement the fix.", "allow_edits": true }
```

`allow_edits` / `allow_bash` may change the level from this message onward.

### `get_session`

Returns the stored session state plus live OpenCode status
(`opencode.status` is `idle`, `busy` or `retry` when a server is running).

### `get_diff`

Returns the changes associated with a session:

- OpenCode's own session diff when the server reports one, otherwise
- a **git diff against a baseline captured when the session was created**, so
  pre-existing uncommitted work is not attributed to the agent.

Returns `{ source, files, diff, truncated, note? }`.

### `abort_session`

Stops a running delegation. Safe to call when the session is idle.

### `list_agents`

Lists the built-in agents plus project-local agents from
`.claude-opencode/agents/`, with `read_only`, `can_edit`, `can_run_bash` flags.

## Agents

| Agent | Purpose | Edit default | Shell default |
| --- | --- | --- | --- |
| `researcher` | architecture, exploration, dependency analysis, recommendations | deny | deny |
| `reviewer` | code review, bugs, regressions, security, architecture | deny | deny |
| `coder` | implementation, refactoring, running tests and fixing failures | allow | allow (no `git commit`/`git push`) |
| `tester` | run tests, inspect failures, root causes, suggested fixes | deny | allow (no `git commit`/`git push`) |

The orchestrator is not limited to those defaults: every tool that starts or
continues a run accepts `allow_edits` and `allow_bash` (`true` grants, `false`
revokes, omitted keeps the default). Grants map to safe permission profiles, so
`allow_edits: true` still protects `.env`/credential files and `allow_bash: true`
still denies git history changes. A researcher with write access is one call:

```json
{
  "agent": "researcher",
  "task": "Investigate the caching layer, then implement and test the fix.",
  "allow_edits": true,
  "allow_bash": true
}
```

Agent prompts live in [`agents/`](agents/) and are loaded into the OpenCode
server configuration at startup. Project-local copies in
`.claude-opencode/agents/*.md` override the prompt, description, model and
temperature; permissions always come from the bridge policy (configurable
through `security.*` and the per-call overrides).

See [docs/agent-configuration.md](docs/agent-configuration.md) for frontmatter
details and custom agents.

## Workspace model

Resolution order for every call:

1. explicit `cwd` argument
2. `CLAUDE_PROJECT_DIR` (set by Claude Code)
3. the MCP server process working directory
4. `workspace.defaultCwd` from configuration

The first two are *required*: if they are present but invalid, the call fails
instead of silently using a different directory.

Validation happens before any session is created:

- the path must exist, be a directory, and be readable;
- it is canonicalized with `realpath`;
- when `workspace.allowedRoots` is set, the canonical path must live inside one
  of those roots (traversal is rejected);
- the git root is detected for diff isolation.

During the first request for a workspace the bridge reads back `directory` from
the OpenCode server and compares it with the requested path, so a misrouted
request can never reach the wrong repository.

A single OpenCode 2 server is started (or `opencode.url` is used) and shared by
all workspaces; each session is bound to its directory through `location.directory`.

## Security

| Control | Default | Where |
| --- | --- | --- |
| Workspace must exist, be readable, be a directory | always | bridge |
| `workspace.allowedRoots` containment | disabled (empty) | config |
| Path hints cannot escape the workspace | always | bridge |
| `.env`/`.env.*`, keys, `credentials`, `.ssh/*` protection | on, even when edits are granted | OpenCode permissions |
| `git commit` / `git push` for shell-enabled agents | denied, even when shell is granted | OpenCode permissions |
| Paths outside the workspace | denied | OpenCode `external_directory` |
| Subagent spawning (`task`) | denied | OpenCode permissions |
| Interactive questions (`question`) | denied (headless) | OpenCode permissions |
| `ask` permission rules | never emitted by the bridge | OpenCode permissions |

The bridge also listens to OpenCode's event stream and **auto-rejects** any
permission request that would otherwise wait for a human, so a delegated run can
never hang on approval.

Caveats, stated plainly:

- A shell-enabled agent (`coder`, `tester`) can technically write files through
  shell commands. The bridge denies the `edit` tools for the tester and forbids
  git history changes for both, but shell access is inherently powerful.
- `.env` protection applies to the file tools. A shell-enabled agent could still
  `cat` a file through `bash`; the OpenCode project permission model has the
  same property.
- When connecting to an **external** OpenCode server (`opencode.url`), the
  bridge cannot inject agent permissions. It verifies the agents exist and
  refuses to run otherwise.

Details and hardening options: [docs/security.md](docs/security.md).

## Configuration

Global file: `~/.config/claude-opencode-mcp/config.json` (honours
`XDG_CONFIG_HOME`).
Project file: `<project>/.claude-opencode/config.json` (overrides global).
Extra file: `CLAUDE_OPENCODE_CONFIG=/path/to/config.json` (highest precedence).

```json
{
  "opencode": {
    "url": null,
    "autoStart": true,
    "hostname": "127.0.0.1",
    "port": 0,
    "startupTimeout": 30000,
    "binary": null,
    "username": null,
    "password": null
  },
  "workspace": {
    "allowedRoots": [],
    "defaultCwd": null
  },
  "defaults": {
    "agent": "researcher",
    "provider": null,
    "model": null
  },
  "timeouts": {
    "execution": 600000
  },
  "security": {
    "protectEnvFiles": true,
    "denyGitPush": true,
    "denyGitCommit": true,
    "externalDirectory": "deny",
    "extraProtectedPatterns": []
  },
  "limits": {
    "summaryChars": 6000,
    "sessionChars": 20000,
    "diffChars": 60000
  },
  "agents": {
    "researcher": { "model": "deepseek/deepseek-v4-pro" }
  }
}
```

- `defaults.model` accepts `provider/model` or a bare model id (completed with
  `defaults.provider` if set, otherwise looked up in OpenCode's catalog; ambiguous ids are rejected). When `null`, your own default model from OpenCode
  is used.
- Provider credentials stay in OpenCode (`opencode auth login`) or environment
  variables; they are never duplicated in this config.
- For auto-started servers the bridge passes `OPENCODE_SERVER_USERNAME` /
  `OPENCODE_SERVER_PASSWORD` through and authenticates its own requests. For
  external URLs it only uses credentials you configure.

Full reference: [docs/configuration.md](docs/configuration.md).

## Sessions

- Sessions are OpenCode sessions; the bridge keeps a small registry at
  `~/.local/state/claude-opencode-mcp/sessions.json` (override with
  `CLAUDE_OPENCODE_STATE_DIR`) so `get_session`, `get_diff` and `send_message`
  survive a bridge restart.
- Records older than 14 days are pruned at startup.
- If an OpenCode server restarts, persisted sessions are still addressable;
  `get_session` reports live status when a server is running.
- Logs: `~/.local/state/claude-opencode-mcp/bridge.log` (rotated at 5 MB).
  Set `CLAUDE_OPENCODE_LOG=debug|info|warn|error|silent`.

## Troubleshooting

| Symptom | Fix |
| --- | --- |
| `OPENCODE_NOT_AVAILABLE` | `npm install -g opencode-ai` or set `OPENCODE_BIN` / `opencode.binary`. |
| `OPENCODE_START_TIMEOUT` | run `opencode serve` manually to see the error; raise `opencode.startupTimeout`; check `OPENCODE_SERVER_PASSWORD` handling. |
| `MODEL_NOT_AVAILABLE` | authenticate a provider (`opencode auth login`) or set `defaults.model`, e.g. `"deepseek/deepseek-v4-pro"`. |
| `ProviderAuthError` in a result | The provider credentials are missing or expired; re-run `opencode auth login`. |
| `AGENT_NOT_FOUND` with an external server | add the four agents to that server's config or stop using `opencode.url`. |
| `AGENT_TIMEOUT` | raise `timeouts.execution` or the `timeout` argument; consider a narrower task. |
| `WORKSPACE_NOT_ALLOWED` | add the project to `workspace.allowedRoots` or clear the list. |
| Tool call seems to hang in Claude Code | Claude Code backgrounds long calls after 2 minutes; progress notifications are sent, and the bridge always resolves or aborts — check `bridge.log`. |
| Claude Code kills the call at 60s | set `"timeout": 600000` in the `.mcp.json` entry (or `MCP_TOOL_TIMEOUT`). |

More: [docs/troubleshooting.md](docs/troubleshooting.md).

## Development

```bash
npm install
npm run lint        # Biome
npm run typecheck
npm test            # unit + integration (no OpenCode needed)
npm run build
```

Real end-to-end tests need an OpenCode 2.x install with a provider authenticated:

```bash
npm run test:e2e                                  # checkpoints: workspace, agents, sessions, diff, abort, stdio
CLAUDE_OPENCODE_E2E_WORKFLOW=1 npm run test:e2e   # full researcher → coder → reviewer → tester workflow
```

Layout:

```text
src/
  index.ts              CLI entry (MCP server + `init`)
  cli/                  `claude-opencode-v2 init`
  config/               configuration loading and merging
  workspace/            resolver, validator, task context
  security/             path policy + OpenCode permission profiles
  opencode/             binary resolution, manager, client, agents, sessions, runner
  mcp/                  MCP server and the seven tools
agents/                 built-in agent prompts
tests/                  unit, integration, e2e
docs/                   documentation
```

See [docs/development.md](docs/development.md) and
[docs/architecture.md](docs/architecture.md).

## Documentation

- [Installation](docs/installation.md)
- [Configuration](docs/configuration.md)
- [Claude Code setup](docs/claude-code-setup.md)
- [OpenCode setup](docs/opencode-setup.md)
- [DeepSeek setup](docs/deepseek-setup.md)
- [Agent configuration](docs/agent-configuration.md)
- [Workspace model](docs/workspace-model.md)
- [Security](docs/security.md)
- [Security audit](docs/security-audit.md)
- [Troubleshooting](docs/troubleshooting.md)
- [Architecture](docs/architecture.md)
- [Development](docs/development.md)
- [Contributing](CONTRIBUTING.md)
- [Changelog](CHANGELOG.md)
- [Security policy](SECURITY.md)
- [Code of Conduct](CODE_OF_CONDUCT.md)

## Contributing

Bug reports, feature requests, and pull requests are welcome. Start with
[CONTRIBUTING.md](CONTRIBUTING.md); for vulnerabilities use
[SECURITY.md](SECURITY.md) instead of a public issue.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation4/5

Most tools map cleanly to distinct resources and actions (get_session/get_diff/abort_session/list_agents). The only fuzzy boundary is delegate_task vs. create_session+send_message, since a one-shot task is essentially create+send combined, but the descriptions explicitly distinguish one-shot vs. persistent session workflows.

Naming Consistency5/5

Every tool follows a clean verb_noun pattern (delegate_task, create_session, send_message, get_session, get_diff, abort_session, list_agents). No style mixing or vague verbs.

Tool Count5/5

Seven tools is well-scoped for a delegation bridge: session lifecycle, message continuation, diff inspection, abort, and agent discovery. Each tool earns its place with no redundant surface.

Completeness4/5

The session lifecycle is well covered (create, send, get, diff, abort, delegate, list_agents). Minor gaps: no list_sessions to enumerate existing sessions and no explicit close/delete, though abort_session partially fills the teardown role.

Maintenance

ActivityMaintained
ResponsivenessNo issues