package kit import ( "context" "encoding/json" "testing" "github.com/mark3labs/mcp-go/mcp" ) type patchArgs struct { Kind string `json:"kind" jsonschema:"类型"` IDs []int `json:"ids" jsonschema:"编号"` } func TestDefProperties(t *testing.T) { d := Def[patchArgs]{ Name: "patch_test", Title: "补充 schema", Description: "测试", ReadOnly: true, Handler: func(context.Context, patchArgs) (*mcp.CallToolResult, error) { return nil, nil }, Properties: map[string]map[string]any{ "kind": {"enum": []string{"pid", "vid"}}, "ids": {"type": "array", "minItems": 1, "items": map[string]any{"type": "integer", "minimum": 0}}, }, } var schema struct { Properties map[string]map[string]any `json:"properties"` Required []string `json:"required"` } if err := json.Unmarshal(d.Tool().RawInputSchema, &schema); err != nil { t.Fatal(err) } ids := schema.Properties["ids"] if ids["type"] != "array" { t.Errorf("ids.type 应为 array(不再可空),实际 %v", ids["type"]) } if ids["description"] != "编号" { t.Errorf("补充约束不应覆盖生成的描述,实际 %v", ids["description"]) } if items, _ := ids["items"].(map[string]any); items["minimum"] != float64(0) { t.Errorf("ids.items.minimum 未生效:%v", ids["items"]) } if enum, _ := schema.Properties["kind"]["enum"].([]any); len(enum) != 2 { t.Errorf("kind.enum 未生效:%v", schema.Properties["kind"]) } if len(schema.Required) != 2 { t.Errorf("required 应保持不变,实际 %v", schema.Required) } } func TestDefPropertiesUnknownField(t *testing.T) { defer func() { if recover() == nil { t.Error("补充不存在的字段应 panic") } }() Def[patchArgs]{Name: "patch_bad", Properties: map[string]map[string]any{"nope": {"type": "string"}}}.Tool() } func TestDefHints(t *testing.T) { h := func(context.Context, NoArgs) (*mcp.CallToolResult, error) { return nil, nil } cases := []struct { def Def[NoArgs] destructive, idem bool }{ {Def[NoArgs]{Name: "ro", ReadOnly: true, Handler: h}, false, true}, {Def[NoArgs]{Name: "write", Handler: h}, false, false}, {Def[NoArgs]{Name: "overwrite", Destructive: true, Handler: h}, true, false}, {Def[NoArgs]{Name: "dedup", Idempotent: true, Handler: h}, false, true}, } for _, c := range cases { a := c.def.Tool().Annotations if *a.DestructiveHint != c.destructive || *a.IdempotentHint != c.idem { t.Errorf("%s: destructive=%v idempotent=%v,期望 %v %v", c.def.Name, *a.DestructiveHint, *a.IdempotentHint, c.destructive, c.idem) } } }