package mcpserver import ( "context" "encoding/json" "strings" "testing" "github.com/google/jsonschema-go/jsonschema" "github.com/modelcontextprotocol/go-sdk/mcp" "git.warky.dev/wdevs/amcs/internal/tools" ) func TestSetToolSchemasUsesStringUUIDsInListOutput(t *testing.T) { tool := &mcp.Tool{Name: "list_thoughts"} if err := setToolSchemas[tools.ListInput, tools.ListOutput](tool); err != nil { t.Fatalf("set tool schemas: %v", err) } schema, ok := tool.OutputSchema.(*jsonschema.Schema) if !ok { t.Fatalf("output schema type = %T, want *jsonschema.Schema", tool.OutputSchema) } thoughtsSchema := schema.Properties["thoughts"] if thoughtsSchema == nil { t.Fatal("missing thoughts schema") } if thoughtsSchema.Items == nil { t.Fatal("missing thoughts item schema") } idSchema := thoughtsSchema.Items.Properties["id"] if idSchema == nil { t.Fatal("missing id schema") } if idSchema.Type != "string" { t.Fatalf("id schema type = %q, want %q", idSchema.Type, "string") } if idSchema.Format != "uuid" { t.Fatalf("id schema format = %q, want %q", idSchema.Format, "uuid") } } func TestTruncateArgsRedactsSensitiveFields(t *testing.T) { args := json.RawMessage(`{ "query": "todo from yesterday", "content": "private thought body", "content_base64": "c2VjcmV0LWJpbmFyeQ==", "email": "user@example.com", "nested": { "notes": "private note", "phone": "+1-555-0100", "keep": "visible" } }`) got := truncateArgs(args) for _, secret := range []string{ "private thought body", "c2VjcmV0LWJpbmFyeQ==", "user@example.com", "private note", "+1-555-0100", } { if strings.Contains(got, secret) { t.Fatalf("truncateArgs leaked sensitive value %q in %s", secret, got) } } for _, expected := range []string{ `"query":"todo from yesterday"`, `"keep":"visible"`, `"content":"\u003credacted\u003e"`, `"content_base64":"\u003credacted\u003e"`, `"email":"\u003credacted\u003e"`, `"notes":"\u003credacted\u003e"`, `"phone":"\u003credacted\u003e"`, } { if !strings.Contains(got, expected) { t.Fatalf("truncateArgs(%s) missing %q", got, expected) } } } func TestAddToolReturnsSchemaErrorInsteadOfPanicking(t *testing.T) { server := mcp.NewServer(&mcp.Implementation{Name: "test", Version: "0.0.1"}, nil) err := addTool(server, nil, &mcp.Tool{Name: "broken"}, func(_ context.Context, _ *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, chan int, error) { return nil, nil, nil }) if err == nil { t.Fatal("addTool() error = nil, want schema inference error") } if !strings.Contains(err.Error(), `configure MCP tool "broken" schemas`) { t.Fatalf("addTool() error = %q, want tool context", err.Error()) } }