claude-opencode-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENSE +21 -0
  3. package/README.md +514 -0
  4. package/SECURITY.md +80 -0
  5. package/agents/deepseek-coder.md +32 -0
  6. package/agents/deepseek-researcher.md +36 -0
  7. package/agents/deepseek-reviewer.md +31 -0
  8. package/agents/deepseek-tester.md +31 -0
  9. package/dist/cli/init.d.ts +6 -0
  10. package/dist/cli/init.js +208 -0
  11. package/dist/cli/init.js.map +1 -0
  12. package/dist/config/config.d.ts +109 -0
  13. package/dist/config/config.js +163 -0
  14. package/dist/config/config.js.map +1 -0
  15. package/dist/errors.d.ts +29 -0
  16. package/dist/errors.js +68 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.js +116 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/mcp/execute.d.ts +30 -0
  22. package/dist/mcp/execute.js +128 -0
  23. package/dist/mcp/execute.js.map +1 -0
  24. package/dist/mcp/server.d.ts +19 -0
  25. package/dist/mcp/server.js +38 -0
  26. package/dist/mcp/server.js.map +1 -0
  27. package/dist/mcp/session-utils.d.ts +5 -0
  28. package/dist/mcp/session-utils.js +55 -0
  29. package/dist/mcp/session-utils.js.map +1 -0
  30. package/dist/mcp/tool-utils.d.ts +11 -0
  31. package/dist/mcp/tool-utils.js +44 -0
  32. package/dist/mcp/tool-utils.js.map +1 -0
  33. package/dist/mcp/tools/abort-session.d.ts +3 -0
  34. package/dist/mcp/tools/abort-session.js +48 -0
  35. package/dist/mcp/tools/abort-session.js.map +1 -0
  36. package/dist/mcp/tools/create-session.d.ts +3 -0
  37. package/dist/mcp/tools/create-session.js +53 -0
  38. package/dist/mcp/tools/create-session.js.map +1 -0
  39. package/dist/mcp/tools/delegate-task.d.ts +4 -0
  40. package/dist/mcp/tools/delegate-task.js +98 -0
  41. package/dist/mcp/tools/delegate-task.js.map +1 -0
  42. package/dist/mcp/tools/get-diff.d.ts +3 -0
  43. package/dist/mcp/tools/get-diff.js +97 -0
  44. package/dist/mcp/tools/get-diff.js.map +1 -0
  45. package/dist/mcp/tools/get-session.d.ts +3 -0
  46. package/dist/mcp/tools/get-session.js +79 -0
  47. package/dist/mcp/tools/get-session.js.map +1 -0
  48. package/dist/mcp/tools/list-agents.d.ts +3 -0
  49. package/dist/mcp/tools/list-agents.js +72 -0
  50. package/dist/mcp/tools/list-agents.js.map +1 -0
  51. package/dist/mcp/tools/send-message.d.ts +3 -0
  52. package/dist/mcp/tools/send-message.js +59 -0
  53. package/dist/mcp/tools/send-message.js.map +1 -0
  54. package/dist/opencode/agents.d.ts +46 -0
  55. package/dist/opencode/agents.js +239 -0
  56. package/dist/opencode/agents.js.map +1 -0
  57. package/dist/opencode/binary.d.ts +19 -0
  58. package/dist/opencode/binary.js +129 -0
  59. package/dist/opencode/binary.js.map +1 -0
  60. package/dist/opencode/client.d.ts +32 -0
  61. package/dist/opencode/client.js +55 -0
  62. package/dist/opencode/client.js.map +1 -0
  63. package/dist/opencode/manager.d.ts +66 -0
  64. package/dist/opencode/manager.js +492 -0
  65. package/dist/opencode/manager.js.map +1 -0
  66. package/dist/opencode/permission-watcher.d.ts +26 -0
  67. package/dist/opencode/permission-watcher.js +144 -0
  68. package/dist/opencode/permission-watcher.js.map +1 -0
  69. package/dist/opencode/run.d.ts +39 -0
  70. package/dist/opencode/run.js +318 -0
  71. package/dist/opencode/run.js.map +1 -0
  72. package/dist/opencode/sessions.d.ts +26 -0
  73. package/dist/opencode/sessions.js +105 -0
  74. package/dist/opencode/sessions.js.map +1 -0
  75. package/dist/opencode/setup.d.ts +38 -0
  76. package/dist/opencode/setup.js +109 -0
  77. package/dist/opencode/setup.js.map +1 -0
  78. package/dist/security/paths.d.ts +20 -0
  79. package/dist/security/paths.js +93 -0
  80. package/dist/security/paths.js.map +1 -0
  81. package/dist/security/policy.d.ts +17 -0
  82. package/dist/security/policy.js +86 -0
  83. package/dist/security/policy.js.map +1 -0
  84. package/dist/types/index.d.ts +131 -0
  85. package/dist/types/index.js +2 -0
  86. package/dist/types/index.js.map +1 -0
  87. package/dist/util/fs.d.ts +12 -0
  88. package/dist/util/fs.js +73 -0
  89. package/dist/util/fs.js.map +1 -0
  90. package/dist/util/git.d.ts +54 -0
  91. package/dist/util/git.js +202 -0
  92. package/dist/util/git.js.map +1 -0
  93. package/dist/util/logger.d.ts +21 -0
  94. package/dist/util/logger.js +129 -0
  95. package/dist/util/logger.js.map +1 -0
  96. package/dist/util/text.d.ts +11 -0
  97. package/dist/util/text.js +126 -0
  98. package/dist/util/text.js.map +1 -0
  99. package/dist/workspace/context.d.ts +12 -0
  100. package/dist/workspace/context.js +67 -0
  101. package/dist/workspace/context.js.map +1 -0
  102. package/dist/workspace/resolver.d.ts +35 -0
  103. package/dist/workspace/resolver.js +112 -0
  104. package/dist/workspace/resolver.js.map +1 -0
  105. package/dist/workspace/validator.d.ts +13 -0
  106. package/dist/workspace/validator.js +102 -0
  107. package/dist/workspace/validator.js.map +1 -0
  108. package/docs/agent-configuration.md +100 -0
  109. package/docs/architecture.md +115 -0
  110. package/docs/claude-code-setup.md +116 -0
  111. package/docs/configuration.md +184 -0
  112. package/docs/contributing.md +71 -0
  113. package/docs/deepseek-setup.md +84 -0
  114. package/docs/development.md +146 -0
  115. package/docs/installation.md +88 -0
  116. package/docs/opencode-setup.md +97 -0
  117. package/docs/security-audit.md +80 -0
  118. package/docs/security.md +128 -0
  119. package/docs/troubleshooting.md +126 -0
  120. package/docs/workspace-model.md +126 -0
  121. package/package.json +79 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.0.0] - 2026-09-24
11
+
12
+ First stable release.
13
+
14
+ ### Added
15
+
16
+ - MCP stdio server with seven tools: `delegate_task`, `create_session`,
17
+ `send_message`, `get_session`, `get_diff`, `abort_session`, `list_agents`.
18
+ - OpenCode runtime management: lazy start of one headless server per workspace,
19
+ health checks, LRU eviction (`opencode.maxServers`), crash detection,
20
+ graceful shutdown, and no orphaned processes.
21
+ - Agent system with four profiles enforced through OpenCode permissions:
22
+ `deepseek-researcher`, `deepseek-reviewer` (read-only),
23
+ `deepseek-coder` (edits + shell), `deepseek-tester` (shell, no edits).
24
+ - Workspace resolution (`cwd` → `CLAUDE_PROJECT_DIR` → process cwd →
25
+ configured default) with canonical-path validation, allowed roots, git-root
26
+ detection, and a per-workspace routing probe (`WORKSPACE_MISMATCH`).
27
+ - Persistent sessions: `create_session` / `send_message` keep agent context;
28
+ registry stored at `~/.local/state/claude-opencode-mcp/sessions.json`
29
+ (mode `0600`) and pruned after 14 days.
30
+ - `get_diff` for reviewing agent changes: OpenCode session diff when
31
+ available, otherwise a git diff against a baseline captured at session
32
+ creation (pre-existing dirty state is isolated).
33
+ - Reliability: per-run timeouts (`AGENT_TIMEOUT`), MCP cancellation
34
+ (`AGENT_ABORTED`), progress notifications, structured error codes, request
35
+ IDs, and a rotating `0600` log file.
36
+ - Security defaults: `.env`/key/credential read and edit protection, `git
37
+ commit`/`git push` denied for shell-enabled agents, `external_directory`
38
+ denied, no `ask` permission rules, and auto-rejection of stray permission
39
+ requests so headless runs cannot hang. Log fields matching
40
+ password/secret/token/api-key patterns are redacted.
41
+ - Configuration layering: global (`~/.config/claude-opencode-mcp/config.json`),
42
+ project (`.claude-opencode/config.json`), explicit
43
+ (`CLAUDE_OPENCODE_CONFIG`), with deep merge and Zod validation.
44
+ - `claude-opencode init` validator/scaffolder (config + agent files, optional
45
+ `.mcp.json`) and `claude-opencode-mcp` executable for `npx`.
46
+ - Documentation set covering installation, configuration, Claude Code, OpenCode,
47
+ DeepSeek, agents, workspace model, security, architecture, development,
48
+ contributing, and troubleshooting.
49
+ - Test suite: unit and integration tests with a fake OpenCode server, plus
50
+ opt-in real OpenCode/DeepSeek E2E checkpoints and a full multi-agent
51
+ workflow acceptance test.
52
+ - CI across Node 20/22/24 (Ubuntu) and Node 24 (macOS), plus an opt-in,
53
+ push-only real-provider E2E job.
54
+
55
+ [Unreleased]: https://github.com/putuandy/claude-opencode-mcp/compare/v1.0.0...HEAD
56
+ [1.0.0]: https://github.com/putuandy/claude-opencode-mcp/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 claude-opencode-mcp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,514 @@
1
+ # claude-opencode-mcp
2
+
3
+ [![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)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+ [![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
6
+
7
+ An MCP server that lets **Claude Code delegate software-engineering tasks to
8
+ OpenCode agents** — DeepSeek by default — while keeping every agent inside the
9
+ same workspace/worktree.
10
+
11
+ ```text
12
+ Claude Code (orchestrator)
13
+ │ MCP
14
+ ▼
15
+ claude-opencode-mcp (this bridge)
16
+ │ workspace + task + agent
17
+ ▼
18
+ OpenCode (agent runtime: tools, sessions, permissions)
19
+ │
20
+ ▼
21
+ DeepSeek (or any provider configured in OpenCode)
22
+ │
23
+ ▼
24
+ your repository — the same working tree Claude Code is using
25
+ ```
26
+
27
+ Claude Code stays in charge: it decomposes the work, picks agents, reviews the
28
+ results and integrates changes. OpenCode does the repository exploration,
29
+ editing and test execution. The bridge is deliberately thin.
30
+
31
+ - [Features](#features)
32
+ - [Requirements](#requirements)
33
+ - [Install](#install)
34
+ - [Claude Code setup](#claude-code-setup)
35
+ - [OpenCode + DeepSeek setup](#opencode--deepseek-setup)
36
+ - [Quick start](#quick-start)
37
+ - [Tools](#tools)
38
+ - [Agents](#agents)
39
+ - [Workspace model](#workspace-model)
40
+ - [Security](#security)
41
+ - [Configuration](#configuration)
42
+ - [Sessions](#sessions)
43
+ - [Troubleshooting](#troubleshooting)
44
+ - [Development](#development)
45
+ - [Documentation](#documentation)
46
+ - [License](#license)
47
+
48
+ ## Features
49
+
50
+ - **Seven focused MCP tools** — `delegate_task`, `create_session`,
51
+ `send_message`, `get_session`, `get_diff`, `abort_session`, `list_agents`.
52
+ - **Same worktree** — the delegated OpenCode server runs with your project as
53
+ its working directory; the agent reads and edits the real files.
54
+ - **Persistent sessions** — follow-up messages keep the agent's context across
55
+ separate MCP calls.
56
+ - **Four agent profiles** — researcher, reviewer, coder, tester, each with
57
+ permissions enforced by OpenCode (not by prompt wording).
58
+ - **Workspace boundaries** — canonical paths, allowed roots, path-traversal
59
+ rejection, and a per-run probe that proves the server is serving the right
60
+ directory.
61
+ - **Safety defaults** — `.env`/credential protection, `git commit`/`git push`
62
+ denied, external directories denied, no `ask` rules that could hang a
63
+ headless run.
64
+ - **Structured results** — every tool returns JSON with stable error codes, and
65
+ `get_diff` gives Claude Code the exact changes a coding session made.
66
+ - **Reliability** — timeouts, cancellation, health checks, crash detection,
67
+ graceful shutdown, request IDs and a rotating log file.
68
+
69
+ ## Requirements
70
+
71
+ | Component | Version |
72
+ | --- | --- |
73
+ | Node.js | 20 or newer |
74
+ | [Claude Code](https://docs.claude.com/en/docs/claude-code) | recent 2.x |
75
+ | [OpenCode](https://opencode.ai) | 1.18+ (tested against 1.18.32) |
76
+ | Model provider | DeepSeek by default; any provider OpenCode supports |
77
+
78
+ ## Install
79
+
80
+ ```bash
81
+ npm install -g claude-opencode-mcp
82
+ ```
83
+
84
+ or run it on demand with `npx -y claude-opencode-mcp` (recommended for
85
+ `.mcp.json`).
86
+
87
+ The bridge can also use an OpenCode installation from `PATH`, from
88
+ `node_modules/.bin`, from `~/.opencode/bin`, or from an explicit
89
+ `OPENCODE_BIN`.
90
+
91
+ ### From source
92
+
93
+ ```bash
94
+ git clone https://github.com/putuandy/claude-opencode-mcp.git
95
+ cd claude-opencode-mcp
96
+ npm install
97
+ npm run build
98
+ npm install -g .
99
+ ```
100
+
101
+ ## Claude Code setup
102
+
103
+ ### Option A — project `.mcp.json` (recommended)
104
+
105
+ Create `.mcp.json` in your project root:
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "opencode": {
111
+ "command": "npx",
112
+ "args": ["-y", "claude-opencode-mcp"],
113
+ "type": "stdio",
114
+ "timeout": 600000
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ `timeout` is milliseconds and is a **per-tool-call** wall-clock limit. Delegated
121
+ runs are long; without it Claude Code falls back to `MCP_TOOL_TIMEOUT`.
122
+ Claude Code also moves main-conversation tool calls to a background task after
123
+ two minutes, which is fine — the result arrives when the run finishes.
124
+
125
+ ### Option B — `claude mcp add`
126
+
127
+ ```bash
128
+ claude mcp add opencode --scope project -- npx -y claude-opencode-mcp
129
+ ```
130
+
131
+ Or for one machine only:
132
+
133
+ ```bash
134
+ claude mcp add opencode --scope user -- npx -y claude-opencode-mcp
135
+ ```
136
+
137
+ Verify:
138
+
139
+ ```bash
140
+ claude mcp list # opencode ... ✔ Connected
141
+ ```
142
+
143
+ Inside Claude Code, `/mcp` shows the server and its seven tools.
144
+
145
+ > The bridge reads `CLAUDE_PROJECT_DIR`, which Claude Code sets for stdio MCP
146
+ > servers, so delegation defaults to the project you launched Claude Code in.
147
+
148
+ ## OpenCode + DeepSeek setup
149
+
150
+ The bridge starts and stops its own headless OpenCode server, so you do not need
151
+ to run `opencode serve` yourself. You only need OpenCode installed and a
152
+ provider authenticated.
153
+
154
+ 1. **Install OpenCode**
155
+
156
+ ```bash
157
+ npm install -g opencode-ai
158
+ # or: brew install sst/tap/opencode
159
+ opencode --version
160
+ ```
161
+
162
+ 2. **Authenticate DeepSeek** (once)
163
+
164
+ ```bash
165
+ opencode auth login # choose DeepSeek, paste your API key
166
+ ```
167
+
168
+ Alternatively export `DEEPSEEK_API_KEY` before starting Claude Code; OpenCode
169
+ reads it for the `deepseek` provider.
170
+
171
+ 3. **Check the models**
172
+
173
+ ```bash
174
+ opencode models | grep deepseek
175
+ # deepseek/deepseek-flash
176
+ # deepseek/deepseek-v4-pro
177
+ ```
178
+
179
+ 4. **(Optional) validate the project**
180
+
181
+ ```bash
182
+ cd my-project
183
+ claude-opencode init
184
+ ```
185
+
186
+ `init` only creates `.claude-opencode/` and validates the environment; it
187
+ never modifies source code and is not required for delegation.
188
+
189
+ If you prefer to control OpenCode yourself, start `opencode serve` and point
190
+ the bridge at it with `opencode.url`; see
191
+ [docs/configuration.md](docs/configuration.md#connecting-to-an-existing-opencode-server).
192
+
193
+ ## Quick start
194
+
195
+ Restart Claude Code, then ask:
196
+
197
+ > Use the `opencode` MCP server to have `deepseek-researcher` map this
198
+ > repository: entry points, main modules, and where authentication lives.
199
+
200
+ Then something that edits:
201
+
202
+ > Have `deepseek-coder` add input validation to `src/api/users.ts`, run the
203
+ > tests, and report what changed. Then show me the diff with `get_diff`.
204
+
205
+ And a full workflow:
206
+
207
+ > Ask DeepSeek to inspect the authentication system, identify potential issues,
208
+ > implement a fix, and review the changes.
209
+
210
+ Claude Code typically orchestrates: `deepseek-researcher` → `deepseek-coder`
211
+ → `deepseek-reviewer` → `deepseek-tester`, calling `get_diff` between steps.
212
+
213
+ ## Tools
214
+
215
+ All tools return JSON in `content[0].text` (mirrored in `structuredContent`).
216
+ Errors return `isError: true` with `{ "error": { "code", "message", ... } }`.
217
+
218
+ ### `delegate_task`
219
+
220
+ Run one task in a fresh session and wait for the agent's answer.
221
+
222
+ ```json
223
+ {
224
+ "task": "Review the authentication implementation for bugs and security issues.",
225
+ "agent": "deepseek-reviewer",
226
+ "cwd": "/Users/andy/projects/my-app",
227
+ "paths": ["src/auth", "src/middleware", "tests/auth"],
228
+ "model": "deepseek/deepseek-v4-pro",
229
+ "timeout": 600000,
230
+ "allow_edits": false
231
+ }
232
+ ```
233
+
234
+ Returns `{ status, session_id, agent, cwd, model, summary, findings,
235
+ files_changed, duration_ms, truncated, error? }`.
236
+
237
+ - `paths` are exploration hints, not a boundary — the agent may inspect the
238
+ whole workspace.
239
+ - `allow_edits: false` disables the `edit`/`write`/`apply_patch` tools for that
240
+ call (the agent's own profile still applies; see [Security](#security)).
241
+ - `findings` are parsed from a `## Findings` section:
242
+ `- [severity: high] Title (path/to/file:42) — detail`.
243
+
244
+ ### `create_session`
245
+
246
+ ```json
247
+ { "cwd": "/abs/path", "agent": "deepseek-researcher", "model": null, "title": "auth investigation" }
248
+ ```
249
+
250
+ Returns `{ session_id, cwd, agent, model, title, status, created_at }`.
251
+
252
+ ### `send_message`
253
+
254
+ Continue a session; the agent keeps its context.
255
+
256
+ ```json
257
+ { "session_id": "ses_...", "message": "Now inspect the database layer for the same issue." }
258
+ ```
259
+
260
+ ### `get_session`
261
+
262
+ Returns the stored session state plus live OpenCode status
263
+ (`opencode.status` is `idle`, `busy` or `retry` when a server is running).
264
+
265
+ ### `get_diff`
266
+
267
+ Returns the changes associated with a session:
268
+
269
+ - OpenCode's own session diff when the server reports one, otherwise
270
+ - a **git diff against a baseline captured when the session was created**, so
271
+ pre-existing uncommitted work is not attributed to the agent.
272
+
273
+ Returns `{ source, files, diff, truncated, note? }`.
274
+
275
+ ### `abort_session`
276
+
277
+ Stops a running delegation. Safe to call when the session is idle.
278
+
279
+ ### `list_agents`
280
+
281
+ Lists the built-in agents plus project-local agents from
282
+ `.claude-opencode/agents/`, with `read_only`, `can_edit`, `can_run_bash` flags.
283
+
284
+ ## Agents
285
+
286
+ | Agent | Purpose | Edit | Shell |
287
+ | --- | --- | --- | --- |
288
+ | `deepseek-researcher` | architecture, exploration, dependency analysis, recommendations | deny | deny |
289
+ | `deepseek-reviewer` | code review, bugs, regressions, security, architecture | deny | deny |
290
+ | `deepseek-coder` | implementation, refactoring, running tests and fixing failures | allow | allow (no `git commit`/`git push`) |
291
+ | `deepseek-tester` | run tests, inspect failures, root causes, suggested fixes | deny | allow (no `git commit`/`git push`) |
292
+
293
+ Agent prompts live in [`agents/`](agents/) and are loaded into the OpenCode
294
+ server configuration at startup. Project-local copies in
295
+ `.claude-opencode/agents/*.md` override the prompt, description, model and
296
+ temperature; permissions always come from the bridge policy (configurable
297
+ through `security.*`).
298
+
299
+ See [docs/agent-configuration.md](docs/agent-configuration.md) for frontmatter
300
+ details and custom agents.
301
+
302
+ ## Workspace model
303
+
304
+ Resolution order for every call:
305
+
306
+ 1. explicit `cwd` argument
307
+ 2. `CLAUDE_PROJECT_DIR` (set by Claude Code)
308
+ 3. the MCP server process working directory
309
+ 4. `workspace.defaultCwd` from configuration
310
+
311
+ The first two are *required*: if they are present but invalid, the call fails
312
+ instead of silently using a different directory.
313
+
314
+ Validation happens before any session is created:
315
+
316
+ - the path must exist, be a directory, and be readable;
317
+ - it is canonicalized with `realpath`;
318
+ - when `workspace.allowedRoots` is set, the canonical path must live inside one
319
+ of those roots (traversal is rejected);
320
+ - the git root is detected for diff isolation.
321
+
322
+ During the first request for a workspace the bridge reads back `directory` from
323
+ the OpenCode server and compares it with the requested path, so a misrouted
324
+ request can never reach the wrong repository.
325
+
326
+ One OpenCode server is started per workspace directory and reused for all
327
+ sessions in that workspace; the server process itself runs with the workspace as
328
+ its working directory.
329
+
330
+ ## Security
331
+
332
+ | Control | Default | Where |
333
+ | --- | --- | --- |
334
+ | Workspace must exist, be readable, be a directory | always | bridge |
335
+ | `workspace.allowedRoots` containment | disabled (empty) | config |
336
+ | Path hints cannot escape the workspace | always | bridge |
337
+ | `.env`/`.env.*`, keys, `credentials`, `.ssh/*` protection | on | OpenCode permissions |
338
+ | `git commit` / `git push` for shell-enabled agents | denied | OpenCode permissions |
339
+ | Paths outside the workspace | denied | OpenCode `external_directory` |
340
+ | Subagent spawning (`task`) | denied | OpenCode permissions |
341
+ | Interactive questions (`question`) | denied (headless) | OpenCode permissions |
342
+ | `ask` permission rules | never emitted by the bridge | OpenCode permissions |
343
+
344
+ The bridge also listens to OpenCode's event stream and **auto-rejects** any
345
+ permission request that would otherwise wait for a human, so a delegated run can
346
+ never hang on approval.
347
+
348
+ Caveats, stated plainly:
349
+
350
+ - A shell-enabled agent (`coder`, `tester`) can technically write files through
351
+ shell commands. The bridge denies the `edit` tools for the tester and forbids
352
+ git history changes for both, but shell access is inherently powerful.
353
+ - `.env` protection applies to the file tools. A shell-enabled agent could still
354
+ `cat` a file through `bash`; the OpenCode project permission model has the
355
+ same property.
356
+ - When connecting to an **external** OpenCode server (`opencode.url`), the
357
+ bridge cannot inject agent permissions. It verifies the agents exist and
358
+ refuses to run otherwise.
359
+
360
+ Details and hardening options: [docs/security.md](docs/security.md).
361
+
362
+ ## Configuration
363
+
364
+ Global file: `~/.config/claude-opencode-mcp/config.json` (honours
365
+ `XDG_CONFIG_HOME`).
366
+ Project file: `<project>/.claude-opencode/config.json` (overrides global).
367
+ Extra file: `CLAUDE_OPENCODE_CONFIG=/path/to/config.json` (highest precedence).
368
+
369
+ ```json
370
+ {
371
+ "opencode": {
372
+ "url": null,
373
+ "autoStart": true,
374
+ "hostname": "127.0.0.1",
375
+ "port": 0,
376
+ "startupTimeout": 30000,
377
+ "binary": null,
378
+ "username": null,
379
+ "password": null,
380
+ "maxServers": 4
381
+ },
382
+ "workspace": {
383
+ "allowedRoots": [],
384
+ "defaultCwd": null
385
+ },
386
+ "defaults": {
387
+ "agent": "deepseek-researcher",
388
+ "provider": "deepseek",
389
+ "model": null
390
+ },
391
+ "timeouts": {
392
+ "execution": 600000
393
+ },
394
+ "security": {
395
+ "protectEnvFiles": true,
396
+ "denyGitPush": true,
397
+ "denyGitCommit": true,
398
+ "externalDirectory": "deny",
399
+ "extraProtectedPatterns": []
400
+ },
401
+ "limits": {
402
+ "summaryChars": 6000,
403
+ "sessionChars": 20000,
404
+ "diffChars": 60000
405
+ },
406
+ "agents": {
407
+ "deepseek-researcher": { "model": "deepseek/deepseek-v4-pro" }
408
+ }
409
+ }
410
+ ```
411
+
412
+ - `defaults.model` accepts `provider/model` or a bare model id (combined with
413
+ `defaults.provider`). When `null`, the provider's default model from OpenCode
414
+ is used.
415
+ - Provider credentials stay in OpenCode (`opencode auth login`) or environment
416
+ variables; they are never duplicated in this config.
417
+ - For auto-started servers the bridge passes `OPENCODE_SERVER_USERNAME` /
418
+ `OPENCODE_SERVER_PASSWORD` through and authenticates its own requests. For
419
+ external URLs it only uses credentials you configure.
420
+
421
+ Full reference: [docs/configuration.md](docs/configuration.md).
422
+
423
+ ## Sessions
424
+
425
+ - Sessions are OpenCode sessions; the bridge keeps a small registry at
426
+ `~/.local/state/claude-opencode-mcp/sessions.json` (override with
427
+ `CLAUDE_OPENCODE_STATE_DIR`) so `get_session`, `get_diff` and `send_message`
428
+ survive a bridge restart.
429
+ - Records older than 14 days are pruned at startup.
430
+ - If an OpenCode server restarts, persisted sessions are still addressable;
431
+ `get_session` reports live status when a server is running.
432
+ - Logs: `~/.local/state/claude-opencode-mcp/bridge.log` (rotated at 5 MB).
433
+ Set `CLAUDE_OPENCODE_LOG=debug|info|warn|error|silent`.
434
+
435
+ ## Troubleshooting
436
+
437
+ | Symptom | Fix |
438
+ | --- | --- |
439
+ | `OPENCODE_NOT_AVAILABLE` | `npm install -g opencode-ai` or set `OPENCODE_BIN` / `opencode.binary`. |
440
+ | `OPENCODE_START_TIMEOUT` | run `opencode serve` manually to see the error; raise `opencode.startupTimeout`; check `OPENCODE_SERVER_PASSWORD` handling. |
441
+ | `MODEL_NOT_AVAILABLE` | authenticate a provider (`opencode auth login`) or set `defaults.model`, e.g. `"deepseek/deepseek-v4-pro"`. |
442
+ | `ProviderAuthError` in a result | DeepSeek credentials are missing/expired; re-run `opencode auth login`. |
443
+ | `AGENT_NOT_FOUND` with an external server | add the four agents to that server's config or stop using `opencode.url`. |
444
+ | `AGENT_TIMEOUT` | raise `timeouts.execution` or the `timeout` argument; consider a narrower task. |
445
+ | `WORKSPACE_NOT_ALLOWED` | add the project to `workspace.allowedRoots` or clear the list. |
446
+ | 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`. |
447
+ | Claude Code kills the call at 60s | set `"timeout": 600000` in the `.mcp.json` entry (or `MCP_TOOL_TIMEOUT`). |
448
+
449
+ More: [docs/troubleshooting.md](docs/troubleshooting.md).
450
+
451
+ ## Development
452
+
453
+ ```bash
454
+ npm install
455
+ npm run lint # Biome
456
+ npm run typecheck
457
+ npm test # unit + integration (no OpenCode needed)
458
+ npm run build
459
+ ```
460
+
461
+ Real end-to-end tests need an OpenCode install with DeepSeek authenticated:
462
+
463
+ ```bash
464
+ npm run test:e2e # checkpoints: workspace, agents, sessions, diff, abort, stdio
465
+ CLAUDE_OPENCODE_E2E_WORKFLOW=1 npm run test:e2e # full researcher → coder → reviewer → tester workflow
466
+ ```
467
+
468
+ Layout:
469
+
470
+ ```text
471
+ src/
472
+ index.ts CLI entry (MCP server + `init`)
473
+ cli/ `claude-opencode init`
474
+ config/ configuration loading and merging
475
+ workspace/ resolver, validator, task context
476
+ security/ path policy + OpenCode permission profiles
477
+ opencode/ binary resolution, manager, client, agents, sessions, runner
478
+ mcp/ MCP server and the seven tools
479
+ agents/ built-in agent prompts
480
+ tests/ unit, integration, e2e
481
+ docs/ documentation
482
+ ```
483
+
484
+ See [docs/development.md](docs/development.md) and
485
+ [docs/architecture.md](docs/architecture.md).
486
+
487
+ ## Documentation
488
+
489
+ - [Installation](docs/installation.md)
490
+ - [Configuration](docs/configuration.md)
491
+ - [Claude Code setup](docs/claude-code-setup.md)
492
+ - [OpenCode setup](docs/opencode-setup.md)
493
+ - [DeepSeek setup](docs/deepseek-setup.md)
494
+ - [Agent configuration](docs/agent-configuration.md)
495
+ - [Workspace model](docs/workspace-model.md)
496
+ - [Security](docs/security.md)
497
+ - [Security audit](docs/security-audit.md)
498
+ - [Troubleshooting](docs/troubleshooting.md)
499
+ - [Architecture](docs/architecture.md)
500
+ - [Development](docs/development.md)
501
+ - [Contributing](CONTRIBUTING.md)
502
+ - [Changelog](CHANGELOG.md)
503
+ - [Security policy](SECURITY.md)
504
+ - [Code of Conduct](CODE_OF_CONDUCT.md)
505
+
506
+ ## Contributing
507
+
508
+ Bug reports, feature requests, and pull requests are welcome. Start with
509
+ [CONTRIBUTING.md](CONTRIBUTING.md); for vulnerabilities use
510
+ [SECURITY.md](SECURITY.md) instead of a public issue.
511
+
512
+ ## License
513
+
514
+ MIT — see [LICENSE](LICENSE).
package/SECURITY.md ADDED
@@ -0,0 +1,80 @@
1
+ # Security Policy
2
+
3
+ `claude-opencode-mcp` executes AI agents with file and shell access inside a
4
+ workspace. We take security reports seriously and appreciate responsible
5
+ disclosure.
6
+
7
+ ## Supported versions
8
+
9
+ | Version | Supported |
10
+ | --- | --- |
11
+ | 1.x | Yes |
12
+ | < 1.0 | No |
13
+
14
+ ## Reporting a vulnerability
15
+
16
+ Please **do not** open a public issue for a security problem.
17
+
18
+ Use GitHub's private vulnerability reporting:
19
+ <https://github.com/putuandy/claude-opencode-mcp/security/advisories/new>
20
+
21
+ Include:
22
+
23
+ - affected version (`claude-opencode-mcp --version`),
24
+ - OpenCode version (`opencode --version`),
25
+ - a minimal reproduction or proof of concept,
26
+ - the impact you believe it has,
27
+ - any suggested fix.
28
+
29
+ We aim to acknowledge reports within 72 hours and to ship a fix or mitigation
30
+ for confirmed issues as quickly as practical. We will credit reporters in the
31
+ advisory unless you prefer otherwise.
32
+
33
+ ## Scope
34
+
35
+ In scope:
36
+
37
+ - bypassing workspace validation, `workspace.allowedRoots`, or path-hint checks,
38
+ - escaping the agent permission model (e.g. read-only agents writing files,
39
+ `git push`/`git commit` bypass, `.env` protection bypass),
40
+ - credential exposure through logs, errors, or network requests,
41
+ - command or argument injection in bridge-spawned processes,
42
+ - denial of service that hangs or crashes a Claude Code session,
43
+ - supply-chain issues in this package's own code or dependencies.
44
+
45
+ Out of scope (documented behavior, see [docs/security.md](docs/security.md)):
46
+
47
+ - an agent with shell access can write files through shell commands,
48
+ - `.env` protection applies to file tools, not to `bash`,
49
+ - prompt injection from repository content influencing a delegated agent,
50
+ - arbitrary code execution caused by a binary you explicitly configure via
51
+ `opencode.binary` / `OPENCODE_BIN`,
52
+ - vulnerabilities in OpenCode, Claude Code, or model providers themselves
53
+ (report those upstream).
54
+
55
+ ## Threat model summary
56
+
57
+ The bridge assumes:
58
+
59
+ - the local user account and the workspace contents are trusted to the degree
60
+ the user chose to delegate,
61
+ - the OpenCode server is bound to `127.0.0.1` by default,
62
+ - provider credentials live in OpenCode or the environment, never in this
63
+ package's configuration or state.
64
+
65
+ Defenses: canonical-path workspace validation, allowed-root containment,
66
+ path-traversal rejection, an OpenCode permission matrix per agent profile
67
+ (no `ask` rules, auto-rejection of stray permission requests), sensitive-file
68
+ patterns, git history protections, bounded inputs/outputs, run timeouts and
69
+ cancellation, redacted logs, and `0600` state files.
70
+
71
+ ## Hardening recommendations
72
+
73
+ - Keep `workspace.allowedRoots` narrow when delegating across projects.
74
+ - Leave `opencode.hostname` at `127.0.0.1`; binding to a routable address
75
+ exposes the OpenCode HTTP API to your network (and its token/password, if
76
+ set, becomes the only barrier).
77
+ - Review diffs with `get_diff` before accepting changes.
78
+ - Prefer read-only agents for untrusted repositories.
79
+ - Never commit `.claude-opencode/config.json` if you put credentials in it
80
+ (provider credentials belong in OpenCode or environment variables).