← Vytvářejte agenty na Cloudflare / agents / model-context-protocol / protocol
Nástroje
Nástroje MCP jsou funkce, které server MCP zpřístupňuje, aby je mohli volat klienti. LLM může nástroj vyvolat, aby vyhledal data, provedl výpočet nebo zavolal API. MCP server nástroj spustí a vrátí jeho výsledek.
Použijte @modelcontextprotocol/server pro bezstavový createMcpHandler server. McpAgent je zastaralé a jeho funkce se dále nerozvíjejí. Stávající McpAgent routy musí i nadále používat @modelcontextprotocol/sdk pouze během migrace.
Definování nástrojů
Použijte server.registerTool() k registraci nástroje u bezstavového McpServer instance. Každý nástroj má název, popis a vstupní schéma definované pomocí knihovny schémat, jako je Zod ↗ nebo Valibot ↗, a funkci handleru.
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "Math", version: "1.0.0" });
server.registerTool(
"add",
{
description: "Add two numbers together",
inputSchema: { a: z.number(), b: z.number() },
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}),
);
return server;
}import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "Math", version: "1.0.0" });
server.registerTool(
"add",
{
description: "Add two numbers together",
inputSchema: { a: z.number(), b: z.number() },
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}),
);
return server;
}Handler nástroje přijímá ověřený vstup a musí vrátit objekt s content pole. Každá položka obsahu má type (obvykle "text") a odpovídající data.
Výsledky nástrojů
Výsledky nástrojů se vrací jako pole částí obsahu. Nejběžnějším typem je text, ale můžete vracet i obrázky a vložené prostředky.
server.registerTool(
"lookup",
{
description: "Look up a user by ID",
inputSchema: { userId: z.string() },
},
async ({ userId }) => {
const user = await db.getUser(userId);
if (!user) {
return {
isError: true,
content: [{ type: "text", text: `User ${userId} not found` }],
};
}
return {
content: [{ type: "text", text: JSON.stringify(user, null, 2) }],
};
},
);server.registerTool(
"lookup",
{
description: "Look up a user by ID",
inputSchema: { userId: z.string() },
},
async ({ userId }) => {
const user = await db.getUser(userId);
if (!user) {
return {
isError: true,
content: [{ type: "text", text: `User ${userId} not found` }],
};
}
return {
content: [{ type: "text", text: JSON.stringify(user, null, 2) }],
};
},
);Nastavte isError: true k signalizaci, že volání nástroje selhalo. LLM obdrží chybovou zprávu a může se rozhodnout, jak dále postupovat.
Popisy nástrojů
description parametr je klíčový: podle něj LLM rozhoduje, zda a kdy váš nástroj zavolat. Pište popisy, které jsou:
- Konkrétní o tom, co nástroj dělá: „Získat aktuální počasí pro město“ je lepší než „Nástroj na počasí“
- Jasnost vstupů: „Vyžaduje název města jako řetězec“ pomáhá LLM správně naformátovat volání
- Upřímný ohledně svých omezení: „Podporuje pouze města v USA“ brání LLM volat nástroj s nepodporovanými vstupy
Validace vstupu pomocí Zod
Vstupy nástrojů se definují jako schémata Zod a před spuštěním handleru se automaticky validují. Použijte .describe() metodu, která LLM poskytne kontext o každém parametru.
server.registerTool(
"search",
{
description: "Search for documents by query",
inputSchema: {
query: z.string().describe("The search query"),
limit: z
.number()
.min(1)
.max(100)
.default(10)
.describe("Maximum number of results to return"),
category: z
.enum(["docs", "blog", "api"])
.optional()
.describe("Filter by content category"),
},
},
async ({ query, limit, category }) => {
const results = await searchIndex(query, { limit, category });
return {
content: [{ type: "text", text: JSON.stringify(results) }],
};
},
);server.registerTool(
"search",
{
description: "Search for documents by query",
inputSchema: {
query: z.string().describe("The search query"),
limit: z
.number()
.min(1)
.max(100)
.default(10)
.describe("Maximum number of results to return"),
category: z
.enum(["docs", "blog", "api"])
.optional()
.describe("Filter by content category"),
},
},
async ({ query, limit, category }) => {
const results = await searchIndex(query, { limit, category });
return {
content: [{ type: "text", text: JSON.stringify(results) }],
};
},
);Používání nástrojů s createMcpHandler
U bezstavových serverů MCP definujte nástroje uvnitř tovární funkce a server předejte createMcpHandler:
import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "My Tools", version: "1.0.0" });
server.registerTool(
"ping",
{ description: "Check if the server is alive", inputSchema: {} },
async () => ({
content: [{ type: "text", text: "pong" }],
}),
);
return server;
}
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
};import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "My Tools", version: "1.0.0" });
server.registerTool(
"ping",
{ description: "Check if the server is alive", inputSchema: {} },
async () => ({
content: [{ type: "text", text: "pong" }],
}),
);
return server;
}
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
} satisfies ExportedHandler;Používání nástrojů s McpAgent
Tato část se týká pouze existujících starších tras během migrace. Jejich nástroje definujte v init() metoda objektu McpAgent. Nástroje mají přístup k instanci agenta prostřednictvím this, takže mohou stav číst i zapisovat.
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
export class MyMCP extends McpAgent {
server = new McpServer({ name: "Stateful Tools", version: "1.0.0" });
async init() {
this.server.tool(
"incrementCounter",
"Increment and return a counter",
{},
async () => {
const count = (this.state?.count ?? 0) + 1;
this.setState({ count });
return {
content: [{ type: "text", text: `Counter: ${count}` }],
};
},
);
}
}import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
export class MyMCP extends McpAgent {
server = new McpServer({ name: "Stateful Tools", version: "1.0.0" });
async init() {
this.server.tool(
"incrementCounter",
"Increment and return a counter",
{},
async () => {
const count = (this.state?.count ?? 0) + 1;
this.setState({ count });
return {
content: [{ type: "text", text: `Counter: ${count}` }],
};
},
);
}
}