INTEGRITY Dokumentace

API handlerů MCP

Agents SDK poskytuje dvě cesty pro obsluhu serveru:

API Cesta importu Balíček serveru MCP Chování
createMcpHandler agents/mcp/server @modelcontextprotocol/server bezstavové s kompatibilitou se staršími verzemi ve výchozím nastavení
createLegacyMcpHandler agents/mcp @modelcontextprotocol/sdk starší relace prostřednictvím WorkerTransport

McpAgent je zastaralé a jeho funkce se dále nerozvíjejí. Přesuňte stávající McpAgent servery na bezstavový handler. Více informací najdete v průvodce migrací když relační funkce vyžadují postupné zavádění.

Nainstalujte závislosti

Pro bezstavový server:

npm i agents @modelcontextprotocol/[email protected] zod

Pro explicitní legacy server:

npm i agents @modelcontextprotocol/[email protected] zod

Použijte přesné verze MCP vyžadované vaší nainstalovanou verzí Agents.

createMcpHandler

createMcpHandler vytvoří volatelnou bezstavovou obslužnou rutinu požadavků MCP z tovární funkce serveru MCP SDK v2. Zavolejte ji z objektu Workeru fetch() export, nebo jej zkombinujte uvnitř jiného handleru.

import {
	createMcpHandler,
	type CreateMcpHandlerOptions,
	type StatelessMcpHandler,
} from "agents/mcp/server";
import type { McpServerFactory } from "@modelcontextprotocol/server";

function createMcpHandler(
	factory: McpServerFactory,
	options?: CreateMcpHandlerOptions,
): StatelessMcpHandler;

Parametry

Factory dostává tento kontext požadavku:

interface McpRequestContext {
	era: "modern" | "legacy";
	authInfo?: AuthInfo;
	requestInfo?: Request;
}

Tovární funkce bez argumentů zůstává platná.

Příklad

import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
import { z } from "zod";

function createServer() {
	const server = new McpServer({
		name: "hello-server",
		version: "1.0.0",
	});

	server.registerTool(
		"hello",
		{
			description: "Return a greeting",
			inputSchema: { name: z.string().optional() },
		},
		async ({ name }) => ({
			content: [{ type: "text", text: `Hello, ${name ?? "World"}!` }],
		}),
	);

	return server;
}

export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer)(request, env, ctx);
	},
};
src/index.ts
import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
import { z } from "zod";

function createServer() {
	const server = new McpServer({
		name: "hello-server",
		version: "1.0.0",
	});

	server.registerTool(
		"hello",
		{
			description: "Return a greeting",
			inputSchema: { name: z.string().optional() },
		},
		async ({ name }) => ({
			content: [{ type: "text", text: `Hello, ${name ?? "World"}!` }],
		}),
	);

	return server;
}

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

Předejte samotnou factory. Nevytvářejte jedinou globální instanci serveru ani nepředávejte sestavený server SDK v2 přímo.

CreateMcpHandlerOptions

K dispozici jsou následující možnosti:

Možnost Typ Výchozí Popis
route string "/mcp" Přesná cesta, kterou obsluhuje Worker wrapper
corsOptions CORSOptions | false Wildcard CORS Hlavičky odpovědi CORS nebo false k jejich odstranění
allowedHostnames string[] Localhost nebo workers.dev trasa Volitelné omezení Host pro vlastní domény
allowedOriginHostnames string[] | "*" Localhost, workers.dev, nebo konkrétní CORS Origin omezení Origin prohlížeče nebo explicitní delegování middlewaru
authContext McpAuthContext Props kontextu spuštění Props aplikace vrácené getMcpAuthContext()
legacy "stateless" | "reject" "stateless" kompatibilita se staršími verzemi nebo odmítnutí čistě bezstavových požadavků
responseMode "auto" | "json" | "sse" "auto" tvarování bezstavových požadavků a odpovědí
onerror (error: Error) => void Žádné Hlášení chyb mimo pásmo
maxSubscriptions number 1,024 Maximální počet souběžných poslechových streamů
keepAliveMs number 15,000 Interval keepalive pro naslouchací streamy

Možnosti transportu SDK v1 se na tento handler nevztahují. Odmítá možnosti jako transport, storage, sessionIdGenerator, eventStore, a enableJsonResponse.

Použijte responseMode: "json" místo enableJsonResponse: true. Režim JSON zahazuje notifikace vydané před finálním výsledkem.

Životní cyklus tovární funkce

Handler vytváří pro každý požadavek jeden server MCP. To odpovídá modelu návrhu protokolu, kde verze, identita a možnosti cestují s každým požadavkem, a ne prostřednictvím relace protokolu.

Data aplikace přesto mohou být trvalá. Data platná napříč požadavky ukládejte za autentizovaný identifikátor v Durable Object, D1, KV nebo R2, ne pod ID relace MCP.

Elicitace s bezstavovým handlerem

Elicitace prostřednictvím bezstavového handleru vrátí input_required a dokončuje se prostřednictvím vícekolových požadavků (MRTR). Při každém opakování SDK znovu odešle poslední requestState a odesílá odpovědi pro bezprostředně předchozí kolo vstupu. Nehromadí dřívější inputResponses. Worker nezůstává pozastavený po dobu, kdy uživatel odpovídá.

Použijte inputRequired(...) k vyžádání vstupu. Přijatý obsah formuláře z daného kola přečtěte z context.mcpReq.inputResponses hodnotou acceptedContent(...). Důvěryhodné mezivýsledky potřebné pro pozdější kola zapečeťte do integritně chráněného requestState.

Viz příklad bezstavového vyžádání ↗ pro dvoukolový tok nástrojů. Pro stavové odeslané (pushed) požadavky viz Elicitace na starších serverech.

Validace originu a CORS

Wrapper Workers ověřuje každou přítomnou hodnotu Origin prohlížeče. Nesprávně formátované, neprůhledné a jiné než HTTP hodnoty Origin odmítá s 403. Neprohlížečoví klienti MCP bez hlavičky Origin zůstávají platní.

Výchozí allowlist zahrnuje hodnoty Origin typu localhost, endpointu workers.dev hostname a konkrétní hostname z corsOptions.origin. Handler navíc uplatňuje odpovídající kontroly Host i na localhost a workers.dev endpointy. Díky tomu zůstává zachována místní ochrana proti DNS rebindingu, aniž by bylo nutné mít samostatný seznam Origin pro běžné trasy Workers.

U vlastní domény se zástupným CORS nastavte allowedHostnames a allowedOriginHostnames výslovně. Pokud corsOptions.origin je konkrétní URL, handler z ní automaticky odvodí název hostitele Origin:

export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer, {
			allowedHostnames: ["mcp.example.com"],
			corsOptions: {
				origin: "https://app.example.com",
			},
		})(request, env, ctx);
	},
};
export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer, {
			allowedHostnames: ["mcp.example.com"],
			corsOptions: {
				origin: "https://app.example.com",
			},
		})(request, env, ctx);
	},
} satisfies ExportedHandler;

Hodnoty allowlistu jsou názvy hostitelů bez schématu nebo portu. Porovnávání originu ignoruje schéma i port.

Nastavte allowedOriginHostnames: "*" pouze tehdy, když důvěryhodný middleware ověří Origin před voláním handleru. Tato hodnota vypíná kontrolu Origin v handleru, včetně odmítání neplatných a neprůhledných hodnot Origin. MCP HTTP servery musí ověřovat Origin prohlížeče.

Hlavičky odpovědi CORS nejsou autentizace. Chraňte endpoint MCP pomocí OAuth nebo jiné autentizační vrstvy.

Handler neodvozuje allowlist hodnot Host z request.url. Pokud nasazení přijímá libovolné hodnoty Host, ověřte je ještě před voláním handleru. Lokální servery mimo Cloudflare Workers by se měly řídit pokyny nadřazeného SDK k ochraně proti DNS rebindingu.

Kompatibilita se staršími klienty

Výchozí legacy: "stateless" nastavení přijímá běžné starší nástroje, prompty a zdroje. Tato cesta používá webově standardní transport SDK v2 a neimportuje WorkerTransport.

Tato cesta kompatibility neposkytuje kompletní transport relace:

Nastavte legacy: "reject" pro čistě bezstavový endpoint. Během migrace směrujte starší klienty, kteří stále vyžadují relace protokolu, na dočasný createLegacyMcpHandler nebo McpAgent dráha.

Návratová hodnota

createMcpHandler vrací StatelessMcpHandler. Je volatelný a zpřístupňuje ovládací prvky pro požadavky a notifikace:

interface StatelessMcpHandler {
	(request: Request, env: unknown, ctx: ExecutionContext): Promise<Response>;

	fetch(
		request: Request,
		options?: McpHandlerRequestOptions,
	): Promise<Response>;

	notify: {
		toolsChanged(): void;
		promptsChanged(): void;
		resourcesChanged(): void;
		resourceUpdated(uri: string): void;
	};
}

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

Vyvolání handleru

Zavolejte handler z objektu Workeru fetch() export:

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

Neexportujte volatelnou hodnotu přímo jako výchozí export Workeru. Wrangler totiž výchozí exporty funkcí považuje za WorkerEntrypoint tříd.

Použijte fetch() když jiný framework nebo autentizační vrstva už data požadavku zpracovaly nebo ověřily:

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

authInfo se předává tovární funkci serveru a handlerům požadavků. Handler ho neodvozuje z hlaviček požadavku ani neověřuje přístupové tokeny. parsedBody se vyhne opakovanému parsování těla JSON, které už zpracoval middleware výše v řetězci.

Publikování změn seznamů a prostředků

notify metody publikují typované události změny do odpovídajících otevřených subscriptions/listen streamy:

Metoda Oznámení MCP
notify.toolsChanged() notifications/tools/list_changed
notify.promptsChanged() notifications/prompts/list_changed
notify.resourcesChanged() notifications/resources/list_changed
notify.resourceUpdated(uri) notifications/resources/updated

Zavolání notifikátoru, když není otevřený žádný odpovídající odběr, nemá žádný účinek.

Ponechte jeden handler pro oznámení

Směrování oznámení patří k instanci handleru. Vytváření nového handleru uvnitř každého Workeru fetch() volání je vhodné pro běžné nástroje, prompty, resources a MRTR elicitation. Nemůže upozornit subscriptions/listen stream, který vlastní starší instance handleru.

Vytvořte handler jednou v rozsahu modulu při použití notify nebo subscriptions/listen, poté ho zavolejte z exportu objektu Worker:

const handler = createMcpHandler(createServer);

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

Oznámení platí pouze v rámci daného izolátu. Oznámení publikované v jednom Worker izolátu se nedostane k odběrovému streamu běžícímu v jiném izolátu.

createLegacyMcpHandler

createLegacyMcpHandler obsluhuje server SDK v1 prostřednictvím 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;

Použijte tento handler pouze jako dočasný migrační most, pokud stávající endpoint SDK v1 stále vyžaduje starší relace, úložiště transportu, přehrávání událostí nebo požadavky odesílané serverem klientovi.

src/index.js
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.ts
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>;

Předání serveru SDK v1 do createMcpHandler stále funguje, ale vypisuje upozornění na zastarání. Přesuňte server na tovární funkci SDK v2 a tuto tovární funkci předejte createMcpHandler. Pokud chování založené na relacích brání okamžité migraci, použijte createLegacyMcpHandler pouze na dočasné starší dráze.

experimental_createMcpHandler je také zastaralé. Přesuňte jeho server SDK v1 do továrny SDK v2. Použijte createLegacyMcpHandler pouze jako dočasný most pro chování závislé na relaci.

CreateLegacyMcpHandlerOptions

CreateLegacyMcpHandlerOptions rozšiřuje WorkerTransportOptions a přidá tato pole:

Možnost Typ Výchozí Popis
route string "/mcp" Přesná cesta, kterou obsluhuje handler
authContext McpAuthContext Props kontextu spuštění Props aplikace pro handlery nástrojů
transport WorkerTransport Nový transport Trvalý nebo předkonfigurovaný transport

Běžné WorkerTransportOptions patří:

Možnost Popis
sessionIdGenerator Vytváří ID relací protokolu
enableJsonResponse Vrací JSON místo SSE, pokud je to podporováno
storage Ukládá stav transportu prostřednictvím { get, set } adaptér
eventStore Ukládá události pro přehrávání a obnovení streamu
corsOptions Přidává hlavičky odpovědi CORS a hlavičky preflight
onsessioninitialized, onsessionclosed Sledovat změny životního cyklu relace

Pro každý požadavek vytvořte nový server SDK v1, pokud neposkytnete trvalý transport, který je k tomuto serveru již připojen. Jeden server se nemůže znovu připojit k více transportům.

Kontext ověřování

Kompatibilní @cloudflare/workers-oauth-provider poskytuje ověřené standardní AuthInfo na callbacky SDK v2 v context.http.authInfo.

Stávající getMcpAuthContext() pomocná funkce nadále vrací aplikační props:

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

server.registerTool(
	"whoami",
	{ description: "Return the current identity", inputSchema: {} },
	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";

server.registerTool(
	"whoami",
	{ description: "Return the current identity", inputSchema: {} },
	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,
					}),
				},
			],
		};
	},
);

Nezaznamenávejte do logu ani nevracejte authInfo.token nebo authInfo.extra.props.

Migrace

Viz Migrovat na MCP SDK v2 než změníte existující server. Průvodce migrací popisuje směrování mezi dvěma verzemi, stavové servery, změny na straně klienta a kontroly při nasazování.

Migrovat na MCP SDK v2

Zvolte migrační cestu a proveďte upgrade SDK.

McpAgent API

Reference pro zastaralou, funkčně zamrzlou cestu stavového serveru během migrace.

Zabezpečení serverů MCP

Chraňte endpoint MCP pomocí OAuth.