From 180732abac60ce307e7f5fd92af67f0648282366 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 20 Jul 2026 20:22:17 +0100 Subject: [PATCH] [Agents] Document MCP and Code Mode SDK updates --- .../2026-07-22-mcp-codemode-updates.mdx | 59 +++++++++++++++++++ .../agents/harnesses/think/configuration.mdx | 1 + .../docs/agents/harnesses/think/tools.mdx | 25 +++++++- .../apis/client-api.mdx | 23 ++++++-- .../agents/tools/codemode/api-reference.mdx | 10 ++++ .../agents/tools/codemode/durable-runtime.mdx | 26 +++++++- .../docs/agents/tools/codemode/mcp.mdx | 19 ++++++ 7 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 src/content/changelog/agents/2026-07-22-mcp-codemode-updates.mdx diff --git a/src/content/changelog/agents/2026-07-22-mcp-codemode-updates.mdx b/src/content/changelog/agents/2026-07-22-mcp-codemode-updates.mdx new file mode 100644 index 00000000000..fb7cb5a5f90 --- /dev/null +++ b/src/content/changelog/agents/2026-07-22-mcp-codemode-updates.mdx @@ -0,0 +1,59 @@ +--- +title: Agents SDK reduces MCP schema conversion, adds exposure controls for MCP in Think and Code Mode SDK adds direct host APIs +description: Agents SDK reduces repeated MCP schema conversion and adds direct Code Mode runtime APIs for hosts that do not use the AI SDK. +products: + - agents + - workers +date: 2026-07-22 +--- + +import { PackageManagers, TypeScriptExample } from "~/components"; + +This release reduces repeated MCP schema conversion and adds an opt-out for Think's automatic MCP tool exposure. It also lets non-AI-SDK hosts invoke the durable Code Mode runtime directly. + +## Control direct MCP tool exposure in Think + +Agents SDK MCP clients now reuse converted input and output schemas while a live connection keeps the same tool catalog. This avoids converting every MCP JSON Schema to Zod again for each model turn. + +`@cloudflare/think` also adds `includeMcpTools`. Set it to `false` when you expose MCP tools through Code Mode or another mechanism outside Think's automatic tool set: + + + +```ts +import { Think } from "@cloudflare/think"; + +export class MyAgent extends Think { + includeMcpTools = false; + waitForMcpConnections = true; +} +``` + + + +This setting skips Think's automatic `getAITools()` call. MCP registration, restoration, discovery, raw catalog access, direct calls, and Code Mode connectors continue to work. + +Use [`listTools()`](/agents/model-context-protocol/apis/client-api/#thismcplisttools) when you only need the raw MCP catalog. For connector setup, refer to [Use MCP tools with Code Mode](/agents/tools/codemode/mcp/). + +## Invoke the Code Mode runtime without the AI SDK + +`@cloudflare/codemode@latest` adds `execute()`, `search()`, and `describe()` to the durable runtime handle. MCP servers and other hosts can now execute code and discover connector methods without adapting the runtime to an AI SDK tool. + + + +```ts +const matches = await runtime.search("create issue"); +const docs = await runtime.describe(matches.results[0].path); +const outcome = await runtime.execute({ + code: `async () => github.create_issue({ title: "Bug" })`, +}); +``` + + + +Search and describe results include `requiresApproval: true` for protected connector methods. Resolve a paused execution with the existing `approve()` and `reject()` methods. + +For setup and exact method types, refer to [Create a durable Code Mode runtime](/agents/tools/codemode/durable-runtime/) and the [Code Mode API reference](/agents/tools/codemode/api-reference/). + +## Upgrade + + diff --git a/src/content/docs/agents/harnesses/think/configuration.mdx b/src/content/docs/agents/harnesses/think/configuration.mdx index 96603155851..633fbce15af 100644 --- a/src/content/docs/agents/harnesses/think/configuration.mdx +++ b/src/content/docs/agents/harnesses/think/configuration.mdx @@ -29,6 +29,7 @@ Think is configured by overriding methods and properties on your `Think` subclas | `getSkillScriptRunner()` | `null` | Enable the optional `run_skill_script` tool | | `workspaceBash` | `true` | Include or configure the default workspace `bash` tool — refer to [Tools](/agents/harnesses/think/tools/) | | `messageConcurrency` | `"queue"` | How overlapping submits behave — refer to [Client tools](/agents/harnesses/think/client-tools/#message-concurrency) | +| `includeMcpTools` | `true` | Convert connected MCP tools to AI SDK tools and add them to model turns. Refer to [MCP tools](/agents/harnesses/think/tools/#mcp-tools) | | `waitForMcpConnections` | `false` | Wait for MCP servers before inference | | `chatRecovery` | `true` | Wrap WebSocket, sub-agent, programmatic, and continuation turns in `runFiber` for durable execution. Set to a configuration object with `maxAttempts`, `stableTimeoutMs`, `terminalMessage`, and `onExhausted` to tune bounded recovery | | `chatStreamStallTimeoutMs` | `0` (off) | Opt-in inactivity watchdog: abort a turn whose model stream produces no chunk for this long (measures the gap between chunks, including tool execution). With `chatRecovery` on, a stall routes into bounded recovery | diff --git a/src/content/docs/agents/harnesses/think/tools.mdx b/src/content/docs/agents/harnesses/think/tools.mdx index 18cc7b1bb3a..54c1b370332 100644 --- a/src/content/docs/agents/harnesses/think/tools.mdx +++ b/src/content/docs/agents/harnesses/think/tools.mdx @@ -21,7 +21,7 @@ On every turn, Think merges tools from multiple sources. Later sources override 3. **Extension tools** — tools from loaded extensions (prefixed by extension name) 4. **Session tools** — `set_context`, `load_context`, `search_context` (from `configureSession`) 5. **Skill tools** — `activate_skill`, `read_skill_resource`, `run_skill_script` (from `getSkills()`, refer to [Agent Skills](/agents/runtime/execution/agent-skills/)) -6. **MCP tools** — from connected MCP servers +6. **MCP tools** — from connected MCP servers when `includeMcpTools` is `true` 7. **Client tools** — from the browser (refer to [Client tools](/agents/harnesses/think/client-tools/)) Tools belong to the agent running the turn. For parent-child orchestration, use [Agents as tools](/agents/runtime/execution/agent-tools/) instead of passing one-off tools through `chat()`. @@ -181,7 +181,7 @@ beforeTurn(ctx: TurnContext) { ## MCP tools -Think inherits MCP client support from the `Agent` base class. MCP tools from connected servers are automatically merged into every turn. +Think inherits MCP client support from the `Agent` base class. By default, Think converts tools from connected MCP servers to AI SDK tools and adds them to every turn. Set `waitForMcpConnections` to ensure MCP servers are connected before inference runs: @@ -200,6 +200,27 @@ export class MyAgent extends Think { +If you expose MCP tools through Code Mode or another mechanism outside Think's automatic tool set, turn off direct AI SDK tool exposure: + + + +```ts +export class MyAgent extends Think { + includeMcpTools = false; + waitForMcpConnections = true; + + getModel() { + /* ... */ + } +} +``` + + + +`includeMcpTools` controls only the automatic model tool merge. MCP connections still register, restore, discover, and wait. Raw catalog access, direct calls, Code Mode connectors, and explicit `this.mcp.getAITools()` calls continue to work. + +Use this property instead of removing MCP tool names through `activeTools` in `beforeTurn`. Think converts MCP schemas before it calls `beforeTurn`, so `activeTools` cannot avoid that conversion. To configure a connector runtime, refer to [Use MCP tools with Code Mode](/agents/tools/codemode/mcp/). + Add MCP servers programmatically or via `@callable` methods: diff --git a/src/content/docs/agents/model-context-protocol/apis/client-api.mdx b/src/content/docs/agents/model-context-protocol/apis/client-api.mdx index 0d3b37f92e5..8552f8b4ce9 100644 --- a/src/content/docs/agents/model-context-protocol/apis/client-api.mdx +++ b/src/content/docs/agents/model-context-protocol/apis/client-api.mdx @@ -320,13 +320,14 @@ Once connected, access the server's capabilities: ### Get available tools +Use `listTools()` to inspect the raw MCP catalog without preparing tools for an AI SDK model call: + ```ts -const state = this.getMcpServers(); +const tools = this.mcp.listTools(); -// All tools from all connected servers -for (const tool of state.tools) { +for (const tool of tools) { console.log(`Tool: ${tool.name}`); console.log(` From server: ${tool.serverId}`); console.log(` Title: ${tool.title ?? tool.annotations?.title ?? tool.name}`); @@ -336,6 +337,8 @@ for (const tool of state.tools) { +`getMcpServers().tools` returns the same raw tool records as part of the full MCP client state. Neither API converts the tool schemas. + #### Integration with AI SDK To use MCP tools with the AI SDK, use `this.mcp.getAITools()` which converts MCP tools to AI SDK format: @@ -364,7 +367,7 @@ export class MyAgent extends Agent { :::note -`getMcpServers().tools` returns raw MCP `Tool` objects for inspection. Use `this.mcp.getAITools()` when passing tools to the AI SDK. +Use `this.mcp.listTools()` or `getMcpServers().tools` for discovery. Call `this.mcp.getAITools()` when passing tools to the AI SDK. `getAITools()` converts each input and output schema to Zod, then reuses those schemas while the live connection keeps the same current catalog. ::: @@ -1145,6 +1148,16 @@ Close all active server connections while preserving registrations. async closeAllConnections(): Promise ``` +#### `this.mcp.listTools()` + +Get raw MCP tool records without converting their schemas to Zod. + +```ts +listTools(filter?: MCPServerFilter): Array +``` + +Use this method for catalog discovery and inspection. Pass an `MCPServerFilter` to limit the returned tools to specific connections. + #### `this.mcp.getAITools()` Get all discovered MCP tools in a format compatible with the AI SDK. @@ -1155,6 +1168,8 @@ getAITools(filter?: MCPServerFilter): ToolSet Tools are automatically namespaced by server ID to prevent conflicts when multiple MCP servers expose tools with the same name. +`getAITools()` reuses converted schemas for the current catalog on each live connection. It converts schemas again after discovery replaces the catalog or the live connection changes. Each call returns fresh tool records and execute functions. Use `this.mcp.listTools()` when you only need the raw catalog. + Pass an `MCPServerFilter` to scope the returned tools to a subset of connected servers: diff --git a/src/content/docs/agents/tools/codemode/api-reference.mdx b/src/content/docs/agents/tools/codemode/api-reference.mdx index 6cbcc3c353b..015362e1142 100644 --- a/src/content/docs/agents/tools/codemode/api-reference.mdx +++ b/src/content/docs/agents/tools/codemode/api-reference.mdx @@ -51,6 +51,9 @@ interface CodemodeRuntimeHandle { tool( options?: CodemodeRuntimeToolOptions, ): Tool; + execute(input: ProxyToolInput): Promise; + search(query: string): Promise; + describe(target: string): Promise; approve(options: CodemodeApproveOptions): Promise; reject(options: CodemodeRejectOptions): Promise; rollback(options: CodemodeRollbackOptions): Promise; @@ -70,6 +73,9 @@ The handle methods have these effects: | Method | Effect | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tool(options?)` | Returns the AI SDK tool given to the model. `description` replaces the default description. `connectorHints` adds a one-line hint for each connector when using the default description. | +| `execute({ code })` | Runs code directly without adapting the runtime to an AI SDK tool. The result can complete, pause for approval, or return an error status. | +| `search(query)` | Searches connector methods and saved snippets without running sandbox code. | +| `describe(target)` | Returns on-demand TypeScript documentation for a connector, method, or saved snippet. | | `approve({ executionId })` | Resumes a paused execution through replay. The result can complete, pause again, or return an error status. It does not revive a non-paused execution. | | `reject({ seq, executionId })` | Rejects one pending action and terminates the execution. Returns `false` if the action is no longer pending. It does not roll back earlier actions. | | `rollback({ executionId })` | Calls available `revert` functions in reverse call order. Missing connectors and methods without `revert` remain applied. It attempts later reverts after a failure. | @@ -230,6 +236,7 @@ type SearchResult = { connector: string; method: string; description?: string; + requiresApproval?: boolean; kind: "method" | "snippet"; score: number; }; @@ -243,11 +250,14 @@ type SearchOutput = { type DescribeOutput = { path: string; description?: string; + requiresApproval?: boolean; types: string; kind: "connector" | "method" | "snippet"; }; ``` +`requiresApproval` is `true` when a connector method pauses before execution. It is omitted for methods that do not require approval and for snippets. + ### Snippet types ```ts diff --git a/src/content/docs/agents/tools/codemode/durable-runtime.mdx b/src/content/docs/agents/tools/codemode/durable-runtime.mdx index 2ca286579fd..ca1cd774f18 100644 --- a/src/content/docs/agents/tools/codemode/durable-runtime.mdx +++ b/src/content/docs/agents/tools/codemode/durable-runtime.mdx @@ -1,6 +1,6 @@ --- title: Create a durable Code Mode runtime -description: Create a Code Mode runtime with connectors, durable approvals, rollback, execution history, and reusable snippets. +description: Create a Code Mode runtime with connectors, direct host APIs, durable approvals, rollback, execution history, and reusable snippets. pcx_content_type: how-to sidebar: order: 1 @@ -23,7 +23,7 @@ Code Mode is experimental and may introduce breaking changes. Use caution in pro ## Prerequisites -You need an existing Agents SDK application that uses `AIChatAgent`, Vite, and the AI SDK. +You need an existing Agents SDK application with a Durable Object and Vite. The example uses `AIChatAgent` and the AI SDK. ## Integrate Code Mode @@ -234,6 +234,28 @@ You need an existing Agents SDK application that uses `AIChatAgent`, Vite, and t +## Use the runtime without the AI SDK + +Use `execute()`, `search()`, and `describe()` when an MCP server or another host invokes Code Mode without an AI SDK tool adapter: + + + +```ts +const runtime = this.#runtime(); +const matches = await runtime.search("create note"); +const method = matches.results[0]; +const docs = await runtime.describe(method.path); +const outcome = await runtime.execute({ + code: `async () => notes.createNote({ text: "Follow up" })`, +}); +``` + + + +`search()` and `describe()` do not run sandbox code. Their results include `requiresApproval: true` for connector methods that pause before execution. + +`execute()` returns the same durable result as the model-facing tool. A result can complete, pause, or contain an execution error. Resolve a paused result with `approve()` or `reject()`. + ## Verify the integration Ask the model to list saved notes. The model receives one `codemode` tool and can discover connector methods inside the sandbox: diff --git a/src/content/docs/agents/tools/codemode/mcp.mdx b/src/content/docs/agents/tools/codemode/mcp.mdx index 2947a635466..6b96ac871d3 100644 --- a/src/content/docs/agents/tools/codemode/mcp.mdx +++ b/src/content/docs/agents/tools/codemode/mcp.mdx @@ -136,6 +136,23 @@ You need: Await `codemodeRuntime()`, then pass `runtime.tool()` to your model as the `codemode` tool. Await the helper again before calling approval, rejection, rollback, or snippet methods. This ensures MCP connections have finished restoring after hibernation. + If the runtime belongs to a `Think` agent, keep MCP tools out of the direct model tool set: + + + + ```ts + import { Think } from "@cloudflare/think"; + + export class Chat extends Think { + includeMcpTools = false; + waitForMcpConnections = true; + } + ``` + + + + `includeMcpTools = false` skips Think's automatic `getAITools()` call. The MCP connection remains available to `McpConnector`. + 4. **Let the model discover and call tools** Tell the model to use `codemode.search()` and `codemode.describe()` before calling unfamiliar methods. Model-generated sandbox code can then discover and call the generated methods: @@ -183,3 +200,5 @@ const codemode = createCodeTool({ This approach exposes the MCP tools under the default `codemode` namespace. It does not use the connector runtime's durable pause, approval, and resume flow. Use `McpConnector` when tools can cause side effects or when the model needs on-demand discovery. + +`getAITools()` converts MCP input and output schemas for use by the AI SDK. The Agents SDK reuses those converted schemas while each live connection keeps the same current catalog. Use `this.mcp.listTools()` instead when you only need to inspect the raw MCP catalog.