Skip to content

Commit 594853e

Browse files
authored
Merge branch 'main' into authorization_cleanup
2 parents 5f47060 + 03dc24b commit 594853e

File tree

3 files changed

+289
-5
lines changed

3 files changed

+289
-5
lines changed

docs/specification/draft/server/tools.mdx

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,19 @@ A tool definition includes:
181181
- `name`: Unique identifier for the tool
182182
- `description`: Human-readable description of functionality
183183
- `inputSchema`: JSON Schema defining expected parameters
184+
- `outputSchema`: Optional JSON Schema defining expected output structure
184185
- `annotations`: optional properties describing tool behavior
185186

186187
<Warning>For trust & safety and security, clients **MUST** consider
187188
tool annotations to be untrusted unless they come from trusted servers.</Warning>
188189

189190
### Tool Result
190191

191-
Tool results can contain multiple content items of different types:
192+
Tool results may be **structured** or **unstructured**, depending on whether the tool definition specifies an [output schema](#output-schema).
193+
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:
192197

193198
#### Text Content
194199

@@ -235,6 +240,150 @@ or data, behind a URI that can be subscribed to or fetched again by the client l
235240
}
236241
```
237242

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.
246+
247+
When a tool specifies an `outputSchema`:
248+
249+
1. Clients **MUST** validate that results from that tool contain a `structuredContent` field whose contents validate against the declared `outputSchema`.
250+
251+
2. Servers **MUST** provide structured results in `structuredContent` that conform to the declared `outputSchema` of the tool.
252+
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>
258+
259+
Example tool with output schema:
260+
261+
```json
262+
{
263+
"name": "get_weather_data",
264+
"description": "Get current weather conditions and forecast data for a location",
265+
"inputSchema": {
266+
"type": "object",
267+
"properties": {
268+
"location": {
269+
"type": "string",
270+
"description": "City name or zip code"
271+
},
272+
"units": {
273+
"type": "string",
274+
"enum": ["celsius", "fahrenheit"],
275+
"default": "celsius",
276+
"description": "Temperature unit"
277+
}
278+
},
279+
"required": ["location"]
280+
},
281+
"outputSchema": {
282+
"type": "object",
283+
"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"]
300+
},
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+
}
313+
},
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"]
329+
}
330+
},
331+
"required": ["current", "forecast", "location"]
332+
}
333+
}
334+
```
335+
336+
Example valid response for this tool:
337+
338+
```json
339+
{
340+
"jsonrpc": "2.0",
341+
"id": 5,
342+
"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+
}
374+
}
375+
}
376+
}
377+
}
378+
```
379+
380+
The `outputSchema` helps clients and LLMs understand and properly handle structured tool outputs by:
381+
382+
- Enabling strict schema validation of responses
383+
- Providing type information for better integration with programming languages
384+
- Guiding clients and LLMs to properly parse and utilize the returned data
385+
- Supporting better documentation and developer experience
386+
238387
## Error Handling
239388

240389
Tools use two error reporting mechanisms:

schema/draft/schema.json

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,69 @@
101101
"type": "object"
102102
},
103103
"CallToolResult": {
104-
"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.",
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.",
116+
"properties": {
117+
"_meta": {
118+
"additionalProperties": {},
119+
"description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.",
120+
"type": "object"
121+
},
122+
"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.",
124+
"items": {
125+
"anyOf": [
126+
{
127+
"$ref": "#/definitions/TextContent"
128+
},
129+
{
130+
"$ref": "#/definitions/ImageContent"
131+
},
132+
{
133+
"$ref": "#/definitions/AudioContent"
134+
},
135+
{
136+
"$ref": "#/definitions/EmbeddedResource"
137+
}
138+
]
139+
},
140+
"type": "array"
141+
},
142+
"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).",
144+
"type": "boolean"
145+
},
146+
"structuredContent": {
147+
"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.",
105159
"properties": {
106160
"_meta": {
107161
"additionalProperties": {},
108162
"description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.",
109163
"type": "object"
110164
},
111165
"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.",
112167
"items": {
113168
"anyOf": [
114169
{
@@ -358,6 +413,25 @@
358413
],
359414
"type": "object"
360415
},
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+
},
361435
"CreateMessageRequest": {
362436
"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.",
363437
"properties": {
@@ -1904,7 +1978,10 @@
19041978
"$ref": "#/definitions/ListToolsResult"
19051979
},
19061980
{
1907-
"$ref": "#/definitions/CallToolResult"
1981+
"$ref": "#/definitions/CallToolUnstructuredResult"
1982+
},
1983+
{
1984+
"$ref": "#/definitions/CallToolStructuredResult"
19081985
},
19091986
{
19101987
"$ref": "#/definitions/CompleteResult"
@@ -2049,6 +2126,12 @@
20492126
"name": {
20502127
"description": "The name of the tool.",
20512128
"type": "string"
2129+
},
2130+
"outputSchema": {
2131+
"additionalProperties": true,
2132+
"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.",
2133+
"properties": {},
2134+
"type": "object"
20522135
}
20532136
},
20542137
"required": [

schema/draft/schema.ts

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -695,8 +695,51 @@ export interface ListToolsResult extends PaginatedResult {
695695
* server does not support tool calls, or any other exceptional conditions,
696696
* should be reported as an MCP error response.
697697
*/
698-
export interface CallToolResult extends Result {
699-
content: (TextContent | ImageContent | AudioContent | EmbeddedResource)[];
698+
export type CallToolResult = CallToolUnstructuredResult | CallToolStructuredResult;
699+
700+
export type ContentList = (TextContent | ImageContent | AudioContent | EmbeddedResource)[];
701+
702+
/**
703+
* Tool result for tools that do not declare an outputSchema.
704+
*/
705+
export interface CallToolUnstructuredResult extends Result {
706+
/**
707+
* A list of content objects that represent the result of the tool call.
708+
*
709+
* If the Tool does not define an outputSchema, this field MUST be present in the result.
710+
*/
711+
content: ContentList;
712+
713+
/**
714+
* Structured output must not be provided in an unstructured tool result.
715+
*/
716+
structuredContent: never;
717+
718+
/**
719+
* Whether the tool call ended in an error.
720+
*
721+
* If not set, this is assumed to be false (the call was successful).
722+
*/
723+
isError?: boolean;
724+
}
725+
726+
/**
727+
* Tool result for tools that do declare an outputSchema.
728+
*/
729+
export interface CallToolStructuredResult extends Result {
730+
/**
731+
* An object containing structured tool output.
732+
*
733+
* If the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema.
734+
*/
735+
structuredContent: { [key: string]: unknown };
736+
737+
/**
738+
* If the Tool defines an outputSchema, this field MAY be present in the result.
739+
* Tools should use this field to provide compatibility with older clients that do not support structured content.
740+
* Clients that support structured content should ignore this field.
741+
*/
742+
content?: ContentList;
700743

701744
/**
702745
* Whether the tool call ended in an error.
@@ -706,6 +749,7 @@ export interface CallToolResult extends Result {
706749
isError?: boolean;
707750
}
708751

752+
709753
/**
710754
* Used by the client to invoke a tool provided by the server.
711755
*/
@@ -803,6 +847,14 @@ export interface Tool {
803847
required?: string[];
804848
};
805849

850+
/**
851+
* An optional JSON Schema object defining the structure of the tool's output.
852+
*
853+
* If set, a CallToolResult for this Tool MUST contain a structuredContent field whose contents validate against this schema.
854+
* If not set, a CallToolResult for this Tool MUST contain a content field.
855+
*/
856+
outputSchema?: object;
857+
806858
/**
807859
* Optional additional tool information.
808860
*/

0 commit comments

Comments
 (0)