Skip to content

fix(codemode): preserve MCP request context#1793

Merged
mattzcarey merged 3 commits into
mainfrom
fix/issue-1510-codemode-sdk
Jun 25, 2026
Merged

fix(codemode): preserve MCP request context#1793
mattzcarey merged 3 commits into
mainfrom
fix/issue-1510-codemode-sdk

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

openApiMcpServer now passes the outer MCP execute tool-call context to its host-side request callback:

request: async (options, context) => {
  // context.requestId, context.signal, context.sendRequest(), ...
}

This lets host callbacks associate elicitation, sampling, roots, and notifications with the originating tool call instead of sending them as standalone messages. The context stays in trusted host code and is not exposed to generated sandbox code. Existing callbacks that only accept options remain compatible.

Why

In #1510 tool registration is delegated to @cloudflare/codemode's openApiMcpServer. The MCP SDK supplies RequestHandlerExtra to every tool handler, but Codemode previously discarded that second argument before invoking the application's request callback. The callback therefore had no request id to pass as relatedRequestId, so server-to-client requests could not use the originating POST response stream. This PR preserves that SDK context in the per-execution host closure and exports it as OpenApiMcpRequestContext.

Relationship to #1734 (now merged)

The McpAgent.serve() + Dynamic Worker RPC path reported in #1510 needs both halves:

createMcpHandler / WorkerTransport only needs this PR.

Hibernation note

For the McpAgent deployment, prefer McpAgent.elicitInput(params, { relatedRequestId: context.requestId }). It wraps the wait in keepAliveWhile, which holds an alarm-backed keepAlive lease so the Durable Object is not evicted mid-elicitation. The pending elicitation resolver is in-memory by design: an elicitation cannot be resumed across a hard eviction, so the contract is to prevent hibernation during the bounded wait, not to persist the pending request. The new integration test asserts that lease is held during the wait and released after.

Tests

Codemode unit/contract (packages/codemode/src/tests/mcp.test.ts, in-memory transport + real DynamicWorkerExecutor):

  • the callback receives the exact outer JSON-RPC request id and cancellation signal;
  • overlapping Dynamic Worker executions retain separate request contexts;
  • a callback elicits input associated with the outer tool call and receives the client's answer.

Real McpAgent integration (packages/agents/src/tests/mcp/codemode-context.test.ts), no mocks of the transport, executor, or RPC boundary:

  • a TestCodemodeMcpAgent registers openApiMcpServer and elicits via McpAgent.elicitInput;
  • a real Streamable HTTP POST with no standalone GET stream goes through the Worker Loader executor;
  • the elicitation/create request arrives on the originating POST stream;
  • the client's response POST is accepted and the final tool result follows on the same stream;
  • the keepAlive lease is 1 while waiting and returns to 0 after completion.

Validation on the rebased branch:

  • agents MCP suite: 493 passed (includes the new integration test)
  • codemode: 299 unit/Workers + 38 runtime + 33 browser
  • pnpm run build (24 projects)
  • pnpm run check (exports, format, lint, 113 TypeScript projects)

Related: #1510, #1490, #1734

@changeset-bot

changeset-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d167fe4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/codemode Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1793

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1793

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1793

create-think

npm i https://pkg.pr.new/create-think@1793

hono-agents

npm i https://pkg.pr.new/hono-agents@1793

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1793

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1793

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1793

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1793

commit: d167fe4

@mattzcarey mattzcarey force-pushed the fix/issue-1510-codemode-sdk branch from a2b5b19 to ff15a40 Compare June 24, 2026 12:39
@mattzcarey mattzcarey marked this pull request as ready for review June 24, 2026 12:40

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@mattzcarey mattzcarey force-pushed the fix/issue-1510-codemode-sdk branch from e705c3d to 6549d28 Compare June 24, 2026 16:44
Matt Carey added 3 commits June 25, 2026 14:35
Adds a TestCodemodeMcpAgent that registers openApiMcpServer and elicits via McpAgent.elicitInput with the forwarded relatedRequestId. The test drives a real Streamable HTTP POST with no standalone GET stream through the Worker Loader executor RPC boundary, asserts the elicitation rides the originating POST and the tool result follows it, and checks the keepAlive lease is held during the nested wait and released afterward.
The request() callback runs while the sandbox is suspended on its codemode.request() RPC, so the DynamicWorkerExecutor timeout bounds the human-in-the-loop elicitation wait. The default executor timeout (60s, #1806) already matches the elicitation timeout; document that lowering it below the elicitation timeout aborts the call before the user can respond.
@mattzcarey mattzcarey force-pushed the fix/issue-1510-codemode-sdk branch from 6549d28 to d167fe4 Compare June 25, 2026 12:36
@mattzcarey mattzcarey merged commit 247ebeb into main Jun 25, 2026
7 checks passed
@mattzcarey mattzcarey deleted the fix/issue-1510-codemode-sdk branch June 25, 2026 12:52
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.

2 participants