runtime

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package runtime provides the hand-written runtime substrate for the auto-generated MCP tool registrations under mcp/tools.

Index

Constants

This section is empty.

Variables

View Source
var ShutdownHooks []func()

ShutdownHooks 是进程优雅退出前要同步执行的钩子(如关闭会话、杀掉子进程)。 由业务包 init() 里 append;进程收到退出信号时由 gtask.BeforeShutdown 回调统一执行。

View Source
var StartupHooks []func(context.Context)

StartupHooks 是 server 启动时要执行的钩子(如启动后台 GC 协程)。 由各业务包在自己的 init() 里 append,避免 runtime 反向 import 业务包造成循环依赖。

Functions

func AnyInputSchema

func AnyInputSchema[T any]() *jsonschema.Schema

AnyInputSchema 反射出 T 的输入 schema,并把其中所有「无类型约束」节点 (interface{} / []any 的 items / map[string]any 的 additionalProperties 等) 放宽为 anyTypes 类型联合。生成器对含 interface{} 入参的工具用它显式设置 Tool.InputSchema,从而绕过 SDK 默认反射产生的空 schema。

func AuthzMiddleware

func AuthzMiddleware(authz *Authz) mcp.Middleware

AuthzMiddleware 在 tools/call 做 token + 按人的鉴权,tools/list 只按 token 过滤。

func BuildServer

func BuildServer(cfg Config, registrar Registrar) *mcp.Server

BuildServer 构造并配置好一个 MCP server(注册工具、spill 资源、日志中间件), 供 HTTP 挂载(MCPHandler)或独立启动(Run)复用。

func HTTPAuditHeaders

func HTTPAuditHeaders(next http.Handler) http.Handler

HTTPAuditHeaders 是一个纯审计用的 HTTP 中间件:按配置的 header 名单从请求头取值, 注入 ctx,供 LoggingMiddleware 写入 MCP 审计日志。与鉴权无关,不影响放行逻辑。 名单为空时不做任何事,零开销透传。

func HTTPAuthContext

func HTTPAuthContext(next http.Handler, authz *Authz) http.Handler

HTTPAuthContext 包一层 http.Handler:解析 Authorization(能力 token)与 X-MCP-User(人身份),注入请求 ctx。token 缺失/无效直接 401。

func HTTPLogID

func HTTPLogID(next http.Handler) http.Handler

HTTPLogID 解析或生成本次请求的 logid:优先取配置头(默认 X-Log-Id),缺失则生成; 注入 ctx(供审计/access 日志读取),并回写同名响应头供上游网关串联。

func InitAuditConfig

func InitAuditConfig(path string)

InitAuditConfig 从 mcp.toml 加载 [audit] 段并设置审计 header 名单。 path 为空或文件不存在(stdio / 单测场景)静默置空;其他 stat / 解析失败则告警后置空—— 审计 header 配置不正确不应导致服务起不来。

func InitLogConfig

func InitLogConfig(path string)

InitLogConfig 从 mcp.toml 加载 log 段并设置 logid 头名。 path 为空 / 文件不存在 / 解析失败时静默或告警后回退默认头名——不影响启动。

func InitSpillConfig

func InitSpillConfig(path string)

InitSpillConfig 从 mcp.toml 加载 spill 配置并设置阈值。 文件不存在(stdio / 单测场景)静默用默认值;其他 stat 失败或解析失败则告警后用默认值—— 阈值不正确不应导致服务起不来。

func InitSpillStore

func InitSpillStore(ctx context.Context, dir string, ttl spillTTLConfig)

InitSpillStore 幂等初始化磁盘 store:建目录 + reconcile + 启动 GC。 dir 为空时用 <os.TempDir>/mcp-toolify/spill。TTL 各项为 0 时使用默认值。

func LogIDFromContext

func LogIDFromContext(ctx context.Context) string

LogIDFromContext 取出 ctx 中的 logid,缺失返回 ""。

func LoggingMiddleware

func LoggingMiddleware() mcp.Middleware

LoggingMiddleware 返回一个 receiving middleware,记录每次 MCP RPC。

若已通过 SetAuditLogger 注入 logger,则以结构化字段写入审计日志,字段包含:

  • logid:本次请求的日志 ID(由 HTTPLogID 注入),与 access 日志共享,用于串联同一请求
  • user:执行人(HTTP 头 X-MCP-User 透传)
  • token_name:本次调用所用 token 的用途名(配置 [[tokens]].name),用于审计追溯接入通道
  • tool / args:调用的工具名与入参 JSON
  • result:返回结果 JSON(截断)
  • cost:耗时;err / tool_error:错误信息
  • 由 [audit] headers 配置指定的请求头:每个 header 一个独立字段(字段名为 header 名小写)

未注入 logger 时回退到标准 log(stdio 场景)。

func MCPHandler

func MCPHandler(cfg Config, s *mcp.Server) (http.Handler, error)

MCPHandler 返回处理 MCP 协议(Streamable HTTP)的 http.Handler,用于挂载到既有 HTTP server。该 handler 不依赖具体请求路径,可挂在任意子路径。

cfg.AuthzEnabled 为 true 时叠加连接级能力 + 调用级风险鉴权,鉴权配置读取 cfg.ConfigPath。

func MaybeSpill

func MaybeSpill(toolName string, raw any, structured any) (*mcp.CallToolResult, any, error)

MaybeSpill 按结果体积决定返回形态:估算 token 数超过配置阈值时落盘为 spill 资源, 否则原样返回 structuredContent。

raw 是原始返回值(用于 json/jsonl 格式推导与体积测量),structured 是打包后的 structuredContent(形如 map[string]any{"result": raw})。序列化失败时记日志后 退回内联路径交给 SDK 处理,保持与旧行为一致;落盘失败时同样降级为内联返回, 不影响工具调用成功——spill 只是上下文体积优化,不该把成功的调用变成失败。

因此第三个返回值目前恒为 nil,仅保留签名位以便将来扩展(生成的 handler 依赖 这个三返回值形状)。生成的 handler 以 `return MaybeSpill(...)` 形式调用它, 工具函数本身不受影响。

func NewAuthzHandler

func NewAuthzHandler(s *mcp.Server, authz *Authz) http.Handler

NewAuthzHandler 构造启用连接级鉴权的 stateless HTTP handler。 Stateless:每个请求独立成会话,逐次重读 Authorization / X-MCP-User, 实现调用级身份透传(多人共用一条 agent 连接的场景)。供 runHTTP 与测试复用。

func NewOwnedSpillID added in v0.4.0

func NewOwnedSpillID() string

NewOwnedSpillID 生成带本实例归属(host:port)的 spill id,供 sysprobe 等外部包 为自管的 spill 文件命名。多副本部署下,spill_explore 及外部工具据此把「本地未命中 但归属为兄弟副本」的请求单跳代理到属主实例(见 spill_id.go / spill_peer.go)。 未设置对外地址(stdio/未 SetSpillBaseURL)时退回纯随机 id,行为与单机一致。

func NewSpillID

func NewSpillID() string

NewSpillID 导出 id 生成,供 sysprobe 等外部包复用同一套 id 约定。

func NewSpillIDForOwnerTest added in v0.2.0

func NewSpillIDForOwnerTest(hostPort string) string

NewSpillIDForOwnerTest 供其它包测试构造指定归属的 spill id。

func OwnerOf added in v0.4.0

func OwnerOf(id string) (hostPort string, ok bool)

OwnerOf 解出 owned spill id 内嵌的属主 host:port(见 spill_id.go)。 ok=false 表示旧式/无归属 id。中性命名,供通用 owner 路由复用。

func RegisterMeta

func RegisterMeta(m ToolMeta)

RegisterMeta 登记一个工具的元数据(供生成代码调用)。

func RegisterOwnerRouted added in v0.4.0

func RegisterOwnerRouted(toolName, paramName string)

RegisterOwnerRouted 声明「工具 toolName 按参数 paramName(owned id)路由」。 应在 init/启动期调用,早于开始处理请求。

func RegisterSpillResource

func RegisterSpillResource(s *mcp.Server)

RegisterSpillResource 注册 spill://{id} 资源模板,使客户端可以 resources/read 读取此前 SpillResult 落盘的内容。由 runtime.Run 在 server 启动时调用。

func ResolveSpillPath

func ResolveSpillPath(id string) (string, bool)

ResolveSpillPath 供外部工具包(如 spill_explore)按 id 定位 spill 文件路径。

func Run

func Run(ctx context.Context, cfg Config, registrar Registrar) error

Run starts the MCP server with the given registrar.

启动后会向标准日志(log 包)打印监听信息:

  • stdio:打印 "MCP server running on stdio"
  • http:打印 "MCP server listening on http://<addr>" (含实际端口)

func RunShutdownHooks

func RunShutdownHooks()

RunShutdownHooks 依次执行所有已注册的退出钩子。幂等由各钩子自身保证。

func SetAuditHeaders

func SetAuditHeaders(names []string)

SetAuditHeaders 设置需要进审计日志的 header 名单(去空白、去空项,按小写保序去重)。

func SetAuditLogger

func SetAuditLogger(l Logger)

SetAuditLogger 注入 MCP 审计日志 logger。应在 server 启动前调用。

func SetLogIDHeader

func SetLogIDHeader(name string)

SetLogIDHeader 设置 logid 头名;空值归一化为默认值。

func SetSpillBaseURL

func SetSpillBaseURL(base string)

SetSpillBaseURL 设置 spill 下载端点的对外基础地址。跨机部署时应传入 agent 可直连的地址;传空串表示当前传输不提供 HTTP 下载(如 stdio)。

func SetSpillPeer added in v0.2.0

func SetSpillPeer(token string, timeoutMS int)

SetSpillPeer 设置副本间代理的共享密钥与超时。timeoutMS<=0 归一化为默认 5000ms。 转发白名单不在此设置——见 SetSpillPeerProvider / SetSpillPeers。

func SetSpillPeerProvider added in v0.2.0

func SetSpillPeerProvider(fn func() []string)

SetSpillPeerProvider 注册动态兄弟副本发现函数:每次代理白名单校验时实时调用它,返回当前 可达的兄弟副本 host:port 列表。用它对接任意服务发现,无需静态配置。传 nil 清除(回退到 无兄弟副本,即拒绝一切远端转发)。与 SetSpillPeers 互为覆盖,后调用者生效。

func SetSpillPeers added in v0.2.0

func SetSpillPeers(hosts []string)

SetSpillPeers 设置静态兄弟副本列表(通常来自配置),内部包装成返回该快照的 provider。 与 SetSpillPeerProvider 互为覆盖:后调用者生效。空列表等价于无兄弟副本。

func SetSpillThreshold

func SetSpillThreshold(tokens int)

SetSpillThreshold 设置自动 spill 的 token 阈值。 配置语义:传 0(含配置缺省)归一化为 defaultMaxResultTokens; 负数关闭自动 spill,规范写法为 -1,小于 -1 的值视为配置疑似有误,归一化为 -1 并告警。

func SpillDir added in v0.4.0

func SpillDir() string

SpillDir 返回框架 spill 文件的落盘目录。外部工具包(如 sysprobe)应把自管的 spill 文件写到该目录,以便与框架共用同一套 GC、下载端点与 spill_explore 解析。

func SpillDirForTest added in v0.2.0

func SpillDirForTest() string

SpillDirForTest 返回当前全局 spill store 目录,供跨包测试落文件。

func SpillDownloadHandler

func SpillDownloadHandler() http.Handler

SpillDownloadHandler 返回一个 http.Handler,按 /spill/<id> 路径把此前 SpillResult 落盘的文件直接作为可下载内容返回。挂到 MCP server 同一个 HTTP 端口上,供跨机 agent 直连下载。未命中/过期返回 404。

func SpillDownloadURLFor

func SpillDownloadURLFor(id string) string

SpillDownloadURLFor 返回该 id 可选的直连下载 URL;未配置对外地址时为空串。

func SpillHandler

func SpillHandler() http.Handler

SpillHandler 返回 /spill/<id> 大结果下载端点的 http.Handler。 与 MCPHandler 挂在同一个 HTTP server 上即可供 agent 直连下载。

func SpillPeerAllowed added in v0.2.0

func SpillPeerAllowed(hostPort string) bool

SpillPeerAllowed 返回 hostPort 是否为当前已知的兄弟副本之一(仅这些地址允许被代理)。 provider 未注册或返回空时返回 false(默认拒绝一切远端转发,防 SSRF/密钥外泄的安全默认)。

func SpillPeerTimeout added in v0.2.0

func SpillPeerTimeout() time.Duration

SpillPeerTimeout 返回代理调用超时。

func SpillPeerToken added in v0.2.0

func SpillPeerToken() string

SpillPeerToken 返回共享密钥;空串表示跨副本代理关闭。

func SpillResult

func SpillResult(toolName string, out any) (*mcp.CallToolResult, error)

SpillResult 把工具返回值按推导出的格式(json/jsonl)序列化并落到磁盘文件, 返回一个只含摘要 + ResourceLink 的 CallToolResult。toolName 用于文件名与摘要文案。

无条件落盘,供手写工具(sysprobe / terminal_* 等)在明确知道结果很大时直接调用。 生成的 handler 走 MaybeSpill,按体积自动判定。

func SpillSelfHostPort added in v0.2.0

func SpillSelfHostPort() string

SpillSelfHostPort 返回本实例对外 host:port(无对外地址时为空)。

func ToolError

func ToolError(err error) *mcp.CallToolResult

ToolError converts a Go error into an IsError CallToolResult so callers can distinguish tool failures from protocol-level errors.

func WithAuthContext

func WithAuthContext(ctx context.Context, ac AuthContext) context.Context

WithAuthContext 把鉴权上下文注入 ctx。

func WithLogID

func WithLogID(ctx context.Context, id string) context.Context

WithLogID 把 logid 注入 ctx。

func WithOwnerRouting added in v0.4.0

func WithOwnerRouting(next http.Handler) http.Handler

WithOwnerRouting 包裹上游 MCP handler:tools/call 若其声明的路由参数是归属兄弟副本的 owned id,则把整条调用反代到该副本 /mcp(属主本地执行);其余交 next 本地处理。

Types

type AuditConfig

type AuditConfig struct {
	// Headers 是需要额外写入 MCP 审计日志的请求头名称列表。
	// 每个 header 会以独立字段落在审计日志里,字段名为该 header 名的小写形式
	// (如 X-Tenant-Id -> x-tenant-id)。缺失或空值记为 "-"。
	Headers []string `toml:"headers"`
}

AuditConfig 是审计相关配置(对应 mcp.toml 的 [audit] 段)。

func LoadAuditConfig

func LoadAuditConfig(path string) (AuditConfig, error)

LoadAuditConfig 从指定 TOML 文件读取 [audit] 段。

type AuthContext

type AuthContext struct {
	Caps      TokenCaps // 由 Authorization token 决定的读/写风险上限
	Identity  string    // 调用人身份,取配置身份头列表(默认 [X-MCP-User])中第一个非空值;可能为空
	TokenName string    // token 用途名(配置里的 name),用于审计日志
}

AuthContext 是从 HTTP header 解析出的连接/调用鉴权上下文。

func AuthFromContext

func AuthFromContext(ctx context.Context) (AuthContext, bool)

AuthFromContext 取出鉴权上下文。

type Authz

type Authz struct {
	RiskAuthorizer
	// contains filtered or unexported fields
}

Authz 聚合 token->读写风险上限 映射与按人风险判定。

func NewAuthz

func NewAuthz(cfg AuthzConfig) *Authz

NewAuthz 从配置构造 Authz。

func (*Authz) CapsOf

func (a *Authz) CapsOf(token string) (TokenCaps, bool)

CapsOf 返回 token 对应的读/写风险上限;token 缺失/未配置时 ok=false(应拒绝连接)。

func (*Authz) IdentityHeaders

func (a *Authz) IdentityHeaders() []string

IdentityHeaders 返回取调用人身份的有序请求头名;未配置时回退 [X-MCP-User]。

func (*Authz) ResolveIdentity

func (a *Authz) ResolveIdentity(get func(name string) string) string

ResolveIdentity 按配置的头名顺序取第一个非空值作为调用人身份;都为空返回 ""。 get 通常为 http.Header.Get。

type AuthzConfig

type AuthzConfig struct {
	Tokens        []TokenEntry        `toml:"tokens"`
	RiskAllowlist map[string][]string `toml:"risk_allowlist"` // level -> 身份列表
	// IdentityHeaders 指定取调用人身份的请求头名(有序):按从前到后的顺序,取第一个
	// 在请求中非空的头值作为身份,用于按人鉴权与审计(user 字段)。缺省/为空时用
	// defaultIdentityHeader(X-MCP-User)。由可信网关注入,服务端直接信任其值。
	IdentityHeaders []string `toml:"identity_headers"`
}

AuthzConfig 是 HTTP 鉴权的配置(对应 conf/mcp/mcp.toml)。

func LoadAuthzConfig

func LoadAuthzConfig(path string) (AuthzConfig, error)

LoadAuthzConfig 从指定 TOML 文件加载鉴权配置。

func (AuthzConfig) Validate

func (c AuthzConfig) Validate() error

Validate 校验 token 配置的基本合法性与审计元信息完整性: token 为空、token 重复、缺 name、缺 applicant 均返回 error, 启动阶段应据此失败,避免上线不可用或无法追溯来源的 token。

错误信息用配置里的序号定位条目,绝不回显 token 值(错误会进日志/终端)。 存在多个问题时只报第一个。

type Capability

type Capability int

Capability 表示一个工具的读/写类别(由其 mcp:tags 是否含 write 派生)。

const (
	ReadOnly Capability = iota
	ReadWrite
)

type Config

type Config struct {
	Transport string   // "stdio" | "http"
	Addr      string   // http listen addr,例如 ":8080";为空时由系统分配端口
	Enable    []string // package-name whitelist
	Tags      []string // tag whitelist

	// PublicBaseURL 是 agent 侧可直连的对外基础地址(如 http://host:8011)。
	// 跨机部署时必须设置,spill 下载 URL 会基于它拼接;为空时回退到实际监听地址
	// (仅适用于同机/本地场景)。
	PublicBaseURL string

	// ConfigPath 指向包含 [spill] 与 [[tokens]]/[risk_allowlist] 段的 TOML 文件。
	// 为空时:spill 阈值用默认值;若 AuthzEnabled=true 则启动报错(鉴权必须有配置)。
	ConfigPath string

	// SpillDir 是大返回结果落盘目录。为空时用 <os.TempDir>/mcp-toolify/spill。
	SpillDir string

	// AuthzEnabled 为 true 时(仅 http 生效)启用连接级能力 + 调用级风险鉴权,
	// 配置来自 ConfigPath。默认关闭。
	AuthzEnabled bool
}

Config controls server startup behavior.

type Field

type Field struct {
	Key   string
	Value string
}

Field is a single structured field in an audit log record.

func String

func String(key, val string) Field

String builds a string-valued audit field.

type LogConfig

type LogConfig struct {
	// LogIDHeader 是读取入站 logid 的请求头名,同时作为回写响应头名。
	// 缺省用 defaultLogIDHeader(X-Log-Id)。
	LogIDHeader string `toml:"logid_header"`
}

LogConfig 是日志相关配置(对应 mcp.toml 的 log 段)。

func LoadLogConfig

func LoadLogConfig(path string) (LogConfig, error)

LoadLogConfig 从指定 TOML 文件读取 log 段。

type Logger

type Logger interface {
	Notice(msg string, fields ...Field)
	Warning(msg string, fields ...Field)
}

Logger is the audit sink for MCP tool calls. Implementations receive a short message tag (always "mcp_call") plus structured fields (user, tool, args, result, cost, ...). Notice is used for successful calls, Warning for calls that returned an error or an IsError tool result.

Injecting a Logger is optional: when none is set (see SetAuditLogger), the runtime falls back to the standard library log package. This keeps the framework free of any specific logging dependency.

type RegisterOptions

type RegisterOptions struct {
	Enable []string // package-name whitelist
	Tags   []string // tag whitelist
}

RegisterOptions controls which generated tools get registered with the server. Empty Enable / Tags means "no filter".

func (RegisterOptions) Allow

func (o RegisterOptions) Allow(pkg string, tags []string) bool

Allow reports whether a tool from the given package with the given tags passes the configured filters.

type Registrar

type Registrar func(s *mcp.Server, opts RegisterOptions)

Registrar is the function generated tools expose (typically tools.RegisterAll).

type RiskAuthorizer

type RiskAuthorizer interface {
	CanRun(identity string, level RiskLevel) bool
}

RiskAuthorizer 判定某身份是否可执行到指定风险等级。

本期由 staticAuthorizer(读配置白名单)实现;未来可替换为按邮件组成员 每 20min 刷新的实现——仅需实现该接口,其余代码不动。

type RiskLevel

type RiskLevel int

RiskLevel 表示单个工具的风险等级;缺省为 RiskNone。

const (
	RiskNone RiskLevel = iota
	RiskLow
	RiskMedium
	RiskHigh
)

func ParseRisk

func ParseRisk(s string) (RiskLevel, bool)

ParseRisk 解析 mcp:risk 标记或配置中的风险字符串。空串视为 none。

func (RiskLevel) String

func (r RiskLevel) String() string

String 返回风险等级的可读名(用于错误文案)。

type SpillConfig

type SpillConfig struct {
	// MaxResultTokens 为工具返回值的 token 阈值:超过则自动落盘为 spill 资源。
	// 0 或缺省表示用 defaultMaxResultTokens;负数关闭自动 spill,规范写法为 -1。
	MaxResultTokens int `toml:"max_result_tokens"`
	// PeerToken 为副本间内部 /spill-explore 端点的共享密钥;为空表示关闭跨副本代理(安全默认)。
	PeerToken string `toml:"peer_token"`
	// PeerTimeoutMS 为代理调用超时(毫秒);0 表示用默认 5000。
	PeerTimeoutMS int `toml:"peer_timeout_ms"`
	// PeerHosts 为可选的静态代理白名单(host:port);多副本部署通常改用 SetSpillPeerProvider
	// 经服务发现动态提供,无需在此配置。为空且未注册 provider 时不允许任何远端转发(安全默认)。
	PeerHosts []string `toml:"peer_hosts"`
}

SpillConfig 是 spill 行为配置(对应 conf/mcp/mcp.toml 的 [spill] 段)。

func LoadSpillConfig

func LoadSpillConfig(path string) (SpillConfig, error)

LoadSpillConfig 从指定 TOML 文件读取 [spill] 段。

type SpillFormat

type SpillFormat string

SpillFormat 是 spill 文件声明的内容格式。

const (
	FormatJSON  SpillFormat = "json"  // .json
	FormatJSONL SpillFormat = "jsonl" // .jsonl
	FormatText  SpillFormat = "text"  // .txt
)

type TokenCaps

type TokenCaps struct {
	ReadOK  bool
	Read    RiskLevel
	WriteOK bool
	Write   RiskLevel
	// Name 是 token 的用途标识,仅用于审计日志,不参与权限判定。
	Name string
}

TokenCaps 是一个 token 解析后的读/写风险上限。 ReadOK/WriteOK 为 false 表示该类操作完全不允许。

type TokenEntry

type TokenEntry struct {
	Token string `toml:"token"`
	// Name 是 token 的用途标识(如 readonly-agent),会写入审计日志的 token_name 字段,
	// 用于定位一次调用走的是哪条接入通道。必填。
	Name string `toml:"name"`
	// Applicant 是申请人标识(requester id),仅留在配置里用于审计追溯(按 token_name 反查),不进日志。必填。
	Applicant string `toml:"applicant"`
	Read      string `toml:"read"`  // 读操作最高风险;空 => 不允许读
	Write     string `toml:"write"` // 写操作最高风险;空 => 不允许写
}

TokenEntry 是单个 token 的配置:审计元信息 + 分别设置读/写允许的最高风险等级。 read/write 取 none|low|medium|high;省略某字段表示该类操作完全不允许。

type ToolMeta

type ToolMeta struct {
	Name       string
	Capability Capability
	Risk       RiskLevel
}

ToolMeta 记录单个工具的鉴权相关元数据,由生成代码在注册时登记。

func LookupMeta

func LookupMeta(name string) (ToolMeta, bool)

LookupMeta 查询工具元数据。未登记的工具(如内置 spill resource)返回 false。

Jump to

Keyboard shortcuts

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