@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 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.49` and align MCP-facing schemas with the current SDK surface.
12
- - Permission mode enum now follows SDK 0.2.49 (`default`, `acceptEdits`, `bypassPermissions`, `plan`, `dontAsk`; `delegate` removed).
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.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
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's bundled CLI version is determined by the SDK package version (e.g. SDK 0.2.38 = Claude Code 2.1.38)
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 resource update notifications after runtime tool discovery so clients can refresh both the `claude_code` tool description and `internal-tools` resource.
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 events (`tool_progress`, `auth_status`) in the events stream. 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 |
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 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.
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
- { behavior: "deny", message: opts?.reason ?? "Session interrupted", interrupt: true },
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
- elapsed_time_seconds: msg.elapsed_time_seconds
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 === "task_notification") {
1240
+ if (msg.type === "system" && msg.subtype === "hook_started") {
1229
1241
  return {
1230
1242
  type: "progress",
1231
1243
  data: {
1232
- type: "task_notification",
1233
- task_id: msg.task_id,
1234
- status: msg.status,
1235
- summary: msg.summary,
1236
- output_file: msg.output_file
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
- activeQuery.interrupt?.();
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 isPosixHomePath(value) {
2498
- return /^\/home\/[^/\s]+(?:\/|$)/.test(value);
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 extractPosixHomePath(value) {
2501
- const match = value.match(/\/home\/[^/\s"'`]+(?:\/[^\s"'`]*)?/);
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 = extractPosixHomePath(command);
2635
+ const embeddedPath = extractSuspiciousPosixAbsolutePath(command);
2531
2636
  if (embeddedPath) candidates.push(embeddedPath);
2532
2637
  }
2533
- const badPath = candidates.find((p) => isPosixHomePath(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 home path '${badPath}' on Windows. Prefer an absolute Windows path${cwdHint} to avoid out-of-bounds permission prompts.`
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.4.6" : "0.0.0-dev";
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
- if (!stdinUnavailable) {
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
- const elapsedMs = Date.now() - stdinClosedAt;
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 (elapsedMs >= STDIN_SHUTDOWN_MAX_WAIT_MS) {
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
- void shutdown("beforeExit");
4291
+ if (!server.isConnected()) {
4292
+ void shutdown("beforeExit");
4293
+ }
4170
4294
  });
4171
4295
  process.on("uncaughtException", handleUnexpectedError);
4172
4296
  process.on("unhandledRejection", handleUnexpectedError);