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 +71 -49
- package/dist/bin/mcp-proxy.js +31 -35
- package/dist/bin/mcp-proxy.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +516 -295
- package/dist/index.js.map +1 -1
- package/dist/{stdio-DQCs94rj.js → stdio-BAyQuMKu.js} +11135 -8848
- package/dist/stdio-BAyQuMKu.js.map +1 -0
- package/jsr.json +1 -1
- package/package.json +19 -19
- package/src/InMemoryEventStore.test.ts +58 -50
- package/src/InMemoryEventStore.ts +2 -3
- package/src/authentication.test.ts +275 -18
- package/src/authentication.ts +57 -5
- package/src/bin/mcp-proxy.ts +2 -1
- package/src/proxyServer.test.ts +40 -22
- package/src/startHTTPServer.test.ts +41 -23
- package/src/startHTTPServer.ts +132 -52
- package/src/startStdioServer.test.ts +8 -5
- package/dist/stdio-DQCs94rj.js.map +0 -1
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(
|
|
116
|
+
new URL("http://localhost:8080/mcp"),
|
|
115
117
|
{
|
|
116
118
|
headers: {
|
|
117
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
|
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
|
|
197
|
+
import { startHTTPServer, CorsOptions } from "mcp-proxy";
|
|
191
198
|
|
|
192
199
|
const corsOptions: CorsOptions = {
|
|
193
200
|
// Allow specific origins
|
|
194
|
-
origin: [
|
|
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(
|
|
198
|
-
|
|
204
|
+
origin: (origin: string) => origin.endsWith(".example.com"),
|
|
205
|
+
|
|
199
206
|
// Specify allowed methods
|
|
200
|
-
methods: [
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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: [
|
|
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:
|
|
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: [
|
|
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: [
|
|
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
|
```
|
package/dist/bin/mcp-proxy.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
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
|
|
43
|
-
processField(field,
|
|
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.
|
|
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
|
-
|
|
1360
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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) {
|