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