> ## Documentation Index
> Fetch the complete documentation index at: https://startai.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 工具

> 让 LLM 通过你的服务器执行操作

工具是 Model Context Protocol (MCP) 中的一个强大原语，它使服务器能够向客户端暴露可执行的功能。通过工具，LLM 可以与外部系统交互、执行计算并在现实世界中采取行动。

<Note>
  工具被设计为**模型可控**的，这意味着工具从服务器暴露给客户端时，目的是让 AI 模型能够自动调用它们（在人工监督下获得批准）。
</Note>

## 概述

MCP 中的工具允许服务器暴露可执行的函数，这些函数可以被客户端调用并被 LLM 用来执行操作。工具的关键方面包括：

* **发现**：客户端可以通过 `tools/list` 端点列出可用工具
* **调用**：工具通过 `tools/call` 端点调用，服务器执行请求的操作并返回结果
* **灵活性**：工具可以从简单的计算到复杂的 API 交互

与[资源](/docs/concepts/resources)一样，工具由唯一的名称标识，并可以包含描述来指导其使用。但是，与资源不同，工具代表可以修改状态或与外部系统交互的动态操作。

## 工具定义结构

每个工具都使用以下结构定义：

```typescript theme={null}
{
  name: string;          // 工具的唯一标识符
  description?: string;  // 人类可读的描述
  inputSchema: {         // 工具参数的 JSON Schema
    type: "object",
    properties: { ... }  // 工具特定的参数
  },
  annotations?: {        // 可选的工具行为提示
    title?: string;      // 工具的人类可读标题
    readOnlyHint?: boolean;    // 如果为 true，工具不会修改其环境
    destructiveHint?: boolean; // 如果为 true，工具可能执行破坏性更新
    idempotentHint?: boolean;  // 如果为 true，使用相同参数重复调用没有额外效果
    openWorldHint?: boolean;   // 如果为 true，工具与外部实体交互
  }
}
```

## 实现工具

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

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {
        tools: {}
      }
    });

    // 定义可用工具
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [{
          name: "calculate_sum",
          description: "将两个数字相加",
          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("未找到工具");
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    app = Server("example-server")

    @app.list_tools()
    async def list_tools() -> list[types.Tool]:
        return [
            types.Tool(
                name="calculate_sum",
                description="将两个数字相加",
                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"未找到工具：{name}")
    ```
  </Tab>
</Tabs>

## 工具模式示例

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

### 系统操作

与本地系统交互的工具：

```typescript theme={null}
{
  name: "execute_command",
  description: "运行 shell 命令",
  inputSchema: {
    type: "object",
    properties: {
      command: { type: "string" },
      args: { type: "array", items: { type: "string" } }
    }
  }
}
```

### API 集成

封装外部 API 的工具：

```typescript theme={null}
{
  name: "github_create_issue",
  description: "创建 GitHub issue",
  inputSchema: {
    type: "object",
    properties: {
      title: { type: "string" },
      body: { type: "string" },
      labels: { type: "array", items: { type: "string" } }
    }
  }
}
```

### 数据处理

转换或分析数据的工具：

```typescript theme={null}
{
  name: "analyze_csv",
  description: "分析 CSV 文件",
  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. 记录工具使用情况以进行调试和监控

## 安全考虑

在暴露工具时：

### 输入验证

* 根据 schema 验证所有参数
* 净化文件路径和系统命令
* 验证 URL 和外部标识符
* 检查参数大小和范围
* 防止命令注入

### 访问控制

* 在需要时实现身份验证
* 使用适当的授权检查
* 审计工具使用情况
* 限制请求速率
* 监控滥用情况

### 错误处理

* 不要向客户端暴露内部错误
* 记录安全相关错误
* 适当处理超时
* 在错误后清理资源
* 验证返回值

## 工具发现和更新

MCP 支持动态工具发现：

1. 客户端可以随时列出可用工具
2. 服务器可以使用 `notifications/tools/list_changed` 通知客户端工具变化
3. 工具可以在运行时添加或删除
4. 工具定义可以更新（但应谨慎进行）

## 错误处理

工具错误应该在结果对象中报告，而不是作为 MCP 协议级别的错误。这允许 LLM 看到并可能处理错误。当工具遇到错误时：

1. 在结果中将 `isError` 设置为 `true`
2. 在 `content` 数组中包含错误详情

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

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    try {
      // 工具操作
      const result = performOperation();
      return {
        content: [
          {
            type: "text",
            text: `操作成功：${result}`
          }
        ]
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `错误：${error.message}`
          }
        ]
      };
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    try:
        # 工具操作
        result = perform_operation()
        return types.CallToolResult(
            content=[
                types.TextContent(
                    type="text",
                    text=f"操作成功：{result}"
                )
            ]
        )
    except Exception as error:
        return types.CallToolResult(
            isError=True,
            content=[
                types.TextContent(
                    type="text",
                    text=f"错误：{str(error)}"
                )
            ]
        )
    ```
  </Tab>
</Tabs>

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

## 工具注解

工具注解提供了关于工具行为的额外元数据，帮助客户端理解如何展示和管理工具。这些注解是描述工具性质和影响的提示，但不应用于安全决策。

### 工具注解的目的

工具注解有几个关键目的：

1. 提供特定于 UX 的信息，而不影响模型上下文
2. 帮助客户端适当地分类和展示工具
3. 传达有关工具潜在副作用的信息
4. 协助开发直观的工具批准界面

### 可用的工具注解

MCP 规范为工具定义了以下注解：

| 注解                | 类型      | 默认值   | 描述                                                          |
| ----------------- | ------- | ----- | ----------------------------------------------------------- |
| `title`           | string  | -     | 工具的人类可读标题，适用于 UI 显示                                         |
| `readOnlyHint`    | boolean | false | 如果为 true，表示工具不会修改其环境                                        |
| `destructiveHint` | boolean | true  | 如果为 true，工具可能执行破坏性更新（仅当 `readOnlyHint` 为 false 时有意义）        |
| `idempotentHint`  | boolean | false | 如果为 true，使用相同参数重复调用工具没有额外效果（仅当 `readOnlyHint` 为 false 时有意义） |
| `openWorldHint`   | boolean | true  | 如果为 true，工具可能与外部实体的"开放世界"交互                                 |

### 使用示例

以下是如何为不同场景定义带有注解的工具：

```typescript theme={null}
// 只读搜索工具
{
  name: "web_search",
  description: "在网上搜索信息",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string" }
    },
    required: ["query"]
  },
  annotations: {
    title: "网络搜索",
    readOnlyHint: true,
    openWorldHint: true
  }
}

// 破坏性文件删除工具
{
  name: "delete_file",
  description: "从文件系统删除文件",
  inputSchema: {
    type: "object",
    properties: {
      path: { type: "string" }
    },
    required: ["path"]
  },
  annotations: {
    title: "删除文件",
    readOnlyHint: false,
    destructiveHint: true,
    idempotentHint: true,
    openWorldHint: false
  }
}

// 非破坏性数据库记录创建工具
{
  name: "create_record",
  description: "在数据库中创建新记录",
  inputSchema: {
    type: "object",
    properties: {
      table: { type: "string" },
      data: { type: "object" }
    },
    required: ["table", "data"]
  },
  annotations: {
    title: "创建数据库记录",
    readOnlyHint: false,
    destructiveHint: false,
    idempotentHint: false,
    openWorldHint: false
  }
}
```

### 在服务器实现中集成注解

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [{
          name: "calculate_sum",
          description: "将两个数字相加",
          inputSchema: {
            type: "object",
            properties: {
              a: { type: "number" },
              b: { type: "number" }
            },
            required: ["a", "b"]
          },
          annotations: {
            title: "计算总和",
            readOnlyHint: true,
            openWorldHint: false
          }
        }]
      };
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from mcp.server.fastmcp import FastMCP

    mcp = FastMCP("example-server")

    @mcp.tool(
        annotations={
            "title": "计算总和",
            "readOnlyHint": True,
            "openWorldHint": False
        }
    )
    async def calculate_sum(a: float, b: float) -> str:
        """将两个数字相加。
        
        参数：
            a: 要相加的第一个数字
            b: 要相加的第二个数字
        """
        result = a + b
        return str(result)
    ```
  </Tab>
</Tabs>

### 工具注解的最佳实践

1. **准确描述副作用**：清楚地指出工具是否修改其环境以及这些修改是否具有破坏性。

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

3. **正确指示幂等性**：只有当使用相同参数重复调用确实没有额外效果时，才将工具标记为幂等。

4. **设置适当的开放/封闭世界提示**：指出工具是与封闭系统（如数据库）还是开放系统（如网络）交互。

5. **记住注解是提示**：ToolAnnotations 中的所有属性都是提示，不保证能忠实描述工具行为。客户端不应仅基于注解做出安全关键决策。

## 测试工具

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

* **功能测试**：验证工具使用有效输入时正确执行，并适当处理无效输入
* **集成测试**：使用真实和模拟的依赖项测试工具与外部系统的交互
* **安全测试**：验证身份验证、授权、输入净化和速率限制
* **性能测试**：检查负载下的行为、超时处理和资源清理
* **错误处理**：确保工具通过 MCP 协议正确报告错误并清理资源
