{"record":{"id":"11f9f935d2643f41","repo":"siyuan-note/siyuan","slug":"property-q-duplicate-x-mcp-header-value-q","errorCode":null,"errorMessage":"property %q: duplicate x-mcp-header value %q","messagePattern":"property %q: duplicate x-mcp-header value %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/validation.go","lineNumber":254,"sourceCode":"\t\t\t\tpath = prefix + \".\" + propertyName\n\t\t\t}\n\t\t\tif rawHeader, exists := property[\"x-mcp-header\"]; exists {\n\t\t\t\theader, ok := rawHeader.(string)\n\t\t\t\tif !ok || header == \"\" {\n\t\t\t\t\treturn fmt.Errorf(`property %q: x-mcp-header must be a non-empty string`, path)\n\t\t\t\t}\n\t\t\t\tpropertyType, _ := property[\"type\"].(string)\n\t\t\t\tif propertyType != \"string\" && propertyType != \"integer\" && propertyType != \"boolean\" {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t`property %q: x-mcp-header can only be applied to primitive types (integer, string, boolean), got %q`,\n\t\t\t\t\t\tpath, propertyType)\n\t\t\t\t}\n\t\t\t\tif !validHTTPFieldName(header) {\n\t\t\t\t\treturn fmt.Errorf(`property %q: x-mcp-header value %q is not a valid HTTP field name`, path, header)\n\t\t\t\t}\n\t\t\t\tnormalized := strings.ToLower(header)\n\t\t\t\tif seen[normalized] {\n\t\t\t\t\treturn fmt.Errorf(`property %q: duplicate x-mcp-header value %q`, path, header)\n\t\t\t\t}\n\t\t\t\tseen[normalized] = true\n\t\t\t}\n\t\t\tnested, _ := property[\"properties\"].(map[string]any)\n\t\t\tif err := walk(nested, path); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\treturn walk(properties, \"\")\n}\n\nfunc validHTTPFieldName(name string) bool {\n\tif name == \"\" {\n\t\treturn false\n\t}\n\tfor _, character := range name {","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/tools/validation.go#L236-L272","documentation":"Thrown by validateParamHeaderAnnotations when two (or more) properties declare the same x-mcp-header value, compared case-insensitively (the value is lowercased before the duplicate check). HTTP header names are case-insensitive, so two properties binding to the same header would conflict and the request behavior would be ambiguous.","triggerScenarios":"Registering a tool where, e.g., property \"userId\" has x-mcp-header \"User-Id\" and property \"userID\" has x-mcp-header \"user-id\"; or the same header name reused across nested object properties (the walker recurses into nested properties).","commonSituations":"Copy-pasting a property and forgetting to change the header; mixing case conventions (\"X-Trace-Id\" vs \"x-trace-id\"); nested objects reusing a parent's header name.","solutions":["Give each header-bound property a distinct header name.","Normalize all x-mcp-header values to a single casing convention (e.g. Title-Case-With-Hyphens) to make duplicates obvious.","If two properties legitimately feed the same header, combine them into one property and format the value in the handler."],"exampleFix":"// before\n{\"a\": {\"type\": \"string\", \"x-mcp-header\": \"X-Trace-Id\"},\n \"b\": {\"type\": \"string\", \"x-mcp-header\": \"x-trace-id\"}}\n// after\n{\"a\": {\"type\": \"string\", \"x-mcp-header\": \"X-Trace-Id\"},\n \"b\": {\"type\": \"string\", \"x-mcp-header\": \"X-Span-Id\"}}","handlingStrategy":"validation","validationCode":"seen := map[string]bool{}\nfor _, prop := range props {\n    if h, ok := prop[\"x-mcp-header\"].(string); ok && h != \"\" {\n        key := strings.ToLower(h)\n        if seen[key] { return fmt.Errorf(\"duplicate header %q\", h) }\n        seen[key] = true\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt a single casing convention for header names to surface duplicates.","Give each header-bound property a distinct, purpose-specific header name.","Run a schema linter that flags duplicate (case-insensitive) headers."],"tags":["mcp","json-schema","http-header","duplicate","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}