Skip to content

Commit 8c83f3f

Browse files
committed
fix: implement Python SDK consistency with JSON string returns
- Return JSON.stringify() results when useStructuredContent=true for Python SDK parity - Update all tests to expect JSON strings instead of objects/arrays - Maintain backward compatibility when useStructuredContent=false (default) - Honor commitment made to @seratch for Python SDK consistency - Preserve falsy value handling (0, false, '', null) within JSON strings - Update documentation and changeset to reflect JSON string approach This resolves the conflict between the author's commitment and implementation, ensuring true cross-SDK compatibility as requested by maintainers.
1 parent f093b4b commit 8c83f3f

File tree

3 files changed

+15
-15
lines changed

3 files changed

+15
-15
lines changed

.changeset/mcp-structured-content.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ feat(mcp): add structuredContent support behind `useStructuredContent`; return f
66

77
- `MCPServer#callTool` now returns the full `CallToolResult` (was `content[]`), exposing optional `structuredContent`.
88
- Add `useStructuredContent` option to MCP servers (stdio/streamable-http/SSE), default `false` to avoid duplicate data by default.
9-
- When enabled, function tool outputs include `structuredContent` (or return it alone when no `content`).
9+
- When enabled, function tool outputs return JSON strings for consistency with Python SDK implementation.

packages/agents-core/src/mcp.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ export async function getAllMcpTools<TContext = UnknownContext>(
457457

458458
/**
459459
* Converts an MCP tool definition to a function tool for the Agents SDK.
460+
* When useStructuredContent is enabled, returns JSON strings for consistency with Python SDK.
460461
*/
461462
export function mcpToFunctionTool(
462463
mcpTool: MCPTool,
@@ -476,32 +477,31 @@ export function mcpToFunctionTool(
476477
}
477478
const result = await server.callTool(mcpTool.name, args);
478479

479-
// JS ergonomics: return objects/arrays; include structuredContent when enabled
480480
if (result.content && result.content.length === 1) {
481481
if (
482482
server.useStructuredContent &&
483483
'structuredContent' in result &&
484484
result.structuredContent !== undefined
485485
) {
486-
return [result.content[0], result.structuredContent];
486+
return JSON.stringify([result.content[0], result.structuredContent]);
487487
}
488488
return result.content[0];
489489
} else if (result.content && result.content.length > 1) {
490-
const outputs: any[] = [...result.content];
491490
if (
492491
server.useStructuredContent &&
493492
'structuredContent' in result &&
494493
result.structuredContent !== undefined
495494
) {
496-
outputs.push(result.structuredContent);
495+
const outputs = [...result.content, result.structuredContent];
496+
return JSON.stringify(outputs);
497497
}
498-
return outputs;
498+
return result.content;
499499
} else if (
500500
server.useStructuredContent &&
501501
'structuredContent' in result &&
502502
result.structuredContent !== undefined
503503
) {
504-
return result.structuredContent;
504+
return JSON.stringify(result.structuredContent);
505505
}
506506
// Preserve backward compatibility: return empty array when no content
507507
return result.content || [];

packages/agents-core/test/mcpStructuredContent.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ describe('MCP structuredContent handling', () => {
107107
);
108108

109109
const out = await tool.invoke({} as any, '{}');
110-
expect(out).toEqual([{ type: 'text', text: 'hello' }, { foo: 1 }]);
110+
expect(out).toEqual(JSON.stringify([{ type: 'text', text: 'hello' }, { foo: 1 }]));
111111
});
112112

113113
it('includes structuredContent when enabled: no content -> structuredContent only', async () => {
@@ -148,7 +148,7 @@ describe('MCP structuredContent handling', () => {
148148
);
149149

150150
const out = await tool.invoke({} as any, '{}');
151-
expect(out).toEqual({ foo: 1 });
151+
expect(out).toEqual(JSON.stringify({ foo: 1 }));
152152
});
153153

154154
it('includes structuredContent when enabled: multiple contents -> array with structuredContent appended', async () => {
@@ -192,11 +192,11 @@ describe('MCP structuredContent handling', () => {
192192
);
193193

194194
const out = await tool.invoke({} as any, '{}');
195-
expect(out).toEqual([
195+
expect(out).toEqual(JSON.stringify([
196196
{ type: 'text', text: 'a' },
197197
{ type: 'text', text: 'b' },
198198
{ foo: 1 },
199-
]);
199+
]));
200200
});
201201

202202
it('preserves falsy structuredContent values when enabled', async () => {
@@ -243,7 +243,7 @@ describe('MCP structuredContent handling', () => {
243243
);
244244

245245
const out = await tool.invoke({} as any, '{}');
246-
expect(out).toEqual([{ type: 'text', text: 'hello' }, falsyValue]);
246+
expect(out).toEqual(JSON.stringify([{ type: 'text', text: 'hello' }, falsyValue]));
247247
}
248248

249249
// Test with no content + falsy structuredContent
@@ -269,7 +269,7 @@ describe('MCP structuredContent handling', () => {
269269
);
270270

271271
const out = await tool.invoke({} as any, '{}');
272-
expect(out).toEqual(falsyValue);
272+
expect(out).toEqual(JSON.stringify(falsyValue));
273273
}
274274
});
275275

@@ -357,10 +357,10 @@ describe('MCP structuredContent handling', () => {
357357
);
358358

359359
let out = await tool.invoke({} as any, '{}');
360-
expect(out).toEqual([
360+
expect(out).toEqual(JSON.stringify([
361361
{ type: 'text', text: 'with-structured' },
362362
{ data: 'structured' },
363-
]);
363+
]));
364364

365365
// Second call: no structured content
366366
(server as any).callTool = async () => ({

0 commit comments

Comments
 (0)