Skip to content

fix(mcp): execute tool dies on Deno >= 2.9 (unix sockets moved behind net permission)#101

Merged
Dithilli merged 1 commit into
mainfrom
david/mcp-execute-deno29-unix-net-gate
Jul 17, 2026
Merged

fix(mcp): execute tool dies on Deno >= 2.9 (unix sockets moved behind net permission)#101
Dithilli merged 1 commit into
mainfrom
david/mcp-execute-deno29-unix-net-gate

Conversation

@Dithilli

Copy link
Copy Markdown
Contributor

Supersedes #100, which fixed Deno 2.9 but would have broken 2.0–2.8.

Problem

Every execute call on @hyperspell/hyperspell-mcp@0.40.0 fails with "Deno exited before being ready" on Deno ≥ 2.9 (found in the 2026-07-16 MCP/CLI test battery). Silent: health checks and tools/list still pass.

Root cause — pinned down empirically and against Deno's changelog: Deno 2.9.0 moved unix sockets behind the net permission (--allow-net=unix:<path>), part of the 2.8.2–2.9.1 socket-hardening series (denoland/deno#34395, #35835). @valtown/deno-http-worker — 0.0.21 and latest 2.0.3, so a dependency bump is not a fix — still grants its Node↔sandbox socket via --allow-read/--allow-write.

Fix

The socket path is generated inside newDenoHTTPWorker; Deno accepts only exact socket paths (no globs/prefixes) and rejects repeated --allow-net flags — so nothing can be scoped up front. Instead use the library's spawnFunc hook: extract the socket path from the --allow-write flag it injects and comma-merge unix:<sock> onto the existing --allow-net scope at spawn time.

Gated on Deno ≥ 2.9 exactly. This is the critical difference from #100: Deno 2.0–2.8 reject the unix: token at startup (invalid port) and 1.x panics on it — while their legacy read/write grant still works.

Verification (real MCP stdio JSON-RPC, real execute calls)

Build Deno 2.8.3 Deno 2.9.3
Published 0.40.0 ✅ (legacy grant works) Deno exited before being ready
#100 (>= 2 gate) invalid port in 'unix:…'
This PR (>= 2.9 gate) ✅ returns 42 ✅ returns 42

Version bracket (worker-level): 2.0.1 / 2.4.4 / 2.6.8 / 2.8.3 all work with legacy grants and all reject the unix: token; enforcement starts at 2.9.0. Sandbox unchanged: fetch('https://example.com') from executed code still denied (NotCapable).

pnpm lint + pnpm test pass; prettier-clean.

Follow-ups (separate): upstream this into the stlc-mcp codegen source (packages/sdk-codegen-typescript/src/mcp/code-tool.ts) so regen doesn't clobber it, and offer the fix to val-town/deno-http-worker.

🤖 Generated with Claude Code

@firetiger-agent

firetiger-agent Bot commented Jul 17, 2026

Copy link
Copy Markdown

Firetiger has created a monitoring plan for this PR.

View monitor

@entelligence-ai-pr-reviews

Copy link
Copy Markdown

Confidence Score: 5/5 - Safe to Merge

Safe to merge — this PR correctly addresses a compatibility break introduced in Deno >= 2.9 where Unix socket access was moved behind a net permission gate, causing execute_tool to fail silently or crash. The fix is targeted and surgical, adding the necessary permission flag without broadening the attack surface beyond what is required for MCP tool execution. No logic regressions, missing validations, or security concerns were identified in the review.

Key Findings:

  • The change directly resolves a documented Deno runtime regression: Unix sockets now require explicit --allow-net or equivalent net permission in Deno >= 2.9, and the fix correctly threads that permission through the execution path.
  • No new code paths, side effects, or conditional branches are introduced — the diff is minimal and confined to the permission configuration for the Deno subprocess invocation.
  • All reviewed files passed automated analysis with zero issues flagged at any severity level, and there are no pre-existing unresolved review comments that would cast doubt on correctness.

… net permission)

Deno 2.9.0 moved unix sockets behind the net permission as part of the
2.8.2-2.9.1 socket-hardening series (denoland/deno#34395, #35835).
deno-http-worker (0.0.21 and 2.0.3 alike) still grants its Node<->sandbox
socket via --allow-read/--allow-write, so on Deno >= 2.9 every execute
call dies at startup: 'Deno exited before being ready' (NotCapable).
Health checks and tools/list still pass, so the breakage is silent.

The socket path is generated inside newDenoHTTPWorker and Deno accepts
only exact socket paths (no globs) with no repeated --allow-net flags,
so no flag can be scoped up front. Use the library's spawnFunc hook to
pluck the socket path from the injected --allow-write flag and
comma-merge unix:<sock> onto the existing --allow-net scope.

Gated on Deno >= 2.9 exactly: 2.0-2.8 reject the unix: token at startup
('invalid port') and 1.x panics on it, while their legacy read/write
grant keeps working.

Verified end-to-end over MCP stdio: published 0.40.0 fails on 2.9.3;
this build returns results on both 2.8.3 and 2.9.3; a >=2 gate (the
naive fix) provably breaks 2.8.3; non-allowlisted fetch stays denied.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Dithilli
Dithilli force-pushed the david/mcp-execute-deno29-unix-net-gate branch from e20f878 to 9ecd689 Compare July 17, 2026 00:56
@Dithilli
Dithilli merged commit 6b11b2f into main Jul 17, 2026
7 checks passed
@aburkard aburkard mentioned this pull request Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant