通过服务器使 LLM 执行操作

工具(Tools)是 模型上下文协议(MCP,Model Context Protocol) 中的一种强大原语,它使服务器能够向客户端暴露可执行的功能。通过工具,LLM(大语言模型)可以与外部系统交互、执行计算,并在现实世界中执行操作。

工具的设计原则是 模型控制(model-controlled),即工具由服务器暴露给客户端,AI 模型可以自动调用它们(但通常需要人工批准)。


概述

MCP 中的工具允许服务器暴露可执行的函数,这些函数可以被客户端调用,并用于让 LLM 执行动作。工具的关键特点包括:

  • 发现(Discovery):客户端可以通过 tools/list 端点获取可用工具的列表。
  • 调用(Invocation):工具通过 tools/call 端点调用,服务器执行请求的操作并返回结果。
  • 灵活性(Flexibility):工具可以从简单的计算扩展到复杂的 API 交互。

资源(resources) 类似,工具也有唯一的名称和描述,以指导其使用。但与资源不同的是,工具代表动态操作,可能会修改状态或与外部系统交互。


工具定义结构

每个工具都按照以下结构定义:

  1. {
  2. name: string; // 工具的唯一标识符
  3. description?: string; // 人类可读的描述
  4. inputSchema: { // 工具参数的 JSON Schema
  5. type: "object",
  6. properties: { ... } // 工具特定的参数
  7. }
  8. }

实现工具

以下是 MCP 服务器中实现基本工具的示例:

TypeScript 示例

  1. const server = new Server({
  2. name: "example-server",
  3. version: "1.0.0"
  4. }, {
  5. capabilities: {
  6. tools: {}
  7. }
  8. });
  9. // 定义可用工具
  10. server.setRequestHandler(ListToolsRequestSchema, async () => {
  11. return {
  12. tools: [{
  13. name: "calculate_sum",
  14. description: "计算两个数的和",
  15. inputSchema: {
  16. type: "object",
  17. properties: {
  18. a: { type: "number" },
  19. b: { type: "number" }
  20. },
  21. required: ["a", "b"]
  22. }
  23. }]
  24. };
  25. });
  26. // 处理工具调用
  27. server.setRequestHandler(CallToolRequestSchema, async (request) => {
  28. if (request.params.name === "calculate_sum") {
  29. const { a, b } = request.params.arguments;
  30. return {
  31. content: [
  32. {
  33. type: "text",
  34. text: String(a + b)
  35. }
  36. ]
  37. };
  38. }
  39. throw new Error("工具未找到");
  40. });

示例工具模式

服务器可以提供多种类型的工具,例如:

1. 系统操作(System operations)

与本地系统交互的工具:

  1. {
  2. name: "execute_command",
  3. description: "运行 Shell 命令",
  4. inputSchema: {
  5. type: "object",
  6. properties: {
  7. command: { type: "string" },
  8. args: { type: "array", items: { type: "string" } }
  9. }
  10. }
  11. }

2. API 集成(API integrations)

封装外部 API 的工具:

  1. {
  2. name: "github_create_issue",
  3. description: "创建 GitHub Issue",
  4. inputSchema: {
  5. type: "object",
  6. properties: {
  7. title: { type: "string" },
  8. body: { type: "string" },
  9. labels: { type: "array", items: { type: "string" } }
  10. }
  11. }
  12. }

3. 数据处理(Data processing)

处理或分析数据的工具:

  1. {
  2. name: "analyze_csv",
  3. description: "分析 CSV 文件",
  4. inputSchema: {
  5. type: "object",
  6. properties: {
  7. filepath: { type: "string" },
  8. operations: {
  9. type: "array",
  10. items: {
  11. enum: ["sum", "average", "count"]
  12. }
  13. }
  14. }
  15. }
  16. }

最佳实践

实现工具时应遵循以下最佳实践:

  1. 提供清晰、描述性的名称和描述
  2. 使用详细的 JSON Schema 定义参数
  3. 在工具描述中包含示例,帮助模型正确调用
  4. 实现适当的错误处理和参数验证
  5. 为长时间运行的操作提供进度报告
  6. 保持工具的功能专注且原子化(单一职责)
  7. 记录返回值的结构
  8. 实现适当的超时处理
  9. 对资源密集型操作进行速率限制
  10. 记录工具的使用情况,以便调试和监控

安全考虑

在暴露工具时,需要注意以下安全问题:

1. 输入验证(Input validation)

  • 确保所有参数都符合 JSON Schema 规范。
  • 对文件路径和系统命令进行清理和验证。
  • 检查 URL 和外部标识符的合法性。
  • 限制参数的大小和范围,防止滥用。
  • 防止命令注入等安全漏洞。

2. 访问控制(Access control)

  • 在必要时实施身份验证(Authentication)。
  • 采用适当的授权检查(Authorization)。
  • 审计工具的使用情况。
  • 限制请求速率,防止滥用。
  • 监控并检测异常使用模式。

3. 错误处理(Error handling)

  • 不要向客户端暴露内部错误信息,防止信息泄露。
  • 记录安全相关的错误信息,以便审计和调查。
  • 适当处理超时,避免资源泄露或阻塞。
  • 在发生错误时清理资源,避免系统资源耗尽。
  • 验证返回值,确保其符合预期格式。

工具发现与更新

MCP 支持动态工具发现:

  1. 客户端可以随时查询可用工具列表tools/list)。
  2. 服务器可以通过 notifications/tools/list_changed 通知客户端工具列表变更
  3. 工具可以在运行时动态添加或删除
  4. 工具定义可以更新(但应谨慎进行,以确保兼容性)。

错误处理

工具的错误应在返回结果对象中报告,而不是作为 MCP 协议级别的错误。这样,LLM 可以识别错误并尝试进行恢复或请求人工干预。

当工具发生错误时,应:

  1. 在返回结果中设置 isError: true
  2. content 数组中包含错误详情。

TypeScript 示例

  1. try {
  2. // 执行工具操作
  3. const result = performOperation();
  4. return {
  5. content: [
  6. {
  7. type: "text",
  8. text: `操作成功: ${result}`
  9. }
  10. ]
  11. };
  12. } catch (error) {
  13. return {
  14. isError: true,
  15. content: [
  16. {
  17. type: "text",
  18. text: `错误: ${error.message}`
  19. }
  20. ]
  21. };
  22. }

这样,LLM 可以检测到错误,并尝试采取纠正措施或请求人工协助。


工具测试

要确保 MCP 工具的稳定性和安全性,需要进行以下测试:

  • 功能测试(Functional testing):验证工具在输入合法时能正确执行,在输入不合法时能正确处理。
  • 集成测试(Integration testing):测试工具与外部系统的交互,包括真实 API 调用和模拟测试。
  • 安全测试(Security testing):检查身份验证、权限控制、输入清理和速率限制等安全措施。
  • 性能测试(Performance testing):评估工具在高负载下的表现,包括超时处理和资源清理。
  • 错误处理测试(Error handling testing):确保工具在异常情况下能够正确报告错误并清理资源。