mcp-proxy 5.8.0 → 5.9.0
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 +23 -3
- package/dist/index.js +2 -2
- package/dist/{stdio-so1-I7Pn.js → stdio-CsjPjeWC.js} +82 -35
- package/dist/stdio-CsjPjeWC.js.map +1 -0
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/authentication.test.ts +77 -2
- package/src/authentication.ts +16 -4
- package/src/index.ts +2 -0
- package/src/startHTTPServer.test.ts +494 -0
- package/src/startHTTPServer.ts +99 -5
- package/dist/stdio-so1-I7Pn.js.map +0 -1
package/dist/bin/mcp-proxy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Client, InMemoryEventStore, ReadBuffer, Server, __commonJS, __toESM, proxyServer, serializeMessage, startHTTPServer } from "../stdio-
|
|
2
|
+
import { Client, InMemoryEventStore, ReadBuffer, Server, __commonJS, __toESM, proxyServer, serializeMessage, startHTTPServer } from "../stdio-CsjPjeWC.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { basename, dirname, extname, join, normalize, relative, resolve } from "path";
|
|
5
5
|
import { format, inspect } from "util";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import http from "http";
|
|
1
|
+
import http, { IncomingMessage } from "http";
|
|
2
2
|
import { EventStore } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
3
|
import { JSONRPCMessage, ServerCapabilities } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -7,8 +7,26 @@ import { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.
|
|
|
7
7
|
import { StreamableHTTPClientTransportOptions } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
8
8
|
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
9
9
|
|
|
10
|
+
//#region src/authentication.d.ts
|
|
11
|
+
interface AuthConfig {
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
oauth?: {
|
|
14
|
+
protectedResource?: {
|
|
15
|
+
resource?: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
declare class AuthenticationMiddleware {
|
|
20
|
+
private config;
|
|
21
|
+
constructor(config?: AuthConfig);
|
|
22
|
+
getUnauthorizedResponse(): {
|
|
23
|
+
body: string;
|
|
24
|
+
headers: Record<string, string>;
|
|
25
|
+
};
|
|
26
|
+
validateRequest(req: IncomingMessage): boolean;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
10
29
|
//#region src/InMemoryEventStore.d.ts
|
|
11
|
-
|
|
12
30
|
/**
|
|
13
31
|
* Simple in-memory implementation of the EventStore interface for resumability
|
|
14
32
|
* This is primarily intended for examples and testing, not for production use
|
|
@@ -68,6 +86,7 @@ declare const startHTTPServer: <T extends ServerLike>({
|
|
|
68
86
|
enableJsonResponse,
|
|
69
87
|
eventStore,
|
|
70
88
|
host,
|
|
89
|
+
oauth,
|
|
71
90
|
onClose,
|
|
72
91
|
onConnect,
|
|
73
92
|
onUnhandledRequest,
|
|
@@ -82,6 +101,7 @@ declare const startHTTPServer: <T extends ServerLike>({
|
|
|
82
101
|
enableJsonResponse?: boolean;
|
|
83
102
|
eventStore?: EventStore;
|
|
84
103
|
host?: string;
|
|
104
|
+
oauth?: AuthConfig["oauth"];
|
|
85
105
|
onClose?: (server: T) => Promise<void>;
|
|
86
106
|
onConnect?: (server: T) => Promise<void>;
|
|
87
107
|
onUnhandledRequest?: (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>;
|
|
@@ -129,5 +149,5 @@ type TransportEvent = {
|
|
|
129
149
|
};
|
|
130
150
|
declare const tapTransport: (transport: Transport, eventHandler: (event: TransportEvent) => void) => Transport;
|
|
131
151
|
//#endregion
|
|
132
|
-
export { InMemoryEventStore, ServerType, proxyServer, startHTTPServer, startStdioServer, tapTransport };
|
|
152
|
+
export { type AuthConfig, AuthenticationMiddleware, InMemoryEventStore, ServerType, proxyServer, startHTTPServer, startStdioServer, tapTransport };
|
|
133
153
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Client, InMemoryEventStore, JSONRPCMessageSchema, LATEST_PROTOCOL_VERSION, NEVER, ReadBuffer, Server, ZodIssueCode, anyType, arrayType, booleanType, isInitializedNotification, isJSONRPCRequest, isJSONRPCResponse, numberType, objectType, proxyServer, serializeMessage, startHTTPServer, stringType } from "./stdio-
|
|
1
|
+
import { AuthenticationMiddleware, Client, InMemoryEventStore, JSONRPCMessageSchema, LATEST_PROTOCOL_VERSION, NEVER, ReadBuffer, Server, ZodIssueCode, anyType, arrayType, booleanType, isInitializedNotification, isJSONRPCRequest, isJSONRPCResponse, numberType, objectType, proxyServer, serializeMessage, startHTTPServer, stringType } from "./stdio-CsjPjeWC.js";
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
|
|
4
4
|
//#region node_modules/.pnpm/eventsource-parser@3.0.6/node_modules/eventsource-parser/dist/index.js
|
|
@@ -1850,5 +1850,5 @@ const tapTransport = (transport, eventHandler) => {
|
|
|
1850
1850
|
};
|
|
1851
1851
|
|
|
1852
1852
|
//#endregion
|
|
1853
|
-
export { InMemoryEventStore, ServerType, proxyServer, startHTTPServer, startStdioServer, tapTransport };
|
|
1853
|
+
export { AuthenticationMiddleware, InMemoryEventStore, ServerType, proxyServer, startHTTPServer, startStdioServer, tapTransport };
|
|
1854
1854
|
//# sourceMappingURL=index.js.map
|
|
@@ -29,6 +29,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
}) : target, mod));
|
|
30
30
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
31
31
|
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/authentication.ts
|
|
34
|
+
var AuthenticationMiddleware = class {
|
|
35
|
+
constructor(config = {}) {
|
|
36
|
+
this.config = config;
|
|
37
|
+
}
|
|
38
|
+
getUnauthorizedResponse() {
|
|
39
|
+
const headers = { "Content-Type": "application/json" };
|
|
40
|
+
if (this.config.oauth?.protectedResource?.resource) headers["WWW-Authenticate"] = `Bearer resource_metadata="${this.config.oauth.protectedResource.resource}/.well-known/oauth-protected-resource"`;
|
|
41
|
+
return {
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
error: {
|
|
44
|
+
code: 401,
|
|
45
|
+
message: "Unauthorized: Invalid or missing API key"
|
|
46
|
+
},
|
|
47
|
+
id: null,
|
|
48
|
+
jsonrpc: "2.0"
|
|
49
|
+
}),
|
|
50
|
+
headers
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
validateRequest(req) {
|
|
54
|
+
if (!this.config.apiKey) return true;
|
|
55
|
+
const apiKey = req.headers["x-api-key"];
|
|
56
|
+
if (!apiKey || typeof apiKey !== "string") return false;
|
|
57
|
+
return apiKey === this.config.apiKey;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
32
61
|
//#endregion
|
|
33
62
|
//#region src/InMemoryEventStore.ts
|
|
34
63
|
/**
|
|
@@ -14968,33 +14997,6 @@ var StreamableHTTPServerTransport = class {
|
|
|
14968
14997
|
}
|
|
14969
14998
|
};
|
|
14970
14999
|
|
|
14971
|
-
//#endregion
|
|
14972
|
-
//#region src/authentication.ts
|
|
14973
|
-
var AuthenticationMiddleware = class {
|
|
14974
|
-
constructor(config = {}) {
|
|
14975
|
-
this.config = config;
|
|
14976
|
-
}
|
|
14977
|
-
getUnauthorizedResponse() {
|
|
14978
|
-
return {
|
|
14979
|
-
body: JSON.stringify({
|
|
14980
|
-
error: {
|
|
14981
|
-
code: 401,
|
|
14982
|
-
message: "Unauthorized: Invalid or missing API key"
|
|
14983
|
-
},
|
|
14984
|
-
id: null,
|
|
14985
|
-
jsonrpc: "2.0"
|
|
14986
|
-
}),
|
|
14987
|
-
headers: { "Content-Type": "application/json" }
|
|
14988
|
-
};
|
|
14989
|
-
}
|
|
14990
|
-
validateRequest(req) {
|
|
14991
|
-
if (!this.config.apiKey) return true;
|
|
14992
|
-
const apiKey = req.headers["x-api-key"];
|
|
14993
|
-
if (!apiKey || typeof apiKey !== "string") return false;
|
|
14994
|
-
return apiKey === this.config.apiKey;
|
|
14995
|
-
}
|
|
14996
|
-
};
|
|
14997
|
-
|
|
14998
15000
|
//#endregion
|
|
14999
15001
|
//#region src/startHTTPServer.ts
|
|
15000
15002
|
const getBody = (request) => {
|
|
@@ -15024,6 +15026,10 @@ const createJsonRpcErrorResponse = (code, message) => {
|
|
|
15024
15026
|
jsonrpc: "2.0"
|
|
15025
15027
|
});
|
|
15026
15028
|
};
|
|
15029
|
+
const getWWWAuthenticateHeader = (oauth) => {
|
|
15030
|
+
if (!oauth?.protectedResource?.resource) return;
|
|
15031
|
+
return `Bearer resource_metadata="${oauth.protectedResource.resource}/.well-known/oauth-protected-resource"`;
|
|
15032
|
+
};
|
|
15027
15033
|
const handleResponseError = (error, res) => {
|
|
15028
15034
|
if (error instanceof Response) {
|
|
15029
15035
|
const fixedHeaders = {};
|
|
@@ -15045,7 +15051,7 @@ const cleanupServer = async (server, onClose) => {
|
|
|
15045
15051
|
console.error("[mcp-proxy] error closing server", error);
|
|
15046
15052
|
}
|
|
15047
15053
|
};
|
|
15048
|
-
const handleStreamRequest = async ({ activeTransports, authenticate, createServer, enableJsonResponse, endpoint, eventStore, onClose, onConnect, req, res, stateless }) => {
|
|
15054
|
+
const handleStreamRequest = async ({ activeTransports, authenticate, createServer, enableJsonResponse, endpoint, eventStore, oauth, onClose, onConnect, req, res, stateless }) => {
|
|
15049
15055
|
if (req.method === "POST" && new URL(req.url, "http://localhost").pathname === endpoint) {
|
|
15050
15056
|
try {
|
|
15051
15057
|
const sessionId = Array.isArray(req.headers["mcp-session-id"]) ? req.headers["mcp-session-id"][0] : req.headers["mcp-session-id"];
|
|
@@ -15053,12 +15059,16 @@ const handleStreamRequest = async ({ activeTransports, authenticate, createServe
|
|
|
15053
15059
|
let server;
|
|
15054
15060
|
const body = await getBody(req);
|
|
15055
15061
|
if (stateless && authenticate) try {
|
|
15056
|
-
|
|
15062
|
+
const authResult = await authenticate(req);
|
|
15063
|
+
if (!authResult || typeof authResult === "object" && "authenticated" in authResult && !authResult.authenticated) {
|
|
15064
|
+
const errorMessage = authResult && typeof authResult === "object" && "error" in authResult && typeof authResult.error === "string" ? authResult.error : "Unauthorized: Authentication failed";
|
|
15057
15065
|
res.setHeader("Content-Type", "application/json");
|
|
15066
|
+
const wwwAuthHeader = getWWWAuthenticateHeader(oauth);
|
|
15067
|
+
if (wwwAuthHeader) res.setHeader("WWW-Authenticate", wwwAuthHeader);
|
|
15058
15068
|
res.writeHead(401).end(JSON.stringify({
|
|
15059
15069
|
error: {
|
|
15060
15070
|
code: -32e3,
|
|
15061
|
-
message:
|
|
15071
|
+
message: errorMessage
|
|
15062
15072
|
},
|
|
15063
15073
|
id: body?.id ?? null,
|
|
15064
15074
|
jsonrpc: "2.0"
|
|
@@ -15066,12 +15076,15 @@ const handleStreamRequest = async ({ activeTransports, authenticate, createServe
|
|
|
15066
15076
|
return true;
|
|
15067
15077
|
}
|
|
15068
15078
|
} catch (error) {
|
|
15079
|
+
const errorMessage = error instanceof Error ? error.message : "Unauthorized: Authentication error";
|
|
15069
15080
|
console.error("Authentication error:", error);
|
|
15070
15081
|
res.setHeader("Content-Type", "application/json");
|
|
15082
|
+
const wwwAuthHeader = getWWWAuthenticateHeader(oauth);
|
|
15083
|
+
if (wwwAuthHeader) res.setHeader("WWW-Authenticate", wwwAuthHeader);
|
|
15071
15084
|
res.writeHead(401).end(JSON.stringify({
|
|
15072
15085
|
error: {
|
|
15073
15086
|
code: -32e3,
|
|
15074
|
-
message:
|
|
15087
|
+
message: errorMessage
|
|
15075
15088
|
},
|
|
15076
15089
|
id: body?.id ?? null,
|
|
15077
15090
|
jsonrpc: "2.0"
|
|
@@ -15112,6 +15125,21 @@ const handleStreamRequest = async ({ activeTransports, authenticate, createServe
|
|
|
15112
15125
|
try {
|
|
15113
15126
|
server = await createServer(req);
|
|
15114
15127
|
} catch (error) {
|
|
15128
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
15129
|
+
if (errorMessage.includes("Authentication") || errorMessage.includes("Invalid JWT") || errorMessage.includes("Token") || errorMessage.includes("Unauthorized")) {
|
|
15130
|
+
res.setHeader("Content-Type", "application/json");
|
|
15131
|
+
const wwwAuthHeader = getWWWAuthenticateHeader(oauth);
|
|
15132
|
+
if (wwwAuthHeader) res.setHeader("WWW-Authenticate", wwwAuthHeader);
|
|
15133
|
+
res.writeHead(401).end(JSON.stringify({
|
|
15134
|
+
error: {
|
|
15135
|
+
code: -32e3,
|
|
15136
|
+
message: errorMessage
|
|
15137
|
+
},
|
|
15138
|
+
id: body?.id ?? null,
|
|
15139
|
+
jsonrpc: "2.0"
|
|
15140
|
+
}));
|
|
15141
|
+
return true;
|
|
15142
|
+
}
|
|
15115
15143
|
if (handleResponseError(error, res)) return true;
|
|
15116
15144
|
res.writeHead(500).end("Error creating server");
|
|
15117
15145
|
return true;
|
|
@@ -15130,6 +15158,21 @@ const handleStreamRequest = async ({ activeTransports, authenticate, createServe
|
|
|
15130
15158
|
try {
|
|
15131
15159
|
server = await createServer(req);
|
|
15132
15160
|
} catch (error) {
|
|
15161
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
15162
|
+
if (errorMessage.includes("Authentication") || errorMessage.includes("Invalid JWT") || errorMessage.includes("Token") || errorMessage.includes("Unauthorized")) {
|
|
15163
|
+
res.setHeader("Content-Type", "application/json");
|
|
15164
|
+
const wwwAuthHeader = getWWWAuthenticateHeader(oauth);
|
|
15165
|
+
if (wwwAuthHeader) res.setHeader("WWW-Authenticate", wwwAuthHeader);
|
|
15166
|
+
res.writeHead(401).end(JSON.stringify({
|
|
15167
|
+
error: {
|
|
15168
|
+
code: -32e3,
|
|
15169
|
+
message: errorMessage
|
|
15170
|
+
},
|
|
15171
|
+
id: body?.id ?? null,
|
|
15172
|
+
jsonrpc: "2.0"
|
|
15173
|
+
}));
|
|
15174
|
+
return true;
|
|
15175
|
+
}
|
|
15133
15176
|
if (handleResponseError(error, res)) return true;
|
|
15134
15177
|
res.writeHead(500).end("Error creating server");
|
|
15135
15178
|
return true;
|
|
@@ -15246,10 +15289,13 @@ const handleSSERequest = async ({ activeTransports, createServer, endpoint, onCl
|
|
|
15246
15289
|
}
|
|
15247
15290
|
return false;
|
|
15248
15291
|
};
|
|
15249
|
-
const startHTTPServer = async ({ apiKey, authenticate, createServer, enableJsonResponse, eventStore, host = "::", onClose, onConnect, onUnhandledRequest, port, sseEndpoint = "/sse", stateless, streamEndpoint = "/mcp" }) => {
|
|
15292
|
+
const startHTTPServer = async ({ apiKey, authenticate, createServer, enableJsonResponse, eventStore, host = "::", oauth, onClose, onConnect, onUnhandledRequest, port, sseEndpoint = "/sse", stateless, streamEndpoint = "/mcp" }) => {
|
|
15250
15293
|
const activeSSETransports = {};
|
|
15251
15294
|
const activeStreamTransports = {};
|
|
15252
|
-
const authMiddleware = new AuthenticationMiddleware({
|
|
15295
|
+
const authMiddleware = new AuthenticationMiddleware({
|
|
15296
|
+
apiKey,
|
|
15297
|
+
oauth
|
|
15298
|
+
});
|
|
15253
15299
|
/**
|
|
15254
15300
|
* @author https://dev.classmethod.jp/articles/mcp-sse/
|
|
15255
15301
|
*/
|
|
@@ -15295,6 +15341,7 @@ const startHTTPServer = async ({ apiKey, authenticate, createServer, enableJsonR
|
|
|
15295
15341
|
enableJsonResponse,
|
|
15296
15342
|
endpoint: streamEndpoint,
|
|
15297
15343
|
eventStore,
|
|
15344
|
+
oauth,
|
|
15298
15345
|
onClose,
|
|
15299
15346
|
onConnect,
|
|
15300
15347
|
req,
|
|
@@ -21509,5 +21556,5 @@ function serializeMessage(message) {
|
|
|
21509
21556
|
}
|
|
21510
21557
|
|
|
21511
21558
|
//#endregion
|
|
21512
|
-
export { Client, InMemoryEventStore, JSONRPCMessageSchema, LATEST_PROTOCOL_VERSION, NEVER, ReadBuffer, Server, ZodIssueCode, __commonJS, __toESM, anyType, arrayType, booleanType, isInitializedNotification, isJSONRPCRequest, isJSONRPCResponse, numberType, objectType, proxyServer, serializeMessage, startHTTPServer, stringType };
|
|
21513
|
-
//# sourceMappingURL=stdio-
|
|
21559
|
+
export { AuthenticationMiddleware, Client, InMemoryEventStore, JSONRPCMessageSchema, LATEST_PROTOCOL_VERSION, NEVER, ReadBuffer, Server, ZodIssueCode, __commonJS, __toESM, anyType, arrayType, booleanType, isInitializedNotification, isJSONRPCRequest, isJSONRPCResponse, numberType, objectType, proxyServer, serializeMessage, startHTTPServer, stringType };
|
|
21560
|
+
//# sourceMappingURL=stdio-CsjPjeWC.js.map
|