基于最新 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 的三大核心组成
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 发现 +调用即可。
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 Protocol
- arXiv 安全分析论文(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
优化- 允许通过消息推送进度或取消命令,而非持续轮询
- 授权机制强制外置 OAuth
- MCP Server 作为资源服务器,不负责颁发令牌,而由独立 Authorization Server 提供 OAuth 2.1 认证,包括 RFC9728、RFC8707 标准项,客户端需传入 resource 参数,同时 Serv er 必须校验并拒绝不合格令牌。
- Resources 功能更完善
- 对于资源,服务器可以声明能力是否支持 subscribe 和 listChanged,客户端可选择订阅变化。这使资源接口更加动态、响应性更强
2.1 MCP Manifest(/manifest
或 .well-known/mcp/manifest
)
MCP Manifest 是模型调用服务的"蓝图",它不仅描述可用工具的参数结构,也包含调用行为提示、版本信息、资源结构等关键元信息。建议每个 MCP 服务通过 /manifest
或 .well-known/mcp/manifest
提供静态清单,以供模型在调用前理解其能力边界。
json
{
"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 通知,无需客户端主动查询状态。
典型结构
json
"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 向客户端推送事件(例如:进度更新、完成通知、取消确认),客户端实时接收,无需轮询。
典型结构
json
"capabilities": {
"notifications": {
"supported": true,
"events": ["progress", "complete", "cancelled"]
}
}
工具注解(Tool Annotations)
**工具注解(Tool Annotations)**是对每个工具行为的元信息提示,帮助 Client 和 LLM 更安全、高效地使用这些工具:
- 安全性提示:客户端在调用此类工具前可提示用户确认,避免误操作。
- 重试安全:当网络中断或超时,Client 可知道是否应该重试该调用;
假设有一个工具 delete_file
:
json
{
"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 授权相关元数据,如:
json
"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
(获取工具清单)
请求:
json
{ "jsonrpc":"2.0","id":"1","method":"tools/list","params":null }
响应:
json
{ "jsonrpc":"2.0","id":"1","result": [/* manifest.tools 的内容 */] }
客户端可使用该接口动态发现工具,构建调用选项。
tools/call
(调用工具执行)
请求样例:
json
{
"jsonrpc":"2.0",
"id":"2",
"method":"tools/call",
"params": {
"name": "solve_vrp",
"arguments": { "scenario_id":"uuid-abc","solve_time":"PT60S" }
}
}
method 字段表明调用工具,服务端据此找到对应工具并执行。
响应(正常):
json
{ "jsonrpc":"2.0","id":"2","result": { "job_id":"job-001","submitted_at":"2025-07-13T10:05:00Z" } }
错误处理结构
推荐将错误编号、类型描述和上下文信息统一返回
响应(错误):
json
{
"jsonrpc":"2.0",
"id":"2",
"error": {
"code": 4002,
"type": "MissingParameter",
"message": "参数 scenario_id 缺失",
"traceId": "abc-123"
}
}
任务取消
请求
json
{
"jsonrpc": "2.0",
"id": "3",
"method": "tools/call",
"params": { "name": "cancel_vrp_job", "arguments": { "job_id": "job-001" } }
}
同步响应
json
{
"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
。
进度推送:
json
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": { "job_id": "job-001", "progress": 80 }
}
完成推送:
json
{
"jsonrpc": "2.0",
"method": "notifications/complete",
"params": { "job_id": "job-001", "result": { /* 求解结果数据 */ } }
}
取消推送:
json
{
"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
(获取资源清单)
请求:
json
{ "jsonrpc": "2.0", "id": "5", "method": "resources/list", "params": null }
响应:
json
{
"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
(读取资源内容)
请求:
json
{
"jsonrpc": "2.0",
"id": "6",
"method": "resources/read",
"params": { "uri": "logs://vrp/2025-07-13" }
}
响应:
json
{
"jsonrpc": "2.0",
"id": "6",
"result": {
"content": "...2025-07-13 的日志内容...",
"mimeType": "text/plain"
}
}
文本型内容用
content
字段返回,二进制内容(如图片、Excel等)建议以 base64 编码置于blob
字段,并指明mimeType
。 复合资源可返回数组,如目录下多个文件。
2.4 调用生命周期
2.5 实践建议
- 核心设计原则
- Manifest 即协议契约:所有工具、资源、Schema 结构必须在 Manifest 中显式声明,便于客户端理解和自动调用。
- 结构化 JSON + 明确 Schema :每个工具的输入
inputSchema
与返回结果结构应清晰、可验证,支持前端校验与自动补全。 - 保持接口幂等与无状态:所有调用遵循 JSON-RPC 标准,接口无状态、返回结构统一,便于扩展与重试。
- 安全提示通过 annotations 明确 :标注
readOnlyHint
、destructiveHint
等属性,帮助模型/用户识别风险操作。
- 异步任务与事件推送
- 支持 callback_url 回调 :Manifest 中声明
capabilities.callbacks
,工具参数允许指定异步通知地址。 - 推荐集成 SSE 通道 :支持如
notifications/progress
、notifications/complete
等实时事件,取代轮询,提升体验。
- 支持 callback_url 回调 :Manifest 中声明
- 资源访问建议
- 使用 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 server
- MCP: Cancellation
- MCP: Progress
- MCP: Specification
- The Model Context Protocol Explained (Medium)
- MCP: Tools Best Practice
- An under the hood look at how Pieces implemented an MCP server
- MCP: 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 Transformation
- jsonschema Python 校验
- Model Context Protocol 官方文档
- n8n Function 节点文档
- An under the hood look at how Pieces implemented an MCP server
- OpenAI'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,大幅提升实时通信能力。
快速上手示例
xml
<dependency>
<groupId>io.quarkiverse.mcp</groupId>
<artifactId>quarkus-mcp-server-sse</artifactId>
<version>1.2.0</version>
</dependency>
java
@ApplicationScoped
public 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 工具,模型即可一次调用完成整个操作,而不必连环调用多个子步骤。
- 这种重构可以看作针对 LLM 用例的接口升级,使之语义化和原子化,更易被模型正确使用。
- 如果旧接口缺乏安全控制,也可借机在 MCP 层引入权限校验和输入验证,从而增强整体安全。
理想情况下,通过 MCP,我们希望实现工具接口统一 且与现有系统解耦 。完全重构虽非必须,但一定程度的契约梳理不可避免。建议的路径是:
- 先利用自动化手段快速生成初版 manifest 和 Schema
- 然后由开发者调整优化(如删除无用端点、补充示例、细化描述)。 这样既避免了全手工重构,又保证了生成的 MCP 接口高质量且贴合业务需求。
正如 MCP 标准所强调的,清单化的工具接口使不同语言、平台的系统都能无缝衔接,大幅减少"N对M"集成的负担。通过聪明地利用现有资源并适度演进接口设计,我们无需大规模重写代码,就能让智能规划引擎畅通无阻地调用各种微服务,实现AI时代的微服务生态升级。
5.3 参考
- MCP与华为云CSE珠联璧合,打造AI时代微服务生态引擎
- fastmcp
- Quarkus MCP Server
- Model Context Protocol Servers in Quarkus
- Implementing a MCP server in Quarkus
- Introducing Model Context Protocol servers project
6 结语
MCP 协议为构建"模型可调用世界"奠定了基础,它规范了工具、资源、任务执行与异步反馈等关键组件,是实现 Agent-to-System 协同的核心协议之一。但 MCP 聚焦于"操作层"的接口设计,而在真正面向用户的场景中,还需与可视化交互、用户意图理解、流程指引等机制结合。
因此,我们正在探索另一项关键协议 ------ AG‑UI 协议,它旨在为 Agent 提供画布式、组件化的 UI 指令与数据绑定机制,使 LLM 不仅能调用工具,还能动态驱动 UI,让"人机共创"成为现实。
下一篇文章将全面介绍 AG‑UI 协议设计与实现,敬请期待。