主题
Tools
Model Context Protocol (MCP) 允许服务端暴露可被语言模型调用的工具。工具使模型能够与外部系统交互,例如查询数据库、调用 API 或执行计算。每个工具由名称唯一标识,并包含描述其 schema 的元数据。
NOTE
为简洁起见,本页的请求示例省略了 _meta 请求元数据 (io.modelcontextprotocol/protocolVersion、 io.modelcontextprotocol/clientInfo 和 io.modelcontextprotocol/clientCapabilities)。每个请求 MUST(必须)包含 必需的 _meta 字段;参见 _meta。
用户交互模型
MCP 中的工具被设计为模型控制的,这意味着语言模型可以基于其上下文理解以及用户的提示模板自动发现并调用工具。
然而,实现方可以自由地通过任何适合其需求的接口模式来暴露工具——协议本身并不强制规定任何特定的用户交互模型。
WARNING
出于信任、安全和保障考虑,SHOULD(应该)始终 有一个人工参与其中,并具备拒绝工具调用的能力。
应用程序 SHOULD(应该):
- 提供 UI,明确说明哪些工具正被暴露给 AI 模型
- 在工具被调用时插入清晰的视觉指示
- 针对相关操作向用户展示确认提示,以确保有人工参与 其中
能力
支持工具的服务端 MUST(必须)声明 tools 能力:
json
{
"capabilities": {
"tools": {
"listChanged": true
}
}
}listChanged 表示当可用工具列表发生变化时,服务端是否会发出通知。
声明了 tools 能力的服务端 MUST(必须)响应 tools/list 请求,返回当前可供发起请求的客户端使用的工具集合。该集合 MAY(可以)为空,并且 MAY(可以)随时间变化(参见 List Changed Notification),但 MUST NOT(不得)因连接而异,也不得作为该连接上其他请求的副作用而变化。该集合 MAY(可以)因请求所呈现的授权而不同——例如,仅返回调用方被授予的 scope 所允许的工具——因为凭证是逐请求输入,而非连接状态。
服务端 SHOULD(应该)以确定性排序返回工具(即,在底层工具集合未发生变化时,跨请求保持相同的顺序)。确定性排序使客户端能够可靠地缓存工具列表,并在工具被包含在模型上下文中时提高 LLM 提示模板缓存命中率。
协议消息
列举工具
为发现可用工具,客户端发送 tools/list 请求。此操作支持 分页 和 缓存。
Request:
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"cursor": "optional-cursor-value"
}
}Response:
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"tools": [
{
"name": "get_weather",
"title": "Weather Information Provider",
"description": "Get current weather information for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or zip code"
}
},
"required": ["location"]
},
"icons": [
{
"src": "https://example.com/weather-icon.png",
"mimeType": "image/png",
"sizes": ["48x48"]
}
]
}
],
"nextCursor": "next-page-cursor",
"ttlMs": 300000,
"cacheScope": "public"
}
}调用工具
为调用工具,客户端发送 tools/call 请求:
Request:
json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "New York"
}
}
}Response:
json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
}
],
"isError": false
}
}需要输入的工具结果
服务端 MAY(可以)以 InputRequiredResult 响应 tools/call,以表示在工具调用完成之前需要补充输入。这遵循 多轮往返请求 机制。
当携带输入响应重试请求时,客户端在请求参数中包含 inputResponses,以及(若服务端提供)requestState:
Input Required Response:
json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "input_required",
"inputRequests": {
"github_login": {
"method": "elicitation/create",
"params": {
"mode": "form",
"message": "Please provide your GitHub username",
"requestedSchema": {
"type": "object",
"properties": {
"name": { "type": "string" }
},
"required": ["name"]
}
}
}
},
"requestState": "eyJsb2NhdGlvbiI6Ik5ldyBZb3JrIn0..."
}
}使用输入响应重试:
json
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "New York"
},
"inputResponses": {
"github_login": {
"action": "accept",
"content": {
"name": "octocat"
}
}
},
"requestState": "eyJsb2NhdGlvbiI6Ik5ldyBZb3JrIn0..."
}
}请注意,初始请求与重试之间的 JSON-RPC id MUST(必须)不同。
列表变更通知
当可用工具的列表发生变化时,声明了 listChanged 能力的服务端 SHOULD(应当)向已打开 subscriptions/listen 流且 toolsListChanged: true 的客户端(连接器)发送通知:
json
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}消息流
sequenceDiagram
participant LLM
participant Client
participant Server
Note over Client,Server: Discovery
Client->>Server: tools/list
Server-->>Client: List of tools
Note over Client,LLM: Tool Selection
LLM->>Client: Select tool to use
Note over Client,Server: Invocation
Client->>Server: tools/call
Server-->>Client: Tool result
Client->>LLM: Process result
opt listChanged
Client->>Server: subscriptions/listen (toolsListChanged: true)
Server--)Client: notifications/subscriptions/acknowledged
Note over Client,Server: Updates
Server--)Client: notifications/tools/list_changed
Client->>Server: tools/list
Server-->>Client: Updated tools
end
数据类型
工具
工具定义包含:
name:工具的唯一标识符title:可选的、供展示用途的工具人类可读名称。description:功能的人类可读描述icons:可选的图标数组,用于在用户界面中展示inputSchema:定义预期参数的 JSON Schema- 遵循 JSON Schema 使用指南
- 若不存在
$schema字段,则默认为 2020-12 - MUST(必须)是有效的 JSON Schema 对象(不能为
null) - 对于无参数的工具,使用以下有效方式之一:
{ "type": "object", "additionalProperties": false }- 推荐:显式地仅接受空对象{ "type": "object" }- 接受任意对象(包括带属性的对象)
- 属性 MAY(可以)包含
x-mcp-header注解,以将参数值暴露为 HTTP 头
outputSchema:可选的 JSON Schema,定义预期的输出结构- 遵循 JSON Schema 使用指南
- 若不存在
$schema字段,则默认为 2020-12
annotations:描述工具行为的可选属性
WARNING
出于信任、安全与保障考虑,客户端(连接器) MUST(必须)将工具注解视为不可信,除非它们来自可信的服务端。
工具名称
- 工具名称 SHOULD(应当)在 1 到 128 个字符之间(含端点)。
- 工具名称 SHOULD(应当)被视为区分大小写。
- 以下 SHOULD(应当)是唯一允许的字符:大小写 ASCII 字母(A-Z、a-z)、数字 (0-9)、下划线(_)、连字符(-)和点(.)
- 工具名称 SHOULD NOT(不应)包含空格、逗号或其他特殊字符。
- 工具名称 SHOULD(应当)在单个服务端内唯一。
- 有效工具名称示例:
getUserDATA_EXPORT_v2admin.tools.list
NOTE
工具名称的唯一性以单个服务端为范围。从多个服务端聚合工具的客户端(连接器)或代理 MAY(可以)遇到命名冲突(例如, 两个服务端各自暴露一个 search 工具),并且 SHOULD(应当)实现一种消歧策略,例如为工具名称添加服务端标识符前缀。
服务端 name(来自 serverInfo)不保证在服务端之间唯一,SHOULD NOT(不应)依赖它进行消歧。
x-mcp-header
x-mcp-header 扩展属性允许服务端指定特定的工具参数,使其在使用 Streamable HTTP 传输时被镜像到 HTTP 头中。 这使网络中间层(负载均衡器、代理、WAF)能够基于参数值路由和处理请求,而无需解析请求体。
x-mcp-header 属性直接放置在要被镜像的属性的 JSON Schema 中。其值指定生成的 Mcp-Param-{name} HTTP 头的名称部分。
对 x-mcp-header 值的约束:
- MUST NOT(不得)为空
- MUST(必须)匹配 HTTP 字段名 token 语法(
1*tchar,RFC 9110 第 5.1 节) - MUST NOT(不得)包含控制字符,包括回车(CR,
\r)或 换行(LF,\n) - MUST(必须)在
inputSchema中的所有x-mcp-header值之间大小写不敏感地唯一 - MUST(必须)仅应用于具有原始类型(integer、string、boolean)的参数。 类型为
number的参数不允许。整数值 MUST(必须)处于使用 IEEE754 双精度浮点数表示的整数安全范围内(−253+1 到 253−1) - MUST(必须)仅应用于从 schema 根 静态可达 的属性,其定义见 来自工具参数的自定义头, 该节还定义了如何从调用参数中提取头值
使用 Streamable HTTP 传输的客户端(连接器) MUST(必须)拒绝任何 x-mcp-header 值违反这些约束的工具定义。拒绝意味着客户端(连接器) MUST(必须) 将无效工具从 tools/list 的结果中排除。客户端(连接器) SHOULD(应当)在拒绝工具定义时记录一条 警告,包含工具名称和拒绝原因。这确保单个格式错误的工具定义不会阻止其他 有效工具被使用。使用其他传输(例如 stdio)的客户端(连接器) MAY(可以)完全忽略 x-mcp-header 注解。
带 x-mcp-header 的工具定义示例:
json
{
"name": "execute_sql",
"description": "Execute SQL on Google Cloud Spanner",
"inputSchema": {
"type": "object",
"properties": {
"region": {
"type": "string",
"description": "The region to execute the query in",
"x-mcp-header": "Region"
},
"query": {
"type": "string",
"description": "The SQL query to execute"
}
},
"required": ["region", "query"]
}
}在此示例中,当工具以 "region": "us-west1" 被调用时,客户端会向 HTTP 请求添加 头 Mcp-Param-Region: us-west1。
WARNING
服务端开发者 SHOULD NOT(不应)将敏感参数(密码、API 密钥、令牌、 PII)标记为 x-mcp-header,因为头值对网络中间人可见。
工具结果
工具结果可以包含结构化或非结构化内容。
非结构化内容在结果的 content 字段中返回,并且可以包含多个不同类型的內容项:
NOTE
所有内容类型(文本、图像、音频、资源链接和嵌入资源) 都支持可选的 注解,用于 提供关于受众、优先级和修改时间的元数据。这与 资源和提示模板使用的注解格式相同。
文本内容
json
{
"type": "text",
"text": "Tool result text"
}图像内容
json
{
"type": "image",
"data": "base64-encoded-data",
"mimeType": "image/png",
"annotations": {
"audience": ["user"],
"priority": 0.9
}
}音频内容
json
{
"type": "audio",
"data": "base64-encoded-audio-data",
"mimeType": "audio/wav"
}资源链接
工具 MAY(可以)返回指向资源的链接,以提供额外的上下文 或数据。在这种情况下,工具将返回一个客户端可以订阅或获取的 URI:
json
{
"type": "resource_link",
"uri": "file:///project/src/main.rs",
"name": "main.rs",
"description": "Primary application entry point",
"mimeType": "text/x-rust"
}资源链接支持与常规资源相同的资源注解,以帮助客户端理解如何使用它们。
INFO
工具返回的资源链接不保证会出现在 resources/list 请求的结果中。
嵌入资源
资源 MAY(可以)使用合适的 URI 方案嵌入,以提供额外的上下文 或数据。使用嵌入资源的服务端 SHOULD(应)实现 resources 能力:
json
{
"type": "resource",
"resource": {
"uri": "file:///project/src/main.rs",
"mimeType": "text/x-rust",
"text": "fn main() {\n println!(\"Hello world!\");\n}",
"annotations": {
"audience": ["user", "assistant"],
"priority": 0.7,
"lastModified": "2025-05-03T14:30:00Z"
}
}
}嵌入资源支持与常规资源相同的资源注解,以帮助客户端理解如何使用它们。
结构化内容
结构化内容在结果的 structuredContent 字段中作为 JSON 值返回。这可以是任何符合工具 outputSchema(如果定义了的话)的 JSON 值(对象、数组、字符串、数字、布尔值或 null)。
为了向后兼容,返回结构化内容的工具 SHOULD(应)同时在一个 TextContent 块中返回序列化后的 JSON。
NOTE
structuredContent 是服务端产生的结果数据,与 LLM "结构化输出"(模式约束的模型生成)无关。
输出模式
工具还可以提供输出模式,用于验证结构化结果。 如果提供了输出模式:
- 服务端 MUST(必须)提供符合此模式的结构化结果。
- 客户端 SHOULD(应)根据此模式验证结构化结果。
带输出模式的工具示例:
json
{
"name": "get_weather_data",
"title": "Weather Data Retriever",
"description": "Get current weather data for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or zip code"
}
},
"required": ["location"]
},
"outputSchema": {
"type": "object",
"properties": {
"temperature": {
"type": "number",
"description": "Temperature in celsius"
},
"conditions": {
"type": "string",
"description": "Weather conditions description"
},
"humidity": {
"type": "number",
"description": "Humidity percentage"
}
},
"required": ["temperature", "conditions", "humidity"]
}
}此工具的有效响应示例:
json
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "{\"temperature\": 22.5, \"conditions\": \"Partly cloudy\", \"humidity\": 65}"
}
],
"structuredContent": {
"temperature": 22.5,
"conditions": "Partly cloudy",
"humidity": 65
}
}
}带数组输出模式的工具示例:
json
{
"name": "list_users",
"title": "User List",
"description": "Returns a list of all users",
"inputSchema": {
"type": "object",
"properties": {}
},
"outputSchema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"email": { "type": "string" }
},
"required": ["id", "name", "email"]
}
}
}工具返回数组输出的有效响应示例:
json
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "Found 2 users: Alice (alice@example.com) and Bob (bob@example.com)."
}
],
"structuredContent": [
{ "id": "1", "name": "Alice", "email": "alice@example.com" },
{ "id": "2", "name": "Bob", "email": "bob@example.com" }
]
}
}提供输出 schema 有助于客户端和 LLM 理解并正确处理结构化的工具输出,方式包括:
- 对响应启用严格的 schema 校验
- 提供类型信息,以便更好地与编程语言集成
- 引导客户端和 LLM 正确解析并使用返回的数据
- 支持更好的文档和开发者体验
Schema 示例
使用默认 2020-12 schema 的工具:
json
{
"name": "calculate_sum",
"description": "Add two numbers",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "number" },
"b": { "type": "number" }
},
"required": ["a", "b"]
}
}使用显式 draft-07 schema 的工具:
json
{
"name": "calculate_sum",
"description": "Add two numbers",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"a": { "type": "number" },
"b": { "type": "number" }
},
"required": ["a", "b"]
}
}无参数的工具:
json
{
"name": "get_current_time",
"description": "Returns the current server time",
"inputSchema": {
"type": "object",
"additionalProperties": false
}
}有状态工具
NOTE
本节是关于工具设计的非规范性指导。协议中没有状态句柄的概念;从传输层面看, 句柄只是工具结果中的一个普通字符串,以及后续工具调用中的一个普通参数。
MCP 没有协议层面的会话,因此服务端不能依赖隐式的逐连接状态来关联一次工具调用与下一次工具调用。需要在多次调用之间维护状态的服务端——例如购物车、打开的浏览器上下文、数据库事务——应当通过从创建工具返回一个显式句柄,并在后续调用中接受该句柄作为参数来实现。
例如,一个管理购物车的服务端可能暴露:
jsonc
// → tools/call
{ "name": "create_basket", "arguments": {} }
// ← result
{
"content": [{ "type": "text", "text": "Created basket bsk_a1b2c3" }],
"structuredContent": { "basket_id": "bsk_a1b2c3" }
}
// → tools/call
{
"name": "add_item",
"arguments": { "basket_id": "bsk_a1b2c3", "sku": "..." }
}模型负责将 basket_id 向前传递;服务端在该键下存储购物车内容,并在每次调用时查找它们。
在设计句柄时,服务端应考虑:
- 授权。 对于需要认证的服务端,句柄是一个名称,而不是一种能力。服务端应在每次调用时根据句柄校验调用方的授权。对于无需认证的服务端,句柄必然是一个持有者令牌,此时应以足够的熵生成(例如 UUIDv4),并赋予其有界的生命周期。
- 不透明性。 编码了内部结构的句柄会招致解析或猜测;不透明的标识符则不会。
- 生命周期。 由于句柄的生命周期长于任何单个连接,服务端的保留策略应在创建工具的 description 中说明(例如 "baskets expire after 24 hours of inactivity"),以便模型在决定创建状态时能够看到它。
- 过期错误。 针对已过期或未知句柄的调用应返回一个说明此情况的工具执行错误,以便模型可以通过创建新句柄来恢复。
错误处理
工具使用两种错误报告机制:
协议错误 表示请求结构本身的问题,模型较难修复:
- 未知工具
- 格式错误的请求(未能满足 CallToolRequest schema 的请求)
- 服务端错误
它们以标准 JSON-RPC 错误的形式返回:
json{ "jsonrpc": "2.0", "id": 3, "error": { "code": -32602, "message": "Unknown tool: invalid_tool_name" } }工具执行错误 包含可操作的反馈,语言模型可以用其自我纠正并以调整后的参数重试:
- API 失败
- 输入校验错误(例如日期格式错误、值超出范围)
- 业务逻辑错误
它们在工具结果中以
isError: true报告:json{ "jsonrpc": "2.0", "id": 4, "result": { "resultType": "complete", "content": [ { "type": "text", "text": "Invalid departure date: must be in the future. Current date is 08/08/2025." } ], "isError": true } }
客户端 MAY(可以)向语言模型提供协议错误,尽管这些错误不太可能带来成功的恢复。 客户端 SHOULD(应该)向语言模型提供工具执行错误,以支持自我纠正。
安全注意事项
服务端 MUST(必须):
- 校验所有工具输入
- 实现适当的访问控制
- 对工具调用进行速率限制
- 对工具输出进行净化
客户端 SHOULD(应该):
- 对敏感操作提示用户确认
- 在调用服务端之前向用户展示工具输入,以避免恶意或 意外的数据外泄
- 在传递给 LLM 之前校验工具结果
- 在根据
inputSchema和outputSchema校验工具输入和输出时, 遵循$ref解析要求 - 为工具调用实现超时
- 为审计目的记录工具使用情况