@leo000001/claude-code-mcp 2.0.3 → 2.4.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.
package/CHANGELOG.md CHANGED
@@ -2,16 +2,95 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Security
6
+
7
+ - Validate `resumeToken` using timing-safe comparison (`timingSafeEqual` for fixed-length HMAC tokens) to reduce timing side-channel risk.
8
+
9
+ ### Improvements
10
+
11
+ - Session cleanup now marks timed-out running/waiting sessions as `cancelled` for consistent status semantics.
12
+ - `SessionManager.destroy()` now clears in-memory session/runtime maps after aborting active runs, so post-destroy reads are no longer stale.
13
+ - Event buffer eviction now uses batch compaction (instead of repeated `findIndex` + `splice`) and `readEvents` now uses binary search for cursor start.
14
+ - Add configurable event-buffer limits via `CLAUDE_CODE_MCP_EVENT_BUFFER_MAX_SIZE` and `CLAUDE_CODE_MCP_EVENT_BUFFER_HARD_MAX_SIZE`.
15
+ - Runtime tool-discovery updates now notify both tools and resources (internal-tools resource change notification).
16
+ - Enrich compatibility resources with package version, disk-resume diagnostics, and runtime limits.
17
+
18
+ ### Documentation
19
+
20
+ - Align README/DESIGN/AGENTS with current defaults and behavior (timeout clamp, advanced parameter count, lifecycle semantics).
21
+ - Clarify package positioning as CLI-first and remove stale guidance that implied a public programmatic API surface.
22
+ - Update CONTRIBUTING with local environment requirements (Node/npm and Windows Git Bash notes).
23
+
24
+ ### Tests
25
+
26
+ - Add dedicated tests for `resume-token` and `claude-code-reply`.
27
+ - Extend tests for event-buffer behavior, resource metadata, and runtime resource notifications.
28
+
29
+ ## 2.2.0 (2026-02-17)
30
+
31
+ ### Improvements
32
+
33
+ - Add `CLAUDE_CODE_MCP_MAX_SESSIONS` (default: `128`) to cap in-memory session count and reduce risk of memory exhaustion.
34
+ - Add `CLAUDE_CODE_MCP_MAX_PENDING_PERMISSIONS` (default: `64`) to cap outstanding permission requests per session.
35
+ - Promote `effort` and `thinking` to top-level parameters on `claude_code` and `claude_code_reply` (deprecated aliases: `advanced.effort`, `advanced.thinking`).
36
+ - Tool responses now include `structuredContent` (in addition to JSON text) for easier MCP client consumption.
37
+ - Emit `tools/list_changed` and `resources/list_changed` once after connect; update `claude_code` tool description dynamically when runtime tool discovery changes.
38
+ - Align declared MCP capabilities with implemented primitives (`logging`, `tools`, `resources`) and remove prompt primitive exposure.
39
+ - Add unit tests for `build-options.ts` and `race-with-abort.ts`.
40
+
41
+ ### Bug Fixes
42
+
43
+ - Fork resume: restore original session state before creating the forked session record to avoid a brief `AbortController` sharing window.
44
+ - Session totals: prevent `totalTurns`/`totalCostUsd` from being overwritten when SDK-provided session totals look incremental.
45
+ - Permission audit: include allow-side `updatedInput`/`updatedPermissions` in `permission_result` events.
46
+
47
+ ### Refactors
48
+
49
+ - Extract shared Zod schema fields for `advanced` and `diskResumeConfig` in `src/server.ts`.
50
+ - Deduplicate `SessionManager.create()` call payloads via a shared helper.
51
+ - Remove `server.close` monkey-patch; perform `sessionManager.destroy()` in the shutdown flow.
52
+
53
+ ### Documentation
54
+
55
+ - Changelog: move released 2.x items out of `Unreleased` and add missing 2.0.0–2.0.3 entries.
56
+ - SECURITY: update supported versions table for 2.x.
57
+ - Docs: clarify same-platform assumption (MCP server and client run on the same machine) across README, AGENTS, SECURITY, and mcp_demo.
58
+
59
+ ## 2.0.3 (2026-02-15)
60
+
61
+ ### Improvements
62
+
63
+ - Version bump only.
64
+
65
+ ## 2.0.2 (2026-02-15)
66
+
67
+ ### Features
68
+
69
+ - MCP resources: `server-info`, `internal-tools`, and `gotchas`
70
+ - Permission workflow: include timeout/expiration metadata in permission actions; support `updatedInput` normalization
71
+
72
+ ### Bug Fixes
73
+
74
+ - Windows: normalize MSYS-style paths for `NotebookEdit` where possible
75
+
76
+ ## 2.0.1 (2026-02-15)
77
+
78
+ ### Improvements
79
+
80
+ - Refined server schema descriptions/default annotations to reduce token overhead for calling models
81
+
82
+ ## 2.0.0 (2026-02-15)
83
+
5
84
  ### Breaking Changes
6
85
 
7
86
  - `claude_code` and `claude_code_reply` now start asynchronously and return `{ sessionId, status: "running", pollInterval }`. Use `claude_code_check` to poll events and fetch the final `result`.
8
87
  - Removed tool: `claude_code_configure`
9
88
  - New tool: `claude_code_check` (poll + respond_permission)
89
+ - Legacy `bypassPermissions` mode is no longer exposed in MCP schemas for 2.x.
10
90
  - **Parameter nesting refactor**: low-frequency parameters have been folded into nested objects to reduce top-level clutter. This is a breaking change for callers that pass these parameters at the top level:
11
- - `claude_code`: 22 low-frequency params moved into `advanced` object (e.g. `effort` `advanced.effort`, `tools` `advanced.tools`, `agents` `advanced.agents`, `env` → `advanced.env`)
91
+ - `claude_code`: 22 low-frequency params moved into `advanced` object in 2.0.0 (current versions expose 20 low-frequency params + 2 compatibility aliases: `advanced.effort`, `advanced.thinking`)
12
92
  - `claude_code_reply`: 28 disk-resume params moved into `diskResumeConfig` object (e.g. `resumeToken` → `diskResumeConfig.resumeToken`, `cwd` → `diskResumeConfig.cwd`)
13
93
  - `claude_code_check`: 9 poll control params moved into `pollOptions` object (e.g. `includeTools` → `pollOptions.includeTools`); 2 permission response params moved into `permissionOptions` object (e.g. `updatedInput` → `permissionOptions.updatedInput`)
14
- - Schema descriptions for nested object fields have been compacted (self-explanatory fields no longer carry `.describe()` text; object-level descriptions enhanced as summaries) to reduce token overhead for calling models
15
94
 
16
95
  ### Features
17
96
 
@@ -28,10 +107,8 @@
28
107
  - `claude_code_check`: minimal mode filters out noisy progress events (`tool_progress`, `auth_status`); use `includeProgressEvents: true` to restore
29
108
  - `claude_code_check`: minimal mode omits `lastEventId`/`lastToolUseId` from top-level response and `durationApiMs`/`sessionTotalTurns`/`sessionTotalCostUsd` from AgentResult
30
109
  - `claude_code_check`: includes lightweight session diagnostics (`cancelledAt`/`cancelledReason`/`cancelledSource`, `lastEventId`, `lastToolUseId`)
31
- - `claude_code_check`: permission actions now include `timeoutMs`, `expiresAt`, and best-effort `remainingMs`
32
110
  - Permission result events now include `toolName`, and denial details (`message`, `interrupt`) when applicable
33
111
  - Disk resume security: disk resume fallback requires `CLAUDE_CODE_MCP_RESUME_SECRET` + `resumeToken`
34
- - MCP resources: server info, internal tool catalog, and gotchas
35
112
 
36
113
  ## 1.6.0 (2026-02-12)
37
114
 
package/CONTRIBUTING.md CHANGED
@@ -10,6 +10,13 @@ cd claude-code-mcp
10
10
  npm install
11
11
  ```
12
12
 
13
+ ### Local Environment Requirements
14
+
15
+ - Node.js `>=18` (Node 20/22 recommended for local development)
16
+ - npm (bundled with Node)
17
+ - Windows contributors: install **Git for Windows** (`bash.exe`) for Claude Code CLI compatibility
18
+ - Optional: set `CLAUDE_CODE_GIT_BASH_PATH` explicitly when testing MCP clients launched outside your terminal environment
19
+
13
20
  ## Development Workflow
14
21
 
15
22
  1. Create a feature branch from the default branch
@@ -35,7 +42,7 @@ npm install
35
42
 
36
43
  - Keep PRs focused on a single change
37
44
  - Include tests for new functionality
38
- - Update documentation (README, DESIGN.md) if the public API changes
45
+ - Update documentation (README, docs/DESIGN.md) if the public API changes
39
46
  - Ensure CI passes before requesting review
40
47
 
41
48
  ## Reporting Issues
@@ -43,3 +50,12 @@ npm install
43
50
  - Use GitHub Issues for bug reports and feature requests
44
51
  - Include reproduction steps for bugs
45
52
  - For security vulnerabilities, see [SECURITY.md](SECURITY.md)
53
+
54
+ ## Release Checklist
55
+
56
+ 1. Update `CHANGELOG.md` with the upcoming version and confirm `package.json` reflects that version.
57
+ 2. Run `npm run format:check`, `npm run lint`, `npm run typecheck` (now covers `src` + `tests`), and `npm test` to prove the working tree is clean.
58
+ 3. Build the bundle (`npm run build`) and verify `dist/` contains the expected entry points.
59
+ 4. Refresh any documentation (README/CONTRIBUTING/docs) that describe public behavior or APIs touched by the release.
60
+ 5. Ensure `NOTICE.md` lists the third-party components bundled in the release and contains links or pointers to their licenses.
61
+ 6. Double-check `files`, `bin`, and other package metadata so the published package only ships the intended assets.
package/NOTICE.md ADDED
@@ -0,0 +1,27 @@
1
+ # NOTICE
2
+
3
+ This project (`@leo000001/claude-code-mcp`) is licensed under the MIT License (see `LICENSE`).
4
+
5
+ ## Third-party components
6
+
7
+ This project depends on third-party packages. Their licenses and terms may impose additional
8
+ requirements on redistribution and use.
9
+
10
+ ### Direct dependencies (from `package.json`)
11
+
12
+ - `@anthropic-ai/claude-agent-sdk@0.2.38` — license is declared as “SEE LICENSE IN README.md” in the package metadata. This package bundles a Claude Code CLI; please review Anthropic's documentation and legal terms referenced by that project before redistributing or deploying.
13
+ - `@modelcontextprotocol/sdk@1.26.0` — MIT License
14
+ - `zod@4.3.6` — MIT License
15
+
16
+ For a complete dependency graph, see `package-lock.json`. When installed, each dependency’s
17
+ license information is included with the package itself (typically under its `LICENSE` file or
18
+ `package.json` fields).
19
+
20
+ ### Optional native dependencies
21
+
22
+ Some optional dependencies pulled in by the Claude Agent SDK (or its transitive dependencies)
23
+ may include prebuilt native binaries with licenses such as LGPL. These packages are platform-
24
+ specific (e.g., `@img/sharp-*` and related `libvips` packages).
25
+
26
+ If you redistribute this project (or produce bundled artifacts), you are responsible for ensuring
27
+ you comply with any applicable third-party license obligations and include required notices.
package/README.md CHANGED
@@ -4,13 +4,16 @@
4
4
  [![license](https://img.shields.io/npm/l/@leo000001/claude-code-mcp.svg)](https://github.com/xihuai18/claude-code-mcp/blob/HEAD/LICENSE)
5
5
  [![node](https://img.shields.io/node/v/@leo000001/claude-code-mcp.svg)](https://nodejs.org)
6
6
 
7
- MCP server that wraps [Claude Code (Claude Agent SDK)](https://docs.anthropic.com/en/docs/claude-code/overview) as tools, enabling any MCP client to invoke Claude Code for autonomous coding tasks.
7
+ MCP server that wraps [Claude Code (Claude Agent SDK)](https://docs.anthropic.com/en/docs/claude-code/overview) as tools, enabling any MCP client to invoke Claude Code for autonomous coding tasks. Designed for local use — the MCP server and client are expected to run on the same machine.
8
8
 
9
9
  Inspired by the [Codex MCP](https://developers.openai.com/codex/guides/agents-sdk/) design philosophy — minimum tools, maximum capability.
10
10
 
11
+ This package is **CLI-first**: it is intended to run as an MCP server process (`npx @leo000001/claude-code-mcp`), not as a stable programmatic library API.
12
+
11
13
  ## Features
12
14
 
13
15
  - **4 tools** covering the full agent lifecycle: start, continue, check/poll, manage
16
+ - **Read-only MCP resources** for server info, internal tool catalog, and compatibility diagnostics
14
17
  - **Session management** with resume and fork support
15
18
  - **Local settings loaded by default** — automatically reads `~/.claude/settings.json`, `.claude/settings.json`, `.claude/settings.local.json`, and `CLAUDE.md` so the agent behaves like your local Claude Code CLI
16
19
  - **Async permissions** — allow/deny lists + explicit approvals via `claude_code_check`
@@ -20,9 +23,12 @@ Inspired by the [Codex MCP](https://developers.openai.com/codex/guides/agents-sd
20
23
  - **Auto-cleanup** — 30-minute idle timeout for expired sessions
21
24
  - **Security** — callers control tool permissions via allow/deny lists + explicit permission decisions
22
25
 
26
+ See `CHANGELOG.md` for release history.
27
+
23
28
  ## Prerequisites
24
29
 
25
30
  - **Node.js >= 18** is required.
31
+ - **Same-platform deployment** — this MCP server is designed to run on the same machine as the MCP client. It communicates via stdio (child process), reads local Claude configuration files from `~/.claude/`, and accesses the local file system directly. Remote deployment is not supported.
26
32
 
27
33
  This MCP server uses the [`@anthropic-ai/claude-agent-sdk`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) package, which **bundles its own Claude Code CLI** (`cli.js`). It does not use the `claude` binary from your system PATH.
28
34
 
@@ -56,6 +62,14 @@ Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
56
62
  }
57
63
  ```
58
64
 
65
+ > Some clients cache tool/resource metadata at connect-time. This server emits `notifications/tools/list_changed` and resource update notifications after runtime tool discovery so clients can refresh both the `claude_code` tool description and `internal-tools` resource.
66
+
67
+ ### Anthropic Claude Code CLI (as an MCP client)
68
+
69
+ ```bash
70
+ claude mcp add --transport stdio claude-code -- npx -y @leo000001/claude-code-mcp
71
+ ```
72
+
59
73
  ### OpenAI Codex CLI
60
74
 
61
75
  ```bash
@@ -96,26 +110,27 @@ Start a new Claude Code session. The agent autonomously performs coding tasks: r
96
110
  | `disallowedTools` | string[] | No | Forbidden tool names. Default: `[]` (none). SDK behavior: disallowed tools are removed from the model's context. Takes precedence over `allowedTools` and will be denied even if later approved interactively |
97
111
  | `maxTurns` | number | No | Maximum number of agent reasoning steps. Each step may involve one or more tool calls. Default: SDK/Claude Code default |
98
112
  | `model` | string | No | Model to use (e.g. `"claude-sonnet-4-5-20250929"`). Default: SDK/Claude Code default |
113
+ | `effort` | string | No | Effort level: `"low"`, `"medium"`, `"high"`, `"max"`. Default: SDK/Claude Code default |
114
+ | `thinking` | object | No | Thinking mode: `{ type: "adaptive" }`, `{ type: "enabled", budgetTokens: N }`, or `{ type: "disabled" }`. Default: SDK/Claude Code default |
99
115
  | `systemPrompt` | string \| object | No | Override the agent's system prompt. Default: SDK/Claude Code default. Pass a string for full replacement, or `{ type: "preset", preset: "claude_code", append?: "..." }` to extend the default prompt |
100
- | `permissionRequestTimeoutMs` | number | No | Timeout in milliseconds waiting for permission decisions. Default: `60000` |
116
+ | `permissionRequestTimeoutMs` | number | No | Timeout in milliseconds waiting for permission decisions, auto-deny on expiry. Default: `60000` (server-clamped to 5min) |
117
+ | `sessionInitTimeoutMs` | number | No | **Compatibility alias** for `advanced.sessionInitTimeoutMs` (deprecated for `claude_code`). Default: `10000`. If both are provided, `advanced.sessionInitTimeoutMs` wins |
101
118
  | `advanced` | object | No | Advanced/low-frequency parameters (see below) |
102
119
 
103
120
  <details>
104
- <summary><code>advanced</code> object parameters (22 low-frequency parameters)</summary>
121
+ <summary><code>advanced</code> object parameters (20 low-frequency parameters)</summary>
105
122
 
106
123
  | Parameter | Type | Description |
107
124
  | ------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
108
125
  | `advanced.tools` | string[] \| object | Define the base tool set. Default: SDK/Claude Code default toolset. Array of tool name strings, or `{ type: "preset", preset: "claude_code" }` for the default toolset. `allowedTools`/`disallowedTools` further filter on top of this |
109
126
  | `advanced.persistSession` | boolean | Persist session history to disk (`~/.claude/projects/`). Default: `true`. Set `false` to disable. |
110
- | `advanced.sessionInitTimeoutMs` | number | Timeout in milliseconds waiting for `system/init`. Default: `10000` |
127
+ | `advanced.sessionInitTimeoutMs` | number | Session init timeout in milliseconds waiting for `system/init`. Default: `10000`. **Recommended location for `claude_code` callers.** |
111
128
  | `advanced.agents` | object | Define custom sub-agents the main agent can delegate tasks to. Default: none. SDK default: if a sub-agent omits `tools`, it inherits all tools from the parent. |
112
129
  | `advanced.agent` | string | Name of a custom agent (defined in `agents`) to use as the primary agent. Default: omitted |
113
130
  | `advanced.maxBudgetUsd` | number | Maximum budget in USD. Default: SDK/Claude Code default |
114
- | `advanced.effort` | string | Effort level: `"low"`, `"medium"`, `"high"`, `"max"`. Default: SDK/Claude Code default |
115
131
  | `advanced.betas` | string[] | Beta features (e.g. `["context-1m-2025-08-07"]`). Default: none |
116
132
  | `advanced.additionalDirectories` | string[] | Additional directories the agent can access beyond cwd. Default: none |
117
133
  | `advanced.outputFormat` | object | Structured output: `{ type: "json_schema", schema: {...} }`. Default: omitted (plain text) |
118
- | `advanced.thinking` | object | Thinking mode: `{ type: "adaptive" }`, `{ type: "enabled", budgetTokens: N }`, or `{ type: "disabled" }`. Default: SDK/Claude Code default |
119
134
  | `advanced.pathToClaudeCodeExecutable` | string | Path to the Claude Code executable. Default: SDK-bundled Claude Code (cli.js) |
120
135
  | `advanced.mcpServers` | object | MCP server configurations (key: server name, value: server config). Default: none |
121
136
  | `advanced.sandbox` | object | Sandbox configuration for isolating shell command execution (e.g., Docker container settings). Default: SDK/Claude Code default |
@@ -128,6 +143,8 @@ Start a new Claude Code session. The agent autonomously performs coding tasks: r
128
143
  | `advanced.debugFile` | string | Write debug logs to a specific file path (implicitly enables debug mode). Default: omitted |
129
144
  | `advanced.env` | object | Environment variables to merge with process.env and pass to the Claude Code process (user values take precedence). Default: inherit process.env |
130
145
 
146
+ Deprecated aliases: `advanced.effort` and `advanced.thinking` are still accepted for compatibility, but prefer top-level `effort` / `thinking` (top-level wins if both are set).
147
+
131
148
  </details>
132
149
 
133
150
  **Returns:** `{ sessionId, status: "running", pollInterval, resumeToken? }`
@@ -136,6 +153,7 @@ Notes:
136
153
 
137
154
  - `resumeToken` is omitted by default, and is only returned when `CLAUDE_CODE_MCP_RESUME_SECRET` is set on the server.
138
155
  - On error: `{ sessionId: "", status: "error", error }`
156
+ - If `sessionInitTimeoutMs` (top-level alias) is used, `claude_code` may return `compatWarnings` to guide migration to `advanced.sessionInitTimeoutMs`.
139
157
 
140
158
  Use `claude_code_check` to poll events and obtain the final `result`.
141
159
 
@@ -156,8 +174,10 @@ Continue an existing session by sending a follow-up message. The agent retains f
156
174
  | `sessionId` | string | Yes | Session ID from a previous `claude_code` call |
157
175
  | `prompt` | string | Yes | Follow-up prompt |
158
176
  | `forkSession` | boolean | No | Create a branched copy of this session. Default: `false` |
159
- | `permissionRequestTimeoutMs` | number | No | Timeout in milliseconds waiting for permission decisions. Default: `60000` |
160
- | `sessionInitTimeoutMs` | number | No | Timeout in milliseconds waiting for fork `system/init`. Default: `10000` |
177
+ | `effort` | string | No | Effort level override for this run (and for future replies when not forking). Default: SDK/Claude Code default |
178
+ | `thinking` | object | No | Thinking mode override for this run (and for future replies when not forking). Default: SDK/Claude Code default |
179
+ | `permissionRequestTimeoutMs` | number | No | Timeout in milliseconds waiting for permission decisions, auto-deny on expiry. Default: `60000` (server-clamped to 5min) |
180
+ | `sessionInitTimeoutMs` | number | No | Fork init timeout in milliseconds (only when `forkSession=true`). Default: `10000` |
161
181
  | `diskResumeConfig` | object | No | Disk resume parameters (see below). Used when `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=1` and in-memory session is missing |
162
182
 
163
183
  <details>
@@ -211,33 +231,46 @@ Gotchas:
211
231
  - Permission approvals have a timeout (default 60s via `permissionRequestTimeoutMs`) and will auto-deny; watch `actions[].expiresAt` / `actions[].remainingMs`.
212
232
  - `Read` has a per-call size cap in practice (often ~256KB); for large files use `offset`/`limit` or chunk with `Grep`.
213
233
  - `Edit` with `replace_all=true` is substring replacement; if no match is found the tool returns a clear error.
214
- - `NotebookEdit` expects native Windows paths (e.g. `D:\path\file.ipynb`); this server normalizes MSYS paths like `/d/...` when possible.
234
+ - On Windows, this server normalizes common MSYS-style paths (e.g. `/d/...`, `/mnt/c/...`, `/cygdrive/c/...`, `//server/share/...`) for `cwd`, `additionalDirectories`, and tool inputs that include `file_path`.
235
+ - On Windows, POSIX home paths like `/home/user/...` are **not** rewritten to drive paths; prefer absolute Windows paths under your current `cwd` to avoid out-of-bounds permission prompts.
215
236
  - `TeamDelete` may require members to reach `shutdown_approved` (otherwise you may see "active member" errors); cleanup can be asynchronous during shutdown.
216
237
  - Skills may become available later in the same session (early calls may show "Unknown", later succeed after skills are loaded/registered).
238
+ - `toolCatalogCount` and `availableTools` are different views: catalog is server-known tools, while `availableTools` comes from each session's runtime `system/init.tools`.
217
239
  - Some internal features (e.g. ToolSearch) may not appear in `availableTools` (derived from SDK `system/init.tools`).
218
240
 
219
241
  ### Resources
220
242
 
221
243
  If your MCP client supports resources, this server exposes a couple of **read-only** MCP resources:
222
244
 
223
- - `claude-code-mcp:///server-info` (JSON): static server metadata (version/platform/runtime)
224
- - `claude-code-mcp:///internal-tools` (JSON): internal tool catalog (static + runtime-discovered)
245
+ - `claude-code-mcp:///server-info` (JSON): server metadata (version/platform/runtime + capabilities/limits)
246
+ - `claude-code-mcp:///internal-tools` (JSON): internal tool catalog (runtime-aware, includes permission/schema metadata)
225
247
  - `claude-code-mcp:///gotchas` (Markdown): practical limits/gotchas
248
+ - `claude-code-mcp:///quickstart` (Markdown): minimal async start/poll/respond flow
249
+ - `claude-code-mcp:///errors` (JSON): structured error-code catalog and remediation hints
250
+ - `claude-code-mcp:///compat-report` (JSON): compatibility report (transport/platform assumptions, runtime warnings, guidance, recommended settings, tool count diagnostics)
251
+
252
+ Resource templates:
253
+
254
+ - `claude-code-mcp:///session/{sessionId}`: lightweight session snapshot for a specific session
255
+ - `claude-code-mcp:///tools/runtime{?sessionId}`: runtime tool view globally or per session
256
+ - `claude-code-mcp:///compat/diff{?client}`: client-specific compatibility guidance
226
257
 
227
258
  **Disk resume (optional):** By default, `claude_code_reply` requires the session to exist in the MCP server's in-memory Session Manager. If you set `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=1`, it can attempt to resume using the Claude Code CLI's on-disk transcript even when the in-memory session is missing (e.g. after a restart / TTL cleanup). For safety, disk resume fallback requires `CLAUDE_CODE_MCP_RESUME_SECRET` to be set on the server and requires callers to pass `diskResumeConfig.resumeToken` (returned by `claude_code` / `claude_code_reply` when `CLAUDE_CODE_MCP_RESUME_SECRET` is set).
228
259
 
229
260
  ### `claude_code_session` — Manage sessions
230
261
 
231
- List, inspect, or cancel sessions.
262
+ List, inspect, cancel, or interrupt sessions.
232
263
 
233
- | Parameter | Type | Required | Description |
234
- | ------------------ | ------- | -------------- | ------------------------------------------------------------------------------ |
235
- | `action` | string | Yes | `"list"`, `"get"`, or `"cancel"` |
236
- | `sessionId` | string | For get/cancel | Target session ID |
264
+ | Parameter | Type | Required | Description |
265
+ | ------------------ | ------- | ------------------------- | ------------------------------------------------------------------------------ |
266
+ | `action` | string | Yes | `"list"`, `"get"`, `"cancel"`, or `"interrupt"` |
267
+ | `sessionId` | string | For get/cancel/interrupt | Target session ID |
237
268
  | `includeSensitive` | boolean | No | Include `cwd`/`systemPrompt`/`agents`/`additionalDirectories` (default: false) |
238
269
 
239
270
  **Returns:** `{ sessions, message?, isError? }`
240
271
 
272
+ `sessions[]` now includes lightweight diagnostics fields: `pendingPermissionCount`, `eventCount`, `currentCursor`, `lastEventId`, `ttlMs`, `lastError?`, `lastErrorAt?`, and `redactions[]`.
273
+
241
274
  ### `claude_code_check` — Poll events and respond to permission requests
242
275
 
243
276
  Poll session events/results and approve/deny pending permission requests.
@@ -247,17 +280,17 @@ Poll session events/results and approve/deny pending permission requests.
247
280
  | `action` | string | Yes | `"poll"` or `"respond_permission"` |
248
281
  | `sessionId` | string | Yes | Target session ID |
249
282
  | `cursor` | number | No | Event cursor for incremental polling (`poll` only). Default: omitted (starts from the beginning of the buffer) |
250
- | `responseMode` | string | No | `"minimal"` (default) or `"full"` controls payload size and redaction behavior |
251
- | `maxEvents` | number | No | Max events per poll (pagination via `nextCursor`). Default: `200` in `"minimal"`; unlimited in `"full"` |
283
+ | `responseMode` | string | No | `"minimal"` (default), `"delta_compact"` (lightweight polling), or `"full"` (verbose diagnostics) |
284
+ | `maxEvents` | number | No | Max events per poll (pagination via `nextCursor`). Default: `200` in `"minimal"`; unlimited in `"full"`/`"delta_compact"` |
252
285
  | `requestId` | string | For respond_permission | Permission request ID |
253
- | `decision` | string | For respond_permission | `"allow"` or `"deny"` |
286
+ | `decision` | string | For respond_permission | `"allow"`, `"deny"`, or `"allow_for_session"` |
254
287
  | `denyMessage` | string | No | Deny reason shown to Claude (`deny` only). Default: `"Permission denied by caller"` |
255
288
  | `interrupt` | boolean | No | When true, denying also interrupts the whole agent (`deny` only). Default: `false` |
256
289
  | `pollOptions` | object | No | Fine-grained poll control options (see below) |
257
290
  | `permissionOptions` | object | No | Advanced permission response options (see below) |
258
291
 
259
292
  <details>
260
- <summary><code>pollOptions</code> object parameters (9 fine-grained poll controls)</summary>
293
+ <summary><code>pollOptions</code> object parameters (10 fine-grained poll controls)</summary>
261
294
 
262
295
  | Parameter | Type | Description |
263
296
  | ------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -265,11 +298,12 @@ Poll session events/results and approve/deny pending permission requests.
265
298
  | `pollOptions.includeEvents` | boolean | When false, omits `events` (but `nextCursor` still advances). Default: `true` |
266
299
  | `pollOptions.includeActions` | boolean | When false, omits `actions[]` even if `waiting_permission`. Default: `true` |
267
300
  | `pollOptions.includeResult` | boolean | When false, omits top-level `result` even when `idle`/`error`. Default: `true` |
268
- | `pollOptions.includeUsage` | boolean | Include `result.usage` (default: true in full mode, false in minimal mode) |
269
- | `pollOptions.includeModelUsage` | boolean | Include `result.modelUsage` (default: true in full mode, false in minimal mode) |
270
- | `pollOptions.includeStructuredOutput` | boolean | Include `result.structuredOutput` (default: true in full mode, false in minimal mode) |
271
- | `pollOptions.includeTerminalEvents` | boolean | When true, keeps terminal `result`/`error` events in `events` even if top-level `result` is included. Default: `false` in `"minimal"`, `true` in `"full"` |
272
- | `pollOptions.includeProgressEvents` | boolean | When true, includes progress events (`tool_progress`, `auth_status`) in the events stream. Default: `false` in `"minimal"`, `true` in `"full"` |
301
+ | `pollOptions.includeUsage` | boolean | Include `result.usage` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`) |
302
+ | `pollOptions.includeModelUsage` | boolean | Include `result.modelUsage` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`) |
303
+ | `pollOptions.includeStructuredOutput` | boolean | Include `result.structuredOutput` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`) |
304
+ | `pollOptions.includeTerminalEvents` | boolean | When true, keeps terminal `result`/`error` events in `events` even if top-level `result` is included. Default: `false` in `"minimal"`/`"delta_compact"`, `true` in `"full"` |
305
+ | `pollOptions.includeProgressEvents` | boolean | When true, includes progress events (`tool_progress`, `auth_status`) in the events stream. Default: `false` in `"minimal"`/`"delta_compact"`, `true` in `"full"` |
306
+ | `pollOptions.maxBytes` | number | Approximate max JSON bytes for `events` in this response. When exceeded, events are truncated and `truncatedFields` includes `"events_bytes"`. Default: unlimited |
273
307
 
274
308
  </details>
275
309
 
@@ -278,23 +312,28 @@ Poll session events/results and approve/deny pending permission requests.
278
312
 
279
313
  | Parameter | Type | Description |
280
314
  | -------------------------------------- | ------ | ----------------------------------------------------------------------- |
281
- | `permissionOptions.updatedInput` | object | Modified tool input to run (`allow` only). Default: none |
282
- | `permissionOptions.updatedPermissions` | array | Permission rule updates suggested/applied (`allow` only). Default: none |
315
+ | `permissionOptions.updatedInput` | object | Modified tool input to run (`allow`/`allow_for_session` only). Default: none |
316
+ | `permissionOptions.updatedPermissions` | array | Permission rule updates suggested/applied (`allow`/`allow_for_session` only). Default: none |
283
317
 
284
318
  </details>
285
319
 
286
- **Returns (poll and respond_permission):** `{ sessionId, status, pollInterval?, cursorResetTo?, truncated?, truncatedFields?, events, nextCursor?, availableTools?, actions?, result?, cancelledAt?, cancelledReason?, cancelledSource?, lastEventId?, lastToolUseId? }`
320
+ **Returns (poll and respond_permission):** `{ sessionId, status, pollInterval?, cursorResetTo?, truncated?, truncatedFields?, events, nextCursor?, availableTools?, toolValidation?, compatWarnings?, actions?, result?, cancelledAt?, cancelledReason?, cancelledSource?, lastEventId?, lastToolUseId? }`
287
321
 
288
322
  Notes:
289
323
 
290
324
  - On error (e.g. invalid arguments, missing/expired session): `{ sessionId, isError: true, error }`
325
+ - `respond_user_input` is not supported on this backend. Use `respond_permission` for interactive approvals.
291
326
  - Always treat `cursor` as an incremental position: store `nextCursor` and pass it back on the next poll to avoid replaying old events.
292
327
  - If `cursorResetTo` is present, your `cursor` was too old (events were evicted); reset your cursor to `cursorResetTo`.
293
328
  - For safety, de-duplicate events by `event.id` on the client side.
294
329
  - If `truncated=true`, the server intentionally limited the payload (e.g. `maxEvents`) — continue polling with `nextCursor`.
330
+ - `nextCursor` can remain unchanged with `events=[]` during quiet intervals; this is normal transient behavior. Retry a few times (for example up to 3) before treating it as abnormal.
331
+ - `toolValidation` reports whether configured `allowedTools`/`disallowedTools` match runtime-discovered tool names.
332
+ - `compatWarnings` surfaces compatibility hints (for example, unresolved tool names or path/platform mismatch signals) and is **non-blocking**; treat it as advisory unless the session actually fails.
295
333
  - Permission `actions[]` include `timeoutMs`, `expiresAt`, and best-effort `remainingMs` to help callers avoid auto-deny timeouts.
296
334
  - `permission_result` event data is `{ requestId, toolName, behavior, source, message?, interrupt? }` (denial details only present for `deny`).
297
335
  - In `"minimal"` mode (default): assistant message events are slimmed (strips `usage`, `model`, `id`, `cache_control` from content blocks); noisy progress events (`tool_progress`, `auth_status`) are filtered out; `lastEventId`/`lastToolUseId` are omitted; `AgentResult` omits `durationApiMs`/`sessionTotalTurns`/`sessionTotalCostUsd`. Use `responseMode: "full"` or individual `include*` flags to restore any of these.
336
+ - In `"delta_compact"` mode: defaults are optimized for high-frequency polling (`events` and top-level `result` omitted unless explicitly enabled via `pollOptions`), while still returning session status/actions/cursors.
298
337
 
299
338
  ## Usage Example
300
339
 
@@ -304,13 +343,13 @@ start = await mcp.call_tool("claude_code", {
304
343
  "prompt": "Fix the authentication bug in src/auth.ts",
305
344
  "cwd": "/path/to/project",
306
345
  "allowedTools": ["Read", "Edit", "Bash", "Glob", "Grep"],
346
+ "effort": "high",
307
347
  "advanced": {
308
- "effort": "high",
309
348
  "maxBudgetUsd": 5.0
310
349
  }
311
350
  })
312
351
  session_id = json.loads(start)["sessionId"]
313
- cursor = None
352
+ cursor = 0
314
353
 
315
354
  # 2) Poll until idle/error/cancelled
316
355
  while True:
@@ -340,7 +379,7 @@ while True:
340
379
  final_result = data.get("result")
341
380
  break
342
381
 
343
- # 3) Manage sessions (list/get/cancel)
382
+ # 3) Manage sessions (list/get/cancel/interrupt)
344
383
  result = await mcp.call_tool("claude_code_session", {"action": "list"})
345
384
  ```
346
385
 
@@ -354,7 +393,7 @@ Claude Code on Windows requires git-bash (https://git-scm.com/downloads/win).
354
393
 
355
394
  This means the spawned CLI process cannot locate `bash.exe`. Your locally installed `claude` command may work fine — the issue is that the MCP server's child process may not inherit your shell environment.
356
395
 
357
- **Fix: set `CLAUDE_CODE_GIT_BASH_PATH` in your MCP server config.**
396
+ `claude-code-mcp` will try to auto-detect Git Bash from common install locations and set `CLAUDE_CODE_GIT_BASH_PATH` for child processes. If you still see this error, set `CLAUDE_CODE_GIT_BASH_PATH` explicitly in your MCP server config:
358
397
 
359
398
  For JSON-based MCP clients (Claude Desktop, Cursor, etc.):
360
399
 
@@ -401,12 +440,14 @@ setx CLAUDE_CODE_GIT_BASH_PATH "C:\Program Files\Git\bin\bash.exe"
401
440
  - **Async permission approvals** — when a tool call needs approval, the session transitions to `waiting_permission` and surfaces requests via `claude_code_check` (`actions[]`).
402
441
  - **No runtime privilege escalation tool** — permission decisions are per-session (allow/deny lists + explicit approvals), and the server does not expose a `claude_code_configure` bypass switch.
403
442
  - **Environment variables are inherited** — the spawned Claude Code process inherits all environment variables (including `ANTHROPIC_API_KEY`) from the parent process by default. The `advanced.env` parameter **merges** with `process.env` (user-provided values take precedence), so you can safely add or override individual variables without losing existing ones.
443
+ - **Permission policy is enforced in two places** — `allowedTools`/`disallowedTools` are passed to the SDK and also guarded in `canUseTool` as a defensive consistency check (for example, `blockedPath` can still trigger an approval flow).
404
444
  - Tool visibility vs approvals:
405
445
  - Use `advanced.tools` to restrict which tools the agent can _see_ (hidden tools cannot be called).
406
446
  - Use `allowedTools` to auto-approve specific tools without prompting (the SDK may still prompt for path-based restrictions like `blockedPath`).
407
447
  - Use `disallowedTools` to hard-block tools; they are denied even if later approved via `claude_code_check`.
408
448
  - `maxTurns` and `advanced.maxBudgetUsd` prevent runaway execution.
409
449
  - Sessions auto-expire after 30 minutes of inactivity.
450
+ - Vulnerability reporting: see `SECURITY.md`.
410
451
 
411
452
  ## Environment Variables
412
453
 
@@ -417,6 +458,10 @@ All environment variables are optional. They are set on the MCP server process (
417
458
  | `CLAUDE_CODE_GIT_BASH_PATH` | Path to `bash.exe` on Windows (see [Windows Support](#windows-support)) | Auto-detected |
418
459
  | `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME` | Set to `1` to allow `claude_code_reply` to resume from on-disk transcripts when the in-memory session is missing | `0` (disabled) |
419
460
  | `CLAUDE_CODE_MCP_RESUME_SECRET` | HMAC secret used to validate `resumeToken` for disk resume fallback (recommended if disk resume is enabled) | _(unset)_ |
461
+ | `CLAUDE_CODE_MCP_MAX_SESSIONS` | Maximum number of in-memory sessions (set `0` to disable the limit) | `128` |
462
+ | `CLAUDE_CODE_MCP_MAX_PENDING_PERMISSIONS` | Maximum number of outstanding permission requests per session (set `0` to disable the limit) | `64` |
463
+ | `CLAUDE_CODE_MCP_EVENT_BUFFER_MAX_SIZE` | Soft limit for in-memory event buffer per session (`0` is not supported) | `1000` |
464
+ | `CLAUDE_CODE_MCP_EVENT_BUFFER_HARD_MAX_SIZE` | Hard limit for in-memory event buffer per session (clamped to be `>= max`; `0` is not supported) | `2000` |
420
465
 
421
466
  ### How to configure
422
467
 
@@ -471,17 +516,39 @@ npm test # Run tests with vitest
471
516
  npm run dev # Watch mode build
472
517
  ```
473
518
 
519
+ ### E2E regression commands
520
+
521
+ ```bash
522
+ # Run cancel->poll regression loop (single mode)
523
+ npm run e2e:stdio:cancel
524
+
525
+ # Run waiting_permission + cancel regression loop
526
+ npm run e2e:stdio:cancel:wp
527
+
528
+ # Run both modes and output one summary report
529
+ npm run e2e:stdio:runner
530
+ ```
531
+
532
+ ### E2E notes (Codex and other clients)
533
+
534
+ - Some clients do not expose `tools/list` directly in the chat loop. In those clients, treat "tool is callable" as the primary discovery signal, and use `tools/list` only when available.
535
+ - `allowedTools: ["Read", "Write"]` does not guarantee the model will never attempt `Bash`. For deterministic smoke tests, add `disallowedTools: ["Bash"]` and state "do not use Bash" in the prompt.
536
+ - For `claude_code_session(action="get", includeSensitive=true)`, only assert fields that were actually configured. Optional fields that were never set may be omitted.
537
+ - If a client reports `Transport closed` during E2E cleanup, reconnect the MCP server first, then run `claude_code_session(action="list")` and cancel any remaining `running` / `waiting_permission` sessions.
538
+
539
+ For an end-to-end local test plan (third-party CLI/client integration + real coding tasks), see `docs/E2E_LOCAL_TEST_PLAN.md`.
540
+
474
541
  ## Architecture
475
542
 
476
543
  ```
477
- MCP Client ←→ (stdio/JSON-RPC) ←→ MCP Server
544
+ MCP Client ←→ (stdio/JSON-RPC) ←→ MCP Server [same machine]
478
545
  ├── Session Manager (Map<id, state>)
479
546
  └── Claude Agent SDK (query())
480
547
  ```
481
548
 
482
549
  **Session persistence:** The MCP server's Session Manager holds **in-memory** session metadata, a snapshot of session options (tool config, limits, `cwd`, allow/deny lists, etc.), and an event buffer used by `claude_code_check`. This metadata is **not** persisted to disk by the MCP server. The actual conversation history is persisted to disk by the Claude Code CLI (under `~/.claude/projects/`) — this is managed by the SDK, not by this MCP server. By default, if the MCP server restarts or the session expires from memory, `claude_code_reply` will return `SESSION_NOT_FOUND` even though the CLI transcript may still exist on disk. You can opt into disk-resume behavior by setting `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=1`.
483
550
 
484
- Sessions are automatically cleaned up after 30 minutes of idle time, or after 4 hours of continuous running.
551
+ Sessions are automatically cleaned up after 30 minutes of idle time, or after 4 hours of continuous running (timed-out running sessions transition to `cancelled`).
485
552
 
486
553
  **Turn/Cost semantics:** `numTurns` and `totalCostUsd` are per-call increments. For cumulative per-session totals, use `sessionTotalTurns` and `sessionTotalCostUsd`. When `forkSession=true`, the returned `sessionId` (and `sessionTotal*`) refer to the forked session; the original session totals are preserved.
487
554
 
@@ -494,6 +561,7 @@ MCP server validation/policy errors are returned as `Error [CODE]: message` wher
494
561
  - `SESSION_BUSY` — session currently running
495
562
  - `PERMISSION_DENIED` — operation not allowed by server policy
496
563
  - `PERMISSION_REQUEST_NOT_FOUND` — permission request ID not found (already finished or expired)
564
+ - `RESOURCE_EXHAUSTED` — resource limit reached (e.g. max sessions or max pending permissions)
497
565
  - `TIMEOUT` — operation timed out
498
566
  - `CANCELLED` — session was cancelled
499
567
  - `INTERNAL` — unexpected error or protocol mismatch
@@ -510,3 +578,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
510
578
 
511
579
  - [Security Policy](SECURITY.md)
512
580
  - [Code of Conduct](CODE_OF_CONDUCT.md)
581
+ - [Third-party Notices](NOTICE.md)
package/SECURITY.md CHANGED
@@ -4,7 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | ------- | --------- |
7
- | 1.x | Yes |
7
+ | 2.x | Yes |
8
+ | 1.x | No |
8
9
 
9
10
  ## Reporting a Vulnerability
10
11
 
@@ -18,9 +19,11 @@ We aim to acknowledge reports within 48 hours and provide a fix or mitigation pl
18
19
 
19
20
  ## Security Considerations
20
21
 
22
+ - This MCP server is designed for local use only — the server and client must run on the same machine. It communicates via stdio (child process), reads local configuration from `~/.claude/`, and accesses the local file system directly. Remote deployment is not supported.
21
23
  - This server uses an async permission flow: when a tool call needs approval, the session pauses (`waiting_permission`) and surfaces requests via `claude_code_check` (`actions[]`). Callers must explicitly approve/deny via `respond_permission`.
22
24
  - The MCP server uses the Claude Agent SDK's bundled CLI (`cli.js`), not the system-installed `claude` binary
23
25
  - Session metadata is held in-memory only and is not persisted to disk by the MCP server (the SDK's CLI persists conversation history separately)
26
+ - To reduce memory exhaustion risk, the server caps in-memory session count via `CLAUDE_CODE_MCP_MAX_SESSIONS` (default: `128`).
24
27
  - Disk resume is disabled by default (`CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=0`). If you set `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=1`, disk resume fallback also requires `CLAUDE_CODE_MCP_RESUME_SECRET` (default: unset) and a valid `resumeToken` from `claude_code`/`claude_code_reply`.
25
28
  - `claude_code_session` redacts sensitive fields (cwd, systemPrompt, agents, additionalDirectories) by default; use `includeSensitive=true` to include them
26
29
  - Sessions auto-expire after 30 minutes of inactivity