MCP中工具概念和实现方式

MCP中工具概念和实现方式

本文详细阐述了MCP(Model Context Protocol)中工具(Tools)的概念和实现方式,为工具的设计、使用和安全提供了清晰的指南。以下是文档的核心要点:

工具概念

工具是MCP的一个关键组成部分,允许服务器暴露可执行的功能,供客户端和LLMs调用。通过工具,模型可以执行计算、操作外部系统,甚至与真实世界交互。

  • 设计目的:工具被设计为模型可控(model-controlled),模型可以自动调用工具执行任务,但需要人类批准。
  • 核心能力
  • 发现(Discovery):列出所有可用工具。
  • 调用(Invocation):通过API调用工具并获取结果。
  • 灵活性(Flexibility):支持从简单操作到复杂API交互。

工具定义

工具通过如下结构定义:

{
  name: string;          // 工具唯一标识符
  description?: string;  // 人类可读的描述
  inputSchema: {         // JSON Schema 描述输入参数
    type: "object",
    properties: { ... }  // 工具的参数定义
  }
}

工具实现

通过MCP服务器(支持TypeScript和Python),可轻松定义和实现工具。

示例工具:求和计算

TypeScript 实现:

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [{
      name: "calculate_sum",
      description: "Add two numbers together",
      inputSchema: {
        type: "object",
        properties: {
          a: { type: "number" },
          b: { type: "number" }
        },
        required: ["a", "b"]
      }
    }]
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "calculate_sum") {
    const { a, b } = request.params.arguments;
    return {
      content: [{ type: "text", text: String(a + b) }]
    };
  }
  throw new Error("Tool not found");
});

Python 实现:

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="calculate_sum",
            description="Add two numbers together",
            inputSchema={
                "type": "object",
                "properties": {
                    "a": {"type": "number"},
                    "b": {"type": "number"}
                },
                "required": ["a", "b"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "calculate_sum":
        return [types.TextContent(type="text", text=str(arguments["a"] + arguments["b"]))]
    raise ValueError(f"Tool not found: {name}")

工具类型示例

  • 系统操作:运行系统命令。
  • API集成:包装外部API,如创建GitHub问题。
  • 数据处理:分析CSV文件。

最佳实践

  1. 使用清晰的名称和描述。
  2. 提供详细的JSON Schema定义。
  3. 实现错误处理和输入校验。
  4. 操作应专注且原子化。
  5. 支持进度报告和日志记录。

安全考虑

  1. 输入验证
  • 校验所有参数是否符合Schema。
  • 防止命令注入和路径遍历。
  1. 访问控制
  • 验证身份与权限。
  • 实施速率限制。
  1. 错误处理
  • 隐藏内部错误,避免暴露敏感信息。

动态工具发现

  • 客户端可以动态列出工具。
  • 服务器可以实时更新工具定义,并通知客户端。

错误处理

工具的错误应通过结果对象报告,而不是MCP协议级别的错误。以下是正确处理错误的示例:

TypeScript

try {
  const result = performOperation();
  return { content: [{ type: "text", text: `Success: ${result}` }] };
} catch (error) {
  return { isError: true, content: [{ type: "text", text: `Error: ${error.message}` }] };
}

Python

try:
    result = perform_operation()
    return types.CallToolResult(content=[types.TextContent(type="text", text=f"Success: {result}")])
except Exception as error:
    return types.CallToolResult(isError=True, content=[types.TextContent(type="text", text=f"Error: {str(error)}")])

测试工具

  1. 功能测试:验证正确执行和错误处理。
  2. 集成测试:测试工具与外部系统的交互。
  3. 安全测试:确保输入验证和访问控制。
  4. 性能测试:验证负载下的行为。
  5. 错误测试:测试工具如何报告和处理异常。

这份文档为开发者提供了清晰的指南,让他们能够快速定义、实现和测试安全且高效的工具,同时确保模型在使用这些工具时的可靠性与安全性。