INTEGRITY Dokumentace

Sestavte server MCP typu vyhledej a spusť

Použijte openApiMcpServer() k publikování rozsáhlé služby OpenAPI prostřednictvím dvou nástrojů Model Context Protocol (MCP):

Dokument OpenAPI zůstává mimo kontext modelu, pokud jeho část nevrátí vyhledávací kód. Autentizace zůstává v hostitelském Workeru.

Předpoklady

Potřebujete projekt Cloudflare Workers, dokument OpenAPI 3.x a metodu na straně hostitele pro ověřování API požadavků.

openApiMcpServer() momentálně vrací server SDK v1. Obsluhujte jej přes explicitní starší createLegacyMcpHandler API.

Publikování služby

  1. Nainstalujte Code Mode a závislosti MCP:

    npm i @cloudflare/codemode agents @modelcontextprotocol/sdk zod
  2. Přidejte vazbu Worker Loader a nodejs_compat příznak kompatibility:

    {
      "$schema": "./node_modules/wrangler/config-schema.json",
      "name": "openapi-codemode-mcp",
      "main": "src/server.ts",
      // Set this to today's date
      "compatibility_date": "2026-08-28",
      "compatibility_flags": [
        "nodejs_compat"
      ],
      "worker_loaders": [
        {
          "binding": "LOADER"
        }
      ]
    }
    name = "openapi-codemode-mcp"
    main = "src/server.ts"
    # Set this to today's date
    compatibility_date = "2026-08-28"
    compatibility_flags = ["nodejs_compat"]
    
    [[worker_loaders]]
    binding = "LOADER"
  3. Načtěte dokument OpenAPI na hostu. Vytvořte server MCP s ověřeným request funkce:

    src/server.js
    import { DynamicWorkerExecutor } from "@cloudflare/codemode";
    import { openApiMcpServer } from "@cloudflare/codemode/mcp";
    import { createLegacyMcpHandler } from "agents/mcp";
    
    const SPEC_URL = "https://api.example.com/openapi.json";
    const API_ORIGIN = "https://api.example.com";
    
    let specCache;
    
    async function loadSpec() {
    	if (specCache) return specCache;
    
    	const response = await fetch(SPEC_URL);
    	if (!response.ok) {
    		throw new Error(`OpenAPI request failed: ${response.status}`);
    	}
    
    	specCache = await response.json();
    	return specCache;
    }
    
    export default {
    	async fetch(request, env, ctx) {
    		const authorization = request.headers.get("Authorization");
    		if (!authorization?.startsWith("Bearer ")) {
    			return new Response("Bearer token required", { status: 401 });
    		}
    
    		const server = openApiMcpServer({
    			spec: await loadSpec(),
    			executor: new DynamicWorkerExecutor({ loader: env.LOADER }),
    			name: "example-api",
    			version: "1.0.0",
    			request: async (options) => {
    				if (!options.path.startsWith("/")) {
    					throw new Error("API path must start with a slash");
    				}
    
    				const url = new URL(`${API_ORIGIN}${options.path}`);
    				for (const [key, value] of Object.entries(options.query ?? {})) {
    					if (value !== undefined) {
    						url.searchParams.set(key, String(value));
    					}
    				}
    
    				const headers = { Authorization: authorization };
    				if (options.contentType) {
    					headers["Content-Type"] = options.contentType;
    				} else if (options.body !== undefined) {
    					headers["Content-Type"] = "application/json";
    				}
    
    				const response = await fetch(url, {
    					method: options.method,
    					headers,
    					body:
    						options.body === undefined
    							? undefined
    							: options.rawBody
    								? options.body
    								: JSON.stringify(options.body),
    				});
    
    				if (!response.ok) {
    					throw new Error(`API request failed: ${response.status}`);
    				}
    				if (response.status === 204) return null;
    
    				const responseType = response.headers.get("Content-Type") ?? "";
    				return responseType.includes("application/json")
    					? await response.json()
    					: await response.text();
    			},
    		});
    
    		return createLegacyMcpHandler(server, { route: "/mcp" })(request, env, ctx);
    	},
    };
    src/server.ts
    import { DynamicWorkerExecutor } from "@cloudflare/codemode";
    import { openApiMcpServer } from "@cloudflare/codemode/mcp";
    import { createLegacyMcpHandler } from "agents/mcp";
    
    const SPEC_URL = "https://api.example.com/openapi.json";
    const API_ORIGIN = "https://api.example.com";
    
    let specCache: Record<string, unknown> | undefined;
    
    async function loadSpec(): Promise<Record<string, unknown>> {
    	if (specCache) return specCache;
    
    	const response = await fetch(SPEC_URL);
    	if (!response.ok) {
    		throw new Error(`OpenAPI request failed: ${response.status}`);
    	}
    
    	specCache = (await response.json()) as Record<string, unknown>;
    	return specCache;
    }
    
    export default {
    	async fetch(request, env, ctx): Promise<Response> {
    		const authorization = request.headers.get("Authorization");
    		if (!authorization?.startsWith("Bearer ")) {
    			return new Response("Bearer token required", { status: 401 });
    		}
    
    		const server = openApiMcpServer({
    			spec: await loadSpec(),
    			executor: new DynamicWorkerExecutor({ loader: env.LOADER }),
    			name: "example-api",
    			version: "1.0.0",
    			request: async (options) => {
    				if (!options.path.startsWith("/")) {
    					throw new Error("API path must start with a slash");
    				}
    
    				const url = new URL(`${API_ORIGIN}${options.path}`);
    				for (const [key, value] of Object.entries(options.query ?? {})) {
    					if (value !== undefined) {
    						url.searchParams.set(key, String(value));
    					}
    				}
    
    				const headers: Record<string, string> = { Authorization: authorization };
    				if (options.contentType) {
    					headers["Content-Type"] = options.contentType;
    				} else if (options.body !== undefined) {
    					headers["Content-Type"] = "application/json";
    				}
    
    				const response = await fetch(url, {
    					method: options.method,
    					headers,
    					body:
    						options.body === undefined
    							? undefined
    							: options.rawBody
    								? (options.body as string)
    								: JSON.stringify(options.body),
    				});
    
    				if (!response.ok) {
    					throw new Error(`API request failed: ${response.status}`);
    				}
    				if (response.status === 204) return null;
    
    				const responseType = response.headers.get("Content-Type") ?? "";
    				return responseType.includes("application/json")
    					? await response.json()
    					: await response.text();
    			},
    		});
    
    		return createLegacyMcpHandler(server, { route: "/mcp" })(
    			request,
    			env,
    			ctx,
    		);
    	},
    } satisfies ExportedHandler<Env>;
  4. Nasaďte Worker:

    npx wrangler deploy
  5. V klientovi MCP se připojte k https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/mcp. Zahrňte bearer token vyžadovaný vaším Workerem.

  6. Vypsat nástroje MCP. Ověřte, že server poskytuje search a execute.

Prohledejte dokument OpenAPI

Zavolejte search před execute. Vyhledávací kód může dokument prozkoumat, aniž by musel provádět API požadavky:

async () => {
	const spec = await codemode.spec();
	return Object.entries(spec.paths)
		.filter(([path]) => path.includes("/orders"))
		.map(([path, operations]) => ({
			path,
			methods: Object.keys(operations),
		}));
};

Lokální OpenAPI $ref hodnoty se přeloží uvnitř sandboxu, když kód zavolá codemode.spec(). Externí odkazy zůstávají nevyřešené.

Volání API

execute nástroj obsahuje stejné codemode.spec() metodu a to, co poskytuje hostitel codemode.request() metoda:

async () => {
	const response = await codemode.request({
		method: "GET",
		path: "/orders",
		query: { status: "processing", limit: 20 },
	});

	return response.items.map(({ id, status }) => ({ id, status }));
};

Callback hostitele přijímá method, path, volitelné query, volitelné body, volitelné contentType, a volitelné rawBody polí. Přesné typy najdete v openApiMcpServer() API.

search a execute nástroje používají pevné ukázkové úryvky. Volitelný description se připojí k execute popisu nástroje. Tato funkce nepoužívá {{types}} nebo {{example}} zástupné symboly podporované codeMcpServer().

Ochrana API

Příklad načte bearer token ještě před vytvořením serveru MCP. Jeho request callback tento token přidává do odchozích požadavků. Token se do sandboxu nikdy nedostane.

openApiMcpServer() neposkytuje trvalé schválení pro každý požadavek uvnitř execute. Vynucujte autorizaci a případné požadované schválení pro jednotlivé operace v host callbacku ještě před provedením vedlejších efektů. Ověřujte cesty, místo abyste přijímali libovolné origins.

Do dokumentu OpenAPI ani do výsledků API nedávejte tajné údaje. Obojí je totiž dostupné kódu napsanému modelem.

DynamicWorkerExecutor blokuje přímý externí fetch() a connect() volání ve výchozím nastavení. Vygenerovaný kód se ke službě dostane pouze přes callback hostitelského požadavku.

Omezte výsledky

Nechte kód vygenerovaný modelem vybírat, mapovat, agregovat nebo stránkovat data, než je vrátí. Vydavatel omezuje konečné odpovědi MCP přibližně na 6 000 odhadovaných tokenů a zkrácené odpovědi označuje pomocí --- TRUNCATED ---.

Zkrácení nesnižuje již provedenou práci API. Vracejte cílené identifikátory, stavová pole, počty a chyby, které podporují další rozhodnutí modelu.