diff --git a/src/content/changelog/agents/2026-03-17-codemode-sdk-v0.2.1.mdx b/src/content/changelog/agents/2026-03-17-codemode-sdk-v0.2.1.mdx new file mode 100644 index 00000000000..40c4300b4f4 --- /dev/null +++ b/src/content/changelog/agents/2026-03-17-codemode-sdk-v0.2.1.mdx @@ -0,0 +1,94 @@ +--- +title: "@cloudflare/codemode v0.2.1: MCP barrel export, zero-dependency main entry point, and custom sandbox modules" +description: "Codemode v0.2.0–v0.2.1 adds a new @cloudflare/codemode/mcp export with codeMcpServer and openApiMcpServer, makes the main entry point dependency-free, and lets you inject custom modules into the sandbox." +products: + - agents + - workers +date: 2026-03-17 +--- + +import { TypeScriptExample } from "~/components"; + +The latest releases of [`@cloudflare/codemode`](https://www.npmjs.com/package/@cloudflare/codemode) add a new MCP barrel export, remove `ai` and `zod` as required peer dependencies from the main entry point, and give you more control over the sandbox. + +## New `@cloudflare/codemode/mcp` export + +A new `@cloudflare/codemode/mcp` entry point provides two functions that wrap MCP servers with Code Mode: + +- **`codeMcpServer({ server, executor })`** — wraps an existing MCP server with a single `code` tool where each upstream tool becomes a typed `codemode.*` method. +- **`openApiMcpServer({ spec, executor, request })`** — creates `search` and `execute` MCP tools from an OpenAPI spec with host-side request proxying and automatic `$ref` resolution. + + + +```ts +import { codeMcpServer } from "@cloudflare/codemode/mcp"; +import { DynamicWorkerExecutor } from "@cloudflare/codemode"; + +const executor = new DynamicWorkerExecutor({ loader: env.LOADER }); + +// Wrap an existing MCP server — all its tools become +// typed methods the LLM can call from generated code +const server = await codeMcpServer({ server: upstreamMcp, executor }); +``` + + + +## Zero-dependency main entry point + +**Breaking change in v0.2.0:** `generateTypes` and the `ToolDescriptor` / `ToolDescriptors` types have moved to `@cloudflare/codemode/ai`: + + + +```ts +// Before +import { generateTypes } from "@cloudflare/codemode"; + +// After +import { generateTypes } from "@cloudflare/codemode/ai"; +``` + + + +The main entry point (`@cloudflare/codemode`) no longer requires the `ai` or `zod` peer dependencies. It now exports: + +| Export | Description | +| ----------------------------- | ---------------------------------------------------------------- | +| `sanitizeToolName` | Sanitize tool names into valid JS identifiers | +| `normalizeCode` | Normalize LLM-generated code into async arrow functions | +| `generateTypesFromJsonSchema` | Generate TypeScript type definitions from plain JSON Schema | +| `jsonSchemaToType` | Convert a single JSON Schema to a TypeScript type string | +| `DynamicWorkerExecutor` | Sandboxed code execution via Dynamic Worker Loader | +| `ToolDispatcher` | RPC target for dispatching tool calls from sandbox to host | + +The `ai` and `zod` peer dependencies are now optional — only required when importing from `@cloudflare/codemode/ai`. + +## Custom sandbox modules + +`DynamicWorkerExecutor` now accepts an optional `modules` option to inject custom ES modules into the sandbox: + + + +```ts +const executor = new DynamicWorkerExecutor({ + loader: env.LOADER, + modules: { + "utils.js": `export function add(a, b) { return a + b; }`, + }, +}); + +// Sandbox code can then: import { add } from "utils.js" +``` + + + +## Internal normalization and sanitization + +`DynamicWorkerExecutor` now normalizes code and sanitizes tool names internally. You no longer need to call `normalizeCode()` or `sanitizeToolName()` before passing code and functions to `execute()`. + +## Upgrade + +```sh +npm i @cloudflare/codemode@latest +``` + +See the [Code Mode documentation](/agents/api-reference/codemode/) for the full API reference. diff --git a/src/content/docs/agents/api-reference/codemode.mdx b/src/content/docs/agents/api-reference/codemode.mdx index d56e33c96d5..28177685bcd 100644 --- a/src/content/docs/agents/api-reference/codemode.mdx +++ b/src/content/docs/agents/api-reference/codemode.mdx @@ -38,7 +38,13 @@ For simple, single tool calls, standard AI SDK tool calling is simpler and suffi ## Installation ```sh -npm install @cloudflare/codemode ai zod +npm install @cloudflare/codemode +``` + +If you use `@cloudflare/codemode/ai`, also install the `ai` and `zod` peer dependencies: + +```sh +npm install ai zod ``` ## Quick start @@ -144,23 +150,6 @@ compatibility_flags = ["nodejs_compat"] -### Vite configuration - -If you use `zod-to-ts` (which codemode depends on), add a `__filename` define to your Vite config: - - - -```ts -export default defineConfig({ - plugins: [react(), cloudflare(), tailwindcss()], - define: { - __filename: "'index.ts'", - }, -}); -``` - - - ## How it works 1. `createCodeTool` generates TypeScript type definitions from your tools and builds a description the LLM can read. @@ -246,6 +235,54 @@ const codemode = createCodeTool({ Tool names with hyphens or dots (common in MCP) are automatically sanitized to valid JavaScript identifiers (for example, `my-server.list-items` becomes `my_server_list_items`). +## MCP server wrappers + +The `@cloudflare/codemode/mcp` export provides two functions that wrap MCP servers with Code Mode. + +### `codeMcpServer` + +Wraps an existing MCP server with a single `code` tool. Each upstream tool becomes a typed `codemode.*` method inside the sandbox: + + + +```ts +import { codeMcpServer } from "@cloudflare/codemode/mcp"; +import { DynamicWorkerExecutor } from "@cloudflare/codemode"; + +const executor = new DynamicWorkerExecutor({ loader: env.LOADER }); +const server = await codeMcpServer({ server: upstreamMcp, executor }); +``` + + + +### `openApiMcpServer` + +Creates an MCP server with `search` and `execute` tools from an OpenAPI spec. All `$ref` pointers are resolved before being passed to the sandbox, and the host-side `request` handler keeps authentication out of the sandbox: + + + +```ts +import { openApiMcpServer } from "@cloudflare/codemode/mcp"; +import { DynamicWorkerExecutor } from "@cloudflare/codemode"; + +const executor = new DynamicWorkerExecutor({ loader: env.LOADER }); +const server = openApiMcpServer({ + spec: openApiSpec, + executor, + request: async ({ method, path, query, body }) => { + // Runs on the host — add auth headers here + const res = await fetch(`https://api.example.com${path}`, { + method, + headers: { Authorization: `Bearer ${token}` }, + body: body ? JSON.stringify(body) : undefined, + }); + return res.json(); + }, +}); +``` + + + ## The Executor interface The `Executor` interface is deliberately minimal — implement it to run code in any sandbox: @@ -283,11 +320,14 @@ Returns an AI SDK compatible `Tool`. Executes code in an isolated Cloudflare Worker via `WorkerLoader`. -| Option | Type | Default | Description | -| ---------------- | ----------------- | -------- | ------------------------------------------------------------ | -| `loader` | `WorkerLoader` | required | Worker Loader binding from `env.LOADER` | -| `timeout` | `number` | `30000` | Execution timeout in ms | -| `globalOutbound` | `Fetcher \| null` | `null` | Network access control. `null` = blocked, `Fetcher` = routed | +| Option | Type | Default | Description | +| ---------------- | -------------------------- | -------- | ---------------------------------------------------------------------------------- | +| `loader` | `WorkerLoader` | required | Worker Loader binding from `env.LOADER` | +| `timeout` | `number` | `30000` | Execution timeout in ms | +| `globalOutbound` | `Fetcher \| null` | `null` | Network access control. `null` = blocked, `Fetcher` = routed | +| `modules` | `Record` | — | Custom ES modules available in the sandbox. Keys are specifiers, values are source. | + +Code and tool names are normalized and sanitized internally — you do not need to call `normalizeCode()` or `sanitizeToolName()` before passing them to `execute()`. ### `generateTypes(tools)` @@ -296,7 +336,7 @@ Generates TypeScript type definitions from your tools. Used internally by `creat ```ts -import { generateTypes } from "@cloudflare/codemode"; +import { generateTypes } from "@cloudflare/codemode/ai"; const types = generateTypes(myTools); // Returns: @@ -308,6 +348,18 @@ const types = generateTypes(myTools); +For JSON Schema inputs that do not depend on the AI SDK, use the main entry point: + + + +```ts +import { generateTypesFromJsonSchema } from "@cloudflare/codemode"; + +const types = generateTypesFromJsonSchema(jsonSchemaToolDescriptors); +``` + + + ### `sanitizeToolName(name)` Converts tool names into valid JavaScript identifiers. @@ -337,7 +389,6 @@ sanitizeToolName("delete"); // "delete_" - **Tool approval (`needsApproval`) is not supported yet.** Tools with `needsApproval: true` execute immediately inside the sandbox without pausing for approval. Support for approval flows within codemode is planned. For now, do not pass approval-required tools to `createCodeTool` — use them through standard AI SDK tool calling instead. - Requires Cloudflare Workers environment for `DynamicWorkerExecutor`. - Limited to JavaScript execution. -- The `zod-to-ts` dependency bundles the TypeScript compiler, which increases Worker size. - LLM code quality depends on prompt engineering and model capability. ## Related resources