mcp-proxy 5.7.0 → 5.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/mcp-proxy.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/{stdio-AohZZTMh.js → stdio-9KZaSDCW.js} +61 -5
- package/dist/{stdio-AohZZTMh.js.map → stdio-9KZaSDCW.js.map} +1 -1
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/startHTTPServer.test.ts +974 -0
- package/src/startHTTPServer.ts +92 -2
package/src/startHTTPServer.ts
CHANGED
|
@@ -93,6 +93,7 @@ const cleanupServer = async <T extends ServerLike>(
|
|
|
93
93
|
|
|
94
94
|
const handleStreamRequest = async <T extends ServerLike>({
|
|
95
95
|
activeTransports,
|
|
96
|
+
authenticate,
|
|
96
97
|
createServer,
|
|
97
98
|
enableJsonResponse,
|
|
98
99
|
endpoint,
|
|
@@ -107,6 +108,7 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
107
108
|
string,
|
|
108
109
|
{ server: T; transport: StreamableHTTPServerTransport }
|
|
109
110
|
>;
|
|
111
|
+
authenticate?: (request: http.IncomingMessage) => Promise<unknown>;
|
|
110
112
|
createServer: (request: http.IncomingMessage) => Promise<T>;
|
|
111
113
|
enableJsonResponse?: boolean;
|
|
112
114
|
endpoint: string;
|
|
@@ -132,6 +134,51 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
132
134
|
|
|
133
135
|
const body = await getBody(req);
|
|
134
136
|
|
|
137
|
+
// Per-request authentication in stateless mode
|
|
138
|
+
if (stateless && authenticate) {
|
|
139
|
+
try {
|
|
140
|
+
const authResult = await authenticate(req);
|
|
141
|
+
|
|
142
|
+
// Check for both falsy AND { authenticated: false } pattern
|
|
143
|
+
if (!authResult || (typeof authResult === 'object' && 'authenticated' in authResult && !authResult.authenticated)) {
|
|
144
|
+
// Extract error message if available
|
|
145
|
+
const errorMessage =
|
|
146
|
+
authResult && typeof authResult === 'object' && 'error' in authResult && typeof authResult.error === 'string'
|
|
147
|
+
? authResult.error
|
|
148
|
+
: "Unauthorized: Authentication failed";
|
|
149
|
+
|
|
150
|
+
res.setHeader("Content-Type", "application/json");
|
|
151
|
+
res.writeHead(401).end(
|
|
152
|
+
JSON.stringify({
|
|
153
|
+
error: {
|
|
154
|
+
code: -32000,
|
|
155
|
+
message: errorMessage
|
|
156
|
+
},
|
|
157
|
+
id: (body as { id?: unknown })?.id ?? null,
|
|
158
|
+
jsonrpc: "2.0"
|
|
159
|
+
})
|
|
160
|
+
);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// Extract error details from thrown errors
|
|
165
|
+
const errorMessage = error instanceof Error ? error.message : "Unauthorized: Authentication error";
|
|
166
|
+
console.error("Authentication error:", error);
|
|
167
|
+
res.setHeader("Content-Type", "application/json");
|
|
168
|
+
res.writeHead(401).end(
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
error: {
|
|
171
|
+
code: -32000,
|
|
172
|
+
message: errorMessage
|
|
173
|
+
},
|
|
174
|
+
id: (body as { id?: unknown })?.id ?? null,
|
|
175
|
+
jsonrpc: "2.0"
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
135
182
|
if (sessionId) {
|
|
136
183
|
const activeTransport = activeTransports[sessionId];
|
|
137
184
|
if (!activeTransport) {
|
|
@@ -186,6 +233,26 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
186
233
|
try {
|
|
187
234
|
server = await createServer(req);
|
|
188
235
|
} catch (error) {
|
|
236
|
+
// Detect authentication errors and return HTTP 401
|
|
237
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
238
|
+
const isAuthError = errorMessage.includes('Authentication') ||
|
|
239
|
+
errorMessage.includes('Invalid JWT') ||
|
|
240
|
+
errorMessage.includes('Token') ||
|
|
241
|
+
errorMessage.includes('Unauthorized');
|
|
242
|
+
|
|
243
|
+
if (isAuthError) {
|
|
244
|
+
res.setHeader("Content-Type", "application/json");
|
|
245
|
+
res.writeHead(401).end(JSON.stringify({
|
|
246
|
+
error: {
|
|
247
|
+
code: -32000,
|
|
248
|
+
message: errorMessage
|
|
249
|
+
},
|
|
250
|
+
id: (body as { id?: unknown })?.id ?? null,
|
|
251
|
+
jsonrpc: "2.0"
|
|
252
|
+
}));
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
|
|
189
256
|
if (handleResponseError(error, res)) {
|
|
190
257
|
return true;
|
|
191
258
|
}
|
|
@@ -218,6 +285,26 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
218
285
|
try {
|
|
219
286
|
server = await createServer(req);
|
|
220
287
|
} catch (error) {
|
|
288
|
+
// Detect authentication errors and return HTTP 401
|
|
289
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
290
|
+
const isAuthError = errorMessage.includes('Authentication') ||
|
|
291
|
+
errorMessage.includes('Invalid JWT') ||
|
|
292
|
+
errorMessage.includes('Token') ||
|
|
293
|
+
errorMessage.includes('Unauthorized');
|
|
294
|
+
|
|
295
|
+
if (isAuthError) {
|
|
296
|
+
res.setHeader("Content-Type", "application/json");
|
|
297
|
+
res.writeHead(401).end(JSON.stringify({
|
|
298
|
+
error: {
|
|
299
|
+
code: -32000,
|
|
300
|
+
message: errorMessage
|
|
301
|
+
},
|
|
302
|
+
id: (body as { id?: unknown })?.id ?? null,
|
|
303
|
+
jsonrpc: "2.0"
|
|
304
|
+
}));
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
|
|
221
308
|
if (handleResponseError(error, res)) {
|
|
222
309
|
return true;
|
|
223
310
|
}
|
|
@@ -457,6 +544,7 @@ const handleSSERequest = async <T extends ServerLike>({
|
|
|
457
544
|
|
|
458
545
|
export const startHTTPServer = async <T extends ServerLike>({
|
|
459
546
|
apiKey,
|
|
547
|
+
authenticate,
|
|
460
548
|
createServer,
|
|
461
549
|
enableJsonResponse,
|
|
462
550
|
eventStore,
|
|
@@ -470,6 +558,7 @@ export const startHTTPServer = async <T extends ServerLike>({
|
|
|
470
558
|
streamEndpoint = "/mcp",
|
|
471
559
|
}: {
|
|
472
560
|
apiKey?: string;
|
|
561
|
+
authenticate?: (request: http.IncomingMessage) => Promise<unknown>;
|
|
473
562
|
createServer: (request: http.IncomingMessage) => Promise<T>;
|
|
474
563
|
enableJsonResponse?: boolean;
|
|
475
564
|
eventStore?: EventStore;
|
|
@@ -508,8 +597,8 @@ export const startHTTPServer = async <T extends ServerLike>({
|
|
|
508
597
|
res.setHeader("Access-Control-Allow-Origin", origin.origin);
|
|
509
598
|
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
510
599
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
511
|
-
res.setHeader("Access-Control-Allow-Headers", "
|
|
512
|
-
res.setHeader("Access-Control-Expose-Headers", "
|
|
600
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, Mcp-Session-Id, Last-Event-Id");
|
|
601
|
+
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
|
|
513
602
|
} catch (error) {
|
|
514
603
|
console.error("[mcp-proxy] error parsing origin", error);
|
|
515
604
|
}
|
|
@@ -553,6 +642,7 @@ export const startHTTPServer = async <T extends ServerLike>({
|
|
|
553
642
|
streamEndpoint &&
|
|
554
643
|
(await handleStreamRequest({
|
|
555
644
|
activeTransports: activeStreamTransports,
|
|
645
|
+
authenticate,
|
|
556
646
|
createServer,
|
|
557
647
|
enableJsonResponse,
|
|
558
648
|
endpoint: streamEndpoint,
|