fix: collect all JSON entries from MCP content arrays instead of only the first
Previously json() in createCallResult returned early on the first parseable JSON entry. When an MCP server returned multiple results in the content array, only the first item was ever surfaced. Now all parseable entries are collected. A single item still returns as a single object (backward compatible); multiple items return as an array. Also increased inspect depth in printRaw from 2 to null to prevent truncation of deeply nested list results.
This commit is contained in:
parent
98c300b3dc
commit
9746dab9d2
@ -156,5 +156,5 @@ function printRaw(raw: unknown): void {
|
||||
console.log(raw.toString());
|
||||
return;
|
||||
}
|
||||
console.log(inspect(raw, { depth: 2, maxStringLength: null, breakLength: 80 }));
|
||||
console.log(inspect(raw, { depth: null, maxStringLength: null, breakLength: 80 }));
|
||||
}
|
||||
|
||||
@ -169,13 +169,14 @@ export function createCallResult<T = unknown>(raw: T): CallResult<T> {
|
||||
|
||||
const content = extractContentArray(raw);
|
||||
if (content) {
|
||||
const collected: unknown[] = [];
|
||||
for (const entry of content) {
|
||||
if (entry && typeof entry === 'object') {
|
||||
const typedEntry = entry as Record<string, unknown>;
|
||||
if (typedEntry.type === 'json') {
|
||||
const parsed = tryParseJson(entry);
|
||||
if (parsed !== null) {
|
||||
return parsed as J;
|
||||
collected.push(parsed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -184,7 +185,7 @@ export function createCallResult<T = unknown>(raw: T): CallResult<T> {
|
||||
if (typeof text === 'string') {
|
||||
const parsedText = tryParseJson(text);
|
||||
if (parsedText !== null) {
|
||||
return parsedText as J;
|
||||
collected.push(parsedText);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@ -193,10 +194,16 @@ export function createCallResult<T = unknown>(raw: T): CallResult<T> {
|
||||
if (typeof entry === 'string') {
|
||||
const parsed = tryParseJson(entry);
|
||||
if (parsed !== null) {
|
||||
return parsed as J;
|
||||
collected.push(parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collected.length === 1) {
|
||||
return collected[0] as J;
|
||||
}
|
||||
if (collected.length > 1) {
|
||||
return collected as J;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof raw === 'string') {
|
||||
|
||||
@ -143,6 +143,36 @@ describe('createCallResult json extraction', () => {
|
||||
expect(result.json()).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('returns all items when content array has multiple json entries', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{ type: 'json', json: { id: 1, name: 'first' } },
|
||||
{ type: 'json', json: { id: 2, name: 'second' } },
|
||||
{ type: 'json', json: { id: 3, name: 'third' } },
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.json()).toEqual([
|
||||
{ id: 1, name: 'first' },
|
||||
{ id: 2, name: 'second' },
|
||||
{ id: 3, name: 'third' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns all items when content has mixed json and text-parseable-as-json entries', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{ type: 'json', json: { source: 'json-type' } },
|
||||
{ type: 'text', text: '{"source":"text-type"}' },
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.json()).toEqual([
|
||||
{ source: 'json-type' },
|
||||
{ source: 'text-type' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('extracts json from structuredContent nested inside raw wrapper', () => {
|
||||
const response = {
|
||||
raw: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user