feat(mcp): 协议层换成官方 Model Context Protocol SDK,删自研实现(裁决 10.4.6 + AGENTS §9.5)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 新增依赖:github.com/modelcontextprotocol/go-sdk v1.8.0(direct)+ github.com/google/jsonschema-go v0.4.3
  (SDK 自带依赖,直接用于 schema 校验/默认值,避免再造一份);go.sum 纯新增
- 删除自研协议层:rpc.go / stdio.go / http.go / sse.go 及其测试
- 用 SDK 的成熟逻辑:命令传输(stdio 子进程)/ SSE / Streamable HTTP、协议版本协商与
  -32022 回退、keepalive(含失败阈值)、tools/list_changed 订阅、能力协商(InitializeResult.Capabilities)
- 保留自研的四件事(其余零自研):配置→传输、发现→registry 注册、能力族推断、schema 缓存(Prepare 命中不重复解析)
- 能力闸诚实化:服务器声明 capabilities 但不含 tools 时 ListTools/DiscoverTools 返回
  ErrCapabilityNotDeclared(不静默空集);完全不声明 capabilities 的老式服务器仍按 legacy 处理
- 复核:build 绿 + capability 全包测试绿(mcp 42 用例,含真子进程 stdio / httptest Streamable HTTP /
  内存传输三类假 server,不依赖外网)+ `-race` 干净;变异 2 条(featuresFrom 恒 true / 删 applySchema 调用)已还原
- 无 REST/WS/env/数据目录变更;包内 API 有增删(见回报),仓外调用方签名未变(未改 cmd/cyrene 与 plugin/manager)
This commit is contained in:
AskaEth committed 2026-10-04 13:53:47 +08:00
1 parent 7b05b4bfa9
commit a1083a322f
26 files changed
+1903 -3011

No files matched your search

+84
View File
@@ -0,0 +1,84 @@
package mcp
import (
"encoding/json"
"fmt"
"github.com/google/jsonschema-go/jsonschema"
)
// schemaMap 把 SDK 传来的 input schema 规整成 map[string]any;nil 或无法识别时
// 退化为「无约束的对象 schema」,保证 Parameters() 永远能返回可用形状。
func schemaMap(v any) map[string]any {
switch s := v.(type) {
case nil:
return emptyObjectSchema()
case map[string]any:
return s
case json.RawMessage:
return decodeSchema(s)
case []byte:
return decodeSchema(s)
default:
data, err := json.Marshal(v)
if err != nil {
return emptyObjectSchema()
}
return decodeSchema(data)
}
}
// emptyObjectSchema 返回无约束的空对象 schema。
func emptyObjectSchema() map[string]any {
return map[string]any{"type": "object", "properties": map[string]any{}}
}
// decodeSchema 把 JSON 文本解成 schema map,失败时退回空对象 schema。
func decodeSchema(data []byte) map[string]any {
out := map[string]any{}
if err := json.Unmarshal(data, &out); err != nil {
return emptyObjectSchema()
}
return out
}
// resolveSchema 把原始 schema 解析成可校验、可补默认值的已解析 schema。
func resolveSchema(raw map[string]any) (*jsonschema.Resolved, error) {
data, err := json.Marshal(raw)
if err != nil {
return nil, fmt.Errorf("marshal input schema: %w", err)
}
var s jsonschema.Schema
if err := json.Unmarshal(data, &s); err != nil {
return nil, fmt.Errorf("parse input schema: %w", err)
}
resolved, err := s.Resolve(&jsonschema.ResolveOptions{ValidateDefaults: true})
if err != nil {
return nil, fmt.Errorf("resolve input schema: %w", err)
}
return resolved, nil
}
// applySchema 按已解析的 input schema 先补默认值、再校验参数。
// resolved 为 nil 表示 schema 不可解析,此时降级为不校验。
// ApplyDefaults 对病态默认值会 panic,这里兜住转成错误,避免拖垮调用方。
func applySchema(resolved *jsonschema.Resolved, args map[string]any) (err error) {
if resolved == nil {
return nil
}
if args == nil {
args = map[string]any{}
}
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("input schema default application panicked: %v", r)
}
}()
if err = resolved.ApplyDefaults(&args); err != nil {
return fmt.Errorf("apply input schema defaults: %w", err)
}
if err = resolved.Validate(args); err != nil {
return fmt.Errorf("arguments do not match input schema: %w", err)
}
return nil
}