Skip to content

Commit 77a284c

Browse files
authored
Merge pull request #527 from modelcontextprotocol/basil/structured_output_check
add server error if tool declares outputSchema but returns no structuredContent
2 parents a41b174 + aeb7b8d commit 77a284c

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

src/server/mcp.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,70 @@ describe("tool()", () => {
11601160
expect(JSON.parse(textContent.text)).toEqual(result.structuredContent);
11611161
});
11621162

1163+
/***
1164+
* Test: Tool with Output Schema Must Provide Structured Content
1165+
*/
1166+
test("should throw error when tool with outputSchema returns no structuredContent", async () => {
1167+
const mcpServer = new McpServer({
1168+
name: "test server",
1169+
version: "1.0",
1170+
});
1171+
1172+
const client = new Client(
1173+
{
1174+
name: "test client",
1175+
version: "1.0",
1176+
},
1177+
{
1178+
capabilities: {
1179+
tools: {},
1180+
},
1181+
},
1182+
);
1183+
1184+
// Register a tool with outputSchema that returns only content without structuredContent
1185+
mcpServer.registerTool(
1186+
"test",
1187+
{
1188+
description: "Test tool with output schema but missing structured content",
1189+
inputSchema: {
1190+
input: z.string(),
1191+
},
1192+
outputSchema: {
1193+
processedInput: z.string(),
1194+
resultType: z.string(),
1195+
},
1196+
},
1197+
async ({ input }) => ({
1198+
// Only return content without structuredContent
1199+
content: [
1200+
{
1201+
type: "text",
1202+
text: `Processed: ${input}`,
1203+
},
1204+
],
1205+
})
1206+
);
1207+
1208+
const [clientTransport, serverTransport] =
1209+
InMemoryTransport.createLinkedPair();
1210+
1211+
await Promise.all([
1212+
client.connect(clientTransport),
1213+
mcpServer.server.connect(serverTransport),
1214+
]);
1215+
1216+
// Call the tool and expect it to throw an error
1217+
await expect(
1218+
client.callTool({
1219+
name: "test",
1220+
arguments: {
1221+
input: "hello",
1222+
},
1223+
}),
1224+
).rejects.toThrow(/Tool test has an output schema but no structured content was provided/);
1225+
});
1226+
11631227
/***
11641228
* Test: Schema Validation Failure for Invalid Structured Content
11651229
*/

src/server/mcp.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,14 @@ export class McpServer {
198198
}
199199
}
200200

201-
if (tool.outputSchema && result.structuredContent) {
201+
if (tool.outputSchema) {
202+
if (!result.structuredContent) {
203+
throw new McpError(
204+
ErrorCode.InvalidParams,
205+
`Tool ${request.params.name} has an output schema but no structured content was provided`,
206+
);
207+
}
208+
202209
// if the tool has an output schema, validate structured content
203210
const parseResult = await tool.outputSchema.safeParseAsync(
204211
result.structuredContent,

0 commit comments

Comments
 (0)