mcp-proxy 5.11.2 → 5.12.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/README.md CHANGED
@@ -56,7 +56,7 @@ npx mcp-proxy --port 8080 -- my-command -v
56
56
 
57
57
  ### Stateless Mode
58
58
 
59
- By default, MCP Proxy maintains persistent sessions for HTTP streamable transport, where each client connection is associated with a server instance that stays alive for the duration of the session.
59
+ By default, MCP Proxy maintains persistent sessions for HTTP streamable transport, where each client connection is associated with a server instance that stays alive for the duration of the session.
60
60
 
61
61
  Stateless mode (`--stateless`) changes this behavior:
62
62
 
@@ -94,11 +94,13 @@ MCP Proxy supports optional API key authentication to secure your endpoints. Whe
94
94
  Authentication is disabled by default for backward compatibility. To enable it, provide an API key via:
95
95
 
96
96
  **Command-line:**
97
+
97
98
  ```bash
98
99
  npx mcp-proxy --port 8080 --apiKey "your-secret-key" tsx server.js
99
100
  ```
100
101
 
101
102
  **Environment variable:**
103
+
102
104
  ```bash
103
105
  export MCP_PROXY_API_KEY="your-secret-key"
104
106
  npx mcp-proxy --port 8080 tsx server.js
@@ -111,28 +113,26 @@ Clients must include the API key in the `X-API-Key` header:
111
113
  ```typescript
112
114
  // For streamable HTTP transport
113
115
  const transport = new StreamableHTTPClientTransport(
114
- new URL('http://localhost:8080/mcp'),
116
+ new URL("http://localhost:8080/mcp"),
115
117
  {
116
118
  headers: {
117
- 'X-API-Key': 'your-secret-key'
118
- }
119
- }
119
+ "X-API-Key": "your-secret-key",
120
+ },
121
+ },
120
122
  );
121
123
 
122
124
  // For SSE transport
123
- const transport = new SSEClientTransport(
124
- new URL('http://localhost:8080/sse'),
125
- {
126
- headers: {
127
- 'X-API-Key': 'your-secret-key'
128
- }
129
- }
130
- );
125
+ const transport = new SSEClientTransport(new URL("http://localhost:8080/sse"), {
126
+ headers: {
127
+ "X-API-Key": "your-secret-key",
128
+ },
129
+ });
131
130
  ```
132
131
 
133
132
  #### Exempt Endpoints
134
133
 
135
134
  The following endpoints do not require authentication:
135
+
136
136
  - `/ping` - Health check endpoint
137
137
  - `OPTIONS` requests - CORS preflight requests
138
138
 
@@ -150,6 +150,7 @@ MCP Proxy provides flexible CORS (Cross-Origin Resource Sharing) configuration t
150
150
  #### Default Behavior
151
151
 
152
152
  By default, CORS is enabled with the following settings:
153
+
153
154
  - **Origin**: `*` (allow all origins)
154
155
  - **Methods**: `GET, POST, OPTIONS`
155
156
  - **Headers**: `Content-Type, Authorization, Accept, Mcp-Session-Id, Last-Event-Id`
@@ -159,24 +160,30 @@ By default, CORS is enabled with the following settings:
159
160
  #### Basic Configuration
160
161
 
161
162
  ```typescript
162
- import { startHTTPServer } from 'mcp-proxy';
163
+ import { startHTTPServer } from "mcp-proxy";
163
164
 
164
165
  // Use default CORS settings (backward compatible)
165
166
  await startHTTPServer({
166
- createServer: async () => { /* ... */ },
167
+ createServer: async () => {
168
+ /* ... */
169
+ },
167
170
  port: 3000,
168
171
  });
169
172
 
170
173
  // Explicitly enable default CORS
171
174
  await startHTTPServer({
172
- createServer: async () => { /* ... */ },
175
+ createServer: async () => {
176
+ /* ... */
177
+ },
173
178
  port: 3000,
174
179
  cors: true,
175
180
  });
176
181
 
177
182
  // Disable CORS completely
178
183
  await startHTTPServer({
179
- createServer: async () => { /* ... */ },
184
+ createServer: async () => {
185
+ /* ... */
186
+ },
180
187
  port: 3000,
181
188
  cors: false,
182
189
  });
@@ -187,44 +194,46 @@ await startHTTPServer({
187
194
  For more control over CORS behavior, you can provide a detailed configuration:
188
195
 
189
196
  ```typescript
190
- import { startHTTPServer, CorsOptions } from 'mcp-proxy';
197
+ import { startHTTPServer, CorsOptions } from "mcp-proxy";
191
198
 
192
199
  const corsOptions: CorsOptions = {
193
200
  // Allow specific origins
194
- origin: ['https://app.example.com', 'https://admin.example.com'],
195
-
201
+ origin: ["https://app.example.com", "https://admin.example.com"],
202
+
196
203
  // Or use a function for dynamic origin validation
197
- origin: (origin: string) => origin.endsWith('.example.com'),
198
-
204
+ origin: (origin: string) => origin.endsWith(".example.com"),
205
+
199
206
  // Specify allowed methods
200
- methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
201
-
207
+ methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
208
+
202
209
  // Allow any headers (useful for browser clients with custom headers)
203
- allowedHeaders: '*',
204
-
210
+ allowedHeaders: "*",
211
+
205
212
  // Or specify exact headers
206
213
  allowedHeaders: [
207
- 'Content-Type',
208
- 'Authorization',
209
- 'Accept',
210
- 'Mcp-Session-Id',
211
- 'Last-Event-Id',
212
- 'X-Custom-Header',
213
- 'X-API-Key'
214
+ "Content-Type",
215
+ "Authorization",
216
+ "Accept",
217
+ "Mcp-Session-Id",
218
+ "Last-Event-Id",
219
+ "X-Custom-Header",
220
+ "X-API-Key",
214
221
  ],
215
-
222
+
216
223
  // Headers to expose to the client
217
- exposedHeaders: ['Mcp-Session-Id', 'X-Total-Count'],
218
-
224
+ exposedHeaders: ["Mcp-Session-Id", "X-Total-Count"],
225
+
219
226
  // Allow credentials
220
227
  credentials: true,
221
-
228
+
222
229
  // Cache preflight requests for 24 hours
223
230
  maxAge: 86400,
224
231
  };
225
232
 
226
233
  await startHTTPServer({
227
- createServer: async () => { /* ... */ },
234
+ createServer: async () => {
235
+ /* ... */
236
+ },
228
237
  port: 3000,
229
238
  cors: corsOptions,
230
239
  });
@@ -233,36 +242,45 @@ await startHTTPServer({
233
242
  #### Common Use Cases
234
243
 
235
244
  **Allow any custom headers (solves browser CORS issues):**
245
+
236
246
  ```typescript
237
247
  await startHTTPServer({
238
- createServer: async () => { /* ... */ },
248
+ createServer: async () => {
249
+ /* ... */
250
+ },
239
251
  port: 3000,
240
252
  cors: {
241
- allowedHeaders: '*', // Allows X-Custom-Header, X-API-Key, etc.
253
+ allowedHeaders: "*", // Allows X-Custom-Header, X-API-Key, etc.
242
254
  },
243
255
  });
244
256
  ```
245
257
 
246
258
  **Restrict to specific domains:**
259
+
247
260
  ```typescript
248
261
  await startHTTPServer({
249
- createServer: async () => { /* ... */ },
262
+ createServer: async () => {
263
+ /* ... */
264
+ },
250
265
  port: 3000,
251
266
  cors: {
252
- origin: ['https://myapp.com', 'https://admin.myapp.com'],
253
- allowedHeaders: '*',
267
+ origin: ["https://myapp.com", "https://admin.myapp.com"],
268
+ allowedHeaders: "*",
254
269
  },
255
270
  });
256
271
  ```
257
272
 
258
273
  **Development-friendly settings:**
274
+
259
275
  ```typescript
260
276
  await startHTTPServer({
261
- createServer: async () => { /* ... */ },
277
+ createServer: async () => {
278
+ /* ... */
279
+ },
262
280
  port: 3000,
263
281
  cors: {
264
- origin: ['http://localhost:3000', 'http://localhost:5173'], // Common dev ports
265
- allowedHeaders: '*',
282
+ origin: ["http://localhost:3000", "http://localhost:5173"], // Common dev ports
283
+ allowedHeaders: "*",
266
284
  credentials: true,
267
285
  },
268
286
  });
@@ -275,16 +293,20 @@ If you were using mcp-proxy 5.5.6 and want the same permissive behavior in 5.9.0
275
293
  ```typescript
276
294
  // Old behavior (5.5.6) - automatic wildcard headers
277
295
  await startHTTPServer({
278
- createServer: async () => { /* ... */ },
296
+ createServer: async () => {
297
+ /* ... */
298
+ },
279
299
  port: 3000,
280
300
  });
281
301
 
282
302
  // New equivalent (5.9.0+) - explicit wildcard headers
283
303
  await startHTTPServer({
284
- createServer: async () => { /* ... */ },
304
+ createServer: async () => {
305
+ /* ... */
306
+ },
285
307
  port: 3000,
286
308
  cors: {
287
- allowedHeaders: '*',
309
+ allowedHeaders: "*",
288
310
  },
289
311
  });
290
312
  ```
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { Client, InMemoryEventStore, ReadBuffer, Server, __commonJS, __toESM, proxyServer, serializeMessage, startHTTPServer } from "../stdio-DQCs94rj.js";
2
+ import { D as __toESM, E as __commonJS, a as startHTTPServer, i as Client, n as serializeMessage, o as proxyServer, r as Server, t as ReadBuffer, w as InMemoryEventStore } from "../stdio-BAyQuMKu.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";
6
- import { fileURLToPath } from "url";
7
6
  import { setTimeout as setTimeout$1 } from "node:timers";
8
7
  import util from "node:util";
9
8
  import { notStrictEqual, strictEqual } from "assert";
10
9
  import { readFileSync, readdirSync, statSync, writeFile } from "fs";
10
+ import { fileURLToPath } from "url";
11
11
  import { readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "node:fs";
12
12
  import { spawn } from "node:child_process";
13
13
  import { PassThrough, Transform } from "node:stream";
@@ -39,8 +39,8 @@ function createParser(callbacks) {
39
39
  }
40
40
  const fieldSeparatorIndex = line.indexOf(":");
41
41
  if (fieldSeparatorIndex !== -1) {
42
- const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
43
- processField(field, value, line);
42
+ const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1;
43
+ processField(field, line.slice(fieldSeparatorIndex + offset), line);
44
44
  return;
45
45
  }
46
46
  processField(line, "", line);
@@ -110,7 +110,7 @@ function splitLines(chunk) {
110
110
  }
111
111
 
112
112
  //#endregion
113
- //#region node_modules/.pnpm/eventsource@4.0.0/node_modules/eventsource/dist/index.js
113
+ //#region node_modules/.pnpm/eventsource@4.1.0/node_modules/eventsource/dist/index.js
114
114
  var ErrorEvent = class extends Event {
115
115
  /**
116
116
  * Constructs a new `ErrorEvent` instance. This is typically not called directly,
@@ -336,6 +336,12 @@ _readyState = /* @__PURE__ */ new WeakMap(), _url = /* @__PURE__ */ new WeakMap(
336
336
  });
337
337
  (_a$1 = __privateGet(this, _onError)) == null || _a$1.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
338
338
  }, _reconnect = /* @__PURE__ */ new WeakMap(), EventSource.CONNECTING = 0, EventSource.OPEN = 1, EventSource.CLOSED = 2;
339
+ Object.defineProperty(EventSource, Symbol.for("eventsource.supports-fetch-override"), {
340
+ value: !0,
341
+ writable: !1,
342
+ configurable: !1,
343
+ enumerable: !1
344
+ });
339
345
  function getBaseURL() {
340
346
  const doc = "document" in globalThis ? globalThis.document : void 0;
341
347
  return doc && typeof doc == "object" && "baseURI" in doc && typeof doc.baseURI == "string" ? doc.baseURI : void 0;
@@ -1355,18 +1361,14 @@ var YargsParser = class {
1355
1361
  return i;
1356
1362
  }
1357
1363
  function setArg(key, val, shouldStripQuotes = inputIsString) {
1358
- if (/-/.test(key) && configuration["camel-case-expansion"]) {
1359
- const alias = key.split(".").map(function(prop) {
1360
- return camelCase(prop);
1361
- }).join(".");
1362
- addNewAlias(key, alias);
1363
- }
1364
+ if (/-/.test(key) && configuration["camel-case-expansion"]) addNewAlias(key, key.split(".").map(function(prop) {
1365
+ return camelCase(prop);
1366
+ }).join("."));
1364
1367
  const value = processValue(key, val, shouldStripQuotes);
1365
1368
  const splitKey = key.split(".");
1366
1369
  setKey(argv$1, splitKey, value);
1367
1370
  if (flags.aliases[key]) flags.aliases[key].forEach(function(x) {
1368
- const keyProperties = x.split(".");
1369
- setKey(argv$1, keyProperties, value);
1371
+ setKey(argv$1, x.split("."), value);
1370
1372
  });
1371
1373
  if (splitKey.length > 1 && configuration["dot-notation"]) (flags.aliases[splitKey[0]] || []).forEach(function(x) {
1372
1374
  let keyProperties = x.split(".");
@@ -2076,15 +2078,13 @@ function argsert(arg1, arg2, arg3) {
2076
2078
  const totalCommands = parsed.demanded.length + parsed.optional.length;
2077
2079
  if (length > totalCommands) throw new YError(`Too many arguments provided. Expected max ${totalCommands} but received ${length}.`);
2078
2080
  parsed.demanded.forEach((demanded) => {
2079
- const arg = args.shift();
2080
- const observedType = guessType(arg);
2081
+ const observedType = guessType(args.shift());
2081
2082
  if (demanded.cmd.filter((type) => type === observedType || type === "*").length === 0) argumentTypeError(observedType, demanded.cmd, position);
2082
2083
  position += 1;
2083
2084
  });
2084
2085
  parsed.optional.forEach((optional) => {
2085
2086
  if (args.length === 0) return;
2086
- const arg = args.shift();
2087
- const observedType = guessType(arg);
2087
+ const observedType = guessType(args.shift());
2088
2088
  if (optional.cmd.filter((type) => type === observedType || type === "*").length === 0) argumentTypeError(observedType, optional.cmd, position);
2089
2089
  position += 1;
2090
2090
  });
@@ -2781,27 +2781,25 @@ function usage(yargs, shim$2) {
2781
2781
  addUngroupedKeys(keys, options.alias, groups, defaultGroup);
2782
2782
  const isLongSwitch = (sw) => /^--/.test(getText(sw));
2783
2783
  const displayedGroups = Object.keys(groups).filter((groupName) => groups[groupName].length > 0).map((groupName) => {
2784
- const normalizedKeys = groups[groupName].filter(filterHiddenOptions).map((key) => {
2785
- if (aliasKeys.includes(key)) return key;
2786
- for (let i = 0, aliasKey; (aliasKey = aliasKeys[i]) !== void 0; i++) if ((options.alias[aliasKey] || []).includes(key)) return aliasKey;
2787
- return key;
2788
- });
2789
2784
  return {
2790
2785
  groupName,
2791
- normalizedKeys
2786
+ normalizedKeys: groups[groupName].filter(filterHiddenOptions).map((key) => {
2787
+ if (aliasKeys.includes(key)) return key;
2788
+ for (let i = 0, aliasKey; (aliasKey = aliasKeys[i]) !== void 0; i++) if ((options.alias[aliasKey] || []).includes(key)) return aliasKey;
2789
+ return key;
2790
+ })
2792
2791
  };
2793
2792
  }).filter(({ normalizedKeys }) => normalizedKeys.length > 0).map(({ groupName, normalizedKeys }) => {
2794
- const switches = normalizedKeys.reduce((acc, key) => {
2795
- acc[key] = [key].concat(options.alias[key] || []).map((sw) => {
2796
- if (groupName === self.getPositionalGroupName()) return sw;
2797
- else return (/^[0-9]$/.test(sw) ? options.boolean.includes(key) ? "-" : "--" : sw.length > 1 ? "--" : "-") + sw;
2798
- }).sort((sw1, sw2) => isLongSwitch(sw1) === isLongSwitch(sw2) ? 0 : isLongSwitch(sw1) ? 1 : -1).join(", ");
2799
- return acc;
2800
- }, {});
2801
2793
  return {
2802
2794
  groupName,
2803
2795
  normalizedKeys,
2804
- switches
2796
+ switches: normalizedKeys.reduce((acc, key) => {
2797
+ acc[key] = [key].concat(options.alias[key] || []).map((sw) => {
2798
+ if (groupName === self.getPositionalGroupName()) return sw;
2799
+ else return (/^[0-9]$/.test(sw) ? options.boolean.includes(key) ? "-" : "--" : sw.length > 1 ? "--" : "-") + sw;
2800
+ }).sort((sw1, sw2) => isLongSwitch(sw1) === isLongSwitch(sw2) ? 0 : isLongSwitch(sw1) ? 1 : -1).join(", ");
2801
+ return acc;
2802
+ }, {})
2805
2803
  };
2806
2804
  });
2807
2805
  if (displayedGroups.filter(({ groupName }) => groupName !== self.getPositionalGroupName()).some(({ normalizedKeys, switches }) => !normalizedKeys.every((key) => isLongSwitch(switches[key])))) displayedGroups.filter(({ groupName }) => groupName !== self.getPositionalGroupName()).forEach(({ normalizedKeys, switches }) => {
@@ -3748,8 +3746,7 @@ var YargsInstance = class {
3748
3746
  __classPrivateFieldGet(this, _YargsInstance_options, "f").key[coerceKey] = true;
3749
3747
  __classPrivateFieldGet(this, _YargsInstance_globalMiddleware, "f").addCoerceMiddleware((argv$1, yargs) => {
3750
3748
  var _a$1;
3751
- const coerceKeyAliases = (_a$1 = yargs.getAliases()[coerceKey]) !== null && _a$1 !== void 0 ? _a$1 : [];
3752
- const argvKeys = [coerceKey, ...coerceKeyAliases].filter((key) => Object.prototype.hasOwnProperty.call(argv$1, key));
3749
+ const argvKeys = [coerceKey, ...(_a$1 = yargs.getAliases()[coerceKey]) !== null && _a$1 !== void 0 ? _a$1 : []].filter((key) => Object.prototype.hasOwnProperty.call(argv$1, key));
3753
3750
  if (argvKeys.length === 0) return argv$1;
3754
3751
  return maybeAsyncResult(() => {
3755
3752
  return value(argv$1[argvKeys[0]]);
@@ -5140,9 +5137,8 @@ const createGracefulShutdown = ({ server, timeout }) => {
5140
5137
  };
5141
5138
  const main = async () => {
5142
5139
  try {
5143
- const server = await proxy();
5144
5140
  createGracefulShutdown({
5145
- server,
5141
+ server: await proxy(),
5146
5142
  timeout: argv.gracefulShutdownTimeout
5147
5143
  });
5148
5144
  } catch (error) {