Help us shape the future of Go! Take the 2026 Go Developer Survey

mcp

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 23 Imported by: 3

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

View Source
const DefaultProbeTimeout = 5 * time.Second

DefaultProbeTimeout 探活独立预算(批次五十六 B:ping 是轻量协议方法,不该吃 连接级 30s 预算;对标 ZCode MCP_PING_TIMEOUT_MS=5s)。

View Source
const DefaultRequestTimeout = 10 * time.Minute

DefaultRequestTimeout HTTP 传输单请求兜底缺省。

View Source
const DefaultTimeout = 30 * time.Second

DefaultTimeout 连接与初始化的缺省超时。

Variables

View Source
var ErrNotConnected = errors.New("mcp: server 无缓存连接(未建连或已被回收)")

ErrNotConnected PingServer 探活时该 server 无缓存连接——懒建连模型下属正常态 (与「有连接但已死」区分,探活无意义不算失败)。

Functions

func CallMeta

func CallMeta(ctx context.Context) map[string]any

CallMeta 从 ctx 取调用元数据;无注入返回 nil(metaClient 对空不注入 _meta)。 返回值可直接作 Pool.RequestMeta:pool.RequestMeta = mcp.CallMeta。

func ExpandEnvRef

func ExpandEnvRef(v string, onMissing func(name string)) string

ExpandEnvRef 展开字符串中的 ${VAR} 环境引用。已定义取环境值;未定义保留 原样(扫描位置跳过本标记,防死循环)并回调 onMissing。

func ExpandEnvRefs

func ExpandEnvRefs(headers map[string]string, onMissing func(name string)) map[string]string

ExpandEnvRefs 对声明式头部表逐值做 ${VAR} 展开(nil/空表原样返回 nil)。 onMissing 可 nil(未定义变量仍保留原样,只是无告警出口)。

func IsToolResultError

func IsToolResultError(err error) bool

IsToolResultError err 链上是否存在工具业务失败(isError:true)。

func OutputSchemaOf

func OutputSchemaOf(t tool.BaseTool) (json.RawMessage, bool)

OutputSchemaOf 取工具的声明 outputSchema(尽力:装饰器链各自转发;断言失败或 未声明返回 false)。

func UnwrapMCPText

func UnwrapMCPText(raw string) string

UnwrapMCPText 解 MCP 工具返回的信封取内层文本;非信封形态原样返回——快照/ 结果进证据条目时,snippet 配额应留给有效数据而非包装层。 信封两种形态:content[].text(标准工具结果,人类可读文本优先);缺失时 structuredContent(较新 MCP 规范的结构化结果)序列化为 JSON——直接把结构化 对象丢给 LLM 优于丢弃。

func WithCallMeta

func WithCallMeta(ctx context.Context, meta map[string]any) context.Context

WithCallMeta 在 ctx 上注入任务级调用元数据(Runner/任务层调用一次,随 ctx 流入该任务全部 MCP 工具调用)。

func WrapErrorAsObservation

func WrapErrorAsObservation(tools []tool.BaseTool) []tool.BaseTool

WrapErrorAsObservation 出口统一包装(幂等:已包装不重复包;非 InvokableTool 原样透传)。

Types

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

func (p *Pool) Hints(server string) map[string]ToolHints

Hints 目录注解快照(server 名 → 工具名 → 注解)。server 未配置或未列举 → nil。 供装饰层做并发治理与风险分级;返回副本,调用方可自由持有。

func (*Pool) PingServer

func (p *Pool) PingServer(ctx context.Context, name string) error

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

func (p *Pool) ReapIdle(maxIdle time.Duration) int

ReapIdle 关闭闲置超过 maxIdle 的缓存连接,返回回收数。闲置时钟 = 最近一次 建连/取工具/探活成功。被回收的 server 下次调用透明重建(evict+lazy 建连)。 在途工具调用(leaseUse 登记)中的连接不回收——原先契约要求 maxIdle 显著大于 最大工具超时,现在由在途计数直接挡下。

func (*Pool) Servers

func (p *Pool) Servers() []string

Servers 返回全部配置的 server 名(字母序,可观测用)。

func (*Pool) StartIdleReaper

func (p *Pool) StartIdleReaper(interval, maxIdle time.Duration)

StartIdleReaper 启动后台闲置回收协程:每 interval 周期执行 ReapIdle(maxIdle)。 Close 停止;重复启动幂等(只起一个)。

func (*Pool) Tools

func (p *Pool) Tools(ctx context.Context, specs []ToolSpec) (ToolsResult, error)

Tools 按 spec 白名单返回 eino 工具与失败面(跨 server 并行拉取)。 spec.Server 未配置 → 报错(配置错误应显式暴露);server 建连/列举失败 → 容忍:记入 Failed(同时经 OnError 发射),可用工具照常返回——列举失败视为 该连接失效,已从缓存摘除关闭(server 崩溃后下次调用自动重建)。 OAuth 授权必需错误 fail-fast 直通(错误返回,不进 Failed)。

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 ToolHints

type ToolHints struct {
	ReadOnly    bool
	Idempotent  bool
	Destructive bool
}

ToolHints 工具注解归一(mcp.ToolAnnotation 子集,nil 视为规范缺省)。

func (ToolHints) ConcurrentSafe

func (h ToolHints) ConcurrentSafe() bool

ConcurrentSafe 读读可并行(readOnly+idempotent,对标 ZCode concurrentSafe); 缺省注解按非安全处理——保守。

func (ToolHints) RiskLevel

func (h ToolHints) RiskLevel() string

RiskLevel 风险级(对标 ZCode:readOnly→low、destructive→high、其余 medium)。

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 工具名白名单;空 = 该 server 全部工具。
	Allow []string
}

ToolSpec 工具白名单:某 server 的哪些工具暴露给 agent。

type ToolsResult

type ToolsResult struct {
	// Tools 装配成功的工具(跨 server 并行拉取,按 specs 序稳定)。
	Tools []tool.BaseTool
	// Failed server → 被容忍的失败原因(建连/列举失败、白名单无一命中)。
	// 失败连接已摘除,下次调用透明重建。空 = 全部成功。OnError 仍发射同源
	// 通知(遥测钩子),失败面的程序化消费一律走这里。
	Failed map[string]error
}

ToolsResult Tools 的结果面(v0.10.38 破坏式:此前返回 []BaseTool,部分失败只 经 OnError 侧面观测——调用方在返回值层面无法区分「失败被容忍」与「真的没 工具」,只能把失败当空表静默降级)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL