@@ -41,14 +41,53 @@ const { values } = parseArgs({
4141 } ,
4242} ) ;
4343
44+ // Function to get HTTP headers.
45+ // Supports only "sse" and "streamable-http" transport types.
46+ const getHttpHeaders = (
47+ req : express . Request ,
48+ transportType : string ,
49+ ) : HeadersInit => {
50+ const headers : HeadersInit = {
51+ Accept :
52+ transportType === "sse"
53+ ? "text/event-stream"
54+ : "text/event-stream, application/json" ,
55+ } ;
56+ const defaultHeaders =
57+ transportType === "sse"
58+ ? SSE_HEADERS_PASSTHROUGH
59+ : STREAMABLE_HTTP_HEADERS_PASSTHROUGH ;
60+
61+ for ( const key of defaultHeaders ) {
62+ if ( req . headers [ key ] === undefined ) {
63+ continue ;
64+ }
65+
66+ const value = req . headers [ key ] ;
67+ headers [ key ] = Array . isArray ( value ) ? value [ value . length - 1 ] : value ;
68+ }
69+
70+ // If the header "x-custom-auth-header" is present, use its value as the custom header name.
71+ if ( req . headers [ "x-custom-auth-header" ] !== undefined ) {
72+ const customHeaderName = req . headers [ "x-custom-auth-header" ] as string ;
73+ const lowerCaseHeaderName = customHeaderName . toLowerCase ( ) ;
74+ if ( req . headers [ lowerCaseHeaderName ] !== undefined ) {
75+ const value = req . headers [ lowerCaseHeaderName ] ;
76+ headers [ customHeaderName ] = value as string ;
77+ }
78+ }
79+ return headers ;
80+ } ;
81+
4482const app = express ( ) ;
4583app . use ( cors ( ) ) ;
4684app . use ( ( req , res , next ) => {
4785 res . header ( "Access-Control-Expose-Headers" , "mcp-session-id" ) ;
4886 next ( ) ;
4987} ) ;
5088
51- const webAppTransports : Map < string , Transport > = new Map < string , Transport > ( ) ; // Transports by sessionId
89+ const webAppTransports : Map < string , Transport > = new Map < string , Transport > ( ) ; // Web app transports by web app sessionId
90+ const serverTransports : Map < string , Transport > = new Map < string , Transport > ( ) ; // Server Transports by web app sessionId
5291
5392const createTransport = async ( req : express . Request ) : Promise < Transport > => {
5493 const query = req . query ;
@@ -79,18 +118,8 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
79118 return transport ;
80119 } else if ( transportType === "sse" ) {
81120 const url = query . url as string ;
82- const headers : HeadersInit = {
83- Accept : "text/event-stream" ,
84- } ;
85-
86- for ( const key of SSE_HEADERS_PASSTHROUGH ) {
87- if ( req . headers [ key ] === undefined ) {
88- continue ;
89- }
90121
91- const value = req . headers [ key ] ;
92- headers [ key ] = Array . isArray ( value ) ? value [ value . length - 1 ] : value ;
93- }
122+ const headers = getHttpHeaders ( req , transportType ) ;
94123
95124 console . log ( `SSE transport: url=${ url } , headers=${ Object . keys ( headers ) } ` ) ;
96125
@@ -107,18 +136,7 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
107136 console . log ( "Connected to SSE transport" ) ;
108137 return transport ;
109138 } else if ( transportType === "streamable-http" ) {
110- const headers : HeadersInit = {
111- Accept : "text/event-stream, application/json" ,
112- } ;
113-
114- for ( const key of STREAMABLE_HTTP_HEADERS_PASSTHROUGH ) {
115- if ( req . headers [ key ] === undefined ) {
116- continue ;
117- }
118-
119- const value = req . headers [ key ] ;
120- headers [ key ] = Array . isArray ( value ) ? value [ value . length - 1 ] : value ;
121- }
139+ const headers = getHttpHeaders ( req , transportType ) ;
122140
123141 const transport = new StreamableHTTPClientTransport (
124142 new URL ( query . url as string ) ,
@@ -137,8 +155,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
137155 }
138156} ;
139157
140- let backingServerTransport : Transport | undefined ;
141-
142158app . get ( "/mcp" , async ( req , res ) => {
143159 const sessionId = req . headers [ "mcp-session-id" ] as string ;
144160 console . log ( `Received GET message for sessionId ${ sessionId } ` ) ;
@@ -161,12 +177,12 @@ app.get("/mcp", async (req, res) => {
161177app . post ( "/mcp" , async ( req , res ) => {
162178 const sessionId = req . headers [ "mcp-session-id" ] as string | undefined ;
163179 console . log ( `Received POST message for sessionId ${ sessionId } ` ) ;
180+ let serverTransport : Transport | undefined ;
164181 if ( ! sessionId ) {
165182 try {
166183 console . log ( "New streamable-http connection" ) ;
167184 try {
168- await backingServerTransport ?. close ( ) ;
169- backingServerTransport = await createTransport ( req ) ;
185+ serverTransport = await createTransport ( req ) ;
170186 } catch ( error ) {
171187 if ( error instanceof SseError && error . code === 401 ) {
172188 console . error (
@@ -180,12 +196,13 @@ app.post("/mcp", async (req, res) => {
180196 throw error ;
181197 }
182198
183- console . log ( "Connected MCP client to backing server transport" ) ;
199+ console . log ( "Connected MCP client to server transport" ) ;
184200
185201 const webAppTransport = new StreamableHTTPServerTransport ( {
186202 sessionIdGenerator : randomUUID ,
187203 onsessioninitialized : ( sessionId ) => {
188204 webAppTransports . set ( sessionId , webAppTransport ) ;
205+ serverTransports . set ( sessionId , serverTransport ! ) ;
189206 console . log ( "Created streamable web app transport " + sessionId ) ;
190207 } ,
191208 } ) ;
@@ -194,7 +211,7 @@ app.post("/mcp", async (req, res) => {
194211
195212 mcpProxy ( {
196213 transportToClient : webAppTransport ,
197- transportToServer : backingServerTransport ,
214+ transportToServer : serverTransport ,
198215 } ) ;
199216
200217 await ( webAppTransport as StreamableHTTPServerTransport ) . handleRequest (
@@ -229,10 +246,9 @@ app.post("/mcp", async (req, res) => {
229246app . get ( "/stdio" , async ( req , res ) => {
230247 try {
231248 console . log ( "New connection" ) ;
232-
249+ let serverTransport : Transport | undefined ;
233250 try {
234- await backingServerTransport ?. close ( ) ;
235- backingServerTransport = await createTransport ( req ) ;
251+ serverTransport = await createTransport ( req ) ;
236252 } catch ( error ) {
237253 if ( error instanceof SseError && error . code === 401 ) {
238254 console . error (
@@ -250,26 +266,24 @@ app.get("/stdio", async (req, res) => {
250266
251267 const webAppTransport = new SSEServerTransport ( "/message" , res ) ;
252268 webAppTransports . set ( webAppTransport . sessionId , webAppTransport ) ;
253-
254- console . log ( "Created web app transport " ) ;
269+ serverTransports . set ( webAppTransport . sessionId , serverTransport ) ;
270+ console . log ( "Created client/server transports " ) ;
255271
256272 await webAppTransport . start ( ) ;
257- ( backingServerTransport as StdioClientTransport ) . stderr ! . on (
258- "data" ,
259- ( chunk ) => {
260- webAppTransport . send ( {
261- jsonrpc : "2.0" ,
262- method : "notifications/stderr" ,
263- params : {
264- content : chunk . toString ( ) ,
265- } ,
266- } ) ;
267- } ,
268- ) ;
273+
274+ ( serverTransport as StdioClientTransport ) . stderr ! . on ( "data" , ( chunk ) => {
275+ webAppTransport . send ( {
276+ jsonrpc : "2.0" ,
277+ method : "notifications/stderr" ,
278+ params : {
279+ content : chunk . toString ( ) ,
280+ } ,
281+ } ) ;
282+ } ) ;
269283
270284 mcpProxy ( {
271285 transportToClient : webAppTransport ,
272- transportToServer : backingServerTransport ,
286+ transportToServer : serverTransport ,
273287 } ) ;
274288
275289 console . log ( "Set up MCP proxy" ) ;
@@ -284,10 +298,9 @@ app.get("/sse", async (req, res) => {
284298 console . log (
285299 "New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http" ,
286300 ) ;
287-
301+ let serverTransport : Transport | undefined ;
288302 try {
289- await backingServerTransport ?. close ( ) ;
290- backingServerTransport = await createTransport ( req ) ;
303+ serverTransport = await createTransport ( req ) ;
291304 } catch ( error ) {
292305 if ( error instanceof SseError && error . code === 401 ) {
293306 console . error (
@@ -305,13 +318,15 @@ app.get("/sse", async (req, res) => {
305318
306319 const webAppTransport = new SSEServerTransport ( "/message" , res ) ;
307320 webAppTransports . set ( webAppTransport . sessionId , webAppTransport ) ;
308- console . log ( "Created web app transport" ) ;
321+ console . log ( "Created client transport" ) ;
322+ serverTransports . set ( webAppTransport . sessionId , serverTransport ) ;
323+ console . log ( "Created server transport" ) ;
309324
310325 await webAppTransport . start ( ) ;
311326
312327 mcpProxy ( {
313328 transportToClient : webAppTransport ,
314- transportToServer : backingServerTransport ,
329+ transportToServer : serverTransport ,
315330 } ) ;
316331
317332 console . log ( "Set up MCP proxy" ) ;
0 commit comments