For the complete documentation index, see llms.txt. This page is also available as Markdown.

9.1 Harness 中的 MCP 集成设计

MCP(Model Context Protocol)已成为行业标准。关于 MCP 协议的基础介绍、核心架构、三种原语(Tools、Resources、Prompts)和设计哲学,请参阅《Claude 技术指南》第四章。

💡 基础参考:关于 MCP 协议的基础介绍和完整开发指南,请参阅《Claude 技术指南》第四章(4.1-4.5)。本节重点讨论 Harness 框架中的 MCP 集成特性。

9.1.1 Harness 对 MCP 的消费模式

Harness 作为一个多工具整合框架,与标准 MCP 客户端的主要差异在于 消费策略性能优化

在标准客户端中,所有 MCP Server 直接连接到主应用。Harness 引入了一个中间抽象层。下图是架构示意,不是 MCP 规范定义的部署拓扑:

用户请求 → Harness调度器 → 工具抽象层 → [MCP Client] → MCP Server

                      状态机管理

优势

  • 跨 Server 的事务一致性:同一工作流中的多个 MCP Server 调用可以共享上下文

  • 失败恢复:工具层可以捕获单个 Server 故障,而不影响整个工作流

  • 审计日志:统一记录所有工具调用,便于合规性检查

9.1.2 MCP Server 发现与注册

动态发现机制

Harness 在启动时扫描配置的 MCP Server,而非硬编码:

Harness 会:

  1. 启动每个 Server 进程(或连接到 HTTP 端点)

  2. 调用 server/discover 一次性拿到 Server 信息与能力(老版本 Server 不支持该方法时回退到直接探测),再按需调用 tools/listresources/listprompts/list 拉取原语清单

  3. 缓存 Schema 以减少运行时开销

  4. 监控 Server 的健康状态

无状态协商:每个请求自带元数据

当前版本的 MCP 是无状态协议:initialize 请求与 notifications/initialized 通知已经移除,不存在握手阶段。客户端把协议版本和能力声明放进 每一个 请求的 params._meta

_meta 中各字段的约定:

字段
类型
是否必需

io.modelcontextprotocol/protocolVersion

字符串,如 "2026-07-28"

必需

io.modelcontextprotocol/clientCapabilities

ClientCapabilities

必需

io.modelcontextprotocol/clientInfo

Implementation(nameversion

可选,建议发送

io.modelcontextprotocol/logLevel

LoggingLevel

可选

对 Harness 实现者而言,有四条硬性约束:

  • 漏发即报错:缺少必需字段的请求会得到 JSON-RPC -32602(HTTP 状态码 400)。因此能力声明必须收敛到统一的请求构造函数,而不是散落在各个调用点。

  • 能力不足有专门错误:Server 需要某项客户端能力而客户端没有声明时,返回 MissingRequiredClientCapabilityError-32021,HTTP 400),data.requiredCapabilities 给出缺失的能力列表,Harness 可据此打印可诊断的配置提示。

  • Server 不得推断状态:Server 不能依据同一连接上的历史请求推断状态;任何跨请求的状态都必须是显式标识符,由客户端每次带上。一个长期存活的 stdio 进程 不是 会话。

  • Server 信息随结果返回:Server 应在每个结果的 _meta 中放入 io.modelcontextprotocol/serverInfo,Harness 可以顺带刷新注册表中的 Server 元数据。

此外,每个结果都必须携带 resultType,取值为 "complete""input_required";客户端遇到 缺失 resultType 的结果(来自旧版 Server)时,必须按 "complete" 处理。

server/discover 替代探测式发现

server/discover 是 Server 必须实现、客户端可选调用的发现入口。请求只带 _meta,一次调用即可拿到过去要靠 tools/list + prompts/list + resources/list 反复探测才能拼出的 Server 画像:

它对 Harness 有两点直接价值:注册阶段用一次 RPC 取代三四次列表探测;在 stdio 场景下,它还是判断对端讲新版还是旧版协议的探针。

向后兼容:2025-11-25 的握手模型

⚠️ 本小节只适用于对接尚未升级的旧版 Server。新写的客户端与 Server 之间不需要握手。

大量已部署的 Server 仍在讲 2025-11-25:连接后先发 initialize 请求协商版本与能力,收到响应后再发 notifications/initialized 通知,之后才进入正常 tools/listresources/read 等操作阶段。

Harness 的探测顺序是“先按新版发,再按错误回退”:

  1. 直接发一个带 _meta 的新版请求(HTTP 上还要带 MCP-Protocol-Version 头)。

  2. 收到 HTTP 400 时检查响应体:如果是可识别的新版 JSON-RPC 错误(例如 -32020 头部与 _meta 版本不一致、-32022 版本不受支持并回带支持列表),说明对端是新版 Server,改正请求后重试;只有响应体为空或无法识别时,才回退到 initialize 握手。

  3. stdio 场景下用 server/discover 做同样的探测。

反过来,一个只实现 2026-07-28 的 Server 在面对旧流量时,应对该端点上的 GET/DELETE 返回 405 Method Not Allowed,并忽略 Mcp-Session-IdLast-Event-ID

还有几项特性被标记为 弃用但未移除,期间它们继续可用。2026-07-28 随之引入了特性生命周期与弃用策略,规定弃用窗口最短 12 个月:Roots、Sampling、Logging 与 OAuth 2.0 动态客户端注册(改用 Client ID Metadata Documents)都是在本修订版被弃用的,弃用特性登记表给出的最早移除时间是「2027-07-28 或之后发布的第一个修订版」。2024-11-05 的 HTTP+SSE 传输是例外:它自 2025-03-26 起就被标注为弃用,本次只是按新策略重新归类,登记表给出的最早移除时间是「SEP-2596 定稿后三个月」——比其余几项短得多,仍在依赖它的实现应优先迁移。迁移方向是:用工具参数或资源 URI 传入目录与文件,替代 Roots;直接调用模型厂商 API,替代 Sampling;写 stderr 或 OpenTelemetry,替代 Logging。需要注意的是 logging/setLevelnotifications/roots/list_changed 已经移除——日志级别改为在每个请求的 _meta 中用 io.modelcontextprotocol/logLevel 指定。

9.1.3 工具调用的性能优化

在生产环境中,频繁地获取和解析工具 Schema 会成为性能瓶颈。本小节介绍 Harness 采用的几种关键优化策略,包括智能缓存机制和流式传输优化,以减少网络往返和内存占用。

Schema 缓存策略

每次调用工具前重新获取 Schema 会浪费大量往返。Harness 采用缓存+增量更新策略:

启动时(冷启动)

  • 一次性获取所有 Server 的 tools/list

  • 将 Schema 存入本地缓存(SQLite 或内存)

  • 计算 Schema 的哈希值,用于增量检测

运行时(热启动)

  • 在工具调用前,先检查缓存中的 Schema 版本

  • 调用 tools/list 时,根据工具列表内容计算哈希

  • 如果哈希不匹配,再做全量同步

示例实现

上例中的 schema_version 是 Harness 自己维护的缓存元数据,不是 MCP tools/list 的标准字段。在 2025-11-25 修订版下,真实实现应根据工具列表哈希、notifications/tools/list_changed 通知或服务端自定义元数据来失效缓存;2026-07-28 修订版起,tools/listprompts/listresources/list 等列表结果必须携带 ttlMs(新鲜度提示,毫秒)与 cacheScope"public""private"),面向新版服务端时应优先以这两个字段作为缓存存活时间与共享范围的依据,旧版服务端不返回它们时再回退到哈希与变更通知。

大资源读取与流式响应

对于大数据量的 Resource 读取(如导入大文件),Harness 需要同时处理 JSON 响应和 Streamable HTTP 的 SSE 响应;但 resources/read 的结果仍是 MCP JSON-RPC 消息,二进制内容应放在 BlobResourceContents.blob 的 base64 字符串中,而不是把 HTTP body 当作任意字节流直接透传。

生产实现应把超大文件拆成资源模板、分页、任务进度或外部对象存储引用,并正确解析响应的 Content-Type

9.1.4 工具调用的状态机集成

在工作流执行中,MCP 工具调用需要与 Harness 的状态机紧密配合。

状态转移中的工具调用

以下示例展示如何在 Harness 的状态机中集成 MCP 工具调用,使得工具调用与状态转移紧密配合:

工具调用的原子性

在多步工作流中,需要确保工具调用的原子性。Harness 使用一个简单但有效的机制:

9.1.5 权限与安全隔离

Harness 中的 MCP Server 运行在受限的沙箱中,权限由 Harness 策略引擎管理。

Harness 在工具调用前,先验证权限:

9.1.6 本小节小结

Harness 通过以下机制有效地集成了 MCP:

  1. 工具层隔离:在应用逻辑和 MCP Server 之间引入抽象层

  2. 性能优化:Schema 缓存、流式传输、连接复用

  3. 状态机集成:工具调用作为工作流的一部分,支持重试和原子性

  4. 安全隔离:细粒度的权限控制和沙箱隔离

更多关于 MCP 协议本身的深度讨论,以及 MCP Server 的实现指南,请参阅《Claude 技术指南》。Harness 的特色在于如何在 多工具、多工作流 的场景中,高效且安全地管理这些 MCP 连接。

最后更新于