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 }