@leo000001/claude-code-mcp 2.2.0 → 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,6 +2,32 @@
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
+
5
31
  ### Improvements
6
32
 
7
33
  - Add `CLAUDE_CODE_MCP_MAX_SESSIONS` (default: `128`) to cap in-memory session count and reduce risk of memory exhaustion.
@@ -60,8 +86,9 @@
60
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`.
61
87
  - Removed tool: `claude_code_configure`
62
88
  - New tool: `claude_code_check` (poll + respond_permission)
89
+ - Legacy `bypassPermissions` mode is no longer exposed in MCP schemas for 2.x.
63
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:
64
- - `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`)
65
92
  - `claude_code_reply`: 28 disk-resume params moved into `diskResumeConfig` object (e.g. `resumeToken` → `diskResumeConfig.resumeToken`, `cwd` → `diskResumeConfig.cwd`)
66
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`)
67
94
 
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
package/README.md CHANGED
@@ -8,6 +8,8 @@ MCP server that wraps [Claude Code (Claude Agent SDK)](https://docs.anthropic.co
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
@@ -60,7 +62,7 @@ Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
60
62
  }
61
63
  ```
62
64
 
63
- > Some clients cache tool definitions at connect-time. This server emits `notifications/tools/list_changed` after runtime tool discovery so clients can refresh the `claude_code` tool description.
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.
64
66
 
65
67
  ### Anthropic Claude Code CLI (as an MCP client)
66
68
 
@@ -174,7 +176,7 @@ Continue an existing session by sending a follow-up message. The agent retains f
174
176
  | `forkSession` | boolean | No | Create a branched copy of this session. Default: `false` |
175
177
  | `effort` | string | No | Effort level override for this run (and for future replies when not forking). Default: SDK/Claude Code default |
176
178
  | `thinking` | object | No | Thinking mode override for this run (and for future replies when not forking). Default: SDK/Claude Code default |
177
- | `permissionRequestTimeoutMs` | number | No | Timeout in milliseconds waiting for permission decisions, auto-deny on expiry. Default: `60000` |
179
+ | `permissionRequestTimeoutMs` | number | No | Timeout in milliseconds waiting for permission decisions, auto-deny on expiry. Default: `60000` (server-clamped to 5min) |
178
180
  | `sessionInitTimeoutMs` | number | No | Fork init timeout in milliseconds (only when `forkSession=true`). Default: `10000` |
179
181
  | `diskResumeConfig` | object | No | Disk resume parameters (see below). Used when `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=1` and in-memory session is missing |
180
182
 
@@ -233,31 +235,42 @@ Gotchas:
233
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.
234
236
  - `TeamDelete` may require members to reach `shutdown_approved` (otherwise you may see "active member" errors); cleanup can be asynchronous during shutdown.
235
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`.
236
239
  - Some internal features (e.g. ToolSearch) may not appear in `availableTools` (derived from SDK `system/init.tools`).
237
240
 
238
241
  ### Resources
239
242
 
240
243
  If your MCP client supports resources, this server exposes a couple of **read-only** MCP resources:
241
244
 
242
- - `claude-code-mcp:///server-info` (JSON): server metadata (version/platform/runtime)
243
- - `claude-code-mcp:///internal-tools` (JSON): internal tool catalog (runtime-aware)
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)
244
247
  - `claude-code-mcp:///gotchas` (Markdown): practical limits/gotchas
245
- - `claude-code-mcp:///compat-report` (JSON): compatibility report (transport/platform assumptions, runtime warnings, guidance)
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
246
257
 
247
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).
248
259
 
249
260
  ### `claude_code_session` — Manage sessions
250
261
 
251
- List, inspect, or cancel sessions.
262
+ List, inspect, cancel, or interrupt sessions.
252
263
 
253
- | Parameter | Type | Required | Description |
254
- | ------------------ | ------- | -------------- | ------------------------------------------------------------------------------ |
255
- | `action` | string | Yes | `"list"`, `"get"`, or `"cancel"` |
256
- | `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 |
257
268
  | `includeSensitive` | boolean | No | Include `cwd`/`systemPrompt`/`agents`/`additionalDirectories` (default: false) |
258
269
 
259
270
  **Returns:** `{ sessions, message?, isError? }`
260
271
 
272
+ `sessions[]` now includes lightweight diagnostics fields: `pendingPermissionCount`, `eventCount`, `currentCursor`, `lastEventId`, `ttlMs`, `lastError?`, `lastErrorAt?`, and `redactions[]`.
273
+
261
274
  ### `claude_code_check` — Poll events and respond to permission requests
262
275
 
263
276
  Poll session events/results and approve/deny pending permission requests.
@@ -267,10 +280,10 @@ Poll session events/results and approve/deny pending permission requests.
267
280
  | `action` | string | Yes | `"poll"` or `"respond_permission"` |
268
281
  | `sessionId` | string | Yes | Target session ID |
269
282
  | `cursor` | number | No | Event cursor for incremental polling (`poll` only). Default: omitted (starts from the beginning of the buffer) |
270
- | `responseMode` | string | No | `"minimal"` (default) or `"full"` controls payload size and redaction behavior |
271
- | `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"` |
272
285
  | `requestId` | string | For respond_permission | Permission request ID |
273
- | `decision` | string | For respond_permission | `"allow"` or `"deny"` |
286
+ | `decision` | string | For respond_permission | `"allow"`, `"deny"`, or `"allow_for_session"` |
274
287
  | `denyMessage` | string | No | Deny reason shown to Claude (`deny` only). Default: `"Permission denied by caller"` |
275
288
  | `interrupt` | boolean | No | When true, denying also interrupts the whole agent (`deny` only). Default: `false` |
276
289
  | `pollOptions` | object | No | Fine-grained poll control options (see below) |
@@ -285,11 +298,11 @@ Poll session events/results and approve/deny pending permission requests.
285
298
  | `pollOptions.includeEvents` | boolean | When false, omits `events` (but `nextCursor` still advances). Default: `true` |
286
299
  | `pollOptions.includeActions` | boolean | When false, omits `actions[]` even if `waiting_permission`. Default: `true` |
287
300
  | `pollOptions.includeResult` | boolean | When false, omits top-level `result` even when `idle`/`error`. Default: `true` |
288
- | `pollOptions.includeUsage` | boolean | Include `result.usage` (default: true in full mode, false in minimal mode) |
289
- | `pollOptions.includeModelUsage` | boolean | Include `result.modelUsage` (default: true in full mode, false in minimal mode) |
290
- | `pollOptions.includeStructuredOutput` | boolean | Include `result.structuredOutput` (default: true in full mode, false in minimal mode) |
291
- | `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"` |
292
- | `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"` |
293
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 |
294
307
 
295
308
  </details>
@@ -299,8 +312,8 @@ Poll session events/results and approve/deny pending permission requests.
299
312
 
300
313
  | Parameter | Type | Description |
301
314
  | -------------------------------------- | ------ | ----------------------------------------------------------------------- |
302
- | `permissionOptions.updatedInput` | object | Modified tool input to run (`allow` only). Default: none |
303
- | `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 |
304
317
 
305
318
  </details>
306
319
 
@@ -309,6 +322,7 @@ Poll session events/results and approve/deny pending permission requests.
309
322
  Notes:
310
323
 
311
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.
312
326
  - Always treat `cursor` as an incremental position: store `nextCursor` and pass it back on the next poll to avoid replaying old events.
313
327
  - If `cursorResetTo` is present, your `cursor` was too old (events were evicted); reset your cursor to `cursorResetTo`.
314
328
  - For safety, de-duplicate events by `event.id` on the client side.
@@ -319,6 +333,7 @@ Notes:
319
333
  - Permission `actions[]` include `timeoutMs`, `expiresAt`, and best-effort `remainingMs` to help callers avoid auto-deny timeouts.
320
334
  - `permission_result` event data is `{ requestId, toolName, behavior, source, message?, interrupt? }` (denial details only present for `deny`).
321
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.
322
337
 
323
338
  ## Usage Example
324
339
 
@@ -364,7 +379,7 @@ while True:
364
379
  final_result = data.get("result")
365
380
  break
366
381
 
367
- # 3) Manage sessions (list/get/cancel)
382
+ # 3) Manage sessions (list/get/cancel/interrupt)
368
383
  result = await mcp.call_tool("claude_code_session", {"action": "list"})
369
384
  ```
370
385
 
@@ -425,6 +440,7 @@ setx CLAUDE_CODE_GIT_BASH_PATH "C:\Program Files\Git\bin\bash.exe"
425
440
  - **Async permission approvals** — when a tool call needs approval, the session transitions to `waiting_permission` and surfaces requests via `claude_code_check` (`actions[]`).
426
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.
427
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).
428
444
  - Tool visibility vs approvals:
429
445
  - Use `advanced.tools` to restrict which tools the agent can _see_ (hidden tools cannot be called).
430
446
  - Use `allowedTools` to auto-approve specific tools without prompting (the SDK may still prompt for path-based restrictions like `blockedPath`).
@@ -444,6 +460,8 @@ All environment variables are optional. They are set on the MCP server process (
444
460
  | `CLAUDE_CODE_MCP_RESUME_SECRET` | HMAC secret used to validate `resumeToken` for disk resume fallback (recommended if disk resume is enabled) | _(unset)_ |
445
461
  | `CLAUDE_CODE_MCP_MAX_SESSIONS` | Maximum number of in-memory sessions (set `0` to disable the limit) | `128` |
446
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` |
447
465
 
448
466
  ### How to configure
449
467
 
@@ -530,7 +548,7 @@ MCP Client ←→ (stdio/JSON-RPC) ←→ MCP Server [same machine]
530
548
 
531
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`.
532
550
 
533
- 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`).
534
552
 
535
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.
536
554