Skip to content

Fix MCP elicitation detection and multi-resume hang - #126

Merged
RhysSullivan merged 3 commits into
mainfrom
fix/mcp-elicitation-and-resume-v2
Apr 9, 2026
Merged

Fix MCP elicitation detection and multi-resume hang#126
RhysSullivan merged 3 commits into
mainfrom
fix/mcp-elicitation-and-resume-v2

Conversation

@RhysSullivan

Copy link
Copy Markdown
Collaborator

Summary

  • Relax supportsManagedElicitation to only require form capability — clients like Claude Code that advertise { form: {} } now use inline elicitation instead of the pause/resume two-tool path
  • Fall back UrlElicitation to a form with the URL in the message when the client lacks url support
  • Fix resume() hanging when an execution triggers multiple elicitations (e.g. a loop calling multiple tools that each require approval) — the pause signal is now re-armable so resume races completion against a new pause
  • Update resume return type from ExecuteResult | null to ExecutionResult | null so callers can handle re-pauses

Test plan

  • All 23 MCP host tests pass (including new URL fallback test)
  • All 7 engine tests pass (including new multi-elicitation resume test)
  • Verified elicitation works end-to-end with Claude Code MCP client
  • Verified multi-resume works end-to-end (4 sequential DNS record creates with approval)

- Relax supportsManagedElicitation to only require form capability (not
  form AND url). Most MCP clients (including Claude Code) only advertise
  form support — they were incorrectly falling back to the pause/resume
  two-tool pattern.

- When a UrlElicitation is triggered but the client lacks url support,
  fall back to a form elicitation with the URL in the message.

- Fix resume hanging when an execution triggers multiple elicitations.
  The pause signal is now re-armable so resume races completion against
  a new pause, matching the executeWithPause pattern. Previously resume
  just awaited the completion promise which would never resolve if the
  execution paused again.

- Update resume return type from ExecuteResult | null to
  ExecutionResult | null so callers can handle re-pauses.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 9, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 8d3adab Commit Preview URL

Branch Preview URL
Apr 09 2026, 02:35 AM

Replace raw Promise.race, mutable callbacks, and unsafe casts with
idiomatic Effect primitives:

- Deferred<PausedExecution> as the pause signal (swappable via Ref)
- Deferred<ElicitationResponse> as the resume response channel
- Fiber for the sandbox execution (stays alive across pause/resume)
- Effect.race (non-interrupting) to await completion or next pause
@RhysSullivan
RhysSullivan merged commit c8d2673 into main Apr 9, 2026
2 checks passed
RhysSullivan added a commit that referenced this pull request May 31, 2026
* Fix MCP elicitation detection and multi-elicitation resume hang

- Relax supportsManagedElicitation to only require form capability (not
  form AND url). Most MCP clients (including Claude Code) only advertise
  form support — they were incorrectly falling back to the pause/resume
  two-tool pattern.

- When a UrlElicitation is triggered but the client lacks url support,
  fall back to a form elicitation with the URL in the message.

- Fix resume hanging when an execution triggers multiple elicitations.
  The pause signal is now re-armable so resume races completion against
  a new pause, matching the executeWithPause pattern. Previously resume
  just awaited the completion promise which would never resolve if the
  execution paused again.

- Update resume return type from ExecuteResult | null to
  ExecutionResult | null so callers can handle re-pauses.

* Refactor pause/resume engine to use Effect Deferred/Fiber/Ref

Replace raw Promise.race, mutable callbacks, and unsafe casts with
idiomatic Effect primitives:

- Deferred<PausedExecution> as the pause signal (swappable via Ref)
- Deferred<ElicitationResponse> as the resume response channel
- Fiber for the sandbox execution (stays alive across pause/resume)
- Effect.race (non-interrupting) to await completion or next pause

* Fix type error: orDie on Fiber.join to eliminate unknown error channel
@RhysSullivan
RhysSullivan deleted the fix/mcp-elicitation-and-resume-v2 branch June 11, 2026 08:01
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