Documentation
¶
Overview ¶
目录层(批次对标 ZCode「连接时一次 tools/list、注册面全量」adapters/src/mcp): 每条连接建立后仅首次取目录走一次线上 ListTools,此后 Tools() 命中内存缓存; 连接被 evict(列举失败/探活死亡/自愈摘除)时目录随连接一并失效,重建连接后 重新列举。第三方 server 工具面在连接生命周期内视为静态——工具集变化需重连 生效,换来每次专家装配/直调不再全量走线(此前 einomcp.GetTools 每次 Tools() 都发一轮 ListTools)。
注解(annotations)随目录同源提取,供并发治理与风险分级消费(对标 ZCode readOnlyHint/idempotentHint/destructiveHint → 风险级 + concurrentSafe 映射)。
envref.go —— ServerConfig 头部值的 ${VAR} 环境引用展开(token 不落配置 文件的纪律件;收编自 argus toolpool,v0.10.39)。未定义变量保留原样并经 onMissing 上报——显式可见优于静默空值。
连接租约面(批次五十三自 bianque 对标 ZCode pool 沉淀):探活 + 闲置回收。
语义裁定——ZCode 原型是「引用计数归零 + 30s 惰性关闭」,本池不可照搬:工具对象 (eino tool)持有连接且生命周期调用方不可见,refcount 无处挂钩。借用模型的等价 租约 = **闲置回收**(ReapIdle/StartIdleReaper)+ **调用期透明重建**(既有 evict + lazy 建连)。在途工具调用经 leaseUse 登记 inFlight,回收据此跳过在用连接 (无须再要求 maxIdle 显著大于最大工具超时)。
请求侧上下文透传(批次五十六 B,对标 ZCode request-context:请求侧 _meta 携带 trace/workspace 上下文,adapters/src/mcp/index.ts:1767-1770): Pool.RequestMeta 在每笔工具调用的 ctx 上取值,经 metaClient 装饰器注入 req.Params.Meta(stdio 与 HTTP 同走 JSON-RPC params,server 侧通用)。 池不感知业务键——metaFn 由装配方提供(bianque 侧从 ctx 取 session/trace/caller)。
errorAsObservation MCP isError 降级器(2026-09-21 k8s 106 审计 P1):eino-ext 把 MCP isError:true 的工具结果当调用 error 上抛,ReAct 直接以 NodeRunError 炸掉整个 agent 步骤——LLM 没有机会看到错误并修正参数(实弹:k8sgpt get-resource 猜错 pod 名 → 专家整步 degraded)。本装饰器把这类错误降级为文本观察回传 LLM(是否修正参数/ 换路径由 LLM 自行决定);传输层等其他错误原样上抛。仅 mcp.Pool.Tools() 出口启用。
Package mcp MCP 工具池:MCP server 连接管理 → eino tool.BaseTool(对齐 eino-ext components/tool/mcp 的能力面,补连接生命周期与白名单池化)。
定位(对应 Argus design §9.2 方向 A):R3/builtin agent 需要 diff 之外的上下文 时,把外部 MCP server 的工具挂进 agent 工具表(工单系统/内部文档/linter 等)。
用法:
pool := mcp.NewPool(
mcp.ServerConfig{Name: "docs", URL: "http://docs.svc/mcp",
Headers: map[string]string{"Authorization": "Bearer " + tok}},
mcp.ServerConfig{Name: "lint", Command: []string{"lint-mcp", "serve"}},
)
defer pool.Close()
res, err := pool.Tools(ctx, []mcp.ToolSpec{{Server: "docs", Allow: []string{"search_docs"}}})
// res.Tools = 装配成功的工具;res.Failed = 被容忍的失败面(server → 原因)
安全模型:stdio 子进程环境走白名单透传(绝不继承密钥,经 procx.ChildEnv 单一纪律);工具白名单按 spec 收敛(未声明的 server/工具不暴露给 agent)。
有线 schema 保真通道(v0.12.5):mcp-go 类型化 Tool 反序列化丢 anyOf—— ToolArgumentsSchema 仅 $defs/type/properties/required/additionalProperties 五类键, outputSchema 的 anyOf/oneOf 联合声明经类型化 tools/list 即残废(inputSchema 同理)。 建连路径本就自建 transport(dialStdio/dialHTTP),句柄入 connState 后 tools/list 走原始 JSON-RPC 自解析,双 schema 无损;transport 未登记(测试注入 InProcess client 等)自动回落类型化通道,outputSchema 置空——宁缺勿假。
工具出参 schema 能力面(v0.12.5,MCP 2025-06-18 outputSchema):目录层经原始 tools/list 无损透传(rawlist.go),invokableTool 以可选接口暴露——eino tool.BaseTool 为封闭接口,schema 进不了 ToolInfo,故走类型断言。断言失败=该 工具无声明(typed 回退/第三方未声明),消费方按「未声明」处理。
Index ¶
- Constants
- Variables
- func CallMeta(ctx context.Context) map[string]any
- func Classify(err error) error
- func ExpandEnvRef(v string, onMissing func(name string)) string
- func ExpandEnvRefs(headers map[string]string, onMissing func(name string)) map[string]string
- func IsToolResultError(err error) bool
- func OutputSchemaOf(t tool.BaseTool) (json.RawMessage, bool)
- func UnwrapMCPText(raw string) string
- func WithCallMeta(ctx context.Context, meta map[string]any) context.Context
- func WrapErrorAsObservation(tools []tool.BaseTool) []tool.BaseTool
- type Catalog
- type CatalogDiff
- type ClassifiedError
- type ErrorKind
- type Health
- type HealthIssue
- type HealthState
- type OAuthClientConfig
- type OutputSchemer
- type Pool
- func (p *Pool) Close()
- func (p *Pool) Hints(server string) map[string]ToolHints
- func (p *Pool) PingServer(ctx context.Context, name string) error
- func (p *Pool) ReapIdle(maxIdle time.Duration) int
- func (p *Pool) Servers() []string
- func (p *Pool) StartIdleReaper(interval, maxIdle time.Duration)
- func (p *Pool) Tool(ctx context.Context, server, name string) (tool.BaseTool, error)
- func (p *Pool) Tools(ctx context.Context, specs []ToolSpec) (ToolsResult, error)
- type SelfcheckOptions
- type SelfcheckResult
- type Selfchecker
- type ServerConfig
- type ToolCheck
- type ToolHints
- type ToolResultError
- type ToolSpec
- type ToolStatus
- type ToolsResult
Constants ¶
const DefaultProbeTimeout = 5 * time.Second
DefaultProbeTimeout 探活独立预算(批次五十六 B:ping 是轻量协议方法,不该吃 连接级 30s 预算;对标 ZCode MCP_PING_TIMEOUT_MS=5s)。
const DefaultRequestTimeout = 10 * time.Minute
DefaultRequestTimeout HTTP 传输单请求兜底缺省。
const DefaultSelfcheckTTL = 30 * time.Second
DefaultSelfcheckTTL 自检默认目录缓存 TTL。
const DefaultSelfcheckTimeout = 10 * time.Second
DefaultSelfcheckTimeout 自检默认超时。
const DefaultTimeout = 30 * time.Second
DefaultTimeout 连接与初始化的缺省超时。
Variables ¶
var ErrNotConnected = errors.New("mcp: server 无缓存连接(未建连或已被回收)")
ErrNotConnected PingServer 探活时该 server 无缓存连接——懒建连模型下属正常态 (与「有连接但已死」区分,探活无意义不算失败)。
Functions ¶
func CallMeta ¶
CallMeta 从 ctx 取调用元数据;无注入返回 nil(metaClient 对空不注入 _meta)。 返回值可直接作 Pool.RequestMeta:pool.RequestMeta = mcp.CallMeta。
func ExpandEnvRef ¶
ExpandEnvRef 展开字符串中的 ${VAR} 环境引用。已定义取环境值;未定义保留 原样(扫描位置跳过本标记,防死循环)并回调 onMissing。
func ExpandEnvRefs ¶
ExpandEnvRefs 对声明式头部表逐值做 ${VAR} 展开(nil/空表原样返回 nil)。 onMissing 可 nil(未定义变量仍保留原样,只是无告警出口)。
func IsToolResultError ¶
IsToolResultError err 链上是否存在工具业务失败(isError:true)。
func OutputSchemaOf ¶
func OutputSchemaOf(t tool.BaseTool) (json.RawMessage, bool)
OutputSchemaOf 取工具的声明 outputSchema(尽力:装饰器链各自转发;断言失败或 未声明返回 false)。
func UnwrapMCPText ¶
UnwrapMCPText 解 MCP 工具返回的信封取内层文本;非信封形态原样返回——快照/ 结果进证据条目时,snippet 配额应留给有效数据而非包装层。 信封两种形态:content[].text(标准工具结果,人类可读文本优先);缺失时 structuredContent(较新 MCP 规范的结构化结果)序列化为 JSON——直接把结构化 对象丢给 LLM 优于丢弃。
func WithCallMeta ¶
WithCallMeta 在 ctx 上注入任务级调用元数据(Runner/任务层调用一次,随 ctx 流入该任务全部 MCP 工具调用)。
Types ¶
type Catalog ¶ added in v0.8.2
type Catalog struct {
// Server 所属 server 名(空 = 跨 server 聚合)。
Server string
// Tools 工具名清单(已去重、已排序)。
Tools []string
}
Catalog 工具面快照:某个 server(或一组 server)实际提供的工具清单。
这是「装包≠开洞」「授权面 ⊄ 契约面」这类治理规则的**数据基础**: 只有把「声明要用的」与「实际有的」摆在一起做差集, 才能答出「我以为有的工具其实没有」与「多出来的没声明的工具」两个问题。
func NewCatalog ¶ added in v0.8.2
NewCatalog 构造目录(去重 + 排序,保证可比与可比较)。
type CatalogDiff ¶ added in v0.8.2
type CatalogDiff struct {
// Missing 声明了但实际没有(expected - actual)——「我以为有的其实没有」。
Missing []string
// Extra 实际有但没声明(actual - expected)——「多出来的、没走授权面」。
Extra []string
}
CatalogDiff 双向差集结果。
func Diff ¶ added in v0.8.2
func Diff(expected, actual Catalog) CatalogDiff
Diff 双向有序差集。
expected = 声明/期望要用的工具面;actual = server 实际提供的工具面。 两个方向都要:**只看一个方向会漏掉一半的治理问题**—— 只看 Missing 漏掉「没声明却存在」的工具(授权面之外的开洞), 只看 Extra 漏掉「声明了却没有」的工具(装包≠开洞)。
结果按字典序(可复现、可比较)。
func DiffNames ¶ added in v0.8.2
func DiffNames(expected, actual []string) CatalogDiff
DiffNames 便捷形态:两个工具名清单的差集。
type ClassifiedError ¶ added in v0.8.2
ClassifiedError 带分类的错误(便于 errors.As 取分类,同时保留原始错误链)。
func (*ClassifiedError) Error ¶ added in v0.8.2
func (e *ClassifiedError) Error() string
func (*ClassifiedError) Unwrap ¶ added in v0.8.2
func (e *ClassifiedError) Unwrap() error
type ErrorKind ¶ added in v0.8.2
type ErrorKind int
ErrorKind MCP 调用失败的稳定分类。
为什么要有枚举:下游此前各自做**字符串匹配**(`strings.Contains(err.Error(), "connection refused")`)判「连不上」还是「工具不存在」,文案一改就失效。 枚举把判定锚在**协议层事实**上(JSON-RPC 错误码 / net.Error / 错误链类型), 不随实现文案漂移。
处置口径(这四类的处置完全不同,不要混):
KindUnreachable —— 连不上。基础设施问题:重试 / 换节点 / 报警。
KindProtocol —— 协议错。server 实现不合规或版本不匹配:修 server / 升级。
KindToolMissing —— 工具不存在。**配置或契约问题**:server 起来了但没有这个
工具(装包≠开洞、工具面未声明)。不要重试——重试一万次
它也不会出现。改配置或改契约。
KindInvalidArgs —— 参数错。**调用问题**:工具在、但传参不合法。改调用方。
func ClassifyError ¶ added in v0.8.2
ClassifyError 把任意错误归到稳定分类。
判定顺序(**先具体后笼统**,避免被笼统分支抢走):
- 工具业务失败(isError:true)→ 按 payload 信号细分,否则 KindProtocol
- JSON-RPC 哨兵错误(mcp.ErrInvalidParams / ErrMethodNotFound …)—— 这是 mcp-go 把 JSON-RPC 错误码转成 Go error 的**官方路径** (JSONRPCErrorDetails.AsError),按哨兵判比按错误码判更可靠: 它扛得住错误码被包进自定义 error 的情况。
- 错误链里有 net.Error / os.ErrNotExist / syscall.ECONNREFUSED 等 → KindUnreachable
- ctx 超时/取消 → KindUnreachable(连不上的一种)
- 兜底 KindUnknown
func ClassifyRPCCode ¶ added in v0.8.2
ClassifyRPCCode JSON-RPC 错误码 → 分类。
供「已知错误码但还没转成 Go error」的场景用(如自检时读了原始响应)。 走 mcp-go 官方转换路径(JSONRPCErrorDetails.AsError)时不必用本函数—— ClassifyError 已经按哨兵错误判好了。
func (ErrorKind) MarshalJSON ¶ added in v0.8.2
MarshalJSON 输出可读分类名(不是数字)——JSON 消费方(监控/告警)不该 看到裸 int 枚举值。
func (ErrorKind) Retryable ¶ added in v0.8.2
Retryable 该类错误重试是否有意义。
关键:**工具不存在与参数错重试没有意义**——重试不会让 server 长出那个工具, 也不会让非法参数变合法。盲目重试会把「配置问题」伪装成「偶发抖动」。
func (*ErrorKind) UnmarshalJSON ¶ added in v0.8.2
UnmarshalJSON 支持从分类名反解。
type Health ¶ added in v0.8.2
type Health struct {
// State 三态结论。
State HealthState
// Servers 参与聚合的 server 名(排序)。
Servers []string
// Issues 问题清单(按 server → tool 排序)。
Issues []HealthIssue
// Total 参与聚合的 server 数。
Total int
// HealthyCount 完全健康的 server 数。
HealthyCount int
// DegradedCount 降级的 server 数。
DegradedCount int
// DownCount 不可达的 server 数。
DownCount int
}
Health 健康聚合结果。
判据可观察:**能看出是哪个 server 的哪个工具出的问题**——不是只给一个总体布尔。 Issues 逐条给出 server / tool / 分类 / 原因。
func Aggregate ¶ added in v0.8.2
func Aggregate(results []SelfcheckResult) Health
Aggregate 把多个 server 的自检结果聚合成一个健康结论。
## 三态判定依据(明确写死,不留给调用方猜)
down —— **有 server 连不上**(Reachable==false)。
这是基础设施故障:server 进程挂了 / 网络不通 / 建连超时。
degraded —— **全部 server 都连得上,但至少一个能力不可用**:
工具缺失(声明了但目录里没有)或个别工具调用失败。
healthy —— 全部 server 连得上,且声明的工具全部在目录里、可调。
## 关键歧义:「工具缺失」归 degraded,**不是** down
这是下游踩过的坑:把「工具缺失」当「server 挂了」→ 依赖故障被 放大成平台故障。理由是二者的**处置完全不同**:
- server 连不上 ⇒ 该 server 的能力**全部**不可用 ⇒ 影响面是整个 server。
- 工具缺失 ⇒ server **活着**且在正常提供服务,只是没有某个工具 ⇒ 影响面是那一个工具。
若把工具缺失算成 down:一个 server 少了个工具,平台就被判全挂, 告警风暴 + 流量全量切走 —— 而实际上 server 还能服务其他工具。
## 「server 挂了」时,工具状态标 unreachable 而非 missing
server 连不上时**无从知道**它有没有那个工具(没应答), 所以自检层把工具标成 ToolUnreachable(未知)而不是 ToolMissing(确认没有)。 聚合时 unreachable 的工具**不计入** missing 计数—— 否则「server 挂了」会被算成「N 个工具缺失」, 再次把基础设施故障伪装成契约故障。
## 部分 server 挂掉时,整体是 down 还是 degraded?
取**最严重**态:任一 server 不可达 ⇒ 整体 down。 理由:聚合结论回答的是「平台能不能按声明提供服务」—— 声明了却完全拿不到的那个 server,其能力是真缺失的。 但 Issues 里会逐条列出,调用方能看出是「哪个 server 挂了」 而不是笼统一个 down。
type HealthIssue ¶ added in v0.8.2
type HealthIssue struct {
// Server 出问题的 server 名(空 = 跨 server 汇总项)。
Server string
// Tool 出问题的工具名(空 = server 级问题,如连不上)。
Tool string
// Kind 错误分类。
Kind ErrorKind
// Reason 人类可读原因。
Reason string
}
HealthIssue 单条问题。
type HealthState ¶ added in v0.8.2
type HealthState string
HealthState 健康三态。
const ( // HealthHealthy 全绿:server 全可达,声明的工具全在且可调。 HealthHealthy HealthState = "healthy" // HealthDegraded 降级:server 活着,但**部分**能力不可用 //(工具缺失 / 个别工具调用失败)。服务还在提供部分能力。 HealthDegraded HealthState = "degraded" // HealthDown 全挂:server 连不上(基础设施故障)。 HealthDown HealthState = "down" )
func (HealthState) MarshalJSON ¶ added in v0.8.2
func (s HealthState) MarshalJSON() ([]byte, error)
MarshalJSON 输出可读状态名。
type OAuthClientConfig ¶
type OAuthClientConfig struct {
ClientID string // 空=依赖 IdP DCR(handler.RegisterClient 由调用方驱动)
ClientSecret string
Scopes []string
MetadataURL string // 空=从 base URL .well-known 发现
RedirectURI string // 授权回调落点(无头服务端=固定平台端点)
TokenStore client.TokenStore
}
OAuthClientConfig URL 传输的 OAuth2 装配输入(映射 mcp-go client.OAuthConfig; TokenStore 必填——缺省会落内存 store,进程内自愈场景重连后丢授权态)。
type OutputSchemer ¶
type OutputSchemer interface {
OutputSchema() json.RawMessage
}
OutputSchemer 工具出参 schema 的可选能力接口。
type Pool ¶
type Pool struct {
// OnError 建连/列举失败回调(nil 安全)。返回错误不中断其余 server——
// 部分失败容忍:可用的工具照常返回,失败的 server 由调用方经钩子观测。
OnError func(server string, err error)
// RequestMeta 每笔工具调用 _meta 注入来源(nil 安全;批次五十六 B,对标 ZCode
// request-context)。metaFn 在调用方 ctx 上取值,池不感知业务键;经 metaClient
// 装饰器注入 req.Params.Meta(见 meta.go)。返回 nil/空 = 不注入。
RequestMeta func(ctx context.Context) map[string]any
// Elicitation server→client 征集输入处理器(mcp-go v1.1 SEP-2322):工具执行中
// server 反向请求补充输入(表单/URL 模式)时回调;nil 时该类请求得到
// "no elicitation handler configured" 错误(调用失败呈现,与不声明能力的服务端
// 行为一致)。池级单点——建连/自愈 redial/Initialize 能力声明共用。
ElicitationHandler client.ElicitationHandler
// contains filtered or unexported fields
}
Pool MCP 连接池:lazy 建连(首次 Tools 时)、连接缓存复用、Close 全量回收。 闲置回收/探活租约面见 lease.go(ReapIdle/StartIdleReaper/PingServer)。
func NewPool ¶
func NewPool(cfgs ...ServerConfig) *Pool
NewPool 创建连接池(建连延后到 Tools 调用时——允许启动期 MCP server 未就绪)。 Name 为空的配置忽略;重名保留先到者(后者忽略)——配置错误尽早收敛为确定性 行为而非静默覆盖。
func (*Pool) Close ¶
func (p *Pool) Close()
Close 关闭全部缓存连接并拒绝后续建连(幂等);停止闲置回收协程。Close 后池不可复用。 锁序:先在 p.mu 内标记 closed 并摘出各 connState 指针,释放后再逐个收连接—— 绝不在持 p.mu 时抢 st.mu(与 dialAndRegister 的写入路径交叉会死锁)。
func (*Pool) Hints ¶
Hints 目录注解快照(server 名 → 工具名 → 注解)。server 未配置或未列举 → nil。 供装饰层做并发治理与风险分级;返回副本,调用方可自由持有。
func (*Pool) PingServer ¶
PingServer 探活指定 server 的缓存连接。死亡连接立即摘除出缓存并关闭,下次 调用透明重建——HTTP server 被停掉不派发断连回调,「无声死亡」只有显式探活 才能暴露(ZCode pool 同款问题与解法)。
探活方法按建连协商的协议代际分流(v0.10.29 审计修复——mcp-go v1.1 起现代 协议 2026-07-28 移除了 ping RPC,Client.Ping 在该代际是 no-op,曾让探活 虚报存活且 touch 给死连接续命、闲置回收永远收不走):
- legacy(≤2025-11-25):协议 ping;
- modern(2026-07-28+):改发真实轻量 RPC(tools/list)——比 ping 重, 但这是该代际下唯一能证明连接活着的信号。
返回 ErrNotConnected = 无缓存连接(不算失败);其余错误 = 探活失败(连接已摘除)。
func (*Pool) ReapIdle ¶
ReapIdle 关闭闲置超过 maxIdle 的缓存连接,返回回收数。闲置时钟 = 最近一次 建连/取工具/探活成功。被回收的 server 下次调用透明重建(evict+lazy 建连)。 在途工具调用(leaseUse 登记)中的连接不回收——原先契约要求 maxIdle 显著大于 最大工具超时,现在由在途计数直接挡下。
func (*Pool) StartIdleReaper ¶
StartIdleReaper 启动后台闲置回收协程:每 interval 周期执行 ReapIdle(maxIdle)。 Close 停止;重复启动幂等(只起一个)。
func (*Pool) Tool ¶ added in v0.9.0
Tool 按 server + 工具名取**单个**工具。
「取不到」是**显式错误**,不是静默降级:此前调用方只能写 `res.Tools[0]` 这种**位置假设**——Allow 给多个工具时取到的可能是另一个工具,server 列举 部分失败时同样可能取错,而这两种失效都是**静默**的(调用成功、调的是别的工具)。
name 可写**原始工具名**(server 内)或带 server 的全名("server.tool")—— 与白名单的两种写法一致。
type SelfcheckOptions ¶ added in v0.8.2
type SelfcheckOptions struct {
// Server server 名(结果标识 + 缓存键)。
Server string
// Timeout 单次探测的超时预算(默认 10s)。
Timeout time.Duration
// TTL 目录缓存有效期(默认 30s)。<= 0 表示不缓存(每次都实拉)。
//
// 为什么需要缓存:自检是「高频拉目录」的动作,而 MCP 侧的工具目录
// 在连接生命周期内视为静态(见 catalog.go)。没有 TTL 时,每次探活
// 都会打一轮 tools/list —— 部署机的巡检会把 server 压垮。
TTL time.Duration
// ProbeTools 是否逐工具做一次**调用**探测(默认 false)。
//
// true = 每个工具都真调一次(最彻底,但有副作用:会真的执行工具)。
// 默认 false = 只探连通性 + 拉目录(无副作用)。
// 工具「存在但调不通」这种情形,用 tools/call 探针单点确认(见 ProbeTool)。
ProbeTools bool
// ProbeArgs 逐工具探测时的参数(nil = 用空对象)。
ProbeArgs map[string]any
// Initialize 是否在自检前先发 initialize 握手。
//
// 默认 false:调用方通常传**已建连**的 client(Pool 的 client 都已
// 握手过)。但若传的是裸 client(未 initialize),协议请求会返回
// "client not initialized"——那时自检会误判成 server 不可达。
// 自检是「诊断工具」,不该因为握手缺失而给出错误结论,
// 所以提供这个开关。
Initialize bool
// Expected 声明期望的工具面(可选)。
//
// 给了它,自检会逐个核:这���工具在不在 server 目录里、在但调不通。
// 这是「装包≠开洞」这类治理规则的输入——只有把声明面与实际面对照,
// 才能发现「我以为有的工具其实没有」。
Expected Catalog
}
SelfcheckOptions 自检参数。
type SelfcheckResult ¶ added in v0.8.2
type SelfcheckResult struct {
// Server server 名。
Server string
// Reachable 连通性(server 能否应答协议请求)。
Reachable bool
// Tools 逐工具结果(按工具名排序)。
Tools []ToolCheck
// Catalog server 实际提供的工具目录(连通时有效)。
Catalog Catalog
// Expected 声明期望的工具面(可选,供差集比对)。
Expected Catalog
// Diff 期望 vs 实际的差集(Expected 非空时有效)。
Diff CatalogDiff
// PingErr ping 探测的错误(**不代表不可达**——server 可能没实现 ping;
// 真正的连通性判据是列举成功)。留在这里供诊断。
PingErr error
// Kind 整体失败的错误分类(Reachable==false 时有效)。
Kind ErrorKind
// Err 整体失败的原始错误。
Err error
// Cached 本次结果是否来自 TTL 缓存。
Cached bool
// At 探测时刻。
At time.Time
}
SelfcheckResult 单个 server 的自检结果。
func (SelfcheckResult) Failed ¶ added in v0.8.2
func (r SelfcheckResult) Failed() []ToolCheck
Failed 失败的工具条目(Status != ToolOK)。
type Selfchecker ¶ added in v0.8.2
type Selfchecker struct {
// contains filtered or unexported fields
}
Selfchecker 带 TTL 缓存的自检器。
用法(部署机上的常驻自检):
sc := NewSelfchecker()
res := sc.Check(ctx, client, SelfcheckOptions{Server: "fs", Expected: exp})
零值不可用——用 NewSelfchecker 构造。
func (*Selfchecker) Check ¶ added in v0.8.2
func (s *Selfchecker) Check(ctx context.Context, cli client.MCPClient, opts SelfcheckOptions) SelfcheckResult
Check 对单个 server 做自检:拉工具目录 + 探连通性 + 逐工具核状态。
client 非 nil 时用它拉目录与探活;nil 时只做「声明面 vs 已有目录」的核, 不发任何请求(离线比对模式)。
type ServerConfig ¶
type ServerConfig struct {
// Name 逻辑名:ToolSpec.Server 引用。
Name string
// Command stdio 传输:可执行 + 参数(子进程由本包启动与回收)。
Command []string
// Env stdio 子进程环境白名单:条目为纯变量名(如 "GITHUB_TOKEN")时按名从
// 当前进程透传;含 "=" 时按 KEY=VALUE 字面透传。未列出的变量一律不继承
// (基础集见 procx.ChildEnv),防止本进程密钥泄漏给外部 MCP server。
Env []string
// URL HTTP 传输(streamable http)。
URL string
// Headers HTTP 请求头(如 Bearer 鉴权)。
Headers map[string]string
// Timeout 连接 + Initialize 超时(默认 30s)。仅作用于建连期(dial +
// Initialize 的 ctx 预算),不约束后续请求——HTTP 传输的每请求兜底见
// RequestTimeout。
Timeout time.Duration
// RequestTimeout HTTP 传输的单请求兜底上限(默认 10 分钟)。mcp-go 的
// WithHTTPTimeout 直接设 httpClient.Timeout、作用于该连接的每一次请求
// (含 tools/call)——此前误用连接级 Timeout(30s)会让任何长工具调用
// 在 HTTP 传输下永远失败(v0.10.29 审计修复);工具调用的正常时长控制
// 归调用方 ctx,这里只是挂死兜底。stdio 不受影响。
RequestTimeout time.Duration
// ProbeTimeout 探活(PingServer)独立预算(默认 5s;租约面 lease.go——
// 探活是轻量协议 ping,不该吃连接级 30s 预算)。
ProbeTimeout time.Duration
// OAuth URL 模式 OAuth2 客户端配置(批次五十六 C,对标 ZCode oauth 全栈;
// 仅 URL 传输生效)。非 nil 时 dial 走 NewOAuthStreamableHttpClient——401 触发
// client.OAuthAuthorizationRequiredError(errors.As 可穿透池的 %w 包装),
// 调用方经 client.GetOAuthHandler 取 handler 驱动授权码+PKCE 流程;
// TokenStore 由调用方提供(进程内缓存失效后重 dial 仍能取回已授权 token)。
OAuth *OAuthClientConfig
}
ServerConfig 单个 MCP server 连接声明。 stdio(Command 非空)与 HTTP(URL 非空)二选一;都空视为无效配置(跳过并告警)。
type ToolCheck ¶ added in v0.8.2
type ToolCheck struct {
// Tool 工具名。
Tool string
// Status 状态。
Status ToolStatus
// Kind 失败时的错误分类(Status==ToolOK 时为 KindUnknown)。
Kind ErrorKind
// Reason 人类可读的失败原因(Status==ToolOK 时为空)。
Reason string
// Err 原始错误(供 errors.Is/As 穿透)。
Err error
}
ToolCheck 单个工具的自检结果。
type ToolHints ¶
ToolHints 工具注解归一(mcp.ToolAnnotation 子集,nil 视为规范缺省)。
func (ToolHints) ConcurrentSafe ¶
ConcurrentSafe 读读可并行(readOnly+idempotent,对标 ZCode concurrentSafe); 缺省注解按非安全处理——保守。
type ToolResultError ¶
type ToolResultError struct {
// contains filtered or unexported fields
}
ToolResultError MCP 工具执行了但业务失败(CallToolResult.IsError=true)。 v0.11 起导出:包外消费方(经 agentkit/mcp 组装工具表的调用方)可 errors.As 穿透 %w 包装直达本类型取 Payload,无须对 Error() 文案做文本匹配——多错误 聚合文本的 marker 分类不可靠。Error() 文案是历史识别锚点(observe 兜底与 既有测试消费),改文案须同步;新代码优先 errors.As / IsToolResultError。
func (*ToolResultError) Error ¶
func (e *ToolResultError) Error() string
func (*ToolResultError) Payload ¶
func (e *ToolResultError) Payload() []byte
Payload 原始 CallToolResult JSON(observe 层剥 content[].text 用)。
type ToolSpec ¶
type ToolSpec struct {
// Server ServerConfig.Name。
Server string
// Allow 工具名白名单。
//
// ⚠️ **破坏式变更**(v0.9.0):**空 = 不授予任何工具**(缺省拒绝)。
// 此前空 = 该 server 的**全部**工具——而这个默认值在配置里**不可见**:
// 一份 `allow: []` 看起来像「没限制」,实际是把该 server 的全部工具
// (含删除/执行类破坏性工具)都授予了模型,最小权限的责任整个落到了下游
// (下游只能靠事后门禁兜——那时配置已生效、模型已拿到工具)。
//
// 要「全给」必须**显式**写:AllowAll: true,或 Allow 里含 "*"。
Allow []string
// AllowAll 显式授予该 server 的全部工具(缺省拒绝的对立面,必须写在配置里)。
//
// 与 Allow 里的 "*" 等价;同时存在时以本字段为准(Allow 被忽略)。
AllowAll bool
}
ToolSpec 工具白名单:某 server 的哪些工具暴露给 agent。
type ToolStatus ¶ added in v0.8.2
type ToolStatus string
ToolStatus 单个工具的自检状态。
const ( // ToolOK 工具在目录里且连通。 ToolOK ToolStatus = "ok" // ToolMissing 工具在声明面里但 server 目录里没有(契约/配置问题)。 ToolMissing ToolStatus = "missing" // ToolUnreachable server 连不上,工具状态未知(**不是** missing)。 ToolUnreachable ToolStatus = "unreachable" // ToolFailed 工具存在但调用失败。 ToolFailed ToolStatus = "failed" )
type ToolsResult ¶
type ToolsResult struct {
// Tools 装配成功的工具(跨 server 并行拉取,按 specs 序稳定)。
//
// ⚠️ 这是**跨 server 的扁平列表**:拿到的工具没有「它来自哪个 server」的
// 结构化归属(工具名虽带 server 命名空间,但那是模型侧的名字,不是归属面)。
// 要按 server 取用走 ByServer;要按 server+名字取单个走 Pool.Tool。
Tools []tool.BaseTool
// ByServer server → 该 server 装配出的工具(按目录序)。
//
// 它是「工具归属」的结构化面——不让调用方靠位置假设(res.Tools[0])去猜
// 某个工具来自哪个 server。空 = 没有工具。
ByServer map[string][]tool.BaseTool
// Failed server → 被容忍的失败原因(建连/列举失败、白名单无一命中)。
// 失败连接已摘除,下次调用透明重建。空 = 全部成功。OnError 仍发射同源
// 通知(遥测钩子),失败面的程序化消费一律走这里。
Failed map[string]error
}
ToolsResult Tools 的结果面(v0.10.38 破坏式:此前返回 []BaseTool,部分失败只 经 OnError 侧面观测——调用方在返回值层面无法区分「失败被容忍」与「真的没 工具」,只能把失败当空表静默降级)。