Agent Systems / Tool Protocol
MCP 与工具调用:把模型输出约束成可验证的外部动作
MCP 的价值不是“让模型更聪明”,而是给模型和工具之间建立可发现、可校验、可记录的协议边界。
Mechanism Lab
动画:MCP 如何把工具调用变成协议合约
动画展示 host/model 发现 MCP server 的 tools/resources/prompts,生成 tool call,经 schema gate 校验后执行,再把结构化结果或错误返回上下文。
Step 1 / 5
Discover
Host 通过 MCP client 发现 server 暴露的 tools、resources 和 prompts。
discover(server)Animation Control
Reduced-motion users receive the same step states without continuous motion.
01 / 直觉
核心直觉
没有工具协议时,模型只能生成自由文本;有工具协议时,模型可以选择被声明过的 tool,并按 schema 生成参数。
MCP 把 host、client、server、tools、resources 和 prompts 分开:模型所在应用不需要硬编码每个工具,只需发现服务端暴露的能力。
工具调用的关键是 contract:名称、描述、输入 schema、权限、执行环境、输出格式和错误语义都必须明确。
对实证研究而言,MCP 让 Agent 能读取文件、查数据库、运行统计脚本、生成表格,但每一步都留下结构化 trace。
02 / 数学
工具调用的协议合约与状态语义
01 / 能力发现
Host 通过 MCP client 连接 server,读取可用 tools/resources/prompts。模型只应选择已声明能力。
C = discover(server) = {tools,resources,prompts}02 / Schema 约束
每个工具有输入 schema。模型生成的 arguments 必须满足类型、必填字段和枚举约束。
valid(args, schema_tool) = true03 / 动作生成
工具调用可以看成从模型上下文到结构化动作的映射;动作不是自然语言承诺,而是可执行对象。
a_t = f_theta(C,s_t) = {name,args}04 / 执行隔离
Server 在自己的权限和运行环境中执行工具。Host 不应把模型文本当成本地 shell 命令直接执行。
o_t = server.execute(a_t)05 / 结果回传
结果可能是结构化数据、文本、文件引用或错误。错误也必须回传给模型和 trace,而不是被吞掉。
r_t in {data,text,artifact,error}06 / 审计日志
可复查系统应记录调用前状态、工具名、参数、结果、错误、权限和时间戳。
trace_t=(s_t,name,args,r_t,permission,time)03 / 代码
Python 演示:用 schema 校验一个 MCP 风格工具调用
真实 MCP 通过协议传输;下面用纯 Python 展示同一个核心思想:先声明工具合约,再校验参数、执行工具、返回结构化结果。
from dataclasses import dataclass
from typing import Any, Callable
@dataclass
class Tool:
name: str
description: str
required: set[str]
types: dict[str, type]
handler: Callable[[dict[str, Any]], dict[str, Any]]
def run_regression(args: dict[str, Any]) -> dict[str, Any]:
outcome = args["outcome"]
treatment = args["treatment"]
controls = args.get("controls", [])
return {
"ok": True,
"table": "outputs/regression.csv",
"formula": f"{outcome} ~ {treatment} + {' + '.join(controls)}",
}
REGISTRY = {
"run_regression": Tool(
name="run_regression",
description="Estimate a simple regression and return a table path.",
required={"outcome", "treatment"},
types={"outcome": str, "treatment": str, "controls": list},
handler=run_regression,
)
}
def validate(tool: Tool, args: dict[str, Any]) -> None:
missing = tool.required - set(args)
if missing:
raise ValueError(f"missing required fields: {sorted(missing)}")
for key, expected_type in tool.types.items():
if key in args and not isinstance(args[key], expected_type):
raise TypeError(f"{key} must be {expected_type.__name__}")
def execute_tool_call(call: dict[str, Any]) -> dict[str, Any]:
tool = REGISTRY.get(call.get("name"))
if tool is None:
return {"ok": False, "error": "unknown tool"}
args = call.get("arguments", {})
try:
validate(tool, args)
result = tool.handler(args)
return {"ok": True, "tool": tool.name, "result": result}
except Exception as exc:
return {"ok": False, "tool": tool.name, "error": str(exc)}
call = {
"name": "run_regression",
"arguments": {
"outcome": "wage",
"treatment": "training",
"controls": ["age", "education"],
},
}
response = execute_tool_call(call)
print(response)04 / 案例
案例:让研究 Agent 安全调用统计工具
- 在 StatsPAI 场景中,Agent 可能需要调用 run_stata、read_table、estimate_did、render_regression_table 或 search_literature。
- 如果没有协议边界,模型可能输出一段看似合理的 shell 命令,但路径、参数、权限和错误处理都不可控。
- MCP 风格设计会先暴露工具清单和 schema。模型只能选择存在的工具,并提供满足 schema 的参数。Server 负责执行,Host 负责把结果和错误写回上下文。
- 这使得审计成为可能:谁调用了哪个工具、用了什么参数、返回了什么文件、失败原因是什么、是否需要人工确认,都能被 trace 记录。
05 / 风险
常见误区
参考资料
- Model Context Protocol Documentationhttps://modelcontextprotocol.io/docs
- Model Context Protocol Specificationhttps://modelcontextprotocol.io/specification
- JSON Schema Documentationhttps://json-schema.org/learn/getting-started-step-by-step
- OpenAI Function Calling Guidehttps://platform.openai.com/docs/guides/function-calling