{"record":{"id":"30e6c236df8ad655","repo":"siyuan-note/siyuan","slug":"expected-one-content-item-got-d","errorCode":null,"errorMessage":"expected one content item, got %d","messagePattern":"expected one content item, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/server.go","lineNumber":348,"sourceCode":"\t\t\tIsError:           result.IsError,\n\t\t}, nil\n\t})\n\treturn true\n}\n\nfunc convertContentItem(item tools.ContentItem) (mcpsdk.Content, error) {\n\tdata, err := json.Marshal(item)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twrapped := append([]byte(`{\"content\":[`), data...)\n\twrapped = append(wrapped, []byte(`]}`)...)\n\tvar result mcpsdk.CallToolResult\n\tif err = json.Unmarshal(wrapped, &result); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(result.Content) != 1 {\n\t\treturn nil, fmt.Errorf(\"expected one content item, got %d\", len(result.Content))\n\t}\n\treturn result.Content[0], nil\n}\n\nfunc toolErrorResult(message string) *mcpsdk.CallToolResult {\n\treturn &mcpsdk.CallToolResult{\n\t\tContent: []mcpsdk.Content{&mcpsdk.TextContent{Text: message}},\n\t\tIsError: true,\n\t}\n}\n","sourceCodeStart":330,"sourceCodeEnd":359,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/mcp/server.go#L330-L359","documentation":"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.","triggerScenarios":"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.","commonSituations":"Tests (TestSkillResourceContentSurvivesMCPConversion) covering skill resource conversion; a tool handler returning nil/empty content; SDK changes to CallToolResult.Content serialization.","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"],"exampleFix":"// before: tool returns CallToolResult{Content: nil}\n// after\nreturn &mcpsdk.CallToolResult{Content: []mcpsdk.Content{mcpsdk.NewTextContent(\"result\")}}, nil","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"item, err := convertContentItem(result)\nif err != nil && strings.Contains(err.Error(), \"expected one content item\") {\n    // inspect result.Content length; return the tool's own error content if present\n}","preventionTips":["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"],"tags":["mcp","json","content"],"backgroundTag":"unexpected-response-shape","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}