What is TextContent?
`TextContent` is the foundational content block in MCP, representing a plain Unicode string payload. It is the default unit of textual exchange wherever the protocol needs to carry human-readable or machine-readable text without embedded structure — think tool result bodies, user and assistant turns in prompt messages, and the content fields within sampling requests and responses. Its simplicity is intentional: by keeping plain text as a distinct type rather than a subset of a richer block, the protocol allows implementations to fast-path rendering and validation without inspecting nested structure.
In the MCP message flow, `TextContent` appears inside arrays — for example, the `content` field of a `CallToolResult`, the `messages` array in `CreateMessageRequest`, or prompt `GetPromptResult` messages. The required `type` discriminant is always the literal string `"text"`, which allows clients and servers to switch on type before deserializing the rest of the block. The `text` field carries the actual string payload and is required; an empty string is technically valid but semantically unusual. The optional `annotations` field attaches metadata such as audience targeting (`user`, `assistant`) and priority hints, letting servers signal how the content should be weighted without changing the text itself.
The type has been stable since the initial MCP specification and carries no version-gated behavior. It deliberately excludes a MIME type or encoding field — callers that need to convey structured data as text (JSON, XML, CSV) simply embed it in the `text` field and communicate format expectations out-of-band via the tool or prompt schema.
When to use
Default content block for text data.
When NOT to use
For images (use ImageContent), structured data (consider EmbeddedResource).
Notes
Empty string is valid but problematic
The spec does not forbid an empty `text` field, but many SDK consumers treat empty-string content as a no-op and silently drop it. If your tool returns an empty result intentionally (e.g., a write-only side-effect tool), prefer returning an explicit confirmation string like `"ok"` rather than an empty `TextContent`, to avoid ambiguous behavior across client implementations.
Annotations are ignored by most clients
The `annotations.audience` and `annotations.priority` fields are part of the spec but are treated as advisory hints, not enforced semantics. As of mid-2025, the official Claude Desktop client and most open-source MCP clients do not filter or re-rank content blocks based on annotations. Include them for forward compatibility but do not rely on them for correctness.
No size limit in spec; servers should self-impose
MCP does not define a maximum byte length for the `text` field. In practice, transport layers (stdio, HTTP SSE) and client context windows impose their own ceilings. For stdio-based servers, a single tool result with several megabytes of text will likely stall or be truncated by the host process. Keep individual `TextContent` blocks under 64 KB for safe interoperability; chunk larger payloads across multiple list items or use a resource URI instead.
Prefer TextContent over ImageContent for structured data
When a tool needs to return JSON, a diff, or tabular data, always use `TextContent` with the formatted string rather than encoding it as a base64 `ImageContent` block. Clients that support tool-use streaming can incrementally process `TextContent`, while `ImageContent` is typically buffered in full before being surfaced. This has measurable latency impact for large structured payloads.
Sibling types share the same annotations surface
`ImageContent` and `EmbeddedResource` use the same `Annotations` shape as `TextContent`, so annotation-handling logic can be shared across all content block types in your SDK layer. When building a content renderer, handle annotations at the container level rather than per-type to avoid duplicating logic and to stay consistent when new content block types are added in future spec revisions.
Fields
| Field | Type | Required | Purpose |
|---|---|---|---|
| type | 'text' | yes | Discriminator. |
| text | string | yes | The text payload. |
| annotations | Annotations? | no | audience/priority/lastModified. |
Examples
Simple text
{ "type": "text", "text": "Done." }
Common mistakes
❌ Putting JSON in text without setting mimeType
✅ Consider EmbeddedResource with mimeType:'application/json'.