9.5 实战:为 MiniHarness 集成 MCP
本节把 MCP 工具接入 MiniHarness 的统一执行管线。实现使用官方 MCP Python SDK,支持 stdio 与 Streamable HTTP,并明确处理初始化、认证、超时取消和关闭。
9.5.1 模块边界
实现不再把传输、认证、客户端、注册表和测试替身放在一个文件中:
lab/mini_harness/mcp/auth.py
Bearer Token 请求头;对象表示不会输出 Token
lab/mini_harness/mcp/transports.py
对官方 stdio_client、streamable_http_client 的薄封装
lab/mini_harness/mcp/client.py
ClientSession 生命周期、协商结果、请求超时和结果归一化
lab/mini_harness/mcp/integration.py
Server 配置、工具发现、Schema 缓存、注册表和 LLM 适配器
lab/mini_harness/application.py
本地工具和 MCP 工具共用的权限、护栏、重试与检查点入口
lab/tests/fakes/
单元测试替身和真实协议测试 Server;不进入生产包
生产路径不会创建 Mock Client。注册表默认工厂只创建基于官方 SDK 的 MCPClient;单元测试通过 client_factory 显式注入 Fake。
9.5.2 传输与配置
stdio 配置把可执行程序与参数分开,避免把整条命令交给 Shell:
import sys
from mini_harness.mcp.integration import MCPServerConfig
stdio_server = MCPServerConfig(
server_id="local-tools",
server_name="Local tools",
transport_type="stdio",
endpoint=sys.executable,
args=("servers/local_tools.py",),
timeout_seconds=10,
)Streamable HTTP 可以带固定请求头和 Bearer Token。真实凭据应来自受控环境变量或 Secret Store,不写入配置文件:
http 仍是 streamable_http 的兼容别名。当前适配层提供 Bearer Token 与自定义请求头;需要 OAuth 动态注册或 Token 刷新时,应接入官方 SDK 的 OAuth Provider,而不是把刷新逻辑塞进注册表。
9.5.3 客户端生命周期
MCP 普通请求必须发生在初始化完成之后。MCPClient 保留 Server 协商得到的协议版本、能力和实现信息,不在客户端硬编码“协商成功”的值:
调用顺序由官方 ClientSession.initialize() 完成;SDK 负责发送 initialize 和初始化通知。MiniHarness 在每个初始化或工具请求外增加截止时间,超时时取消等待并抛出 MCPRequestTimeout。关闭是幂等的,关闭后再请求会抛出 MCPClientClosedError。
9.5.4 工具发现与 Schema 缓存
MCPToolRegistry 串行保护一次发现过程,并用新的发现结果整体替换旧映射,避免已经下线的工具残留:
Schema 使用内存与 JSON 文件两层缓存,并带 TTL。缓存只减少重复的 tools/list 与 Schema 转换;它不缓存工具执行结果,也不能替代 Server 可用性检查。多个 Server 提供同名工具时,当前实现按 Server 优先级选择第一个,没有实现自动故障转移。
9.5.5 统一安全执行入口
MCP 工具不能绕过本地工具的安全策略。HarnessApplication.execute_tool() 先调用 SecureToolExecutor,只有权限、命令护栏、路径校验和必要批准全部通过,才进入 MCP 注册表:
管线顺序是:
执行权限和护栏判断;
原子认领相同
session_id + call_id的检查点;已完成记录直接回放,只有获得随机 Lease 的 Owner 才能写入
started后执行;仅对配置的可恢复异常重试,并写入同一 Trace 的事件;
成功返回后保存可重放结果,并校验完成者持有对应 Lease。
已完成的调用在恢复时直接复用结果,不重复副作用。并发请求若遇到另一个 Owner 的 started 记录,会得到明确的“正在执行或结果未知”错误;Owner 抛出异常时也保留 started,因为远端操作可能已经成功。该策略优先避免重复写入;它不能让“远端副作用 + 本地 JSON 检查点”获得跨系统原子性。需要严格一次性语义时,Server 仍须支持幂等键、事务或可查询的操作状态。
9.5.6 真实协议测试
lab/tests/integration/test_mcp_lifecycle.py 启动两个真实 Server:
子进程 stdio Server:验证初始化前拒绝、版本/能力协商、工具发现与调用;
本机回环 Streamable HTTP Server:验证 Bearer Token、401、调用与关闭;
慢工具:验证请求超时会取消客户端等待,随后仍能正常关闭。
lab/tests/integration/test_application.py 进一步验证 DENY 发生在副作用前、重试事件共享 Trace、检查点恢复不重复执行,以及 MCP 与本地工具共用安全执行器。运行方式:
9.5.7 集成检查清单
9.5.8 小结
MiniHarness 的 MCP 集成将协议细节限制在 SDK adapter 内,将工具发现限制在注册表内,并把安全、重试和恢复收口到应用入口。清晰边界比“自己实现一套 JSON-RPC”更重要:协议演进由官方 SDK 承担,Harness 只负责自身的策略和生命周期。
最后更新于
