← Vytvářejte agenty na Cloudflare / agents / model-context-protocol / apis
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] zodPro explicitní legacy server:
npm i agents @modelcontextprotocol/[email protected] zodPouž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
factoryvytvoří novýMcpServerneboServerz@modelcontextprotocol/server. Může být synchronní nebo asynchronní.optionskombinuje možnosti Agents Worker s podporovanými možnostmi handlerů upstream SDK v2.
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);
},
};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:
- Každý POST vytvoří nový server a transport.
- HTTP GET a DELETE vracejí
405. - Nezachovává se žádné ID relace MCP.
- Odeslané požadavky elicitation, sampling a roots okamžitě selžou.
- Samostatné streamy, obnovitelnost, přehrávání a mazání relací nejsou k dispozici.
- Publikované experimentální úlohy nejsou přes tuto cestu podporovány.
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.
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);
},
};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í.