diff --git a/packages/core/src/mcp/client.test.ts b/packages/core/src/mcp/client.test.ts index ac03416..3ae92b6 100644 --- a/packages/core/src/mcp/client.test.ts +++ b/packages/core/src/mcp/client.test.ts @@ -11,6 +11,7 @@ import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { + capMcpOutput, connectAllMcpServers, connectMcpServer, expandMcpResourceRefs, @@ -442,6 +443,19 @@ describe('parseHelperOutput', () => { }); }); +describe('capMcpOutput', () => { + it('passes through output under the cap', () => { + expect(capMcpOutput('short', 100)).toBe('short'); + }); + it('truncates over-long output with a notice', () => { + const big = 'x'.repeat(120); + const out = capMcpOutput(big, 100); + expect(out.startsWith('x'.repeat(100))).toBe(true); + expect(out).toMatch(/20 characters truncated/); + expect(out).toMatch(/100-char cap/); + }); +}); + describe('parseResourceRefs', () => { it('finds @server:scheme://path references', () => { const refs = parseResourceRefs( diff --git a/packages/core/src/mcp/client.ts b/packages/core/src/mcp/client.ts index 0e64d52..6a533dc 100644 --- a/packages/core/src/mcp/client.ts +++ b/packages/core/src/mcp/client.ts @@ -179,6 +179,20 @@ interface FinishableTransport extends Transport { finishAuth(code: string): Promise; } +/** Max characters of MCP tool output fed back to the model (keeps a runaway + * server response from blowing the context window). */ +export const MCP_OUTPUT_CAP = 50_000; + +/** Truncate over-long MCP output with a visible notice. Exported for testing. */ +export function capMcpOutput(text: string, cap = MCP_OUTPUT_CAP): string { + if (text.length <= cap) return text; + const omitted = text.length - cap; + return ( + text.slice(0, cap) + + `\n\n[… ${omitted} characters truncated — MCP output exceeded the ${cap}-char cap]` + ); +} + /** * Connect to one MCP server (stdio / http / sse). Returns a handle containing * the registered tools (qualified as `mcp____`). @@ -264,7 +278,7 @@ export async function connectMcpServer( .map((c) => c.text ?? '') .join('\n') || ''; return { - content: textParts || '(MCP tool returned no text content)', + content: textParts ? capMcpOutput(textParts) : '(MCP tool returned no text content)', isError: result.isError === true, data: { serverName, serverToolName: t.name }, };