跳转到内容
搜索文档

工具

最后更新 查看 MarkdownAgent 设置

MCP tool 是 MCP 服务器暴露供 client 调用的函数。当 LLM 决定需要采取行动 — 查找数据、运行计算、调用 API — 它会调用 tool。MCP 服务器执行 tool 并返回结果。

Tool 使用 @modelcontextprotocol/sdk 包定义。Agents SDK 处理 transport 与生命周期;无论使用 createMcpHandler 还是 McpAgent,tool 定义相同。

WebMCP 示例

将 Cloudflare McpAgent 的 MCP tool 桥接到 Chrome 实验性 WebMCP API。

定义 tool

McpServer 实例上用 server.tool() 注册 tool。每个 tool 有名称、description(LLM 用于决定何时调用)、用 Zod 定义的输入 schema 与 handler 函数。

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

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

	server.tool(
		"add",
		"Add two numbers together",
		{ a: z.number(), b: z.number() },
		async ({ a, b }) => ({
			content: [{ type: "text", text: String(a + b) }],
		}),
	);

	return server;
}
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

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

	server.tool(
		"add",
		"Add two numbers together",
		{ a: z.number(), b: z.number() },
		async ({ a, b }) => ({
			content: [{ type: "text", text: String(a + b) }],
		}),
	);

	return server;
}

Tool handler 接收已验证输入,必须返回带 content 数组的对象。每个 content 项有 type(通常为 "text")及对应数据。

Tool 结果

Tool 结果以 content part 数组返回。最常见类型为 text,也可返回 image 与 embedded resource。

server.tool(
	"lookup",
	"Look up a user by ID",
	{ 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.tool(
	"lookup",
	"Look up a user by ID",
	{ 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) }],
		};
	},
);

设置 isError: true 表示 tool 调用失败。LLM 收到 error 消息并决定如何继续。

Tool 描述

description 参数至关重要 — LLM 读取它来决定是否及何时调用 tool。描述应:

  • 具体说明 tool 做什么:「获取城市当前天气」优于「天气 tool」
  • 清楚说明输入:「需要城市名字符串」帮助 LLM 正确格式化调用
  • 诚实说明限制:「仅支持美国城市」防止 LLM 用不支持的输入调用

用 Zod 验证输入

Tool 输入定义为 Zod schema,handler 运行前自动验证。用 Zod 的 .describe() 为 LLM 提供每个参数的上下文。

server.tool(
	"search",
	"Search for documents by query",
	{
		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.tool(
	"search",
	"Search for documents by query",
	{
		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) }],
		};
	},
);

createMcpHandler 一起使用 tool

对无状态 MCP 服务器,在 factory 函数内定义 tool 并将 server 传给 createMcpHandler

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

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

	server.tool("ping", "Check if the server is alive", {}, async () => ({
		content: [{ type: "text", text: "pong" }],
	}));

	return server;
}

export default {
	fetch: (request, env, ctx) => {
		const server = createServer();
		return createMcpHandler(server)(request, env, ctx);
	},
};
import { createMcpHandler } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

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

	server.tool("ping", "Check if the server is alive", {}, async () => ({
		content: [{ type: "text", text: "pong" }],
	}));

	return server;
}

export default {
	fetch: (request: Request, env: Env, ctx: ExecutionContext) => {
		const server = createServer();
		return createMcpHandler(server)(request, env, ctx);
	},
} satisfies ExportedHandler<Env>;

McpAgent 一起使用 tool

对有状态 MCP 服务器,在 McpAgentinit() 方法中定义 tool。Tool 可通过 this 访问 agent 实例,即读写状态。

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}` }],
				};
			},
		);
	}
}

下一步

这篇文档对您有帮助吗?