1- import { randomUUID } from 'node:crypto'
21import type { IncomingMessage , ServerResponse } from 'node:http'
32import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
4- import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js'
53import type { SevLogger } from '@transloadit/sev-logger'
64import {
75 applyCorsHeaders ,
@@ -23,6 +21,7 @@ export type TransloaditMcpHttpOptions = TransloaditMcpServerOptions & {
2321 path ?: string
2422 metricsPath ?: string | false
2523 metricsAuth ?: { username : string ; password : string }
24+ // Ignored on purpose: the hosted HTTP server is stateless and does not mint session IDs.
2625 sessionIdGenerator ?: ( ( ) => string ) | undefined
2726 logger ?: SevLogger
2827}
@@ -36,7 +35,7 @@ export type TransloaditMcpHttpHandler = ((
3635
3736const defaultPath = '/mcp'
3837
39- /** Read the full request body and JSON-parse it so `isInitializeRequest` can inspect the payload . */
38+ /** Read the full request body and JSON-parse it before handing it to the MCP transport . */
4039function readJsonBody ( req : IncomingMessage ) : Promise < unknown > {
4140 return new Promise ( ( resolve , reject ) => {
4241 const chunks : Buffer [ ] = [ ]
@@ -64,10 +63,6 @@ export function createTransloaditMcpHttpHandler(
6463 const metricsPath =
6564 options . metricsPath === false ? undefined : normalizePath ( options . metricsPath ?? '/metrics' )
6665 const metricsAuth = options . metricsAuth
67- const sessionIdGenerator = options . sessionIdGenerator ?? ( ( ) => randomUUID ( ) )
68-
69- // Per-session transport map: each MCP client gets its own transport + server pair.
70- const transports = new Map < string , StreamableHTTPServerTransport > ( )
7166
7267 const serverCardJson = JSON . stringify (
7368 buildServerCard ( expectedPath , { authKey : options . authKey , authSecret : options . authSecret } ) ,
@@ -162,78 +157,33 @@ export function createTransloaditMcpHttpHandler(
162157 return
163158 }
164159
165- // Route request to the correct per-session transport.
166- const sessionId = req . headers [ 'mcp-session-id' ] as string | undefined
167- let transport : StreamableHTTPServerTransport | undefined
168-
169- if ( sessionId ) {
170- transport = transports . get ( sessionId )
171- if ( ! transport ) {
172- res . statusCode = 404
173- res . setHeader ( 'Content-Type' , 'application/json' )
174- res . end (
175- JSON . stringify ( {
176- jsonrpc : '2.0' ,
177- error : { code : - 32000 , message : 'Session not found' } ,
178- id : null ,
179- } ) ,
180- )
181- return
182- }
183- }
184-
185- // For POST requests without a session, read the body to check for initialization.
186- let parsedBody : unknown
187- if ( req . method === 'POST' && ! transport ) {
188- parsedBody = await readJsonBody ( req )
189- if ( isInitializeRequest ( parsedBody ) ) {
190- const newTransport = new StreamableHTTPServerTransport ( {
191- sessionIdGenerator,
192- allowedOrigins : options . allowedOrigins ,
193- allowedHosts : options . allowedHosts ,
194- enableDnsRebindingProtection : options . enableDnsRebindingProtection ,
195- onsessioninitialized : ( sid ) => {
196- transports . set ( sid , newTransport )
197- } ,
198- } )
199-
200- newTransport . onclose = ( ) => {
201- const sid = newTransport . sessionId
202- if ( sid ) {
203- transports . delete ( sid )
204- }
205- }
206-
207- const server = createTransloaditMcpServer ( options )
208- await server . connect ( newTransport )
209- transport = newTransport
210- } else {
211- res . statusCode = 400
212- res . setHeader ( 'Content-Type' , 'application/json' )
213- res . end (
214- JSON . stringify ( {
215- jsonrpc : '2.0' ,
216- error : { code : - 32600 , message : 'Bad Request: No valid session ID provided' } ,
217- id : null ,
218- } ) ,
219- )
220- return
221- }
222- }
223-
224- if ( ! transport ) {
225- res . statusCode = 400
160+ if ( req . method !== 'POST' ) {
161+ res . statusCode = 405
226162 res . setHeader ( 'Content-Type' , 'application/json' )
227163 res . end (
228164 JSON . stringify ( {
229165 jsonrpc : '2.0' ,
230- error : { code : - 32600 , message : 'Bad Request: No valid session ID provided ' } ,
166+ error : { code : - 32000 , message : 'Method not allowed. ' } ,
231167 id : null ,
232168 } ) ,
233169 )
234170 return
235171 }
236172
173+ const parsedBody = await readJsonBody ( req )
174+ const transport = new StreamableHTTPServerTransport ( {
175+ sessionIdGenerator : undefined ,
176+ allowedOrigins : options . allowedOrigins ,
177+ allowedHosts : options . allowedHosts ,
178+ enableDnsRebindingProtection : options . enableDnsRebindingProtection ,
179+ } )
180+ const server = createTransloaditMcpServer ( options )
181+ res . on ( 'close' , ( ) => {
182+ void transport . close ( )
183+ void server . close ( )
184+ } )
185+ await server . connect ( transport )
186+
237187 try {
238188 await transport . handleRequest ( req , res , parsedBody )
239189 } catch {
@@ -245,9 +195,7 @@ export function createTransloaditMcpHttpHandler(
245195 } ) as TransloaditMcpHttpHandler
246196
247197 handler . close = async ( ) => {
248- const closePromises = [ ...transports . values ( ) ] . map ( ( t ) => t . close ( ) )
249- await Promise . all ( closePromises )
250- transports . clear ( )
198+ return Promise . resolve ( )
251199 }
252200
253201 return handler
0 commit comments