Skip to content

Commit 901ac03

Browse files
authored
Merge pull request modelcontextprotocol#559 from modelcontextprotocol/basil/nonoptional_content
make CallToolResult.content non-optional and relax output schema validation requirement
2 parents 3b30e30 + 9240700 commit 901ac03

File tree

3 files changed

+53
-228
lines changed

3 files changed

+53
-228
lines changed

docs/specification/draft/server/tools.mdx

Lines changed: 32 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,9 @@ tool annotations to be untrusted unless they come from trusted servers.</Warning
189189

190190
### Tool Result
191191

192-
Tool results may be **structured** or **unstructured**, depending on whether the tool definition specifies an [output schema](#output-schema).
192+
Tool results may contain [**structured**](#structured-content) or **unstructured** content.
193193

194-
**Structured** tool results are JSON objects that are valid with respect to the tool's output schema.
195-
196-
**Unstructured** tool results can contain multiple content items of different types:
194+
**Unstructured** content is returned in the `content` field of a result, and can contain multiple content items of different types:
197195

198196
#### Text Content
199197

@@ -240,95 +238,53 @@ or data, behind a URI that can be subscribed to or fetched again by the client l
240238
}
241239
```
242240

243-
### Output Schema
244-
245-
Tools that produce structured results can use the `outputSchema` property to provide a JSON Schema describing the expected structure of their output.
241+
#### Structured Content
246242

247-
When a tool specifies an `outputSchema`:
243+
**Structured** content is returned as a JSON object in the `structuredContent` field of a result.
248244

249-
1. Clients **MUST** validate that results from that tool contain a `structuredContent` field whose contents validate against the declared `outputSchema`.
245+
For backwards compatibility, a tool that returns structured content SHOULD also return functionally equivalent unstructured content.
246+
(For example, serialized JSON can be returned in a `TextContent` block.)
250247

251-
2. Servers **MUST** provide structured results in `structuredContent` that conform to the declared `outputSchema` of the tool.
248+
#### Output Schema
252249

253-
<Info>
254-
For backwards compatibility, a tool that declares an `outputSchema` may also return unstructured results in the `content` field.
255-
* If present, the unstructured result should be functionally equivalent to the structured result. (For example, serialized JSON can be returned in a `TextContent` block.)
256-
* Clients that support `structuredContent` should ignore the `content` field if present.
257-
</Info>
250+
Tools may also provide an output schema for validation of structured results.
251+
If an output schema provided:
252+
* Servers **MUST** provide structured results that conform to this schema.
253+
* Clients **SHOULD** validate structured results against this schema.
258254

259255
Example tool with output schema:
260256

261257
```json
262258
{
263259
"name": "get_weather_data",
264-
"description": "Get current weather conditions and forecast data for a location",
260+
"description": "Get current weather data for a location",
265261
"inputSchema": {
266262
"type": "object",
267263
"properties": {
268264
"location": {
269265
"type": "string",
270266
"description": "City name or zip code"
271-
},
272-
"units": {
273-
"type": "string",
274-
"enum": ["celsius", "fahrenheit"],
275-
"default": "celsius",
276-
"description": "Temperature unit"
277267
}
278268
},
279269
"required": ["location"]
280270
},
281271
"outputSchema": {
282272
"type": "object",
283273
"properties": {
284-
"current": {
285-
"type": "object",
286-
"properties": {
287-
"temperature": { "type": "number" },
288-
"humidity": { "type": "number" },
289-
"conditions": { "type": "string" },
290-
"wind": {
291-
"type": "object",
292-
"properties": {
293-
"speed": { "type": "number" },
294-
"direction": { "type": "string" }
295-
},
296-
"required": ["speed", "direction"]
297-
}
298-
},
299-
"required": ["temperature", "humidity", "conditions", "wind"]
274+
"temperature": {
275+
"type": "number",
276+
"description": "Temperature in celsius"
300277
},
301-
"forecast": {
302-
"type": "array",
303-
"items": {
304-
"type": "object",
305-
"properties": {
306-
"date": { "type": "string", "format": "date" },
307-
"high": { "type": "number" },
308-
"low": { "type": "number" },
309-
"conditions": { "type": "string" }
310-
},
311-
"required": ["date", "high", "low", "conditions"]
312-
}
278+
"conditions": {
279+
"type": "string",
280+
"description": "Weather conditions description"
313281
},
314-
"location": {
315-
"type": "object",
316-
"properties": {
317-
"city": { "type": "string" },
318-
"country": { "type": "string" },
319-
"coordinates": {
320-
"type": "object",
321-
"properties": {
322-
"latitude": { "type": "number" },
323-
"longitude": { "type": "number" }
324-
},
325-
"required": ["latitude", "longitude"]
326-
}
327-
},
328-
"required": ["city", "country", "coordinates"]
282+
"humidity": {
283+
"type": "number",
284+
"description": "Humidity percentage"
329285
}
330286
},
331-
"required": ["current", "forecast", "location"]
287+
"required": ["temperature", "conditions", "humidity"]
332288
}
333289
}
334290
```
@@ -340,44 +296,22 @@ Example valid response for this tool:
340296
"jsonrpc": "2.0",
341297
"id": 5,
342298
"result": {
343-
"structuredContent": {
344-
"current": {
345-
"temperature": 22.5,
346-
"humidity": 65,
347-
"conditions": "Partly cloudy",
348-
"wind": {
349-
"speed": 12,
350-
"direction": "NW"
351-
}
352-
},
353-
"forecast": [
354-
{
355-
"date": "2024-03-28",
356-
"high": 25,
357-
"low": 18,
358-
"conditions": "Sunny"
359-
},
360-
{
361-
"date": "2024-03-29",
362-
"high": 23,
363-
"low": 17,
364-
"conditions": "Cloudy"
365-
}
366-
],
367-
"location": {
368-
"city": "San Francisco",
369-
"country": "US",
370-
"coordinates": {
371-
"latitude": 37.7749,
372-
"longitude": -122.4194
373-
}
299+
"content": [
300+
{
301+
"type": "text",
302+
"text": "{\"temperature\": 22.5, \"conditions\": \"Partly cloudy\", \"humidity\": 65}"
374303
}
304+
],
305+
"structuredContent": {
306+
"temperature": 22.5,
307+
"conditions": "Partly cloudy",
308+
"humidity": 65
375309
}
376310
}
377311
}
378312
```
379313

380-
The `outputSchema` helps clients and LLMs understand and properly handle structured tool outputs by:
314+
Providing an output schema helps clients and LLMs understand and properly handle structured tool outputs by:
381315

382316
- Enabling strict schema validation of responses
383317
- Providing type information for better integration with programming languages

schema/draft/schema.json

Lines changed: 6 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -101,26 +101,15 @@
101101
"type": "object"
102102
},
103103
"CallToolResult": {
104-
"anyOf": [
105-
{
106-
"$ref": "#/definitions/CallToolUnstructuredResult"
107-
},
108-
{
109-
"$ref": "#/definitions/CallToolStructuredResult"
110-
}
111-
],
112-
"description": "The server's response to a tool call.\n\nAny errors that originate from the tool SHOULD be reported inside the result\nobject, with `isError` set to true, _not_ as an MCP protocol-level error\nresponse. Otherwise, the LLM would not be able to see that an error occurred\nand self-correct.\n\nHowever, any errors in _finding_ the tool, an error indicating that the\nserver does not support tool calls, or any other exceptional conditions,\nshould be reported as an MCP error response."
113-
},
114-
"CallToolStructuredResult": {
115-
"description": "Tool result for tools that do declare an outputSchema.",
104+
"description": "The server's response to a tool call.",
116105
"properties": {
117106
"_meta": {
118107
"additionalProperties": {},
119108
"description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.",
120109
"type": "object"
121110
},
122111
"content": {
123-
"description": "If the Tool defines an outputSchema, this field MAY be present in the result.\nTools should use this field to provide compatibility with older clients that do not support structured content.\nClients that support structured content should ignore this field.",
112+
"description": "A list of content objects that represent the unstructured result of the tool call.",
124113
"items": {
125114
"anyOf": [
126115
{
@@ -140,51 +129,13 @@
140129
"type": "array"
141130
},
142131
"isError": {
143-
"description": "Whether the tool call ended in an error.\n\nIf not set, this is assumed to be false (the call was successful).",
132+
"description": "Whether the tool call ended in an error.\n\nIf not set, this is assumed to be false (the call was successful).\n\nAny errors that originate from the tool SHOULD be reported inside the result\nobject, with `isError` set to true, _not_ as an MCP protocol-level error\nresponse. Otherwise, the LLM would not be able to see that an error occurred\nand self-correct.\n\nHowever, any errors in _finding_ the tool, an error indicating that the\nserver does not support tool calls, or any other exceptional conditions,\nshould be reported as an MCP error response.",
144133
"type": "boolean"
145134
},
146135
"structuredContent": {
147136
"additionalProperties": {},
148-
"description": "An object containing structured tool output.\n\nIf the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema.",
149-
"type": "object"
150-
}
151-
},
152-
"required": [
153-
"structuredContent"
154-
],
155-
"type": "object"
156-
},
157-
"CallToolUnstructuredResult": {
158-
"description": "Tool result for tools that do not declare an outputSchema.",
159-
"properties": {
160-
"_meta": {
161-
"additionalProperties": {},
162-
"description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.",
137+
"description": "An optional JSON object that represents the structured result of the tool call.",
163138
"type": "object"
164-
},
165-
"content": {
166-
"description": "A list of content objects that represent the result of the tool call.\n\nIf the Tool does not define an outputSchema, this field MUST be present in the result.",
167-
"items": {
168-
"anyOf": [
169-
{
170-
"$ref": "#/definitions/TextContent"
171-
},
172-
{
173-
"$ref": "#/definitions/ImageContent"
174-
},
175-
{
176-
"$ref": "#/definitions/AudioContent"
177-
},
178-
{
179-
"$ref": "#/definitions/EmbeddedResource"
180-
}
181-
]
182-
},
183-
"type": "array"
184-
},
185-
"isError": {
186-
"description": "Whether the tool call ended in an error.\n\nIf not set, this is assumed to be false (the call was successful).",
187-
"type": "boolean"
188139
}
189140
},
190141
"required": [
@@ -413,25 +364,6 @@
413364
],
414365
"type": "object"
415366
},
416-
"ContentList": {
417-
"items": {
418-
"anyOf": [
419-
{
420-
"$ref": "#/definitions/TextContent"
421-
},
422-
{
423-
"$ref": "#/definitions/ImageContent"
424-
},
425-
{
426-
"$ref": "#/definitions/AudioContent"
427-
},
428-
{
429-
"$ref": "#/definitions/EmbeddedResource"
430-
}
431-
]
432-
},
433-
"type": "array"
434-
},
435367
"CreateMessageRequest": {
436368
"description": "A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.",
437369
"properties": {
@@ -1978,10 +1910,7 @@
19781910
"$ref": "#/definitions/ListToolsResult"
19791911
},
19801912
{
1981-
"$ref": "#/definitions/CallToolUnstructuredResult"
1982-
},
1983-
{
1984-
"$ref": "#/definitions/CallToolStructuredResult"
1913+
"$ref": "#/definitions/CallToolResult"
19851914
},
19861915
{
19871916
"$ref": "#/definitions/CompleteResult"
@@ -2128,7 +2057,7 @@
21282057
"type": "string"
21292058
},
21302059
"outputSchema": {
2131-
"description": "An optional JSON Schema object defining the structure of the tool's output.\n\nIf set, a CallToolResult for this Tool MUST contain a structuredContent field whose contents validate against this schema.\nIf not set, a CallToolResult for this Tool MUST contain a content field.",
2060+
"description": "An optional JSON Schema object defining the structure of the tool's output returned in \nthe structuredContent field of a CallToolResult.",
21322061
"properties": {
21332062
"properties": {
21342063
"additionalProperties": {

0 commit comments

Comments
 (0)