You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SEP-1624: Clarify structuredContent vs content Usage Guidance
Status: proposal Type: Informational Created: 2025-10-07 Related Issues: #1411 Related PRs: #371, #559
Abstract
This SEP proposes clarifying the specification around structuredContent and content fields in CallToolResult to address inconsistent client and server implementations. The proposal focuses on non-breaking clarifications to the existing spec language to better communicate the intended design and usage patterns for both fields.
Motivation
Current State of Confusion
Since the introduction of structuredContent in PR #371, there has been significant confusion about when and how clients and servers should use these fields:
Cursor recently changed to prefering content for the model input per @msfeldstein
VS Code prefers structuredContent over content for model context. Both are shown in Chat UI.
Most other clients (CC/Windsurf) ignore structuredContent entirely
Some clients forward both fields verbatim, causing redundant context (Citation? Mentioned in Discord discussion)
Server Implementation Issues:
Servers returning different semantic information in each field (violating backwards compatibility intent)
Unclear guidance leading to JSON stringification in content in structuredContent resulting in at best indentical output, at worst semanitcally duplicated output in structuredContent
Current perception: structuredContent is "better" and should always be preferred
Lack of clarity on which modality is appropriate for different client architectures
Historical Context
PR #371 introduced structuredContent with these design goals:
Enable strict validation of structured tool results for programmatic tool use
Support use cases like agent code generation, tool composition, and typed orchestration
Originally made content and structuredContent mutually exclusive
PR #559 relaxed the requirements for backwards compatibility:
Made content non-optional again (additive change only)
Changed validation requirement from MUST to SHOULD
Introduced the backwards compatibility guidance: "For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block."
For conversational/agent use with language models directly, content is often preferred (lower token cost, better readability)
Current spec language inadvertently leads to treating structuredContent as superior in all contexts
Specification
Proposed Changes
1. Clarify Client Guidance in /specification/draft/server/tools.mdx
Current Language (lines 298-305):
#### Structured Content**Structured** content is returned as a JSON object in the `structuredContent` field of a result.
For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block.
Proposed Change:
#### Structured Content**Structured** content is returned as a JSON object in the `structuredContent` field of a result.
The `structuredContent` and `content` fields serve different use cases:
-**`content`**: Model-oriented output optimized for readability and token efficiency. Preferred for conversational agents and direct model prompting. Does not require strict schematisation. A plain text or markdown representation of the output for example.
-**`structuredContent`**: Machine-oriented output for programmatic tool use, code generation, type-safe orchestration, and strict schema validation.
**Server Requirements**:
- When both fields are present, they MUST be semantically equivalent (same information, different presentation)
- In some cases, an explicit field in `structuredContent` can be semantically present in `content` without specific mention. For example if expected fields are returned and no error is mentioned, a `structuredContent` response that contains a `"status": "success",` object is evident without the status being verbatim mentioned as successful in `content`.
- For backwards compatibility, a tool that returns structured content SHOULD also return a response in `content`.
**Client Guidance**:
- Clients SHOULD choose the appropriate field to expose to the model based on their use case:
-**Conversational/Agent UX**: Prefer `content` for lower token cost and readability (by both humans and models).
-**Programmatic/Code Mode**: Prefer `structuredContent` for type safety and schema validation
- Clients SHOULD NOT forward both fields verbatim to models as semantically distinct inputs.
- Clients that use `content` MUST still perform `outputSchema` validation against `structuredContent` when present
2. Update Tool Output Schema Documentation
Add Section After Output Schema Example (around line 345):
### Designing Tools with Complementary Output Formats
Tool developers should design outputs where `content` and `structuredContent` serve complementary roles, enabling both conversational and programmatic use cases:
-**`content`** provides a human/model-oriented representation:
- Natural language content, context, and explanations
- Optimized for readability and token efficiency
- Includes suggestions, interpretations, or additional guidance
- Suitable for direct consumption by conversational agents or end-users
-**`structuredContent`** provides a machine-oriented representation:
- Strict schema validation via `outputSchema`- Type safety for programmatic tool composition
- Consistent structure for code generation and scripting
- Enables reliable data extraction and transformation
**Design patterns for complementary outputs:**- Define an `outputSchema` that captures all data fields, ensuring that the `text` field from `content` is present as a substring of `structuredContent`.
- Provide semantically equivalent `content` with enhanced readability
- Format `content` with context that helps models use the information effectively
- Example: A weather tool returns structured temperature/humidity data in `structuredContent`, plus a natural language summary in `content`, i.e:
structuredContent (machine-oriented):
```json
{
"temperature": 72,
"units": "F",
"condition": "sunny",
"city": "Seattle",
"summary": "It's 72 degrees F and sunny in Seattle"
}
```
content (model / human-oriented):
```json
{
"type": "text",
"text": "It's 72 degrees F and sunny in Seattle"
}
```
Update outputSchema description in schema.ts (draft/schema.ts around line 975):
Current:
/** * An optional JSON Schema object defining the structure of the tool's output returned in * the structuredContent field of a CallToolResult. */
outputSchema?: {
type: "object";
properties?: {[key: string]: object};
required?: string[];};
Proposed:
/** * An optional JSON Schema object defining the structure of the tool's output returned in * the structuredContent field of a CallToolResult. * * When outputSchema is provided: * - Servers MUST populate structuredContent with data conforming to this schema * - Clients SHOULD validate structuredContent against this schema * - Servers SHOULD also provide a human-readable representation in content * * Use outputSchema for programmatic tool use, code generation, and type-safe integrations. * For conversational agents, consider whether unstructured content provides better model performance. */
outputSchema?: {
type: "object";
properties?: {[key: string]: object};
required?: string[];};
Open Question: if we continue to expect that content is present in structuredContent as a substring, rather than the stringified JSON we have today, we will have semantic duplication in structuredContent. By the letter of the proposed spec this is not an issue as codeful use of structuredContent can ignore the embedded content field. In practice with clients currently preferring structuredContent as model input, this duplication could lead to increased token usage and duplicate information being provided.
Non-Changes (Explicitly Out of Scope)
This SEP intentionally does NOT propose:
Breaking changes to field optionality - Both fields remain as currently specified
Changes to validation semantics - SHOULD/MUST requirements remain unchanged
New protocol fields or capabilities - Pure clarification only
Deprecation of either field - Both remain first-class citizens for their use cases
Servers already returning both fields with semantic equivalence: ✅ No change needed
Servers returning only content: ✅ Still valid
Servers returning only structuredContent with outputSchema: ✅ Still valid
Servers returning different semantics in each field: ⚠️ Should align to guidance (was always problematic)
Clients:
Clients preferring content: ✅ Now explicitly supported
Clients preferring structuredContent: ✅ Still valid for their use case
Clients validating against outputSchema: ✅ No change needed
Clients forwarding both fields to models: ⚠️ Should align to guidance (was always problematic)
Security Implications
This SEP has no direct security implications as it introduces no protocol changes. Existing security considerations from the original specification for structuredContent remain applicable.
Clients should consider tool annotations for trust decisions
Validation of untrusted server data remains critical
Schema validation is a defense mechanism, not a security boundary
Reference Implementation
Proposed throughout the issue and purely documentation-driven. Related, though different changes would be beneficial in the SDKs as mentioned in #1411.
Below are valid, semantically equivalent responses for a hypothetical get_email tool that retrieves an email for both conten and structuredContent
Note: I am taking the liberty of putting new lines in in place of \n in the outputs of both structuredContent and content to better communicate the differences. In a real implementation, these would be \n within the strings.
structuredContent
284 tokens of output excluding the semantically duplicative content object embedded inside.
{
"status": "success",
"response_format": "detailed",
"mailItem": {
"subject": "Project Update – Q3 Metrics Review",
"bodyText":
"Hi Kyle Rubenok,Summary of the requested project artifacts.Key Points:- Revenue +14% QoQ- Churn down 0.6 pts- Infra cost stable while traffic increasedNext Actions:1. Prepare draft reply summarizing highlights.2. Schedule follow‑up review.Thanks,Automated System","conversationId": "CONV-EXAMPLE-123456",
"receivedTime": "2025-10-07T19:45:23-07:00",
"from": {
"name": "Kyle Rubenok",
"email": "sender@example.com"
},
"to": [
{
"name": "Recipient",
"email": "recipient@example.com"
}
],
"cc": [
{
"name": "Review Bot",
"email": "review.bot@example.com"
}
]
},
"suggestions": [
"Use email_draft_message to start a reply when you have enough context.",
"Call email_get_conversations_in_folder to gather thread context before acting."
],
"content":"Subject: 'Project Update – Q3 Metrics Review' from Kyle Rubenok (received 2025-10-07 19:45 UTC). conversationId 'CONV-EXAMPLE-123456'\n To: Recipient <recipient@example.com>, CC: Review Bot <review.bot@example.com>\n Status: unread (labels: inbox, unread).\n Attachments: metrics-summary.xlsx (47 KB).\n\n -- Message body --\n\n Hi Kyle Rubenok,\n\n Summary of the requested project artifacts.\n Key Points:\n - Revenue +14% QoQ\n - Churn down 0.6 pts\n - Infra cost stable while traffic increased\n\n Next Actions:\n 1. Prepare draft reply summarizing highlights.\n 2. Schedule follow‑up review.\n\n Thanks,\n Automated System\n\n -- End Message --\n\n Potential actions:\n - Use email_draft_message to start a reply when you have enough context.\n - Call email_get_conversations_in_folder to gather thread context before acting."}
content
189 tokens of output
{
"type": "text",
"text": "Subject: 'Project Update – Q3 Metrics Review' from Kyle Rubenok (received 2025-10-07 19:45 UTC). conversationId 'CONV-EXAMPLE-123456'To: Recipient <recipient@example.com>, CC: Review Bot <review.bot@example.com>-- Message body --Hi Kyle Rubenok,Summary of the requested project artifacts.Key Points:- Revenue +14% QoQ- Churn down 0.6 pts- Infra cost stable while traffic increasedNext Actions:1. Prepare draft reply summarizing highlights.2. Schedule follow‑up review.Thanks,Automated System-- End Message --Potential actions:- Use email_draft_message to start a reply when you have enough context.- Call email_get_conversations_in_folder to gather thread context before acting."
}
SEP-1624: Clarify
structuredContentvscontentUsage GuidanceStatus: proposal
Type: Informational
Created: 2025-10-07
Related Issues: #1411
Related PRs: #371, #559
Abstract
This SEP proposes clarifying the specification around
structuredContentandcontentfields inCallToolResultto address inconsistent client and server implementations. The proposal focuses on non-breaking clarifications to the existing spec language to better communicate the intended design and usage patterns for both fields.Motivation
Current State of Confusion
Since the introduction of
structuredContentin PR #371, there has been significant confusion about when and how clients and servers should use these fields:Inconsistent Client Behavior (#1411):
contentfor the model input per @msfeldsteinstructuredContentovercontentfor model context. Both are shown in Chat UI.structuredContententirelyServer Implementation Issues:
contentinstructuredContentresulting in at best indentical output, at worst semanitcally duplicated output instructuredContentMisaligned Use Cases:
Tool.outputSchemaandCallToolResult.structuredContent#371): Strict schema validation for programmatic/codeful tool usestructuredContentis "better" and should always be preferredHistorical Context
PR #371 introduced
structuredContentwith these design goals:contentandstructuredContentmutually exclusivePR #559 relaxed the requirements for backwards compatibility:
contentnon-optional again (additive change only)Discord Discussion (Aug-Sep 2025):
structuredContentis primarily valuable at for "Code Mode" / programmatic MCP usage (per Cloudflare Code Mode blog, @domdomegg prototypes, etc...)contentis often preferred (lower token cost, better readability)structuredContentas superior in all contextsSpecification
Proposed Changes
1. Clarify Client Guidance in
/specification/draft/server/tools.mdxCurrent Language (lines 298-305):
Proposed Change:
2. Update Tool Output Schema Documentation
Add Section After Output Schema Example (around line 345):
3. Clarify Schema Validation Requirements
Update
outputSchemadescription in schema.ts (draft/schema.ts around line 975):Current:
Proposed:
Non-Changes (Explicitly Out of Scope)
This SEP intentionally does NOT propose:
Rationale
Why These Changes
Aligns with Original Design Intent: PR RFC: add
Tool.outputSchemaandCallToolResult.structuredContent#371 was explicitly designed for programmatic tool use, not as a universal replacement forcontentAddresses Real-World Pain Points:
contentbased on the Discord discussionPrevents Future Issues:
Maintains Backwards Compatibility:
Alternative Approaches Considered
Making
structuredContenta side-channel for metadata_metafor additional data.Deprecating one field in favor of the other
Adding capability negotiation for structured content
Backward Compatibility
This SEP introduces no backward incompatibilities.
All proposed changes are purely clarifications of existing behavior:
Tool.outputSchemaandCallToolResult.structuredContent#371Impact on Existing Implementations
Servers:
content: ✅ Still validstructuredContentwithoutputSchema: ✅ Still validClients:
content: ✅ Now explicitly supportedstructuredContent: ✅ Still valid for their use caseoutputSchema: ✅ No change neededSecurity Implications
This SEP has no direct security implications as it introduces no protocol changes. Existing security considerations from the original specification for
structuredContentremain applicable.Reference Implementation
Proposed throughout the issue and purely documentation-driven. Related, though different changes would be beneficial in the SDKs as mentioned in #1411.
References
Tool.outputSchemaandCallToolResult.structuredContent#371: RFC: addTool.outputSchemaandCallToolResult.structuredContent#371Appendix: Example Tool Resposes
Below are valid, semantically equivalent responses for a hypothetical
get_emailtool that retrieves an email for bothcontenandstructuredContentNote: I am taking the liberty of putting new lines in in place of \n in the outputs of both
structuredContentandcontentto better communicate the differences. In a real implementation, these would be\nwithin the strings.structuredContent284 tokens of output excluding the semantically duplicative
contentobject embedded inside.{ "status": "success", "response_format": "detailed", "mailItem": { "subject": "Project Update – Q3 Metrics Review", "bodyText": "Hi Kyle Rubenok, Summary of the requested project artifacts. Key Points: - Revenue +14% QoQ - Churn down 0.6 pts - Infra cost stable while traffic increased Next Actions: 1. Prepare draft reply summarizing highlights. 2. Schedule follow‑up review. Thanks, Automated System", "conversationId": "CONV-EXAMPLE-123456", "receivedTime": "2025-10-07T19:45:23-07:00", "from": { "name": "Kyle Rubenok", "email": "sender@example.com" }, "to": [ { "name": "Recipient", "email": "recipient@example.com" } ], "cc": [ { "name": "Review Bot", "email": "review.bot@example.com" } ] }, "suggestions": [ "Use email_draft_message to start a reply when you have enough context.", "Call email_get_conversations_in_folder to gather thread context before acting." ], "content":"Subject: 'Project Update – Q3 Metrics Review' from Kyle Rubenok (received 2025-10-07 19:45 UTC). conversationId 'CONV-EXAMPLE-123456'\n To: Recipient <recipient@example.com>, CC: Review Bot <review.bot@example.com>\n Status: unread (labels: inbox, unread).\n Attachments: metrics-summary.xlsx (47 KB).\n\n -- Message body --\n\n Hi Kyle Rubenok,\n\n Summary of the requested project artifacts.\n Key Points:\n - Revenue +14% QoQ\n - Churn down 0.6 pts\n - Infra cost stable while traffic increased\n\n Next Actions:\n 1. Prepare draft reply summarizing highlights.\n 2. Schedule follow‑up review.\n\n Thanks,\n Automated System\n\n -- End Message --\n\n Potential actions:\n - Use email_draft_message to start a reply when you have enough context.\n - Call email_get_conversations_in_folder to gather thread context before acting."}content189 tokens of output
{ "type": "text", "text": " Subject: 'Project Update – Q3 Metrics Review' from Kyle Rubenok (received 2025-10-07 19:45 UTC). conversationId 'CONV-EXAMPLE-123456' To: Recipient <recipient@example.com>, CC: Review Bot <review.bot@example.com> -- Message body -- Hi Kyle Rubenok, Summary of the requested project artifacts. Key Points: - Revenue +14% QoQ - Churn down 0.6 pts - Infra cost stable while traffic increased Next Actions: 1. Prepare draft reply summarizing highlights. 2. Schedule follow‑up review. Thanks, Automated System -- End Message -- Potential actions: - Use email_draft_message to start a reply when you have enough context. - Call email_get_conversations_in_folder to gather thread context before acting." }