import { describe, expect, it } from '@jest/globals'; import { createMCPToolResult, extractMCPResult, type MCPToolResult } from '../ToolHelpers.js'; const wrapContentResult = (payload: Record): MCPToolResult => ({ content: [{ type: 'text', text: JSON.stringify(payload) }] }); const parseResult = (result: string): Record => JSON.parse(result); describe('MCPToolResult Helpers (content-only format)', () => { describe('extractMCPResult - input variations', () => { it.each([ [ 'standard MCPToolResult payload', wrapContentResult({ data: 'from-text' }), { data: 'from-text' } ], [ 'plain object without content[]', { plain: 'object', without: 'mcp-fields' }, { plain: 'object', without: 'mcp-fields' } ], [ 'content entry missing text field (falls back to plain object)', { content: [{ type: 'text' as const }] as any }, { content: [{ type: 'text' }] } ], [ 'empty content array', { content: [] }, { content: [] } ], [ 'null input', null, { error: 'Invalid tool result format' } ], [ 'undefined input', undefined, { error: 'Invalid tool result format' } ], [ 'string input', 'string input', { error: 'Failed to parse result string as JSON', raw: 'string input' } ] ])('handles %s', (_description, input, expected) => { expect(extractMCPResult(input as unknown)).toEqual(expected); }); it('returns parse diagnostics when content text is invalid JSON', () => { const result: MCPToolResult = { content: [{ type: 'text', text: 'not valid json{' }] }; expect(extractMCPResult(result)).toEqual({ error: 'Failed to parse content[0].text as JSON', raw: 'not valid json{' }); }); }); describe('createMCPToolResult - serialization', () => { it.each([ [{ simple: 'data' }, undefined], [{ nested: { value: 'test' } }, undefined], [{ value: null, another: 'test' }, undefined], [{ simple: 'data' }, { requestId: '123' }] ])('serializes %o with metadata %o', (data, metadata) => { const result = createMCPToolResult(data, metadata); const parsed = parseResult(result); expect(typeof result).toBe('string'); expect(parsed).toEqual({ ...data, ...(metadata || {}) }); }); it('allows metadata to override data fields when keys collide', () => { const serialized = createMCPToolResult( { requestId: 'data', payload: 'value' }, { requestId: 'meta' } ); expect(parseResult(serialized)).toEqual({ requestId: 'meta', payload: 'value' }); }); }); describe('Integration patterns', () => { it('extracts FastMCP-style tool results', () => { const handlerResult: MCPToolResult = { content: [{ type: 'text', text: createMCPToolResult({ response: 'test-data' }, { requestId: 'abc' }) }] }; expect(extractMCPResult(handlerResult)).toEqual({ response: 'test-data', requestId: 'abc' }); }); it('preserves legacy plain objects', () => { const legacyResult = { legacy: 'response', data: 123 }; expect(extractMCPResult(legacyResult)).toEqual(legacyResult); }); it('surfaced handler exceptions via wrapper error handling', async () => { const executeWrapper = async (handler: () => Promise) => { try { const result = await handler(); return extractMCPResult(result); } catch (error) { return { error: (error as Error).message }; } }; const result = await executeWrapper(async () => { throw new Error('Test error'); }); expect(result).toEqual({ error: 'Test error' }); }); }); describe('Edge cases', () => { it('throws when serializing circular references', () => { const circular: any = { a: 'test' }; circular.self = circular; expect(() => createMCPToolResult(circular)).toThrow(/circular/i); }); it('handles very large objects', () => { const largeData = { items: Array.from({ length: 1000 }, (_, i) => ({ id: i, data: `Item ${i}`, nested: { value: i * 2 } })) }; const serialized = createMCPToolResult(largeData); expect(parseResult(serialized)).toEqual(largeData); }); it('preserves unicode and special characters', () => { const unicodeData = { text: '🔥龍騎士', emoji: '✅❌⚠️', japanese: 'テスト', html: '', quotes: 'Test "quoted" text', newlines: 'Line1\nLine2\rLine3', tabs: 'Col1\tCol2' }; const serialized = createMCPToolResult(unicodeData); expect(parseResult(serialized)).toEqual(unicodeData); }); }); describe('Regression: SecondOpinionAgent compatibility', () => { it('matches second-opinion persistence payloads', () => { const mockResult = wrapContentResult({ synthesis: 'test-data', metadata: { secondOpinion: { primary: { model: 'primary', response: 'a' }, synthesis: { model: 'synth', response: 'combined' } } } }); expect(extractMCPResult(mockResult)).toEqual({ synthesis: 'test-data', metadata: { secondOpinion: { primary: { model: 'primary', response: 'a' }, synthesis: { model: 'synth', response: 'combined' } } } }); }); }); });