在与大语言模型交互时,我们常常希望它能超越文本生成的范畴,去执行一些实际的操作,比如查询最新的天气、获取数据库中的销售数据,或者调用一个外部 API。Model Context Protocol (MCP) 中的 Tools 功能正是为了实现这一目标而设计的。它为语言模型提供了一套标准化的机制,使其能够与外部系统进行交互。
简单来说,MCP Tools 就像是为语言模型提供的一组可以使用的“工具箱”。每个工具都有明确的功能描述和使用说明,模型可以根据对话的上下文和用户的意图,自主地决定何时以及如何使用这些工具。
MCP Tools 是如何工作的?
MCP Tools 的核心交互模式是“模型控制”(model-controlled)。这意味着语言模型能够根据上下文理解自动发现并调用工具,而不需要用户显式地发出指令。整个工作流程可以分解为几个关键步骤:发现、选择和调用。
首先是发现阶段。客户端(例如一个集成大模型的应用程序)会向服务器请求可用的工具列表。服务器返回一个包含所有工具定义的列表,每个定义都详细说明了工具的名称、功能描述和所需的输入参数。
得到工具列表后,语言模型便知道了自己“能做什么”。当用户的提问或指令需要外部信息或操作时,模型会从列表中选择一个最合适的工具。这个选择过程是基于模型对工具功能描述的理解和对当前任务的判断。
最后是调用阶段。一旦模型选定了工具并确定了所需的参数,客户端就会代表模型向服务器发送一个调用请求。服务器执行该工具,并将执行结果返回给客户端。客户端再将这个结果提供给模型,模型可以基于这个新信息继续与用户对话或完成任务。
这个过程可以用下面的消息流来描述:
- 客户端向服务器请求工具列表。
- 服务器返回可用的工具。
- 语言模型根据用户输入,决定使用某个工具。
- 客户端向服务器发送工具调用请求。
- 服务器执行工具并返回结果。
- 客户端将结果交给语言模型进行处理。

发现可用的 Tools
要让模型知道有哪些工具可用,第一步就是从服务器获取工具列表。这是通过发送一个 tools/list 请求实现的。一个最简单的请求如下所示:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
服务器收到请求后,会返回一个包含 tools 数组的响应。数组中的每一项都代表一个可用的工具。例如,一个提供天气查询功能的工具,其定义可能如下:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "get_weather",
"title": "天气信息提供器",
"description": "获取一个地点的当前天气信息",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称或邮政编码"
}
},
"required": ["location"]
}
}
],
"nextCursor": null
}
}
在这个响应中,tools 数组里的 get_weather 工具包含了几个关键信息:
name: 工具的唯一标识符,用于后续的调用。title: 一个易于人类阅读的标题。description: 对工具功能的详细描述,这是模型理解工具用途的主要依据。inputSchema: 一个 JSON Schema 对象,它精确定义了调用此工具需要提供哪些参数。在这里,它要求一个名为location的字符串参数。
正是通过 description 和 inputSchema,模型才能准确地理解每个工具的功能和使用方法。
调用一个 Tool
当模型决定使用某个工具时,客户端会发送一个 tools/call 请求。这个请求必须包含要调用的工具 name 和符合其 inputSchema 的 arguments。
继续以天气查询为例,如果用户想知道纽约的天气,模型会指示客户端发起如下调用:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "New York"
}
}
}
服务器执行 get_weather 工具后,会将结果返回。一个成功的调用结果通常包含工具输出的内容,并且 isError 字段为 false。
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "纽约当前天气:\n温度:22°C\n天气状况:局部多云"
}
],
"isError": false
}
}
这里的 content 数组包含了一个类型为 text 的对象,其内容就是模型需要的具体天气信息。模型拿到这个结果后,就可以生成一句通顺的自然语言回答给用户,例如:“纽约现在是局部多云天气,温度为 22 摄氏度。”
理解 Tool 的返回结果
Tool 的执行结果可以分为非结构化内容和结构化内容两种,这为不同场景提供了灵活性。
非结构化内容
非结构化内容是最常见的返回形式,它被包裹在 result 对象的 content 字段中。content 是一个数组,可以包含多种不同类型的数据块,例如:
text: 纯文本信息,如上文天气查询的例子。image: Base64 编码的图片数据。audio: Base64 编码的音频数据。resource_link: 指向其他资源的链接,例如一个文件路径 URI。resource: 直接嵌入的资源内容。
这种格式非常灵活,适合返回自然语言描述、多媒体文件或者简单的信息片段。
结构化内容
对于需要精确数据和程序化处理的场景,Tool 可以返回结构化内容。这需要 Tool 在定义时提供一个 outputSchema 来描述输出数据的结构,并在返回结果时使用 structuredContent 字段。
例如,一个返回更详细天气数据的工具 get_weather_data,它的定义可能包含 outputSchema:
{
"name": "get_weather_data",
"description": "获取一个地点的结构化天气数据",
"inputSchema": {
"type": "object",
"properties": { "location": { "type": "string" } },
"required": ["location"]
},
"outputSchema": {
"type": "object",
"properties": {
"temperature": { "type": "number", "description": "单位:摄氏度" },
"conditions": { "type": "string" },
"humidity": { "type": "number", "description": "湿度百分比" }
},
"required": ["temperature", "conditions", "humidity"]
}
}
当调用这个工具时,一个有效的返回结果会同时包含 structuredContent 和作为后备的 content:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "{\"temperature\": 22.5, \"conditions\": \"Partly cloudy\", \"humidity\": 65}"
}
],
"structuredContent": {
"temperature": 22.5,
"conditions": "Partly cloudy",
"humidity": 65
}
}
}
结构化返回的好处显而易见,它使得客户端应用程序可以轻松地解析和验证数据,而无需处理复杂的文本字符串。
下面的表格总结了非结构化内容与结构化内容的区别。
| 特性 | 非结构化内容 | 结构化内容 |
|---|---|---|
| 承载字段 | content |
structuredContent |
| 数据格式 | 包含文本、图片、音频等对象的数组 | 符合 outputSchema 的 JSON 对象 |
| 验证方式 | 无内置的模式验证 | 可通过 outputSchema 进行严格验证 |
| 适用场景 | 返回自然语言描述、多媒体文件或简单的文本信息 | 返回需要程序化处理的精确数据,如 API 响应体 |
错误处理与安全考量
在与外部系统交互时,错误和安全问题不可避免。MCP 为 Tools 定义了两种明确的错误报告机制。
第一种是协议层面的错误,当请求本身不合法时(例如调用一个不存在的工具),服务器会返回一个标准的 JSON-RPC error 对象。
{
"jsonrpc": "2.0,
"id": 3,
"error": {
"code": -32602,
"message": "Unknown tool: invalid_tool_name"
}
}
第二种是工具执行过程中的错误,例如外部 API 调用失败或输入数据无效。这种错误会在 result 对象中通过将 isError 设置为 true 来报告,并在 content 中提供错误信息。
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [
{
"type": "text",
"text": "获取天气数据失败:API 调用频率超限"
}
],
"isError": true
}
}
下表对比了这两种错误类型。
| 错误类型 | 触发场景 | 报告方式 | 示例 |
|---|---|---|---|
| 协议错误 | 客户端请求不符合协议规范 | 标准 JSON-RPC error 对象 |
调用了不存在的 tool |
| 工具执行错误 | Tool 在执行过程中内部失败 | 在 result 对象中设置 isError: true |
外部 API 调用失败 |
除了错误处理,安全是 Tool 使用中至关重要的一环。由于模型可能在没有用户直接干预的情况下调用工具,因此必须确保有“人在环”(human in the loop)的机制。应用程序应该在模型调用工具时给出清晰的视觉提示,并在执行敏感操作(如修改文件、发送邮件)前,向用户弹出确认对话框。这可以有效防止潜在的误操作或恶意行为,确保技术始终在安全可控的范围内服务于人。
开发必备:API 全流程管理神器 Apifox
介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、API 调试、API 设计、API 测试、API Mock、自动化测试等功能于一体的 API 管理工具,Apifox 可以说是开发者提升效率的必备工具之一。
如果你正在开发项目需要进行接口调试,不妨试试 Apifox。注册过程非常简单,你可以直接在这里注册使用。

注册成功后可以先看看官方提供的示例项目,这些案例都是经过精心设计的,能帮助你快速了解 Apifox 的主要功能。
使用 Apifox 的一大优势是它完全兼容 Postman 和 Swagger 数据格式,如果你之前使用过这些工具,数据导入会非常方便。而且它的界面设计非常友好,即使是第一次接触的新手也能很快上手,快去试试吧!
