MCP handler APIs·续

type McpHandlerRequestOptions = { authInfo?: AuthInfo; parsedBody?: unknown; };


#### Invoke the handler

Call the handler from a Worker's object `fetch()` export:

```ts
export default {
    fetch(request, env, ctx) {
        return createMcpHandler(createServer)(request, env, ctx);
    },
} satisfies ExportedHandler;

Do not export the callable directly as a Worker's default export. Wrangler treats function default exports as WorkerEntrypoint classes.

Use fetch() when another framework or authentication layer has already parsed or validated request data:

const response = await handler.fetch(request, {
    authInfo,
    parsedBody,
});

authInfo is passed to the server factory and request handlers. The handler does not derive it from request headers or verify access tokens. parsedBody avoids reparsing a JSON body that upstream middleware already consumed.

Publish list and resource changes

The notify methods publish typed change events to matching open subscriptions/listen streams:

Method MCP notification
notify.toolsChanged() notifications/tools/list_changed
notify.promptsChanged() notifications/prompts/list_changed
notify.resourcesChanged() notifications/resources/list_changed
notify.resourceUpdated(uri) notifications/resources/updated

Calling a notifier when no matching subscription is open is a no-op.

Keep one handler for notifications

Notification routing belongs to the handler instance. Constructing a new handler inside every Worker fetch() call is suitable for ordinary tools, prompts, resources, and MRTR elicitation. It cannot notify a subscriptions/listen stream owned by an earlier handler instance.

Create the handler once at module scope when using notify or subscriptions/listen, then invoke it from the Worker object export:

const handler = createMcpHandler(createServer);

export default {
    fetch(request, env, ctx) {
        return handler(request, env, ctx);
    },
} satisfies ExportedHandler;

Notifications are isolate-local. A notification published in one Worker isolate does not reach a subscription stream running in another isolate.

createLegacyMcpHandler

createLegacyMcpHandler serves an SDK v1 server through WorkerTransport.

import {
    createLegacyMcpHandler,
    type CreateLegacyMcpHandlerOptions,
    type LegacyMcpHandler,
} from "agents/mcp";
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

function createLegacyMcpHandler(
    server: McpServer | Server,
    options?: CreateLegacyMcpHandlerOptions,
): LegacyMcpHandler;

Use this handler only as a temporary migration bridge when an existing SDK v1 endpoint still requires legacy sessions, transport storage, event replay, or pushed server-to-client requests.

src/index.jsjs

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { createLegacyMcpHandler } from "agents/mcp";

function createServer() {
    return new McpServer({ name: "legacy-server", version: "1.0.0" });
}

export default {
    async fetch(request, env, ctx) {
        return createLegacyMcpHandler(createServer())(request, env, ctx);
    },
};

src/index.tsts

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { createLegacyMcpHandler } from "agents/mcp";

function createServer() {
    return new McpServer({ name: "legacy-server", version: "1.0.0" });
}

export default {
    async fetch(request: Request, env: Env, ctx: ExecutionContext) {
        return createLegacyMcpHandler(createServer())(request, env, ctx);
    },
} satisfies ExportedHandler<Env>;

Passing an SDK v1 server to createMcpHandler still works but emits a deprecation warning. Move the server to an SDK v2 factory and pass the factory to createMcpHandler. If sessionful behavior prevents an immediate migration, use createLegacyMcpHandler only on the temporary legacy lane.

experimental_createMcpHandler is also deprecated. Move its SDK v1 server to an SDK v2 factory. Use createLegacyMcpHandler only as a temporary bridge for sessionful behavior.

CreateLegacyMcpHandlerOptions

CreateLegacyMcpHandlerOptions extends WorkerTransportOptions and adds these fields:

Option Type Default Description
route string "/mcp" Exact path handled by the handler
authContext McpAuthContext Execution context props Application props for tool handlers
transport WorkerTransport New transport Persistent or preconfigured transport

Common WorkerTransportOptions include:

Option Description
sessionIdGenerator Creates protocol session IDs
enableJsonResponse Returns JSON instead of SSE where supported
storage Persists transport state through an { get, set } adapter
eventStore Persists events for replay and stream recovery
corsOptions Adds CORS response and preflight headers
onsessioninitialized, onsessionclosed Observe session lifecycle changes

Create a fresh SDK v1 server for each request unless you provide a persistent transport already connected to that server. One server cannot reconnect to several transports.

Authentication context

A compatible @cloudflare/workers-oauth-provider supplies verified standard AuthInfo to SDK v2 callbacks at context.http.authInfo.

The existing getMcpAuthContext() helper continues to return application props:

interface McpAuthContext {
    props: Record<string, unknown>;
}
import { getMcpAuthContext } from "agents/mcp/server";
import { z } from "zod";

server.registerTool(
    "whoami",
    { description: "Return the current identity", inputSchema: z.object({}) },
    async (_args, context) => {
        const auth = getMcpAuthContext();

return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({
                        clientId: context.http?.authInfo?.clientId,
                        scopes: context.http?.authInfo?.scopes,
                        userId: auth?.props.userId,
                    }),
                },
            ],
        };
    },
);
import { getMcpAuthContext } from "agents/mcp/server";
import { z } from "zod";

server.registerTool(
    "whoami",
    { description: "Return the current identity", inputSchema: z.object({}) },
    async (_args, context) => {
        const auth = getMcpAuthContext();

return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({
                        clientId: context.http?.authInfo?.clientId,
                        scopes: context.http?.authInfo?.scopes,
                        userId: auth?.props.userId,
                    }),
                },
            ],
        };
    },
);

Do not log or return authInfo.token or authInfo.extra.props.

Migration

Refer to Migrate to MCP SDK v2 before changing an existing server. The migration guide covers dual-era routing, stateful servers, client changes, and rollout checks.

Migrate to MCP SDK v2

Choose a migration path and roll out the SDK upgrade.

McpAgent API

Reference for the deprecated, feature-frozen stateful server path during migration.

Secure MCP servers

Protect an MCP endpoint with OAuth.

Was this helpful?

YesNo

On this page

MCP handler APIs·续 - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/#page","headline":"MCP handler APIs","description":"Create stateless or legacy MCP server handlers for Cloudflare Workers with the Agents SDK.","url":"https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/","inLanguage":"en","image":"https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/og.png?v=8656f1af1f0b68d0","dateModified":"2026-10-18","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["MCP"]}


description: MCP server portals in Access. title: MCP server portals image: https://developers.cloudflare.com/cloudflare-one/access-controls/ai-controls/mcp-portals/og.png?v=0b257854e7de7b3f


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/cloudflare-one/llms.txt
Use this file to discover all available pages before exploring further.