{"record":{"id":"0e9e9fa2edefcab0","repo":"siyuan-note/siyuan","slug":"property-q-x-mcp-header-must-be-a-non-empty-stri","errorCode":null,"errorMessage":"property %q: x-mcp-header must be a non-empty string","messagePattern":"property %q: x-mcp-header must be a non-empty string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/validation.go","lineNumber":241,"sourceCode":"\t\treturn nil\n\t}\n\tproperties, _ := root[\"properties\"].(map[string]any)\n\tseen := map[string]bool{}\n\tvar walk func(map[string]any, string) error\n\twalk = func(props map[string]any, prefix string) error {\n\t\tfor propertyName, rawProperty := range props {\n\t\t\tproperty, ok := rawProperty.(map[string]any)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpath := propertyName\n\t\t\tif prefix != \"\" {\n\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 {","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/tools/validation.go#L223-L259","documentation":"During MCP tool schema validation, a property that declares x-mcp-header must carry a string value that is not empty. This extension keyword maps a schema property to an HTTP header, so a non-string or empty value is meaningless and rejected with a path-qualified error. Validation walks nested properties and prefixes the error with the dotted property path.","triggerScenarios":"Defining a tool input schema where a property sets \"x-mcp-header\": \"\" or a non-string value (e.g. true, 42, null), then the schema is validated by the kernel's MCP tool registration path.","commonSituations":"Hand-edited or generated tool schemas, template placeholders left empty, JSON tooling writing booleans where strings are expected.","solutions":["Set x-mcp-header to a non-empty string header name, e.g. \"x-mcp-header\": \"X-Trace-Id\"","Remove the x-mcp-header key if the property is not meant to map to a header","Check the generator/template that emits the schema for empty placeholder values"],"exampleFix":"// before\n{\"type\":\"string\",\"x-mcp-header\":\"\"}\n// after\n{\"type\":\"string\",\"x-mcp-header\":\"X-Request-Id\"}","handlingStrategy":"validation","validationCode":"function validateHeaderAnnotations(schema) {\n  for (const [name, prop] of Object.entries(schema.properties || {})) {\n    if ('x-mcp-header' in prop && (typeof prop['x-mcp-header'] !== 'string' || prop['x-mcp-header'] === '')) {\n      throw new Error(`property ${name}: x-mcp-header must be a non-empty string`);\n    }\n  }\n}","typeGuard":"const hasValidHeader = (p) => typeof p['x-mcp-header'] === 'string' && p['x-mcp-header'] !== '';","tryCatchPattern":"try { registerTool(schema) } catch (e) { if (String(e).includes('x-mcp-header')) fixSchemaAndRetry(schema); else throw e; }","preventionTips":["Always pair x-mcp-header with a real header name string","Lint tool schemas for empty extension values before registration","Avoid template placeholders left unfilled in generated schemas"],"tags":["json-schema","mcp","validation","http-headers"],"backgroundTag":"schema-validation-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}