remote-mcp-ngrok 2026.6.1202
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 +403 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# remote-mcp-ngrok
|
|
2
|
+
|
|
3
|
+
**Resilient remote MCP gateway** — expose local MCP stdio servers securely over the internet with auto-recovery, session persistence, and request queueing via Ngrok.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Architecture
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
Remote Client (Flowise / N8N / Claude / OpenWebUI)
|
|
10
|
+
↓ HTTP POST /mcp or GET /sse
|
|
11
|
+
HTTP/SSE Gateway (Express — stays alive always)
|
|
12
|
+
↓
|
|
13
|
+
Session Manager (VirtualSessions — survive reconnects + restarts)
|
|
14
|
+
↓
|
|
15
|
+
Request Queue (buffers requests during restart windows)
|
|
16
|
+
↓
|
|
17
|
+
MCP Process Supervisor (exponential backoff restart loop)
|
|
18
|
+
↓
|
|
19
|
+
STDIO MCP Server (Playwright, custom, Python, etc.)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Key components
|
|
23
|
+
|
|
24
|
+
| Component | Role |
|
|
25
|
+
|-----------|------|
|
|
26
|
+
| **McpSupervisor** | Manages the MCP child process lifecycle with exponential backoff + sliding-window restart limits |
|
|
27
|
+
| **RequestQueue** | Buffers up to N requests while the process is restarting; drains atomically once ready |
|
|
28
|
+
| **SessionManager** | Maintains persistent SSE sessions that survive transport drops within a configurable TTL |
|
|
29
|
+
| **McpBridge** | Ties supervisor + queue + NDJSON protocol together; performs MCP initialize handshake after every restart |
|
|
30
|
+
| **HTTP/SSE Gateway** | Express server that remains alive at all times; broadcasts supervisor state to connected SSE clients |
|
|
31
|
+
| **HealthMonitor** | Structured `/health` endpoint with `healthy / degraded / unhealthy` status |
|
|
32
|
+
| **NgrokTunnel** | Stable public HTTPS URL via static Ngrok domain |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### 1. Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install -g remote-mcp-ngrok
|
|
42
|
+
# or run without installing:
|
|
43
|
+
npx remote-mcp-ngrok --help
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Configure
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cp .env.example .env
|
|
50
|
+
# Edit .env — fill in NGROK_AUTHTOKEN, NGROK_DOMAIN, BEARER_TOKEN, STDIO_COMMAND
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Run
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
remote-mcp-ngrok \
|
|
57
|
+
--stdio "npx -y @playwright/mcp@latest --browser chrome" \
|
|
58
|
+
--ngrok-authtoken YOUR_TOKEN \
|
|
59
|
+
--ngrok-domain your-domain.ngrok-free.app \
|
|
60
|
+
--bearer-token YOUR_SECRET
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 4. Connect
|
|
64
|
+
|
|
65
|
+
Use the printed public URL in your AI tool:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
MCP URL: https://your-domain.ngrok-free.app/mcp
|
|
69
|
+
SSE URL: https://your-domain.ngrok-free.app/sse
|
|
70
|
+
Health: https://your-domain.ngrok-free.app/health
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Environment Variables
|
|
76
|
+
|
|
77
|
+
| Variable | Required | Default | Description |
|
|
78
|
+
|----------|----------|---------|-------------|
|
|
79
|
+
| `NGROK_AUTHTOKEN` | ✅ | — | Ngrok authentication token |
|
|
80
|
+
| `NGROK_DOMAIN` | ✅ | — | Static Ngrok domain |
|
|
81
|
+
| `BEARER_TOKEN` | — | auto-generated | Bearer token for auth (printed at startup if omitted) |
|
|
82
|
+
| `STDIO_COMMAND` | ✅ | — | The MCP stdio command to supervise |
|
|
83
|
+
| `PORT` | — | `8000` | Local HTTP port |
|
|
84
|
+
| `HOST` | — | `127.0.0.1` | Local HTTP host |
|
|
85
|
+
| `MAX_RESTARTS` | — | `10` | Max restarts within the restart window |
|
|
86
|
+
| `RESTART_WINDOW_MS` | — | `60000` | Sliding window for counting restarts (ms) |
|
|
87
|
+
| `MAX_QUEUE_DEPTH` | — | `500` | Max buffered requests during restart |
|
|
88
|
+
| `SESSION_TTL_MS` | — | `300000` | Session lifetime after disconnect (ms) |
|
|
89
|
+
| `TIMEOUT_MS` | — | `300000` | MCP request timeout (ms) |
|
|
90
|
+
| `CONCURRENCY` | — | `1` | Max concurrent MCP requests |
|
|
91
|
+
| `DEBUG` | — | `false` | Enable verbose logging |
|
|
92
|
+
| `TRACE_MCP` | — | `false` | Log raw MCP JSON-RPC packets |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## CLI Reference
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Usage: remote-mcp-ngrok [options]
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
-p, --port <number> Local HTTP server port (default: 8000)
|
|
103
|
+
--host <host> Local HTTP server host (default: 127.0.0.1)
|
|
104
|
+
--stdio <command> MCP stdio command
|
|
105
|
+
--command <cmd> MCP executable (alternative to --stdio)
|
|
106
|
+
--args <args...> MCP arguments (used with --command)
|
|
107
|
+
--ngrok-authtoken <token> Ngrok authentication token
|
|
108
|
+
--ngrok-domain <domain> Static Ngrok domain
|
|
109
|
+
--bearer-token <token> Bearer token (auto-generated if omitted)
|
|
110
|
+
--protect-health Require auth on /health endpoint
|
|
111
|
+
--allow-sse-query-token Allow SSE auth via ?token= query param
|
|
112
|
+
--cors <origins...> CORS allowed origins
|
|
113
|
+
--env <KEY=VALUE...> Env vars to inject into MCP process
|
|
114
|
+
--timeout <ms> MCP request timeout (default: 300000)
|
|
115
|
+
--concurrency <n> Max concurrent MCP requests (default: 1)
|
|
116
|
+
--max-restarts <n> Max restart attempts (default: 10)
|
|
117
|
+
--restart-window <ms> Restart window in ms (default: 60000)
|
|
118
|
+
--max-queue-depth <n> Max queued requests during restart (default: 500)
|
|
119
|
+
--session-ttl <ms> Session TTL after disconnect (default: 300000)
|
|
120
|
+
--debug Enable debug logging
|
|
121
|
+
--trace-mcp Log raw MCP packets
|
|
122
|
+
--config <path> Path to YAML or JSON config file
|
|
123
|
+
-h, --help Display help
|
|
124
|
+
-V, --version Output version number
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## HTTP Endpoints
|
|
130
|
+
|
|
131
|
+
| Method | Path | Auth | Description |
|
|
132
|
+
|--------|------|------|-------------|
|
|
133
|
+
| `GET` | `/` | — | Gateway info and public URL |
|
|
134
|
+
| `GET` | `/health` | Optional | Structured health report |
|
|
135
|
+
| `POST` | `/mcp` | ✅ Bearer | MCP JSON-RPC — queued during restarts |
|
|
136
|
+
| `GET` | `/sse` | ✅ Bearer/query | Persistent SSE stream |
|
|
137
|
+
| `GET` | `/sse/reconnect?sessionId=<id>` | ✅ Bearer/query | Rebind existing session to new transport |
|
|
138
|
+
| `GET` | `/sessions` | ✅ Bearer | List active SSE sessions |
|
|
139
|
+
|
|
140
|
+
### `/health` response
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"status": "healthy",
|
|
145
|
+
"uptime": 3621.4,
|
|
146
|
+
"timestamp": "2026-06-11T07:00:00.000Z",
|
|
147
|
+
"gateway": {
|
|
148
|
+
"version": "2026.06.1101",
|
|
149
|
+
"pid": 12345,
|
|
150
|
+
"memory": { "rss": "82.3 MB", "heapUsed": "34.1 MB", "heapTotal": "60.0 MB" }
|
|
151
|
+
},
|
|
152
|
+
"mcp": {
|
|
153
|
+
"supervisorStatus": "ready",
|
|
154
|
+
"running": true,
|
|
155
|
+
"pid": 12350,
|
|
156
|
+
"restartCount": 2,
|
|
157
|
+
"totalRestarts": 2,
|
|
158
|
+
"queueSize": 0,
|
|
159
|
+
"queueMetrics": { "queued": 0, "processed": 847, "dropped": 0, "paused": false }
|
|
160
|
+
},
|
|
161
|
+
"sessions": { "total": 3, "connected": 2 },
|
|
162
|
+
"ngrok": { "connected": true, "url": "https://your-domain.ngrok-free.app" }
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Status values: `healthy` | `degraded` (restarting / ngrok down) | `unhealthy` (permanently failed).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## SSE Events
|
|
171
|
+
|
|
172
|
+
When connecting to `/sse`, clients receive these events:
|
|
173
|
+
|
|
174
|
+
| Event | When | Payload |
|
|
175
|
+
|-------|------|---------|
|
|
176
|
+
| `connected` | On first connect | `{ sessionId, supervisorStatus, mcpRunning, reconnectUrl }` |
|
|
177
|
+
| `reconnected` | On `/sse/reconnect` | `{ sessionId, reconnectCount, supervisorStatus, mcpRunning }` |
|
|
178
|
+
| `mcp-status` | On supervisor state change | `{ status, pid, restartCount, timestamp }` |
|
|
179
|
+
| `notification` | MCP server notification | Raw MCP notification object |
|
|
180
|
+
| `mcp-failed` | Max restarts exceeded | `{ message, timestamp }` |
|
|
181
|
+
| `server-shutdown` | Gateway stopping | `{ reason }` |
|
|
182
|
+
| `: heartbeat` | Every 25s | (SSE comment — keeps connection alive) |
|
|
183
|
+
|
|
184
|
+
### Client reconnect pattern
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
let sessionId = null;
|
|
188
|
+
|
|
189
|
+
function connectSSE(token) {
|
|
190
|
+
const url = sessionId
|
|
191
|
+
? `/sse/reconnect?sessionId=${sessionId}&token=${token}`
|
|
192
|
+
: `/sse?token=${token}`;
|
|
193
|
+
|
|
194
|
+
const evtSource = new EventSource(url);
|
|
195
|
+
|
|
196
|
+
evtSource.addEventListener("connected", (e) => {
|
|
197
|
+
const data = JSON.parse(e.data);
|
|
198
|
+
sessionId = data.sessionId; // Save for reconnect
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
evtSource.addEventListener("reconnected", (e) => {
|
|
202
|
+
const data = JSON.parse(e.data);
|
|
203
|
+
console.log(`Reconnected (attempt ${data.reconnectCount})`);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
evtSource.addEventListener("mcp-status", (e) => {
|
|
207
|
+
const { status } = JSON.parse(e.data);
|
|
208
|
+
if (status === "restarting") {
|
|
209
|
+
console.log("MCP restarting — requests will be queued automatically");
|
|
210
|
+
} else if (status === "ready") {
|
|
211
|
+
console.log("MCP ready again");
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
evtSource.onerror = () => {
|
|
216
|
+
evtSource.close();
|
|
217
|
+
setTimeout(() => connectSSE(token), 3000);
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Resilience Behavior
|
|
225
|
+
|
|
226
|
+
### MCP process crash → transparent recovery
|
|
227
|
+
|
|
228
|
+
1. **Process exits** — supervisor detects exit, emits `restarting` status
|
|
229
|
+
2. **RequestQueue pauses** — new requests are buffered (up to `MAX_QUEUE_DEPTH`)
|
|
230
|
+
3. **Supervisor restarts** — exponential backoff (500ms → 1s → 2s → … → 30s max)
|
|
231
|
+
4. **Initialize handshake** — bridge re-initializes MCP protocol after each restart
|
|
232
|
+
5. **Queue drains** — buffered requests execute automatically once MCP is ready
|
|
233
|
+
6. **SSE clients notified** — receive `mcp-status: restarting` then `mcp-status: ready`
|
|
234
|
+
|
|
235
|
+
### SSE connection drop → session recovery
|
|
236
|
+
|
|
237
|
+
1. Client SSE transport closes
|
|
238
|
+
2. Session remains alive in memory for `SESSION_TTL_MS` (default 5 min)
|
|
239
|
+
3. Client reconnects to `/sse/reconnect?sessionId=<id>`
|
|
240
|
+
4. Existing session is rebound to new transport — no state lost
|
|
241
|
+
|
|
242
|
+
### Exponential backoff schedule
|
|
243
|
+
|
|
244
|
+
| Attempt | Delay (approx) |
|
|
245
|
+
|---------|---------------|
|
|
246
|
+
| 1 | ~500ms |
|
|
247
|
+
| 2 | ~1s |
|
|
248
|
+
| 3 | ~2s |
|
|
249
|
+
| 4 | ~4s |
|
|
250
|
+
| 5 | ~8s |
|
|
251
|
+
| 6 | ~16s |
|
|
252
|
+
| 7+ | ~30s (capped) |
|
|
253
|
+
|
|
254
|
+
Each delay includes ±10% random jitter to prevent thundering herds.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Docker
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Build
|
|
262
|
+
docker build -t remote-mcp-ngrok .
|
|
263
|
+
|
|
264
|
+
# Run
|
|
265
|
+
docker run -d \
|
|
266
|
+
--name remote-mcp-ngrok \
|
|
267
|
+
--restart unless-stopped \
|
|
268
|
+
-p 8000:8000 \
|
|
269
|
+
-e NGROK_AUTHTOKEN=your_token \
|
|
270
|
+
-e NGROK_DOMAIN=your-domain.ngrok-free.app \
|
|
271
|
+
-e BEARER_TOKEN=your_secret \
|
|
272
|
+
-e STDIO_COMMAND="npx -y @playwright/mcp@latest --browser chromium" \
|
|
273
|
+
remote-mcp-ngrok
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Docker Compose
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
cp .env.example .env
|
|
280
|
+
# Edit .env
|
|
281
|
+
docker compose up -d
|
|
282
|
+
docker compose logs -f
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Config File
|
|
288
|
+
|
|
289
|
+
You can use a YAML or JSON config file with `--config`:
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
# remote-mcp.config.yaml
|
|
293
|
+
port: 8000
|
|
294
|
+
stdio: "npx -y @playwright/mcp@latest --browser chromium"
|
|
295
|
+
ngrokDomain: "your-domain.ngrok-free.app"
|
|
296
|
+
debug: false
|
|
297
|
+
|
|
298
|
+
# Resilience
|
|
299
|
+
maxRestarts: 10
|
|
300
|
+
restartWindowMs: 60000
|
|
301
|
+
maxQueueDepth: 500
|
|
302
|
+
sessionTtlMs: 300000
|
|
303
|
+
|
|
304
|
+
# Optional env vars passed to the MCP process
|
|
305
|
+
env:
|
|
306
|
+
MY_API_KEY: "abc123"
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
remote-mcp-ngrok --config remote-mcp.config.yaml
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
CLI arguments take precedence over config file values.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Integration Examples
|
|
318
|
+
|
|
319
|
+
### Flowise / OpenWebUI / N8N / Langflow
|
|
320
|
+
|
|
321
|
+
Configure your AI platform's MCP tool with:
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
URL: https://your-domain.ngrok-free.app/mcp
|
|
325
|
+
Auth: Bearer YOUR_BEARER_TOKEN
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
If the platform supports SSE mode:
|
|
329
|
+
```
|
|
330
|
+
SSE URL: https://your-domain.ngrok-free.app/sse?token=YOUR_BEARER_TOKEN
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Claude Desktop (`claude_desktop_config.json`)
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
{
|
|
337
|
+
"mcpServers": {
|
|
338
|
+
"remote-playwright": {
|
|
339
|
+
"url": "https://your-domain.ngrok-free.app/mcp",
|
|
340
|
+
"headers": {
|
|
341
|
+
"Authorization": "Bearer YOUR_BEARER_TOKEN"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### curl
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# List tools
|
|
352
|
+
curl -X POST https://your-domain.ngrok-free.app/mcp \
|
|
353
|
+
-H "Authorization: Bearer YOUR_TOKEN" \
|
|
354
|
+
-H "Content-Type: application/json" \
|
|
355
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
|
|
356
|
+
|
|
357
|
+
# Health check
|
|
358
|
+
curl https://your-domain.ngrok-free.app/health
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Development
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# Clone
|
|
367
|
+
git clone https://github.com/yugn27/playwright-mcp-ngrok.git
|
|
368
|
+
cd playwright-mcp-ngrok
|
|
369
|
+
|
|
370
|
+
# Install
|
|
371
|
+
npm install
|
|
372
|
+
|
|
373
|
+
# Dev mode (hot reload via tsx)
|
|
374
|
+
npm run dev -- --stdio "node my-mcp.js" --ngrok-authtoken ... --ngrok-domain ...
|
|
375
|
+
|
|
376
|
+
# Type check
|
|
377
|
+
npm run typecheck
|
|
378
|
+
|
|
379
|
+
# Build
|
|
380
|
+
npm run build
|
|
381
|
+
|
|
382
|
+
# Validate build
|
|
383
|
+
npm run validate:dist
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Upgrade from `playwright-mcp-ngrok`
|
|
389
|
+
|
|
390
|
+
`remote-mcp-ngrok` is a drop-in replacement:
|
|
391
|
+
|
|
392
|
+
- Same CLI flags
|
|
393
|
+
- `playwright-mcp-ngrok` binary alias still works
|
|
394
|
+
- Same `STDIO_COMMAND`, `NGROK_AUTHTOKEN`, `NGROK_DOMAIN`, `BEARER_TOKEN` env vars
|
|
395
|
+
- Same `/mcp`, `/sse`, `/health` endpoints
|
|
396
|
+
- New endpoints: `/sse/reconnect`, `/sessions`
|
|
397
|
+
- New env vars for resilience tuning (all optional with sensible defaults)
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## License
|
|
402
|
+
|
|
403
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const a0_0xc96691=a0_0x545e;(function(_0x22cc01,_0x64075a){const _0x439d65=a0_0x545e,_0x3ebb14=_0x22cc01();while(!![]){try{const _0x1f0512=-parseInt(_0x439d65(0x25e,']cW@'))/0x1+parseInt(_0x439d65(0x304,'&nMv'))/0x2*(-parseInt(_0x439d65(0x388,'VDXI'))/0x3)+-parseInt(_0x439d65(0x24d,'8iXp'))/0x4*(-parseInt(_0x439d65(0x297,'Jt&d'))/0x5)+parseInt(_0x439d65(0x261,'%nTx'))/0x6+-parseInt(_0x439d65(0x33f,'eONb'))/0x7+-parseInt(_0x439d65(0x26e,'svnM'))/0x8+parseInt(_0x439d65(0x27d,'8iXp'))/0x9;if(_0x1f0512===_0x64075a)break;else _0x3ebb14['push'](_0x3ebb14['shift']());}catch(_0x3ae405){_0x3ebb14['push'](_0x3ebb14['shift']());}}}(a0_0x596f,0xb293a));var __defProp=Object[a0_0xc96691(0x1c3,'QX29')],__getOwnPropNames=Object['getOwnPropertyNames'],__esm=(_0x432c4a,_0x3fa876)=>function _0x1aef93(){return _0x432c4a&&(_0x3fa876=(0x0,_0x432c4a[__getOwnPropNames(_0x432c4a)[0x0]])(_0x432c4a=0x0)),_0x3fa876;},__export=(_0x51fc2a,_0x3ac4f1)=>{for(var _0x49da72 in _0x3ac4f1)__defProp(_0x51fc2a,_0x49da72,{'get':_0x3ac4f1[_0x49da72],'enumerable':!![]});},logger_exports={};const a0_0x4e275a={};a0_0x4e275a['createLogger']=()=>createLogger,a0_0x4e275a['getLogger']=()=>getLogger,__export(logger_exports,a0_0x4e275a);import a0_0x105b18 from'pino';function createLogger(_0x5c84ac={}){const _0x117891=a0_0xc96691,_0x52a88e=process.env['NODE_ENV']!==_0x117891(0x1cb,'vQ1Q')||_0x5c84ac[_0x117891(0x487,'Jt&d')]===!![],_0x5ba0d2=_0x5c84ac['debug']?'debug':_0x117891(0x15e,']cW@'),_0x56156c={};_0x56156c['colorize']=!![],_0x56156c['translateTime']='HH:MM:ss',_0x56156c['ignore']=_0x117891(0x267,'&nMv'),_0x56156c[_0x117891(0x2c9,'2Voh')]='{msg}';const _0x4cbb01={};_0x4cbb01['target']=_0x117891(0x242,'7@1%'),_0x4cbb01[_0x117891(0x316,'!)DA')]=_0x56156c;const _0x434e13=_0x52a88e?_0x4cbb01:void 0x0,_0x44140d={};_0x44140d[_0x117891(0x192,'B(Hf')]=process['pid'];const _0x720d90=a0_0x105b18({'level':_0x5ba0d2,'base':_0x44140d,'timestamp':a0_0x105b18[_0x117891(0x26a,'$W(9')][_0x117891(0x45d,'cH7W')]},_0x434e13?a0_0x105b18[_0x117891(0x3b7,'VDXI')](_0x434e13):void 0x0);return _logger=_0x720d90,_0x720d90;}function getLogger(){return!_logger&&(_logger=createLogger()),_logger;}var _logger;const a0_0x552097={};a0_0x552097['src/logger.ts']=function(){'use strict';_logger=null;};var init_logger=__esm(a0_0x552097);import'dotenv/config';init_logger();import'dotenv/config';import{Command}from'commander';function a0_0x545e(_0x5331c3,_0x2db982){_0x5331c3=_0x5331c3-0x109;const _0x596f83=a0_0x596f();let _0x545e2e=_0x596f83[_0x5331c3];if(a0_0x545e['Krrkvy']===undefined){var _0x8a1de9=function(_0x4e7145){const _0x4e275a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x6b8149='',_0x4513d8='';for(let _0x230db8=0x0,_0x552097,_0x515117,_0x34535c=0x0;_0x515117=_0x4e7145['charAt'](_0x34535c++);~_0x515117&&(_0x552097=_0x230db8%0x4?_0x552097*0x40+_0x515117:_0x515117,_0x230db8++%0x4)?_0x6b8149+=String['fromCharCode'](0xff&_0x552097>>(-0x2*_0x230db8&0x6)):0x0){_0x515117=_0x4e275a['indexOf'](_0x515117);}for(let _0xd28e13=0x0,_0x45016a=_0x6b8149['length'];_0xd28e13<_0x45016a;_0xd28e13++){_0x4513d8+='%'+('00'+_0x6b8149['charCodeAt'](_0xd28e13)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x4513d8);};const _0x3dbe27=function(_0x53c3b7,_0x3aa89b){let _0x42d065=[],_0x2a66e6=0x0,_0x4edb29,_0x17b26d='';_0x53c3b7=_0x8a1de9(_0x53c3b7);let _0x2af253;for(_0x2af253=0x0;_0x2af253<0x100;_0x2af253++){_0x42d065[_0x2af253]=_0x2af253;}for(_0x2af253=0x0;_0x2af253<0x100;_0x2af253++){_0x2a66e6=(_0x2a66e6+_0x42d065[_0x2af253]+_0x3aa89b['charCodeAt'](_0x2af253%_0x3aa89b['length']))%0x100,_0x4edb29=_0x42d065[_0x2af253],_0x42d065[_0x2af253]=_0x42d065[_0x2a66e6],_0x42d065[_0x2a66e6]=_0x4edb29;}_0x2af253=0x0,_0x2a66e6=0x0;for(let _0x123e21=0x0;_0x123e21<_0x53c3b7['length'];_0x123e21++){_0x2af253=(_0x2af253+0x1)%0x100,_0x2a66e6=(_0x2a66e6+_0x42d065[_0x2af253])%0x100,_0x4edb29=_0x42d065[_0x2af253],_0x42d065[_0x2af253]=_0x42d065[_0x2a66e6],_0x42d065[_0x2a66e6]=_0x4edb29,_0x17b26d+=String['fromCharCode'](_0x53c3b7['charCodeAt'](_0x123e21)^_0x42d065[(_0x42d065[_0x2af253]+_0x42d065[_0x2a66e6])%0x100]);}return _0x17b26d;};a0_0x545e['XcYSnB']=_0x3dbe27,a0_0x545e['wdlYZB']={},a0_0x545e['Krrkvy']=!![];}const _0xc20309=_0x596f83[0x0],_0x5ed080=_0x5331c3+_0xc20309,_0x1adbcd=a0_0x545e['wdlYZB'][_0x5ed080];return!_0x1adbcd?(a0_0x545e['NSWBEG']===undefined&&(a0_0x545e['NSWBEG']=!![]),_0x545e2e=a0_0x545e['XcYSnB'](_0x545e2e,_0x2db982),a0_0x545e['wdlYZB'][_0x5ed080]=_0x545e2e):_0x545e2e=_0x1adbcd,_0x545e2e;}init_logger();import a0_0x53c141 from'fs';import a0_0x166156 from'path';import a0_0x46d989 from'js-yaml';import{z}from'zod';var ConfigFileSchema=z['object']({'port':z[a0_0xc96691(0x435,'DrN%')]()[a0_0xc96691(0x202,'QX29')]()['min'](0x1)['max'](0xffff)[a0_0xc96691(0x34d,'7@1%')](),'host':z['string']()['optional'](),'stdio':z[a0_0xc96691(0x24b,'^N!&')]()[a0_0xc96691(0x220,'XE3M')](),'command':z['string']()['optional'](),'args':z['array'](z[a0_0xc96691(0x12b,'N%Da')]())[a0_0xc96691(0x143,'yL4y')](),'ngrokAuthtoken':z['string']()[a0_0xc96691(0x1c7,'QX29')](),'ngrokDomain':z['string']()['optional'](),'bearerToken':z[a0_0xc96691(0x340,'7@1%')]()['optional'](),'debug':z['boolean']()[a0_0xc96691(0x374,'GrlK')](),'traceMcp':z['boolean']()['optional'](),'cors':z[a0_0xc96691(0x398,'$Vfi')]([z['string'](),z[a0_0xc96691(0x27c,'yUR%')](z['string']())])[a0_0xc96691(0x223,'d)Ik')](),'protectHealth':z[a0_0xc96691(0x480,'!mXe')]()[a0_0xc96691(0x460,'ToP^')](),'allowSseQueryToken':z['boolean']()['optional'](),'timeout':z[a0_0xc96691(0x182,'N%Da')]()[a0_0xc96691(0x218,'vQ1Q')]()['min'](0x3e8)[a0_0xc96691(0x4b5,']cW@')](),'concurrency':z[a0_0xc96691(0x23d,'$W(9')]()[a0_0xc96691(0x284,']cW@')]()['min'](0x1)['optional'](),'env':z['record'](z['string']())[a0_0xc96691(0x260,'uX3F')](),'maxRestarts':z['number']()[a0_0xc96691(0x422,'DrN%')]()['min'](0x1)['optional'](),'restartWindowMs':z[a0_0xc96691(0x1ae,'8nSx')]()['int']()['min'](0x3e8)['optional'](),'maxQueueDepth':z['number']()[a0_0xc96691(0x38e,'30)t')]()['min'](0x1)[a0_0xc96691(0x302,'DrN%')](),'sessionTtlMs':z[a0_0xc96691(0x10d,'cH7W')]()['int']()['min'](0x3e8)[a0_0xc96691(0x370,'^lJJ')]()});function loadConfigFile(_0x4c290d){const _0x4bdffd=a0_0xc96691;if(!_0x4c290d)return{};const _0x2df72c=getLogger(),_0x3e071b=a0_0x166156[_0x4bdffd(0x39e,'GrlK')](process['cwd'](),_0x4c290d);if(!a0_0x53c141[_0x4bdffd(0x30e,'S!i)')](_0x3e071b))throw new Error('Config\x20file\x20not\x20found:\x20'+_0x3e071b);const _0x3fa760=a0_0x166156[_0x4bdffd(0x258,'%nTx')](_0x3e071b)[_0x4bdffd(0x159,'uX3F')](),_0x19e780=a0_0x53c141[_0x4bdffd(0x145,'JUp6')](_0x3e071b,'utf-8');let _0x180e96;try{if(_0x3fa760==='.yaml'||_0x3fa760==='.yml')_0x180e96=a0_0x46d989['load'](_0x19e780);else{if(_0x3fa760===_0x4bdffd(0x11e,'vQ1Q'))_0x180e96=JSON[_0x4bdffd(0x33c,'yUR%')](_0x19e780);else try{_0x180e96=a0_0x46d989['load'](_0x19e780);}catch{_0x180e96=JSON['parse'](_0x19e780);}}}catch(_0x5559ab){throw new Error(_0x4bdffd(0x294,'OeEa')+_0x3e071b+':\x20'+_0x5559ab[_0x4bdffd(0x276,'yO(Q')]);}const _0x5c0b82=ConfigFileSchema['safeParse'](_0x180e96);if(!_0x5c0b82['success']){const _0xb80792=_0x5c0b82['error']['issues']['map'](_0x52a248=>'\x20\x20'+_0x52a248[_0x4bdffd(0x1e3,'S!i)')]['join']('.')+':\x20'+_0x52a248['message'])[_0x4bdffd(0x33d,'V&f(')]('\x0a');throw new Error('Invalid\x20config\x20file\x20'+_0x3e071b+':\x0a'+_0xb80792);}const _0x50fba2={};return _0x50fba2['configPath']=_0x3e071b,_0x2df72c[_0x4bdffd(0x11f,'yL4y')](_0x50fba2,_0x4bdffd(0x1d8,'fR1R')),_0x5c0b82[_0x4bdffd(0x15c,'30)t')];}import a0_0x25ab99 from'crypto';var SENSITIVE_KEY_PATTERNS=[/token/i,/secret/i,/api[_-]?key/i,/password/i,/auth/i,/credential/i,/passwd/i,/private/i];function generateSecureToken(_0x40a012=0x20){const _0x2adcfa=a0_0xc96691;return a0_0x25ab99[_0x2adcfa(0x1e0,'30)t')](_0x40a012)['toString'](_0x2adcfa(0x4a8,'$W(9'));}function isSensitiveKey(_0x1bdf62){const _0xd3a4b3=a0_0xc96691;return SENSITIVE_KEY_PATTERNS['some'](_0x931ae7=>_0x931ae7[_0xd3a4b3(0x18e,'AmkZ')](_0x1bdf62));}function maskValue(_0x230136,_0x319924){if(isSensitiveKey(_0x230136))return'********';return _0x319924;}function a0_0x596f(){const _0x2bc0f5=['nxm+WRddRSkA','WPioW5uaW7FcOfT1CSoNcN8McSojW6PHohCDlSklwg/dImkOWRW','WQJdU8o4W784','gHddSfO','kNKxa3LtWRW/wCohcmo+WPhcTxq/WP9xWPDpW7ZdMvNcVJmRoCkmWP9wWQHoyc/cUgevjSo1WPjlWO/dJUkdMeDEdCkFBmk/wg5FW7ldP2/dSs8LWR7cH8oC','ctSFW6hdQKZdSmkXkSodt8kEWR4','jxuPWRJdTmky','wgfdWRC','wComlCoNFCktW5VdQ8kxoaDuWRy','W6JdUSotbCoqW7vXgJXDhCksW4SwymkzWRPjWOldKu8Ox8oAlCknshrHhcRdOSoxmtldIdlcV8oTDHKKrokFGW','WPJdPXa8wKaz','WR04gN58W40i','WOpdQCo/W7W4Fb1yAJJdGSk7kG53WOZdSCkCWP0d4Ow/WQG','jea3lColF8kvWR4emLe0bZNdO8kCjq','W5S5W6pdI8ki','zLhdQmo+W4tdPmkBWPhcLa','d8oMEg3dJW','zaxcHq','WRKUo2H8W44u','oxeVWRJdTCkrW6RdGG','W6LZa3fZW694','o2aJWOddR8kAW77dI8kKWPLaW4T6','W5LgWONdVSogEa','WPFdRHC+qfW','WQ0XW7qLrmkKFW3dU2NdQqPYW68','bbddRvvWW5/dKSoXWRtdOSkDm1e','aN8Bb3bnWRmH','h1hdVWi','W5S6W6VdH8kBW4n2','t8ogfmoNCmkd','ugC/W6vPWQ/cKM0','wHGXqh7cS8owAmkeaCknW68','m2tdNZmBW79tWQ48W49NtCkcW7JdId4WW4ddI8ooW6exW6TWbSkpWO0Br2HDWQZcQa','W507W7a','m28T','B8ouWO7dOcldQMScqSo2W4NdGIWTzG','vwLvWR3cUdZcRSk3lSoKxmkDWPZcVq','oCoZh3bQna','WQaVbM54W5KE','jmoGeMKM','yeNcPSomWRtcNWv7rCkGW4ONWPDLzSoQWOO0BCorWQi','wmksWQhdMWW+WRDhaJC','fSkHW7D5gITRWQ1UnK9Ib2dcSSo7W7O','rW00xhtcRSor','W4FdGYCaWP/cHSoNWQZcGaFdKqhcGq','pJZdTYO','C8obWONdUItdQW','W7ddNJuzWO7cMmo2W4hdIutcMb3cGH9JDmoGW7NcP8oTW6pcU0VdJSoTzSktaCoDW7apW74PwavMW4BdOCkiW5tcG8ogWQmdosLWWQHjr3bLW50sWOWKW4qwW4RdKNhdIqXwvW','CeBdRSocW4i','kSo2h3i','WOJcQ8oFW6tdQKldIsNdGSoBBCoJn8o1','kCkLW7WTnHPpW5L3kuvYfNlcRmkRW7SSv2WgWPyaB2KGueRdICkqkuWHoSk4rr3cPCoRo8kGW7C7D1ZcN8ktWPdcN8k6rSo7p8kZW4D3WRv9WOddSGa8omkTgSkNW6hcSW','vCoJW57dJW','nrhcJmoMW6RcPmkWWPNcU1JdMmkOWO9G','oSoMbx5XmSoECq','wXGZrNlcR8omfa','xCk9WRqGtqBdLeepWR83gJD6d8oFFGzfamkIWQVdRmoaWPenW5qHW5TcCL0NbCo2W7nDCa','fXRdRq','oeuZiCowz8kDWQe','cWtcKCoQW6tdT8kN','W5HcWP/dI8oxy8k5omoYkCks','W7BdISoZm8o6W5vgcfDpBCoWW54','AYHnW4NdL8onqr1fW6C','WRiJW6m/sSk0ErNdSa','W5hdJH89nMRcR8o8WRNcHCkQc8oJW4JdGmknWQzqlSo4W5XLoSkBf8kSW5mLDSoYD2LmstFdKamsWOu6omoPWPpcN8keWPxcTYatW7FdSqNcVSkrqx4fWOpcUt3dVCoPWOntrfdcT3HNF8oRFxm','iepdRHbiW7fDWRqeWPHfrSohW7xdLsGGWOxdK8ooW70eWR5+bmkpWPykqgSoW6ZdQq','zbNcGt8K','rZ1lW7xdGmojrHTt','dJ90','aCo2CSohWOmS','fInkWRpcQ1lcS8k8m8o1xSkBWO3cQHFdVfRcKq','W4hdVColcCoxW6y','WQdcGa9EW5RcIgG','umoNW4BdHmkoWRa','ygLgWQBcTGJcOmkGhCkHCCkmWO7dUwtcK3hcJXSQW6HMeCoWwL/dNb7cSmoNW6NdT8o3WOJcGIOa','WQRdV8oGW6K+EG','W4ztWOVdSmorDq','zvVdR8oz','qI1brIHgWP4lumkfca','mmoUax5SjCoRDmoDW7jR','W4hdGCoMW4BdUSkj','ySkJWQWKuq0','eH7dQLfoW6JdG8oWWRNdJSkC','m8oXfhm0rG','g8oSzW','8koXOZpcK8kLdgyPy8oaxmkyvmo/W4DBfYnFAf9gnCkwnCktW7i','W6afWRPl','pCknWQ56W4qLqHjhWPmqW4BcSLWItCk7WRvg','aWRdQvfUW7VdNSoXWQ/dSq','dgb0W60IW5CSCmkTp8o0zq','WOBcOCofW6ldOeu','WOzVb2zNWQe9','W58WW7i','pCk4emk1ha','W7LLd31O','qmkBWPXJW70','twTvWQhcUHdcRW','qmoSlCkrW6ddPCkwWRBdSxbDW4tcSJPNWOJdPJ8dW5uZatVcJmktW4qB','zuBdS8ozW5xdPSkBWQZcGLJcOcCL','WRKZd2i','jva0j8ovF8kz','CqtcGsq','DKpcOmoiWQ/cNW15aG','W5CLW7ldG8kvW4nH','W6/dUsbTdxVcQSoNWQldH8kSbCo6','zCkJWQ8MtrhdUWqZWRK/','W5BcPGO8r0DDWONdJf97WR5wErRdMLKd','A8o+lCksW6a','W4FdGYqrWP/cGa','rY5grYW','CW41rx7cSSouumkcc8kkW5FcLeDHW5DSj257n8k6BCkzWQZcR8oJWOVcTSoWWPFdT8ksh8kPbG','wYHlW4/dM8ogqq','kmkjWQr3W5vSeq','kmkuWRLG','aSoNFCoxWP8Xra','hKldUqXj','fv52zSo2tmodtdKsjCoCW6W','ovLJCmoWw8oysXupFCobW6W+WRdcVCog','dHJcNmoGW6/dOa','W5ncWPLpW43cKLaWuCo3hhK+lmosW7i+DG','WPtcGX5eW4BcJ3rqW53cKY3dUhuJWO7dR8kTmK9feSoWW5OfW7/cSx/dVCk4mHqmq27dNCoMdZFcGG0','wSogcG','hW/dRv1ZW6pdHa','W59mWO7dTW','swTuWQBcSG3cTCknkCoSwSkAWO3cUfRcSeC','bwWxgw9uWRi0Ca','lJBdTIRcI8ojWOvi','WQRdV8oRW6GKwqPyBtldGSkv','qwCSW6L+','qNWYW7jPWPa','gSoTymoh','DCocWQ/dPIxdQ2XbrG','eupdPa1jW6Hr','W7hdKdWlzNTMWRS','W7NdOZ5OigVcRG','agStaNLa','W4SHW6NdMSkYW4HZCCo+WOJdGa3cUG','vh5tWRVcVbe','W6JdVY5ZnM7cPmoNWQi','c2yTW6mJWPdcLh7cTmokWQ8bC3C','kSkJW7zIehL7WPzQoKn/uYy','nCkVfSkYavm','c0ldPabEW6TbW7CRW51NumoB','q3aQ','uSoRW4G','E0lcO8oCWQpcGHa3eCk6W4iWWO51ya','W5/dGCo7W5tdO8ke','WR04hx90W4KE','WRVdGCoQWR0DWP/dKmolW4VcOCkVWQyJyW3cGwDpz8otWORdP8owW7ZcT8kZuCkHWP0/BmoLisa9x3iZqx7dVglcNfJdGbL5iWNcQ8kHh8o7WQyTD8kM','W6BcSmoipNNcPmkbWR7cQG','i8oQbxi1','Dq7cIYr5WOeSWOxcNJCSjI9xWONcIg8','gbldGr3cSmoVWQvUD8k9','xSkuWRq','kmkxWQPGW5zWebO','W4ddGCoH','qtzDW4/dMSom','wKlcOCoAWQ/cNGPK','WO/dK8oSWR0wWPy','jmoKbh0','WQVdU8oSW6KnBXLcFa','otBdPYZcHq','calcMSoGW64','crpcJCo9W6ddTSkGWQlcV1tdLmk1W5SMnrfv','rSkgWQe','p1WPpa','W4zgWPtdQSoBF8kJkG','W4fmWQhdSmokDCkP','xq4L','WRuVg2jV','CCoSn8kp','aGRdTW','ortdSCoiW4tdRCkaWOddMG','ffOPpmoCz8kiW6a/oqeI','lIBdTtZcKmoqWOjis8kk','oK1HDmoVxG','Amo6k8ksW6ZdUmkoWPBdPG','W4blWPreW4m','WOlcQSosW6BdUKxdMd8','W5ehWQbaWR8knGeFjSo8W70eWRVcR+kcSeLDW6pcKK4+W5ZcTY0iW7zHWQdcImk1W51UFmo5','dmkRW7D5','WO7cQCoyW74','e38feK5bWQK0FCkQkq','gY4hW7ldS1/dRmkrymkJFSkCWO3cSvJcSL3dLqK7W7j6fSkLfd3dNaZcTSoJW7NcU8ohWRtcVX07sL90DviDeIO','wNXaWQe','WOhcRCkzx8knWQeLl3zslSk1WQW','xConzCorjJu1gfaRW6OIWRS','W6dcVmoep28','h8oHaNmXqGW0','gwvuxSolyCo9','l8kRc8kUc0uM','W4ydWOBdV8ogDCk/ECoKnmksC8oYW5ivWRuIlG','jCo3bgr7','W4blWPHbW5pcR0O7zW','WRC4hq','emo7yM0','lCoKce00vXW1F8kNWQpdR3i','oCkpWR9XW51VfG','cxe6WQtdQCkAW68','xtzzW4K','W5qWW6JdJCkoW4u','w8ocf8oUDSkt','W7X5cxfJW6HU','WQpcNXW','W5RdISoJW5ldU8kfW5mqW5VcHSobW7ldH27dLKLc','kNWehNHdWRGBjmkQgColW5lcRMGWWPLr','y8k+WRmQsG','W67dQdXPjgZcV8owWRNdKmkNea','qSkjWRFdKq','nw41WR/dV8kCW7/dI8keWR9FW4P8zW','d8ksmmo1','W5zbWPHbW5pcRW','wHGZqxRcSSowESkEeCkwW74','puyOjSolECkF','k8kpWQ99W58','WRxdU8oYWQeVAXHfEcxdHmkvjXH7WO7dOmkmWOPgWOK','cNDKW7y0W5q3u8kS','WQq1dgm','smkmWPPKW6bs','aM0tjxLhWRiOASkcoCoV','smonhmoRFCkt','xW8Pqx4','hCkunSo0WOm','ehiA','c8oGDxddHq','Aq7cKJqZWPyPWRtcMs5KoI5r','WRW0b2HFW58lvmkeFG','oeLJCmoJwq','W7HIc3DPW65PwJ4','WOVdOGK8','WQ3dV13dP8oN','WPddKCo3WRCCWOVdHG','DCoFWOK','oshdPddcJmo2WOrxsmk1WPy','cxiVWRddRSkkW7G','gSksnSoLWPlcNub/','WRNdV1hdTSoPDmkc','Bq7cNtCIWOW','WRFdQSo+W6uYybG','jmoJfgj7eCoAACocW756sW','c8oXyMRdG8o4fgS','W5VdIsaDWPJcNCoWWPRcNqddMGa','c8ohW7hcNL5OW7nqtwlcNtlcPZDMwt1PW6fly8oSdLGyC8kfwX4mxSkXWPBcL8osWOxcQSkgWPnEhCkEWPCAW43cSSoUE8ozW6JdHWW2W4bCpxS','o2aJW7ZdQmkAW7JdMSkbWO5eW4W/DG3dTSoQW6bna8o3','tulcVSomWRlcLa','pSk4dCk3','b8o2DCkl','WOJdVGK8rKjDWPxdJqa','W7JdRdT8','W6dcVmowl3FcO8kbWQtcSfdcONNcGmoRW5y','kSkVeCkUd0uHn8oWEmoTWRiHW4tcUa','CSoeWPddSs7dTW','W4zxWOpdSmoD','WONdKmokWQexWPBdNmo4WOW','sCkgWOK','FSoYmCkv','cSkfjmoYWOxcV1O','iSoKggn/pSotEmo1W7L9xvy','rZ1mW5xdNCohxdPuW68BAa','fmoJESoFWPm7','qulcS8oBWRlcKWf2eCkhW4y4WOrY','D8kmWP95W6PffSkxDf7cOmonWQOwx8k4W4NdQMGGWRpcGWuTx8kmja4','e2WzfNHhWRW1Ca','WQFdU1ldTW','WOBcPCojW5VdUKtdIcNdOSo9CSoImq','pmo4f3G','i8kJb8kMWOFcOKXSvmk4W5vty8ognwBcLdtcH8o2rSo3W4/dICkJW4pcKrFcQmkUsSkPWQu9f+kbVGtcOSo4WPaXbYhcQMpcN8oVxxFcO2hcP8knqtjsW6ddHSk2W5D8W5dcIq','d1NdPGzj','h1OWAmovzSksWQPlnb5NaYRdSSkAm8k9WPNcNHTGW4b7ASkvWRHUkCopWPWDW5pcK0ldO8kJWP4tzgxdMCoXeLPSgepcRCkhds/dUHtcJCoQvmkBW63dRc5RW6S8wmoe','FCoDW4xdJ8keWRdcTvm','W4ddGCoMW4ddVSkdW5L5W54','hSoMFNq','W7JdOIj8lha','rbiN','rrW4z37cS8owwmkdemkl','W6itWRrxWR4ndKa7e8oGW6meWQ0','qmkSiW','WQVdV8o5W780yqvc','WO85g2jTW5OivG','WR/dV03dOCoPDCkl','WQNdR8oVW7K4','iMG4WRO','wbW5wxtcOCog','CSk1qIHSa1H9c8o3','jXRcRa','cKxdRHzE','jSoZaMr3m8orvmou','vH3dVXfAW7TxW7C0W5T2','dwX/W70','W7DgWOBdQ8oxySoT','cCkzzmoogNaYbveNW6TTW69GW5L5c0HqW6JcVSo7W5xcHXWshCohsmoonmkfW7D/ASk1gc0GWOe/kSk2WQCrlSk8W540W5qsW6tdQZpcVCo5AdX4nqLlbCkXW4hdLIlcT8ozWRa+eH5um8omyL0uWPNdKJLaW6n4t2ldMSkkWQBdLwmSiW','W7xdVIbjlhpcRG','W48NW6/dNSkF','nfOYjSon','mIpdStdcJCoiWOPx','W5K/WPjXWO89jG','WRaJW7yVxCkrErddUN7dMqP2W79jEq','WP/dV8o+WQWKyr5dospdN8knBXmJWOZdSCotW45lWPNdVmoOmhzusx0mWQWVoXeioSk9WOvJW4lcMHtcHmoAqmkEA8ksvrvZz8oPWQxdN8oNWOjEWPzkCYnurHb4pSkQW5FcHIL3wLi','h8oJA8oHWPmRuxbRW50','WRZcRw89bgVcV8o9WRNdL8kGhSoVW5hdImkmWQXkjSoFWPDJzSoEr8oI','WP8dWP1pW4NcTqnPAmoTcN95','jblcJmoMW7hdTmkXWPi','W4SHW6FdNSkpW54','xa8Pwa','DmkPWQaHqq','WO7cSSouW6tdUW','yv3dSCoeW57dOSk8WOxcGvZcIsi4u8oN','W57dH8oL','jea3lColF8kvWR4emIiZeIZdOSkA','tCoYW5JdImkcWQRcMq','s8koWPXJW6rJemoB','kCkoWQ5HW5u','y8k6WQqRtfNcQq','eMPI','W5hdLduDWPdcPmo8WPFcHstdHG','lmoGhNS1wG','W7HGWRFcUCocySkIoSoLlSksmmoTW5KjWR0GnmkVW65VAmo3W5pdNcDXWQquWP3dOEkdQbhcHCkaWOldK8kBwmo8WPxdMmkxiSkzaCo+WOmmW7DWySkZWOO','WQW0W6WVtmkt','vSkDWOPLW6e','mIpdStdcJCoiWPG','WQuZc2rZW44','zh5oWRy','WR3cLrHyW5VcIh5DW7tdSbhdQgGK','CSk+WQaRsXpdPHmP','tSogcSokDSkwW63dQ8ku','m8oWahKZraaJvmkW','WRiYbMf4W4Sd','rZbwW4ddGa','vmkCWOT5W6O','W7/dT8ocdCoyWRjCe0HaFSkXWO4nEmkvWRWaWOVdKLuM','uhWZW6nJWPFcHvdcQa','CColB8osgJeMhMCMW7OTWRS','WQZdS8oNW6KYEX8','zq7cKsuX','W4hdJZKrWPhcGCoN','fSozW548WR8g','tSoxeCoYw8ksW6JdVmkslWDgWRy','oeLIymoNxSofAq8yjCox','C8k+WQ0','W7NdOZK','omoZbx9Xomom','W64tWQvrWQi','WOBdKCo3WRK','b8k6c8k+','WOtcTmofW6pdOe8','k8k+a8kOgN8WaCoRySoRWRG3W70','sapcVfipW7PXWPCnW5Pu','uComgq','WOVdPaST','hwPRW7SYW5yQrmk2oCo4','WO/dK8oSWR0wWPBdHG','WQZcNXvrW5ZcGq','ixvKW600W4e8','W51EWOfjW5xcRW','WOPLWRtcNmouWP0KlCk7W5VcLv0','W70xWRXrWQ8Dga','oCo5fG','bSokWR/dMqWNWRuzdddcKNJcUsTIuIe5WR4DnSkLwrGw','hJZdQY3cH8oiWP8wCmkbWPxcVW','f8kWW6bOcsSYWPvUnu8','WPtdUW0Ww1Ph','WQddTfZdVSo1FSkauW','W4tdLSo8W4FdSG','g3D3W7C1','WQmOgwHVW5WeqCkoFG','nYddQJC','W5PlWO0','WRNdQmoTW78','xNzxWRVcOrRcPq','W4LLb3bQW749CYHSAGuOix7cLHBcUSkwfa','oeLGyCoJx8ofsW','i8oQfhK','W6/dUd94n2JcOSoMWRNdL8kAemoVW5hdLmkq','bSofndDToComBSozW7H3sXjiaCoNF8o7WRe','y8k+WRm','WO3dKmk4W7WqWPZcIa','WPFdPb4','vM9FWOdcTGZcTCk4mSo1ta','gmoXFmoD','W5PtWPpdSmoDFSkSnq','cmoeWO1JW6fvf8ofy0pcVSohWQftb8o2WPu','oxeVWRJdTCkrW7G','WQRdTvVdTW','kpc/RRZcGConWPtcN25qW581b8kSWOXpWQhdRYTTWP/cQu3dUrpdO8oKyG4','W6PtWOBdRmobDCkP','W6GxWQzaWPGkh1m2cSo6','rbWIuhC','vaxcM8o6W7ldRCk7WPJcPq','fXRdT1fUW6ZdG8oNWQtdL8kaleFcJa','BbJdKYC+WO02WOxdKdj0mc5aWOG','W7ldUcj/igW','W4fmWRtdRCoaECkJpG','o1OG','oCo/hh5Q','W61hWOzZW5lcTfCHACoShK8Od8ot','WRCKW68N','BqRcKtu6','ASo8uSkpafSMoCox','B8ouWONdMY7dPgfkuW','WQi4gNL8W5GzzSkiyvFdTSkgaMNcQ8kV','W48KWOD6WOqOow4egmkXWR5qW6y','WO7cVmobW6pdVvJdQsxdI8o9Ca','WRZcNbjuW5a','EHGKj8ouzmkDWQmpye0KhJZcQq','r8oWW57dJSkF','WRRdQmoJW6G6AW','W4/dJSo7WQq','WPVdJcCBWPa','qha8W7nR','hgr2W70vW4eSu8kHf8oY','b8oaja','z1hdR8ozW5hdT8kBWPC','wu7cTG','dCkQW6jI','aWRdQvfUW7VdNSoXWQ/dSCk8m0pcLGJcSW','AbJcGcuZWPC','aMOxa2Lx','W6VdRczPa3hcUCohWRpdHmkThq','W4VdPmkrWQRcRWhcKatcHSk6qCo5n8o1W6RdOCksCIlcMCoPWQtdGSkFW5jbrMHbWRJdGK41W4mxW5GGWRFdK8oyr8omsW','emkocSoRFSksW6BdU8ksBv5kWReQ','wLpcOmoaWQJcLG','jblcJmoOW6JdQSk9WPJcSq','jwqOWQldS8kqW6xdNq','hmoLyCoCWP0kuwu','BaRcI30KWOePWPtcKtf1jNzaWPtcIMFcNCk8WRNdJW','sCo6kCkuW6ddPmkuW7/dPM1aW6NdOG1MW4hcSI8eW4rMaNRcG8kkW40t','ESkaWP1FW6DdfSodEeJcT8oGWRCevq','tSoTW4S','W5NdGZOtWORcNa','gXRdOeC','W5PtWPpdSmoDFSk+','W79Ke2bLW74','fLhdSZjoW71hWR8DW512qmok','xa8HvN7cJCobsq','c8oGCg3dN8oK','yh1cWQhcObBcRSk3hCkHBmkmWORcQL7cR1RcJXW9W7P7c8oVwW3dJu3cTSoJW6JdTmoWWPxcJYWqE3q','WRRdV0ZdOCoPDCkluW','nSkYo8koW7FdPmoaW6pdRw1gW77dUWzXW5xcVhbp','D0BdS8omW5tdPSkoWPFcKW','WR3dS1ldT8oVB8krBCoU','ov92qmoWqq','DZDrW4JdKColrGDpW60','vCoWW4xdLCki','crpcJSoMW7pdSa','s2uQW69JWOZcKhe','feddVWPuW7zb','v8kmWO9OW4LFdSosqL/cVSoh','W4FdT8oOp8o7W4fGnxv+oq','W4xdKYCC','zWlcNtqFWOO+WOxcIa','W7/cUmoDcxpcOSkbWPlcQ0RcTq','AmozWPJdVq','c8oGy3ddHmoW','hHJdQ1T3W4ZdGSo2WQJdT8kaleFcJa','W4ddRCorcCogW6r9nhnI','W4hdGCo4W5ZdO8kjWPPDW5NcG8kyW7tdLhpdKKC','od7dRc0','mmo4bW','W7GtWRzkWQqbdKi7bmoMW7SpWQS','e2r9W4KYW4eTrmkCp8oXDmkr','WQhdV17dOSouDCkrqCoX','reBcQSoTWQpcGrb/','uCogemoLz8kF','hmkvoCoOWP7cVKq','jwjKW6WIW5m5wmkfESomq8kPW5KDnL4PamoiW7ZcUu0WW6jbW4v3','k8kEWR9CW5v+bHjh','d1/dHWXmW71aWPK4W4TJ','B8ouWO7dOcldQMTC','hCkfjmo1WP7cV018','fSoJz8os','W5NdItm','W5XnWOhdTG','sxaTW7vTWOxcLa','WPpdL8o5WQamWOS','pmkVamkVcq','WPVcQ8odW74','rYXEW5ldGCoB','d1NdPGzuW61gWPCQ','r8kiWRy','vSkmWP1/W6zzdmo+DqBcOCorWR0bqSk4W5VdRNWUWQZcG1eSx8onpWvzW7lcVmo3WOju','WRRdV0ZdOCoPDCklACo5','eCo6D3y','W5RdISoZW5W','mFcCS6ZdSSoZkSkYWRGNW6qFWOZcGCk4wSkWwmoksgFdUgakW7mDrq','jwqVWPNdV8kEW6/dI8ks','WRe5W7mKsW','qmkeWOD4','wColy8ovcW','xxXiWR8','WQ3dU0VdSW','fmkTW6a','hM4chNnkWQ4','W6fUfwfNW7X4','WO7dVX9H','ochdTZBcKa','WRRcGHC','nCoXfIq','iCoPhhm2yrO1ASk3WRBdQwpdRfxdUJmm','WQi4cgLKW70mw8kvAuddTG','WRuLahK','nSo5hhP/mSoB','W79Nd3fJ','rNqTW6nEWOFcHw/cOSoPWRi','BmkhWPPPW71ya8oBmupcOSowWRCb','ya/cLYi','iNm6WR/dQCkpW6tdNmku','rJ1vW4pdL8oC','r1lcV8olWQpcGW','WRaJW7yVxCkrErddUN4','xuJcM8o6WONcOHbLdmk9W4G','WPtdJmoEWR0bWP3dKq','gXRdVeqXW6ZdM8oRWRBdPG','nmoKfMq','W4hdGCo/W5BdTmky','ketdQHfpW7fCWR15W7vfzmkcW6FdLd0HW5FdK8ooW7WFWRKXrSkb','oLa0o8oyBSkz','cmoMFNRdJ8oKctulWQmMW67dKq','k3/dMdCBWRDFWRKP','WQtdRWS4xvPDWOJdHq','WPtdHSoRWQa','xCoCECosbZ86gq','W6ZdQd1WjhdcRSo7WQldICkWrmoOW4tdImkpWQCu','AYPAW5xdGmojqbPJW6WJDCoR','dMXH','cSkpbmoJWPNcThfUrSkzW4mcFSocnti','A8o2pa','cvxdUbDAW6PgWPK2W41Oqa','sSocdmoS','ACo6k8koW6NdOCkf','tg9vWRW','W5HgWPtdQSotD8kO','wbW0xq','nmoShxKUrX0Dsa','o8kLbSk/','thOTW7i','bMWFa31gWReJqCkjpSo+WPy','EfhdR8oEW5hdOSkk','g8o7y2RdPCoLe38rWRK0','EvVdUW','kCo2iMKVxaa+xa','wmktWQpdLXaVWRDsfa','B8oWeCkYW4RdHmkuWQ3dQ3fi','WRFdQSo+W6uYyaPD','W4ddSmoicSoa','eqxcKCoN','W4FdLSo0W53dPmkCW5HcW44','tuBcPSoi','smkgWQxdNry','jCo/fq','WOJdRG0kqfvaWPpdKq','sXiUw37cO8owxmkv','rGGTv37cSG','nd3dOZy','wLlcSCokWQpcGHC','rCkiWQy','qI5grYWu','hrRdRvXZW6K','CfabvNJcPCoofmkZeCkEW6ZdKwz4W5H8','w8oxySoedZWGaL0','jSoIegnRlW','qSkjWRldKGSSWRTh','b8k5fSk7gKiM','CW41rx7cSSouumkcc8kkW5FcLeDyW7fpdfvyCmo8qCkZWPddQSo3W5xdUCo1WP3dTSkcwmoPt8oWW6KfWPtdV8k6WQfQ','ACo6kmkeW6tdOW','WR3dTmoU','o8ktmSkMWOpcUeyVqSkUW5uaySoika/cGhhcH8o+u8oSW5JdICkYW4VdIf7cOmoVv8kTWQv5xGrnWQBdVCkupfrRW7LIWP/cVeP5WR97W6lcML0YfSkNW4lcTmoxzCof','gf/dPqboW6PaWR83W5T/','WRaZW7icsSkgDaBdPW','bIddOcRcKCopWOrvECoyWRhcQmk/WPGZWPiDD8odrmk4WP3cMupcMSoygWlIGyBdQ8kOWORdUbFdJutcOCkVENDkxZNcV8okxueTz3tcUfOYWQNdS0PDqfZdVSkc','kSkEWQH7W55XbXrbWPi','tcJcO3aMWPy1WOpcLtbYDtjwW4ZcH23cJmo4WR3dNCorjmk0bCkNWOyNgmkSh0agf8oxWOtdTuSKWPddNmkAW645FmoBWPVdRYK','WOmPchL0W4LnFmkgFL3dRSosb2VcTSk9p8kGkvfqugaOgdzDW4VdO8kBudldLmoIW459u8kTxmoeW5NdNMrjjmk4WR5i','jmoGfNuVvZKIvmkYWRBdQw7dGq','nCo3ha','4P+C77MAWQBcISoAW6v3ySoMWP7dJuZcJvSFjmkzoL7cSmo0WQP6WObKjc8C','nwaVWRldSG','l8o1bhuUxaG8','mCkvWQ17','WQVdS8oTW6i8yG','i0jWECo3sCousW','W4xdLdSqWOVcL8oNWPlcHGC','W6KzWRTgWR8DguqHjmoW','W7TeWPxdTSozmmkPnSoTpmkiFG','sKJcOmoAWONcGW1Wdmk9W5W','iSoKa3KtvX0IqSkpWQa','W7OFWRe','vhW6','oSo0g3j9ka','k8oDvLddPmod','W6/dQdXUlhhcPCoM','W6JdVY5+ifpcQmoL','W5hdLSo8W5FdSmkj','fHFcHSoBW6tdT8kGWPFcPe3dGG','W7/dI8o0W5FdSSkiWPDtW5xcNCotW7pdLchdM0vaoa','aSo3gxGMv0KJu8k3WQFdR3pdLL3cStinWQyX','yv3dSCoiW4i','B8kIWQCQ','W6bKaq','W6OWW6ZdJ8kzW5L3z8kQWPJdGb3cU1yjm8oiibpdUCkNW7KZW44Jje5jtCk1oSkHEIrMW5CqBNnJCSkNimoVndu','nw42WRZdU8krW68','f8o6ESoh','amoJFCoxWPKYyxbsW4Tl','WQRcNG0','nCkyWRTbW4jZ','WOVdQG0X','W5ZcQXaQffvyWPtdHXnRWRmAmeJcL19oWQ3cI8ohW4tcUCkKpsCnWR0lW5HDv28kD0TYwZT3iCoPWPefbmoUWRpcUL4lchVcGxSOWQpcJmkfhKZcGX7dHmkabG8xWOFdG0FdLmoFb8oGm8kaW7G','W5W6W4/dHmktW5L7ySoMWOpdNWK','WQiMW7y','cSkRW7m','W607W6FdN8koW4v9CCoJWPddGaG','x8kvWRddNrSfWR1e','o1L2ymoN','CmkhWO95W7TEdCofEfZcTCoa','wmkeWRNdMXO9WRjrpYdcLwtcRdz9','n8oKghn5oq','a8kdj8kRWOtcPej7rmk4','rYXnW4/dMSopwWHz','W57dGCo4W5ZdPCkvW6jdW5VcLmoq','b8kRW6PJhJPRWPXJ','WPiVagL6W49nqCkjEuBdSCkBdwpdU8k4oCk5zW','kun9DSo3x8odxrqEkq','mCobW5hcS2BcQhvau8oWWOZcNZy9BYNcVf44','smkiWPzEW6PffSowy1lcOW','FSkyWPTPW7Ptp8kxv0RcPCoxWRaAvCo/WOVdRMiJW6hcL1aSwmkikubAW6lcPmoWWOjdW7aJ','WQVdV8o+','WRNdVmoagmovWQG0','WORdTvhdPSoLDmkrdCojjmoQWRi','zuBdS8ooW5xdTSkCW4NcGKhcPsC','qeNcSCofWRpcLqfK','E2C7W7v4WOpcG2NcMmolWRqkza','kCoRfNm','W7ddHCo2W5VdSSobW7rFW5tcH8ohW7xdNW','xmoCA8offWC1a1aSW70W','tSoRW4ldHmkVWRhcJgPzW4q','CColW6VdQmkJWPa','kCoRba','W6VdRd1Z','uCo2W43dK8kz','uwWtbMLbWQ4YDW','W4ldJYyrWQ3cGCoJWP7cMX/dNb3cMqLpBCkLWRxcVCoU','4OsEkYTrvG','W74dWRTlWQ8ds0aJnCoSW68fWQBcR8owdfJdV8khxd7dNmk7jW','W7hdRdDpig3cV8o0WQtdKCk6','n8kbW5DEmHzrWQzca3PyiutcMW','oLq/gSoCFCkoWRqMmW','CSowWO/dVcddKhDd','W7e7W7ddI8kwW4r2i8o6WOxdLXJdTbm','xSolzCovatm7bNiSW70WWQzcW5y','pK4IpLnQWO4','n/c3QP/VUO0ZW5FcQCoCWOm+c0VcQ3hdPNnhva','WPNcOCocW7/dO1u','EaiJ','qCkgWR1PW6fsmmowzNtcTCovWQ0wsmoS','mmoGfhLQzSkFBSovW6vVxuaghSoGECoQWRhcOCkmWP0JmCoLbSkvb8kd','iCoWbhqUqaaQwSk2WRRdThq','ohq3WR0','zaBcMIq','W5ZdIca','vMyT','x0lcOmoAWQ/cNGO','vgCXW6vPWPhcGG','W4FdGYCBWPlcGSo2WRJcHGtdMa/cMb8','r8oVW4xdLq','gHRcKSoMW7BdL8kNWPpcH0ZdLmk0W5ytnWPdW4u','WRZcMrXzW5tcIG','faBcISoGW67dQSk1WPO','j1WJ','EmoEWPddSIldQW','DmoVlmkiW6RdUCkbWRm','umocbSkVyCksW7RdUSkhpXzuW69XW7bZrWVdHmoAW5m','WO3cQmoeW7NdP2NdMc3dGSo9CmoL','eG3dTLv4W67dLSoXWRtdKmkAn0FcKaVcQtSHW6bTxmo9W5GaW6y','sCkmWObRW7TE','dmo7ENZdHa','DCk4WQaXxq','fhzQW7y','lZBdTI3cG8ouWP94s8knWOVcRG','W5e7W7BdN8ko','W7NdVZ1YnW','qdDSW5ldHSobxaK','WReZW6WVtmkt','q8oCECosdZCX','WQJcQ8oFW6NdULpdJYNdImo7E8k2nmo0W7ZdU8ogprpdGmo4WRxdMmotW5zqrxaiW6RcJq','rdLnW4FdMCoB','EmoQqSo6p0iWfCo8nSoTWRGMW73cO3W5W6Sbdg1sixHdWRD2','WQyKW7qLxq','ceu1j8oABmkpWR4oja','rZffW4m','zdDnW5lcLa','WQmPch9P','W6bQbhDQ','W4FdGZuhWPhcMG','WQRdU0VdSCoO','4P2pddnNW6DaW55mh1a9W5hdQhlcQSkVW4FdVWxcPSkHW7OEWPtdOCkKW7r2xrZcNW','W5XBWPHcW5/cSW','WR8ThwrYW4qE','tSkvWQpdKqW','a8k5b8kPhv46dSoenSoAWRGLW7RcOIL3W6Tfst4gCZCAW7iY','W7uwW5BcISkiW4HJDSoVWPNdKuZcULOxiSkDDqRcSmk1W6WUW4u2ja','jMG1WR7cT8kpW7NdI8kuWOHj','n8k6fSkZavK','iCk2W7zIcxL8WPvOken/fchcKCoSW7SMtZGtWPeAiw04','tLpdVCozW5xdSSkoWP3cUHNcGraDeSo4ECoBDSk4zxG+W7LeW4iGWO5yjfNcJCo+c8oNW53cQCkWA8oS','WR3dQmo4','W7SdWRbqWQ8','lshdQJRcH8ovWPG','fCk4WPS0W5j+arXqWO8BWPtdJvyIt8k7W6ykpYNdOfK','qeNcTmog','WRRdRK3dU8oUFq','zSkKWOhcNG46WRfxcdBcLtdcQdXGqYP9WQiCn8kRraznmSoDhbmebCkR4OkZWPVcGSknWR7cH8kEqG3cNmoAuCovWRhcOxxdJ8oNW5KamCogfYu4','bwWlWPdcHmoAqZHQW6aX','tCkgWP14','kSkVqmowWOuSsMziWOnXWQW','c1/dVa','hxDGW7KZW4e8ymkS','WReZW7u+tSkvzdFdVghdRW1JW6PrESkK','WR3dQf7dVmoZASkkuSoP','cfxdUbbsW7DCWPm9','uxS1W6HJWPxcNW','W7pdRYv4jMO','WR7dU1BdPSogDCkxCSo4pmo+WQ4','W50TW7ldHmkBW4b3','CSoEW5ddScRdPM1k','qCkgWQDIW6zcc8owFu/cQSob','c8k0W7bKfdDS','hHJcMSo6W5BdRCkGWP4','AmoRkSkiW6VdSmkjWRNdUW','WOmtW5dcOmkdiCkll8oWk8kWxW','WRhdQCoAW60OFq5v','feddVWPuW7ztWRy','WObNWR/cMmojWP8MDCoaWP3dVcNcUG','wHGZwNFcTSoh','kCoRe3a0vGWJ','W4SHW7tdG8kuW4P7zCoZ','ghaqga','WQlcKqm','uSoRW4JcJCkfWQVcMxHsW5C7qG','W5VdIxKxWP/cL8o7WP4','WQxdSCokWOS3WR/dP8ozWQdcRmo7W7vZ','W4fAWPf0W5pcReytDCoSgN8Uf8otW6O','WO7cTSodW6xdVq','jxu/WRtdQmkn','mmoaruNcISoWg2WDWQaMW6xcHCkVlLekoSkR','W5ldTSkjWRJcVXJcIXNdQCoXr8ovkq','WQ3dTmoOW6uZAG','mwqV','j0LGzSoJsSou','W5VdI8oMW4C','W7f4WRy','h1xdPWzpW70','nCkyWRS5W5z+cXTqWOu','nCkVeCkPd1aW','cSkJW7zIebPWWPDPpKLLfMu','leBcKJW6WOSTW43cGZbKEcPqWONcM3VdLCkSWRpdGmoviW','W4blWPzpW5tcR0y2DmoX','kX3dQ114W6RdKSoFW6ddJSkSfWlcIXpcQtWNW7nsqCoMW4LvW6CyW6VdTmkuWRBcRCkFbtfYWOjfvsDpCq','W77cTSoc','WRNdQmo4W60K','bMKoWP/cGCkqbLHjW6CVESowWOG','bCkOW6HIddX7WRfIoK50axi','jee1iCoxBSkvWQSs','ovHYyCo3xG','uSowWO/dVcdcPxfAt8oQW4NdJ3GRBItcQKLI','vgCXW7jPWOhcHvxcVSofWQ0qEa','W4FdGZuqWOFcO8oYWPlcNqZdHX0','W5XnWPm','vfJdRGjxW6XA','jwqOWQldS8kqW6xcG8ksWPLtW5b8FrddTSo7W6bn','aSoRy8ow','WPxdJCoZWROwWO/dMW','W5BdTCoiga','W73dNKS','g2aJW7hdUmkkW63dImkfWO5vW5SYyrddPmo6W6bAeSoGW7FcLenwWOrlWODfW5NcTuDnW4RcTmooW7S1BCkpFWSwW5BdV8klzmoTBhldT8k0tuVcMW','W68eWQDkWRG','kSkEWRHGW5fTfJrAWPqrW4a','BCkOhx05hXGLxSk3WRBcTN7dNuRdPt5cW60XWPm','ESoyWPpdTWldQ2fkwq','egWrba','wmkcWQldJrCNWRazcsZcLxpcOIPNuIXTW6Cn','eupdPa0','ibtcJmoGW6xdO8kXWQVdTNtdSSkwWO80lavjW57dGCodw0zVW7fKW7xcH8ocEHSnDCkYma','kmkbpSoQWPlcTan7xSoRW5ysECoui2BcHZ7cM8o9tSo+WORdGCk+W4pcJrC','BmoqWONdUW','oCkjWQXN','m13dGWu4WOGPWRNcVG','qcPEW4JdH8oyxrXu','ocVdTtdcKmod','WQCVahL4','gf/dRWy','axCgeG','smovF8osbHGXc0aSW70W','A8kPWRi2wqtdRa','pmoLyCoCWP1/v3XiW4bDWOqBW7pdMLTmyrmHda5WW5i','W4blWOzuW5VcS1CbACoVhhGZgCoqW6KO','dgb2W7CRW5i9','W6KxWQfgWQi','pmkEWQXMW5f7bXm','W5e7W6ddHq','W4ddRmoagmor','W5hdItKvWPFcMG','lIFdQINcQSodWOPjumkAWOdcU8kQ','EfxdPmo8W4xdOmkAWOhcO1ZcVcCL','WPxdRaS2x3bBWOVdGXTH','W7FcT8obkehcUmkbWPS','Dmk5WQ8Ruq3dRG','WRtcRCocW5NdP1tdItJdJ8o2zCosnSo2W6e','WPBdQGeDuuraWO4','x2fkWRpcUHe','kmkoWRH8','W4NcU0TVgGqcW4JcK0m/W7S','eCoTFSoEWPCXrW','eL7dRqW','W4ddTmoid8or','C8k4WQD9','z8kgWQldILmnWQHraZhdI1NcIq','WQVdV17dOmoLAmkXt8o2omo0','a8kCWQPGW5vOaW5OW4eSW6FdVrG3s8k7W6evlItdVKG2csuxWQDnzMRIGQtdVSk3v8kmWR/dOJVcNmkkAGxdLCksxbFdNSkzWPm','q8onoCoHWOxcV0GIvCkKW4SsySojzNRcGd7cMmo6tSo3WPq','s8kpWPfLsXBdUqqVWQWVhd17w8kAzbTnf8kJW6/cO8ogWPfmW5CSWOGo','wd1rW4hdGmoa','nw41WR/dV8kCW7/dI8ke','WQ3dQSo+W6uWAW','WPJcOCocW7NdPK7dKZ8','shaWW6f4WOO','dfhdUq0','o2qVWRNdTCkB','oL58DSoNxSocxr4','aWVdUeb5','d3bGW60I','CGpcHIqYWOSTWO4','pmo4eNTRomoABG','WPeZW7uJq8koDq3dTMNcQH14W6vAy8kW','wdflW4pdHSojxG','wKVcU8okWQm','umogdCoXCSkqW6ZdImkjpW9gWRy','tSkvWQm','v8kmWP14W65efSo0FLpcVSoq','rrW4ggNcPCortCkqfSkmW7NcMxfPW5v+lgnWna','xComESoehcy9guS7','FCoDWPe','W7OxWQfn','smklWRtdNXaTWRO','WOtcTmofW6pdOe/dJG','WOtdGSoSWRu','WPGLW7m6sSkvzGRdPMpdUcm3W4z/wSo3f8kUW6FdHmoUW5FcPmoXcmoCWO8FtNJdJ8kjxXfOCCo+pSo3yei','wsSw','WO/cRCocW6NdOe/dKYNdHCoSz8oY','pJZdQdtcG8oiWO8','mZZdSxNcKmotWOvvtCkwWOi','gGZdTLO','uCo2W57dImkdWQpcG2Pf','oSoMbx5XmSom','nCkZeSofWQlcGMPBAmkwWOyGASori2BcKdNcNmoOb8oTW4xdJmkYW4hdIrFcL8kGvSoIWQW1fWrbWRFdSmovoqbKW75+W5RdV0z4WR9WW6tcJqKLf8oQW4JcTSoxk8osWPWHt8oZWRmDptq','WOtcTmofW6pdOe/dNca','WRmXbN54','phi0WR8','nmksWQz9W4r6ea','w8oqzW','trmK','W77dOITK','qCojFSoiat4N','WRxdU8o4W6CpAWPvya','Cb7cLIuZ','hGRdTfz5W78','zCkJWRqRta','W6jTwZSZWPPBhmoqpqlcTa','bq3dTq','DCk4WQaXtra','vCoRW4ldHCkcWRpcP38','WOxcO8odW6xdPgldKIldImo9yCoIpmoL','nCkRgSkic0qHaCoRySo6','W4NcQSoakgxcUmkAWP3cHb7cHgtcMmohW4hdNthdTapdQmofWRxcSWGSWRjRWPe','WOWrW5/cQ8kckCo7dmopnmkKu8oT','WOFcOCoFW63dU0K','wmoCEmosbZ86','jeeOomojBmky','qcPwW4S','hb7dU1fW','FCodWPRdOa','WOpdQCoVW78UzWrFrhFdKSkpzbKRW4tcPCkkWO9pWOhdRCo8yYOufdKyWReSnXeEjSo5W5HOW5BcMXlcGmkA','W4pdGCo7W5FdVSkcW5a','u8o3W4NdLmki','l8kYWR1jW4XJmmo+rx/cJCkeWPyCg8o6W47dRNWQWRpdHLeMrSkii0byW7xcUSoZWO5uW6e0WQVIGz9hWO9LBgpcKKRdG8o4aGxdGYhdLI4KlMZdPCoaW5xdOxBdHaDzWRS/oG','qYPwW5ldLCokxGTLW60YFSo7','nrNdNSoeW4ldLmo0WPxcUvtdNmkNW4eJEbjwW47dLSkqhufLW7TNWP/cGCo+urTmmCkViv4yfmkFxxZdUmo4hKfJymkgWQmWw1pdMYv0rctdUSo4','u3qSW6G','bgu7W7qS','uSojuq','W4DaWPXpW5q','lmktWQ56','bSkTW6PP','C8obWONdUItdQ2rd','W5bvWOldT8ogkSoTnmoJlComy8oPW50pWQuYumkUW6fVzCk0W5m','e8k6WPtdQCkJWQRcP0ni','EmoBW6S0W6n6eqrCWO4rWPtdRgWpa8o6WQ9gFMVcRbW2sMLy','fCkXW6f4hG','cetdQGbq','wCkcWQddIXS7WQPLgcdcK3u','DmoXc8kvW6hdUmkvWQVdHN5BW7G','FCoXW5JdGmkzWRhcMq','fvFdUqXqW5TDWRq3W51LqmohW7a','lJBdTIRcI8ojWOvVumkuWQJcQq','WP8dWPzpW5tcP0OYimk+cwOZemkd','WP7dSXaQqeDNWP/dJbe','W5e7W6xdHSkpW4L3Ca','faBcISoGW67dQG','BHVcHZK5WOOP','FSkyWPTPW7Ptp8kxvvtcSConWRzts8o5W57dVgSRW6hcI0WTamkliqLpW6/cOq','dHJcLSoSW6ddQmkGWP7cRW','hbpcIG','W6ldNrLsW5tcLh5mWQ3dHXhdTMm+W4FcVmk3FufydmkN','n8klWR99W59Xeq','WQJdOWWTufTdWOJcGHfGWQDknupdG08D4P+B','kCkHWQi1','jb/cJCoAW6NdSCkGWOlcV1FdLSkcW4aWnG','C8kIWQmSvGC','rSkfWODPW6fck8ozD0K','W5q0W6tdJ8kw','zb3cLJ4IW556WOpcNY1VmdHrWONcJqJcNmk5WQJdISkkBq','phxdN0muW6TbWR92W4PJv8onW7RdJYGNW5hcMSouW6OdWRH2b8obWQWldIqoW6FcUq','ymkMqq','CqRcHZG','Amo6lmkPW6ddTSkeWRRdSa','mCk5i8k2b0eW','W5brWPxdTSoa','o8kLdmk0c1qHbCo9','F0FdS8odW4ldTCkm','cvxdQaXvW7zxWRKTW7TPqComW6a','FCoYW43dLmkEWQhcJG','W6ytWRTcWR4h','jKaIoSoa','tfxcOmogWRq','W5tdUaO8','ymoEEmoobxa1h1aHW6OTWRTeW5TZgGfmW7pdRmoQWPRcLryj','WOZdHSo2WRmnWPa','W4ddKmoXW5RdUa','fmkLW7bL','rwC5W7u','mdldVq','lCoYESox','s8kgWPPLW6LFaCowzu/cV8okWQTCuSo2W4ldU2CUWQ3cJ18Ssq','W4DgWOBdVCoEECkJpa','tSoXoCkuW7hdV8kpWQ3dQ2vkW70','WONcTSoyW67dQeq','F8o+lmka','ltBdQZ3cI8oiWOW','mCkvWQH4W4v7bWq'];a0_0x596f=function(){return _0x2bc0f5;};return a0_0x596f();}function parseEnvVars(_0x589b35){const _0x1d5f9e=a0_0xc96691,_0x411688={};for(const _0x462897 of _0x589b35){const _0x32f173=_0x462897['indexOf']('=');if(_0x32f173===-0x1){const _0x1dd06d=_0x462897[_0x1d5f9e(0x2f3,'8iXp')]();if(_0x1dd06d)_0x411688[_0x1dd06d]='';continue;}const _0x2fab14=_0x462897[_0x1d5f9e(0x2c8,'N%Da')](0x0,_0x32f173)[_0x1d5f9e(0x469,'8nSx')]();let _0x5a70fe=_0x462897[_0x1d5f9e(0x17c,'$Vfi')](_0x32f173+0x1);if(!_0x2fab14)continue;(_0x5a70fe['startsWith']('\x22')&&_0x5a70fe[_0x1d5f9e(0x25c,'XE3M')]('\x22')||_0x5a70fe['startsWith']('\x27')&&_0x5a70fe[_0x1d5f9e(0x2aa,'A^&K')]('\x27'))&&(_0x5a70fe=_0x5a70fe['slice'](0x1,-0x1)),_0x411688[_0x2fab14]=_0x5a70fe;}return _0x411688;}function buildMaskedEnvLog(_0xb2c0fa){const _0x3cd89a={};for(const [_0x14cb42,_0x2e4749]of Object['entries'](_0xb2c0fa)){_0x3cd89a[_0x14cb42]=maskValue(_0x14cb42,_0x2e4749);}return _0x3cd89a;}function splitCommand(_0x5c784f){const _0x4fbb70=a0_0xc96691,_0x21cad2=[];let _0x4ef61a='',_0x2a10f7=![],_0x241be4=![],_0x39245a=0x0;while(_0x39245a<_0x5c784f[_0x4fbb70(0x351,'S!i)')]){const _0xa0517e=_0x5c784f[_0x39245a];if(_0xa0517e==='\x5c'&&!_0x2a10f7&&_0x39245a+0x1<_0x5c784f['length'])_0x39245a++,_0x4ef61a+=_0x5c784f[_0x39245a]??'';else{if(_0xa0517e==='\x27'&&!_0x241be4)_0x2a10f7=!_0x2a10f7;else{if(_0xa0517e==='\x22'&&!_0x2a10f7)_0x241be4=!_0x241be4;else _0xa0517e==='\x20'&&!_0x2a10f7&&!_0x241be4?_0x4ef61a['length']>0x0&&(_0x21cad2['push'](_0x4ef61a),_0x4ef61a=''):_0x4ef61a+=_0xa0517e;}}_0x39245a++;}return _0x4ef61a['length']>0x0&&_0x21cad2[_0x4fbb70(0x2af,'!)DA')](_0x4ef61a),_0x21cad2;}function sleep(_0xc2af95){return new Promise(_0x40cced=>setTimeout(_0x40cced,_0xc2af95));}init_logger();import{EventEmitter as a0_0x311af2}from'events';import{z as a0_0x307087}from'zod';init_logger();import{EventEmitter}from'events';import a0_0x396568 from'cross-spawn';import a0_0x4e76c7 from'tree-kill';var McpSupervisor=class extends EventEmitter{[a0_0xc96691(0x3aa,'!)DA')]=null;[a0_0xc96691(0x41c,'!mXe')]='';[a0_0xc96691(0x498,'AmkZ')];['_status']='starting';['_pid'];['_restartCount']=0x0;['_totalRestarts']=0x0;['_isShuttingDown']=![];[a0_0xc96691(0x2a0,'$W(9')]=[];[a0_0xc96691(0x179,'!mXe')]=[];constructor(_0x1640ca){const _0x4fcc28=a0_0xc96691;super();const _0x396263={};_0x396263[_0x4fcc28(0x41a,'Rq!U')]=_0x1640ca[_0x4fcc28(0x3dc,'XE3M')]??'',_0x396263['command']=_0x1640ca['command']??'',_0x396263[_0x4fcc28(0x2f5,'DrN%')]=_0x1640ca['args']??[],_0x396263[_0x4fcc28(0x35c,'7@1%')]=_0x1640ca['env']??{},_0x396263[_0x4fcc28(0x149,'A^&K')]=_0x1640ca[_0x4fcc28(0x209,'cH7W')]??0xa,_0x396263['restartWindowMs']=_0x1640ca[_0x4fcc28(0x434,'yO(Q')]??0xea60,_0x396263[_0x4fcc28(0x1cf,'QX29')]=_0x1640ca[_0x4fcc28(0x4bb,'4TBd')]??0x1f4,_0x396263[_0x4fcc28(0x20b,'GrlK')]=_0x1640ca['maxRetryMs']??0x7530,_0x396263['traceMcp']=_0x1640ca['traceMcp']??![],this['options']=_0x396263;}get['status'](){const _0x44d6cf=a0_0xc96691;return this[_0x44d6cf(0x1b8,'yO(Q')];}get[a0_0xc96691(0x1d0,'4TBd')](){const _0x16fcec=a0_0xc96691;return this[_0x16fcec(0x491,'yO(Q')];}get['isReady'](){const _0x232721=a0_0xc96691;return this['_status']===_0x232721(0x3eb,'$W(9');}get['restartCount'](){const _0x5bc010=a0_0xc96691;return this[_0x5bc010(0x485,'gOga')];}get['totalRestarts'](){return this['_totalRestarts'];}get['process_ref'](){const _0x1fa02b=a0_0xc96691;return this[_0x1fa02b(0x248,'ToP^')];}[a0_0xc96691(0x349,'@QVa')](_0x3ca4fa){const _0x427f6c=a0_0xc96691,_0x57d5da=this['_status'];if(_0x57d5da===_0x3ca4fa)return;this['_status']=_0x3ca4fa;const _0x5dec5c=getLogger(),_0x5584a8={};_0x5584a8['prev']=_0x57d5da,_0x5584a8['next']=_0x3ca4fa,_0x5584a8['pid']=this[_0x427f6c(0x47b,'eONb')],_0x5584a8[_0x427f6c(0x122,'@QVa')]=this[_0x427f6c(0x3ae,'ZiR@')],_0x5dec5c['info'](_0x5584a8,_0x427f6c(0x346,'yUR%')+_0x3ca4fa),this['emit']('status',_0x3ca4fa,_0x57d5da);if(_0x3ca4fa===_0x427f6c(0x3f5,'A^&K')){const _0x573011=this['readyWaiters']['splice'](0x0);for(const _0x5c82d9 of _0x573011)_0x5c82d9[_0x427f6c(0x197,'d)Ik')]();}if(_0x3ca4fa==='failed'||_0x3ca4fa==='stopped'){const _0x1fcec5=this[_0x427f6c(0x3b9,'yUR%')]['splice'](0x0),_0x1ae5f5=new Error(_0x427f6c(0x2b9,'k6M)')+_0x3ca4fa);for(const _0x440489 of _0x1fcec5)_0x440489[_0x427f6c(0x385,'yUR%')](_0x1ae5f5);}}[a0_0xc96691(0x257,'^N!&')](_0x41ddef=0x1d4c0){const _0x50fa31=a0_0xc96691;if(this[_0x50fa31(0x424,'7@1%')]==='ready')return Promise['resolve']();if(this['_status']===_0x50fa31(0x403,'2Voh')||this['_status']==='stopped')return Promise['reject'](new Error('MCP\x20supervisor\x20is\x20in\x20state:\x20'+this[_0x50fa31(0x30a,'&nMv')]));return new Promise((_0x1e5035,_0x53e70c)=>{const _0x332997=setTimeout(()=>{const _0x1fbcfb=a0_0x545e,_0x50b3c9=this[_0x1fbcfb(0x283,'vQ1Q')][_0x1fbcfb(0x148,'Jt&d')](_0x52b8b2=>_0x52b8b2[_0x1fbcfb(0x39e,'GrlK')]===_0x1e5035);if(_0x50b3c9!==-0x1)this[_0x1fbcfb(0x1ff,'gOga')][_0x1fbcfb(0x386,']cW@')](_0x50b3c9,0x1);_0x53e70c(new Error('Timed\x20out\x20waiting\x20for\x20MCP\x20supervisor\x20to\x20become\x20ready\x20('+_0x41ddef+_0x1fbcfb(0x2d4,'8iXp')));},_0x41ddef);this['readyWaiters']['push']({'resolve':()=>{clearTimeout(_0x332997),_0x1e5035();},'reject':_0x2d86a6=>{clearTimeout(_0x332997),_0x53e70c(_0x2d86a6);}});});}async['start'](){const _0x4fc846=a0_0xc96691;if(this[_0x4fc846(0x111,'$W(9')])return;const _0x5159f4=getLogger(),[_0x3be556,..._0x567480]=this[_0x4fc846(0x21c,'vQ1Q')]();if(!_0x3be556)throw new Error('No\x20MCP\x20command\x20specified.\x20Use\x20--stdio\x20or\x20--command/--args.');const _0xcaad23={...process.env,...this[_0x4fc846(0x4b7,'7@1%')][_0x4fc846(0x48d,'cH7W')]},_0x226b00={};_0x226b00['executable']=_0x3be556,_0x226b00[_0x4fc846(0x330,'yL4y')]=_0x567480,_0x5159f4[_0x4fc846(0x39d,'!mXe')](_0x226b00,_0x4fc846(0x3a8,'8nSx')),this[_0x4fc846(0x200,'&nMv')]='';const _0xf83eeb={};_0xf83eeb['stdio']=[_0x4fc846(0x41f,'S!i)'),_0x4fc846(0x287,'30)t'),_0x4fc846(0x29c,'VDXI')],_0xf83eeb['env']=_0xcaad23,_0xf83eeb['windowsHide']=!![];const _0x1b54eb=a0_0x396568(_0x3be556,_0x567480,_0xf83eeb);this[_0x4fc846(0x404,'$Vfi')]=_0x1b54eb,this['_pid']=_0x1b54eb[_0x4fc846(0x171,'D@Jg')],_0x1b54eb['stdout']?.['on'](_0x4fc846(0x432,'cH7W'),_0x26a0f9=>{const _0x1dbd1e=_0x4fc846;this[_0x1dbd1e(0x309,'d)Ik')](_0x26a0f9);}),_0x1b54eb[_0x4fc846(0x26c,'7@1%')]?.['on']('data',_0x549cfb=>{const _0x4f1280=_0x4fc846,_0x37688d=_0x549cfb['toString']('utf8')['trim']();if(_0x37688d){if(this['options']['traceMcp']){const _0x3b5025={};_0x3b5025[_0x4f1280(0x136,'$Vfi')]='mcp-stderr',_0x5159f4[_0x4f1280(0x161,'yO(Q')](_0x3b5025,_0x37688d);}this['emit'](_0x4f1280(0x4a1,'D@Jg'),_0x37688d);}}),_0x1b54eb['on']('error',_0x3eb7e1=>{const _0x438e5f=_0x4fc846,_0x4ada77={};_0x4ada77[_0x438e5f(0x2ca,'nsSN')]=_0x3eb7e1[_0x438e5f(0x230,'gOga')],_0x5159f4[_0x438e5f(0x323,']cW@')](_0x4ada77,'[supervisor]\x20MCP\x20process\x20spawn\x20error');}),_0x1b54eb['on']('exit',(_0x590ca4,_0x745907)=>{const _0x5042f6=_0x4fc846;this['_pid']=void 0x0;const _0x4b0351={};_0x4b0351[_0x5042f6(0x29b,'uX3F')]=_0x590ca4,_0x4b0351[_0x5042f6(0x21f,'[NGc')]=_0x745907,_0x4b0351[_0x5042f6(0x4ac,'ZiR@')]=this[_0x5042f6(0x191,'8iXp')],_0x5159f4[_0x5042f6(0x196,'2Voh')](_0x4b0351,'[supervisor]\x20MCP\x20process\x20exited'),this['emit']('process-exit',_0x590ca4,_0x745907,this[_0x5042f6(0x1fc,'yL4y')]),!this[_0x5042f6(0x319,'XE3M')]?(this[_0x5042f6(0x1ac,'S!i)')]('restarting'),this[_0x5042f6(0x1ec,'nsSN')]()):this[_0x5042f6(0x37d,'8iXp')]('stopped');});const _0x5bd694={};_0x5bd694['pid']=_0x1b54eb[_0x4fc846(0x221,'GrlK')],_0x5159f4['info'](_0x5bd694,'[supervisor]\x20MCP\x20process\x20spawned'),this['emit']('process-start',_0x1b54eb['pid']);}['onStdoutData'](_0x4045cb){const _0x1f00af=a0_0xc96691;this['lineBuffer']+=_0x4045cb[_0x1f00af(0x22e,'8iXp')]('utf8');const _0x5a04d4=this['lineBuffer']['split']('\x0a');this['lineBuffer']=_0x5a04d4['pop']()??'';for(const _0x3ae4cb of _0x5a04d4){const _0x2c0a71=_0x3ae4cb['trim']();_0x2c0a71&&this[_0x1f00af(0x3ef,'svnM')]('stdout-line',_0x2c0a71);}}['markReady'](){const _0x377877=a0_0xc96691;this['setStatus'](_0x377877(0x46a,'k6M)')),this[_0x377877(0x21d,'&nMv')](_0x377877(0x3c8,'uX3F'),this['_pid']);}['scheduleRestart'](){const _0x195b1e=a0_0xc96691,_0x43a6c4=getLogger();if(this['_isShuttingDown'])return;const _0x45c311=Date[_0x195b1e(0x1e7,'D@Jg')]();this[_0x195b1e(0x3b6,'eONb')]=this[_0x195b1e(0x364,'D@Jg')][_0x195b1e(0x3bb,'yL4y')](_0x5c658b=>_0x45c311-_0x5c658b<this[_0x195b1e(0x2da,'^lJJ')]['restartWindowMs']);if(this['restartTimestamps']['length']>=this[_0x195b1e(0x382,'[NGc')]['maxRestarts']){const _0x28e72d={};_0x28e72d['restarts']=this[_0x195b1e(0x252,'TUy$')]['length'],_0x28e72d[_0x195b1e(0x2eb,'&nMv')]=this['options']['restartWindowMs'],_0x43a6c4['error'](_0x28e72d,'[supervisor]\x20Max\x20restart\x20limit\x20exceeded\x20—\x20giving\x20up'),this['setStatus']('failed'),this['emit'](_0x195b1e(0x12f,'Jt&d'));return;}this[_0x195b1e(0x116,'!mXe')]['push'](_0x45c311),this['_restartCount']++,this['_totalRestarts']++;const _0x37ef54=this[_0x195b1e(0x3dd,'XE3M')]['length'],_0x4b67b9=this[_0x195b1e(0x25b,'D@Jg')][_0x195b1e(0x17d,'yL4y')]*Math[_0x195b1e(0x250,'uX3F')](0x2,_0x37ef54-0x1),_0x536303=Math['min'](_0x4b67b9,this[_0x195b1e(0x311,'Jt&d')][_0x195b1e(0x464,'30)t')]),_0x41b1b9=_0x536303*0.2*(Math['random']()-0.5),_0x16d21a=Math[_0x195b1e(0x331,'ToP^')](0x64,Math[_0x195b1e(0x16c,'TUy$')](_0x536303+_0x41b1b9)),_0x2eca72={};_0x2eca72[_0x195b1e(0x3ff,'!)DA')]=_0x37ef54,_0x2eca72['delayMs']=_0x16d21a,_0x2eca72[_0x195b1e(0x1d7,'XE3M')]=this[_0x195b1e(0x144,'uX3F')][_0x195b1e(0x1f5,'JUp6')],_0x43a6c4[_0x195b1e(0x198,'eONb')](_0x2eca72,'[supervisor]\x20Restarting\x20MCP\x20process\x20in\x20'+_0x16d21a+'ms\x20(attempt\x20'+_0x37ef54+'/'+this['options']['maxRestarts']+')...'),sleep(_0x16d21a)[_0x195b1e(0x300,'!)DA')](()=>{const _0x41c509=_0x195b1e;!this[_0x41c509(0x2ac,'svnM')]&&this['start']()[_0x41c509(0x2a2,'4TBd')](_0x176688=>{const _0x266fa1=_0x41c509,_0x557b7a={};_0x557b7a[_0x266fa1(0x2ca,'nsSN')]=_0x176688['message'],_0x43a6c4[_0x266fa1(0x175,'ToP^')](_0x557b7a,_0x266fa1(0x39b,'d)Ik')),this['scheduleRestart']();});});}[a0_0xc96691(0x34a,'Rq!U')](_0x4fbdc6){return new Promise((_0x11d63e,_0x5e9091)=>{const _0x3a2b23=a0_0x545e;if(!this['process']?.[_0x3a2b23(0x478,'JUp6')]){_0x5e9091(new Error('MCP\x20stdin\x20not\x20available\x20(process\x20not\x20running)'));return;}this[_0x3a2b23(0x21b,'yL4y')]['stdin']['write'](_0x4fbdc6,'utf8',_0x4863b7=>{if(_0x4863b7)_0x5e9091(_0x4863b7);else _0x11d63e();});});}['resolveCommand'](){const _0x2476ca=a0_0xc96691;if(this['options'][_0x2476ca(0x356,'%nTx')])return[this[_0x2476ca(0x172,'VDXI')]['command'],...this[_0x2476ca(0x144,'uX3F')][_0x2476ca(0x290,'VDXI')]];if(this[_0x2476ca(0x4b7,'7@1%')]['stdio'])return splitCommand(this[_0x2476ca(0x135,']cW@')][_0x2476ca(0x436,']cW@')]);return[];}async['shutdown'](){const _0x2620dd=a0_0xc96691,_0x3f44bc=getLogger();if(this['_isShuttingDown'])return;this[_0x2620dd(0x131,'JUp6')]=!![],this['setStatus'](_0x2620dd(0x2f2,'GrlK'));if(this['process']?.['pid']){const _0x2949b3={};_0x2949b3[_0x2620dd(0x1d1,'yL4y')]=this[_0x2620dd(0x360,'!mXe')][_0x2620dd(0x1ab,'^lJJ')],_0x3f44bc[_0x2620dd(0x443,'^lJJ')](_0x2949b3,'[supervisor]\x20Killing\x20MCP\x20process\x20tree...'),await new Promise(_0x1f8305=>{const _0x3cecd9=_0x2620dd;a0_0x4e76c7(this[_0x3cecd9(0x421,'AmkZ')]['pid'],'SIGTERM',_0x53de98=>{const _0x1fc01e=_0x3cecd9;if(_0x53de98){const _0x4163f3={};_0x4163f3[_0x1fc01e(0x4b0,'k6M)')]=_0x53de98,_0x3f44bc[_0x1fc01e(0x2fc,'yL4y')](_0x4163f3,_0x1fc01e(0x1b9,'8nSx')),a0_0x4e76c7(this['process'][_0x1fc01e(0x123,'N%Da')],_0x1fc01e(0x3f7,'ZiR@'),()=>_0x1f8305());}else _0x1f8305();});});}this[_0x2620dd(0x375,'XE3M')]=null,this[_0x2620dd(0x332,'30)t')]=void 0x0,_0x3f44bc[_0x2620dd(0x1db,'k6M)')](_0x2620dd(0x2d3,'TUy$'));}};init_logger();var RequestQueue=class{['queue']=[];[a0_0xc96691(0x365,'8nSx')];[a0_0xc96691(0x400,'7@1%')]=![];[a0_0xc96691(0x12c,'XE3M')]=![];['_processed']=0x0;[a0_0xc96691(0x467,'XE3M')]=0x0;constructor(_0x28b812={}){const _0xfc10d1=a0_0xc96691,_0x3f6e89={};_0x3f6e89['maxDepth']=_0x28b812[_0xfc10d1(0x154,'N%Da')]??0x1f4,_0x3f6e89[_0xfc10d1(0x474,'vQ1Q')]=_0x28b812[_0xfc10d1(0x423,'ToP^')]??0x64,this['options']=_0x3f6e89;}get['size'](){const _0x13b8d2=a0_0xc96691;return this[_0x13b8d2(0x2e5,'Jt&d')][_0x13b8d2(0x475,'QX29')];}get[a0_0xc96691(0x25f,'yUR%')](){return this['_paused'];}get['metrics'](){const _0x4ed71b=a0_0xc96691,_0x1adeaf={};return _0x1adeaf['queued']=this[_0x4ed71b(0x306,'D@Jg')][_0x4ed71b(0x2be,'yL4y')],_0x1adeaf[_0x4ed71b(0x2c1,'ZiR@')]=this[_0x4ed71b(0x378,'8iXp')],_0x1adeaf['dropped']=this[_0x4ed71b(0x3f6,'QX29')],_0x1adeaf['paused']=this['_paused'],_0x1adeaf;}[a0_0xc96691(0x3a5,'d)Ik')](){const _0x13b76f=a0_0xc96691,_0x2d3d93=getLogger();if(!this['_paused']){this['_paused']=!![];const _0x3180d6={};_0x3180d6['queued']=this[_0x13b76f(0x452,'yUR%')][_0x13b76f(0x2f0,'svnM')],_0x2d3d93[_0x13b76f(0x265,'VDXI')](_0x3180d6,_0x13b76f(0x3ed,'4TBd'));}}[a0_0xc96691(0x38a,'fR1R')](_0x144228){const _0x1e7f38=a0_0xc96691,_0x42de8c=getLogger();if(this[_0x1e7f38(0x4ba,']cW@')]){this[_0x1e7f38(0x49a,'B(Hf')]=![];const _0x19854b={};_0x19854b[_0x1e7f38(0x3c1,'VDXI')]=this['queue'][_0x1e7f38(0x133,'vQ1Q')],_0x42de8c[_0x1e7f38(0x169,'fR1R')](_0x19854b,'[queue]\x20Resumed\x20—\x20draining\x20queued\x20requests'),void this['drain'](_0x144228);}}['enqueue'](_0x1eb532,_0x26cbfd){const _0x332c81=a0_0xc96691,_0x2e919e=getLogger();if(this[_0x332c81(0x1ea,'ZiR@')][_0x332c81(0x155,'2Voh')]>=this['options']['maxDepth']){this['_dropped']++;const _0x5cf3d9={};_0x5cf3d9[_0x332c81(0x48f,'4TBd')]=this['queue'][_0x332c81(0x427,'Jt&d')],_0x5cf3d9['maxDepth']=this['options'][_0x332c81(0x2ad,'S!i)')],_0x2e919e['warn'](_0x5cf3d9,'[queue]\x20Queue\x20full\x20—\x20dropping\x20oldest\x20request');const _0x2a5e41=this[_0x332c81(0x2c3,'B(Hf')][_0x332c81(0x1a6,'*f75')]();_0x2a5e41&&(clearTimeout(_0x2a5e41[_0x332c81(0x445,'uX3F')]),_0x2a5e41[_0x332c81(0x357,'2Voh')](new Error(_0x332c81(0x130,'d)Ik'))));}return new Promise((_0x3811c7,_0x2b4999)=>{const _0x595b08=_0x332c81,_0x54ec79=Math['random']()[_0x595b08(0x10e,']cW@')](0x24)[_0x595b08(0x2b3,'*f75')](0x2),_0x30cb2d=Date[_0x595b08(0x1b1,'nsSN')](),_0x12c8ec=setTimeout(()=>{const _0x48fbba=_0x595b08,_0x5b5829=this[_0x48fbba(0x247,'4TBd')][_0x48fbba(0x28f,'DrN%')](_0x3f4dac=>_0x3f4dac['id']===_0x54ec79);if(_0x5b5829!==-0x1){this['queue']['splice'](_0x5b5829,0x1),this['_dropped']++,_0x2b4999(new Error('Request\x20timed\x20out\x20after\x20'+_0x26cbfd+_0x48fbba(0x10c,'Jt&d')));const _0x1cff55={};_0x1cff55['id']=_0x54ec79,_0x1cff55[_0x48fbba(0x19b,'QX29')]=_0x26cbfd,_0x2e919e[_0x48fbba(0x36e,'&nMv')](_0x1cff55,_0x48fbba(0x372,'k6M)'));}},_0x26cbfd),_0x43a0c1={};_0x43a0c1['id']=_0x54ec79,_0x43a0c1['execute']=_0x1eb532,_0x43a0c1[_0x595b08(0x197,'d)Ik')]=_0x3811c7,_0x43a0c1[_0x595b08(0x181,'8iXp')]=_0x2b4999,_0x43a0c1['enqueueTime']=_0x30cb2d,_0x43a0c1[_0x595b08(0x164,'uX3F')]=_0x26cbfd,_0x43a0c1['timer']=_0x12c8ec;const _0x4bab35=_0x43a0c1;this[_0x595b08(0x457,'uX3F')]['push'](_0x4bab35);const _0x4b1bb3={};_0x4b1bb3['id']=_0x54ec79,_0x4b1bb3['queueDepth']=this[_0x595b08(0x471,'!)DA')][_0x595b08(0x402,'%nTx')],_0x2e919e[_0x595b08(0x3db,'ToP^')](_0x4b1bb3,'[queue]\x20Request\x20enqueued');});}async['drain'](_0x15b5e2){const _0x199719=a0_0xc96691;if(this[_0x199719(0x3a0,'N%Da')])return;this[_0x199719(0x18d,'S!i)')]=!![];const _0x3efdf6=getLogger();while(this['queue'][_0x199719(0x35f,'^lJJ')]>0x0&&!this[_0x199719(0x327,'&nMv')]){const _0x43822b=this[_0x199719(0x2f8,'&nMv')]['shift']();if(!_0x43822b)break;if(Date['now']()-_0x43822b['enqueueTime']>_0x43822b[_0x199719(0x3cf,'A^&K')]){clearTimeout(_0x43822b['timer']),this[_0x199719(0x450,'!mXe')]++,_0x43822b['reject'](new Error(_0x199719(0x43f,'JUp6')));continue;}clearTimeout(_0x43822b['timer']);try{await _0x15b5e2(_0x43822b),this[_0x199719(0x235,'GrlK')]++;}catch(_0x48e0b6){const _0x5e6a49={};_0x5e6a49['err']=_0x48e0b6[_0x199719(0x199,']cW@')],_0x3efdf6['warn'](_0x5e6a49,'[queue]\x20Error\x20draining\x20request'),_0x43822b[_0x199719(0x383,'&nMv')](_0x48e0b6),this['_dropped']++;}await sleep(0x0);}this['_draining']=![];if(this['queue']['length']>0x0&&this[_0x199719(0x4ba,']cW@')]){const _0x1b786e={};_0x1b786e[_0x199719(0x3fb,'$W(9')]=this['queue'][_0x199719(0x227,'JUp6')],_0x3efdf6['debug'](_0x1b786e,_0x199719(0x312,'JUp6'));}}['flush'](_0x1c560d='Queue\x20flushed\x20on\x20shutdown'){const _0x4a684e=a0_0xc96691,_0x2583b3=getLogger(),_0x3ff0fc={};_0x3ff0fc[_0x4a684e(0x2e7,'k6M)')]=this['queue'][_0x4a684e(0x133,'vQ1Q')],_0x2583b3['info'](_0x3ff0fc,_0x4a684e(0x1f6,'JUp6'));for(const _0x3bcb2c of this['queue']){clearTimeout(_0x3bcb2c['timer']),_0x3bcb2c[_0x4a684e(0x22f,'TUy$')](new Error(_0x1c560d));}this[_0x4a684e(0x482,'JUp6')]['length']=0x0,this[_0x4a684e(0x49a,'B(Hf')]=![];}},JsonRpcIdSchema=a0_0x307087['union']([a0_0x307087[a0_0xc96691(0x14b,'Rq!U')](),a0_0x307087['number'](),a0_0x307087[a0_0xc96691(0x216,'7@1%')]()]),McpRequestSchema=a0_0x307087['object']({'jsonrpc':a0_0x307087['literal'](a0_0xc96691(0x44e,'30)t')),'id':JsonRpcIdSchema[a0_0xc96691(0x2dc,'svnM')](),'method':a0_0x307087['string'](),'params':a0_0x307087['unknown']()[a0_0xc96691(0x1a5,'yUR%')]()}),McpSuccessResponseSchema=a0_0x307087['object']({'jsonrpc':a0_0x307087['literal'](a0_0xc96691(0x456,'@QVa')),'id':JsonRpcIdSchema,'result':a0_0x307087['unknown']()}),McpErrorResponseSchema=a0_0x307087[a0_0xc96691(0x256,'cH7W')]({'jsonrpc':a0_0x307087['literal'](a0_0xc96691(0x28a,'[NGc')),'id':JsonRpcIdSchema['optional'](),'error':a0_0x307087[a0_0xc96691(0x477,'TUy$')]({'code':a0_0x307087[a0_0xc96691(0x2e6,'V&f(')](),'message':a0_0x307087['string'](),'data':a0_0x307087[a0_0xc96691(0x288,'AmkZ')]()[a0_0xc96691(0x143,'yL4y')]()})}),McpNotificationSchema=a0_0x307087[a0_0xc96691(0x1d2,'^lJJ')]({'jsonrpc':a0_0x307087[a0_0xc96691(0x2c7,'8iXp')](a0_0xc96691(0x212,'ZiR@')),'method':a0_0x307087['string'](),'params':a0_0x307087['unknown']()['optional']()}),McpOutboundSchema=a0_0x307087[a0_0xc96691(0x2ff,'$W(9')]([McpSuccessResponseSchema,McpErrorResponseSchema,McpNotificationSchema]),ConcurrencyLimiter=class{constructor(_0x54a946){this['concurrency']=_0x54a946;}[a0_0xc96691(0x3a3,'k6M)')];['running']=0x0;['waiters']=[];async['run'](_0x164036){return new Promise((_0x195b24,_0x151f82)=>{const _0x44f453=a0_0x545e,_0x2c09bd=async()=>{try{_0x195b24(await _0x164036());}catch(_0x2368aa){_0x151f82(_0x2368aa);}};this[_0x44f453(0x3f8,'yO(Q')][_0x44f453(0x147,'vQ1Q')](_0x2c09bd),this[_0x44f453(0x453,'7@1%')]();});}['tick'](){const _0x1f4854=a0_0xc96691;while(this['running']<this['concurrency']&&this[_0x1f4854(0x49d,'4TBd')][_0x1f4854(0x2ba,'8iXp')]>0x0){const _0x1e4f6b=this['waiters'][_0x1f4854(0x481,'8iXp')]();if(!_0x1e4f6b)break;this['running']++,_0x1e4f6b()['finally'](()=>{this['running']--,this['tick']();});}}get[a0_0xc96691(0x45a,'B(Hf')](){const _0x226bc0=a0_0xc96691;return this['waiters']['length']+this[_0x226bc0(0x2ab,'k6M)')];}},McpBridge=class extends a0_0x311af2{['supervisor'];['limiter'];['requestQueue'];['options'];['pending']=new Map();['_isShuttingDown']=![];constructor(_0xc3ab94){const _0x56cfed=a0_0xc96691;super();const _0x38483={};_0x38483['stdio']=_0xc3ab94[_0x56cfed(0x32e,'fR1R')]??'',_0x38483['command']=_0xc3ab94[_0x56cfed(0x2b1,'30)t')]??'',_0x38483[_0x56cfed(0x4a9,'yUR%')]=_0xc3ab94['args']??[],_0x38483[_0x56cfed(0x35b,'%nTx')]=_0xc3ab94[_0x56cfed(0x34b,'Jt&d')]??{},_0x38483['timeoutMs']=_0xc3ab94[_0x56cfed(0x41e,'$Vfi')]??0x493e0,_0x38483['concurrency']=_0xc3ab94[_0x56cfed(0x1cc,'4TBd')]??0x1,_0x38483[_0x56cfed(0x358,'yL4y')]=_0xc3ab94['traceMcp']??![],_0x38483[_0x56cfed(0x44c,'8nSx')]=_0xc3ab94['maxRestarts']??0xa,_0x38483[_0x56cfed(0x433,'A^&K')]=_0xc3ab94['restartWindowMs']??0xea60,_0x38483[_0x56cfed(0x120,'B(Hf')]=_0xc3ab94[_0x56cfed(0x3f0,'VDXI')]??0x1f4,_0x38483['maxRetryMs']=_0xc3ab94['maxRetryMs']??0x7530,_0x38483['maxQueueDepth']=_0xc3ab94[_0x56cfed(0x442,'svnM')]??0x1f4,this['options']=_0x38483,this['limiter']=new ConcurrencyLimiter(this[_0x56cfed(0x172,'VDXI')][_0x56cfed(0x497,'B(Hf')]),this['requestQueue']=new RequestQueue({'maxDepth':this[_0x56cfed(0x428,'yUR%')][_0x56cfed(0x2a8,'@QVa')]}),this['supervisor']=new McpSupervisor({'stdio':this[_0x56cfed(0x3a1,'%nTx')]['stdio'],'command':this[_0x56cfed(0x3a9,'8iXp')][_0x56cfed(0x17b,'^lJJ')],'args':this[_0x56cfed(0x2e3,'gOga')][_0x56cfed(0x40c,'OeEa')],'env':this['options']['env'],'maxRestarts':this['options'][_0x56cfed(0x2ed,'yO(Q')],'restartWindowMs':this['options']['restartWindowMs'],'baseRetryMs':this[_0x56cfed(0x46f,'&nMv')][_0x56cfed(0x38c,'V&f(')],'maxRetryMs':this[_0x56cfed(0x2d1,'svnM')]['maxRetryMs'],'traceMcp':this['options'][_0x56cfed(0x138,'8nSx')]}),this['wireSupervisorEvents']();}get['isRunning'](){const _0x47ec52=a0_0xc96691;return this[_0x47ec52(0x3e8,'ToP^')][_0x47ec52(0x34c,'!mXe')];}get['pid'](){const _0x398ec0=a0_0xc96691;return this[_0x398ec0(0x392,'V&f(')]['pid'];}get[a0_0xc96691(0x2cb,'JUp6')](){return this['supervisor']['restartCount'];}get['totalRestarts'](){const _0x4070e3=a0_0xc96691;return this[_0x4070e3(0x363,'nsSN')]['totalRestarts'];}get['queueSize'](){const _0xec0b28=a0_0xc96691;return this['limiter']['size']+this['requestQueue'][_0xec0b28(0x236,'8iXp')];}get[a0_0xc96691(0x4ae,'cH7W')](){return this['supervisor']['status'];}get[a0_0xc96691(0x429,'^lJJ')](){const _0x140ca1=a0_0xc96691;return this[_0x140ca1(0x393,'B(Hf')][_0x140ca1(0x3cd,'!mXe')];}[a0_0xc96691(0x206,'vQ1Q')](){const _0x279ef4=a0_0xc96691,_0x364b90=getLogger();this['supervisor']['on']('stdout-line',_0x28133d=>{this['handleMessage'](_0x28133d);}),this[_0x279ef4(0x14d,'*f75')]['on'](_0x279ef4(0x18b,'Rq!U'),_0xd47f6a=>{const _0x3119e3=_0x279ef4,_0x268750={};_0x268750[_0x3119e3(0x3ca,'&nMv')]=_0xd47f6a,_0x364b90['info'](_0x268750,'[bridge]\x20MCP\x20process\x20started\x20—\x20performing\x20initialize\x20handshake...'),this[_0x3119e3(0x14f,'ToP^')](_0x3119e3(0x204,'&nMv'),_0xd47f6a),this['requestQueue']['pause'](),this[_0x3119e3(0x25a,'JUp6')]()[_0x3119e3(0x413,'!mXe')](()=>{const _0x40c9bc=_0x3119e3;this['supervisor'][_0x40c9bc(0x2e4,'yUR%')](),this['requestQueue']['resume'](async _0x5d1bd6=>{const _0x4bd17b=_0x40c9bc;try{const _0x5b7a35=await _0x5d1bd6[_0x4bd17b(0x34e,'$Vfi')]();_0x5d1bd6['resolve'](_0x5b7a35);}catch(_0x14b9b7){_0x5d1bd6[_0x4bd17b(0x381,'*f75')](_0x14b9b7);}});const _0x24b62e={};_0x24b62e['pid']=_0xd47f6a,_0x364b90['info'](_0x24b62e,'[bridge]\x20MCP\x20ready\x20—\x20queue\x20resumed');})[_0x3119e3(0x1aa,'nsSN')](_0x2f83f7=>{const _0x4fda68=_0x3119e3,_0x3df732={};_0x3df732['err']=_0x2f83f7[_0x4fda68(0x173,'$Vfi')],_0x364b90['error'](_0x3df732,'[bridge]\x20Initialize\x20handshake\x20failed\x20—\x20will\x20retry\x20on\x20next\x20restart');});}),this[_0x279ef4(0x183,'TUy$')]['on'](_0x279ef4(0x1fa,'@QVa'),(_0x2ef9f4,_0x4058d6)=>{const _0x424e5e=_0x279ef4,_0x549f28={};_0x549f28['code']=_0x2ef9f4,_0x549f28['signal']=_0x4058d6,_0x364b90['warn'](_0x549f28,'[bridge]\x20MCP\x20process\x20exited\x20—\x20rejecting\x20in-flight\x20requests'),this[_0x424e5e(0x439,'d)Ik')]('exit',_0x2ef9f4,_0x4058d6);for(const [_0x34e268,_0x597b2f]of this['pending']){_0x597b2f['reject'](new Error(_0x424e5e(0x24c,'nsSN'))),clearTimeout(_0x597b2f['timer']),this['pending']['delete'](_0x34e268);}this[_0x424e5e(0x359,'8nSx')][_0x424e5e(0x3fa,'^lJJ')]();}),this[_0x279ef4(0x47f,'QX29')]['on']('status',_0x1ba5a0=>{const _0x144b54=_0x279ef4;this[_0x144b54(0x289,'*f75')]('supervisor-status',_0x1ba5a0,this['supervisor']['pid'],this['supervisor']['restartCount']);}),this[_0x279ef4(0x47f,'QX29')]['on'](_0x279ef4(0x411,'yUR%'),()=>{const _0x108f3f=_0x279ef4;_0x364b90[_0x108f3f(0x11b,'&nMv')]('[bridge]\x20Supervisor\x20gave\x20up\x20—\x20flushing\x20request\x20queue'),this[_0x108f3f(0x48b,'ZiR@')]['flush'](_0x108f3f(0x476,']cW@')),this['emit'](_0x108f3f(0x224,'2Voh'));});}async['start'](){const _0x13133e=a0_0xc96691;await this['supervisor'][_0x13133e(0x238,'!mXe')](),await this['supervisor'][_0x13133e(0x128,'cH7W')](0x1d4c0);}async[a0_0xc96691(0x1e5,'%nTx')](){const _0x46469a=a0_0xc96691,_0x1755a6=getLogger(),_0x15ba9f=this[_0x46469a(0x4a2,'S!i)')][_0x46469a(0x13e,'^N!&')],_0x1079c4=Math[_0x46469a(0x266,'[NGc')](_0x15ba9f,0x1d4c0);_0x1755a6[_0x46469a(0x1fd,'QX29')]('[bridge]\x20Performing\x20MCP\x20initialize\x20handshake...');try{const _0x3893e5={};_0x3893e5['listChanged']=![];const _0x27dc57={};_0x27dc57['roots']=_0x3893e5,_0x27dc57[_0x46469a(0x354,'VDXI')]={};const _0x2bf6ce={};_0x2bf6ce['name']=_0x46469a(0x14e,'fR1R'),_0x2bf6ce[_0x46469a(0x39a,'eONb')]=_0x46469a(0x2b0,'S!i)');const _0x43f48a={};_0x43f48a[_0x46469a(0x20e,'gOga')]=_0x46469a(0x455,'QX29'),_0x43f48a['capabilities']=_0x27dc57,_0x43f48a[_0x46469a(0x31b,'JUp6')]=_0x2bf6ce;const _0x6a754c={};_0x6a754c['jsonrpc']='2.0',_0x6a754c['id']=_0x46469a(0x447,'&nMv'),_0x6a754c[_0x46469a(0x1b3,'V&f(')]='initialize',_0x6a754c[_0x46469a(0x232,'8iXp')]=_0x43f48a;const _0xcdcf32=await this[_0x46469a(0x193,'OeEa')](_0x6a754c,_0x1079c4),_0x47ab17={};_0x47ab17['initResponse']=_0xcdcf32,_0x1755a6['debug'](_0x47ab17,_0x46469a(0x27a,'V&f('));const _0x2b0a5f={};_0x2b0a5f[_0x46469a(0x325,'@QVa')]='2.0',_0x2b0a5f[_0x46469a(0x3c7,'yO(Q')]=_0x46469a(0x333,'JUp6'),_0x2b0a5f[_0x46469a(0x3e9,'ZiR@')]={},await this[_0x46469a(0x4a6,'!mXe')]['write'](JSON[_0x46469a(0x25d,'d)Ik')](_0x2b0a5f)+'\x0a'),_0x1755a6['info'](_0x46469a(0x343,'*f75'));}catch(_0x1bd15e){const _0x5b5dcb={};_0x5b5dcb['err']=_0x1bd15e[_0x46469a(0x18a,'GrlK')],_0x1755a6['error'](_0x5b5dcb,'[bridge]\x20MCP\x20initialize\x20handshake\x20failed');throw _0x1bd15e;}}async['sendRequest'](_0x3906dd){const _0x22a3ec=a0_0xc96691,_0x39ef4e=McpRequestSchema['safeParse'](_0x3906dd);if(!_0x39ef4e[_0x22a3ec(0x1b0,'N%Da')]){const _0x1ab8c9={};_0x1ab8c9[_0x22a3ec(0x341,'eONb')]=-0x7f58,_0x1ab8c9[_0x22a3ec(0x19f,'@QVa')]='Invalid\x20Request',_0x1ab8c9[_0x22a3ec(0x337,'d)Ik')]=_0x39ef4e[_0x22a3ec(0x37c,'Jt&d')]['issues'];const _0x336740={};return _0x336740['jsonrpc']='2.0',_0x336740['id']=_0x3906dd['id']??null,_0x336740['error']=_0x1ab8c9,_0x336740;}const _0x40900c=_0x39ef4e[_0x22a3ec(0x3d9,'QX29')];if(this['requestQueue']['isPaused'])return this['requestQueue']['enqueue'](()=>this['limiter']['run'](()=>this['doSendRequest'](_0x40900c)),this['options']['timeoutMs']);return this[_0x22a3ec(0x2df,'!)DA')][_0x22a3ec(0x3e5,'V&f(')](()=>this['doSendRequest'](_0x40900c));}async[a0_0xc96691(0x342,'2Voh')](_0x36094f){const _0x4cc8dd=a0_0xc96691;if(!this[_0x4cc8dd(0x392,'V&f(')]['isReady']){if(this['supervisor'][_0x4cc8dd(0x2ea,'k6M)')]===_0x4cc8dd(0x43d,'30)t')||this['supervisor']['status']==='stopped'){const _0x5c58cf={};_0x5c58cf[_0x4cc8dd(0x4ad,'QX29')]=-0x7f5b,_0x5c58cf[_0x4cc8dd(0x29e,'k6M)')]=_0x4cc8dd(0x1c1,'Jt&d')+this['supervisor']['status']+')';const _0x1fa71e={};return _0x1fa71e[_0x4cc8dd(0x40f,'GrlK')]=_0x4cc8dd(0x456,'@QVa'),_0x1fa71e['id']=_0x36094f['id']??null,_0x1fa71e[_0x4cc8dd(0x4a5,'B(Hf')]=_0x5c58cf,_0x1fa71e;}return this['requestQueue'][_0x4cc8dd(0x3c0,'cH7W')](()=>this['doSendRequest'](_0x36094f),this[_0x4cc8dd(0x311,'Jt&d')]['timeoutMs']);}if(_0x36094f['id']===void 0x0||_0x36094f['id']===null){await this[_0x4cc8dd(0x2cd,'gOga')]['write'](JSON['stringify'](_0x36094f)+'\x0a');const _0x3c480b={};return _0x3c480b['jsonrpc']=_0x4cc8dd(0x273,'TUy$'),_0x3c480b['id']=null,_0x3c480b[_0x4cc8dd(0x211,'svnM')]=null,_0x3c480b;}return this['doSendRawRequest'](_0x36094f,this[_0x4cc8dd(0x479,'ToP^')]['timeoutMs']);}[a0_0xc96691(0x213,'JUp6')](_0x5aa508,_0x352386){const _0x14fca1=getLogger(),_0x1f90ec=_0x5aa508['id'];return new Promise((_0x22d37f,_0xf1d6fa)=>{const _0xc160d8=a0_0x545e,_0x213f56=setTimeout(()=>{const _0x92c01e=a0_0x545e;this[_0x92c01e(0x3ac,'30)t')]['delete'](_0x1f90ec),_0xf1d6fa(new Error(_0x92c01e(0x241,'%nTx')+_0x352386+_0x92c01e(0x4b1,'AmkZ')+String(_0x1f90ec)+_0x92c01e(0x3e6,'@QVa')+String(_0x5aa508['method'])+')'));},_0x352386),_0x30b9ba={};_0x30b9ba[_0xc160d8(0x262,'8nSx')]=_0x22d37f,_0x30b9ba[_0xc160d8(0x188,'fR1R')]=_0xf1d6fa,_0x30b9ba['timer']=_0x213f56,this['pending'][_0xc160d8(0x3d5,'fR1R')](_0x1f90ec,_0x30b9ba);if(this['options']['traceMcp']){const _0x173a57={};_0x173a57['direction']=_0xc160d8(0x207,'$Vfi'),_0x173a57[_0xc160d8(0x454,'8nSx')]=_0x5aa508,_0x14fca1['debug'](_0x173a57,'[bridge]\x20MCP\x20trace');}this[_0xc160d8(0x431,'S!i)')]['write'](JSON[_0xc160d8(0x27f,'GrlK')](_0x5aa508)+'\x0a')[_0xc160d8(0x1c6,'7@1%')](_0x59bbb4=>{const _0x33658d=_0xc160d8;clearTimeout(_0x213f56),this['pending'][_0x33658d(0x42e,'N%Da')](_0x1f90ec),_0xf1d6fa(_0x59bbb4);});});}['handleMessage'](_0x5ab733){const _0x533497=a0_0xc96691,_0x2a4052=getLogger();let _0xbfc7f2;try{_0xbfc7f2=JSON['parse'](_0x5ab733);}catch{const _0x28f5c5={};_0x28f5c5['line']=_0x5ab733,_0x2a4052['debug'](_0x28f5c5,_0x533497(0x293,'XE3M'));return;}const _0x5886a2=McpOutboundSchema[_0x533497(0x3da,'yUR%')](_0xbfc7f2);if(!_0x5886a2['success']){const _0x171b3c={};_0x171b3c['raw']=_0xbfc7f2,_0x2a4052['warn'](_0x171b3c,_0x533497(0x3ce,'AmkZ'));return;}const _0x4394de=_0x5886a2[_0x533497(0x2d2,'AmkZ')];if(this[_0x533497(0x23e,'!mXe')]['traceMcp']){const _0x1e2682={};_0x1e2682['direction']='←\x20MCP',_0x1e2682['payload']=_0x4394de,_0x2a4052[_0x533497(0x11f,'yL4y')](_0x1e2682,_0x533497(0x407,'VDXI'));}if(!('id'in _0x4394de)){const _0x42d774=McpNotificationSchema['safeParse'](_0x4394de);_0x42d774['success']&&this['emit']('notification',_0x42d774[_0x533497(0x170,'^N!&')]);return;}const _0x2ec1b3=_0x4394de['id'];if(_0x2ec1b3!==null&&_0x2ec1b3!==void 0x0){const _0x46a441=this['pending']['get'](_0x2ec1b3);if(_0x46a441){clearTimeout(_0x46a441[_0x533497(0x1da,'@QVa')]),this[_0x533497(0x2f7,'fR1R')]['delete'](_0x2ec1b3),_0x46a441[_0x533497(0x2a1,'B(Hf')](_0x4394de);return;}}const _0xe08873={};_0xe08873['id']=_0x2ec1b3,_0x2a4052['debug'](_0xe08873,'[bridge]\x20Received\x20response\x20for\x20unknown\x20request\x20id');}async['shutdown'](){const _0x5816cb=a0_0xc96691,_0x45515a=getLogger();this['_isShuttingDown']=!![];for(const [_0x57ee78,_0x24fc9f]of this[_0x5816cb(0x338,'ToP^')]){clearTimeout(_0x24fc9f['timer']),_0x24fc9f['reject'](new Error(_0x5816cb(0x1f2,'!mXe'))),this[_0x5816cb(0x426,'^N!&')][_0x5816cb(0x274,'uX3F')](_0x57ee78);}this[_0x5816cb(0x308,'nsSN')]['flush'](_0x5816cb(0x1d9,'QX29')),await this[_0x5816cb(0x363,'nsSN')][_0x5816cb(0x2c4,'Jt&d')](),_0x45515a[_0x5816cb(0x2a4,'%nTx')]('[bridge]\x20Bridge\x20shutdown\x20complete');}};import a0_0x4ef407 from'crypto';import a0_0x4a095f from'express';import a0_0x5c7457 from'cors';init_logger();import a0_0x43cc2f from'crypto';import{EventEmitter as a0_0x4c0edd}from'events';var SessionManager=class extends a0_0x4c0edd{[a0_0xc96691(0x15a,'DrN%')]=new Map();[a0_0xc96691(0x3b4,'V&f(')];constructor(_0x7fbcf7={}){const _0x3ab437=a0_0xc96691;super();const _0x14daaf={};_0x14daaf['sessionTtlMs']=_0x7fbcf7['sessionTtlMs']??0x5*0xea60,_0x14daaf['heartbeatIntervalMs']=_0x7fbcf7['heartbeatIntervalMs']??0x61a8,this[_0x3ab437(0x25b,'D@Jg')]=_0x14daaf;}[a0_0xc96691(0x33a,'7@1%')](_0x35850d){const _0x429ad3=a0_0xc96691,_0x4a9094=a0_0x43cc2f['randomUUID'](),_0x588399={'id':_0x4a9094,'label':_0x35850d??_0x429ad3(0x371,'8nSx')+_0x4a9094['slice'](0x0,0x8),'createdAt':new Date(),'lastConnectedAt':null,'lastDisconnectedAt':null,'state':'disconnected','transport':null,'heartbeatTimer':null,'expiryTimer':null,'reconnectCount':0x0,'meta':{}};this[_0x429ad3(0x18f,'gOga')][_0x429ad3(0x1f7,'yUR%')](_0x4a9094,_0x588399);const _0x580ad5=getLogger(),_0x4f499f={};return _0x4f499f['sessionId']=_0x4a9094,_0x4f499f[_0x429ad3(0x31c,'%nTx')]=_0x588399['label'],_0x580ad5['info'](_0x4f499f,_0x429ad3(0x37b,'uX3F')),this[_0x429ad3(0x217,'Jt&d')](_0x429ad3(0x35d,'DrN%'),_0x588399),_0x588399;}['bind'](_0x51f235,_0xc8e209){const _0x42c761=a0_0xc96691,_0x1c7e7=getLogger();let _0x44fee2=this['sessions']['get'](_0x51f235);if(!_0x44fee2){const _0x4c428a={};return _0x4c428a[_0x42c761(0x448,'fR1R')]=_0x51f235,_0x1c7e7[_0x42c761(0x203,'cH7W')](_0x4c428a,_0x42c761(0x2f6,'yUR%')),null;}const _0x5a93e1=_0x44fee2['state']==='disconnected';_0x44fee2['expiryTimer']&&(clearTimeout(_0x44fee2['expiryTimer']),_0x44fee2['expiryTimer']=null);this[_0x42c761(0x48a,'2Voh')](_0x44fee2),_0x44fee2['transport']=_0xc8e209,_0x44fee2[_0x42c761(0x2c2,'V&f(')]='connected',_0x44fee2['lastConnectedAt']=new Date();if(_0x5a93e1&&_0x44fee2['reconnectCount']>0x0){_0x44fee2[_0x42c761(0x326,'uX3F')]++;const _0x57d1f2={};_0x57d1f2['sessionId']=_0x51f235,_0x57d1f2[_0x42c761(0x279,'$W(9')]=_0x44fee2['reconnectCount'],_0x1c7e7[_0x42c761(0x124,'D@Jg')](_0x57d1f2,_0x42c761(0x13a,'eONb')),this['emit'](_0x42c761(0x286,'7@1%'),_0x44fee2);}else _0x44fee2[_0x42c761(0x151,'4TBd')]++,this[_0x42c761(0x16d,'JUp6')]('session-connected',_0x44fee2);this[_0x42c761(0x493,'yO(Q')](_0x44fee2);const _0x55e0f2={};return _0x55e0f2['sessionId']=_0x51f235,_0x55e0f2['label']=_0x44fee2[_0x42c761(0x239,'$Vfi')],_0x1c7e7['info'](_0x55e0f2,'[session]\x20Transport\x20bound'),_0x44fee2;}['unbind'](_0x123989){const _0x5aa267=a0_0xc96691,_0x290a88=getLogger(),_0xca5d21=this[_0x5aa267(0x18f,'gOga')][_0x5aa267(0x3fc,'!mXe')](_0x123989);if(!_0xca5d21)return;this[_0x5aa267(0x3f4,'gOga')](_0xca5d21),_0xca5d21['transport']=null,_0xca5d21['state']=_0x5aa267(0x2d5,'svnM'),_0xca5d21['lastDisconnectedAt']=new Date();const _0x4db2d6={};_0x4db2d6['sessionId']=_0x123989,_0x4db2d6[_0x5aa267(0x109,'8nSx')]=_0xca5d21[_0x5aa267(0x113,'Jt&d')],_0x290a88[_0x5aa267(0x15e,']cW@')](_0x4db2d6,_0x5aa267(0x1bf,'ToP^')),this['emit'](_0x5aa267(0x291,'nsSN'),_0xca5d21),_0xca5d21['expiryTimer']=setTimeout(()=>{const _0x504cc2=_0x5aa267;this[_0x504cc2(0x299,'ToP^')](_0x123989);},this['options']['sessionTtlMs']);}['expire'](_0x20eb08){const _0x37c3c4=a0_0xc96691,_0x5246b9=getLogger(),_0x51f5dc=this[_0x37c3c4(0x42a,'Rq!U')][_0x37c3c4(0x3c9,'yL4y')](_0x20eb08);if(!_0x51f5dc)return;this['stopHeartbeat'](_0x51f5dc);_0x51f5dc['expiryTimer']&&(clearTimeout(_0x51f5dc['expiryTimer']),_0x51f5dc[_0x37c3c4(0x118,'svnM')]=null);_0x51f5dc[_0x37c3c4(0x2a5,'*f75')]='expired',this['sessions']['delete'](_0x20eb08);const _0x1d97d5={};_0x1d97d5[_0x37c3c4(0x458,'^lJJ')]=_0x20eb08,_0x1d97d5[_0x37c3c4(0x2f4,'V&f(')]=_0x51f5dc['label'],_0x5246b9[_0x37c3c4(0x40a,'nsSN')](_0x1d97d5,_0x37c3c4(0x3b2,'[NGc')),this[_0x37c3c4(0x289,'*f75')]('session-expired',_0x20eb08);}[a0_0xc96691(0x43a,'OeEa')](_0x1a5711){const _0x4eac7c=a0_0xc96691,_0x4a9a24=getLogger(),_0x31b528=this['sessions'][_0x4eac7c(0x373,'V&f(')](_0x1a5711);if(!_0x31b528)return;this[_0x4eac7c(0x2a7,'ToP^')](_0x31b528);_0x31b528['expiryTimer']&&(clearTimeout(_0x31b528['expiryTimer']),_0x31b528['expiryTimer']=null);if(_0x31b528['transport']&&!_0x31b528[_0x4eac7c(0x47d,'k6M)')][_0x4eac7c(0x43b,'^lJJ')])try{_0x31b528[_0x4eac7c(0x180,'7@1%')][_0x4eac7c(0x2e1,'8nSx')]();}catch{}_0x31b528['state']=_0x4eac7c(0x4aa,'eONb'),this[_0x4eac7c(0x44f,'yUR%')]['delete'](_0x1a5711);const _0x9b519={};_0x9b519[_0x4eac7c(0x3ea,'d)Ik')]=_0x1a5711,_0x4a9a24[_0x4eac7c(0x1fd,'QX29')](_0x9b519,_0x4eac7c(0x240,'yO(Q'));}[a0_0xc96691(0x440,'VDXI')](_0x5a6625,_0x2b71c6){const _0x19fbe8=a0_0xc96691,_0x22db44=getLogger(),_0x314439=_0x19fbe8(0x472,'k6M)')+_0x5a6625+_0x19fbe8(0x1f8,'*f75')+JSON['stringify'](_0x2b71c6)+'\x0a\x0a';let _0x365789=0x0,_0x147fa0=0x0;for(const [_0x425153,_0x513504]of this[_0x19fbe8(0x13b,'^N!&')]){if(_0x513504['state']!=='connected'||!_0x513504[_0x19fbe8(0x1a8,'fR1R')])continue;if(_0x513504['transport']['writableEnded']){this[_0x19fbe8(0x3d6,'8iXp')](_0x425153),_0x147fa0++;continue;}try{_0x513504['transport'][_0x19fbe8(0x16e,'gOga')](_0x314439),_0x365789++;}catch{this[_0x19fbe8(0x31a,'k6M)')](_0x425153),_0x147fa0++;}}if(_0x365789>0x0||_0x147fa0>0x0){const _0x1ded13={};_0x1ded13[_0x19fbe8(0x46b,'svnM')]=_0x5a6625,_0x1ded13['sent']=_0x365789,_0x1ded13[_0x19fbe8(0x2d0,'nsSN')]=_0x147fa0,_0x22db44[_0x19fbe8(0x420,'^N!&')](_0x1ded13,_0x19fbe8(0x2ee,'A^&K'));}}['send'](_0x5f55a4,_0x2b1c13,_0xb85a7a){const _0x3d907e=a0_0xc96691,_0x336222=this['sessions']['get'](_0x5f55a4);if(!_0x336222||_0x336222['state']!==_0x3d907e(0x1ad,'8nSx')||!_0x336222[_0x3d907e(0x298,'8iXp')])return![];if(_0x336222[_0x3d907e(0x3c4,'cH7W')][_0x3d907e(0x19e,'VDXI')])return this[_0x3d907e(0x47a,'!mXe')](_0x5f55a4),![];try{const _0xdb7b67='event:\x20'+_0x2b1c13+_0x3d907e(0x395,'$Vfi')+JSON[_0x3d907e(0x264,'%nTx')](_0xb85a7a)+'\x0a\x0a';return _0x336222['transport'][_0x3d907e(0x141,'&nMv')](_0xdb7b67),!![];}catch{return this['unbind'](_0x5f55a4),![];}}[a0_0xc96691(0x226,'V&f(')](_0x38df85,_0x4f92a9={}){const _0x35beca=a0_0xc96691;this['broadcast'](_0x35beca(0x1ee,'OeEa'),{'status':_0x38df85,..._0x4f92a9,'timestamp':new Date()['toISOString']()});}['startHeartbeat'](_0x2515a6){_0x2515a6['heartbeatTimer']=setInterval(()=>{const _0x3c4d0a=a0_0x545e;if(!_0x2515a6['transport']||_0x2515a6['transport'][_0x3c4d0a(0x2fa,'8iXp')]){this['unbind'](_0x2515a6['id']);return;}try{_0x2515a6['transport']['write'](':\x20heartbeat\x0a\x0a');}catch{this['unbind'](_0x2515a6['id']);}},this['options']['heartbeatIntervalMs']);}[a0_0xc96691(0x3a2,'cH7W')](_0x386ab6){const _0x1f8e8f=a0_0xc96691;_0x386ab6[_0x1f8e8f(0x44d,'4TBd')]&&(clearInterval(_0x386ab6['heartbeatTimer']),_0x386ab6[_0x1f8e8f(0x43e,'N%Da')]=null);}[a0_0xc96691(0x314,'XE3M')](_0x22174e){return this['sessions']['get'](_0x22174e);}['has'](_0x18b1ae){return this['sessions']['has'](_0x18b1ae);}get['size'](){const _0x2e529a=a0_0xc96691;return this[_0x2e529a(0x3b8,'ToP^')]['size'];}get[a0_0xc96691(0x40b,'7@1%')](){const _0x4453b5=a0_0xc96691;let _0x3fd5e8=0x0;for(const _0x184d40 of this[_0x4453b5(0x1d4,'cH7W')]['values']()){if(_0x184d40['state']===_0x4453b5(0x2bb,'7@1%'))_0x3fd5e8++;}return _0x3fd5e8;}get[a0_0xc96691(0x2ce,'DrN%')](){const _0x4cf8a0=a0_0xc96691;return Array[_0x4cf8a0(0x490,'AmkZ')](this[_0x4cf8a0(0x12d,'7@1%')]['values']());}['destroyAll'](_0x8cc745='Server\x20shutting\x20down'){const _0x45e20e=a0_0xc96691,_0x484bf0=getLogger(),_0x40cc5d={};_0x40cc5d[_0x45e20e(0x3d0,'QX29')]=this[_0x45e20e(0x3d7,'N%Da')]['size'],_0x484bf0[_0x45e20e(0x24a,'N%Da')](_0x40cc5d,'[session]\x20Destroying\x20all\x20sessions');for(const _0xa58220 of this['sessions']['values']()){this[_0x45e20e(0x3c2,'%nTx')](_0xa58220);if(_0xa58220[_0x45e20e(0x389,'^lJJ')])clearTimeout(_0xa58220['expiryTimer']);if(_0xa58220[_0x45e20e(0x253,'^N!&')]&&!_0xa58220[_0x45e20e(0x412,'B(Hf')]['writableEnded'])try{const _0x195182={};_0x195182[_0x45e20e(0x23a,'vQ1Q')]=_0x8cc745,_0xa58220[_0x45e20e(0x47d,'k6M)')]['write'](_0x45e20e(0x214,'^lJJ')+JSON['stringify'](_0x195182)+'\x0a\x0a'),_0xa58220['transport']['end']();}catch{}}this['sessions'][_0x45e20e(0x348,'%nTx')]();}},HealthMonitor=class{[a0_0xc96691(0x1d6,'fR1R')];[a0_0xc96691(0x15b,'OeEa')];['version'];[a0_0xc96691(0x35e,'eONb')];[a0_0xc96691(0x470,'JUp6')];constructor(_0x431a54){const _0x3db511=a0_0xc96691;this[_0x3db511(0x1ed,'^lJJ')]=_0x431a54[_0x3db511(0x336,'svnM')],this['sessions']=_0x431a54['sessions'],this[_0x3db511(0x21a,'N%Da')]=_0x431a54['version'],this[_0x3db511(0x30b,'uX3F')]=_0x431a54[_0x3db511(0x277,'D@Jg')],this['ngrokUrl']=_0x431a54[_0x3db511(0x12e,'30)t')];}['report'](){const _0x51f7ec=a0_0xc96691,_0x5f3f50=process[_0x51f7ec(0x1f0,'fR1R')](),_0x141b23={};_0x141b23['supervisorStatus']=this[_0x51f7ec(0x11c,'yUR%')][_0x51f7ec(0x46e,'GrlK')],_0x141b23['running']=this[_0x51f7ec(0x1ed,'^lJJ')][_0x51f7ec(0x437,'AmkZ')],_0x141b23['pid']=this['bridge']['pid']??null,_0x141b23[_0x51f7ec(0x195,'uX3F')]=this['bridge'][_0x51f7ec(0x28d,'!)DA')],_0x141b23['totalRestarts']=this['bridge'][_0x51f7ec(0x353,'V&f(')],_0x141b23[_0x51f7ec(0x379,'TUy$')]=this['bridge']['queueSize'],_0x141b23['queueMetrics']=this['bridge']['queueMetrics'];const _0x25de18=_0x141b23,_0x302775={};_0x302775['total']=this[_0x51f7ec(0x2bd,'svnM')]['size'],_0x302775[_0x51f7ec(0x1f1,'D@Jg')]=this[_0x51f7ec(0x3e0,']cW@')]['connectedCount'];const _0x20d8a5=_0x302775,_0x139ccf={'connected':this[_0x51f7ec(0x352,'TUy$')](),'url':this[_0x51f7ec(0x20c,'DrN%')]()};let _0x6a30d8='healthy';if(_0x25de18['supervisorStatus']==='failed')_0x6a30d8='unhealthy';else{if(_0x25de18['supervisorStatus']==='stopped')_0x6a30d8='unhealthy';else{if(!_0x25de18['running']&&_0x25de18[_0x51f7ec(0x125,'V&f(')]==='restarting')_0x6a30d8=_0x51f7ec(0x2a3,'!)DA');else!_0x139ccf[_0x51f7ec(0x324,'yO(Q')]&&(_0x6a30d8='degraded');}}return{'status':_0x6a30d8,'uptime':process[_0x51f7ec(0x2bc,'yUR%')](),'timestamp':new Date()[_0x51f7ec(0x146,'*f75')](),'gateway':{'version':this['version'],'pid':process['pid'],'memory':{'rss':formatBytes(_0x5f3f50[_0x51f7ec(0x219,'yL4y')]),'heapUsed':formatBytes(_0x5f3f50['heapUsed']),'heapTotal':formatBytes(_0x5f3f50[_0x51f7ec(0x153,'^N!&')])}},'mcp':_0x25de18,'sessions':_0x20d8a5,'ngrok':_0x139ccf};}[a0_0xc96691(0x322,'yO(Q')](){const _0x23412e=a0_0xc96691,_0x4cefa9=this[_0x23412e(0x142,'XE3M')]();return _0x4cefa9['status']!==_0x23412e(0x313,'XE3M');}};function formatBytes(_0x3ea2fa){const _0x252181=a0_0xc96691;if(_0x3ea2fa<0x400)return _0x3ea2fa+'\x20B';if(_0x3ea2fa<0x400*0x400)return(_0x3ea2fa/0x400)[_0x252181(0x3e1,']cW@')](0x1)+_0x252181(0x2fe,'30)t');return(_0x3ea2fa/(0x400*0x400))[_0x252181(0x185,'AmkZ')](0x1)+'\x20MB';}init_logger();import a0_0x42f3c1 from'crypto';function createAuthMiddleware(_0x4311ac){return function _0x334aed(_0x46e917,_0x3b1869,_0x4dae99){const _0x57f2dd=a0_0x545e,_0x654aeb=getLogger(),_0x5540b9=_0x46e917['headers']['authorization'];if(!_0x5540b9){const _0x578f2d={};_0x578f2d['ip']=_0x46e917['ip'],_0x578f2d[_0x57f2dd(0x32f,'D@Jg')]=_0x46e917['path'],_0x654aeb['warn'](_0x578f2d,_0x57f2dd(0x1dd,'%nTx'));const _0x4c2dde={};_0x4c2dde[_0x57f2dd(0x28c,'4TBd')]=_0x57f2dd(0x335,'d)Ik'),_0x3b1869[_0x57f2dd(0x37f,'30)t')](0x191)[_0x57f2dd(0x2de,'7@1%')](_0x4c2dde);return;}if(!_0x5540b9['startsWith'](_0x57f2dd(0x45b,']cW@'))){const _0x3c0f10={};_0x3c0f10['ip']=_0x46e917['ip'],_0x3c0f10[_0x57f2dd(0x320,'Jt&d')]=_0x46e917['path'],_0x654aeb[_0x57f2dd(0x2bf,'uX3F')](_0x3c0f10,'Rejected\x20request:\x20invalid\x20Authorization\x20format\x20(expected\x20Bearer)');const _0x6c99f5={};_0x6c99f5['error']=_0x57f2dd(0x1eb,'JUp6'),_0x3b1869['status'](0x191)[_0x57f2dd(0x2d8,'V&f(')](_0x6c99f5);return;}const _0x2a2bb8=_0x5540b9[_0x57f2dd(0x119,'[NGc')]('Bearer\x20'[_0x57f2dd(0x3cc,'fR1R')])['trim']();if(!isTokenValid(_0x2a2bb8,_0x4311ac)){const _0x1041a8={};_0x1041a8['ip']=_0x46e917['ip'],_0x1041a8['path']=_0x46e917[_0x57f2dd(0x19a,'8nSx')],_0x654aeb['warn'](_0x1041a8,'Rejected\x20request:\x20invalid\x20bearer\x20token');const _0x2a753d={};_0x2a753d[_0x57f2dd(0x22d,'cH7W')]='Unauthorized',_0x3b1869['status'](0x191)[_0x57f2dd(0x22a,'B(Hf')](_0x2a753d);return;}_0x4dae99();};}function isTokenValid(_0x46dcc2,_0x348e06){const _0x8d2688=a0_0xc96691;if(_0x46dcc2['length']!==_0x348e06[_0x8d2688(0x32d,'AmkZ')])return![];if(_0x46dcc2['length']===0x0)return![];try{const _0x555212=Buffer[_0x8d2688(0x16f,'eONb')](_0x46dcc2,_0x8d2688(0x2b4,'k6M)')),_0x2843ca=Buffer[_0x8d2688(0x42f,'yO(Q')](_0x348e06,_0x8d2688(0x177,'QX29'));return a0_0x42f3c1['timingSafeEqual'](_0x555212,_0x2843ca);}catch{return![];}}init_logger();function createApp(_0x112eff){const _0x187610=a0_0xc96691,{bridge:_0x30c732,bearerToken:_0x32a773,corsOrigins:_0x71286b,protectHealth:_0x71a309,allowSseQueryToken:_0x815074,ngrokConnected:_0x42879f,ngrokUrl:_0x3cd770,version:version='2026.06.1101',sessionTtlMs:sessionTtlMs=0x5*0xea60}=_0x112eff,_0x34acea=getLogger(),_0x3060df=a0_0x4a095f();_0x3060df['set']('trust\x20proxy',!![]);const _0x29f635={};_0x29f635['sessionTtlMs']=sessionTtlMs;const _0x420e93=new SessionManager(_0x29f635),_0x3ddab1={};_0x3ddab1['bridge']=_0x30c732,_0x3ddab1[_0x187610(0x3e0,']cW@')]=_0x420e93,_0x3ddab1[_0x187610(0x451,'^N!&')]=version,_0x3ddab1[_0x187610(0x2ec,'svnM')]=_0x42879f,_0x3ddab1['ngrokUrl']=_0x3cd770;const _0x51e218=new HealthMonitor(_0x3ddab1);if(_0x71286b[_0x187610(0x328,'4TBd')]>0x0){const _0x5d9ca4={};_0x5d9ca4['origin']=_0x71286b['length']===0x1&&_0x71286b[0x0]==='*'?'*':_0x71286b,_0x5d9ca4[_0x187610(0x48e,'^lJJ')]=[_0x187610(0x121,'QX29'),'POST',_0x187610(0x20f,'VDXI')],_0x5d9ca4[_0x187610(0x27e,'D@Jg')]=['Authorization',_0x187610(0x4a0,'ToP^'),_0x187610(0x2b5,'nsSN')],_0x5d9ca4['exposedHeaders']=['X-Session-ID'],_0x3060df[_0x187610(0x3d3,'nsSN')](a0_0x5c7457(_0x5d9ca4));}const _0xd633be={};_0xd633be[_0x187610(0x110,'^lJJ')]='1mb',_0x3060df[_0x187610(0x3e2,'8nSx')](a0_0x4a095f[_0x187610(0x3e4,'d)Ik')](_0xd633be)),_0x3060df['use']((_0x225a72,_0x3881bf,_0x4099b7)=>{const _0x3d39c1=_0x187610,_0x390f90={};_0x390f90[_0x3d39c1(0x414,'JUp6')]=_0x225a72[_0x3d39c1(0x394,'svnM')],_0x390f90[_0x3d39c1(0x295,'DrN%')]=_0x225a72[_0x3d39c1(0x2cf,'4TBd')],_0x390f90['ip']=_0x225a72['ip'],_0x34acea[_0x3d39c1(0x11f,'yL4y')](_0x390f90,'→\x20request'),_0x4099b7();});const _0x1304a1=createAuthMiddleware(_0x32a773),_0x1a4d94=(_0x1e54ca,_0x3b0d63,_0x2315fd)=>{const _0x2c8d67=_0x187610,_0x11444c=_0x1e54ca['headers'][_0x2c8d67(0x215,'QX29')]?.['replace'](/^Bearer\s+/i,''),_0x4b0748=_0x815074?_0x1e54ca[_0x2c8d67(0x329,'GrlK')][_0x2c8d67(0x228,'Rq!U')]:void 0x0,_0x2aa112=_0x11444c??_0x4b0748;if(!_0x2aa112){const _0x19db03={};_0x19db03['error']='Unauthorized',_0x3b0d63[_0x2c8d67(0x160,'AmkZ')](0x191)[_0x2c8d67(0x4b4,'30)t')](_0x19db03);return;}try{const _0x220a85=Buffer[_0x2c8d67(0x449,'Rq!U')](_0x32a773,_0x2c8d67(0x430,'30)t')),_0x38d431=Buffer['from'](_0x2aa112,_0x2c8d67(0x174,'S!i)'));if(_0x220a85['length']!==_0x38d431[_0x2c8d67(0x350,']cW@')]||!a0_0x4ef407[_0x2c8d67(0x46c,'@QVa')](_0x220a85,_0x38d431)){const _0x5e53b1={};_0x5e53b1[_0x2c8d67(0x32a,'N%Da')]=_0x2c8d67(0x1e8,'%nTx'),_0x3b0d63['status'](0x191)[_0x2c8d67(0x36b,'QX29')](_0x5e53b1);return;}}catch{const _0x1a2a1a={};_0x1a2a1a['error']='Unauthorized',_0x3b0d63[_0x2c8d67(0x280,'ZiR@')](0x191)[_0x2c8d67(0x292,'uX3F')](_0x1a2a1a);return;}_0x2315fd();};_0x30c732['on']('notification',_0x1f8e6e=>{const _0x3312e8=_0x187610;_0x420e93[_0x3312e8(0x36c,'svnM')]>0x0&&_0x420e93['broadcast'](_0x3312e8(0x42b,'vQ1Q'),_0x1f8e6e);}),_0x30c732['on'](_0x187610(0x3af,'ZiR@'),(_0x15a12c,_0x2c6dcc,_0x4b890b)=>{const _0x101d88=_0x187610,_0x179e5d={};_0x179e5d['status']=_0x15a12c,_0x179e5d['pid']=_0x2c6dcc,_0x179e5d['restartCount']=_0x4b890b,_0x34acea[_0x101d88(0x1c8,'!)DA')](_0x179e5d,_0x101d88(0x245,'@QVa'));const _0x208057={};_0x208057['pid']=_0x2c6dcc,_0x208057[_0x101d88(0x409,'cH7W')]=_0x4b890b,_0x420e93['broadcastSupervisorStatus'](_0x15a12c,_0x208057);}),_0x30c732['on'](_0x187610(0x2cc,'8nSx'),()=>{const _0x8d5064=_0x187610;_0x420e93[_0x8d5064(0x13d,'@QVa')](_0x8d5064(0x275,'!)DA'),{'message':_0x8d5064(0x444,'OeEa'),'timestamp':new Date()[_0x8d5064(0x184,'N%Da')]()});}),_0x3060df[_0x187610(0x270,'7@1%')]('/',(_0x1c3fe5,_0x328f67)=>{const _0x5f4cf6=_0x187610,_0x2d4f83={};_0x2d4f83[_0x5f4cf6(0x46d,'fR1R')]=_0x5f4cf6(0x18c,'uX3F'),_0x2d4f83['sse']='GET\x20/sse',_0x2d4f83[_0x5f4cf6(0x415,'VDXI')]=_0x5f4cf6(0x31e,'uX3F'),_0x2d4f83['health']='GET\x20/health';const _0x466904={};_0x466904[_0x5f4cf6(0x163,'8iXp')]=_0x30c732['supervisorStatus'],_0x466904[_0x5f4cf6(0x156,'OeEa')]=_0x30c732['isRunning'],_0x328f67['json']({'name':'remote-mcp-ngrok','version':version,'description':'Resilient\x20remote\x20MCP\x20gateway\x20over\x20HTTP\x20+\x20Ngrok','endpoints':_0x2d4f83,'publicUrl':_0x3cd770(),'mcp':_0x466904});}),_0x3060df[_0x187610(0x3b3,'2Voh')](_0x187610(0x285,'uX3F'),..._0x71a309?[_0x1304a1]:[],(_0x5db5cc,_0x310fbd)=>{const _0x577d9f=_0x187610,_0x2ad4ef=_0x51e218['report'](),_0x428748=_0x2ad4ef[_0x577d9f(0x139,'Rq!U')]===_0x577d9f(0x1b5,'gOga')?0x1f7:0xc8;_0x310fbd['status'](_0x428748)['json'](_0x2ad4ef);}),_0x3060df[_0x187610(0x387,'@QVa')](_0x187610(0x11d,'AmkZ'),_0x1304a1,async(_0x3ac6c7,_0x5202f1)=>{const _0xdc9f60=_0x187610,_0x291667=_0x3ac6c7[_0xdc9f60(0x2e2,'cH7W')],_0x138879=McpRequestSchema['safeParse'](_0x291667);if(!_0x138879['success']){const _0x2c64a2={};_0x2c64a2['code']=-0x7f58,_0x2c64a2[_0xdc9f60(0x345,'!mXe')]='Invalid\x20Request',_0x2c64a2[_0xdc9f60(0x1a9,'N%Da')]=_0x138879[_0xdc9f60(0x3ba,'yL4y')][_0xdc9f60(0x126,'Jt&d')];const _0x37f9da={};_0x37f9da['jsonrpc']=_0xdc9f60(0x273,'TUy$'),_0x37f9da['id']=null,_0x37f9da['error']=_0x2c64a2,_0x5202f1['status'](0x190)[_0xdc9f60(0x1a7,'XE3M')](_0x37f9da);return;}try{const _0xe7af4e=await _0x30c732['sendRequest'](_0x138879['data']);_0x5202f1['json'](_0xe7af4e);}catch(_0x23b800){const _0xf5d334=_0x23b800,_0x36788d={};_0x36788d['err']=_0xf5d334[_0xdc9f60(0x15f,'yL4y')],_0x36788d[_0xdc9f60(0x2c0,'7@1%')]=_0x138879['data']['method'],_0x34acea[_0xdc9f60(0x36a,'@QVa')](_0x36788d,_0xdc9f60(0x157,'B(Hf'));const _0x14cd89=_0xf5d334['message'][_0xdc9f60(0x4a3,'^N!&')]('timeout'),_0x36fc96=_0xf5d334[_0xdc9f60(0x276,'yO(Q')][_0xdc9f60(0x339,'!)DA')](_0xdc9f60(0x2d7,'ToP^'))||_0xf5d334['message']['includes'](_0xdc9f60(0x190,'cH7W'))||_0xf5d334['message'][_0xdc9f60(0x30f,'%nTx')](_0xdc9f60(0x347,'GrlK')),_0x475f0b=_0x14cd89?0x1f8:_0x36fc96?0x1f7:0x1f4,_0x1ab624=_0x14cd89?-0x7d01:_0x36fc96?-0x7d02:-0x7f5b,_0x409031=_0x14cd89?_0xdc9f60(0x3cb,'N%Da'):_0x36fc96?_0xdc9f60(0x249,'!)DA'):_0xdc9f60(0x17e,'JUp6'),_0x35b33f={};_0x35b33f[_0xdc9f60(0x19c,'yO(Q')]=_0x1ab624,_0x35b33f['message']=_0x409031,_0x35b33f['data']=_0xf5d334['message'];const _0x54c9e1={};_0x54c9e1[_0xdc9f60(0x3be,'uX3F')]='2.0',_0x54c9e1['id']=_0x138879[_0xdc9f60(0x355,'uX3F')]['id']??null,_0x54c9e1[_0xdc9f60(0x234,'TUy$')]=_0x35b33f,_0x5202f1['status'](_0x475f0b)[_0xdc9f60(0x390,'4TBd')](_0x54c9e1);}}),_0x3060df['get']('/sse',_0x1a4d94,(_0x7dd3b2,_0xd3bd6)=>{const _0x52d33e=_0x187610;_0xd3bd6[_0x52d33e(0x1be,'TUy$')](_0x52d33e(0x3e7,'GrlK'),_0x52d33e(0x3d1,'Jt&d')),_0xd3bd6[_0x52d33e(0x16b,'7@1%')]('Cache-Control',_0x52d33e(0x268,'vQ1Q')),_0xd3bd6[_0x52d33e(0x158,'!)DA')]('Connection',_0x52d33e(0x186,'V&f(')),_0xd3bd6['setHeader']('X-Accel-Buffering','no'),_0xd3bd6[_0x52d33e(0x225,'svnM')]();const _0x40bdab=_0x420e93['create'](_0x52d33e(0x344,'S!i)')+(_0x7dd3b2['ip']??_0x52d33e(0x255,'yL4y')));_0xd3bd6[_0x52d33e(0x1be,'TUy$')]('X-Session-ID',_0x40bdab['id']),_0x420e93[_0x52d33e(0x301,'D@Jg')](_0x40bdab['id'],_0xd3bd6);const _0x321d41={};_0x321d41['sessionId']=_0x40bdab['id'],_0x321d41['ip']=_0x7dd3b2['ip'],_0x34acea['info'](_0x321d41,_0x52d33e(0x384,'eONb')),_0xd3bd6[_0x52d33e(0x29a,'!mXe')](_0x52d33e(0x31d,'Jt&d')+JSON[_0x52d33e(0x1ef,'8iXp')]({'sessionId':_0x40bdab['id'],'supervisorStatus':_0x30c732['supervisorStatus'],'mcpRunning':_0x30c732[_0x52d33e(0x3bd,'DrN%')],'timestamp':new Date()['toISOString'](),'reconnectUrl':_0x52d33e(0x3c5,'yL4y')})+'\x0a\x0a'),!_0x30c732[_0x52d33e(0x1a2,'QX29')]&&_0xd3bd6[_0x52d33e(0x4a4,'fR1R')](_0x52d33e(0x303,']cW@')+JSON['stringify']({'status':_0x30c732[_0x52d33e(0x4ae,'cH7W')],'pid':_0x30c732['pid']??null,'restartCount':_0x30c732[_0x52d33e(0x40e,'8nSx')],'timestamp':new Date()['toISOString']()})+'\x0a\x0a'),_0x7dd3b2['on']('close',()=>{const _0x3a43ac=_0x52d33e;_0x420e93[_0x3a43ac(0x3b0,'XE3M')](_0x40bdab['id']);const _0x41047e={};_0x41047e['sessionId']=_0x40bdab['id'],_0x34acea['info'](_0x41047e,_0x3a43ac(0x2b7,'!)DA'));}),_0x7dd3b2['on'](_0x52d33e(0x23f,'nsSN'),()=>{_0x420e93['unbind'](_0x40bdab['id']);});}),_0x3060df[_0x187610(0x396,'%nTx')]('/sse/reconnect',_0x1a4d94,(_0x1181ed,_0x275600)=>{const _0xc638c5=_0x187610,_0x506065=_0x1181ed['query'][_0xc638c5(0x167,'^N!&')];if(!_0x506065){const _0x2160f1={};_0x2160f1['error']=_0xc638c5(0x166,'JUp6'),_0x2160f1[_0xc638c5(0x3df,'GrlK')]=_0xc638c5(0x1bc,'OeEa'),_0x275600[_0xc638c5(0x1b6,'^lJJ')](0x190)[_0xc638c5(0x4a7,'ToP^')](_0x2160f1);return;}const _0x30a7f2=_0x420e93['get'](_0x506065);if(!_0x30a7f2){const _0x208c90={};_0x208c90[_0xc638c5(0x3ad,'uX3F')]='Session\x20expired\x20or\x20not\x20found',_0x208c90['hint']='Connect\x20to\x20/sse\x20to\x20create\x20a\x20new\x20session',_0x208c90['code']=_0xc638c5(0x20a,'D@Jg'),_0x275600[_0xc638c5(0x468,'%nTx')](0x19a)[_0xc638c5(0x2d8,'V&f(')](_0x208c90);return;}_0x275600[_0xc638c5(0x115,'DrN%')](_0xc638c5(0x1f9,'^N!&'),'text/event-stream'),_0x275600[_0xc638c5(0x47e,'2Voh')](_0xc638c5(0x1fe,'fR1R'),_0xc638c5(0x259,'DrN%')),_0x275600['setHeader'](_0xc638c5(0x140,'8iXp'),'keep-alive'),_0x275600['setHeader'](_0xc638c5(0x1b4,'8nSx'),'no'),_0x275600[_0xc638c5(0x321,'d)Ik')](_0xc638c5(0x24f,'30)t'),_0x506065),_0x275600[_0xc638c5(0x29d,'gOga')]();const _0x4dfbe4=_0x420e93['bind'](_0x506065,_0x275600);if(!_0x4dfbe4){const _0x3b3af8={};_0x3b3af8['error']='Failed\x20to\x20rebind\x20session',_0x275600[_0xc638c5(0x45e,'%nTx')](_0xc638c5(0x391,'!)DA')+JSON['stringify'](_0x3b3af8)+'\x0a\x0a'),_0x275600[_0xc638c5(0x1bb,'yUR%')]();return;}const _0x4ca836={};_0x4ca836[_0xc638c5(0x254,'uX3F')]=_0x506065,_0x4ca836[_0xc638c5(0x1c0,'!)DA')]=_0x30a7f2['reconnectCount'],_0x34acea[_0xc638c5(0x168,'Rq!U')](_0x4ca836,'[gateway]\x20SSE\x20session\x20transport\x20rebound\x20(reconnected)'),_0x275600[_0xc638c5(0x417,'8nSx')]('event:\x20reconnected\x0adata:\x20'+JSON[_0xc638c5(0x1a3,'nsSN')]({'sessionId':_0x506065,'reconnectCount':_0x30a7f2[_0xc638c5(0x47c,'[NGc')],'supervisorStatus':_0x30c732[_0xc638c5(0x462,'TUy$')],'mcpRunning':_0x30c732['isRunning'],'timestamp':new Date()['toISOString']()})+'\x0a\x0a'),_0x275600['write']('event:\x20mcp-status\x0adata:\x20'+JSON[_0xc638c5(0x2d9,'&nMv')]({'status':_0x30c732[_0xc638c5(0x125,'V&f(')],'pid':_0x30c732['pid']??null,'restartCount':_0x30c732['restartCount'],'timestamp':new Date()[_0xc638c5(0x1a4,'d)Ik')]()})+'\x0a\x0a'),_0x1181ed['on']('close',()=>{const _0x165f78=_0xc638c5;_0x420e93[_0x165f78(0x26f,'yUR%')](_0x506065);const _0x55da0b={};_0x55da0b['sessionId']=_0x506065,_0x34acea['info'](_0x55da0b,_0x165f78(0x33e,'VDXI'));}),_0x1181ed['on']('error',()=>{const _0x34cdd7=_0xc638c5;_0x420e93[_0x34cdd7(0x416,'2Voh')](_0x506065);});}),_0x3060df['get'](_0x187610(0x10a,'XE3M'),_0x1304a1,(_0x3e20de,_0x25e2f3)=>{const _0xf856f3=_0x187610,_0x8574ba=_0x420e93[_0xf856f3(0x419,'VDXI')][_0xf856f3(0x3de,'nsSN')](_0x161d95=>({'id':_0x161d95['id'],'label':_0x161d95['label'],'state':_0x161d95[_0xf856f3(0x229,'k6M)')],'createdAt':_0x161d95[_0xf856f3(0x251,'B(Hf')],'lastConnectedAt':_0x161d95['lastConnectedAt'],'lastDisconnectedAt':_0x161d95['lastDisconnectedAt'],'reconnectCount':_0x161d95['reconnectCount']})),_0x295126={};_0x295126[_0xf856f3(0x45f,'GrlK')]=_0x8574ba['length'],_0x295126['sessions']=_0x8574ba,_0x25e2f3['json'](_0x295126);}),_0x3060df['use']((_0x23435e,_0x12be39)=>{const _0x2629cd={};_0x2629cd['error']='Not\x20found',_0x12be39['status'](0x194)['json'](_0x2629cd);}),_0x3060df['use']((_0x302e86,_0x2d86fe,_0x2850ba,_0x57dcc1)=>{const _0x248c49=_0x187610,_0x581f58={};_0x581f58['err']=_0x302e86['message'],_0x34acea[_0x248c49(0x408,'k6M)')](_0x581f58,'Unhandled\x20Express\x20error');const _0x2e6a70={};_0x2e6a70['error']=_0x248c49(0x362,'N%Da'),_0x2850ba[_0x248c49(0x127,'VDXI')](0x1f4)['json'](_0x2e6a70);});const _0x3060c1={};return _0x3060c1[_0x187610(0x1e6,'TUy$')]=_0x3060df,_0x3060c1['sessions']=_0x420e93,_0x3060c1['health']=_0x51e218,_0x3060c1;}function startServer(_0x11e539,_0x1e6587,_0x1d4ac8){return new Promise((_0x24e209,_0x24f4d5)=>{const _0x3abcc7=a0_0x545e,_0x5e8a97=_0x11e539['listen'](_0x1e6587,_0x1d4ac8,()=>{_0x24e209(_0x5e8a97);});_0x5e8a97['on']('error',_0x461c6b=>{const _0x30654f=a0_0x545e;_0x461c6b[_0x30654f(0x4b8,'^N!&')]===_0x30654f(0x3d2,'ToP^')?_0x24f4d5(new Error(_0x30654f(0x237,'8iXp')+_0x1e6587+'\x20is\x20already\x20in\x20use.\x20Use\x20--port\x20to\x20choose\x20another.')):_0x24f4d5(_0x461c6b);}),_0x5e8a97['keepAliveTimeout']=0x15f90,_0x5e8a97[_0x3abcc7(0x41b,'Jt&d')]=0x17318;});}function stopServer(_0x3906b2){return new Promise(_0x408b34=>{_0x3906b2['close'](()=>_0x408b34());});}init_logger();import*as a0_0x21f2c1 from'@ngrok/ngrok';var _listener=null,_connected=![],_publicUrl=null;async function startNgrokTunnel(_0x80fb){const _0x2e21a7=a0_0xc96691,_0x298e33=getLogger(),_0x20b81f={};_0x20b81f['domain']=_0x80fb[_0x2e21a7(0x40d,'$W(9')],_0x298e33['info'](_0x20b81f,'Connecting\x20to\x20Ngrok...');try{const _0x5a4fe7={};_0x5a4fe7['authtoken']=_0x80fb['authtoken'],_0x5a4fe7[_0x2e21a7(0x17f,'Jt&d')]=_0x80fb['addr'],_0x5a4fe7[_0x2e21a7(0x38b,'k6M)')]=_0x80fb[_0x2e21a7(0x2ae,'eONb')];const _0x4a3a92=await a0_0x21f2c1['connect'](_0x5a4fe7),_0xafad76=_0x4a3a92[_0x2e21a7(0x2e9,'V&f(')]();if(!_0xafad76)throw new Error('Ngrok\x20tunnel\x20started\x20but\x20no\x20URL\x20was\x20returned.');_listener=_0x4a3a92,_connected=!![],_publicUrl=_0xafad76;const _0x3098bf={};return _0x3098bf[_0x2e21a7(0x2e9,'V&f(')]=_0xafad76,_0x298e33['info'](_0x3098bf,_0x2e21a7(0x29f,'30)t')),{'url':_0xafad76,'close':async()=>{await closeNgrokTunnel();}};}catch(_0x33b836){const _0x3b5d39=_0x33b836;_connected=![];const _0x58f5b8=_0x3b5d39[_0x2e21a7(0x271,'ZiR@')]??String(_0x3b5d39);if(_0x58f5b8['includes']('authentication\x20failed')||_0x58f5b8[_0x2e21a7(0x1b7,'nsSN')](_0x2e21a7(0x406,'fR1R'))||_0x58f5b8[_0x2e21a7(0x3ec,'svnM')](_0x2e21a7(0x269,'AmkZ')))throw new Error('Ngrok\x20authentication\x20failed.\x20Check\x20your\x20--ngrok-authtoken\x20value.\x0a\x20\x20Detail:\x20'+_0x58f5b8);if(_0x58f5b8[_0x2e21a7(0x263,'QX29')]('is\x20already\x20bound')||_0x58f5b8['includes'](_0x2e21a7(0x208,'4TBd'))||_0x58f5b8[_0x2e21a7(0x2c5,'^lJJ')]('ERR_NGROK_302')||_0x58f5b8['includes']('ERR_NGROK_8012'))throw new Error(_0x2e21a7(0x3c6,'D@Jg')+_0x80fb['domain']+_0x2e21a7(0x1e4,'S!i)')+_0x58f5b8);if(_0x58f5b8['includes']('domain\x20not\x20found')||_0x58f5b8[_0x2e21a7(0x1fb,'N%Da')](_0x2e21a7(0x377,'*f75'))||_0x58f5b8[_0x2e21a7(0x1ca,'ZiR@')](_0x2e21a7(0x117,'4TBd')))throw new Error(_0x2e21a7(0x36f,'XE3M')+_0x80fb[_0x2e21a7(0x44a,'cH7W')]+_0x2e21a7(0x45c,'gOga')+_0x58f5b8);throw new Error('Ngrok\x20connection\x20failed:\x20'+_0x58f5b8);}}async function closeNgrokTunnel(){const _0x2579b1=a0_0xc96691,_0x53e789=getLogger();if(_listener){try{await _listener[_0x2579b1(0x2dd,'!mXe')](),_0x53e789['info']('Ngrok\x20tunnel\x20closed');}catch(_0x3e76e7){const _0x942caa={};_0x942caa[_0x2579b1(0x246,'yUR%')]=_0x3e76e7,_0x53e789['warn'](_0x942caa,_0x2579b1(0x244,'D@Jg'));}_listener=null;}_connected=![],_publicUrl=null;}var PACKAGE_VERSION=a0_0xc96691(0x2e8,'!mXe');async function runCli(_0xe25f56){const _0x428413=a0_0xc96691,_0x549136=new Command();_0x549136[_0x428413(0x441,'^N!&')]('remote-mcp-ngrok')['description']('Resilient\x20remote\x20MCP\x20gateway\x20—\x20expose\x20local\x20MCP\x20stdio\x20servers\x20over\x20the\x20internet\x20with\x20auto-recovery')['version'](PACKAGE_VERSION)['option'](_0x428413(0x1f4,'DrN%'),'Local\x20HTTP\x20server\x20port','8000')['option'](_0x428413(0x466,'$W(9'),_0x428413(0x483,'*f75'),'127.0.0.1')['option']('--stdio\x20<command>',_0x428413(0x37a,'cH7W'))['option'](_0x428413(0x11a,'GrlK'),'MCP\x20executable\x20(alternative\x20to\x20--stdio)')[_0x428413(0x3d8,'AmkZ')]('--args\x20<args...>','MCP\x20arguments\x20(used\x20with\x20--command)')[_0x428413(0x310,'XE3M')](_0x428413(0x49f,'nsSN'),_0x428413(0x32c,'gOga'))[_0x428413(0x368,'DrN%')](_0x428413(0x2b8,'OeEa'),_0x428413(0x1c2,'!mXe'))['option'](_0x428413(0x315,'[NGc'),'Bearer\x20token\x20for\x20HTTP\x20authentication\x20(auto-generated\x20if\x20omitted)')['option']('--protect-health','Require\x20authentication\x20on\x20/health\x20endpoint')[_0x428413(0x3c3,'eONb')](_0x428413(0x278,'Jt&d'),'Allow\x20SSE\x20auth\x20via\x20?token=\x20query\x20param\x20(default:\x20true)')[_0x428413(0x243,'yO(Q')](_0x428413(0x13c,'d)Ik'),'CORS\x20allowed\x20origins\x20(use\x20*\x20for\x20all,\x20or\x20space-separated\x20list)')['option']('--env\x20<KEY=VALUE...>','Environment\x20variables\x20to\x20inject\x20into\x20MCP\x20process\x20(repeatable)')[_0x428413(0x492,'svnM')](_0x428413(0x12a,'2Voh'),'MCP\x20request\x20timeout\x20in\x20milliseconds',_0x428413(0x1b2,'VDXI'))['option'](_0x428413(0x4b6,'JUp6'),'Max\x20concurrent\x20MCP\x20requests\x20(default:\x201\x20for\x20sequential)','1')[_0x428413(0x368,'DrN%')](_0x428413(0x380,'eONb'),_0x428413(0x36d,'D@Jg'),'10')['option']('--restart-window\x20<ms>','Sliding\x20window\x20for\x20counting\x20restarts\x20(default:\x2060000ms)','60000')['option'](_0x428413(0x28e,'QX29'),_0x428413(0x28b,'7@1%'),_0x428413(0x31f,'^lJJ'))[_0x428413(0x49b,'$W(9')](_0x428413(0x3a4,'S!i)'),_0x428413(0x446,'GrlK'),'300000')['option']('--debug',_0x428413(0x4ab,'$Vfi'))['option'](_0x428413(0x459,'uX3F'),'Log\x20raw\x20MCP\x20packets\x20(useful\x20for\x20debugging)')['option'](_0x428413(0x30d,'$W(9'),'Path\x20to\x20YAML\x20or\x20JSON\x20config\x20file'),_0x549136['parse'](_0xe25f56);const _0x34555d=_0x549136['opts'](),_0x395522=loadConfigFile(_0x34555d[_0x428413(0x499,'[NGc')]),_0x417e3b=Boolean(_0x34555d['debug'])||_0x395522['debug']===!![],_0x32905d=Boolean(_0x34555d[_0x428413(0x1d5,'cH7W')])||_0x395522['traceMcp']===!![],_0x33845a={};_0x33845a[_0x428413(0x361,'QX29')]=_0x417e3b,_0x33845a['traceMcp']=_0x32905d;const _0x130c8b=createLogger(_0x33845a),_0x33ca21=parseInt(String(_0x34555d[_0x428413(0x162,'svnM')]??_0x395522[_0x428413(0x3ab,'!)DA')]??process.env['PORT']??'8000'),0xa),_0x4add28=_0x34555d[_0x428413(0x24e,'JUp6')]??_0x395522[_0x428413(0x3ee,'D@Jg')]??process.env['HOST']??'127.0.0.1',_0x2612dd=_0x34555d['stdio']??_0x395522[_0x428413(0x410,'!)DA')]??process.env['STDIO_COMMAND'],_0x567caa=_0x34555d[_0x428413(0x1de,'7@1%')]??_0x395522['command'],_0xaaebb2=_0x34555d[_0x428413(0x296,'!)DA')]??_0x395522['args']??[],_0x5a6022=_0x34555d['ngrokAuthtoken']??_0x395522['ngrokAuthtoken']??process.env['NGROK_AUTHTOKEN']??'',_0xe59461=_0x34555d[_0x428413(0x2a9,'S!i)')]??_0x395522['ngrokDomain']??process.env['NGROK_DOMAIN']??'';let _0x5d00ba=_0x34555d['bearerToken']??_0x395522['bearerToken']??process.env['BEARER_TOKEN']??'',_0x4f8865=![];!_0x5d00ba&&(_0x5d00ba=generateSecureToken(),_0x4f8865=!![]);const _0x3880a5=Boolean(_0x34555d[_0x428413(0x39c,'@QVa')])||_0x395522['protectHealth']===!![],_0x319f5f=_0x34555d[_0x428413(0x367,'ToP^')]??_0x395522['cors'];let _0x362607=[];_0x319f5f&&(_0x362607=Array['isArray'](_0x319f5f)?_0x319f5f:[_0x319f5f]);const _0x1e8181=parseInt(String(_0x34555d[_0x428413(0x486,'yUR%')]??_0x395522[_0x428413(0x488,'vQ1Q')]??_0x428413(0x489,'JUp6')),0xa),_0x55e9fd=parseInt(String(_0x34555d['concurrency']??_0x395522[_0x428413(0x1f3,'ZiR@')]??'1'),0xa),_0x1b7a8d=parseInt(String(_0x34555d[_0x428413(0x4b3,'eONb')]??_0x395522['maxRestarts']??'10'),0xa),_0x5be059=parseInt(String(_0x34555d[_0x428413(0x366,'vQ1Q')]??_0x395522['restartWindowMs']??_0x428413(0x3a7,'VDXI')),0xa),_0x5c03a9=parseInt(String(_0x34555d[_0x428413(0x3fe,'QX29')]??_0x395522['maxQueueDepth']??_0x428413(0x2e0,'OeEa')),0xa),_0x14c2d7=parseInt(String(_0x34555d['sessionTtl']??_0x395522[_0x428413(0x43c,'8iXp')]??'300000'),0xa),_0x4322fc=_0x34555d['allowSseQueryToken']!==![]&&_0x395522['allowSseQueryToken']!==![],_0x566b04=_0x34555d['env']??[],_0x5891bd=parseEnvVars(_0x566b04),_0x478533={..._0x395522['env']??{},..._0x5891bd},_0x353e27=_0x478533;!_0x2612dd&&!_0x567caa&&(_0x130c8b['error'](_0x428413(0x2fb,'XE3M')),_0x130c8b['error'](_0x428413(0x369,'vQ1Q')),process['exit'](0x1));!_0x5a6022&&(_0x130c8b['error']('Ngrok\x20auth\x20token\x20is\x20required.\x20Use\x20--ngrok-authtoken\x20or\x20set\x20NGROK_AUTHTOKEN\x20env\x20var.'),_0x130c8b[_0x428413(0x26b,'svnM')](_0x428413(0x463,'yUR%')),process['exit'](0x1));!_0xe59461&&(_0x130c8b[_0x428413(0x234,'TUy$')]('Ngrok\x20domain\x20is\x20required.\x20Use\x20--ngrok-domain\x20or\x20set\x20NGROK_DOMAIN\x20env\x20var.'),_0x130c8b['error']('Claim\x20a\x20free\x20static\x20domain\x20at:\x20https://dashboard.ngrok.com/cloud-edge/domains'),process['exit'](0x1));(isNaN(_0x33ca21)||_0x33ca21<0x1||_0x33ca21>0xffff)&&(_0x130c8b[_0x428413(0x399,'JUp6')](_0x428413(0x20d,'%nTx')+String(_0x34555d['port'])+'.\x20Must\x20be\x201–65535.'),process[_0x428413(0x1df,'30)t')](0x1));(isNaN(_0x1e8181)||_0x1e8181<0x3e8)&&(_0x130c8b['error']('Timeout\x20must\x20be\x20at\x20least\x201000ms.'),process['exit'](0x1));(isNaN(_0x55e9fd)||_0x55e9fd<0x1)&&(_0x130c8b[_0x428413(0x397,'yO(Q')](_0x428413(0x231,'svnM')),process[_0x428413(0x17a,'!mXe')](0x1));const _0x1d8b52={};_0x1d8b52['port']=_0x33ca21,_0x1d8b52[_0x428413(0x3bc,'30)t')]=_0x4add28,_0x1d8b52['stdio']=_0x2612dd,_0x1d8b52[_0x428413(0x2d6,'ToP^')]=_0x567caa,_0x1d8b52[_0x428413(0x3f2,'eONb')]=_0xaaebb2,_0x1d8b52['ngrokAuthtoken']=_0x5a6022,_0x1d8b52['ngrokDomain']=_0xe59461,_0x1d8b52['bearerToken']=_0x5d00ba,_0x1d8b52['debug']=_0x417e3b,_0x1d8b52['traceMcp']=_0x32905d,_0x1d8b52[_0x428413(0x1a0,'Rq!U')]=_0x362607,_0x1d8b52[_0x428413(0x282,'yL4y')]=_0x3880a5,_0x1d8b52[_0x428413(0x3b1,'$W(9')]=_0x4322fc,_0x1d8b52['timeoutMs']=_0x1e8181,_0x1d8b52[_0x428413(0x1bd,'uX3F')]=_0x55e9fd,_0x1d8b52['maxRestarts']=_0x1b7a8d,_0x1d8b52['restartWindowMs']=_0x5be059,_0x1d8b52['maxQueueDepth']=_0x5c03a9,_0x1d8b52['sessionTtlMs']=_0x14c2d7,_0x1d8b52[_0x428413(0x150,'^lJJ')]=_0x353e27,_0x1d8b52['generatedToken']=_0x4f8865;const _0x2f36a2=_0x1d8b52;_0x130c8b[_0x428413(0x124,'D@Jg')]('='['repeat'](0x3e)),_0x130c8b['info']('\x20\x20remote-mcp-ngrok\x20\x20—\x20\x20Resilient\x20Remote\x20MCP\x20Gateway'),_0x130c8b['info']('='[_0x428413(0x3a6,'vQ1Q')](0x3e));_0x4f8865&&(console['log'](_0x428413(0x2f9,'JUp6')),console[_0x428413(0x495,'2Voh')]('[SECURITY]\x20Bearer\x20token:\x20'+_0x5d00ba),console[_0x428413(0x1dc,'$Vfi')](_0x428413(0x2db,'OeEa')));const _0xc5e501={};_0xc5e501['port']=_0x33ca21,_0xc5e501['host']=_0x4add28,_0x130c8b[_0x428413(0x169,'fR1R')](_0xc5e501,_0x428413(0x26d,'Rq!U')),_0x130c8b['info']({'stdio':_0x2612dd??((_0x567caa??'')+'\x20'+_0xaaebb2[_0x428413(0x3b5,']cW@')]('\x20'))[_0x428413(0x112,'TUy$')]()},'MCP\x20command');const _0x46be18={};_0x46be18[_0x428413(0x222,'DrN%')]=_0xe59461,_0x130c8b['info'](_0x46be18,_0x428413(0x1cd,']cW@'));const _0x1643ef={};_0x1643ef[_0x428413(0x376,']cW@')]=_0x1b7a8d,_0x1643ef['restartWindowMs']=_0x5be059,_0x1643ef[_0x428413(0x152,'B(Hf')]=_0x5c03a9,_0x1643ef[_0x428413(0x30c,'ToP^')]=_0x14c2d7,_0x130c8b[_0x428413(0x2b2,'uX3F')](_0x1643ef,_0x428413(0x2c6,'TUy$')),Object[_0x428413(0x134,'V&f(')](_0x353e27)['length']>0x0&&_0x130c8b['info']({'env':buildMaskedEnvLog(_0x353e27)},'MCP\x20environment\x20variables\x20(secrets\x20masked)'),await runApp(_0x2f36a2);}async function runApp(_0x2c9381){const _0x13eb87=a0_0xc96691,{getLogger:_0x22dcd8}=await Promise['resolve']()[_0x13eb87(0x14a,'DrN%')](()=>(init_logger(),logger_exports)),_0x232066=_0x22dcd8();let _0x20e250=null,_0x55d1cd=null,_0x4521af=null,_0x532fe6=![],_0x4ee6f1=![],_0x2a1726=null;async function _0x542244(_0x50b320){const _0x1b9eb6=_0x13eb87;if(_0x532fe6)return;_0x532fe6=!![];const _0x7bed26={};_0x7bed26[_0x1b9eb6(0x1c9,'yUR%')]=_0x50b320,_0x232066[_0x1b9eb6(0x401,'8iXp')](_0x7bed26,'Shutdown\x20signal\x20received\x20—\x20cleaning\x20up...'),_0x4521af&&(_0x4521af['destroyAll']('Gateway\x20shutting\x20down'),_0x232066['info'](_0x1b9eb6(0x4af,'^lJJ'))),_0x55d1cd&&(await stopServer(_0x55d1cd),_0x232066[_0x1b9eb6(0x1af,'ToP^')]('HTTP\x20server\x20stopped')),await closeNgrokTunnel(),_0x232066['info'](_0x1b9eb6(0x281,'DrN%')),_0x20e250&&await _0x20e250[_0x1b9eb6(0x2c4,'Jt&d')](),_0x232066[_0x1b9eb6(0x1af,'ToP^')](_0x1b9eb6(0x317,'S!i)')),process['exit'](0x0);}process['on'](_0x13eb87(0x201,'&nMv'),()=>void _0x542244(_0x13eb87(0x1d3,'Rq!U'))),process['on']('SIGTERM',()=>void _0x542244(_0x13eb87(0x461,'4TBd')));if(process[_0x13eb87(0x3d4,'!)DA')]==='win32'){const _0x5f1ae8=await import(_0x13eb87(0x334,']cW@')),_0x598aea={};_0x598aea[_0x13eb87(0x22c,'%nTx')]=process['stdin'],_0x598aea['output']=process[_0x13eb87(0x38d,'QX29')];const _0x56c624=_0x5f1ae8['createInterface'](_0x598aea);_0x56c624['on']('SIGINT',()=>void _0x542244('SIGINT'));}_0x232066['info'](_0x13eb87(0x189,'uX3F'));const _0x47bca5={};_0x47bca5['stdio']=_0x2c9381['stdio'],_0x47bca5['command']=_0x2c9381['command'],_0x47bca5['args']=_0x2c9381[_0x13eb87(0x187,'^lJJ')],_0x47bca5[_0x13eb87(0x1e1,'[NGc')]=_0x2c9381['env'],_0x47bca5[_0x13eb87(0x164,'uX3F')]=_0x2c9381[_0x13eb87(0x484,'yL4y')],_0x47bca5['concurrency']=_0x2c9381['concurrency'],_0x47bca5[_0x13eb87(0x425,'OeEa')]=_0x2c9381[_0x13eb87(0x1e9,'nsSN')],_0x47bca5[_0x13eb87(0x2ed,'yO(Q')]=_0x2c9381['maxRestarts'],_0x47bca5['restartWindowMs']=_0x2c9381['restartWindowMs'],_0x47bca5[_0x13eb87(0x137,'uX3F')]=_0x2c9381['maxQueueDepth'],_0x20e250=new McpBridge(_0x47bca5),_0x20e250['on'](_0x13eb87(0x42d,'7@1%'),()=>{_0x232066['error']('MCP\x20supervisor\x20has\x20exceeded\x20maximum\x20restart\x20attempts.\x20Gateway\x20continues\x20running\x20but\x20MCP\x20is\x20unavailable.'),_0x232066['error']('Restart\x20remote-mcp-ngrok\x20to\x20recover.');}),_0x20e250['on']('supervisor-status',(_0x423442,_0x3bbe8f,_0x5b5c36)=>{const _0x15e989=_0x13eb87;if(_0x423442==='restarting'){const _0x13c2fa={};_0x13c2fa['pid']=_0x3bbe8f,_0x13c2fa['restartCount']=_0x5b5c36,_0x232066['warn'](_0x13c2fa,'MCP\x20process\x20restarting\x20—\x20requests\x20are\x20being\x20queued...');}else{if(_0x423442==='ready'){const _0x1e5164={};_0x1e5164['pid']=_0x3bbe8f,_0x1e5164[_0x15e989(0x22b,'ToP^')]=_0x5b5c36,_0x232066['info'](_0x1e5164,'MCP\x20process\x20ready\x20—\x20queue\x20draining\x20✓');}}}),await _0x20e250[_0x13eb87(0x418,'OeEa')]();const _0x4a94ce={};_0x4a94ce[_0x13eb87(0x194,'d)Ik')]=_0x20e250[_0x13eb87(0x171,'D@Jg')],_0x232066['info'](_0x4a94ce,'MCP\x20supervisor\x20ready\x20✓');const _0x403140={};_0x403140[_0x13eb87(0x496,'S!i)')]=_0x2c9381['port'],_0x403140['host']=_0x2c9381[_0x13eb87(0x272,'fR1R')],_0x232066['info'](_0x403140,'Starting\x20HTTP\x20gateway...');const _0x263b4e={};_0x263b4e['port']=_0x2c9381[_0x13eb87(0x39f,'Jt&d')],_0x263b4e['host']=_0x2c9381[_0x13eb87(0x3fd,'Rq!U')],_0x263b4e['bridge']=_0x20e250,_0x263b4e['bearerToken']=_0x2c9381[_0x13eb87(0x2b6,'^N!&')],_0x263b4e['corsOrigins']=_0x2c9381[_0x13eb87(0x1ce,'N%Da')],_0x263b4e['protectHealth']=_0x2c9381['protectHealth'],_0x263b4e[_0x13eb87(0x178,'QX29')]=_0x2c9381[_0x13eb87(0x21e,'XE3M')],_0x263b4e['ngrokConnected']=()=>_0x4ee6f1,_0x263b4e['ngrokUrl']=()=>_0x2a1726,_0x263b4e[_0x13eb87(0x2f1,'gOga')]=_0x13eb87(0x49c,'%nTx'),_0x263b4e['sessionTtlMs']=_0x2c9381['sessionTtlMs'];const {app:_0x3be523,sessions:_0x3644da}=createApp(_0x263b4e);_0x4521af=_0x3644da,_0x55d1cd=await startServer(_0x3be523,_0x2c9381['port'],_0x2c9381['host']);const _0x279b78={};_0x279b78['port']=_0x2c9381['port'],_0x279b78[_0x13eb87(0x19d,'yL4y')]=_0x2c9381['host'],_0x232066['info'](_0x279b78,_0x13eb87(0x35a,'uX3F')+_0x2c9381['host']+':'+_0x2c9381['port']),_0x232066['info']('Connecting\x20to\x20Ngrok...');const _0x12d657={};_0x12d657['authtoken']=_0x2c9381[_0x13eb87(0x14c,'V&f(')],_0x12d657[_0x13eb87(0x2a6,'vQ1Q')]=_0x2c9381['ngrokDomain'],_0x12d657['addr']=_0x2c9381[_0x13eb87(0x39f,'Jt&d')];const _0x4eed06=await startNgrokTunnel(_0x12d657);_0x4ee6f1=!![],_0x2a1726=_0x4eed06['url'];const _0x351e84=_0x4eed06['url']+_0x13eb87(0x318,'k6M)'),_0x2d9577=_0x4eed06[_0x13eb87(0x1c4,'QX29')]+_0x13eb87(0x32b,'S!i)'),_0x3c351c=_0x4eed06[_0x13eb87(0x48c,'k6M)')]+'/sse/reconnect',_0x38ff37=_0x4eed06['url']+'/health',_0x518f5e=_0x4eed06[_0x13eb87(0x176,'[NGc')]+'/sessions';console['log']('\x0a'+'='[_0x13eb87(0x1ba,'d)Ik')](0x3e)),console[_0x13eb87(0x473,'B(Hf')](_0x13eb87(0x23c,'ZiR@')),console['log']('='[_0x13eb87(0x41d,'ZiR@')](0x3e)),console['log'](_0x13eb87(0x4b9,'&nMv')+_0x351e84),console[_0x13eb87(0x49e,'^lJJ')](_0x13eb87(0x38f,'30)t')+_0x2d9577),console[_0x13eb87(0x4b2,'S!i)')]('🔁\x20\x20SSE\x20Reconnect:\x20\x20\x20\x20\x20\x20\x20\x20\x20'+_0x3c351c),console[_0x13eb87(0x1a1,'@QVa')](_0x13eb87(0x1c5,'%nTx')+_0x38ff37),console[_0x13eb87(0x405,'[NGc')]('📋\x20\x20Active\x20Sessions:\x20\x20\x20\x20\x20\x20\x20'+_0x518f5e),console['log']('\x0a🔐\x20\x20Authentication:'),console['log'](_0x13eb87(0x465,'cH7W')+(_0x2c9381[_0x13eb87(0x10b,'V&f(')]?'(see\x20above)':_0x13eb87(0x37e,'yL4y'))),console[_0x13eb87(0x132,'&nMv')](_0x13eb87(0x210,'2Voh')),console[_0x13eb87(0x165,'nsSN')](_0x13eb87(0x33b,'$W(9')+_0x2c9381['maxRestarts']+_0x13eb87(0x2fd,'yL4y')+_0x2c9381['restartWindowMs']/0x3e8+'s\x20window'),console['log'](_0x13eb87(0x233,'yO(Q')+_0x2c9381[_0x13eb87(0x34f,'7@1%')]+_0x13eb87(0x205,'VDXI')),console[_0x13eb87(0x438,'JUp6')](_0x13eb87(0x305,'!)DA')+_0x2c9381[_0x13eb87(0x43c,'8iXp')]/0x3e8+_0x13eb87(0x3f9,']cW@')),console[_0x13eb87(0x27b,'A^&K')](_0x13eb87(0x16a,'eONb')),console['log']('\x20\x20\x20\x20curl\x20-X\x20POST\x20'+_0x351e84+'\x20\x5c'),console[_0x13eb87(0x10f,'GrlK')](_0x13eb87(0x3f1,'eONb')),console[_0x13eb87(0x15d,'vQ1Q')](_0x13eb87(0x129,'svnM')),console['log'](_0x13eb87(0x42c,'nsSN')),console[_0x13eb87(0x44b,'8nSx')]('\x0a'+'='['repeat'](0x3e)+'\x0a');const _0x571634={};_0x571634[_0x13eb87(0x1e2,'!)DA')]=_0x351e84,_0x571634[_0x13eb87(0x13f,'ZiR@')]=_0x2d9577,_0x232066['info'](_0x571634,'Gateway\x20ready\x20—\x20waiting\x20for\x20connections...'),await new Promise(()=>{});}runCli(process['argv'])[a0_0xc96691(0x23b,'^N!&')](_0x13227d=>{const _0x3e94a4=a0_0xc96691;console[_0x3e94a4(0x3e3,'!mXe')](_0x3e94a4(0x3bf,'S!i)'),_0x13227d[_0x3e94a4(0x15f,'yL4y')]),(process.env['DEBUG']||process.env['NODE_ENV']==='development')&&console[_0x3e94a4(0x3ba,'yL4y')](_0x13227d[_0x3e94a4(0x307,'uX3F')]),process['exit'](0x1);});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logger.ts","../src/index.ts","../src/cli.ts","../src/config.ts","../src/utils.ts","../src/bridge.ts","../src/supervisor.ts","../src/queue.ts","../src/server.ts","../src/session.ts","../src/health.ts","../src/middleware/auth.ts","../src/ngrok.ts"],"sourcesContent":["import pino from \"pino\";\n\nlet _logger: pino.Logger | null = null;\n\nexport interface LoggerOptions {\n debug?: boolean;\n traceMcp?: boolean;\n}\n\nexport function createLogger(options: LoggerOptions = {}): pino.Logger {\n const isDev =\n process.env[\"NODE_ENV\"] !== \"production\" || options.debug === true;\n const level = options.debug ? \"debug\" : \"info\";\n\n const transport = isDev\n ? {\n target: \"pino-pretty\",\n options: {\n colorize: true,\n translateTime: \"HH:MM:ss\",\n ignore: \"pid,hostname\",\n messageFormat: \"{msg}\",\n },\n }\n : undefined;\n\n const logger = pino(\n {\n level,\n base: { pid: process.pid },\n timestamp: pino.stdTimeFunctions.isoTime,\n },\n transport\n ? (pino.transport(transport) as pino.DestinationStream)\n : undefined\n );\n\n _logger = logger;\n return logger;\n}\n\nexport function getLogger(): pino.Logger {\n if (!_logger) {\n _logger = createLogger();\n }\n return _logger;\n}\n\nexport type Logger = pino.Logger;\n","import \"dotenv/config\";\nimport { runCli } from \"./cli.js\";\n\nrunCli(process.argv).catch((err: Error) => {\n console.error(\"\\n[ERROR]\", err.message);\n if (process.env[\"DEBUG\"] || process.env[\"NODE_ENV\"] === \"development\") {\n console.error(err.stack);\n }\n process.exit(1);\n});\n","import \"dotenv/config\";\nimport { Command } from \"commander\";\nimport { createLogger } from \"./logger.js\";\nimport { loadConfigFile, type AppConfig } from \"./config.js\";\nimport {\n generateSecureToken,\n parseEnvVars,\n buildMaskedEnvLog,\n} from \"./utils.js\";\nimport { McpBridge } from \"./bridge.js\";\nimport { createApp, startServer, stopServer } from \"./server.js\";\nimport {\n startNgrokTunnel,\n closeNgrokTunnel,\n isNgrokConnected,\n getNgrokUrl,\n} from \"./ngrok.js\";\nimport type { Server } from \"http\";\nimport type { SessionManager } from \"./session.js\";\n\n// ---------------------------------------------------------------------------\n// CLI version\n// ---------------------------------------------------------------------------\n\nconst PACKAGE_VERSION = \"2026.06.1101\";\n\n// ---------------------------------------------------------------------------\n// Build and run the CLI\n// ---------------------------------------------------------------------------\n\nexport async function runCli(argv: string[]): Promise<void> {\n const program = new Command();\n\n program\n .name(\"remote-mcp-ngrok\")\n .description(\n \"Resilient remote MCP gateway — expose local MCP stdio servers over the internet with auto-recovery\"\n )\n .version(PACKAGE_VERSION)\n\n // Core options\n .option(\"-p, --port <number>\", \"Local HTTP server port\", \"8000\")\n .option(\"--host <host>\", \"Local HTTP server host\", \"127.0.0.1\")\n .option(\n \"--stdio <command>\",\n 'MCP stdio command (e.g. \"npx -y @playwright/mcp@latest --browser chrome\")'\n )\n .option(\"--command <cmd>\", \"MCP executable (alternative to --stdio)\")\n .option(\"--args <args...>\", \"MCP arguments (used with --command)\")\n\n // Ngrok\n .option(\"--ngrok-authtoken <token>\", \"Ngrok authentication token\")\n .option(\n \"--ngrok-domain <domain>\",\n \"Static Ngrok domain (e.g. myagent.ngrok-free.app)\"\n )\n\n // Security\n .option(\n \"--bearer-token <token>\",\n \"Bearer token for HTTP authentication (auto-generated if omitted)\"\n )\n .option(\"--protect-health\", \"Require authentication on /health endpoint\")\n .option(\n \"--allow-sse-query-token\",\n \"Allow SSE auth via ?token= query param (default: true)\"\n )\n .option(\n \"--cors <origins...>\",\n \"CORS allowed origins (use * for all, or space-separated list)\"\n )\n\n // Environment\n .option(\n \"--env <KEY=VALUE...>\",\n \"Environment variables to inject into MCP process (repeatable)\"\n )\n\n // Resilience options\n .option(\n \"--timeout <ms>\",\n \"MCP request timeout in milliseconds\",\n \"300000\"\n )\n .option(\n \"--concurrency <n>\",\n \"Max concurrent MCP requests (default: 1 for sequential)\",\n \"1\"\n )\n .option(\n \"--max-restarts <n>\",\n \"Max MCP process restart attempts within restart window (default: 10)\",\n \"10\"\n )\n .option(\n \"--restart-window <ms>\",\n \"Sliding window for counting restarts (default: 60000ms)\",\n \"60000\"\n )\n .option(\n \"--max-queue-depth <n>\",\n \"Max buffered requests during MCP restart (default: 500)\",\n \"500\"\n )\n .option(\n \"--session-ttl <ms>\",\n \"How long to preserve disconnected SSE sessions (default: 300000ms)\",\n \"300000\"\n )\n\n // Logging\n .option(\"--debug\", \"Enable debug logging\")\n .option(\"--trace-mcp\", \"Log raw MCP packets (useful for debugging)\")\n\n // Config file\n .option(\"--config <path>\", \"Path to YAML or JSON config file\");\n\n program.parse(argv);\n const opts = program.opts<Record<string, unknown>>();\n\n // ---------------------------------------------------------------------------\n // Load config file (lowest priority)\n // ---------------------------------------------------------------------------\n const configFile = loadConfigFile(opts[\"config\"] as string | undefined);\n\n // ---------------------------------------------------------------------------\n // Create logger early\n // ---------------------------------------------------------------------------\n const debugEnabled =\n Boolean(opts[\"debug\"]) || configFile.debug === true;\n const traceMcp =\n Boolean(opts[\"traceMcp\"]) || configFile.traceMcp === true;\n\n const logger = createLogger({ debug: debugEnabled, traceMcp });\n\n // ---------------------------------------------------------------------------\n // Resolve configuration: CLI > config file > env vars > defaults\n // ---------------------------------------------------------------------------\n\n const port = parseInt(\n String(opts[\"port\"] ?? configFile.port ?? process.env[\"PORT\"] ?? \"8000\"),\n 10\n );\n\n const host =\n (opts[\"host\"] as string | undefined) ??\n configFile.host ??\n process.env[\"HOST\"] ??\n \"127.0.0.1\";\n\n const stdio =\n (opts[\"stdio\"] as string | undefined) ??\n configFile.stdio ??\n process.env[\"STDIO_COMMAND\"];\n\n const command =\n (opts[\"command\"] as string | undefined) ??\n configFile.command;\n\n const args =\n (opts[\"args\"] as string[] | undefined) ??\n configFile.args ??\n [];\n\n const ngrokAuthtoken =\n (opts[\"ngrokAuthtoken\"] as string | undefined) ??\n configFile.ngrokAuthtoken ??\n process.env[\"NGROK_AUTHTOKEN\"] ??\n \"\";\n\n const ngrokDomain =\n (opts[\"ngrokDomain\"] as string | undefined) ??\n configFile.ngrokDomain ??\n process.env[\"NGROK_DOMAIN\"] ??\n \"\";\n\n // Bearer token — auto-generate if not provided\n let bearerToken =\n (opts[\"bearerToken\"] as string | undefined) ??\n configFile.bearerToken ??\n process.env[\"BEARER_TOKEN\"] ??\n \"\";\n\n let generatedToken = false;\n if (!bearerToken) {\n bearerToken = generateSecureToken();\n generatedToken = true;\n }\n\n const protectHealth =\n Boolean(opts[\"protectHealth\"]) || configFile.protectHealth === true;\n\n const corsRaw =\n (opts[\"cors\"] as string[] | string | undefined) ??\n configFile.cors;\n let corsOrigins: string[] = [];\n if (corsRaw) {\n corsOrigins = Array.isArray(corsRaw) ? corsRaw : [corsRaw];\n }\n\n const timeoutMs = parseInt(\n String(opts[\"timeout\"] ?? configFile.timeout ?? \"300000\"),\n 10\n );\n\n const concurrency = parseInt(\n String(opts[\"concurrency\"] ?? configFile.concurrency ?? \"1\"),\n 10\n );\n\n const maxRestarts = parseInt(\n String(opts[\"maxRestarts\"] ?? configFile.maxRestarts ?? \"10\"),\n 10\n );\n\n const restartWindowMs = parseInt(\n String(opts[\"restartWindow\"] ?? configFile.restartWindowMs ?? \"60000\"),\n 10\n );\n\n const maxQueueDepth = parseInt(\n String(opts[\"maxQueueDepth\"] ?? configFile.maxQueueDepth ?? \"500\"),\n 10\n );\n\n const sessionTtlMs = parseInt(\n String(opts[\"sessionTtl\"] ?? configFile.sessionTtlMs ?? \"300000\"),\n 10\n );\n\n const allowSseQueryToken =\n opts[\"allowSseQueryToken\"] !== false &&\n configFile.allowSseQueryToken !== false;\n\n // Environment variables — merge: config file < CLI --env\n const cliEnvEntries = (opts[\"env\"] as string[] | undefined) ?? [];\n const cliEnvVars = parseEnvVars(cliEnvEntries);\n const mergedEnv: Record<string, string> = {\n ...(configFile.env ?? {}),\n ...cliEnvVars,\n };\n\n // ---------------------------------------------------------------------------\n // Validate required options\n // ---------------------------------------------------------------------------\n\n if (!stdio && !command) {\n logger.error(\n \"No MCP command specified. Use --stdio or --command/--args.\"\n );\n logger.error(\n 'Example: --stdio \"npx -y @playwright/mcp@latest --browser chrome\"'\n );\n process.exit(1);\n }\n\n if (!ngrokAuthtoken) {\n logger.error(\n \"Ngrok auth token is required. Use --ngrok-authtoken or set NGROK_AUTHTOKEN env var.\"\n );\n logger.error(\n \"Get your token at: https://dashboard.ngrok.com/get-started/your-authtoken\"\n );\n process.exit(1);\n }\n\n if (!ngrokDomain) {\n logger.error(\n \"Ngrok domain is required. Use --ngrok-domain or set NGROK_DOMAIN env var.\"\n );\n logger.error(\n \"Claim a free static domain at: https://dashboard.ngrok.com/cloud-edge/domains\"\n );\n process.exit(1);\n }\n\n if (isNaN(port) || port < 1 || port > 65535) {\n logger.error(`Invalid port: ${String(opts[\"port\"])}. Must be 1–65535.`);\n process.exit(1);\n }\n\n if (isNaN(timeoutMs) || timeoutMs < 1000) {\n logger.error(\"Timeout must be at least 1000ms.\");\n process.exit(1);\n }\n\n if (isNaN(concurrency) || concurrency < 1) {\n logger.error(\"Concurrency must be at least 1.\");\n process.exit(1);\n }\n\n // ---------------------------------------------------------------------------\n // Build resolved config\n // ---------------------------------------------------------------------------\n\n const config: AppConfig = {\n port,\n host,\n stdio,\n command,\n args,\n ngrokAuthtoken,\n ngrokDomain,\n bearerToken,\n debug: debugEnabled,\n traceMcp,\n corsOrigins,\n protectHealth,\n allowSseQueryToken,\n timeoutMs,\n concurrency,\n maxRestarts,\n restartWindowMs,\n maxQueueDepth,\n sessionTtlMs,\n env: mergedEnv,\n generatedToken,\n };\n\n // ---------------------------------------------------------------------------\n // Print startup info\n // ---------------------------------------------------------------------------\n\n logger.info(\"=\".repeat(62));\n logger.info(\" remote-mcp-ngrok — Resilient Remote MCP Gateway\");\n logger.info(\"=\".repeat(62));\n\n if (generatedToken) {\n console.log(\"\\n[SECURITY] No bearer token provided — generated one automatically:\");\n console.log(`[SECURITY] Bearer token: ${bearerToken}`);\n console.log(\"[SECURITY] Save this token! You'll need it to connect remote clients.\\n\");\n }\n\n logger.info({ port, host }, \"HTTP gateway config\");\n logger.info(\n { stdio: stdio ?? `${command ?? \"\"} ${args.join(\" \")}`.trim() },\n \"MCP command\"\n );\n logger.info({ domain: ngrokDomain }, \"Ngrok domain\");\n logger.info(\n { maxRestarts, restartWindowMs, maxQueueDepth, sessionTtlMs },\n \"Resilience config\"\n );\n\n if (Object.keys(mergedEnv).length > 0) {\n logger.info(\n { env: buildMaskedEnvLog(mergedEnv) },\n \"MCP environment variables (secrets masked)\"\n );\n }\n\n // ---------------------------------------------------------------------------\n // Run the application\n // ---------------------------------------------------------------------------\n\n await runApp(config);\n}\n\n// ---------------------------------------------------------------------------\n// Application orchestration\n// ---------------------------------------------------------------------------\n\nasync function runApp(config: AppConfig): Promise<void> {\n const { getLogger } = await import(\"./logger.js\");\n const log = getLogger();\n\n let bridge: McpBridge | null = null;\n let httpServer: Server | null = null;\n let sessions: SessionManager | null = null;\n let shuttingDown = false;\n\n // ngrok state\n let ngrokConnected = false;\n let ngrokPublicUrl: string | null = null;\n\n // ---------------------------------------------------------------------------\n // Graceful shutdown handler\n // ---------------------------------------------------------------------------\n\n async function shutdown(signal: string): Promise<void> {\n if (shuttingDown) return;\n shuttingDown = true;\n\n log.info({ signal }, \"Shutdown signal received — cleaning up...\");\n\n // 1. Notify all SSE clients\n if (sessions) {\n sessions.destroyAll(\"Gateway shutting down\");\n log.info(\"SSE sessions closed\");\n }\n\n // 2. Stop accepting new HTTP connections\n if (httpServer) {\n await stopServer(httpServer);\n log.info(\"HTTP server stopped\");\n }\n\n // 3. Close Ngrok tunnel\n await closeNgrokTunnel();\n log.info(\"Ngrok tunnel closed\");\n\n // 4. Shut down MCP bridge (kills process tree, flushes queue)\n if (bridge) {\n await bridge.shutdown();\n }\n\n log.info(\"Shutdown complete ✓\");\n process.exit(0);\n }\n\n process.on(\"SIGINT\", () => void shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => void shutdown(\"SIGTERM\"));\n\n // Windows Ctrl+C\n if (process.platform === \"win32\") {\n const readline = await import(\"readline\");\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.on(\"SIGINT\", () => void shutdown(\"SIGINT\"));\n }\n\n // ---------------------------------------------------------------------------\n // 1. Start MCP bridge (supervisor + queue)\n // ---------------------------------------------------------------------------\n\n log.info(\"Starting MCP supervisor...\");\n\n bridge = new McpBridge({\n stdio: config.stdio,\n command: config.command,\n args: config.args,\n env: config.env,\n timeoutMs: config.timeoutMs,\n concurrency: config.concurrency,\n traceMcp: config.traceMcp,\n maxRestarts: config.maxRestarts,\n restartWindowMs: config.restartWindowMs,\n maxQueueDepth: config.maxQueueDepth,\n });\n\n bridge.on(\"max-restarts-exceeded\", () => {\n log.error(\n \"MCP supervisor has exceeded maximum restart attempts. Gateway continues running but MCP is unavailable.\"\n );\n log.error(\"Restart remote-mcp-ngrok to recover.\");\n });\n\n // Log supervisor status transitions\n bridge.on(\"supervisor-status\", (status, pid, restartCount) => {\n if (status === \"restarting\") {\n log.warn({ pid, restartCount }, \"MCP process restarting — requests are being queued...\");\n } else if (status === \"ready\") {\n log.info({ pid, restartCount }, \"MCP process ready — queue draining ✓\");\n }\n });\n\n await bridge.start();\n log.info({ pid: bridge.pid }, \"MCP supervisor ready ✓\");\n\n // ---------------------------------------------------------------------------\n // 2. Start Express HTTP gateway\n // ---------------------------------------------------------------------------\n\n log.info({ port: config.port, host: config.host }, \"Starting HTTP gateway...\");\n\n const { app, sessions: sessionMgr } = createApp({\n port: config.port,\n host: config.host,\n bridge,\n bearerToken: config.bearerToken,\n corsOrigins: config.corsOrigins,\n protectHealth: config.protectHealth,\n allowSseQueryToken: config.allowSseQueryToken,\n ngrokConnected: () => ngrokConnected,\n ngrokUrl: () => ngrokPublicUrl,\n version: \"2026.06.1101\",\n sessionTtlMs: config.sessionTtlMs,\n });\n\n sessions = sessionMgr;\n httpServer = await startServer(app, config.port, config.host);\n\n log.info(\n { port: config.port, host: config.host },\n `HTTP gateway listening on http://${config.host}:${config.port}`\n );\n\n // ---------------------------------------------------------------------------\n // 3. Connect Ngrok tunnel\n // ---------------------------------------------------------------------------\n\n log.info(\"Connecting to Ngrok...\");\n\n const tunnel = await startNgrokTunnel({\n authtoken: config.ngrokAuthtoken,\n domain: config.ngrokDomain,\n addr: config.port,\n });\n\n ngrokConnected = true;\n ngrokPublicUrl = tunnel.url;\n\n // ---------------------------------------------------------------------------\n // 4. Print public URL and connection info\n // ---------------------------------------------------------------------------\n\n const mcpUrl = `${tunnel.url}/mcp`;\n const sseUrl = `${tunnel.url}/sse`;\n const sseReconnectUrl = `${tunnel.url}/sse/reconnect`;\n const healthUrl = `${tunnel.url}/health`;\n const sessionsUrl = `${tunnel.url}/sessions`;\n\n console.log(\"\\n\" + \"=\".repeat(62));\n console.log(\"✅ remote-mcp-ngrok is running!\");\n console.log(\"=\".repeat(62));\n console.log(`\\n🌐 Public MCP URL: ${mcpUrl}`);\n console.log(`📡 SSE Endpoint: ${sseUrl}`);\n console.log(`🔁 SSE Reconnect: ${sseReconnectUrl}`);\n console.log(`❤️ Health Check: ${healthUrl}`);\n console.log(`📋 Active Sessions: ${sessionsUrl}`);\n console.log(\"\\n🔐 Authentication:\");\n console.log(\n ` Authorization: Bearer ${config.generatedToken ? \"(see above)\" : \"***\"}`\n );\n console.log(\"\\n🛡️ Resilience:\");\n console.log(` Max restarts: ${config.maxRestarts} per ${config.restartWindowMs / 1000}s window`);\n console.log(` Queue depth: ${config.maxQueueDepth} requests`);\n console.log(` Session TTL: ${config.sessionTtlMs / 1000}s after disconnect`);\n console.log(\"\\n📋 Usage example (curl):\");\n console.log(` curl -X POST ${mcpUrl} \\\\`);\n console.log(` -H \"Authorization: Bearer YOUR_TOKEN\" \\\\`);\n console.log(` -H \"Content-Type: application/json\" \\\\`);\n console.log(` -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}'`);\n console.log(\"\\n\" + \"=\".repeat(62) + \"\\n\");\n\n log.info({ mcpUrl, sseUrl }, \"Gateway ready — waiting for connections...\");\n\n // Keep the process alive\n await new Promise<void>(() => {\n // Intentionally never resolves — process runs until SIGINT/SIGTERM\n });\n}\n","import fs from \"fs\";\nimport path from \"path\";\nimport yaml from \"js-yaml\";\nimport { z } from \"zod\";\nimport { getLogger } from \"./logger.js\";\n\n/**\n * Zod schema for the configuration file (YAML or JSON).\n * All fields are optional — CLI args take precedence.\n */\nexport const ConfigFileSchema = z.object({\n port: z.number().int().min(1).max(65535).optional(),\n host: z.string().optional(),\n stdio: z.string().optional(),\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n ngrokAuthtoken: z.string().optional(),\n ngrokDomain: z.string().optional(),\n bearerToken: z.string().optional(),\n debug: z.boolean().optional(),\n traceMcp: z.boolean().optional(),\n cors: z.union([z.string(), z.array(z.string())]).optional(),\n protectHealth: z.boolean().optional(),\n allowSseQueryToken: z.boolean().optional(),\n timeout: z.number().int().min(1000).optional(),\n concurrency: z.number().int().min(1).optional(),\n env: z.record(z.string()).optional(),\n // Resilience options\n maxRestarts: z.number().int().min(1).optional(),\n restartWindowMs: z.number().int().min(1000).optional(),\n maxQueueDepth: z.number().int().min(1).optional(),\n sessionTtlMs: z.number().int().min(1000).optional(),\n});\n\nexport type ConfigFile = z.infer<typeof ConfigFileSchema>;\n\n/**\n * Load and parse a YAML or JSON config file.\n * Returns empty object if no path provided.\n * Throws if file cannot be read or parsed.\n */\nexport function loadConfigFile(configPath: string | undefined): ConfigFile {\n if (!configPath) return {};\n\n const logger = getLogger();\n const resolved = path.resolve(process.cwd(), configPath);\n\n if (!fs.existsSync(resolved)) {\n throw new Error(`Config file not found: ${resolved}`);\n }\n\n const ext = path.extname(resolved).toLowerCase();\n const content = fs.readFileSync(resolved, \"utf-8\");\n\n let raw: unknown;\n try {\n if (ext === \".yaml\" || ext === \".yml\") {\n raw = yaml.load(content);\n } else if (ext === \".json\") {\n raw = JSON.parse(content);\n } else {\n // Try YAML first, then JSON\n try {\n raw = yaml.load(content);\n } catch {\n raw = JSON.parse(content);\n }\n }\n } catch (err) {\n throw new Error(\n `Failed to parse config file ${resolved}: ${(err as Error).message}`\n );\n }\n\n const result = ConfigFileSchema.safeParse(raw);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid config file ${resolved}:\\n${issues}`);\n }\n\n logger.debug({ configPath: resolved }, \"Loaded config file\");\n return result.data;\n}\n\n/**\n * Full resolved application configuration.\n * Merged result of: CLI args > config file > env vars > defaults.\n */\nexport interface AppConfig {\n port: number;\n host: string;\n stdio: string | undefined;\n command: string | undefined;\n args: string[];\n ngrokAuthtoken: string;\n ngrokDomain: string;\n bearerToken: string;\n debug: boolean;\n traceMcp: boolean;\n corsOrigins: string[];\n protectHealth: boolean;\n allowSseQueryToken: boolean;\n timeoutMs: number;\n concurrency: number;\n env: Record<string, string>;\n generatedToken: boolean;\n // Resilience options\n maxRestarts: number;\n restartWindowMs: number;\n maxQueueDepth: number;\n sessionTtlMs: number;\n}\n","import crypto from \"crypto\";\n\n/** Sensitive key patterns — values are masked in logs */\nconst SENSITIVE_KEY_PATTERNS = [\n /token/i,\n /secret/i,\n /api[_-]?key/i,\n /password/i,\n /auth/i,\n /credential/i,\n /passwd/i,\n /private/i,\n];\n\n/**\n * Generate a cryptographically secure random hex token.\n */\nexport function generateSecureToken(bytes = 32): string {\n return crypto.randomBytes(bytes).toString(\"hex\");\n}\n\n/**\n * Determine if a key name is considered sensitive.\n */\nexport function isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));\n}\n\n/**\n * Mask a value if its key is sensitive.\n */\nexport function maskValue(key: string, value: string): string {\n if (isSensitiveKey(key)) {\n return \"********\";\n }\n return value;\n}\n\n/**\n * Parse an array of \"KEY=VALUE\" strings into a Record.\n * Supports:\n * - Simple: KEY=VALUE\n * - Values with equals signs: KEY=a=b=c\n * - Quoted values (quotes stripped): KEY=\"some value\"\n */\nexport function parseEnvVars(entries: string[]): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const entry of entries) {\n const eqIdx = entry.indexOf(\"=\");\n if (eqIdx === -1) {\n // No value — treat as empty string\n const key = entry.trim();\n if (key) result[key] = \"\";\n continue;\n }\n\n const key = entry.slice(0, eqIdx).trim();\n let value = entry.slice(eqIdx + 1);\n\n if (!key) continue;\n\n // Strip surrounding quotes (single or double)\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Build a log-safe representation of env vars (masks sensitive values).\n */\nexport function buildMaskedEnvLog(\n env: Record<string, string>\n): Record<string, string> {\n const masked: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n masked[key] = maskValue(key, value);\n }\n return masked;\n}\n\n/**\n * Split a shell-like command string into [executable, ...args].\n * Handles:\n * - Single/double quoted arguments\n * - Escaped spaces\n * - Multiple spaces between tokens\n *\n * Example:\n * 'npx -y @playwright/mcp@latest --browser chrome'\n * => ['npx', '-y', '@playwright/mcp@latest', '--browser', 'chrome']\n */\nexport function splitCommand(cmd: string): string[] {\n const args: string[] = [];\n let current = \"\";\n let inSingle = false;\n let inDouble = false;\n let i = 0;\n\n while (i < cmd.length) {\n const ch = cmd[i];\n\n if (ch === \"\\\\\" && !inSingle && i + 1 < cmd.length) {\n // Escaped character\n i++;\n current += cmd[i] ?? \"\";\n } else if (ch === \"'\" && !inDouble) {\n inSingle = !inSingle;\n } else if (ch === '\"' && !inSingle) {\n inDouble = !inDouble;\n } else if (ch === \" \" && !inSingle && !inDouble) {\n if (current.length > 0) {\n args.push(current);\n current = \"\";\n }\n } else {\n current += ch;\n }\n\n i++;\n }\n\n if (current.length > 0) {\n args.push(current);\n }\n\n return args;\n}\n\n/**\n * Format bytes as a human-readable string.\n */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Sleep for a given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Resilient MCP Bridge\n *\n * Sits between the HTTP gateway and the MCP Process Supervisor.\n * Decouples remote client sessions from the MCP child process lifecycle.\n *\n * Key behaviors:\n * - Uses McpSupervisor to manage child process restarts with exponential backoff\n * - Uses RequestQueue to buffer requests during restart windows\n * - Re-binds to the new process stdout automatically after each restart\n * - Performs MCP initialize handshake after each restart before resuming queue\n * - Concurrent request limiting via ConcurrencyQueue\n * - Emits notifications to subscribers (SSE broadcast layer)\n */\n\nimport { EventEmitter } from \"events\";\nimport { z } from \"zod\";\nimport { getLogger } from \"./logger.js\";\nimport { McpSupervisor, type SupervisorOptions } from \"./supervisor.js\";\nimport { RequestQueue } from \"./queue.js\";\n\n// ---------------------------------------------------------------------------\n// MCP JSON-RPC Zod Schemas\n// ---------------------------------------------------------------------------\n\nconst JsonRpcIdSchema = z.union([z.string(), z.number(), z.null()]);\n\n/** Inbound request from HTTP client → MCP process */\nexport const McpRequestSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n id: JsonRpcIdSchema.optional(),\n method: z.string(),\n params: z.unknown().optional(),\n});\n\n/** Success response from MCP process */\nconst McpSuccessResponseSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n id: JsonRpcIdSchema,\n result: z.unknown(),\n});\n\n/** Error response from MCP process */\nconst McpErrorResponseSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n id: JsonRpcIdSchema.optional(),\n error: z.object({\n code: z.number(),\n message: z.string(),\n data: z.unknown().optional(),\n }),\n});\n\n/** Notification (no id) from MCP process */\nconst McpNotificationSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n method: z.string(),\n params: z.unknown().optional(),\n});\n\n/** Union of all valid MCP outbound message types */\nconst McpOutboundSchema = z.union([\n McpSuccessResponseSchema,\n McpErrorResponseSchema,\n McpNotificationSchema,\n]);\n\nexport type McpRequest = z.infer<typeof McpRequestSchema>;\nexport type McpOutbound = z.infer<typeof McpOutboundSchema>;\nexport type McpNotification = z.infer<typeof McpNotificationSchema>;\n\n// ---------------------------------------------------------------------------\n// Pending request entry\n// ---------------------------------------------------------------------------\n\ninterface PendingRequest {\n resolve: (value: unknown) => void;\n reject: (reason: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n// ---------------------------------------------------------------------------\n// Concurrency limiter\n// ---------------------------------------------------------------------------\n\ntype QueueTask = () => Promise<void>;\n\nclass ConcurrencyLimiter {\n private running = 0;\n private readonly waiters: QueueTask[] = [];\n\n constructor(private readonly concurrency: number) {}\n\n async run<T>(task: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const wrapped: QueueTask = async () => {\n try {\n resolve(await task());\n } catch (err) {\n reject(err as Error);\n }\n };\n this.waiters.push(wrapped);\n this.tick();\n });\n }\n\n private tick(): void {\n while (this.running < this.concurrency && this.waiters.length > 0) {\n const task = this.waiters.shift();\n if (!task) break;\n this.running++;\n task().finally(() => {\n this.running--;\n this.tick();\n });\n }\n }\n\n get size(): number {\n return this.waiters.length + this.running;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Bridge options\n// ---------------------------------------------------------------------------\n\nexport interface BridgeOptions extends SupervisorOptions {\n /** Request timeout in ms (default: 300000) */\n timeoutMs?: number;\n /** Max concurrent MCP requests (default: 1) */\n concurrency?: number;\n /** Log raw MCP packets */\n traceMcp?: boolean;\n /** Max buffered requests during restart (default: 500) */\n maxQueueDepth?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Bridge events\n// ---------------------------------------------------------------------------\n\nexport interface McpBridgeEvents {\n start: [pid: number | undefined];\n exit: [code: number | null, signal: string | null];\n notification: [notification: McpNotification];\n \"max-restarts-exceeded\": [];\n \"supervisor-status\": [status: string, pid: number | undefined, restartCount: number];\n}\n\n// ---------------------------------------------------------------------------\n// Resilient MCP Bridge\n// ---------------------------------------------------------------------------\n\nexport class McpBridge extends EventEmitter {\n declare emit: <K extends keyof McpBridgeEvents>(\n event: K,\n ...args: McpBridgeEvents[K]\n ) => boolean;\n declare on: <K extends keyof McpBridgeEvents>(\n event: K,\n listener: (...args: McpBridgeEvents[K]) => void\n ) => this;\n declare once: <K extends keyof McpBridgeEvents>(\n event: K,\n listener: (...args: McpBridgeEvents[K]) => void\n ) => this;\n\n private readonly supervisor: McpSupervisor;\n private readonly limiter: ConcurrencyLimiter;\n private readonly requestQueue: RequestQueue;\n private readonly options: Required<BridgeOptions>;\n private readonly pending = new Map<string | number, PendingRequest>();\n\n private _isShuttingDown = false;\n\n constructor(options: BridgeOptions) {\n super();\n this.options = {\n stdio: options.stdio ?? \"\",\n command: options.command ?? \"\",\n args: options.args ?? [],\n env: options.env ?? {},\n timeoutMs: options.timeoutMs ?? 300_000,\n concurrency: options.concurrency ?? 1,\n traceMcp: options.traceMcp ?? false,\n maxRestarts: options.maxRestarts ?? 10,\n restartWindowMs: options.restartWindowMs ?? 60_000,\n baseRetryMs: options.baseRetryMs ?? 500,\n maxRetryMs: options.maxRetryMs ?? 30_000,\n maxQueueDepth: options.maxQueueDepth ?? 500,\n };\n\n this.limiter = new ConcurrencyLimiter(this.options.concurrency);\n this.requestQueue = new RequestQueue({ maxDepth: this.options.maxQueueDepth });\n\n this.supervisor = new McpSupervisor({\n stdio: this.options.stdio,\n command: this.options.command,\n args: this.options.args,\n env: this.options.env,\n maxRestarts: this.options.maxRestarts,\n restartWindowMs: this.options.restartWindowMs,\n baseRetryMs: this.options.baseRetryMs,\n maxRetryMs: this.options.maxRetryMs,\n traceMcp: this.options.traceMcp,\n });\n\n this.wireSupervisorEvents();\n }\n\n // ---------------------------------------------------------------------------\n // Accessors\n // ---------------------------------------------------------------------------\n\n get isRunning(): boolean {\n return this.supervisor.isReady;\n }\n\n get pid(): number | undefined {\n return this.supervisor.pid;\n }\n\n get restartCount(): number {\n return this.supervisor.restartCount;\n }\n\n get totalRestarts(): number {\n return this.supervisor.totalRestarts;\n }\n\n get queueSize(): number {\n return this.limiter.size + this.requestQueue.size;\n }\n\n get supervisorStatus(): string {\n return this.supervisor.status;\n }\n\n get queueMetrics() {\n return this.requestQueue.metrics;\n }\n\n // ---------------------------------------------------------------------------\n // Wire supervisor events → bridge behavior\n // ---------------------------------------------------------------------------\n\n private wireSupervisorEvents(): void {\n const logger = getLogger();\n\n // Forward stdout lines to our NDJSON parser\n this.supervisor.on(\"stdout-line\", (line) => {\n this.handleMessage(line);\n });\n\n // On process start — perform initialize handshake\n this.supervisor.on(\"process-start\", (pid) => {\n logger.info({ pid }, \"[bridge] MCP process started — performing initialize handshake...\");\n this.emit(\"start\", pid);\n\n // Pause the queue while we initialize\n this.requestQueue.pause();\n\n // Run initialize handshake\n this.doInitialize().then(() => {\n this.supervisor.markReady();\n // Resume queue drain using our send function\n this.requestQueue.resume(async (req) => {\n try {\n const result = await req.execute();\n req.resolve(result);\n } catch (err) {\n req.reject(err as Error);\n }\n });\n logger.info({ pid }, \"[bridge] MCP ready — queue resumed\");\n }).catch((err: Error) => {\n logger.error({ err: err.message }, \"[bridge] Initialize handshake failed — will retry on next restart\");\n // The supervisor will restart the process on its own exit handler\n });\n });\n\n // On process exit — flush pending requests with error, pause queue\n this.supervisor.on(\"process-exit\", (code, signal) => {\n logger.warn({ code, signal }, \"[bridge] MCP process exited — rejecting in-flight requests\");\n this.emit(\"exit\", code, signal);\n\n // Reject all currently pending in-flight requests\n for (const [id, pending] of this.pending) {\n pending.reject(new Error(\"MCP process exited unexpectedly — request will be retried\"));\n clearTimeout(pending.timer);\n this.pending.delete(id);\n }\n\n // Pause the queue — it will be resumed after restart+init\n this.requestQueue.pause();\n });\n\n // Status changes\n this.supervisor.on(\"status\", (status) => {\n this.emit(\"supervisor-status\", status, this.supervisor.pid, this.supervisor.restartCount);\n });\n\n // Max restarts\n this.supervisor.on(\"max-restarts-exceeded\", () => {\n logger.error(\"[bridge] Supervisor gave up — flushing request queue\");\n this.requestQueue.flush(\"MCP process permanently failed — max restarts exceeded\");\n this.emit(\"max-restarts-exceeded\");\n });\n }\n\n // ---------------------------------------------------------------------------\n // Start\n // ---------------------------------------------------------------------------\n\n async start(): Promise<void> {\n await this.supervisor.start();\n // Wait for the first initialize handshake to complete\n await this.supervisor.waitForReady(120_000);\n }\n\n // ---------------------------------------------------------------------------\n // MCP initialize handshake\n // ---------------------------------------------------------------------------\n\n private async doInitialize(): Promise<void> {\n const logger = getLogger();\n const savedTimeout = this.options.timeoutMs;\n // Allow longer timeout for first run (npx download etc.)\n const initTimeout = Math.max(savedTimeout, 120_000);\n\n logger.info(\"[bridge] Performing MCP initialize handshake...\");\n\n try {\n const initResponse = await this.doSendRawRequest(\n {\n jsonrpc: \"2.0\",\n id: \"__init__\",\n method: \"initialize\",\n params: {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n roots: { listChanged: false },\n sampling: {},\n },\n clientInfo: {\n name: \"remote-mcp-ngrok\",\n version: \"2026.06.1101\",\n },\n },\n },\n initTimeout\n );\n\n logger.debug({ initResponse }, \"[bridge] MCP initialize response received\");\n\n // Send initialized notification (no response expected)\n await this.supervisor.write(\n JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n params: {},\n }) + \"\\n\"\n );\n\n logger.info(\"[bridge] MCP initialize handshake complete ✓\");\n } catch (err) {\n logger.error({ err: (err as Error).message }, \"[bridge] MCP initialize handshake failed\");\n throw err;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Send a request to MCP — routes through queue when paused\n // ---------------------------------------------------------------------------\n\n async sendRequest(request: McpRequest): Promise<unknown> {\n const parsed = McpRequestSchema.safeParse(request);\n if (!parsed.success) {\n return {\n jsonrpc: \"2.0\",\n id: (request as Record<string, unknown>)[\"id\"] ?? null,\n error: {\n code: -32600,\n message: \"Invalid Request\",\n data: parsed.error.issues,\n },\n };\n }\n\n const req = parsed.data;\n\n // If queue is paused (restart in progress), buffer the request\n if (this.requestQueue.isPaused) {\n return this.requestQueue.enqueue(\n () => this.limiter.run(() => this.doSendRequest(req)),\n this.options.timeoutMs\n );\n }\n\n // Otherwise send directly through the concurrency limiter\n return this.limiter.run(() => this.doSendRequest(req));\n }\n\n private async doSendRequest(request: McpRequest): Promise<unknown> {\n if (!this.supervisor.isReady) {\n // Check if we should queue or fail fast\n if (this.supervisor.status === \"failed\" || this.supervisor.status === \"stopped\") {\n return {\n jsonrpc: \"2.0\",\n id: request.id ?? null,\n error: {\n code: -32603,\n message: `MCP process is not available (supervisor status: ${this.supervisor.status})`,\n },\n };\n }\n\n // Queue it — supervisor is restarting\n return this.requestQueue.enqueue(\n () => this.doSendRequest(request),\n this.options.timeoutMs\n );\n }\n\n // Notifications (no id) — fire and forget\n if (request.id === undefined || request.id === null) {\n await this.supervisor.write(JSON.stringify(request) + \"\\n\");\n return { jsonrpc: \"2.0\", id: null, result: null };\n }\n\n return this.doSendRawRequest(request, this.options.timeoutMs);\n }\n\n // ---------------------------------------------------------------------------\n // Core request/response with NDJSON framing\n // ---------------------------------------------------------------------------\n\n private doSendRawRequest(\n request: Record<string, unknown>,\n timeoutMs: number\n ): Promise<unknown> {\n const logger = getLogger();\n const id = request[\"id\"] as string | number;\n\n return new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(\n new Error(\n `MCP request timeout after ${timeoutMs}ms (id=${String(id)}, method=${String(request[\"method\"])})`\n )\n );\n }, timeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n\n if (this.options.traceMcp) {\n logger.debug({ direction: \"→ MCP\", payload: request }, \"[bridge] MCP trace\");\n }\n\n this.supervisor.write(JSON.stringify(request) + \"\\n\").catch((err: Error) => {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(err);\n });\n });\n }\n\n // ---------------------------------------------------------------------------\n // Handle incoming NDJSON line from MCP stdout\n // ---------------------------------------------------------------------------\n\n private handleMessage(lineStr: string): void {\n const logger = getLogger();\n\n let raw: unknown;\n try {\n raw = JSON.parse(lineStr);\n } catch {\n logger.debug({ line: lineStr }, \"[bridge] MCP stdout: non-JSON line\");\n return;\n }\n\n const parsed = McpOutboundSchema.safeParse(raw);\n if (!parsed.success) {\n logger.warn({ raw }, \"[bridge] Received invalid MCP message structure, dropping\");\n return;\n }\n\n const msg = parsed.data;\n\n if (this.options.traceMcp) {\n logger.debug({ direction: \"← MCP\", payload: msg }, \"[bridge] MCP trace\");\n }\n\n // Notification (no id field)\n if (!(\"id\" in msg)) {\n const notifParsed = McpNotificationSchema.safeParse(msg);\n if (notifParsed.success) {\n this.emit(\"notification\", notifParsed.data);\n }\n return;\n }\n\n // Response — resolve the pending request\n const id = (msg as { id: string | number | null }).id;\n if (id !== null && id !== undefined) {\n const pending = this.pending.get(id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pending.delete(id);\n pending.resolve(msg);\n return;\n }\n }\n\n logger.debug({ id }, \"[bridge] Received response for unknown request id\");\n }\n\n // ---------------------------------------------------------------------------\n // Graceful shutdown\n // ---------------------------------------------------------------------------\n\n async shutdown(): Promise<void> {\n const logger = getLogger();\n this._isShuttingDown = true;\n\n // Reject all pending in-flight\n for (const [id, pending] of this.pending) {\n clearTimeout(pending.timer);\n pending.reject(new Error(\"Bridge shutting down\"));\n this.pending.delete(id);\n }\n\n // Flush queued\n this.requestQueue.flush(\"Bridge shutting down\");\n\n // Shut down supervisor\n await this.supervisor.shutdown();\n logger.info(\"[bridge] Bridge shutdown complete\");\n }\n}\n","/**\n * MCP Process Supervisor\n *\n * Manages the lifecycle of the underlying STDIO MCP child process.\n * Decoupled from client sessions — the supervisor restarts the process\n * transparently while sessions remain alive via the session/queue layer.\n *\n * Features:\n * - Exponential backoff with jitter for restart delays\n * - Configurable max-restarts within a sliding time window\n * - Status events: \"ready\" | \"restarting\" | \"failed\" | \"stopped\"\n * - Observers can subscribe to status transitions\n */\n\nimport { EventEmitter } from \"events\";\nimport { ChildProcess } from \"child_process\";\nimport spawn from \"cross-spawn\";\nimport treeKill from \"tree-kill\";\nimport { getLogger } from \"./logger.js\";\nimport { splitCommand, sleep } from \"./utils.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type SupervisorStatus = \"starting\" | \"ready\" | \"restarting\" | \"failed\" | \"stopped\";\n\nexport interface SupervisorOptions {\n /** Full stdio command string */\n stdio?: string;\n /** Executable path (alternative to stdio string) */\n command?: string;\n /** Arguments (used with command) */\n args?: string[];\n /** Environment variables to inject */\n env?: Record<string, string>;\n /** Max restart attempts within restartWindowMs */\n maxRestarts?: number;\n /** Window for counting restarts in ms */\n restartWindowMs?: number;\n /** Base delay for first restart (ms) */\n baseRetryMs?: number;\n /** Cap for exponential backoff (ms) */\n maxRetryMs?: number;\n /** Log raw MCP stderr */\n traceMcp?: boolean;\n}\n\nexport interface SupervisorEvents {\n \"status\": [status: SupervisorStatus, prevStatus: SupervisorStatus];\n \"process-start\": [pid: number | undefined];\n \"process-exit\": [code: number | null, signal: string | null, restartCount: number];\n \"process-ready\": [pid: number | undefined];\n \"max-restarts-exceeded\": [];\n \"stdout-line\": [line: string];\n \"stderr-line\": [line: string];\n}\n\n// ---------------------------------------------------------------------------\n// MCP Process Supervisor\n// ---------------------------------------------------------------------------\n\nexport class McpSupervisor extends EventEmitter {\n declare emit: <K extends keyof SupervisorEvents>(\n event: K,\n ...args: SupervisorEvents[K]\n ) => boolean;\n declare on: <K extends keyof SupervisorEvents>(\n event: K,\n listener: (...args: SupervisorEvents[K]) => void\n ) => this;\n declare once: <K extends keyof SupervisorEvents>(\n event: K,\n listener: (...args: SupervisorEvents[K]) => void\n ) => this;\n\n private process: ChildProcess | null = null;\n private lineBuffer = \"\";\n private readonly options: Required<SupervisorOptions>;\n\n private _status: SupervisorStatus = \"starting\";\n private _pid: number | undefined;\n private _restartCount = 0;\n private _totalRestarts = 0;\n private _isShuttingDown = false;\n\n // Sliding window restart tracking\n private restartTimestamps: number[] = [];\n\n // Callbacks waiting for the process to be ready\n private readyWaiters: Array<{ resolve: () => void; reject: (err: Error) => void }> = [];\n\n constructor(options: SupervisorOptions) {\n super();\n this.options = {\n stdio: options.stdio ?? \"\",\n command: options.command ?? \"\",\n args: options.args ?? [],\n env: options.env ?? {},\n maxRestarts: options.maxRestarts ?? 10,\n restartWindowMs: options.restartWindowMs ?? 60_000,\n baseRetryMs: options.baseRetryMs ?? 500,\n maxRetryMs: options.maxRetryMs ?? 30_000,\n traceMcp: options.traceMcp ?? false,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Accessors\n // ---------------------------------------------------------------------------\n\n get status(): SupervisorStatus {\n return this._status;\n }\n\n get pid(): number | undefined {\n return this._pid;\n }\n\n get isReady(): boolean {\n return this._status === \"ready\";\n }\n\n get restartCount(): number {\n return this._restartCount;\n }\n\n get totalRestarts(): number {\n return this._totalRestarts;\n }\n\n get process_ref(): ChildProcess | null {\n return this.process;\n }\n\n // ---------------------------------------------------------------------------\n // Status management\n // ---------------------------------------------------------------------------\n\n private setStatus(next: SupervisorStatus): void {\n const prev = this._status;\n if (prev === next) return;\n this._status = next;\n const logger = getLogger();\n logger.info({ prev, next, pid: this._pid, restarts: this._restartCount }, `[supervisor] status → ${next}`);\n this.emit(\"status\", next, prev);\n\n // Resolve ready waiters when we become ready\n if (next === \"ready\") {\n const waiters = this.readyWaiters.splice(0);\n for (const w of waiters) w.resolve();\n }\n\n // Reject ready waiters when we fail permanently\n if (next === \"failed\" || next === \"stopped\") {\n const waiters = this.readyWaiters.splice(0);\n const err = new Error(`MCP supervisor entered state: ${next}`);\n for (const w of waiters) w.reject(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Wait for ready\n // ---------------------------------------------------------------------------\n\n /** Returns a promise that resolves when supervisor is in \"ready\" state */\n waitForReady(timeoutMs = 120_000): Promise<void> {\n if (this._status === \"ready\") return Promise.resolve();\n if (this._status === \"failed\" || this._status === \"stopped\") {\n return Promise.reject(new Error(`MCP supervisor is in state: ${this._status}`));\n }\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n const idx = this.readyWaiters.findIndex((w) => w.resolve === resolve);\n if (idx !== -1) this.readyWaiters.splice(idx, 1);\n reject(new Error(`Timed out waiting for MCP supervisor to become ready (${timeoutMs}ms)`));\n }, timeoutMs);\n\n this.readyWaiters.push({\n resolve: () => { clearTimeout(timer); resolve(); },\n reject: (err) => { clearTimeout(timer); reject(err); },\n });\n });\n }\n\n // ---------------------------------------------------------------------------\n // Start / spawn\n // ---------------------------------------------------------------------------\n\n async start(): Promise<void> {\n if (this._isShuttingDown) return;\n\n const logger = getLogger();\n const [executable, ...spawnArgs] = this.resolveCommand();\n\n if (!executable) {\n throw new Error(\"No MCP command specified. Use --stdio or --command/--args.\");\n }\n\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n ...this.options.env,\n };\n\n logger.info({ executable, args: spawnArgs }, \"[supervisor] Spawning MCP process...\");\n\n this.lineBuffer = \"\";\n\n const child = spawn(executable, spawnArgs, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n windowsHide: true,\n });\n\n this.process = child;\n this._pid = child.pid;\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n this.onStdoutData(chunk);\n });\n\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString(\"utf8\").trim();\n if (text) {\n if (this.options.traceMcp) {\n logger.debug({ source: \"mcp-stderr\" }, text);\n }\n this.emit(\"stderr-line\", text);\n }\n });\n\n child.on(\"error\", (err) => {\n logger.error({ err: err.message }, \"[supervisor] MCP process spawn error\");\n });\n\n child.on(\"exit\", (code, signal) => {\n this._pid = undefined;\n logger.warn({ code, signal, restarts: this._restartCount }, \"[supervisor] MCP process exited\");\n this.emit(\"process-exit\", code, signal, this._restartCount);\n\n if (!this._isShuttingDown) {\n this.setStatus(\"restarting\");\n this.scheduleRestart();\n } else {\n this.setStatus(\"stopped\");\n }\n });\n\n logger.info({ pid: child.pid }, \"[supervisor] MCP process spawned\");\n this.emit(\"process-start\", child.pid);\n }\n\n // ---------------------------------------------------------------------------\n // STDOUT parsing — emit raw lines to listeners (bridge handles protocol)\n // ---------------------------------------------------------------------------\n\n private onStdoutData(chunk: Buffer): void {\n this.lineBuffer += chunk.toString(\"utf8\");\n const lines = this.lineBuffer.split(\"\\n\");\n this.lineBuffer = lines.pop() ?? \"\";\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed) {\n this.emit(\"stdout-line\", trimmed);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Mark as ready (called by the bridge after initialize handshake)\n // ---------------------------------------------------------------------------\n\n markReady(): void {\n this.setStatus(\"ready\");\n this.emit(\"process-ready\", this._pid);\n }\n\n // ---------------------------------------------------------------------------\n // Restart scheduler with exponential backoff + jitter\n // ---------------------------------------------------------------------------\n\n private scheduleRestart(): void {\n const logger = getLogger();\n if (this._isShuttingDown) return;\n\n const now = Date.now();\n // Prune old timestamps outside the sliding window\n this.restartTimestamps = this.restartTimestamps.filter(\n (ts) => now - ts < this.options.restartWindowMs\n );\n\n if (this.restartTimestamps.length >= this.options.maxRestarts) {\n logger.error(\n {\n restarts: this.restartTimestamps.length,\n windowMs: this.options.restartWindowMs,\n },\n \"[supervisor] Max restart limit exceeded — giving up\"\n );\n this.setStatus(\"failed\");\n this.emit(\"max-restarts-exceeded\");\n return;\n }\n\n this.restartTimestamps.push(now);\n this._restartCount++;\n this._totalRestarts++;\n\n const attempt = this.restartTimestamps.length;\n // Exponential backoff: base * 2^(attempt-1), capped at maxRetryMs, with ±20% jitter\n const base = this.options.baseRetryMs * Math.pow(2, attempt - 1);\n const capped = Math.min(base, this.options.maxRetryMs);\n const jitter = capped * 0.2 * (Math.random() - 0.5); // ±10%\n const delayMs = Math.max(100, Math.round(capped + jitter));\n\n logger.warn(\n { attempt, delayMs, maxRestarts: this.options.maxRestarts },\n `[supervisor] Restarting MCP process in ${delayMs}ms (attempt ${attempt}/${this.options.maxRestarts})...`\n );\n\n sleep(delayMs).then(() => {\n if (!this._isShuttingDown) {\n this.start().catch((err: Error) => {\n logger.error({ err: err.message }, \"[supervisor] Restart failed\");\n this.scheduleRestart();\n });\n }\n });\n }\n\n // ---------------------------------------------------------------------------\n // Send stdin data (used by bridge)\n // ---------------------------------------------------------------------------\n\n write(data: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.process?.stdin) {\n reject(new Error(\"MCP stdin not available (process not running)\"));\n return;\n }\n this.process.stdin.write(data, \"utf8\", (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n // ---------------------------------------------------------------------------\n // Resolve command\n // ---------------------------------------------------------------------------\n\n private resolveCommand(): string[] {\n if (this.options.command) {\n return [this.options.command, ...this.options.args];\n }\n if (this.options.stdio) {\n return splitCommand(this.options.stdio);\n }\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Graceful shutdown\n // ---------------------------------------------------------------------------\n\n async shutdown(): Promise<void> {\n const logger = getLogger();\n if (this._isShuttingDown) return;\n this._isShuttingDown = true;\n\n this.setStatus(\"stopped\");\n\n if (this.process?.pid) {\n logger.info({ pid: this.process.pid }, \"[supervisor] Killing MCP process tree...\");\n await new Promise<void>((resolve) => {\n treeKill(this.process!.pid!, \"SIGTERM\", (err) => {\n if (err) {\n logger.warn({ err }, \"[supervisor] SIGTERM failed, forcing SIGKILL\");\n treeKill(this.process!.pid!, \"SIGKILL\", () => resolve());\n } else {\n resolve();\n }\n });\n });\n }\n\n this.process = null;\n this._pid = undefined;\n logger.info(\"[supervisor] MCP process shutdown complete\");\n }\n}\n","/**\n * Request Queue\n *\n * Buffers MCP JSON-RPC requests during supervisor restart windows so that\n * in-flight and queued requests are not lost. Requests are replayed once\n * the supervisor becomes ready again.\n *\n * Features:\n * - Configurable queue depth\n * - Per-request timeout (independent of the drain timeout)\n * - Graceful drain on shutdown\n * - Metrics exposed for health endpoint\n */\n\nimport { getLogger } from \"./logger.js\";\nimport { sleep } from \"./utils.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface QueuedRequest<T> {\n id: string;\n execute: () => Promise<T>;\n resolve: (value: T) => void;\n reject: (err: Error) => void;\n enqueueTime: number;\n timeoutMs: number;\n timer: ReturnType<typeof setTimeout>;\n}\n\nexport interface RequestQueueOptions {\n /** Maximum requests to hold in queue (default: 500) */\n maxDepth?: number;\n /** How long to wait between drain polls when paused (ms) */\n drainPollMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Request Queue\n// ---------------------------------------------------------------------------\n\nexport class RequestQueue {\n private readonly queue: Array<QueuedRequest<unknown>> = [];\n private readonly options: Required<RequestQueueOptions>;\n\n private _paused = false;\n private _draining = false;\n private _processed = 0;\n private _dropped = 0;\n\n constructor(options: RequestQueueOptions = {}) {\n this.options = {\n maxDepth: options.maxDepth ?? 500,\n drainPollMs: options.drainPollMs ?? 100,\n };\n }\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n get size(): number {\n return this.queue.length;\n }\n\n get isPaused(): boolean {\n return this._paused;\n }\n\n get metrics() {\n return {\n queued: this.queue.length,\n processed: this._processed,\n dropped: this._dropped,\n paused: this._paused,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Pause / Resume (called by bridge when supervisor is restarting)\n // ---------------------------------------------------------------------------\n\n pause(): void {\n const logger = getLogger();\n if (!this._paused) {\n this._paused = true;\n logger.info({ queued: this.queue.length }, \"[queue] Paused — buffering requests\");\n }\n }\n\n resume(executor: (req: QueuedRequest<unknown>) => Promise<void>): void {\n const logger = getLogger();\n if (this._paused) {\n this._paused = false;\n logger.info({ queued: this.queue.length }, \"[queue] Resumed — draining queued requests\");\n void this.drain(executor);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Enqueue a request\n // ---------------------------------------------------------------------------\n\n enqueue<T>(\n execute: () => Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n const logger = getLogger();\n\n if (this.queue.length >= this.options.maxDepth) {\n this._dropped++;\n logger.warn(\n { depth: this.queue.length, maxDepth: this.options.maxDepth },\n \"[queue] Queue full — dropping oldest request\"\n );\n // Drop the oldest item\n const oldest = this.queue.shift();\n if (oldest) {\n clearTimeout(oldest.timer);\n oldest.reject(new Error(\"Request dropped: queue full\"));\n }\n }\n\n return new Promise<T>((resolve, reject) => {\n const id = Math.random().toString(36).slice(2);\n const enqueueTime = Date.now();\n\n const timer = setTimeout(() => {\n const idx = this.queue.findIndex((r) => r.id === id);\n if (idx !== -1) {\n this.queue.splice(idx, 1);\n this._dropped++;\n reject(new Error(`Request timed out after ${timeoutMs}ms while queued`));\n logger.warn({ id, timeoutMs }, \"[queue] Request timed out while queued\");\n }\n }, timeoutMs);\n\n const entry: QueuedRequest<unknown> = {\n id,\n execute: execute as () => Promise<unknown>,\n resolve: resolve as (value: unknown) => void,\n reject,\n enqueueTime,\n timeoutMs,\n timer,\n };\n\n this.queue.push(entry);\n logger.debug({ id, queueDepth: this.queue.length }, \"[queue] Request enqueued\");\n });\n }\n\n // ---------------------------------------------------------------------------\n // Drain queued requests\n // ---------------------------------------------------------------------------\n\n private async drain(executor: (req: QueuedRequest<unknown>) => Promise<void>): Promise<void> {\n if (this._draining) return;\n this._draining = true;\n const logger = getLogger();\n\n while (this.queue.length > 0 && !this._paused) {\n const req = this.queue.shift();\n if (!req) break;\n\n // Check if already timed out\n if (Date.now() - req.enqueueTime > req.timeoutMs) {\n clearTimeout(req.timer);\n this._dropped++;\n req.reject(new Error(\"Request expired before drain\"));\n continue;\n }\n\n clearTimeout(req.timer);\n\n try {\n await executor(req);\n this._processed++;\n } catch (err) {\n logger.warn({ err: (err as Error).message }, \"[queue] Error draining request\");\n req.reject(err as Error);\n this._dropped++;\n }\n\n // Small yield to prevent blocking event loop\n await sleep(0);\n }\n\n this._draining = false;\n if (this.queue.length > 0 && this._paused) {\n logger.debug({ remaining: this.queue.length }, \"[queue] Drain paused mid-flight\");\n }\n }\n\n // ---------------------------------------------------------------------------\n // Flush all pending (shutdown)\n // ---------------------------------------------------------------------------\n\n flush(reason = \"Queue flushed on shutdown\"): void {\n const logger = getLogger();\n logger.info({ count: this.queue.length }, \"[queue] Flushing all queued requests\");\n for (const req of this.queue) {\n clearTimeout(req.timer);\n req.reject(new Error(reason));\n }\n this.queue.length = 0;\n this._paused = false;\n }\n}\n","/**\n * Resilient HTTP/SSE Gateway\n *\n * The HTTP server remains alive even when the backend MCP process restarts.\n * Client SSE connections are maintained via VirtualSessions that survive\n * process restarts. Supervisor status changes are broadcast as SSE events\n * so remote clients know when the backend is temporarily unavailable.\n *\n * Endpoints:\n * GET / — Info page\n * GET /health — Structured health report\n * POST /mcp — MCP JSON-RPC (queued during restarts)\n * GET /sse — Persistent SSE stream (survives MCP restarts)\n * GET /sse/reconnect?sessionId=<id> — Rebind existing session to new transport\n */\n\nimport crypto from \"crypto\";\nimport express, { type Request, type Response, type NextFunction } from \"express\";\nimport cors from \"cors\";\nimport type { Server } from \"http\";\nimport { McpBridge, McpRequestSchema, type McpNotification } from \"./bridge.js\";\nimport { SessionManager } from \"./session.js\";\nimport { HealthMonitor } from \"./health.js\";\nimport { createAuthMiddleware } from \"./middleware/auth.js\";\nimport { getLogger } from \"./logger.js\";\n\n// ---------------------------------------------------------------------------\n// Server options\n// ---------------------------------------------------------------------------\n\nexport interface ServerOptions {\n port: number;\n host: string;\n bridge: McpBridge;\n bearerToken: string;\n corsOrigins: string[];\n protectHealth: boolean;\n allowSseQueryToken: boolean;\n ngrokConnected: () => boolean;\n ngrokUrl: () => string | null;\n version?: string;\n /** Session TTL in ms after disconnect (default: 5 min) */\n sessionTtlMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Create Express application\n// ---------------------------------------------------------------------------\n\nexport function createApp(options: ServerOptions): {\n app: express.Application;\n sessions: SessionManager;\n health: HealthMonitor;\n} {\n const {\n bridge,\n bearerToken,\n corsOrigins,\n protectHealth,\n allowSseQueryToken,\n ngrokConnected,\n ngrokUrl,\n version = \"2026.06.1101\",\n sessionTtlMs = 5 * 60_000,\n } = options;\n\n const logger = getLogger();\n const app = express();\n\n // Trust reverse-proxy headers from Ngrok (X-Forwarded-For, etc.)\n app.set(\"trust proxy\", true);\n\n // ---------------------------------------------------------------------------\n // Persistent session manager\n // ---------------------------------------------------------------------------\n\n const sessions = new SessionManager({ sessionTtlMs });\n\n // ---------------------------------------------------------------------------\n // Health monitor\n // ---------------------------------------------------------------------------\n\n const health = new HealthMonitor({\n bridge,\n sessions,\n version,\n ngrokConnected,\n ngrokUrl,\n });\n\n // ---------------------------------------------------------------------------\n // Global middleware\n // ---------------------------------------------------------------------------\n\n // CORS\n if (corsOrigins.length > 0) {\n app.use(\n cors({\n origin:\n corsOrigins.length === 1 && corsOrigins[0] === \"*\"\n ? \"*\"\n : corsOrigins,\n methods: [\"GET\", \"POST\", \"OPTIONS\"],\n allowedHeaders: [\"Authorization\", \"Content-Type\", \"Last-Event-ID\"],\n exposedHeaders: [\"X-Session-ID\"],\n })\n );\n }\n\n // JSON body parser\n app.use(express.json({ limit: \"1mb\" }));\n\n // Request logger\n app.use((req: Request, _res: Response, next: NextFunction) => {\n logger.debug(\n { method: req.method, path: req.path, ip: req.ip },\n \"→ request\"\n );\n next();\n });\n\n // ---------------------------------------------------------------------------\n // Auth middleware\n // ---------------------------------------------------------------------------\n\n /** Standard Bearer token auth (header only) */\n const authMiddleware = createAuthMiddleware(bearerToken);\n\n /**\n * SSE-compatible auth: accepts token from:\n * - Authorization: Bearer <token> (standard)\n * - ?token=<token> (query param, for Flowise / SSE clients)\n */\n const sseAuthMiddleware = (\n req: Request,\n res: Response,\n next: NextFunction\n ): void => {\n const headerToken = req.headers.authorization?.replace(/^Bearer\\s+/i, \"\");\n const queryToken = allowSseQueryToken\n ? (req.query[\"token\"] as string | undefined)\n : undefined;\n\n const token = headerToken ?? queryToken;\n\n if (!token) {\n res.status(401).json({ error: \"Unauthorized\" });\n return;\n }\n\n try {\n const expected = Buffer.from(bearerToken, \"utf8\");\n const provided = Buffer.from(token, \"utf8\");\n\n if (\n expected.length !== provided.length ||\n !crypto.timingSafeEqual(expected, provided)\n ) {\n res.status(401).json({ error: \"Unauthorized\" });\n return;\n }\n } catch {\n res.status(401).json({ error: \"Unauthorized\" });\n return;\n }\n\n next();\n };\n\n // ---------------------------------------------------------------------------\n // Wire bridge events → SSE broadcast\n // ---------------------------------------------------------------------------\n\n // Broadcast MCP notifications to all connected SSE clients\n bridge.on(\"notification\", (notification: McpNotification) => {\n if (sessions.connectedCount > 0) {\n sessions.broadcast(\"notification\", notification);\n }\n });\n\n // Broadcast supervisor status changes to all SSE clients\n bridge.on(\"supervisor-status\", (status, pid, restartCount) => {\n logger.info({ status, pid, restartCount }, \"[gateway] MCP supervisor status changed\");\n sessions.broadcastSupervisorStatus(status, { pid, restartCount });\n });\n\n // Broadcast permanent failure\n bridge.on(\"max-restarts-exceeded\", () => {\n sessions.broadcast(\"mcp-failed\", {\n message: \"MCP process has permanently failed — please restart the gateway\",\n timestamp: new Date().toISOString(),\n });\n });\n\n // ---------------------------------------------------------------------------\n // Routes\n // ---------------------------------------------------------------------------\n\n /** GET / — Info page */\n app.get(\"/\", (_req: Request, res: Response) => {\n res.json({\n name: \"remote-mcp-ngrok\",\n version,\n description: \"Resilient remote MCP gateway over HTTP + Ngrok\",\n endpoints: {\n mcp: \"POST /mcp\",\n sse: \"GET /sse\",\n sseReconnect: \"GET /sse/reconnect?sessionId=<id>\",\n health: \"GET /health\",\n },\n publicUrl: ngrokUrl(),\n mcp: {\n status: bridge.supervisorStatus,\n running: bridge.isRunning,\n },\n });\n });\n\n // ---------------------------------------------------------------------------\n // GET /health\n // ---------------------------------------------------------------------------\n\n app.get(\n \"/health\",\n ...(protectHealth ? [authMiddleware] : []),\n (_req: Request, res: Response) => {\n const report = health.report();\n // Return 503 if unhealthy so load balancers can detect issues\n const statusCode = report.status === \"unhealthy\" ? 503 : 200;\n res.status(statusCode).json(report);\n }\n );\n\n // ---------------------------------------------------------------------------\n // POST /mcp — Main MCP JSON-RPC endpoint\n // Requests are queued transparently during MCP process restarts.\n // ---------------------------------------------------------------------------\n\n app.post(\"/mcp\", authMiddleware, async (req: Request, res: Response) => {\n const body = req.body as unknown;\n\n const parsed = McpRequestSchema.safeParse(body);\n if (!parsed.success) {\n res.status(400).json({\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32600,\n message: \"Invalid Request\",\n data: parsed.error.issues,\n },\n });\n return;\n }\n\n try {\n const response = await bridge.sendRequest(parsed.data);\n res.json(response);\n } catch (err) {\n const error = err as Error;\n logger.error({ err: error.message, method: parsed.data.method }, \"[gateway] MCP request failed\");\n\n const isTimeout = error.message.includes(\"timeout\");\n const isUnavailable =\n error.message.includes(\"not running\") ||\n error.message.includes(\"permanently failed\") ||\n error.message.includes(\"supervisor status\");\n\n const httpStatus = isTimeout ? 504 : isUnavailable ? 503 : 500;\n const rpcCode = isTimeout ? -32001 : isUnavailable ? -32002 : -32603;\n const rpcMsg = isTimeout\n ? \"Request timeout\"\n : isUnavailable\n ? \"MCP backend unavailable\"\n : \"Internal error\";\n\n res.status(httpStatus).json({\n jsonrpc: \"2.0\",\n id: parsed.data.id ?? null,\n error: {\n code: rpcCode,\n message: rpcMsg,\n data: error.message,\n },\n });\n }\n });\n\n // ---------------------------------------------------------------------------\n // GET /sse — New persistent SSE session\n //\n // Creates a new VirtualSession and binds the SSE transport to it.\n // The session survives transport reconnects within the TTL window.\n // Client receives the stable sessionId on connection for use with /sse/reconnect.\n // ---------------------------------------------------------------------------\n\n app.get(\"/sse\", sseAuthMiddleware, (req: Request, res: Response) => {\n // Set SSE headers\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n res.flushHeaders();\n\n // Create a new persistent virtual session\n const session = sessions.create(`client-${req.ip ?? \"unknown\"}`);\n\n // Expose the session ID in response header (for reconnect)\n res.setHeader(\"X-Session-ID\", session.id);\n\n // Bind transport\n sessions.bind(session.id, res);\n\n logger.info(\n { sessionId: session.id, ip: req.ip },\n \"[gateway] New SSE session established\"\n );\n\n // Send initial connection event with session ID\n res.write(\n `event: connected\\ndata: ${JSON.stringify({\n sessionId: session.id,\n supervisorStatus: bridge.supervisorStatus,\n mcpRunning: bridge.isRunning,\n timestamp: new Date().toISOString(),\n reconnectUrl: \"/sse/reconnect\",\n })}\\n\\n`\n );\n\n // Also immediately send current MCP status\n if (!bridge.isRunning) {\n res.write(\n `event: mcp-status\\ndata: ${JSON.stringify({\n status: bridge.supervisorStatus,\n pid: bridge.pid ?? null,\n restartCount: bridge.restartCount,\n timestamp: new Date().toISOString(),\n })}\\n\\n`\n );\n }\n\n // Clean up on disconnect — session is preserved for reconnect\n req.on(\"close\", () => {\n sessions.unbind(session.id);\n logger.info({ sessionId: session.id }, \"[gateway] SSE transport closed — session preserved\");\n });\n\n req.on(\"error\", () => {\n sessions.unbind(session.id);\n });\n });\n\n // ---------------------------------------------------------------------------\n // GET /sse/reconnect?sessionId=<id>\n //\n // Rebind an existing VirtualSession to a new SSE transport.\n // Enables SSE reconnection without losing session state.\n // Clients should use this after receiving a network error or browser reconnect.\n // ---------------------------------------------------------------------------\n\n app.get(\"/sse/reconnect\", sseAuthMiddleware, (req: Request, res: Response) => {\n const sessionId = req.query[\"sessionId\"] as string | undefined;\n\n if (!sessionId) {\n res.status(400).json({\n error: \"sessionId query parameter required\",\n hint: \"Use the sessionId returned in the initial /sse connected event\",\n });\n return;\n }\n\n const session = sessions.get(sessionId);\n if (!session) {\n // Session expired or never existed — tell client to start fresh\n res.status(410).json({\n error: \"Session expired or not found\",\n hint: \"Connect to /sse to create a new session\",\n code: \"SESSION_EXPIRED\",\n });\n return;\n }\n\n // Set SSE headers\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n res.setHeader(\"X-Session-ID\", sessionId);\n res.flushHeaders();\n\n // Rebind transport to existing session\n const bound = sessions.bind(sessionId, res);\n if (!bound) {\n res.write(\n `event: error\\ndata: ${JSON.stringify({ error: \"Failed to rebind session\" })}\\n\\n`\n );\n res.end();\n return;\n }\n\n logger.info(\n { sessionId, reconnects: session.reconnectCount },\n \"[gateway] SSE session transport rebound (reconnected)\"\n );\n\n // Send reconnect confirmation\n res.write(\n `event: reconnected\\ndata: ${JSON.stringify({\n sessionId,\n reconnectCount: session.reconnectCount,\n supervisorStatus: bridge.supervisorStatus,\n mcpRunning: bridge.isRunning,\n timestamp: new Date().toISOString(),\n })}\\n\\n`\n );\n\n // Send current MCP status\n res.write(\n `event: mcp-status\\ndata: ${JSON.stringify({\n status: bridge.supervisorStatus,\n pid: bridge.pid ?? null,\n restartCount: bridge.restartCount,\n timestamp: new Date().toISOString(),\n })}\\n\\n`\n );\n\n req.on(\"close\", () => {\n sessions.unbind(sessionId);\n logger.info({ sessionId }, \"[gateway] Reconnected SSE transport closed — session preserved\");\n });\n\n req.on(\"error\", () => {\n sessions.unbind(sessionId);\n });\n });\n\n // ---------------------------------------------------------------------------\n // GET /sessions — Active session list (protected)\n // ---------------------------------------------------------------------------\n\n app.get(\"/sessions\", authMiddleware, (_req: Request, res: Response) => {\n const all = sessions.all.map((s) => ({\n id: s.id,\n label: s.label,\n state: s.state,\n createdAt: s.createdAt,\n lastConnectedAt: s.lastConnectedAt,\n lastDisconnectedAt: s.lastDisconnectedAt,\n reconnectCount: s.reconnectCount,\n }));\n res.json({ count: all.length, sessions: all });\n });\n\n // ---------------------------------------------------------------------------\n // 404 handler\n // ---------------------------------------------------------------------------\n\n app.use((_req: Request, res: Response) => {\n res.status(404).json({ error: \"Not found\" });\n });\n\n // ---------------------------------------------------------------------------\n // Error handler\n // ---------------------------------------------------------------------------\n\n app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {\n logger.error({ err: err.message }, \"Unhandled Express error\");\n res.status(500).json({ error: \"Internal server error\" });\n });\n\n return { app, sessions, health };\n}\n\n// ---------------------------------------------------------------------------\n// Start HTTP server\n// ---------------------------------------------------------------------------\n\nexport function startServer(\n app: express.Application,\n port: number,\n host: string\n): Promise<Server> {\n return new Promise((resolve, reject) => {\n const server = app.listen(port, host, () => {\n resolve(server);\n });\n\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n reject(\n new Error(\n `Port ${port} is already in use. Use --port to choose another.`\n )\n );\n } else {\n reject(err);\n }\n });\n\n // Keep SSE connections alive through Ngrok's idle timeout (default 60s)\n server.keepAliveTimeout = 90_000;\n server.headersTimeout = 95_000;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Stop HTTP server\n// ---------------------------------------------------------------------------\n\nexport function stopServer(server: Server): Promise<void> {\n return new Promise((resolve) => {\n server.close(() => resolve());\n });\n}\n","/**\n * Persistent Virtual Session Manager\n *\n * Maintains logical client sessions independently of:\n * - SSE transport connections (can reconnect)\n * - MCP child process lifecycle (survives restarts)\n *\n * A \"session\" represents a persistent logical connection to a remote client.\n * The underlying SSE response object is swappable — when a client reconnects\n * after a network hiccup or the MCP process restarts, the session survives\n * and the new transport is bound to the existing session.\n *\n * Architecture:\n * Remote Client → HTTP SSE connection → VirtualSession → RequestQueue → Bridge\n */\n\nimport crypto from \"crypto\";\nimport { EventEmitter } from \"events\";\nimport type { Response } from \"express\";\nimport { getLogger } from \"./logger.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type SessionState = \"connected\" | \"disconnected\" | \"expired\";\n\nexport interface VirtualSession {\n /** Stable session ID (survives reconnects) */\n readonly id: string;\n /** Human-readable label for logging */\n readonly label: string;\n /** When the session was first created */\n readonly createdAt: Date;\n /** When the transport last connected or reconnected */\n lastConnectedAt: Date | null;\n /** When the transport last disconnected */\n lastDisconnectedAt: Date | null;\n /** Current transport state */\n state: SessionState;\n /** Active SSE response object (null when disconnected) */\n transport: Response | null;\n /** Heartbeat timer handle */\n heartbeatTimer: ReturnType<typeof setInterval> | null;\n /** Expiry timer handle (after disconnect) */\n expiryTimer: ReturnType<typeof setTimeout> | null;\n /** Number of times this session has reconnected */\n reconnectCount: number;\n /** Metadata bag for extensibility */\n meta: Record<string, unknown>;\n}\n\nexport interface SessionManagerOptions {\n /** How long (ms) to keep a disconnected session alive before expiry (default: 5 min) */\n sessionTtlMs?: number;\n /** SSE heartbeat interval (ms) (default: 25s) */\n heartbeatIntervalMs?: number;\n}\n\nexport interface SessionManagerEvents {\n \"session-created\": [session: VirtualSession];\n \"session-connected\": [session: VirtualSession];\n \"session-disconnected\": [session: VirtualSession];\n \"session-expired\": [sessionId: string];\n \"session-reconnected\": [session: VirtualSession];\n}\n\n// ---------------------------------------------------------------------------\n// Session Manager\n// ---------------------------------------------------------------------------\n\nexport class SessionManager extends EventEmitter {\n declare emit: <K extends keyof SessionManagerEvents>(\n event: K,\n ...args: SessionManagerEvents[K]\n ) => boolean;\n declare on: <K extends keyof SessionManagerEvents>(\n event: K,\n listener: (...args: SessionManagerEvents[K]) => void\n ) => this;\n\n private readonly sessions = new Map<string, VirtualSession>();\n private readonly options: Required<SessionManagerOptions>;\n\n constructor(options: SessionManagerOptions = {}) {\n super();\n this.options = {\n sessionTtlMs: options.sessionTtlMs ?? 5 * 60_000, // 5 minutes\n heartbeatIntervalMs: options.heartbeatIntervalMs ?? 25_000,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Create a new virtual session\n // ---------------------------------------------------------------------------\n\n create(label?: string): VirtualSession {\n const id = crypto.randomUUID();\n const session: VirtualSession = {\n id,\n label: label ?? `session-${id.slice(0, 8)}`,\n createdAt: new Date(),\n lastConnectedAt: null,\n lastDisconnectedAt: null,\n state: \"disconnected\",\n transport: null,\n heartbeatTimer: null,\n expiryTimer: null,\n reconnectCount: 0,\n meta: {},\n };\n\n this.sessions.set(id, session);\n const logger = getLogger();\n logger.info({ sessionId: id, label: session.label }, \"[session] Created virtual session\");\n this.emit(\"session-created\", session);\n return session;\n }\n\n // ---------------------------------------------------------------------------\n // Bind a transport (SSE Response) to a session\n // ---------------------------------------------------------------------------\n\n bind(sessionId: string, res: Response): VirtualSession | null {\n const logger = getLogger();\n let session = this.sessions.get(sessionId);\n\n if (!session) {\n logger.warn({ sessionId }, \"[session] bind() called for unknown session\");\n return null;\n }\n\n const wasDisconnected = session.state === \"disconnected\";\n\n // Cancel expiry timer — session is alive again\n if (session.expiryTimer) {\n clearTimeout(session.expiryTimer);\n session.expiryTimer = null;\n }\n\n // Stop old heartbeat if any\n this.stopHeartbeat(session);\n\n // Bind new transport\n session.transport = res;\n session.state = \"connected\";\n session.lastConnectedAt = new Date();\n\n if (wasDisconnected && session.reconnectCount > 0) {\n session.reconnectCount++;\n logger.info(\n { sessionId, reconnects: session.reconnectCount },\n \"[session] Session transport reconnected\"\n );\n this.emit(\"session-reconnected\", session);\n } else {\n session.reconnectCount++;\n this.emit(\"session-connected\", session);\n }\n\n // Start heartbeat\n this.startHeartbeat(session);\n\n logger.info({ sessionId, label: session.label }, \"[session] Transport bound\");\n return session;\n }\n\n // ---------------------------------------------------------------------------\n // Unbind transport (disconnect without destroying session)\n // ---------------------------------------------------------------------------\n\n unbind(sessionId: string): void {\n const logger = getLogger();\n const session = this.sessions.get(sessionId);\n if (!session) return;\n\n this.stopHeartbeat(session);\n\n session.transport = null;\n session.state = \"disconnected\";\n session.lastDisconnectedAt = new Date();\n\n logger.info(\n { sessionId, label: session.label },\n \"[session] Transport unbound — session preserved for reconnect\"\n );\n\n this.emit(\"session-disconnected\", session);\n\n // Schedule expiry\n session.expiryTimer = setTimeout(() => {\n this.expire(sessionId);\n }, this.options.sessionTtlMs);\n }\n\n // ---------------------------------------------------------------------------\n // Expire a session permanently\n // ---------------------------------------------------------------------------\n\n private expire(sessionId: string): void {\n const logger = getLogger();\n const session = this.sessions.get(sessionId);\n if (!session) return;\n\n this.stopHeartbeat(session);\n if (session.expiryTimer) {\n clearTimeout(session.expiryTimer);\n session.expiryTimer = null;\n }\n\n session.state = \"expired\";\n this.sessions.delete(sessionId);\n\n logger.info({ sessionId, label: session.label }, \"[session] Session expired (TTL exceeded)\");\n this.emit(\"session-expired\", sessionId);\n }\n\n // ---------------------------------------------------------------------------\n // Destroy a session immediately (e.g., on explicit client logout or shutdown)\n // ---------------------------------------------------------------------------\n\n destroy(sessionId: string): void {\n const logger = getLogger();\n const session = this.sessions.get(sessionId);\n if (!session) return;\n\n this.stopHeartbeat(session);\n if (session.expiryTimer) {\n clearTimeout(session.expiryTimer);\n session.expiryTimer = null;\n }\n\n // Close transport if open\n if (session.transport && !session.transport.writableEnded) {\n try {\n session.transport.end();\n } catch {\n // ignore\n }\n }\n\n session.state = \"expired\";\n this.sessions.delete(sessionId);\n logger.info({ sessionId }, \"[session] Session destroyed\");\n }\n\n // ---------------------------------------------------------------------------\n // Broadcast to all connected sessions\n // ---------------------------------------------------------------------------\n\n broadcast(event: string, data: unknown): void {\n const logger = getLogger();\n const payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n let sent = 0;\n let cleaned = 0;\n\n for (const [id, session] of this.sessions) {\n if (session.state !== \"connected\" || !session.transport) continue;\n\n if (session.transport.writableEnded) {\n this.unbind(id);\n cleaned++;\n continue;\n }\n\n try {\n session.transport.write(payload);\n sent++;\n } catch {\n this.unbind(id);\n cleaned++;\n }\n }\n\n if (sent > 0 || cleaned > 0) {\n logger.debug(\n { event, sent, cleaned },\n \"[session] Broadcast complete\"\n );\n }\n }\n\n /**\n * Send an event to a specific session only.\n */\n send(sessionId: string, event: string, data: unknown): boolean {\n const session = this.sessions.get(sessionId);\n if (!session || session.state !== \"connected\" || !session.transport) return false;\n if (session.transport.writableEnded) {\n this.unbind(sessionId);\n return false;\n }\n try {\n const payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n session.transport.write(payload);\n return true;\n } catch {\n this.unbind(sessionId);\n return false;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Send supervisor status update to all SSE clients\n // ---------------------------------------------------------------------------\n\n broadcastSupervisorStatus(status: string, extra: Record<string, unknown> = {}): void {\n this.broadcast(\"mcp-status\", { status, ...extra, timestamp: new Date().toISOString() });\n }\n\n // ---------------------------------------------------------------------------\n // Heartbeat\n // ---------------------------------------------------------------------------\n\n private startHeartbeat(session: VirtualSession): void {\n session.heartbeatTimer = setInterval(() => {\n if (!session.transport || session.transport.writableEnded) {\n this.unbind(session.id);\n return;\n }\n try {\n session.transport.write(\": heartbeat\\n\\n\");\n } catch {\n this.unbind(session.id);\n }\n }, this.options.heartbeatIntervalMs);\n }\n\n private stopHeartbeat(session: VirtualSession): void {\n if (session.heartbeatTimer) {\n clearInterval(session.heartbeatTimer);\n session.heartbeatTimer = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Accessors\n // ---------------------------------------------------------------------------\n\n get(sessionId: string): VirtualSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n has(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n get size(): number {\n return this.sessions.size;\n }\n\n get connectedCount(): number {\n let count = 0;\n for (const s of this.sessions.values()) {\n if (s.state === \"connected\") count++;\n }\n return count;\n }\n\n get all(): VirtualSession[] {\n return Array.from(this.sessions.values());\n }\n\n // ---------------------------------------------------------------------------\n // Shutdown — destroy all sessions\n // ---------------------------------------------------------------------------\n\n destroyAll(reason = \"Server shutting down\"): void {\n const logger = getLogger();\n logger.info({ count: this.sessions.size }, \"[session] Destroying all sessions\");\n\n for (const session of this.sessions.values()) {\n this.stopHeartbeat(session);\n if (session.expiryTimer) clearTimeout(session.expiryTimer);\n\n if (session.transport && !session.transport.writableEnded) {\n try {\n session.transport.write(\n `event: server-shutdown\\ndata: ${JSON.stringify({ reason })}\\n\\n`\n );\n session.transport.end();\n } catch {\n // ignore\n }\n }\n }\n this.sessions.clear();\n }\n}\n","/**\n * Health Monitor\n *\n * Tracks gateway liveness metrics and provides structured health data\n * for the /health endpoint and internal diagnostics.\n *\n * Features:\n * - Process uptime and memory usage\n * - MCP supervisor status and restart history\n * - SSE session counts\n * - Request queue metrics\n * - Ngrok tunnel status\n * - Overall health score (healthy / degraded / unhealthy)\n */\n\nimport { McpBridge } from \"./bridge.js\";\nimport { SessionManager } from \"./session.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type HealthStatus = \"healthy\" | \"degraded\" | \"unhealthy\";\n\nexport interface HealthReport {\n status: HealthStatus;\n uptime: number;\n timestamp: string;\n gateway: {\n version: string;\n pid: number;\n memory: {\n rss: string;\n heapUsed: string;\n heapTotal: string;\n };\n };\n mcp: {\n supervisorStatus: string;\n running: boolean;\n pid: number | null;\n restartCount: number;\n totalRestarts: number;\n queueSize: number;\n queueMetrics: {\n queued: number;\n processed: number;\n dropped: number;\n paused: boolean;\n };\n };\n sessions: {\n total: number;\n connected: number;\n };\n ngrok: {\n connected: boolean;\n url: string | null;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Health Monitor\n// ---------------------------------------------------------------------------\n\nexport class HealthMonitor {\n private readonly bridge: McpBridge;\n private readonly sessions: SessionManager;\n private readonly version: string;\n private readonly ngrokConnected: () => boolean;\n private readonly ngrokUrl: () => string | null;\n\n constructor(opts: {\n bridge: McpBridge;\n sessions: SessionManager;\n version: string;\n ngrokConnected: () => boolean;\n ngrokUrl: () => string | null;\n }) {\n this.bridge = opts.bridge;\n this.sessions = opts.sessions;\n this.version = opts.version;\n this.ngrokConnected = opts.ngrokConnected;\n this.ngrokUrl = opts.ngrokUrl;\n }\n\n // ---------------------------------------------------------------------------\n // Build a health report snapshot\n // ---------------------------------------------------------------------------\n\n report(): HealthReport {\n const mem = process.memoryUsage();\n\n const mcp = {\n supervisorStatus: this.bridge.supervisorStatus,\n running: this.bridge.isRunning,\n pid: this.bridge.pid ?? null,\n restartCount: this.bridge.restartCount,\n totalRestarts: this.bridge.totalRestarts,\n queueSize: this.bridge.queueSize,\n queueMetrics: this.bridge.queueMetrics,\n };\n\n const sessionInfo = {\n total: this.sessions.size,\n connected: this.sessions.connectedCount,\n };\n\n const ngrok = {\n connected: this.ngrokConnected(),\n url: this.ngrokUrl(),\n };\n\n // ---------------------------------------------------------------------------\n // Determine overall health status\n // ---------------------------------------------------------------------------\n\n let status: HealthStatus = \"healthy\";\n\n if (mcp.supervisorStatus === \"failed\") {\n // Supervisor permanently gave up\n status = \"unhealthy\";\n } else if (mcp.supervisorStatus === \"stopped\") {\n status = \"unhealthy\";\n } else if (!mcp.running && mcp.supervisorStatus === \"restarting\") {\n // Temporary restart — degraded, not unhealthy\n status = \"degraded\";\n } else if (!ngrok.connected) {\n // Ngrok down — public endpoint unavailable\n status = \"degraded\";\n }\n\n return {\n status,\n uptime: process.uptime(),\n timestamp: new Date().toISOString(),\n gateway: {\n version: this.version,\n pid: process.pid,\n memory: {\n rss: formatBytes(mem.rss),\n heapUsed: formatBytes(mem.heapUsed),\n heapTotal: formatBytes(mem.heapTotal),\n },\n },\n mcp,\n sessions: sessionInfo,\n ngrok,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Simple boolean liveness check\n // ---------------------------------------------------------------------------\n\n isAlive(): boolean {\n const r = this.report();\n return r.status !== \"unhealthy\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n","import crypto from \"crypto\";\nimport type { Request, Response, NextFunction } from \"express\";\nimport { getLogger } from \"../logger.js\";\n\n/**\n * Create Bearer token authentication middleware.\n *\n * Uses a length-checked timing-safe comparison to prevent:\n * - Timing attacks\n * - Node.js buffer length mismatch throws\n */\nexport function createAuthMiddleware(expectedToken: string) {\n return function authMiddleware(\n req: Request,\n res: Response,\n next: NextFunction\n ): void {\n const logger = getLogger();\n const authHeader = req.headers[\"authorization\"];\n\n if (!authHeader) {\n logger.warn(\n { ip: req.ip, path: req.path },\n \"Rejected request: missing Authorization header\"\n );\n res.status(401).json({ error: \"Unauthorized\" });\n return;\n }\n\n if (!authHeader.startsWith(\"Bearer \")) {\n logger.warn(\n { ip: req.ip, path: req.path },\n \"Rejected request: invalid Authorization format (expected Bearer)\"\n );\n res.status(401).json({ error: \"Unauthorized\" });\n return;\n }\n\n const providedToken = authHeader.slice(\"Bearer \".length).trim();\n\n if (!isTokenValid(providedToken, expectedToken)) {\n logger.warn(\n { ip: req.ip, path: req.path },\n \"Rejected request: invalid bearer token\"\n );\n res.status(401).json({ error: \"Unauthorized\" });\n return;\n }\n\n next();\n };\n}\n\n/**\n * Perform a timing-safe comparison of two token strings.\n * Returns false if lengths differ (avoids Node.js timingSafeEqual throw).\n */\nfunction isTokenValid(provided: string, expected: string): boolean {\n // Must check lengths first — timingSafeEqual requires equal-length buffers\n if (provided.length !== expected.length) {\n return false;\n }\n if (provided.length === 0) {\n return false;\n }\n\n try {\n const providedBuf = Buffer.from(provided, \"utf8\");\n const expectedBuf = Buffer.from(expected, \"utf8\");\n return crypto.timingSafeEqual(providedBuf, expectedBuf);\n } catch {\n return false;\n }\n}\n","import * as ngrok from \"@ngrok/ngrok\";\nimport { getLogger } from \"./logger.js\";\n\nexport interface NgrokOptions {\n authtoken: string;\n domain: string;\n addr: number | string;\n}\n\nexport interface NgrokTunnel {\n url: string;\n close: () => Promise<void>;\n}\n\nlet _listener: ngrok.Listener | null = null;\nlet _connected = false;\nlet _publicUrl: string | null = null;\n\n/**\n * Start an Ngrok tunnel using the official @ngrok/ngrok SDK.\n * Binds to a static domain if provided.\n */\nexport async function startNgrokTunnel(\n options: NgrokOptions\n): Promise<NgrokTunnel> {\n const logger = getLogger();\n\n logger.info({ domain: options.domain }, \"Connecting to Ngrok...\");\n\n try {\n const listener = await ngrok.connect({\n authtoken: options.authtoken,\n addr: options.addr,\n domain: options.domain,\n });\n\n const url = listener.url();\n\n if (!url) {\n throw new Error(\"Ngrok tunnel started but no URL was returned.\");\n }\n\n _listener = listener;\n _connected = true;\n _publicUrl = url;\n\n logger.info({ url }, \"Ngrok tunnel established\");\n\n return {\n url,\n close: async () => {\n await closeNgrokTunnel();\n },\n };\n } catch (err) {\n const error = err as Error;\n _connected = false;\n\n // Provide user-friendly error messages for common failures\n const message = error.message ?? String(error);\n\n if (\n message.includes(\"authentication failed\") ||\n message.includes(\"invalid authtoken\") ||\n message.includes(\"ERR_NGROK_105\")\n ) {\n throw new Error(\n `Ngrok authentication failed. Check your --ngrok-authtoken value.\\n Detail: ${message}`\n );\n }\n\n if (\n message.includes(\"is already bound\") ||\n message.includes(\"tunnel already registered\") ||\n message.includes(\"ERR_NGROK_302\") ||\n message.includes(\"ERR_NGROK_8012\")\n ) {\n throw new Error(\n `Ngrok domain '${options.domain}' is already in use. ` +\n `Wait a few minutes or use a different domain.\\n Detail: ${message}`\n );\n }\n\n if (\n message.includes(\"domain not found\") ||\n message.includes(\"ERR_NGROK_325\") ||\n message.includes(\"ERR_NGROK_8019\")\n ) {\n throw new Error(\n `Ngrok domain '${options.domain}' not found. ` +\n `Make sure you have claimed this domain at https://dashboard.ngrok.com/\\n Detail: ${message}`\n );\n }\n\n throw new Error(`Ngrok connection failed: ${message}`);\n }\n}\n\n/**\n * Gracefully close the active Ngrok tunnel.\n */\nexport async function closeNgrokTunnel(): Promise<void> {\n const logger = getLogger();\n\n if (_listener) {\n try {\n await _listener.close();\n logger.info(\"Ngrok tunnel closed\");\n } catch (err) {\n logger.warn({ err }, \"Error closing Ngrok tunnel\");\n }\n _listener = null;\n }\n\n _connected = false;\n _publicUrl = null;\n}\n\n/**\n * Check if Ngrok tunnel is currently connected.\n */\nexport function isNgrokConnected(): boolean {\n return _connected;\n}\n\n/**\n * Get the current public Ngrok URL.\n */\nexport function getNgrokUrl(): string | null {\n return _publicUrl;\n}\n"],"mappings":"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","names":["key","EventEmitter","z","z","EventEmitter","crypto","crypto","EventEmitter","ngrok","crypto","crypto","getLogger"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "remote-mcp-ngrok",
|
|
3
|
+
"version": "2026.6.1202",
|
|
4
|
+
"description": "Resilient remote MCP gateway — expose local MCP stdio servers over the internet with auto-recovery, session persistence, and request queueing via Ngrok",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"remote-mcp-ngrok": "dist/index.js",
|
|
8
|
+
"playwright-mcp-ngrok": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "tsx src/index.ts",
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"build:obfuscate": "javascript-obfuscator dist/index.js --output dist/index.js --compact true --self-defending false --disable-console-output false --identifier-names-generator hexadecimal --rename-globals false --string-array true --string-array-encoding rc4 --string-array-threshold 0.5 --transform-object-keys true --unicode-escape-sequence false",
|
|
23
|
+
"validate:dist": "node dist/index.js --help",
|
|
24
|
+
"start": "node dist/index.js",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"lint": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mcp",
|
|
30
|
+
"remote-mcp",
|
|
31
|
+
"ngrok",
|
|
32
|
+
"mcp-server",
|
|
33
|
+
"model-context-protocol",
|
|
34
|
+
"ai",
|
|
35
|
+
"llm",
|
|
36
|
+
"flowise",
|
|
37
|
+
"openwebui",
|
|
38
|
+
"claude",
|
|
39
|
+
"n8n",
|
|
40
|
+
"langflow",
|
|
41
|
+
"resilient",
|
|
42
|
+
"gateway",
|
|
43
|
+
"tunnel",
|
|
44
|
+
"stdio-bridge",
|
|
45
|
+
"auto-recovery",
|
|
46
|
+
"session-management",
|
|
47
|
+
"playwright"
|
|
48
|
+
],
|
|
49
|
+
"author": "",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=20.0.0"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@ngrok/ngrok": "^1.4.0",
|
|
56
|
+
"commander": "^12.1.0",
|
|
57
|
+
"cors": "^2.8.5",
|
|
58
|
+
"cross-spawn": "^7.0.3",
|
|
59
|
+
"dotenv": "^16.4.5",
|
|
60
|
+
"express": "^4.19.2",
|
|
61
|
+
"js-yaml": "^4.1.0",
|
|
62
|
+
"pino": "^9.3.2",
|
|
63
|
+
"pino-pretty": "^11.2.1",
|
|
64
|
+
"tree-kill": "^1.2.2",
|
|
65
|
+
"zod": "^3.23.8"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/cors": "^2.8.17",
|
|
69
|
+
"@types/cross-spawn": "^6.0.6",
|
|
70
|
+
"@types/express": "^4.17.21",
|
|
71
|
+
"@types/js-yaml": "^4.0.9",
|
|
72
|
+
"@types/node": "^20.14.10",
|
|
73
|
+
"javascript-obfuscator": "^5.4.3",
|
|
74
|
+
"tsup": "^8.1.0",
|
|
75
|
+
"tsx": "^4.16.2",
|
|
76
|
+
"typescript": "^5.5.3"
|
|
77
|
+
}
|
|
78
|
+
}
|