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

  1. Inspect what the tool returned; ensure it returns exactly one content item (e.g. one TextContent or EmbeddedResource)
  2. Check that toolErrorResult / the wrapping JSON marshals and unmarshals symmetrically
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/30e6c236df8ad655. Report an issue: GitHub.