siyuan-note/siyuan · error
expected one content item, got %d
Error message
expected one content item, got %d
What it means
convertContentItem re-wraps a tool result into a CallToolResult JSON and expects exactly one content item after unmarshalling. Any other count means the wrapped result did not round-trip as a single content item, and the conversion fails.
Source
Thrown at kernel/mcp/server.go:348
IsError: result.IsError,
}, nil
})
return true
}
func convertContentItem(item tools.ContentItem) (mcpsdk.Content, error) {
data, err := json.Marshal(item)
if err != nil {
return nil, err
}
wrapped := append([]byte(`{"content":[`), data...)
wrapped = append(wrapped, []byte(`]}`)...)
var result mcpsdk.CallToolResult
if err = json.Unmarshal(wrapped, &result); err != nil {
return nil, err
}
if len(result.Content) != 1 {
return nil, fmt.Errorf("expected one content item, got %d", len(result.Content))
}
return result.Content[0], nil
}
func toolErrorResult(message string) *mcpsdk.CallToolResult {
return &mcpsdk.CallToolResult{
Content: []mcpsdk.Content{&mcpsdk.TextContent{Text: message}},
IsError: true,
}
}
View on GitHub (pinned to 8641553a1f)
Solutions
- Inspect what the tool returned; ensure it returns exactly one content item (e.g. one TextContent or EmbeddedResource)
- Check that toolErrorResult / the wrapping JSON marshals and unmarshals symmetrically
- If the SDK changed CallToolResult.Content semantics, update convertContentItem to handle the new shape
Example fix
// before: tool returns CallToolResult{Content: nil}
// after
return &mcpsdk.CallToolResult{Content: []mcpsdk.Content{mcpsdk.NewTextContent("result")}}, nil Defensive patterns
Strategy: try-catch
Try / catch
item, err := convertContentItem(result)
if err != nil && strings.Contains(err.Error(), "expected one content item") {
// inspect result.Content length; return the tool's own error content if present
} Prevention
- Ensure tool handlers always return exactly one content item
- Add round-trip tests for wrap/unwrap of CallToolResult
- Pin/verify the MCP SDK version so Content serialization stays stable
When it happens
Trigger: A tool produced a result that, after wrapping and unmarshalling, yielded zero or multiple content entries — e.g. the tool returned an empty result, an error result with no content, or the wrapper JSON was built incorrectly.
Common situations: Tests (TestSkillResourceContentSurvivesMCPConversion) covering skill resource conversion; a tool handler returning nil/empty content; SDK changes to CallToolResult.Content serialization.
Related errors
- invalid tool arguments: %w
- JSON depth exceeds %d
- JSON node count exceeds %d
- This is not a valid .sy.zip archive. If the archive was expo
- invalid capability arguments: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/30e6c236df8ad655.
Report an issue: GitHub.