基于最新 MCP 规范(Schema Version:2025-06-18)
随着大语言模型(LLM)成为智能系统核心引擎,模型“能理解”远比“能调用”来得更快。如何让模型可靠地调用工具、管理任务、处理资源,逐渐成为构建 Agent 系统的基础挑战。Model Context Protocol(MCP)应运而生,它提供了一套清晰、通用的调用契约,使 LLM 能够安全、高效、语义一致地与服务接口交互。Model Context Protocol(MCP) 由 Anthropic 于 2024 年底提出,随后被 OpenAI、Microsoft、Google 等巨头采纳,MCP 已成为连接 LLM 与真实世界能力的桥梁。它是 Function Calling 的演进,也是 Agent 系统迈向实用的重要支撑。
(图像来自:github.com/open-interp…
1 什么是 MCP?
Model Context Protocol(MCP) 是一种专为 LLM 打造的通用接口协议,基于 JSON-RPC 2.0 构建,目标是在不绑定厂商的前提下,让任何模型都可以发现、调用外部功能(tools)和数据资源(resources),统一接入各种工具链。
它的核心设计理念包括:
- 🌐 标准化:不再每接一个 API 就要重写代码,MCP 统一了调用格式。🧩 模块化:每个 MCP Server 声明自己的能力和数据资源,供模型动态发现。🔐 安全性:支持权限控制、调用跟踪、进度上报、取消请求等功能。🤖 通用模型适配:Claude、ChatGPT、Gemini 等模型都可接入。
1.1 MCP 的三大核心组成
sequenceDiagram title MCP 协议下 LLM 工具调用与响应流程 participant User participant MCPClient as MCP-Client participant LLM participant MCPServer as MCP-Server User ->> MCPClient: 发送请求 MCPClient ->> LLM: 传递用户查询及工具描述 [1,2](@ref) LLM -->> MCPClient: 返回需调用的工具指令 MCPClient ->> MCPServer: 执行工具调用(HTTP/SSE/stdio)[1](@ref) MCPServer -->> MCPClient: 返回执行结果 MCPClient ->> LLM: 传递工具执行结果 [2](@ref) LLM -->> MCPClient: 生成自然语言响应 MCPClient -->> User: 返回最终响应
1. MCP Server —— 能力的提供者
MCP Server 是一个“对外注册能力和数据”的服务节点。它通过 JSON Schema 格式声明:
- 提供哪些
tools
可访问哪些 resources
(如数据库、文件系统)支持哪些 prompts
(用于生成指令或上下文)2. MCP Client —— 模型端的接入适配器
MCP Client 运行在 LLM 所在的上下文中,负责:
- 自动发现 MCP Server(支持本地、远程、注册中心)查询其功能(通过
list_tools()
)发起调用请求(call_tool()
)转换返回结构供模型理解(结构化 JSON 转自然语言)OpenAI 的 Agents SDK 已经内置了 MCP Client,未来也可能集成到更多应用中,如 VSCode Copilot、Windows Copilot、浏览器助手等。
3. LLM Agent —— 思考 + 执行的主体
Agent 是具备规划、推理、多步执行能力的 LLM 应用。例如:
当用户问“帮我整理下 Downloads 目录里的 PDF 按时间排序”,模型会:
- 使用 MCP Client 查询 MCP Server 中的文件工具;调用
list_files(path="/Users/xx/Downloads")
;过滤出 .pdf
文件,调用 get_metadata()
获取创建时间;输出整理后的列表。过去这些流程要写死在程序中,现在只需通过 MCP 发现 +调用即可。
sequenceDiagram title 多MCP智能体复杂任务编排流程 participant User as 用户 participant Agent as 智能体 participant MCP1 as 规划引擎 MCP Server participant MCP2 as 地址解析 MCP Server User ->> Agent: 提交任务(如:配送最优路径生成) Agent ->> Agent: 分解任务、规划调用流程 Agent ->> MCP2: 地址标准化(解析文本为结构化地址) MCP2 -->> Agent: 返回标准地址对象 Agent ->> MCP1: 调用规划引擎(输入结构化地址等参数) MCP1 -->> Agent: 返回初步规划方案 Note right of Agent: 智能体判断结果是否符合业务约束 Agent ->> Agent: 若不满足,则调整约束参数 Agent ->> MCP1: 重新调用规划引擎 alt 需要再次解析新地址 MCP1 ->> MCP2: 触发新一轮地址解析 MCP2 -->> MCP1: 返回新地址对象 end MCP1 -->> Agent: 返回多种备选规划方案 Agent -->> User: 交付最终多方案规划结果
1.2 Function Calling 与 MCP 有什么不同?
功能 | Function Calling(OpenAI) | MCP(开放协议) |
---|---|---|
接入方式 | 开发者自定义 schema | JSON-RPC 标准化 |
适配对象 | ChatGPT 系列 | 任意 LLM |
功能列表 | 静态注册 | 动态发现(list_tools) |
安全机制 | 需自行实现 | 支持取消 / 权限管理 |
工具执行方 | 通常是 OpenAI 服务器 | 用户本地或远程 MCP Server |
生态整合 | 专属 API | 开放注册中心(Microsoft、Claude、Gemini 等通用) |
简而言之,Function Call 是 OpenAI 的“私有厨房”,MCP 是全世界都可以使用的“厨房标准化接口”。虽然 MCP 带来了灵活开放的生态,但它也引入了新的攻击面,例如:
- Tool Injection:恶意 MCP Server 提供诱导工具Prompt Injection:在指令层干扰 LLM 行为能力误用:如获取敏感文件、操控本地进程等
因此,微软正在将 MCP 接入 Windows 系统安全沙盒中(AI Foundry);OpenAI 和 Anthropic 也在构建 MCP 能力注册中心,并引入权限认证、可调用范围管理等机制。
项目 | 内容 |
---|---|
协议名称 | Model Context Protocol(MCP) |
发布者 | Anthropic,OpenAI,Microsoft 等联合 |
功能定位 | 统一 LLM 调用外部工具与数据源的接口协议 |
技术基础 | JSON-RPC 2.0 + JSON Schema |
关键组件 | MCP Server、MCP Client、Agent |
典型用途 | 文件管理、数据库操作、自动化助手、浏览器插件 |
替代方案 | OpenAI Function Calling(功能较弱) |
安全风险 | Prompt Injection、恶意 Server、权限失控等 |
1.3 参考
- OpenAI Agents SDK (MCP文档)Anthropic 官方 MCP 介绍Wikipedia: Model Context ProtocolarXiv 安全分析论文(2025)微软 Windows AI Foundry 计划
2 MCP Server 接口设计示例
基于最新 MCP 规范(截至 2025‑06‑18)
JSON-RPC
+ Streamable HTTP
是目前标准tools/list
和 tools/call
是基础接口tools/list
用于工具发现,tools/call
用于执行操作,是 MCP 必选标准Notifications
优化- 允许通过消息推送进度或取消命令,而非持续轮询
- MCP Server 作为资源服务器,不负责颁发令牌,而由独立 Authorization Server 提供 OAuth 2.1 认证,包括 RFC9728、RFC8707 标准项,客户端需传入 resource 参数,同时 Serv er 必须校验并拒绝不合格令牌。
- 对于资源,服务器可以声明能力是否支持 subscribe 和 listChanged,客户端可选择订阅变化。这使资源接口更加动态、响应性更强
2.1 MCP Manifest(/manifest
或 .well-known/mcp/manifest
)
MCP Manifest 是模型调用服务的“蓝图”,它不仅描述可用工具的参数结构,也包含调用行为提示、版本信息、资源结构等关键元信息。建议每个 MCP 服务通过 /manifest
或 .well-known/mcp/manifest
提供静态清单,以供模型在调用前理解其能力边界。
{ "schema_version": "2025-06-18", "name": "vrp-planner-mcp", "title": "VRP Planner", "description": "多约束多车辆智能调度规划引擎", "version": "1.2.0", "last_updated": "2025-07-14T03:00:00Z", "capabilities": { "callback": { "field": "callback_url", "methods": ["webhook"], "description": "支持异步任务完成后的 Webhook 通知" }, "notifications": { "supported": true, "events": ["progress", "complete", "cancelled"] }, "elicitation": {} }, "oauth": { "resource_metadata": "https://auth.example.com/.well-known/oauth-authorization-server", "resource_indicators_supported": true }, "tools": [ { "name": "create_scenario", "title": "Create Scenario", "description": "创建配送场景,包括车辆和工单", "inputSchema": { "$ref": "#/components/schemas/Scenario" }, "returns": { "type": "object", "properties": { "scenario_id": { "type": "string", "example": "scenario-123" } }, "required": ["scenario_id"] }, "annotations": { "readOnlyHint": false, "destructiveHint": false, "idempotentHint": false, "openWorldHint": false }, "_meta": { "example": { "name": "北京城配", "planning_date": "2025-07-15", "agents": [{ "id": "veh-1", "capacity": 100 }], "tickets": [{ "id": "t-1", "location": "LOC_A", "demand": 20 }] } } }, { "name": "solve_vrp", "title": "Solve VRP", "description": "提交 VRP 求解任务", "inputSchema": { "type": "object", "properties": { "scenario_id": { "type": "string", "example": "scenario-123" }, "solve_time": { "type": "string", "default": "PT30S", "pattern": "^PT\\d+S$", "example": "PT60S" }, "callback_url": { "type": "string", "format": "uri", "example": "https://example.com/webhook" } }, "required": ["scenario_id"] }, "returns": { "type": "object", "properties": { "job_id": { "type": "string", "example": "job-abc-123" }, "submitted_at": { "type": "string", "format": "date-time", "example": "2025-07-14T03:10:00Z" } }, "required": ["job_id", "submitted_at"] }, "annotations": { "readOnlyHint": false, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "callbackSupport": true } }, { "name": "query_vrp_status", "title": "Query VRP Status", "description": "查询 VRP 求解进度与状态", "inputSchema": { "type": "object", "properties": { "job_id": { "type": "string", "example": "job-abc-123" } }, "required": ["job_id"] }, "returns": { "type": "object", "properties": { "job_id": { "type": "string", "example": "job-abc-123" }, "status": { "type": "string", "enum": ["SOLVING", "FAILED", "COMPLETED"], "example": "SOLVING" }, "progress": { "type": "integer", "minimum": 0, "maximum": 100, "example": 45 } }, "required": ["job_id", "status", "progress"] }, "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false } }, { "name": "cancel_vrp_job", "title": "Cancel VRP Job", "description": "取消正在进行的 VRP 求解任务", "inputSchema": { "type": "object", "properties": { "job_id": { "type": "string", "example": "job-abc-123" } }, "required": ["job_id"] }, "returns": { "type": "object", "properties": { "cancelled": { "type": "boolean", "example": true }, "cancelled_at": { "type": "string", "format": "date-time", "example": "2025-07-14T03:12:00Z" } }, "required": ["cancelled", "cancelled_at"] }, "annotations": { "readOnlyHint": false, "destructiveHint": true, "idempotentHint": true, "openWorldHint": false } } ], "components": { "schemas": { "Scenario": { "type": "object", "properties": { "name": { "type": "string", "example": "北京城配" }, "planning_date": { "type": "string", "format": "date", "example": "2025-07-15" }, "agents": { "type": "array", "items": { "$ref": "#/components/schemas/Agent" } }, "tickets": { "type": "array", "items": { "$ref": "#/components/schemas/Ticket" } } }, "required": ["name", "planning_date", "agents", "tickets"] }, "Agent": { "type": "object", "properties": { "id": { "type": "string", "example": "veh-1" }, "capacity": { "type": "integer", "example": 100 } }, "required": ["id", "capacity"] }, "Ticket": { "type": "object", "properties": { "id": { "type": "string", "example": "t-1" }, "location": { "type": "string", "example": "LOC_A" }, "demand": { "type": "integer", "example": 20 } }, "required": ["id", "location", "demand"] } } }}
清单说明
schema_version
, version
, last_updated
用于 manifest 版本控制与缓存策略,推荐采用语义化版本机制。每个 MCP 工具需要用 JSON Schema 描述其输入参数结构和约束,工具定义包括唯一名称、描述和 inputSchema(参数模式)等- 使用 type, properties, required 等字段明确限定数据结构和数据类型。支持嵌套对象时,子属性也要各自定义 Schema。对于枚举值或特定格式,可利用 JSON Schema 的 enum、pattern 等约束。例如,一个分析CSV的工具参数可定义一个枚举列表:
"operations": { "type": "array", "items": { "enum": ["sum","average","count"] } }
。这指导模型只能提供允许的操作名称。提供字段描述或示例。在 MCP 工具定义中可以加入对参数的自然语言描述,帮助模型理解各参数含义。Anthropic 的实践建议在工具描述中包含使用示例,演示模型应如何提供参数。这有助于模型正确构造复杂输入。如果工具有返回值的预期结构,也应在 manifest 或文档中加以说明。例如 manifest 可用 "returns" 字段描述返回的数据类型,如返回一个对象数组。标准的输出格式使模型对调用结果有正确预期(例如知道返回的是文本还是 JSON 对象)。components/schemas
统一定义,以保持一致性与复用性。capabilities
capabilities.callback
声明服务端支持客户端提供 callback_url,用于异步通知任务完成或失败。适用于长任务(如 solve_vrp),当任务完成时,服务端会向客户端的 callback_url 发 POST 通知,无需客户端主动查询状态。
典型结构
"capabilities": { "callback": { "field": "callback_url", "methods": ["webhook"], "description": "支持异步任务完成后的 Webhook 通知" }}
MCP 支持异步调用,推荐使用 Webhook 模式回调模型:
- 指定 callback_url 字段;可对回调增加 HMAC 签名字段或 token 以保证安全;MCP 协议统一推荐在 callback_url 中发送 job_id + status 等最小字段,但每个工具的回调请求体可以基于它的上下文进行扩展定义
- 可以在 manifest 的每个 tool 下增加 _meta.callbackPayloadSchema 或 callback_payload 字段,来定义callback的请求体数据结构。
capabilities.notifications
声明服务端支持通过 Streamable HTTP + Notifications 向客户端推送事件(例如:进度更新、完成通知、取消确认),客户端实时接收,无需轮询。
典型结构
"capabilities": { "notifications": { "supported": true, "events": ["progress", "complete", "cancelled"] }}
工具注解(Tool Annotations)
**工具注解(Tool Annotations)**是对每个工具行为的元信息提示,帮助 Client 和 LLM 更安全、高效地使用这些工具:
- 安全性提示:客户端在调用此类工具前可提示用户确认,避免误操作。重试安全:当网络中断或超时,Client 可知道是否应该重试该调用;
假设有一个工具 delete_file
:
{ "name": "delete_file", "annotations": { "readOnlyHint": false, "destructiveHint": true, "idempotentHint": true, "openWorldHint": false }}
Hint 名称 | 类型 | 含义说明 | 使用场景示例 |
---|---|---|---|
destructiveHint | boolean | 是否会对系统产生破坏性修改,如删除、修改、重命名、发起变更等操作。 | 删除任务、取消订单、修改配置等 |
idempotentHint | boolean | 幂等性提示:重复调用不会改变最终结果,可安全重试。 | 删除资源(已删也视为成功)、查询状态等 |
readOnlyHint | boolean | 是否为只读操作,即不对系统状态产生任何更改。 | 查询状态、获取详情、列表获取等 |
openWorldHint | boolean | 是否访问开放系统或外部世界,如互联网或跨系统调用,涉及安全边界时应标记为 true 。 | 访问外部 API、调用外部模型、发送通知等 |
callbackSupport | boolean? | (可选)是否支持异步回调机制(如 webhook),便于客户端获知操作完成。 | 异步求解任务、模型执行任务等 |
注:
- 幂等工具可安全重试,非幂等工具需要谨慎,以免重复造成副作用,若一个工具是“创建用户”的工具,多次调用会产生多个用户账户,此行为非幂等,应设置
idempotentHint: false
。- 若涉及外部系统权限、调用、安全敏感时设为
openWorldHint: true
所有 MCP 工具函数接口都应根据行为意图明确标注这些 Hint,有助于 UI 层、代理调度层、权限策略系统做出合适决策。OAuth 授权配置
Manifest 中需包含 OAuth 授权相关元数据,如:
"oauth": { "resource_metadata": "https://auth.example.com/.well-known/oauth-authorization-server", "resource_indicators_supported": true}
授权流程
- 客户端访问受保护 endpoint 时,服务返回 HTTP 401 并带有 WWW-Authenticate header,指向 OAuth 元数据 URL。客户端根据 RFC9728 和 RFC8414,通过 .well-known/oauth-authorization-server 获取授权服务器地址、token endpoint 等信息。通过预定义方式获取access token,客户端在后续请求中加入
Authorization: Bearer <token>
。服务端验证 token 的 issuer、scope、有效期等。根据 RFC7591,客户端首次连接可自动注册获取 client_id/secret 。具体OAuth配置推荐使用Keycloak。
2.2 MCP JSON‑RPC 接口
tools/list
(获取工具清单)
请求:
{ "jsonrpc":"2.0","id":"1","method":"tools/list","params":null }
响应:
{ "jsonrpc":"2.0","id":"1","result": [/* manifest.tools 的内容 */] }
客户端可使用该接口动态发现工具,构建调用选项。
tools/call
(调用工具执行)
请求样例:
{ "jsonrpc":"2.0", "id":"2", "method":"tools/call", "params": { "name": "solve_vrp", "arguments": { "scenario_id":"uuid-abc","solve_time":"PT60S" } }}
method 字段表明调用工具,服务端据此找到对应工具并执行。
响应(正常):
{ "jsonrpc":"2.0","id":"2","result": { "job_id":"job-001","submitted_at":"2025-07-13T10:05:00Z" } }
错误处理结构
推荐将错误编号、类型描述和上下文信息统一返回
响应(错误):
{ "jsonrpc":"2.0", "id":"2", "error": { "code": 4002, "type": "MissingParameter", "message": "参数 scenario_id 缺失", "traceId": "abc-123" }}
任务取消
请求
{ "jsonrpc": "2.0", "id": "3", "method": "tools/call", "params": { "name": "cancel_vrp_job", "arguments": { "job_id": "job-001" } }}
同步响应
{ "jsonrpc": "2.0", "id": "3", "result": { "cancelled": true, "cancelled_at": "2025-07-13T10:07:00Z" }}
随后服务端也会通过 notifications/cancelled 主动推送事件
Notifications(事件推送,取代持续轮询)
对于可能长时间运行的工具操作,应考虑提供状态查询和取消的机制:
- 客户端建议在发起调用后,同时开启 SSE 监听,以实时接收进度/完成/取消等事件;事件推送采用 JSON‑RPC 通知消息,无需
id
字段;事件类型由 method
指定,如 notifications/progress
。进度推送:
{ "jsonrpc": "2.0", "method": "notifications/progress", "params": { "job_id": "job-001", "progress": 80 }}
完成推送:
{ "jsonrpc": "2.0", "method": "notifications/complete", "params": { "job_id": "job-001", "result": { /* 求解结果数据 */ } }}
取消推送:
{ "jsonrpc": "2.0", "method": "notifications/cancelled", "params": { "job_id": "job-001", "cancelled_at": "2025-07-13T10:07:00Z" }}
推荐工作流
- 客户端 POST
tools/call
启动作业,并开启 SSE 通道(或通过 Streamable HTTP 持续接收事件)。服务器通过 notifications/progress
、notifications/complete
、notifications/cancelled
等推送任务实时状态,客户端无需主动轮询 query_vrp_status
,只在断线或异常时可手动查询。取消任务,依然通过 tools/call
+ cancel_vrp_job
工具实现。2.3 资源接口
根据 MCP 2025‑06‑18 最新规范,结合 Notifications 与 Streamable HTTP 推荐实践,对资源接口与设计要点进行了调整和补充。最终优化内容如下:
MCP 资源(Resource)代表服务可提供的结构化数据内容,包括文件、API 响应、数据库记录等,均以唯一 URI 或 URI 模板标识。Manifest 中可统一声明资源类型及其 JSON Schema。
资源类型与 URI 命名
- 静态资源:如
"uri": "file:///var/reports/plan-2025-06.pdf"
动态资源/模板:如 "uriTemplate": "scenario://{scenario_id}/result"
复合/分页资源:如 "uriTemplate": "jobs://vrp/status/{status}?page={page}&size={size}"
资源 URI 应规范命名,例如:
file://
本地静态文件scenario://{id}/result
动态数据视图logs://vrp/{date}
时序日志所有资源均应采用清晰的协议前缀(如 file://
、db://
、logs://
),便于客户端识别来源和处理方式。若资源涉及敏感字段,manifest 中可使用 "x-sensitive-fields": ["user_id", "price"]
提示客户端脱敏或限制暴露。
资源列表接口
resources/list
(获取资源清单)
请求:
{ "jsonrpc": "2.0", "id": "5", "method": "resources/list", "params": null }
响应:
{ "jsonrpc": "2.0", "id": "5", "result": [ { "uri": "file:///var/reports/plan-2025-06.pdf", "name": "6月调度执行报告", "mimeType": "application/pdf", "size": 2183344 }, { "uriTemplate": "logs://vrp/{date}", "name": "VRP 系统调度日志", "mimeType": "text/plain" } // ...更多资源 ]}
推荐每个资源项包含:
uri
/uriTemplate
、name
、mimeType
、size
(如可用)、description
等元数据。Manifest 可进一步通过 JSON Schema 规范资源结构。
资源读取接口
resources/read
(读取资源内容)
请求:
{ "jsonrpc": "2.0", "id": "6", "method": "resources/read", "params": { "uri": "logs://vrp/2025-07-13" }}
响应:
{ "jsonrpc": "2.0", "id": "6", "result": { "content": "...2025-07-13 的日志内容...", "mimeType": "text/plain" }}
文本型内容用
content
字段返回,二进制内容(如图片、Excel等)建议以 base64 编码置于blob
字段,并指明mimeType
。复合资源可返回数组,如目录下多个文件。
2.4 调用生命周期
sequenceDiagram autonumber participant 智能体 Agent participant MCP服务端 participant SSE通道 participant WebHook接口(callback_url) %% 工具发现与调用 智能体 Agent->>MCP服务端: tools/list → 获取工具清单 MCP服务端-->>智能体 Agent: 返回 tools + inputSchema 智能体 Agent->>MCP服务端: tools/call → 提交 solve_vrp 调用(附带 callback_url) MCP服务端-->>智能体 Agent: 返回 job_id:"job-001",任务提交成功 %% 主流程:使用 SSE 实时获取进度 智能体 Agent->>SSE通道: 建立 SSE 通道,监听任务进度 SSE通道-->>智能体 Agent: notifications/progress → 任务进度 20% SSE通道-->>智能体 Agent: notifications/progress → 任务进度 80% SSE通道-->>智能体 Agent: notifications/complete → 任务完成结果 %% 可选分支 A:使用 Webhook 接收通知 MCP服务端-->>WebHook接口(callback_url): notifications/complete → POST 最终结果 %% 可选分支 B:Agent 主动轮询获取结果 智能体 Agent->>MCP服务端: tools/call → query_status 查询任务状态 MCP服务端-->>智能体 Agent: 返回任务完成状态 + 结果数据
2.5 实践建议
- 核心设计原则
- Manifest 即协议契约:所有工具、资源、Schema 结构必须在 Manifest 中显式声明,便于客户端理解和自动调用。结构化 JSON + 明确 Schema:每个工具的输入
inputSchema
与返回结果结构应清晰、可验证,支持前端校验与自动补全。保持接口幂等与无状态:所有调用遵循 JSON-RPC 标准,接口无状态、返回结构统一,便于扩展与重试。安全提示通过 annotations 明确:标注 readOnlyHint
、destructiveHint
等属性,帮助模型/用户识别风险操作。- 支持 callback_url 回调:Manifest 中声明
capabilities.callbacks
,工具参数允许指定异步通知地址。推荐集成 SSE 通道:支持如 notifications/progress
、notifications/complete
等实时事件,取代轮询,提升体验。- 使用 URI 与 uriTemplate:静态/动态/分页资源统一建模,支持结构化读取。可结合事件推送资源变更:如
resources/changed
事件,让客户端感知数据刷新。2.6 参考
- Secoda 的 MCP manifest 最佳实践Model Context Protocol(MCP)官方文档:Tools 定义结构Anthropic:Model Context Protocol 官方介绍与应用场景工作流:Secoda 接入 MCP 的说明OpenAI Agents SDK 中的 MCP 文档Wikipedia:Model Context Protocol 背景与标准内容Deep Dive into Public MCP Servers (with FastAPI & GitHub MCP Examples)TaskManager MCP serverMCP: CancellationMCP: ProgressMCP: SpecificationThe Model Context Protocol Explained (Medium)MCP: Tools Best PracticeAn under the hood look at how Pieces implemented an MCP serverMCP: Resources
3 动态生成满足类型约束的输入数据
MCP 的一大优势在于模型能够根据 manifest 自动构造正确格式的工具输入。为实现这一点,必须确保类型约束明确且上下文提示充分,使 LLM 在决策调用时能够“填空作答”,动态生成合法的 JSON 参数。
3.1 Schema 驱动输入生成
当客户端(LLM 主机)获取 MCP 服务的 manifest 后,会解析出各工具的参数Schema。在对话过程中,如果模型决定使用某工具,它会按照 Schema 组织参数。
- 例如,manifest 指定参数
maxResults
是整数且默认为10,模型就会遵守此约束提供一个数字(除非有特定需要改变默认值)。OpenAI 新推出的函数调用机制正体现了这一思路——开发者为函数提供 JSON Schema,模型会产出匹配该Schema的 JSON。这种自动约束生成减少了出错概率。3.2 复杂对象的生成
当工具参数本身是复杂结构(如 Scenario 场景对象,包含嵌套字段),需要模型一次性构造嵌套 JSON。为辅助模型:
- 逐层描述:在 Schema 中对每个子字段都提供类型和含义说明。例如 Scenario 对象也许有
context
(字符串)和 steps
(步骤数组)等字段,就应在Schema里详细定义这些子元素的类型和要求。模型会依据这些定义填充每个字段,保证完整性。提供示例:如前述,工具描述中加入示例调用最为直接。如果模型看到例子里的 Scenario JSON,它更容易模仿格式输出。利用参数描述:MCP 协议允许在参数 Schema 之外,还可在工具manifest里为每个参数写人类可读的说明。例如 Pieces MCP 服务的一个工具参数 time_ranges
带有说明,指导模型提供带 from
、to
、phrase
三个属性的数组。模型据此提取用户问题中的时间范围,生成正确结构的 JSON。例如用户问“我昨天在做什么?”,模型会按照描述将“昨天”解析成相应的 UTC 起止时间并填入 JSON。这种提示式约束极大提高了复杂输入的正确率。3.3 传统业务数据映射
企业的数据分散在多张表、多个系统里,如果不能方便地把这些数据整理成标准的 JSON 格式,LLM 智能体就无法顺利调用算法和工具。只有把数据结构统一好,智能体才能理解业务、自动执行任务,让企业的数据真正用起来、发挥出更大的价值。在这里提出一种五步对接方法,具体如下:
A 读取 MCP manifest 的 inputSchema
- 目的: 明确工具所需的 JSON 结构与类型约束,做到数据标准一目了然。关键点: manifest 的 inputSchema 应作为“源真理”(single source of truth)驱动后续所有映射和校验环节。建议: 若 manifest 有变更,应自动刷新本地 Schema 缓存。
B 导出业务数据表的记录(JSON格式)
目的: 从现有数据库、API 或中台系统直接提取所需业务事实。
关键点:
- 关注导出字段、命名、嵌套与原有业务语义。尽量与 inputSchema 做初步字段对齐,减少后续处理难度。
建议: 推荐以“单记录单 JSON”或“批量 JSON 数组”两种模式导出。
C 设计提示词,引导 LLM 自动生成转换代码
目的: 利用大模型“推断能力”自动补齐字段映射、重命名、结构变换等代码(如 Python)。
关键点:
- 提示词需清楚描述原数据格式、目标 Schema,以及需处理的特殊字段/缺省值/类型转换。结合导出的业务数据,采用 few-shot(少样本)方式举例输入/输出,提升 LLM 生成准确率。
建议:
- 先人工 review LLM 生成的脚本,保证数据安全与业务合规。若常用转换可沉淀为通用 mapping 函数或脚本模板。
D 测试用例驱动 Schema 校验与逻辑校验
- 目的: 保证最终 JSON 输入既合规又符合业务逻辑,避免后续工具调用异常。关键点:
- 用 JSON Schema 自动校验格式和必填字段。逻辑校验可自定义(如:ID 唯一性、数量大于零、时间戳合法等)。
- 每次映射后都做 schema 校验,并输出详细报错定位。可以持续收集失败样例,用于优化 mapping/prompt 设计。
E 脚本的集成或 Function 化,为 LLM/Agent 提供标准化业务数据
- 目的: 把数据转换能力封装为可复用的服务/脚本/Function(如 n8n Function、微服务、Serverless 函数等),为上游 LLM/Agent 调用提供标准入口。关键点:
- 应保证接口语义清晰、幂等、输出稳定。支持输入参数灵活指定,如按业务主键、批量处理等。
- 可结合 CI/CD,对转换脚本/Function 持续回归测试与自动化部署。若有权限要求,需同步集成权限/审计控制。
实践建议
最大限度利用 LLM 自动化能力,减少人工编码与维护负担。
- 既适应 Schema 变化,也能动态适配不同业务系统和表结构。全流程测试与校验环节保障安全与正确性。最终形态为“标准化 Function/服务”,高度可扩展与集成。
需要关注的风险
- LLM 生成代码需严格测试和审计,避免不符合业务规则或隐含安全隐患。Schema 变更需自动同步,否则会引入数据格式漂移问题。业务逻辑校验要分层设计,测试用例的维护非常重要。
3.4 验证与纠错
服务端在接收到模型生成的输入后,应对其进行验证,确保满足 Schema 约定。可以借助 JSON Schema 校验库或静态类型工具(如 Pydantic)进行检查,在发现缺失字段或类型不符时返回结构化错误,让模型明白哪里不合规。模型通常会依据错误信息重试,并修正输出以满足约束。因此,清晰的错误反馈也是动态生成正确输入的重要环节。
此外,模型可能会依赖上下文动态调整输入。例如某些工具manifest是动态的,只有满足一定条件才出现额外参数。模型需要先通过 tools/list
获取最新Schema,再生成输入。这要求客户端实现上每次对话开始或 manifest 有变动时都刷新模型对工具的认知。Anthropic Claude 等实现支持 notifications/tools/list_changed
来通知工具列表变化,模型据此更新调用策略。
总结来说,让模型动态地产生合规输入的关键在于:完善的模式定义和充分的语义提示。通过 MCP manifest,将输入输出格式精确定义,并辅以描述和示例,LLM 就能在推理中自动拟合这些约束,构造出满足类型要求的 JSON 对象。这种能力使智能代理能够安全地调用复杂操作(如规划场景Scenario的创建等)而不需要硬编码每种接口格式,大大提高了系统的灵活性和健壮性。
3.5 参考
- OpenAI Cookbook: Schema-guided Data Transformationjsonschema Python 校验Model Context Protocol 官方文档n8n Function 节点文档An under the hood look at how Pieces implemented an MCP serverOpenAI's Agents SDK and Anthropic's Model Context Protocol (MCP)The Model Context Protocol Explained
4 降低 LLM Token 消耗的策略
在集成 MCP 工具时,需要密切关注上下文 Token的消耗,因为每增加一个工具及其说明,都会占用模型的提示窗口,进而增加费用和延迟。
按需加载工具:尽可能避免在不需要时向模型提供大量工具信息。当注册了 MCP 服务后,客户端通常会在每次对话请求中附带所有工具描述给模型。这意味着即便工具未被使用,其名称、说明、参数列表都会占用提示tokens。因此应提供机制让用户或系统启用/停用某些 MCP 工具。例如,在 Cursor 等应用中,如果当前任务不需要 Pieces 的长时记忆检索,就暂时禁用该 MCP 服务,以免无谓地增加 token 开销。只在需要时启用工具,能直接减少上下文长度。
精简工具清单:控制提供给模型的工具数量。每多一个可选工具,模型推理时就要考虑更多选项并处理相应描述,消耗更多token。对于从现有 API 自动生成的大量 MCP 工具,应筛除不必要的部分,保留最有用的操作。例如,如果通过 OpenAPI 规范自动生成了几十个工具,可以只保留其中模型可能用到的几个关键操作。工具越少,模型决策越高效,且提示中的无关内容也减少。每个保留的工具都应该有清晰的使用场景说明,以便模型准确判断何时调用。
过滤无关数据:当工具调用会返回大量数据时,服务端应对返回内容做处理,减少传给模型的冗余信息。例如,一个工具可能封装第三方API,返回很大的 JSON,其中只有部分字段对模型任务有用。此时 MCP 服务可对响应进行裁剪或汇总,只返回相关字段或更小的摘要数据给模型。实践案例表明,对API响应JSON过滤无关部分,可使提示tokens减少90%以上。同理,对于资源读取,如果文件过大,可以只返回片段或增加查询参数限制大小。总之,让进入模型上下文的数据尽量精简,既降低成本又提升模型处理效率。
缓存和复用:利用缓存策略避免重复消费 tokens。对于重复出现的提示或响应,可以实现:
- 提示缓存(Prompt Caching):如果相同的请求上下文已经向模型询问过,并得到结果,可缓存该模型回答,下次遇到类似请求直接复用结果而非再次调用模型。响应缓存:类似地,对于相同参数的工具调用结果,可以缓存起来,下次模型再调用同样的 MCP 工具时直接返回缓存内容,避免再次耗费模型 token。语义缓存:对提问或工具请求做语义哈希,如果新请求在语义上与之前类似,则复用以前结果。
需要注意,缓存应与实时性需求权衡,并保持缓存内容不过期失效。同时,随着增加工具或API上下文,有时即使缓存也可能增加一定提示开销,因此缓存策略需结合实际流量和模型成本综合考虑。
监控与优化:部署LLM 可观测性工具监控每次调用的 token 使用情况,以发现瓶颈。观察哪些工具描述占用大量上下文、哪些响应文本冗长,从而有针对性地优化。例如,如果发现某一类工具的描述过长且很少被用,可以尝试简化描述或拆分工具集。在大规模代理应用中,引入 AI 网关可以帮助监控和限流,通过集中路由和缓存来降低总体token消耗。定期审计模型对话日志,筛查无效的长回答或重复对话,也有助于识别削减token的机会。
优化上下文窗口利用:MCP 的初衷之一就是更高效地使用模型上下文,以减少无效token。开发者应充分利用这一优势:把大量背景知识从提示中拿掉,改由工具按需提供。例如,与其在每次对话中都填充大段说明,不如将说明作为资源或提示模板,在需要时模型通过调用获取。这种延迟提供信息的策略确保模型只在必要时才“看到”该信息,从而节省了平时的token占用。同样,如果需要模型多步推理,可考虑让模型调用自身的采样功能(MCP sampling特性)而非一次性输出所有步骤,也可以一定程度降低每步的提示长度。
综合以上策略,核心在于减少模型上下文中无效或次要的信息。每一次Agent-LLM交互都会消耗token并产生成本和时延,所以应努力让每个token都“物有所值”。通过精简工具和数据、聪明地调度何时提供何种信息,以及技术手段如缓存和监控,开发者可以将LLM集成的开销降到最低。正如经验所示,一个适度提供精确信息的MCP集成,能以更低的token成本获得更高质量的结果。
4.1 参考
5 接口重构
将传统微服务功能暴露为 MCP 工具,有时需要调整接口设计,以符合 MCP 的统一规范和 JSON Schema 要求。这种适配如果逐个手工改造,工作量和风险都很高。例如,一个老系统可能有众多 REST API,各自返回格式不同,也缺少机器可读的契约说明。那么要把它们纳入 MCP,就需为每个API编写 Schema、提供描述,并统一通过 manifest 公布——相当于对接口进行重构和数据格式转换。这被视为MCP落地的一大挑战之一。
5.1 接口重构是否必要
好消息是,未必需要对每个微服务API大动干戈。业界已经出现多种MCP 适配层和自动化工具,帮助将现有接口快速包装为 MCP 工具,尽量减少人工重构:
API 网关适配: 如华为云提出的方案,在微服务网关层进行一次性的协议转换。网关拦截内部服务的 OpenAPI/Swagger 描述或服务注册信息,自动生成 MCP 所需的manifest和工具模式。这样企业无需修改内部各微服务,只需在网关输出一个统一的 MCP Server 接口。该网关会承担把 MCP 请求转换为内部 REST 请求的工作,并把内部响应转回 MCP 格式。这一“一次适配,全局受益”的方法显著降低了改造成本。
契约导出与描述生成: 除了纯手工编写 manifest,现在有工具能自动提取服务的接口契约并生成 Schema 描述。例如,一些框架可扫描代码或注解生成 JSON Schema,可以利用 AI 自动生成工具描述的尝试——根据接口定义和实现代码,预填描述文本,减轻人工编写负担。这种人机协同方式确保描述准确一致,同时减少了人工成本。
开源适配库: 社区已有若干 MCP 工具库支持从现有应用直接导出工具。例如 FastMCP 提供了 from_fastapi()
和 from_openapi()
等方法,可将已有 FastAPI 应用或 OpenAPI 文档直接转换成 MCP Server,实现自动包装。OpenAI 的 Agents SDK 也支持直接用 Python 函数定义工具,并自动根据函数签名生成 JSON Schema——这对于新开发的服务非常便利,开发者写好函数,Schema 和 manifest 便可由框架生成。还有像 LangChain 等代理框架也在集成 MCP 客户端/服务端,以简化适配过程。
因此,一般不建议为适配 MCP 而彻底推倒重写现有接口。相反,可以增设一层 MCP 接口或使用工具将它们包装起来。在保持原有微服务不变的情况下,通过 MCP Server 将其功能暴露给 LLM。这避免了高昂的系统重构代价和潜在风险。
Quarkus 提供的 MCP Server 扩展
- Quarkus 提供了
quarkus-mcp-server-stdio
和 quarkus-mcp-server-sse
扩展,支持标准的 stdio 和 HTTP/SSE 传输协议,还引入了对 Streamable HTTP 的支持,是 Java 生态中使用最便捷的 MCP Server SDK。使用方式简单:通过 CDI 注解 @Tool
, @Resource
, @Prompt
宣告 server capabilities,同时 Quarkus 自动构建工具清单与 JSON-RPC 接口,实现声明式注册和运行时处理。安全认证支持
- Quarkus MCP Server 扩展支持通过 Quarkus OIDC(如 Keycloak、GitHub OAuth2)为 MCP Server 端点和工具调用启用安全认证。使用
@Authenticated
注解标示工具方法,仅允许认证用户访问。客户端(如 MCP Inspector 或 curl)可以通过 Bearer Token 调用工具。Quarkus MCP Client 也支持将用户的权限令牌传递给 MCP Server 实现安全调用 。支持多种通信形式
- 支持 stdio 子进程模式、HTTP/SSE(现代流式 HTTP via Streamable HTTP)两种方式,适应控制台或云原生场景.Quarkus 1.2.0+ 为首个支持 Streamable HTTP 的 Java SDK,大幅提升实时通信能力。
快速上手示例
<dependency> <groupId>io.quarkiverse.mcp</groupId> <artifactId>quarkus-mcp-server-sse</artifactId> <version>1.2.0</version></dependency>
@ApplicationScopedpublic class ServerFeatures { @Tool(description = "Convert text to lowercase") String toLower(@ToolArg(description="Text") String input) { return input.toLowerCase(); } @Resource(uri="file:///data/config.json") BlobResourceContents config() { /* load file */ }}
启动 Quarkus 应用后,它会自动:
- 生成 manifest 清单并暴露 /mcp(Streamable HTTP)或 /mcp/sse(SSE)端点MCP 客户端(如 Claude、LangChain4j、MCP Inspector)可用 JSON‑RPC 协议自动识别工具、调用执行。
5.2 何时需要重构
然而,在某些情况下适度的接口重构是值得的:
- 现有接口设计对模型并不友好(比如需要多次往返才能完成一项任务,或请求/响应格式非常复杂),那么优化接口以更贴近“工具”概念可能提高 Agent 调用效率。
- 例如,将多个细粒度API整合为一个更高阶的 MCP 工具,模型即可一次调用完成整个操作,而不必连环调用多个子步骤。
理想情况下,通过 MCP,我们希望实现工具接口统一且与现有系统解耦。完全重构虽非必须,但一定程度的契约梳理不可避免。建议的路径是:
- 先利用自动化手段快速生成初版 manifest 和 Schema然后由开发者调整优化(如删除无用端点、补充示例、细化描述)。这样既避免了全手工重构,又保证了生成的 MCP 接口高质量且贴合业务需求。
正如 MCP 标准所强调的,清单化的工具接口使不同语言、平台的系统都能无缝衔接,大幅减少“N对M”集成的负担。通过聪明地利用现有资源并适度演进接口设计,我们无需大规模重写代码,就能让智能规划引擎畅通无阻地调用各种微服务,实现AI时代的微服务生态升级。
5.3 参考
- MCP与华为云CSE珠联璧合,打造AI时代微服务生态引擎fastmcpQuarkus MCP ServerModel Context Protocol Servers in QuarkusImplementing a MCP server in QuarkusIntroducing Model Context Protocol servers project
6 结语
MCP 协议为构建“模型可调用世界”奠定了基础,它规范了工具、资源、任务执行与异步反馈等关键组件,是实现 Agent-to-System 协同的核心协议之一。但 MCP 聚焦于“操作层”的接口设计,而在真正面向用户的场景中,还需与可视化交互、用户意图理解、流程指引等机制结合。
因此,我们正在探索另一项关键协议 —— AG‑UI 协议,它旨在为 Agent 提供画布式、组件化的 UI 指令与数据绑定机制,使 LLM 不仅能调用工具,还能动态驱动 UI,让“人机共创”成为现实。
下一篇文章将全面介绍 AG‑UI 协议设计与实现,敬请期待。