11import { Server } from '@modelcontextprotocol/sdk/server/index.js'
2- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp .js'
2+ import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp .js'
33import {
44 CallToolRequestSchema ,
55 type CallToolResult ,
@@ -166,16 +166,6 @@ function createError(id: RequestId, code: ErrorCode | number, message: string):
166166 }
167167}
168168
169- function normalizeRequestHeaders ( request : NextRequest ) : HeaderMap {
170- const headers : HeaderMap = { }
171-
172- request . headers . forEach ( ( value , key ) => {
173- headers [ key . toLowerCase ( ) ] = value
174- } )
175-
176- return headers
177- }
178-
179169function readHeader ( headers : HeaderMap | undefined , name : string ) : string | undefined {
180170 if ( ! headers ) return undefined
181171 const value = headers [ name . toLowerCase ( ) ]
@@ -185,190 +175,6 @@ function readHeader(headers: HeaderMap | undefined, name: string): string | unde
185175 return value
186176}
187177
188- class NextResponseCapture {
189- private _status = 200
190- private _headers = new Headers ( )
191- private _controller : ReadableStreamDefaultController < Uint8Array > | null = null
192- private _pendingChunks : Uint8Array [ ] = [ ]
193- private _closeHandlers : Array < ( ) => void > = [ ]
194- private _errorHandlers : Array < ( error : Error ) => void > = [ ]
195- private _headersWritten = false
196- private _ended = false
197- private _headersPromise : Promise < void >
198- private _resolveHeaders : ( ( ) => void ) | null = null
199- private _endedPromise : Promise < void >
200- private _resolveEnded : ( ( ) => void ) | null = null
201- readonly readable : ReadableStream < Uint8Array >
202-
203- constructor ( ) {
204- this . _headersPromise = new Promise < void > ( ( resolve ) => {
205- this . _resolveHeaders = resolve
206- } )
207-
208- this . _endedPromise = new Promise < void > ( ( resolve ) => {
209- this . _resolveEnded = resolve
210- } )
211-
212- this . readable = new ReadableStream < Uint8Array > ( {
213- start : ( controller ) => {
214- this . _controller = controller
215- if ( this . _pendingChunks . length > 0 ) {
216- for ( const chunk of this . _pendingChunks ) {
217- controller . enqueue ( chunk )
218- }
219- this . _pendingChunks = [ ]
220- }
221- } ,
222- cancel : ( ) => {
223- this . _ended = true
224- this . _resolveEnded ?.( )
225- this . triggerCloseHandlers ( )
226- } ,
227- } )
228- }
229-
230- private markHeadersWritten ( ) : void {
231- if ( this . _headersWritten ) return
232- this . _headersWritten = true
233- this . _resolveHeaders ?.( )
234- }
235-
236- private triggerCloseHandlers ( ) : void {
237- for ( const handler of this . _closeHandlers ) {
238- try {
239- handler ( )
240- } catch ( error ) {
241- this . triggerErrorHandlers ( toError ( error ) )
242- }
243- }
244- }
245-
246- private triggerErrorHandlers ( error : Error ) : void {
247- for ( const errorHandler of this . _errorHandlers ) {
248- errorHandler ( error )
249- }
250- }
251-
252- private normalizeChunk ( chunk : unknown ) : Uint8Array | null {
253- if ( typeof chunk === 'string' ) {
254- return new TextEncoder ( ) . encode ( chunk )
255- }
256-
257- if ( chunk instanceof Uint8Array ) {
258- return chunk
259- }
260-
261- if ( chunk === undefined || chunk === null ) {
262- return null
263- }
264-
265- return new TextEncoder ( ) . encode ( String ( chunk ) )
266- }
267-
268- writeHead ( status : number , headers ?: Record < string , string | number | string [ ] > ) : this {
269- this . _status = status
270-
271- if ( headers ) {
272- Object . entries ( headers ) . forEach ( ( [ key , value ] ) => {
273- if ( Array . isArray ( value ) ) {
274- this . _headers . set ( key , value . join ( ', ' ) )
275- } else {
276- this . _headers . set ( key , String ( value ) )
277- }
278- } )
279- }
280-
281- this . markHeadersWritten ( )
282- return this
283- }
284-
285- flushHeaders ( ) : this {
286- this . markHeadersWritten ( )
287- return this
288- }
289-
290- write ( chunk : unknown ) : boolean {
291- const normalized = this . normalizeChunk ( chunk )
292- if ( ! normalized ) return true
293-
294- this . markHeadersWritten ( )
295-
296- if ( this . _controller ) {
297- try {
298- this . _controller . enqueue ( normalized )
299- } catch ( error ) {
300- this . triggerErrorHandlers ( toError ( error ) )
301- }
302- } else {
303- this . _pendingChunks . push ( normalized )
304- }
305-
306- return true
307- }
308-
309- end ( chunk ?: unknown ) : this {
310- if ( chunk !== undefined ) this . write ( chunk )
311- this . markHeadersWritten ( )
312- if ( this . _ended ) return this
313-
314- this . _ended = true
315- this . _resolveEnded ?.( )
316-
317- if ( this . _controller ) {
318- try {
319- this . _controller . close ( )
320- } catch ( error ) {
321- this . triggerErrorHandlers ( toError ( error ) )
322- }
323- }
324-
325- this . triggerCloseHandlers ( )
326-
327- return this
328- }
329-
330- async waitForHeaders ( timeoutMs = 30000 ) : Promise < void > {
331- if ( this . _headersWritten ) return
332-
333- await Promise . race ( [
334- this . _headersPromise ,
335- new Promise < void > ( ( resolve ) => {
336- setTimeout ( resolve , timeoutMs )
337- } ) ,
338- ] )
339- }
340-
341- async waitForEnd ( timeoutMs = 30000 ) : Promise < void > {
342- if ( this . _ended ) return
343-
344- await Promise . race ( [
345- this . _endedPromise ,
346- new Promise < void > ( ( resolve ) => {
347- setTimeout ( resolve , timeoutMs )
348- } ) ,
349- ] )
350- }
351-
352- on ( event : 'close' | 'error' , handler : ( ( ) => void ) | ( ( error : Error ) => void ) ) : this {
353- if ( event === 'close' ) {
354- this . _closeHandlers . push ( handler as ( ) => void )
355- }
356-
357- if ( event === 'error' ) {
358- this . _errorHandlers . push ( handler as ( error : Error ) => void )
359- }
360-
361- return this
362- }
363-
364- toNextResponse ( ) : NextResponse {
365- return new NextResponse ( this . readable , {
366- status : this . _status ,
367- headers : this . _headers ,
368- } )
369- }
370- }
371-
372178function buildMcpServer ( abortSignal ?: AbortSignal ) : Server {
373179 const server = new Server (
374180 {
@@ -503,29 +309,17 @@ function buildMcpServer(abortSignal?: AbortSignal): Server {
503309async function handleMcpRequestWithSdk (
504310 request : NextRequest ,
505311 parsedBody : unknown
506- ) : Promise < NextResponse > {
312+ ) : Promise < Response > {
507313 const server = buildMcpServer ( request . signal )
508- const transport = new StreamableHTTPServerTransport ( {
314+ const transport = new WebStandardStreamableHTTPServerTransport ( {
509315 sessionIdGenerator : undefined ,
510316 enableJsonResponse : true ,
511317 } )
512318
513- const responseCapture = new NextResponseCapture ( )
514- const requestAdapter = {
515- method : request . method ,
516- headers : normalizeRequestHeaders ( request ) ,
517- }
518-
519319 await server . connect ( transport )
520320
521321 try {
522- await transport . handleRequest ( requestAdapter as any , responseCapture as any , parsedBody )
523- await responseCapture . waitForHeaders ( )
524- // Must exceed the longest possible tool execution.
525- // Using ORCHESTRATION_TIMEOUT_MS + 60 s buffer so the orchestrator can
526- // finish or time-out on its own before the transport is torn down.
527- await responseCapture . waitForEnd ( ORCHESTRATION_TIMEOUT_MS + 60_000 )
528- return responseCapture . toNextResponse ( )
322+ return await transport . handleRequest ( request , { parsedBody } )
529323 } finally {
530324 await server . close ( ) . catch ( ( ) => { } )
531325 await transport . close ( ) . catch ( ( ) => { } )
0 commit comments