siyuan-note/siyuan · error
property : x-mcp-header must be a non-empty string
Error message
property %q: x-mcp-header must be a non-empty string
What it means
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.
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
Example fix
// before
{"type":"string","x-mcp-header":""}
// after
{"type":"string","x-mcp-header":"X-Request-Id"} Defensive patterns
Strategy: validation
Validate before calling
function validateHeaderAnnotations(schema) {
for (const [name, prop] of Object.entries(schema.properties || {})) {
if ('x-mcp-header' in prop && (typeof prop['x-mcp-header'] !== 'string' || prop['x-mcp-header'] === '')) {
throw new Error(`property ${name}: x-mcp-header must be a non-empty string`);
}
}
} Type guard
const hasValidHeader = (p) => typeof p['x-mcp-header'] === 'string' && p['x-mcp-header'] !== '';
Try / catch
try { registerTool(schema) } catch (e) { if (String(e).includes('x-mcp-header')) fixSchemaAndRetry(schema); else throw e; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: Hand-edited or generated tool schemas, template placeholders left empty, JSON tooling writing booleans where strings are expected.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- property : duplicate x-mcp-header value
- property : x-mcp-header can only be applied to primitive…
- property : x-mcp-header value is not a valid HTTP field name
- invalid input schema
- invalid output schema
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/0e9e9fa2edefcab0.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/tools/validation.go:241
return nil
}
properties, _ := root["properties"].(map[string]any)
seen := map[string]bool{}
var walk func(map[string]any, string) error
walk = func(props map[string]any, prefix string) error {
for propertyName, rawProperty := range props {
property, ok := rawProperty.(map[string]any)
if !ok {
continue
}
path := propertyName
if prefix != "" {
path = prefix + "." + propertyName
}
if rawHeader, exists := property["x-mcp-header"]; exists {
header, ok := rawHeader.(string)
if !ok || header == "" {
return fmt.Errorf(`property %q: x-mcp-header must be a non-empty string`, path)
}
propertyType, _ := property["type"].(string)
if propertyType != "string" && propertyType != "integer" && propertyType != "boolean" {
return fmt.Errorf(
`property %q: x-mcp-header can only be applied to primitive types (integer, string, boolean), got %q`,
path, propertyType)
}
if !validHTTPFieldName(header) {
return fmt.Errorf(`property %q: x-mcp-header value %q is not a valid HTTP field name`, path, header)
}
normalized := strings.ToLower(header)
if seen[normalized] {
return fmt.Errorf(`property %q: duplicate x-mcp-header value %q`, path, header)
}
seen[normalized] = true
}
nested, _ := property["properties"].(map[string]any)
if err := walk(nested, path); err != nil {View on GitHub (pinned to 9f775e8a12)