diff --git a/backend/src/mcp/orgClient.ts b/backend/src/mcp/orgClient.ts index bf2b5d2..ad638f1 100644 --- a/backend/src/mcp/orgClient.ts +++ b/backend/src/mcp/orgClient.ts @@ -1,6 +1,7 @@ import { config } from '../config.js'; type OrgToolResult = { content: { type: string; text: string }[]; isError?: boolean }; +type Envelope = { result?: OrgToolResult; error?: { message: string } }; let _requestId = 1; @@ -38,7 +39,19 @@ export async function callOrgTool( }; } - const envelope = await res.json() as { result?: OrgToolResult; error?: { message: string } }; + const contentType = res.headers.get('content-type') ?? ''; + const rawText = await res.text(); + let envelope: Envelope; + try { + envelope = contentType.includes('text/event-stream') + ? parseSseEnvelope(rawText) + : JSON.parse(rawText); + } catch (err) { + return { + content: [{ type: 'text', text: `Failed to parse mcp-org response (${contentType}): ${String(err)} — body: ${rawText.slice(0, 200)}` }], + isError: true, + }; + } if (envelope.error) { return { content: [{ type: 'text', text: `mcp-org error: ${envelope.error.message}` }], isError: true }; } @@ -47,3 +60,14 @@ export async function callOrgTool( return { content: [{ type: 'text', text: `Failed to reach mcp-org: ${String(err)}` }], isError: true }; } } + +function parseSseEnvelope(text: string): Envelope { + for (const frame of text.split(/\r?\n\r?\n/)) { + const dataLines: string[] = []; + for (const line of frame.split(/\r?\n/)) { + if (line.startsWith('data:')) dataLines.push(line.slice(5).trimStart()); + } + if (dataLines.length > 0) return JSON.parse(dataLines.join('\n')) as Envelope; + } + throw new Error('no data lines in SSE response'); +}