mcp-proxy 5.8.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.js +1 -1
- package/dist/{stdio-so1-I7Pn.js → stdio-9KZaSDCW.js} +33 -4
- package/dist/{stdio-so1-I7Pn.js.map → stdio-9KZaSDCW.js.map} +1 -1
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/startHTTPServer.test.ts +494 -0
- package/src/startHTTPServer.ts +53 -3
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -1181,3 +1181,497 @@ it("includes Authorization in CORS allowed headers", async () => {
|
|
|
1181
1181
|
|
|
1182
1182
|
await httpServer.close();
|
|
1183
1183
|
});
|
|
1184
|
+
|
|
1185
|
+
// Tests for FastMCP-style authentication with { authenticated: false } pattern
|
|
1186
|
+
|
|
1187
|
+
it("returns 401 when authenticate callback returns { authenticated: false } in stateless mode", async () => {
|
|
1188
|
+
const stdioTransport = new StdioClientTransport({
|
|
1189
|
+
args: ["src/fixtures/simple-stdio-server.ts"],
|
|
1190
|
+
command: "tsx",
|
|
1191
|
+
});
|
|
1192
|
+
|
|
1193
|
+
const stdioClient = new Client(
|
|
1194
|
+
{
|
|
1195
|
+
name: "mcp-proxy",
|
|
1196
|
+
version: "1.0.0",
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
capabilities: {},
|
|
1200
|
+
},
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
await stdioClient.connect(stdioTransport);
|
|
1204
|
+
|
|
1205
|
+
const serverVersion = stdioClient.getServerVersion() as {
|
|
1206
|
+
name: string;
|
|
1207
|
+
version: string;
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
const serverCapabilities = stdioClient.getServerCapabilities() as {
|
|
1211
|
+
capabilities: Record<string, unknown>;
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
const port = await getRandomPort();
|
|
1215
|
+
|
|
1216
|
+
// Mock authenticate callback that returns { authenticated: false }
|
|
1217
|
+
const authenticate = vi.fn().mockResolvedValue({
|
|
1218
|
+
authenticated: false,
|
|
1219
|
+
error: "Invalid JWT token",
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
const httpServer = await startHTTPServer({
|
|
1223
|
+
authenticate,
|
|
1224
|
+
createServer: async () => {
|
|
1225
|
+
const mcpServer = new Server(serverVersion, {
|
|
1226
|
+
capabilities: serverCapabilities,
|
|
1227
|
+
});
|
|
1228
|
+
|
|
1229
|
+
await proxyServer({
|
|
1230
|
+
client: stdioClient,
|
|
1231
|
+
server: mcpServer,
|
|
1232
|
+
serverCapabilities,
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
return mcpServer;
|
|
1236
|
+
},
|
|
1237
|
+
port,
|
|
1238
|
+
stateless: true,
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
// Create client with invalid Bearer token
|
|
1242
|
+
const streamTransport = new StreamableHTTPClientTransport(
|
|
1243
|
+
new URL(`http://localhost:${port}/mcp`),
|
|
1244
|
+
{
|
|
1245
|
+
requestInit: {
|
|
1246
|
+
headers: {
|
|
1247
|
+
Authorization: "Bearer invalid-jwt-token",
|
|
1248
|
+
},
|
|
1249
|
+
},
|
|
1250
|
+
},
|
|
1251
|
+
);
|
|
1252
|
+
|
|
1253
|
+
const streamClient = new Client(
|
|
1254
|
+
{
|
|
1255
|
+
name: "stream-client-auth-false",
|
|
1256
|
+
version: "1.0.0",
|
|
1257
|
+
},
|
|
1258
|
+
{
|
|
1259
|
+
capabilities: {},
|
|
1260
|
+
},
|
|
1261
|
+
);
|
|
1262
|
+
|
|
1263
|
+
// Connection should fail due to authentication returning false
|
|
1264
|
+
await expect(streamClient.connect(streamTransport)).rejects.toThrow();
|
|
1265
|
+
|
|
1266
|
+
// Verify authenticate callback was called
|
|
1267
|
+
expect(authenticate).toHaveBeenCalled();
|
|
1268
|
+
|
|
1269
|
+
await httpServer.close();
|
|
1270
|
+
await stdioClient.close();
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
it("returns 401 with custom error message when { authenticated: false, error: '...' }", async () => {
|
|
1274
|
+
const stdioTransport = new StdioClientTransport({
|
|
1275
|
+
args: ["src/fixtures/simple-stdio-server.ts"],
|
|
1276
|
+
command: "tsx",
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
const stdioClient = new Client(
|
|
1280
|
+
{
|
|
1281
|
+
name: "mcp-proxy",
|
|
1282
|
+
version: "1.0.0",
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
capabilities: {},
|
|
1286
|
+
},
|
|
1287
|
+
);
|
|
1288
|
+
|
|
1289
|
+
await stdioClient.connect(stdioTransport);
|
|
1290
|
+
|
|
1291
|
+
const serverVersion = stdioClient.getServerVersion() as {
|
|
1292
|
+
name: string;
|
|
1293
|
+
version: string;
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
const serverCapabilities = stdioClient.getServerCapabilities() as {
|
|
1297
|
+
capabilities: Record<string, unknown>;
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
const port = await getRandomPort();
|
|
1301
|
+
|
|
1302
|
+
const customErrorMessage = "Token expired at 2025-10-06T12:00:00Z";
|
|
1303
|
+
|
|
1304
|
+
// Mock authenticate callback with custom error message
|
|
1305
|
+
const authenticate = vi.fn().mockResolvedValue({
|
|
1306
|
+
authenticated: false,
|
|
1307
|
+
error: customErrorMessage,
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
const httpServer = await startHTTPServer({
|
|
1311
|
+
authenticate,
|
|
1312
|
+
createServer: async () => {
|
|
1313
|
+
const mcpServer = new Server(serverVersion, {
|
|
1314
|
+
capabilities: serverCapabilities,
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
await proxyServer({
|
|
1318
|
+
client: stdioClient,
|
|
1319
|
+
server: mcpServer,
|
|
1320
|
+
serverCapabilities,
|
|
1321
|
+
});
|
|
1322
|
+
|
|
1323
|
+
return mcpServer;
|
|
1324
|
+
},
|
|
1325
|
+
port,
|
|
1326
|
+
stateless: true,
|
|
1327
|
+
});
|
|
1328
|
+
|
|
1329
|
+
// Make request directly with fetch to check error message
|
|
1330
|
+
const response = await fetch(`http://localhost:${port}/mcp`, {
|
|
1331
|
+
body: JSON.stringify({
|
|
1332
|
+
id: 1,
|
|
1333
|
+
jsonrpc: "2.0",
|
|
1334
|
+
method: "initialize",
|
|
1335
|
+
params: {
|
|
1336
|
+
capabilities: {},
|
|
1337
|
+
clientInfo: { name: "test", version: "1.0.0" },
|
|
1338
|
+
protocolVersion: "2024-11-05",
|
|
1339
|
+
},
|
|
1340
|
+
}),
|
|
1341
|
+
headers: {
|
|
1342
|
+
"Accept": "application/json, text/event-stream",
|
|
1343
|
+
"Authorization": "Bearer expired-token",
|
|
1344
|
+
"Content-Type": "application/json",
|
|
1345
|
+
},
|
|
1346
|
+
method: "POST",
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
expect(response.status).toBe(401);
|
|
1350
|
+
|
|
1351
|
+
const errorResponse = (await response.json()) as {
|
|
1352
|
+
error: { code: number; message: string };
|
|
1353
|
+
id: null | number;
|
|
1354
|
+
jsonrpc: string;
|
|
1355
|
+
};
|
|
1356
|
+
expect(errorResponse.error.message).toBe(customErrorMessage);
|
|
1357
|
+
|
|
1358
|
+
await httpServer.close();
|
|
1359
|
+
await stdioClient.close();
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
it("returns 401 when createServer throws authentication error", async () => {
|
|
1363
|
+
const stdioTransport = new StdioClientTransport({
|
|
1364
|
+
args: ["src/fixtures/simple-stdio-server.ts"],
|
|
1365
|
+
command: "tsx",
|
|
1366
|
+
});
|
|
1367
|
+
|
|
1368
|
+
const stdioClient = new Client(
|
|
1369
|
+
{
|
|
1370
|
+
name: "mcp-proxy",
|
|
1371
|
+
version: "1.0.0",
|
|
1372
|
+
},
|
|
1373
|
+
{
|
|
1374
|
+
capabilities: {},
|
|
1375
|
+
},
|
|
1376
|
+
);
|
|
1377
|
+
|
|
1378
|
+
await stdioClient.connect(stdioTransport);
|
|
1379
|
+
|
|
1380
|
+
const port = await getRandomPort();
|
|
1381
|
+
|
|
1382
|
+
// Mock authenticate that passes, but createServer throws auth error
|
|
1383
|
+
const authenticate = vi.fn().mockResolvedValue({
|
|
1384
|
+
authenticated: true,
|
|
1385
|
+
session: { userId: "test" },
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
const httpServer = await startHTTPServer({
|
|
1389
|
+
authenticate,
|
|
1390
|
+
createServer: async () => {
|
|
1391
|
+
// Simulate FastMCP throwing error for authenticated: false
|
|
1392
|
+
throw new Error("Authentication failed: Invalid JWT payload");
|
|
1393
|
+
},
|
|
1394
|
+
port,
|
|
1395
|
+
stateless: true,
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
// Make request
|
|
1399
|
+
const response = await fetch(`http://localhost:${port}/mcp`, {
|
|
1400
|
+
body: JSON.stringify({
|
|
1401
|
+
id: 1,
|
|
1402
|
+
jsonrpc: "2.0",
|
|
1403
|
+
method: "initialize",
|
|
1404
|
+
params: {
|
|
1405
|
+
capabilities: {},
|
|
1406
|
+
clientInfo: { name: "test", version: "1.0.0" },
|
|
1407
|
+
protocolVersion: "2024-11-05",
|
|
1408
|
+
},
|
|
1409
|
+
}),
|
|
1410
|
+
headers: {
|
|
1411
|
+
"Accept": "application/json, text/event-stream",
|
|
1412
|
+
"Authorization": "Bearer test-token",
|
|
1413
|
+
"Content-Type": "application/json",
|
|
1414
|
+
},
|
|
1415
|
+
method: "POST",
|
|
1416
|
+
});
|
|
1417
|
+
|
|
1418
|
+
expect(response.status).toBe(401);
|
|
1419
|
+
|
|
1420
|
+
const errorResponse = (await response.json()) as {
|
|
1421
|
+
error: { code: number; message: string };
|
|
1422
|
+
id: null | number;
|
|
1423
|
+
jsonrpc: string;
|
|
1424
|
+
};
|
|
1425
|
+
expect(errorResponse.error.message).toContain("Authentication failed");
|
|
1426
|
+
|
|
1427
|
+
await httpServer.close();
|
|
1428
|
+
await stdioClient.close();
|
|
1429
|
+
});
|
|
1430
|
+
|
|
1431
|
+
it("returns 401 when createServer throws JWT-related error", async () => {
|
|
1432
|
+
const port = await getRandomPort();
|
|
1433
|
+
|
|
1434
|
+
const httpServer = await startHTTPServer({
|
|
1435
|
+
createServer: async () => {
|
|
1436
|
+
throw new Error("Invalid JWT signature");
|
|
1437
|
+
},
|
|
1438
|
+
port,
|
|
1439
|
+
stateless: true,
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
const response = await fetch(`http://localhost:${port}/mcp`, {
|
|
1443
|
+
body: JSON.stringify({
|
|
1444
|
+
id: 1,
|
|
1445
|
+
jsonrpc: "2.0",
|
|
1446
|
+
method: "initialize",
|
|
1447
|
+
params: {
|
|
1448
|
+
capabilities: {},
|
|
1449
|
+
clientInfo: { name: "test", version: "1.0.0" },
|
|
1450
|
+
protocolVersion: "2024-11-05",
|
|
1451
|
+
},
|
|
1452
|
+
}),
|
|
1453
|
+
headers: {
|
|
1454
|
+
"Accept": "application/json, text/event-stream",
|
|
1455
|
+
"Content-Type": "application/json",
|
|
1456
|
+
},
|
|
1457
|
+
method: "POST",
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
expect(response.status).toBe(401);
|
|
1461
|
+
|
|
1462
|
+
const errorResponse = (await response.json()) as {
|
|
1463
|
+
error: { code: number; message: string };
|
|
1464
|
+
id: null | number;
|
|
1465
|
+
jsonrpc: string;
|
|
1466
|
+
};
|
|
1467
|
+
expect(errorResponse.error.message).toContain("Invalid JWT");
|
|
1468
|
+
|
|
1469
|
+
await httpServer.close();
|
|
1470
|
+
});
|
|
1471
|
+
|
|
1472
|
+
it("returns 401 when createServer throws Token-related error", async () => {
|
|
1473
|
+
const port = await getRandomPort();
|
|
1474
|
+
|
|
1475
|
+
const httpServer = await startHTTPServer({
|
|
1476
|
+
createServer: async () => {
|
|
1477
|
+
throw new Error("Token has been revoked");
|
|
1478
|
+
},
|
|
1479
|
+
port,
|
|
1480
|
+
stateless: true,
|
|
1481
|
+
});
|
|
1482
|
+
|
|
1483
|
+
const response = await fetch(`http://localhost:${port}/mcp`, {
|
|
1484
|
+
body: JSON.stringify({
|
|
1485
|
+
id: 1,
|
|
1486
|
+
jsonrpc: "2.0",
|
|
1487
|
+
method: "initialize",
|
|
1488
|
+
params: {
|
|
1489
|
+
capabilities: {},
|
|
1490
|
+
clientInfo: { name: "test", version: "1.0.0" },
|
|
1491
|
+
protocolVersion: "2024-11-05",
|
|
1492
|
+
},
|
|
1493
|
+
}),
|
|
1494
|
+
headers: {
|
|
1495
|
+
"Accept": "application/json, text/event-stream",
|
|
1496
|
+
"Content-Type": "application/json",
|
|
1497
|
+
},
|
|
1498
|
+
method: "POST",
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
expect(response.status).toBe(401);
|
|
1502
|
+
|
|
1503
|
+
const errorResponse = (await response.json()) as {
|
|
1504
|
+
error: { code: number; message: string };
|
|
1505
|
+
id: null | number;
|
|
1506
|
+
jsonrpc: string;
|
|
1507
|
+
};
|
|
1508
|
+
expect(errorResponse.error.message).toContain("Token");
|
|
1509
|
+
|
|
1510
|
+
await httpServer.close();
|
|
1511
|
+
});
|
|
1512
|
+
|
|
1513
|
+
it("returns 401 when createServer throws Unauthorized error", async () => {
|
|
1514
|
+
const port = await getRandomPort();
|
|
1515
|
+
|
|
1516
|
+
const httpServer = await startHTTPServer({
|
|
1517
|
+
createServer: async () => {
|
|
1518
|
+
throw new Error("Unauthorized access");
|
|
1519
|
+
},
|
|
1520
|
+
port,
|
|
1521
|
+
stateless: true,
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
const response = await fetch(`http://localhost:${port}/mcp`, {
|
|
1525
|
+
body: JSON.stringify({
|
|
1526
|
+
id: 1,
|
|
1527
|
+
jsonrpc: "2.0",
|
|
1528
|
+
method: "initialize",
|
|
1529
|
+
params: {
|
|
1530
|
+
capabilities: {},
|
|
1531
|
+
clientInfo: { name: "test", version: "1.0.0" },
|
|
1532
|
+
protocolVersion: "2024-11-05",
|
|
1533
|
+
},
|
|
1534
|
+
}),
|
|
1535
|
+
headers: {
|
|
1536
|
+
"Accept": "application/json, text/event-stream",
|
|
1537
|
+
"Content-Type": "application/json",
|
|
1538
|
+
},
|
|
1539
|
+
method: "POST",
|
|
1540
|
+
});
|
|
1541
|
+
|
|
1542
|
+
expect(response.status).toBe(401);
|
|
1543
|
+
|
|
1544
|
+
const errorResponse = (await response.json()) as {
|
|
1545
|
+
error: { code: number; message: string };
|
|
1546
|
+
id: null | number;
|
|
1547
|
+
jsonrpc: string;
|
|
1548
|
+
};
|
|
1549
|
+
expect(errorResponse.error.message).toContain("Unauthorized");
|
|
1550
|
+
|
|
1551
|
+
await httpServer.close();
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
it("returns 500 when createServer throws non-auth error", async () => {
|
|
1555
|
+
const port = await getRandomPort();
|
|
1556
|
+
|
|
1557
|
+
const httpServer = await startHTTPServer({
|
|
1558
|
+
createServer: async () => {
|
|
1559
|
+
throw new Error("Database connection failed");
|
|
1560
|
+
},
|
|
1561
|
+
port,
|
|
1562
|
+
stateless: true,
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
const response = await fetch(`http://localhost:${port}/mcp`, {
|
|
1566
|
+
body: JSON.stringify({
|
|
1567
|
+
id: 1,
|
|
1568
|
+
jsonrpc: "2.0",
|
|
1569
|
+
method: "initialize",
|
|
1570
|
+
params: {
|
|
1571
|
+
capabilities: {},
|
|
1572
|
+
clientInfo: { name: "test", version: "1.0.0" },
|
|
1573
|
+
protocolVersion: "2024-11-05",
|
|
1574
|
+
},
|
|
1575
|
+
}),
|
|
1576
|
+
headers: {
|
|
1577
|
+
"Accept": "application/json, text/event-stream",
|
|
1578
|
+
"Content-Type": "application/json",
|
|
1579
|
+
},
|
|
1580
|
+
method: "POST",
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
expect(response.status).toBe(500);
|
|
1584
|
+
|
|
1585
|
+
await httpServer.close();
|
|
1586
|
+
});
|
|
1587
|
+
|
|
1588
|
+
it("succeeds when authenticate returns { authenticated: true } in stateless mode", async () => {
|
|
1589
|
+
const stdioTransport = new StdioClientTransport({
|
|
1590
|
+
args: ["src/fixtures/simple-stdio-server.ts"],
|
|
1591
|
+
command: "tsx",
|
|
1592
|
+
});
|
|
1593
|
+
|
|
1594
|
+
const stdioClient = new Client(
|
|
1595
|
+
{
|
|
1596
|
+
name: "mcp-proxy",
|
|
1597
|
+
version: "1.0.0",
|
|
1598
|
+
},
|
|
1599
|
+
{
|
|
1600
|
+
capabilities: {},
|
|
1601
|
+
},
|
|
1602
|
+
);
|
|
1603
|
+
|
|
1604
|
+
await stdioClient.connect(stdioTransport);
|
|
1605
|
+
|
|
1606
|
+
const serverVersion = stdioClient.getServerVersion() as {
|
|
1607
|
+
name: string;
|
|
1608
|
+
version: string;
|
|
1609
|
+
};
|
|
1610
|
+
|
|
1611
|
+
const serverCapabilities = stdioClient.getServerCapabilities() as {
|
|
1612
|
+
capabilities: Record<string, unknown>;
|
|
1613
|
+
};
|
|
1614
|
+
|
|
1615
|
+
const port = await getRandomPort();
|
|
1616
|
+
|
|
1617
|
+
// Mock authenticate callback that returns { authenticated: true }
|
|
1618
|
+
const authenticate = vi.fn().mockResolvedValue({
|
|
1619
|
+
authenticated: true,
|
|
1620
|
+
session: { email: "test@example.com", userId: "user123" },
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1623
|
+
const httpServer = await startHTTPServer({
|
|
1624
|
+
authenticate,
|
|
1625
|
+
createServer: async () => {
|
|
1626
|
+
const mcpServer = new Server(serverVersion, {
|
|
1627
|
+
capabilities: serverCapabilities,
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
await proxyServer({
|
|
1631
|
+
client: stdioClient,
|
|
1632
|
+
server: mcpServer,
|
|
1633
|
+
serverCapabilities,
|
|
1634
|
+
});
|
|
1635
|
+
|
|
1636
|
+
return mcpServer;
|
|
1637
|
+
},
|
|
1638
|
+
port,
|
|
1639
|
+
stateless: true,
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
// Create client with valid Bearer token
|
|
1643
|
+
const streamTransport = new StreamableHTTPClientTransport(
|
|
1644
|
+
new URL(`http://localhost:${port}/mcp`),
|
|
1645
|
+
{
|
|
1646
|
+
requestInit: {
|
|
1647
|
+
headers: {
|
|
1648
|
+
Authorization: "Bearer valid-jwt-token",
|
|
1649
|
+
},
|
|
1650
|
+
},
|
|
1651
|
+
},
|
|
1652
|
+
);
|
|
1653
|
+
|
|
1654
|
+
const streamClient = new Client(
|
|
1655
|
+
{
|
|
1656
|
+
name: "stream-client-auth-true",
|
|
1657
|
+
version: "1.0.0",
|
|
1658
|
+
},
|
|
1659
|
+
{
|
|
1660
|
+
capabilities: {},
|
|
1661
|
+
},
|
|
1662
|
+
);
|
|
1663
|
+
|
|
1664
|
+
// Should connect successfully
|
|
1665
|
+
await streamClient.connect(streamTransport);
|
|
1666
|
+
|
|
1667
|
+
// Should be able to make requests
|
|
1668
|
+
const result = await streamClient.listResources();
|
|
1669
|
+
expect(result.resources).toBeDefined();
|
|
1670
|
+
|
|
1671
|
+
// Verify authenticate callback was called
|
|
1672
|
+
expect(authenticate).toHaveBeenCalled();
|
|
1673
|
+
|
|
1674
|
+
await streamClient.close();
|
|
1675
|
+
await httpServer.close();
|
|
1676
|
+
await stdioClient.close();
|
|
1677
|
+
});
|
package/src/startHTTPServer.ts
CHANGED
|
@@ -138,13 +138,21 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
138
138
|
if (stateless && authenticate) {
|
|
139
139
|
try {
|
|
140
140
|
const authResult = await authenticate(req);
|
|
141
|
-
|
|
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
|
+
|
|
142
150
|
res.setHeader("Content-Type", "application/json");
|
|
143
151
|
res.writeHead(401).end(
|
|
144
152
|
JSON.stringify({
|
|
145
153
|
error: {
|
|
146
154
|
code: -32000,
|
|
147
|
-
message:
|
|
155
|
+
message: errorMessage
|
|
148
156
|
},
|
|
149
157
|
id: (body as { id?: unknown })?.id ?? null,
|
|
150
158
|
jsonrpc: "2.0"
|
|
@@ -153,13 +161,15 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
153
161
|
return true;
|
|
154
162
|
}
|
|
155
163
|
} catch (error) {
|
|
164
|
+
// Extract error details from thrown errors
|
|
165
|
+
const errorMessage = error instanceof Error ? error.message : "Unauthorized: Authentication error";
|
|
156
166
|
console.error("Authentication error:", error);
|
|
157
167
|
res.setHeader("Content-Type", "application/json");
|
|
158
168
|
res.writeHead(401).end(
|
|
159
169
|
JSON.stringify({
|
|
160
170
|
error: {
|
|
161
171
|
code: -32000,
|
|
162
|
-
message:
|
|
172
|
+
message: errorMessage
|
|
163
173
|
},
|
|
164
174
|
id: (body as { id?: unknown })?.id ?? null,
|
|
165
175
|
jsonrpc: "2.0"
|
|
@@ -223,6 +233,26 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
223
233
|
try {
|
|
224
234
|
server = await createServer(req);
|
|
225
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
|
+
|
|
226
256
|
if (handleResponseError(error, res)) {
|
|
227
257
|
return true;
|
|
228
258
|
}
|
|
@@ -255,6 +285,26 @@ const handleStreamRequest = async <T extends ServerLike>({
|
|
|
255
285
|
try {
|
|
256
286
|
server = await createServer(req);
|
|
257
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
|
+
|
|
258
308
|
if (handleResponseError(error, res)) {
|
|
259
309
|
return true;
|
|
260
310
|
}
|