Skip to content

Commit 3681f66

Browse files
committed
fix: preserve falsy structuredContent values (0, false, '', null)
- Replace truthy checks with 'structuredContent' in result to detect property existence - Add comprehensive tests for falsy values: 0, false, empty string, null - Ensures valid structured outputs are not dropped due to falsy evaluation - Addresses P1 feedback from @chatgpt-codex-connector about data loss - Maintains parity with Python implementation behavior
1 parent 98e81c1 commit 3681f66

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,4 @@ openai-agents-python
148148
bundled/
149149

150150
.wrangler/
151-
.dev.vars
152-
package-lock.json
151+
.dev.vars

packages/agents-core/src/mcp.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,19 +477,19 @@ export function mcpToFunctionTool(
477477

478478
// JS ergonomics: return objects/arrays; include structuredContent when enabled
479479
if (result.content && result.content.length === 1) {
480-
if (server.useStructuredContent && (result as any).structuredContent) {
480+
if (server.useStructuredContent && 'structuredContent' in result) {
481481
return [result.content[0], (result as any).structuredContent];
482482
}
483483
return result.content[0];
484484
} else if (result.content && result.content.length > 1) {
485485
const outputs: any[] = result.content.map((c) => c);
486-
if (server.useStructuredContent && (result as any).structuredContent) {
486+
if (server.useStructuredContent && 'structuredContent' in result) {
487487
outputs.push((result as any).structuredContent);
488488
}
489489
return outputs;
490490
} else if (
491491
server.useStructuredContent &&
492-
(result as any).structuredContent
492+
'structuredContent' in result
493493
) {
494494
return (result as any).structuredContent;
495495
}

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,78 @@ describe('MCP structuredContent handling', () => {
198198
{ foo: 1 },
199199
]);
200200
});
201+
202+
it('preserves falsy structuredContent values when enabled', async () => {
203+
const server = new StubServer(
204+
's',
205+
[
206+
{
207+
name: 't',
208+
description: '',
209+
inputSchema: {
210+
type: 'object',
211+
properties: {},
212+
required: [],
213+
additionalProperties: false,
214+
},
215+
},
216+
],
217+
true,
218+
);
219+
220+
// Test different falsy values
221+
const falsyValues = [0, false, '', null];
222+
223+
for (const falsyValue of falsyValues) {
224+
// Test with single content + falsy structuredContent
225+
(server as any).callTool = async () => ({
226+
content: [{ type: 'text', text: 'hello' }],
227+
structuredContent: falsyValue,
228+
});
229+
230+
const tool = mcpToFunctionTool(
231+
{
232+
name: 't',
233+
description: '',
234+
inputSchema: {
235+
type: 'object',
236+
properties: {},
237+
required: [],
238+
additionalProperties: false,
239+
},
240+
},
241+
server,
242+
false,
243+
);
244+
245+
const out = await tool.invoke({} as any, '{}');
246+
expect(out).toEqual([{ type: 'text', text: 'hello' }, falsyValue]);
247+
}
248+
249+
// Test with no content + falsy structuredContent
250+
for (const falsyValue of falsyValues) {
251+
(server as any).callTool = async () => ({
252+
content: [],
253+
structuredContent: falsyValue,
254+
});
255+
256+
const tool = mcpToFunctionTool(
257+
{
258+
name: 't',
259+
description: '',
260+
inputSchema: {
261+
type: 'object',
262+
properties: {},
263+
required: [],
264+
additionalProperties: false,
265+
},
266+
},
267+
server,
268+
false,
269+
);
270+
271+
const out = await tool.invoke({} as any, '{}');
272+
expect(out).toEqual(falsyValue);
273+
}
274+
});
201275
});

0 commit comments

Comments
 (0)