From 27181988b010c203c43a9b95e4b1f7804ba12756 Mon Sep 17 00:00:00 2001 From: localhost Date: Thu, 20 Aug 2026 19:07:08 +0200 Subject: [PATCH] fix(mcp): enable JSON response mode for HTTP transport Avoid SSE stream response for finite HTTP MCP tool calls by enabling enableJsonResponse option on transport. --- src/router/mcp.test.ts | 51 ++++++++++++++++++++++++++++++++++++++++++ src/router/mcp.ts | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/router/mcp.test.ts diff --git a/src/router/mcp.test.ts b/src/router/mcp.test.ts new file mode 100644 index 0000000..cc5ff64 --- /dev/null +++ b/src/router/mcp.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it, mock } from 'bun:test' + +process.env.MCP_SECRET = 'test-secret' + +mock.module('@/utils/archive', () => ({ + archiveVideo: async (input: string) => { + // Integration delay simulation to test async handler waiting + await Bun.sleep(50) + return { success: true, message: 'Video archived successfully.', videoId: input } + }, + addToSizeWhitelist: async () => ({ success: true, message: 'Whitelisted.' }), + getVideoMetadata: async () => ({ success: true, metadata: {} }), + extractVideoId: (input: string) => input +})) + +// Dynamic import required so mock.module executes before mcp module is imported +const { default: app } = await import('./mcp') + +describe('HTTP MCP Transport', () => { + it('returns JSON response for delayed tool call without streaming SSE', async () => { + const startTime = Date.now() + const response = await app.handle( + new Request('http://localhost/api/mcp/', { + method: 'POST', + headers: { + 'Authorization': 'Bearer test-secret', + 'Accept': 'application/json, text/event-stream', + 'Content-Type': 'application/json', + 'Mcp-Protocol-Version': '2025-03-26' + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'tools/call', + params: { + name: 'archive_video', + arguments: { videoId: 'dQw4w9WgXcQ' } + } + }) + }) + ) + + const duration = Date.now() - startTime + expect(duration).toBeLessThan(1000) + expect(response.status).toBe(200) + expect(response.headers.get('content-type')).toContain('application/json') + + const body = await response.json() + expect(body.result.content[0].text).toContain('Video archived successfully.') + }) +}) diff --git a/src/router/mcp.ts b/src/router/mcp.ts index 7b8b9b1..8d84ba9 100644 --- a/src/router/mcp.ts +++ b/src/router/mcp.ts @@ -83,7 +83,7 @@ function createMcpServer() { } async function handleMcpStreamRequest(request: Request): Promise { - const transport = new WebStandardStreamableHTTPServerTransport() + const transport = new WebStandardStreamableHTTPServerTransport({ enableJsonResponse: true }) const mcpServer = createMcpServer() await mcpServer.connect(transport) return await transport.handleRequest(request)