@leo000001/claude-code-mcp 2.4.6 → 2.5.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 +13 -4
- package/NOTICE.md +2 -2
- package/README.md +18 -18
- package/dist/index.js +150 -26
- package/dist/index.js.map +1 -1
- package/package.json +96 -93
package/CHANGELOG.md
CHANGED
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- (TBD)
|
|
6
|
+
|
|
7
|
+
## 2.5.0 (2026-02-27)
|
|
8
|
+
|
|
5
9
|
### Security
|
|
6
10
|
|
|
7
11
|
- Validate `resumeToken` using timing-safe comparison (`timingSafeEqual` for fixed-length HMAC tokens) to reduce timing side-channel risk.
|
|
12
|
+
- Refresh transitive dependencies via `npm audit fix` (0 known vulnerabilities after update).
|
|
8
13
|
|
|
9
14
|
### Improvements
|
|
10
15
|
|
|
11
|
-
- Upgrade `@anthropic-ai/claude-agent-sdk` to `^0.2.
|
|
12
|
-
-
|
|
16
|
+
- Upgrade `@anthropic-ai/claude-agent-sdk` to `^0.2.62` and align MCP-facing schemas with the current SDK surface.
|
|
17
|
+
- Upgrade `@modelcontextprotocol/sdk` to `^1.27.1`.
|
|
18
|
+
- Permission mode enum now follows SDK 0.2.62 (`default`, `acceptEdits`, `bypassPermissions`, `plan`, `dontAsk`; `delegate` removed).
|
|
13
19
|
- Session cleanup now marks timed-out running/waiting sessions as `cancelled` for consistent status semantics.
|
|
14
20
|
- `SessionManager.destroy()` now clears in-memory session/runtime maps after aborting active runs, so post-destroy reads are no longer stale.
|
|
15
21
|
- Event buffer eviction now uses batch compaction (instead of repeated `findIndex` + `splice`) and `readEvents` now uses binary search for cursor start.
|
|
@@ -18,10 +24,13 @@
|
|
|
18
24
|
- Enrich compatibility resources with package version, disk-resume diagnostics, and runtime limits.
|
|
19
25
|
- Remove deprecated `claude_code` parameter aliases: top-level `sessionInitTimeoutMs` and `advanced.effort` / `advanced.thinking`.
|
|
20
26
|
- Add support for SDK `promptSuggestions` option passthrough and expose `promptSuggestions` in `advanced`/`diskResumeConfig`.
|
|
21
|
-
- Query consumer now maps additional SDK stream messages (`system/task_started`, `rate_limit`, `prompt_suggestion`) to progress events.
|
|
27
|
+
- Query consumer now maps additional SDK stream messages (`system/task_started`, `system/task_progress`, `system/hook_*`, `system/files_persisted`, `rate_limit`, `prompt_suggestion`) to progress events.
|
|
28
|
+
- Event buffer eviction now prefers dropping noisy progress events before output events to reduce missed output under high-frequency streams.
|
|
22
29
|
|
|
23
30
|
### Documentation
|
|
24
31
|
|
|
32
|
+
- Restructure documentation architecture: `AGENTS.md` is now execution-first, while `docs/DESIGN.md` is the single detailed source for interface/mapping semantics.
|
|
33
|
+
- Add explicit doc-governance rules, upgrade submission template, and document DoD to reduce AGENTS/DESIGN duplication regression.
|
|
25
34
|
- Align README/DESIGN/AGENTS with current defaults and behavior (timeout clamp, advanced parameter count, lifecycle semantics).
|
|
26
35
|
- Clarify package positioning as CLI-first and remove stale guidance that implied a public programmatic API surface.
|
|
27
36
|
- Update CONTRIBUTING with local environment requirements (Node/npm and Windows Git Bash notes).
|
|
@@ -39,7 +48,7 @@
|
|
|
39
48
|
- Add `CLAUDE_CODE_MCP_MAX_PENDING_PERMISSIONS` (default: `64`) to cap outstanding permission requests per session.
|
|
40
49
|
- Promote `effort` and `thinking` to top-level parameters on `claude_code` and `claude_code_reply` (deprecated aliases: `advanced.effort`, `advanced.thinking`).
|
|
41
50
|
- Tool responses now include `structuredContent` (in addition to JSON text) for easier MCP client consumption.
|
|
42
|
-
- Emit `tools/list_changed` and `resources/list_changed` once after connect; update `claude_code` tool description dynamically when runtime tool discovery changes.
|
|
51
|
+
- Emit `notifications/tools/list_changed` and `notifications/resources/list_changed` once after connect; update `claude_code` tool description dynamically when runtime tool discovery changes.
|
|
43
52
|
- Align declared MCP capabilities with implemented primitives (`logging`, `tools`, `resources`) and remove prompt primitive exposure.
|
|
44
53
|
- Add unit tests for `build-options.ts` and `race-with-abort.ts`.
|
|
45
54
|
|
package/NOTICE.md
CHANGED
|
@@ -9,8 +9,8 @@ requirements on redistribution and use.
|
|
|
9
9
|
|
|
10
10
|
### Direct dependencies (from `package.json`)
|
|
11
11
|
|
|
12
|
-
- `@anthropic-ai/claude-agent-sdk@0.2.
|
|
13
|
-
- `@modelcontextprotocol/sdk@1.
|
|
12
|
+
- `@anthropic-ai/claude-agent-sdk@0.2.62` — 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.27.1` — MIT License
|
|
14
14
|
- `zod@4.3.6` — MIT License
|
|
15
15
|
|
|
16
16
|
For a complete dependency graph, see `package-lock.json`. When installed, each dependency’s
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ See `CHANGELOG.md` for release history.
|
|
|
32
32
|
|
|
33
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.
|
|
34
34
|
|
|
35
|
-
- The SDK
|
|
35
|
+
- The SDK bundles a Claude Code CLI; its version generally tracks the SDK package version, but the exact scheme is not guaranteed
|
|
36
36
|
- **Configuration is shared** — the bundled CLI reads API keys and settings from `~/.claude/`, same as the system-installed `claude`
|
|
37
37
|
- **All local settings are loaded by default** — unlike the raw SDK (which defaults to isolation mode), this MCP server loads `user`, `project`, and `local` settings automatically, including `CLAUDE.md` project context. Pass `advanced.settingSources: []` to opt out
|
|
38
38
|
- You must have Claude Code configured (API key set up) before using this MCP server: see [Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/overview)
|
|
@@ -62,7 +62,7 @@ Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
|
|
|
62
62
|
}
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
> Some clients cache tool/resource metadata at connect-time. This server emits `notifications/tools/list_changed` and
|
|
65
|
+
> Some clients cache tool/resource metadata at connect-time. This server emits `notifications/tools/list_changed` and `notifications/resources/list_changed` after runtime tool discovery so clients can refresh both the `claude_code` tool description and `internal-tools` resource.
|
|
66
66
|
|
|
67
67
|
### Anthropic Claude Code CLI (as an MCP client)
|
|
68
68
|
|
|
@@ -123,7 +123,7 @@ Start a new Claude Code session. The agent autonomously performs coding tasks: r
|
|
|
123
123
|
| ------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
124
124
|
| `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 |
|
|
125
125
|
| `advanced.persistSession` | boolean | Persist session history to disk (`~/.claude/projects/`). Default: `true`. Set `false` to disable. |
|
|
126
|
-
| `advanced.sessionInitTimeoutMs` | number | Session init timeout in milliseconds waiting for `system/init`. Default: `10000`.
|
|
126
|
+
| `advanced.sessionInitTimeoutMs` | number | Session init timeout in milliseconds waiting for `system/init`. Default: `10000`. |
|
|
127
127
|
| `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. |
|
|
128
128
|
| `advanced.agent` | string | Name of a custom agent (defined in `agents`) to use as the primary agent. Default: omitted |
|
|
129
129
|
| `advanced.maxBudgetUsd` | number | Maximum budget in USD. Default: SDK/Claude Code default |
|
|
@@ -136,7 +136,7 @@ Start a new Claude Code session. The agent autonomously performs coding tasks: r
|
|
|
136
136
|
| `advanced.fallbackModel` | string | Fallback model if the primary model fails or is unavailable. Default: none |
|
|
137
137
|
| `advanced.enableFileCheckpointing` | boolean | Enable file checkpointing to track file changes during the session. Default: `false` |
|
|
138
138
|
| `advanced.includePartialMessages` | boolean | When true, includes intermediate streaming messages in the response. Useful for real-time progress monitoring. Default: false |
|
|
139
|
-
| `advanced.promptSuggestions` | boolean | When true, emits post-turn prompt suggestion events (`prompt_suggestion`). Default: `false`
|
|
139
|
+
| `advanced.promptSuggestions` | boolean | When true, emits post-turn prompt suggestion events (`prompt_suggestion`). Default: `false` |
|
|
140
140
|
| `advanced.strictMcpConfig` | boolean | Enforce strict validation of MCP server configurations. Default: `false` |
|
|
141
141
|
| `advanced.settingSources` | string[] | Which filesystem settings to load. Defaults to `["user", "project", "local"]` (loads all settings and CLAUDE.md). Pass `[]` for SDK isolation mode |
|
|
142
142
|
| `advanced.debug` | boolean | Enable debug mode for verbose logging. Default: `false` |
|
|
@@ -207,7 +207,7 @@ Continue an existing session by sending a follow-up message. The agent retains f
|
|
|
207
207
|
| `diskResumeConfig.fallbackModel` | string | Fallback model. Default: none |
|
|
208
208
|
| `diskResumeConfig.enableFileCheckpointing` | boolean | Enable file checkpointing. Default: `false` |
|
|
209
209
|
| `diskResumeConfig.includePartialMessages` | boolean | Include intermediate streaming messages. Default: `false` |
|
|
210
|
-
| `diskResumeConfig.promptSuggestions` | boolean | Emit post-turn prompt suggestion events (`prompt_suggestion`). Default: `false`
|
|
210
|
+
| `diskResumeConfig.promptSuggestions` | boolean | Emit post-turn prompt suggestion events (`prompt_suggestion`). Default: `false` |
|
|
211
211
|
| `diskResumeConfig.strictMcpConfig` | boolean | Strict MCP config validation. Default: `false` |
|
|
212
212
|
| `diskResumeConfig.settingSources` | string[] | Which filesystem settings to load. Default: `["user", "project", "local"]` |
|
|
213
213
|
| `diskResumeConfig.debug` | boolean | Debug mode. Default: `false` |
|
|
@@ -291,18 +291,18 @@ Poll session events/results and approve/deny pending permission requests.
|
|
|
291
291
|
<details>
|
|
292
292
|
<summary><code>pollOptions</code> object parameters (10 fine-grained poll controls)</summary>
|
|
293
293
|
|
|
294
|
-
| Parameter | Type | Description
|
|
295
|
-
| ------------------------------------- | ------- |
|
|
296
|
-
| `pollOptions.includeTools` | boolean | When true, includes `availableTools` (`poll` only). Default: `false` (omitted until session init is received). Derived from SDK `system/init.tools` (internal features may not appear).
|
|
297
|
-
| `pollOptions.includeEvents` | boolean | When false, omits `events` (but `nextCursor` still advances). Default: `true`
|
|
298
|
-
| `pollOptions.includeActions` | boolean | When false, omits `actions[]` even if `waiting_permission`. Default: `true`
|
|
299
|
-
| `pollOptions.includeResult` | boolean | When false, omits top-level `result` even when `idle`/`error`. Default: `true`
|
|
300
|
-
| `pollOptions.includeUsage` | boolean | Include `result.usage` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`)
|
|
301
|
-
| `pollOptions.includeModelUsage` | boolean | Include `result.modelUsage` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`)
|
|
302
|
-
| `pollOptions.includeStructuredOutput` | boolean | Include `result.structuredOutput` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`)
|
|
303
|
-
| `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"`
|
|
304
|
-
| `pollOptions.includeProgressEvents` | boolean | When true, includes progress
|
|
305
|
-
| `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
|
+
| Parameter | Type | Description |
|
|
295
|
+
| ------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
296
|
+
| `pollOptions.includeTools` | boolean | When true, includes `availableTools` (`poll` only). Default: `false` (omitted until session init is received). Derived from SDK `system/init.tools` (internal features may not appear). |
|
|
297
|
+
| `pollOptions.includeEvents` | boolean | When false, omits `events` (but `nextCursor` still advances). Default: `true` |
|
|
298
|
+
| `pollOptions.includeActions` | boolean | When false, omits `actions[]` even if `waiting_permission`. Default: `true` |
|
|
299
|
+
| `pollOptions.includeResult` | boolean | When false, omits top-level `result` even when `idle`/`error`. Default: `true` |
|
|
300
|
+
| `pollOptions.includeUsage` | boolean | Include `result.usage` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`) |
|
|
301
|
+
| `pollOptions.includeModelUsage` | boolean | Include `result.modelUsage` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`) |
|
|
302
|
+
| `pollOptions.includeStructuredOutput` | boolean | Include `result.structuredOutput` (default: `true` in `"full"`, `false` in `"minimal"`/`"delta_compact"`) |
|
|
303
|
+
| `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"` |
|
|
304
|
+
| `pollOptions.includeProgressEvents` | boolean | When true, includes noisy SDK progress subtypes (e.g. `tool_progress`, `auth_status`, `system/task_progress`, `system/hook_progress`) as MCP `progress` events. Default: `false` in `"minimal"`/`"delta_compact"`, `true` in `"full"` |
|
|
305
|
+
| `pollOptions.maxBytes` | number | Approximate max JSON bytes for `events` in this response. When exceeded, events are truncated and `truncatedFields` includes `"events_bytes"`. Default: unlimited |
|
|
306
306
|
|
|
307
307
|
</details>
|
|
308
308
|
|
|
@@ -331,7 +331,7 @@ Notes:
|
|
|
331
331
|
- `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.
|
|
332
332
|
- Permission `actions[]` include `timeoutMs`, `expiresAt`, and best-effort `remainingMs` to help callers avoid auto-deny timeouts.
|
|
333
333
|
- `permission_result` event data is `{ requestId, toolName, behavior, source, message?, interrupt? }` (denial details only present for `deny`).
|
|
334
|
-
- In `"minimal"` mode (default): assistant message events are slimmed (strips `usage`, `model`, `id`, `cache_control` from content blocks); noisy progress
|
|
334
|
+
- In `"minimal"` mode (default): assistant message events are slimmed (strips `usage`, `model`, `id`, `cache_control` from content blocks); noisy SDK progress subtypes (`tool_progress`, `auth_status`, `system/task_progress`, `system/hook_progress`) are filtered out; `lastEventId`/`lastToolUseId` are omitted; `AgentResult` omits `durationApiMs`/`sessionTotalTurns`/`sessionTotalCostUsd`. Use `responseMode: "full"` or individual `include*` flags to restore any of these.
|
|
335
335
|
- 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.
|
|
336
336
|
|
|
337
337
|
## Usage Example
|
package/dist/index.js
CHANGED
|
@@ -329,7 +329,9 @@ var SessionManager = class _SessionManager {
|
|
|
329
329
|
if (info.status === "waiting_permission") {
|
|
330
330
|
this.finishAllPending(
|
|
331
331
|
sessionId,
|
|
332
|
-
|
|
332
|
+
// Similar to cancel(), avoid emitting interrupt=true while the query stream is
|
|
333
|
+
// being torn down to reduce SDK-level write/teardown races on stdio clients.
|
|
334
|
+
{ behavior: "deny", message: opts?.reason ?? "Session interrupted", interrupt: false },
|
|
333
335
|
"interrupt"
|
|
334
336
|
);
|
|
335
337
|
}
|
|
@@ -839,7 +841,15 @@ var SessionManager = class _SessionManager {
|
|
|
839
841
|
if (typeof requestId !== "string") return true;
|
|
840
842
|
return isActivePermissionRequest ? !isActivePermissionRequest(requestId) : true;
|
|
841
843
|
};
|
|
844
|
+
const isNoisyProgressEvent = (event) => {
|
|
845
|
+
if (event.type !== "progress") return false;
|
|
846
|
+
const t = event.data?.type;
|
|
847
|
+
return t === "tool_progress" || t === "auth_status" || t === "task_progress" || t === "hook_progress";
|
|
848
|
+
};
|
|
842
849
|
let toDropForSoftLimit = remaining - buffer.maxSize;
|
|
850
|
+
if (toDropForSoftLimit > 0) {
|
|
851
|
+
toDropForSoftLimit -= dropOldestMatching(toDropForSoftLimit, isNoisyProgressEvent);
|
|
852
|
+
}
|
|
843
853
|
if (toDropForSoftLimit > 0) {
|
|
844
854
|
toDropForSoftLimit -= dropOldestMatching(toDropForSoftLimit, (event) => !event.pinned);
|
|
845
855
|
}
|
|
@@ -1204,7 +1214,9 @@ function messageToEvent(msg) {
|
|
|
1204
1214
|
type: "tool_progress",
|
|
1205
1215
|
tool_use_id: msg.tool_use_id,
|
|
1206
1216
|
tool_name: msg.tool_name,
|
|
1207
|
-
|
|
1217
|
+
parent_tool_use_id: msg.parent_tool_use_id,
|
|
1218
|
+
elapsed_time_seconds: msg.elapsed_time_seconds,
|
|
1219
|
+
task_id: msg.task_id
|
|
1208
1220
|
}
|
|
1209
1221
|
};
|
|
1210
1222
|
}
|
|
@@ -1225,15 +1237,55 @@ function messageToEvent(msg) {
|
|
|
1225
1237
|
data: { type: "status", status: msg.status, permissionMode: msg.permissionMode }
|
|
1226
1238
|
};
|
|
1227
1239
|
}
|
|
1228
|
-
if (msg.type === "system" && msg.subtype === "
|
|
1240
|
+
if (msg.type === "system" && msg.subtype === "hook_started") {
|
|
1229
1241
|
return {
|
|
1230
1242
|
type: "progress",
|
|
1231
1243
|
data: {
|
|
1232
|
-
type: "
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1244
|
+
type: "hook_started",
|
|
1245
|
+
hook_id: msg.hook_id,
|
|
1246
|
+
hook_name: msg.hook_name,
|
|
1247
|
+
hook_event: msg.hook_event
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
if (msg.type === "system" && msg.subtype === "hook_progress") {
|
|
1252
|
+
return {
|
|
1253
|
+
type: "progress",
|
|
1254
|
+
data: {
|
|
1255
|
+
type: "hook_progress",
|
|
1256
|
+
hook_id: msg.hook_id,
|
|
1257
|
+
hook_name: msg.hook_name,
|
|
1258
|
+
hook_event: msg.hook_event,
|
|
1259
|
+
stdout: msg.stdout,
|
|
1260
|
+
stderr: msg.stderr,
|
|
1261
|
+
output: msg.output
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
if (msg.type === "system" && msg.subtype === "hook_response") {
|
|
1266
|
+
return {
|
|
1267
|
+
type: "progress",
|
|
1268
|
+
data: {
|
|
1269
|
+
type: "hook_response",
|
|
1270
|
+
hook_id: msg.hook_id,
|
|
1271
|
+
hook_name: msg.hook_name,
|
|
1272
|
+
hook_event: msg.hook_event,
|
|
1273
|
+
output: msg.output,
|
|
1274
|
+
stdout: msg.stdout,
|
|
1275
|
+
stderr: msg.stderr,
|
|
1276
|
+
exit_code: msg.exit_code,
|
|
1277
|
+
outcome: msg.outcome
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
if (msg.type === "system" && msg.subtype === "files_persisted") {
|
|
1282
|
+
return {
|
|
1283
|
+
type: "progress",
|
|
1284
|
+
data: {
|
|
1285
|
+
type: "files_persisted",
|
|
1286
|
+
files: msg.files,
|
|
1287
|
+
failed: msg.failed,
|
|
1288
|
+
processed_at: msg.processed_at
|
|
1237
1289
|
}
|
|
1238
1290
|
};
|
|
1239
1291
|
}
|
|
@@ -1249,9 +1301,38 @@ function messageToEvent(msg) {
|
|
|
1249
1301
|
}
|
|
1250
1302
|
};
|
|
1251
1303
|
}
|
|
1304
|
+
if (msg.type === "system" && msg.subtype === "task_progress") {
|
|
1305
|
+
return {
|
|
1306
|
+
type: "progress",
|
|
1307
|
+
data: {
|
|
1308
|
+
type: "task_progress",
|
|
1309
|
+
task_id: msg.task_id,
|
|
1310
|
+
tool_use_id: msg.tool_use_id,
|
|
1311
|
+
description: msg.description,
|
|
1312
|
+
usage: msg.usage,
|
|
1313
|
+
last_tool_name: msg.last_tool_name
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
if (msg.type === "system" && msg.subtype === "task_notification") {
|
|
1318
|
+
return {
|
|
1319
|
+
type: "progress",
|
|
1320
|
+
data: {
|
|
1321
|
+
type: "task_notification",
|
|
1322
|
+
task_id: msg.task_id,
|
|
1323
|
+
tool_use_id: msg.tool_use_id,
|
|
1324
|
+
status: msg.status,
|
|
1325
|
+
summary: msg.summary,
|
|
1326
|
+
output_file: msg.output_file,
|
|
1327
|
+
usage: msg.usage
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1252
1331
|
if (msg.type === "rate_limit" || msg.type === "prompt_suggestion") {
|
|
1253
1332
|
const rest = { ...msg };
|
|
1254
1333
|
delete rest.type;
|
|
1334
|
+
delete rest.uuid;
|
|
1335
|
+
delete rest.session_id;
|
|
1255
1336
|
return {
|
|
1256
1337
|
type: "progress",
|
|
1257
1338
|
data: { type: msg.type, ...rest }
|
|
@@ -1404,7 +1485,11 @@ function consumeQuery(params) {
|
|
|
1404
1485
|
}
|
|
1405
1486
|
};
|
|
1406
1487
|
const interrupt = () => {
|
|
1407
|
-
|
|
1488
|
+
try {
|
|
1489
|
+
void Promise.resolve(activeQuery.interrupt?.()).catch(() => {
|
|
1490
|
+
});
|
|
1491
|
+
} catch {
|
|
1492
|
+
}
|
|
1408
1493
|
};
|
|
1409
1494
|
const done = (async () => {
|
|
1410
1495
|
const preInit = [];
|
|
@@ -2298,6 +2383,23 @@ var TOOL_CATALOG = {
|
|
|
2298
2383
|
description: "Ask user a question",
|
|
2299
2384
|
category: "interaction"
|
|
2300
2385
|
},
|
|
2386
|
+
SubscribeMcpResource: {
|
|
2387
|
+
description: "Subscribe to an MCP resource stream",
|
|
2388
|
+
category: "mcp",
|
|
2389
|
+
notes: ["Requires an MCP server that supports resource subscriptions."]
|
|
2390
|
+
},
|
|
2391
|
+
UnsubscribeMcpResource: {
|
|
2392
|
+
description: "Unsubscribe from an MCP resource stream",
|
|
2393
|
+
category: "mcp"
|
|
2394
|
+
},
|
|
2395
|
+
SubscribePolling: {
|
|
2396
|
+
description: "Subscribe to periodic polling",
|
|
2397
|
+
category: "mcp"
|
|
2398
|
+
},
|
|
2399
|
+
UnsubscribePolling: {
|
|
2400
|
+
description: "Unsubscribe from periodic polling",
|
|
2401
|
+
category: "mcp"
|
|
2402
|
+
},
|
|
2301
2403
|
TeamDelete: {
|
|
2302
2404
|
description: "Delete team (may need shutdown_approved first)",
|
|
2303
2405
|
category: "agent",
|
|
@@ -2494,11 +2596,14 @@ function detectPathCompatibilityWarnings(session) {
|
|
|
2494
2596
|
}
|
|
2495
2597
|
return warnings;
|
|
2496
2598
|
}
|
|
2497
|
-
function
|
|
2498
|
-
|
|
2599
|
+
function isSuspiciousPosixAbsolutePathOnWindows(value) {
|
|
2600
|
+
if (!value.startsWith("/") || value.startsWith("//")) return false;
|
|
2601
|
+
return /^\/home\/[^/\s]+(?:\/|$)/.test(value) || /^\/(?:mnt\/)?[a-zA-Z](?:\/|$)/.test(value) || /^\/(tmp|var|etc|opt|usr|bin|sbin)(?:\/|$)/.test(value);
|
|
2499
2602
|
}
|
|
2500
|
-
function
|
|
2501
|
-
const match = value.match(
|
|
2603
|
+
function extractSuspiciousPosixAbsolutePath(value) {
|
|
2604
|
+
const match = value.match(
|
|
2605
|
+
/\/(?:home\/[^/\s"'`]+(?:\/[^\s"'`]*)?|(?:mnt\/)?[a-zA-Z](?:\/[^\s"'`]*)?|(?:tmp|var|etc|opt|usr|bin|sbin)(?:\/[^\s"'`]*)?)/
|
|
2606
|
+
);
|
|
2502
2607
|
return match?.[0];
|
|
2503
2608
|
}
|
|
2504
2609
|
function detectPendingPermissionPathWarnings(pending, session) {
|
|
@@ -2527,13 +2632,13 @@ function detectPendingPermissionPathWarnings(pending, session) {
|
|
|
2527
2632
|
}
|
|
2528
2633
|
const command = req.input.command;
|
|
2529
2634
|
if (typeof command === "string") {
|
|
2530
|
-
const embeddedPath =
|
|
2635
|
+
const embeddedPath = extractSuspiciousPosixAbsolutePath(command);
|
|
2531
2636
|
if (embeddedPath) candidates.push(embeddedPath);
|
|
2532
2637
|
}
|
|
2533
|
-
const badPath = candidates.find((p) =>
|
|
2638
|
+
const badPath = candidates.find((p) => isSuspiciousPosixAbsolutePathOnWindows(p));
|
|
2534
2639
|
if (!badPath) continue;
|
|
2535
2640
|
warnings.push(
|
|
2536
|
-
`Permission request '${req.requestId}' uses POSIX
|
|
2641
|
+
`Permission request '${req.requestId}' uses POSIX absolute path '${badPath}' on Windows. Prefer an absolute Windows path${cwdHint} to avoid out-of-bounds permission prompts.`
|
|
2537
2642
|
);
|
|
2538
2643
|
}
|
|
2539
2644
|
return warnings;
|
|
@@ -2649,7 +2754,7 @@ function buildResult(sessionManager, toolCache, input) {
|
|
|
2649
2754
|
if (e.type !== "progress") return true;
|
|
2650
2755
|
const d = e.data;
|
|
2651
2756
|
const progressType = d?.type;
|
|
2652
|
-
return progressType !== "tool_progress" && progressType !== "auth_status";
|
|
2757
|
+
return progressType !== "tool_progress" && progressType !== "auth_status" && progressType !== "task_progress" && progressType !== "hook_progress";
|
|
2653
2758
|
});
|
|
2654
2759
|
}
|
|
2655
2760
|
return filtered;
|
|
@@ -3590,7 +3695,7 @@ function registerResources(server, deps) {
|
|
|
3590
3695
|
}
|
|
3591
3696
|
|
|
3592
3697
|
// src/server.ts
|
|
3593
|
-
var SERVER_VERSION = true ? "2.
|
|
3698
|
+
var SERVER_VERSION = true ? "2.5.0" : "0.0.0-dev";
|
|
3594
3699
|
function createServerContext(serverCwd) {
|
|
3595
3700
|
const sessionManager = new SessionManager();
|
|
3596
3701
|
const server = new McpServer(
|
|
@@ -4029,7 +4134,8 @@ var BENIGN_MESSAGE_PATTERNS = [
|
|
|
4029
4134
|
"write after end",
|
|
4030
4135
|
"stream was destroyed",
|
|
4031
4136
|
"cannot call write after a stream was destroyed",
|
|
4032
|
-
"the pipe is being closed"
|
|
4137
|
+
"the pipe is being closed",
|
|
4138
|
+
"query closed before response received"
|
|
4033
4139
|
];
|
|
4034
4140
|
function isBenignRuntimeError(error) {
|
|
4035
4141
|
if (!(error instanceof Error)) return false;
|
|
@@ -4041,6 +4147,15 @@ function isBenignRuntimeError(error) {
|
|
|
4041
4147
|
return BENIGN_MESSAGE_PATTERNS.some((pattern) => message.includes(pattern));
|
|
4042
4148
|
}
|
|
4043
4149
|
|
|
4150
|
+
// src/utils/stdin-shutdown.ts
|
|
4151
|
+
function decideStdinShutdown(params) {
|
|
4152
|
+
if (!params.stdinUnavailable) return "clear";
|
|
4153
|
+
if (params.isConnected) return "reschedule";
|
|
4154
|
+
if (!params.hasActiveSessions) return "shutdown_now";
|
|
4155
|
+
if (params.elapsedMs >= params.maxWaitMs) return "shutdown_timeout";
|
|
4156
|
+
return "reschedule";
|
|
4157
|
+
}
|
|
4158
|
+
|
|
4044
4159
|
// src/index.ts
|
|
4045
4160
|
var STDIN_SHUTDOWN_CHECK_MS = 750;
|
|
4046
4161
|
var STDIN_SHUTDOWN_MAX_WAIT_MS = process.platform === "win32" ? 15e3 : 1e4;
|
|
@@ -4117,19 +4232,26 @@ async function main() {
|
|
|
4117
4232
|
const evaluateStdinTermination = () => {
|
|
4118
4233
|
if (closing || stdinClosedAt === void 0) return;
|
|
4119
4234
|
const stdinUnavailable = process.stdin.destroyed || process.stdin.readableEnded || !process.stdin.readable;
|
|
4120
|
-
|
|
4235
|
+
const elapsedMs = Date.now() - stdinClosedAt;
|
|
4236
|
+
const active = hasActiveSessions();
|
|
4237
|
+
const connected = server.isConnected();
|
|
4238
|
+
const decision = decideStdinShutdown({
|
|
4239
|
+
stdinUnavailable,
|
|
4240
|
+
elapsedMs,
|
|
4241
|
+
maxWaitMs: STDIN_SHUTDOWN_MAX_WAIT_MS,
|
|
4242
|
+
hasActiveSessions: active,
|
|
4243
|
+
isConnected: connected
|
|
4244
|
+
});
|
|
4245
|
+
if (decision === "clear") {
|
|
4121
4246
|
stdinClosedAt = void 0;
|
|
4122
4247
|
stdinClosedReason = void 0;
|
|
4123
4248
|
return;
|
|
4124
4249
|
}
|
|
4125
|
-
|
|
4126
|
-
const active = hasActiveSessions();
|
|
4127
|
-
const connected = server.isConnected();
|
|
4128
|
-
if (!active && !connected) {
|
|
4250
|
+
if (decision === "shutdown_now") {
|
|
4129
4251
|
void shutdown(`stdin_${stdinClosedReason ?? "closed"}`);
|
|
4130
4252
|
return;
|
|
4131
4253
|
}
|
|
4132
|
-
if (
|
|
4254
|
+
if (decision === "shutdown_timeout") {
|
|
4133
4255
|
void shutdown(`stdin_${stdinClosedReason ?? "closed"}_timeout`);
|
|
4134
4256
|
return;
|
|
4135
4257
|
}
|
|
@@ -4166,7 +4288,9 @@ async function main() {
|
|
|
4166
4288
|
void shutdown("SIGHUP");
|
|
4167
4289
|
});
|
|
4168
4290
|
process.on("beforeExit", () => {
|
|
4169
|
-
|
|
4291
|
+
if (!server.isConnected()) {
|
|
4292
|
+
void shutdown("beforeExit");
|
|
4293
|
+
}
|
|
4170
4294
|
});
|
|
4171
4295
|
process.on("uncaughtException", handleUnexpectedError);
|
|
4172
4296
|
process.on("unhandledRejection", handleUnexpectedError);
|