Skip to content
Closed
5 changes: 4 additions & 1 deletion docs/specification/draft/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ the previous revision, [2025-03-26](/specification/2025-03-26).
## Major changes

1. Removed support for JSON-RPC **[batching](https://www.jsonrpc.org/specification#batch)**
(PR [#416](https://github.com/modelcontextprotocol/specification/pull/416))
(PR [#416](https://github.com/modelcontextprotocol/specification/pull/416))
2. Added support for [structured tool output](https://modelcontextprotocol.io/specification/draft/server/tools#structured-content)
(PR [#371](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/371))
3. Classified MCP servers as [OAuth Resource Servers](https://modelcontextprotocol.io/specification/draft/basic/authorization#2-3-authorization-server-discovery), adding protected resource metadata to discover the corresponding Authorization server. (PR [#338](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/338))
Expand All @@ -18,6 +18,9 @@ the previous revision, [2025-03-26](/specification/2025-03-26).

## Other schema changes

- PromptMessage and SamplingMessage now contain Arrays of content.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a major change with a note that it's breaking

- TODO

## Full changelog

For a complete list of all changes that have been made since the last protocol revision,
Expand Down
12 changes: 7 additions & 5 deletions docs/specification/draft/client/sampling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Applications **SHOULD**:
- Provide UI that makes it easy and intuitive to review sampling requests
- Allow users to view and edit prompts before sending
- Present generated responses for review before delivery
</Warning>
</Warning>

## Capabilities

Expand Down Expand Up @@ -90,10 +90,12 @@ To request a language model generation, servers send a `sampling/createMessage`
"id": 1,
"result": {
"role": "assistant",
"content": {
"type": "text",
"text": "The capital of France is Paris."
},
"content": [
{
"type": "text",
"text": "The capital of France is Paris."
}
],
"model": "claude-3-sonnet-20240307",
"stopReason": "endTurn"
}
Expand Down
10 changes: 6 additions & 4 deletions docs/specification/draft/server/prompts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@ auto-completed through [the completion API](/specification/draft/server/utilitie
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Please review this Python code:\ndef hello():\n print('world')"
}
"content": [
{
"type": "text",
"text": "Please review this Python code:\ndef hello():\n print('world')"
}
]
}
]
}
Expand Down
83 changes: 46 additions & 37 deletions schema/draft/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -468,17 +468,20 @@
"type": "object"
},
"content": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
}
]
"items": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
}
]
},
"type": "array"
},
"model": {
"description": "The name of the model that generated the message.",
Expand Down Expand Up @@ -1599,20 +1602,23 @@
"description": "Describes a message returned as part of a prompt.\n\nThis is similar to `SamplingMessage`, but also supports the embedding of\nresources from the MCP server.",
"properties": {
"content": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
"items": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"type": "array"
},
"role": {
"$ref": "#/definitions/Role"
Expand Down Expand Up @@ -1948,17 +1954,20 @@
"description": "Describes a message issued to or received from an LLM API.",
"properties": {
"content": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
}
]
"items": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
}
]
},
"type": "array"
},
"role": {
"$ref": "#/definitions/Role"
Expand Down Expand Up @@ -2279,7 +2288,7 @@
"type": "string"
},
"outputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in \nthe structuredContent field of a CallToolResult.",
"description": "An optional JSON Schema object defining the structure of the tool's output returned in\nthe structuredContent field of a CallToolResult.",
"properties": {
"properties": {
"additionalProperties": {
Expand Down
8 changes: 4 additions & 4 deletions schema/draft/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ export type Role = "user" | "assistant";
*/
export interface PromptMessage {
role: Role;
content: TextContent | ImageContent | AudioContent | EmbeddedResource;
content: (TextContent | ImageContent | AudioContent | EmbeddedResource)[];
}

/**
Expand Down Expand Up @@ -705,7 +705,7 @@ export interface CallToolResult extends Result {
* Whether the tool call ended in an error.
*
* If not set, this is assumed to be false (the call was successful).
*
*
* Any errors that originate from the tool SHOULD be reported inside the result
* object, with `isError` set to true, _not_ as an MCP protocol-level error
* response. Otherwise, the LLM would not be able to see that an error occurred
Expand Down Expand Up @@ -816,7 +816,7 @@ export interface Tool {
};

/**
* An optional JSON Schema object defining the structure of the tool's output returned in
* An optional JSON Schema object defining the structure of the tool's output returned in
* the structuredContent field of a CallToolResult.
*/
outputSchema?: {
Expand Down Expand Up @@ -937,7 +937,7 @@ export interface CreateMessageResult extends Result, SamplingMessage {
*/
export interface SamplingMessage {
role: Role;
content: TextContent | ImageContent | AudioContent;
content: (TextContent | ImageContent | AudioContent)[];

@cliffhall cliffhall Jun 2, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last-ditch ask for a backward compatible way to handle this. Defining an ArrayContent type which can contain any of the existing types, and then this could become:

Suggested change
content: (TextContent | ImageContent | AudioContent)[];
content: (TextContent | ImageContent | AudioContent | ArrayContent);

Not certain if there's a reason why it wouldn't work, but thought I'd put it out there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the concern, however the original proposal is still my preference. My reasoning is:

  • Changing content to an Array makes it the same as content in CallToolResult.
  • SDK compatibility for both Client and Server is quite straightforward. E.g. converting from content to [content] or from [content,content] to [Message,Message]. This should mean the rollout at both the SDK and protocol level can be managed. There is example code in fast-agent that does this conversion (as it uses this type internally).
  • It is more directly expressive. For example mcp-webcam development version has image prompts for ICL. These have to be [Message TextContent],[Message ImageContent] rather than the actual LLM API Shape of Message [TextContent,ImageContent].
  • Adoption of Sampling and Prompts containing embedded content is still relatively small in comparison to the broader MCP system, so this will be nowhere near as impactful as a breaking change on CallToolResult.

So the trade-off is between a new type introduced for backwards compatibility, or expressing the Message content semantically. I think because it can be mitigated at the SDK with low effort I fall towards the latter.

}

/**
Expand Down