侧边栏壁纸
博主头像
AI中文站

开拓MCP洪荒时代

  • 累计撰写 17 篇文章
  • 累计创建 3 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

MCP核心概念-Tools

工具

工具是模型上下文协议 (MCP) 中一个强大的原语,它使服务器能够向客户端公开可执行功能。通过工具,LLM 可以与外部系统交互、执行计算并在现实世界中采取行动。

概述

MCP 中的工具允许服务器公开可执行函数,这些函数可供客户端调用,并由 LLM 用来执行操作。这些工具的关键方面包括:

  • 发现tools/list:客户端可以通过端点列出可用的工具

  • 调用:使用端点调用工具tools/call,服务器执行请求的操作并返回结果

  • 灵活性:工具范围从简单的计算到复杂的 API 交互

资源类似,工具也由唯一名称标识,并可包含用于指导其使用的描述。然而,与资源不同的是,工具代表着动态操作,可以修改状态或与外部系统交互。

工具定义结构

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

{
  name: string;          // Unique identifier for the tool
  description?: string;  // Human-readable description
  inputSchema: {         // JSON Schema for the tool's parameters
    type: "object",
    properties: { ... }  // Tool-specific parameters
  },
  annotations?: {        // Optional hints about tool behavior
    title?: string;      // Human-readable title for the tool
    readOnlyHint?: boolean;    // If true, the tool does not modify its environment
    destructiveHint?: boolean; // If true, the tool may perform destructive updates
    idempotentHint?: boolean;  // If true, repeated calls with same args have no additional effect
    openWorldHint?: boolean;   // If true, tool interacts with external entities
  }
}

实施工具

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

app = Server("example-server")

@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 | types.ImageContent | types.EmbeddedResource]:
    if name == "calculate_sum":
        a = arguments["a"]
        b = arguments["b"]
        result = a + b
        return [types.TextContent(type="text", text=str(result))]
    raise ValueError(f"Tool not found: {name}")

工具图案示例

以下是服务器可以提供的工具类型的一些示例:

系统操作

与本地系统交互的工具:

{
  name: "execute_command",
  description: "Run a shell command",
  inputSchema: {
    type: "object",
    properties: {
      command: { type: "string" },
      args: { type: "array", items: { type: "string" } }
    }
  }
}

API 集成

包装外部 API 的工具:

{
  name: "github_create_issue",
  description: "Create a GitHub issue",
  inputSchema: {
    type: "object",
    properties: {
      title: { type: "string" },
      body: { type: "string" },
      labels: { type: "array", items: { type: "string" } }
    }
  }
}

数据处理

转换或分析数据的工具:

{
  name: "analyze_csv",
  description: "Analyze a CSV file",
  inputSchema: {
    type: "object",
    properties: {
      filepath: { type: "string" },
      operations: {
        type: "array",
        items: {
          enum: ["sum", "average", "count"]
        }
      }
    }
  }
}

最佳实践

实施工具时:

  1. 提供清晰、描述性的名称和描述

  2. 使用详细的 JSON Schema 定义参数

  3. 在工具描述中包含示例,以演示模型应如何使用它们

  4. 实施适当的错误处理和验证

  5. 对长时间操作使用进度报告

  6. 保持工具操作的集中性和原子性

  7. 记录预期回报价值结构

  8. 实施适当的超时

  9. 考虑对资源密集型操作进行速率限制

  10. 用于调试和监控的日志工具使用情况

安全注意事项

输入验证

  • 根据架构验证所有参数

  • 清理文件路径和系统命令

  • 验证 URL 和外部标识符

  • 检查参数大小和范围

  • 防止命令注入

访问控制

  • 在需要的地方实施身份验证

  • 使用适当的授权检查

  • 审计工具使用情况

  • 速率限制请求

  • 监控滥用行为

错误处理

  • 不要向客户端暴露内部错误

  • 记录与安全相关的错误

  • 适当处理超时

  • 错误发生后清理资源

  • 验证返回值

工具发现和更新

MCP 支持动态工具发现:

  1. 客户可以随时列出可用的工具

  2. 当工具发生变化时,服务器可以使用notifications/tools/list_changed

  3. 可以在运行时添加或删除工具

  4. 工具定义可以更新(但应谨慎操作)

错误处理

工具错误应在结果对象中报告,而不是作为 MCP 协议级错误报告。这样,LLM 才能发现并处理错误。当工具遇到错误时:

  1. 在结果中设置isErrortrue

  2. content在数组中包含错误详细信息

以下是工具正确错误处理的示例:

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

这种方法允许 LLM 发现发生的错误并可能采取纠正措施或请求人工干预。

工具注释

工具注释提供有关工具行为的额外元数据,帮助客户端了解如何呈现和管理工具。这些注释只是描述工具性质和影响的提示,不应作为安全决策的依据。

工具注释的用途

工具注释有几个主要用途:

  1. 在不影响模型上下文的情况下提供特定于 UX 的信息

  2. 帮助客户适当分类和展示工具

  3. 传达有关工具潜在副作用的信息

  4. 协助开发直观的工具审批界面

可用的工具注释

MCP 规范为工具定义了以下注释:

注解

类型

默认

描述

title

细绳

-

工具的可读标题,有助于 UI 显示

readOnlyHint

布尔值

错误的

如果为 true,则表示该工具不会修改其环境

destructiveHint

布尔值

真的

如果为真,该工具可能会执行破坏性更新(仅当为readOnlyHint假时才有意义)

idempotentHint

布尔值

错误的

如果为真,则使用相同参数重复调用该工具不会产生额外效果(仅当为readOnlyHint假时才有意义)

openWorldHint

布尔值

真的

如果属实,该工具可能会与外部实体的“开放世界”进行交互

示例用法

以下是针对不同场景使用注释定义工具的方法:

// A read-only search tool
{
  name: "web_search",
  description: "Search the web for information",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string" }
    },
    required: ["query"]
  },
  annotations: {
    title: "Web Search",
    readOnlyHint: true,
    openWorldHint: true
  }
}

// A destructive file deletion tool
{
  name: "delete_file",
  description: "Delete a file from the filesystem",
  inputSchema: {
    type: "object",
    properties: {
      path: { type: "string" }
    },
    required: ["path"]
  },
  annotations: {
    title: "Delete File",
    readOnlyHint: false,
    destructiveHint: true,
    idempotentHint: true,
    openWorldHint: false
  }
}

// A non-destructive database record creation tool
{
  name: "create_record",
  description: "Create a new record in the database",
  inputSchema: {
    type: "object",
    properties: {
      table: { type: "string" },
      data: { type: "object" }
    },
    required: ["table", "data"]
  },
  annotations: {
    title: "Create Database Record",
    readOnlyHint: false,
    destructiveHint: false,
    idempotentHint: false,
    openWorldHint: false
  }
}

在服务器实现中集成注释

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("example-server")

@mcp.tool(
    annotations={
        "title": "Calculate Sum",
        "readOnlyHint": True,
        "openWorldHint": False
    }
)
async def calculate_sum(a: float, b: float) -> str:
    """Add two numbers together.

    Args:
        a: First number to add
        b: Second number to add
    """
    result = a + b
    return str(result)

工具注释的最佳实践

  1. 准确说明副作用:清楚地表明工具是否修改了其环境以及这些修改是否具有破坏性。

  2. 使用描述性标题:提供人性化的标题,清楚地描述工具的用途。

  3. 正确指示幂等性:仅当使用相同参数重复调用确实没有额外影响时,才将工具标记为幂等。

  4. 设置适当的开放/封闭世界提示:指示工具是否与封闭系统(如数据库)或开放系统(如网络)交互。

  5. 请记住,注释只是提示:ToolAnnotations 中的所有属性都只是提示,并不保证能够如实地描述工具的行为。客户端切勿仅根据注释做出安全关键决策。

测试工具

MCP 工具的全面测试策略应涵盖:

  • 功能测试:验证工具在有效输入下正确执行,并适当处理无效输入

  • 集成测试:使用真实和模拟依赖关系测试工具与外部系统的交互

  • 安全测试:验证身份验证、授权、输入清理和速率限制

  • 性能测试:检查负载下的行为、超时处理和资源清理

  • 错误处理:确保工具通过 MCP 协议正确报告错误并清理资源

0

评论区