agent-task-manager-mcp 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +187 -22
  2. package/dist/certs.d.ts +11 -0
  3. package/dist/certs.d.ts.map +1 -0
  4. package/dist/certs.js +56 -0
  5. package/dist/certs.js.map +1 -0
  6. package/dist/cli.d.ts +14 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +35 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/hostValidation.d.ts +3 -0
  11. package/dist/hostValidation.d.ts.map +1 -0
  12. package/dist/hostValidation.js +58 -0
  13. package/dist/hostValidation.js.map +1 -0
  14. package/dist/http.server.d.ts +13 -0
  15. package/dist/http.server.d.ts.map +1 -0
  16. package/dist/http.server.js +188 -0
  17. package/dist/http.server.js.map +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +19 -62
  20. package/dist/index.js.map +1 -1
  21. package/dist/server.d.ts +36 -0
  22. package/dist/server.d.ts.map +1 -0
  23. package/dist/server.js +64 -0
  24. package/dist/server.js.map +1 -0
  25. package/dist/storage/adapters/json.adapter.d.ts +3 -0
  26. package/dist/storage/adapters/json.adapter.d.ts.map +1 -0
  27. package/dist/storage/adapters/json.adapter.js +314 -0
  28. package/dist/storage/adapters/json.adapter.js.map +1 -0
  29. package/dist/storage/adapters/mongodb.adapter.d.ts +3 -0
  30. package/dist/storage/adapters/mongodb.adapter.d.ts.map +1 -0
  31. package/dist/storage/adapters/mongodb.adapter.js +232 -0
  32. package/dist/storage/adapters/mongodb.adapter.js.map +1 -0
  33. package/dist/storage/adapters/postgres.adapter.d.ts +3 -0
  34. package/dist/storage/adapters/postgres.adapter.d.ts.map +1 -0
  35. package/dist/storage/adapters/postgres.adapter.js +440 -0
  36. package/dist/storage/adapters/postgres.adapter.js.map +1 -0
  37. package/dist/storage/adapters/sqlite.adapter.d.ts +3 -0
  38. package/dist/storage/adapters/sqlite.adapter.d.ts.map +1 -0
  39. package/dist/storage/adapters/sqlite.adapter.js +437 -0
  40. package/dist/storage/adapters/sqlite.adapter.js.map +1 -0
  41. package/dist/storage/index.d.ts +17 -0
  42. package/dist/storage/index.d.ts.map +1 -0
  43. package/dist/storage/index.js +22 -0
  44. package/dist/storage/index.js.map +1 -0
  45. package/dist/storage/interface.d.ts +72 -0
  46. package/dist/storage/interface.d.ts.map +1 -0
  47. package/dist/storage/interface.js +3 -0
  48. package/dist/storage/interface.js.map +1 -0
  49. package/dist/storage/json.adapter.d.ts +3 -0
  50. package/dist/storage/json.adapter.d.ts.map +1 -0
  51. package/dist/storage/json.adapter.js +314 -0
  52. package/dist/storage/json.adapter.js.map +1 -0
  53. package/dist/storage/mongodb.adapter.d.ts +3 -0
  54. package/dist/storage/mongodb.adapter.d.ts.map +1 -0
  55. package/dist/storage/mongodb.adapter.js +232 -0
  56. package/dist/storage/mongodb.adapter.js.map +1 -0
  57. package/dist/storage/router.d.ts +30 -0
  58. package/dist/storage/router.d.ts.map +1 -0
  59. package/dist/storage/router.js +100 -0
  60. package/dist/storage/router.js.map +1 -0
  61. package/dist/storage/sqlite.adapter.d.ts +3 -0
  62. package/dist/storage/sqlite.adapter.d.ts.map +1 -0
  63. package/dist/storage/sqlite.adapter.js +437 -0
  64. package/dist/storage/sqlite.adapter.js.map +1 -0
  65. package/dist/storage/types.d.ts +80 -0
  66. package/dist/storage/types.d.ts.map +1 -0
  67. package/dist/storage/types.js +7 -0
  68. package/dist/storage/types.js.map +1 -0
  69. package/dist/tools/checkpoint.tools.d.ts.map +1 -1
  70. package/dist/tools/checkpoint.tools.js +8 -21
  71. package/dist/tools/checkpoint.tools.js.map +1 -1
  72. package/dist/tools/session.tools.d.ts.map +1 -1
  73. package/dist/tools/session.tools.js +21 -30
  74. package/dist/tools/session.tools.js.map +1 -1
  75. package/dist/tools/subtask.tools.d.ts.map +1 -1
  76. package/dist/tools/subtask.tools.js +9 -32
  77. package/dist/tools/subtask.tools.js.map +1 -1
  78. package/dist/tools/task.tools.d.ts.map +1 -1
  79. package/dist/tools/task.tools.js +23 -50
  80. package/dist/tools/task.tools.js.map +1 -1
  81. package/package.json +18 -4
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.5-blue.svg)](https://www.typescriptlang.org/)
6
6
  [![MCP](https://img.shields.io/badge/MCP-1.0-green.svg)](https://modelcontextprotocol.io/)
7
- [![MongoDB](https://img.shields.io/badge/MongoDB-ODM-green.svg)](https://mongoosejs.com/)
7
+ [![Storage](https://img.shields.io/badge/Storage-MongoDB%20%7C%20PostgreSQL%20%7C%20SQLite%20%7C%20JSON-green.svg)]()
8
8
 
9
9
  ```bash
10
10
  npm install -g agent-task-manager-mcp
@@ -93,7 +93,7 @@ AI agents operate within a fixed **context window** (e.g., 100K–200K tokens).
93
93
  │ │ │
94
94
  │ ▼ │
95
95
  │ ┌───────────────────────────────┐ │
96
- │ │ MongoDB
96
+ │ │ Storage (MongoDB/SQLite/JSON)
97
97
  │ │ Tasks • Subtasks • Sessions │ │
98
98
  │ │ Checkpoints • Progress │ │
99
99
  │ └───────────────────────────────┘ │
@@ -120,11 +120,11 @@ flowchart TB
120
120
  end
121
121
 
122
122
  subgraph Storage["Persistence"]
123
- MongoDB[(MongoDB)]
123
+ DB[(MongoDB / SQLite / JSON)]
124
124
  end
125
125
 
126
- Agent <-->|stdio/JSON-RPC| Server
127
- Server <-->|Mongoose| MongoDB
126
+ Agent <-->|stdio or HTTP| Server
127
+ Server <-->|Storage Adapter| DB
128
128
 
129
129
  subgraph ToolsDetail["Tool Categories"]
130
130
  T1[task_*]
@@ -238,7 +238,7 @@ flowchart LR
238
238
  ## Features
239
239
 
240
240
  - **14 MCP tools** for full task lifecycle
241
- - **MongoDB persistence** with Mongoose ODM
241
+ - **MongoDB, SQLite, or JSON file** storage (configurable)
242
242
  - **Zod validation** on all tool inputs
243
243
  - **Task locking** for multi-agent coordination
244
244
  - **Evidence-based verification** (no passing without proof)
@@ -252,8 +252,8 @@ flowchart LR
252
252
  ### Prerequisites
253
253
 
254
254
  - **Node.js** 18+
255
- - **MongoDB** 6+ (local, remote IP, or Atlas)
256
- - **MCP-compatible client** (Claude Desktop, Cursor, etc.)
255
+ - **Storage backend** (choose one): MongoDB 6+, PostgreSQL 12+, SQLite (file-based), or JSON file
256
+ - **MCP-compatible client** (Claude Desktop, Cursor, ChatGPT Desktop, etc.)
257
257
 
258
258
  ### Installation
259
259
 
@@ -265,11 +265,9 @@ npm install
265
265
 
266
266
  ### Environment Setup
267
267
 
268
- (optional and can be define in MCP config of the agent in MONGODB_URI)
269
-
270
268
  ```bash
271
269
  cp .env.example .env
272
- # Edit .env and set MONGODB_URI
270
+ # Edit .env and set STORAGE (mongodb | postgres | sqlite | json) and the corresponding backend config
273
271
  ```
274
272
 
275
273
  ### Run
@@ -277,18 +275,66 @@ cp .env.example .env
277
275
  ```bash
278
276
  # Production (compiled)
279
277
  npm run build
278
+
279
+ # Stdio mode (default) — for Claude Desktop, Cursor
280
280
  npm start
281
+ node dist/index.js
282
+
283
+ # HTTP mode (default 8000; auto-finds free port if busy)
284
+ npm run start:http
285
+ node dist/index.js --http
286
+
287
+ # HTTPS mode (default 8443; auto-finds free port if busy)
288
+ npm run start:https
289
+ node dist/index.js --https
290
+
291
+ # Custom port (node directly — npm eats --port)
292
+ node dist/index.js --http --port=3000
293
+
294
+ # HTTPS with user-provided cert and key (separate files)
295
+ agent-task-manager-mcp --https --cert=./certs/cert.pem --key=./certs/key.pem
296
+
297
+ # HTTPS with combined cert+key file (mkcert, or single PEM with both blocks)
298
+ agent-task-manager-mcp --https --cert-key=./certs/localhost.pem
299
+ agent-task-manager-mcp --https --cert=./certs/combined.pem
281
300
  ```
282
301
 
283
302
  ---
284
303
 
285
304
  ## Configuration
286
305
 
306
+ ### Storage Backends
307
+
308
+ | `STORAGE` | Use when | Config |
309
+ |-----------|----------|--------|
310
+ | `mongodb` | Production, multi-agent, document store | `MONGODB_URI` required |
311
+ | `postgres` | Enterprise, high concurrency, swarm of agents | `POSTGRES_URL` or `DATABASE_URL` required |
312
+ | `sqlite` | Local dev, no server, single-file | `SQLITE_PATH` (default: `./data/agent-tasks.db`) |
313
+ | `json` | Quick testing, single agent | `JSON_STORAGE_PATH` (default: `./data/agent-tasks.json`) |
314
+
315
+ ### Choosing a Backend
316
+
317
+ | Scenario | Recommended |
318
+ |----------|-------------|
319
+ | Swarm of agents, production | `postgres` or `mongodb` |
320
+ | Single agent, local dev | `sqlite` |
321
+ | Quick test, no DB setup | `json` |
322
+ | Existing MongoDB/Postgres infra | Use matching backend |
323
+
324
+ ### Swarm / Multi-Agent
325
+
326
+ For multiple agents working on tasks concurrently: use **PostgreSQL** or **MongoDB**. Both support task locking and concurrent writes. SQLite and JSON are single-writer; fine for one agent but may conflict with multiple.
327
+
287
328
  ### Environment Variables
288
329
 
289
- | Variable | Required | Description | Example |
290
- | ------------- | -------- | ------------------------- | --------------------------------------- |
291
- | `MONGODB_URI` | Yes | MongoDB connection string | `mongodb://localhost:27017/agent-tasks` |
330
+ | Variable | Required when | Description | Example |
331
+ |----------|---------------|-------------|---------|
332
+ | `STORAGE` | No | Backend: `mongodb` \| `postgres` \| `sqlite` \| `json` (default: `mongodb`) | `postgres` |
333
+ | `MONGODB_URI` | `STORAGE=mongodb` | MongoDB connection string | `mongodb://localhost:27017/agent-tasks` |
334
+ | `POSTGRES_URL` or `DATABASE_URL` | `STORAGE=postgres` | PostgreSQL connection string | `postgresql://user:pass@localhost:5432/agent_tasks` |
335
+ | `SQLITE_PATH` | `STORAGE=sqlite` | SQLite database file path | `./data/agent-tasks.db` |
336
+ | `JSON_STORAGE_PATH` | `STORAGE=json` | JSON file path | `./data/agent-tasks.json` |
337
+ | `MCP_ALLOWED_HOSTS` | No | Comma-separated hosts for HTTP/HTTPS (ngrok, etc) | `myapp.ngrok.io,custom.local` |
292
338
 
293
339
  ### MongoDB URI Examples
294
340
 
@@ -303,15 +349,27 @@ MONGODB_URI=mongodb://user:password@IP2:27017/agent-tasks?authSource=admin
303
349
  MONGODB_URI=mongodb+srv://user:password@cluster.mongodb.net/agent-tasks?retryWrites=true&w=majority
304
350
  ```
305
351
 
352
+ ### PostgreSQL URI Examples
353
+
354
+ ```env
355
+ # Local
356
+ POSTGRES_URL=postgresql://user:password@localhost:5432/agent_tasks
357
+
358
+ # Supabase, Neon, Railway, etc.
359
+ DATABASE_URL=postgresql://user:password@host:5432/dbname?sslmode=require
360
+ ```
361
+
306
362
  > **Note:** URL-encode special characters in passwords (e.g., `@` → `%40`).
307
363
 
308
364
  ---
309
365
 
310
366
  ## Integration
311
367
 
312
- ### Claude Desktop
368
+ ### Option 1: Global install (recommended)
369
+
370
+ After `npm install -g agent-task-manager-mcp`, use the binary name. No path or `npx` needed.
313
371
 
314
- Add to `claude_desktop_config.json`:
372
+ **Claude Desktop** — add to `claude_desktop_config.json`:
315
373
 
316
374
  **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
317
375
  **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
@@ -320,9 +378,10 @@ Add to `claude_desktop_config.json`:
320
378
  {
321
379
  "mcpServers": {
322
380
  "agent-task-manager-mcp": {
323
- "command": "npx",
324
- "args": ["tsx", "C:/path/to/agent-task-manager-mcp/src/index.ts"],
381
+ "command": "agent-task-manager-mcp",
382
+ "args": [],
325
383
  "env": {
384
+ "STORAGE": "mongodb",
326
385
  "MONGODB_URI": "mongodb://localhost:27017/agent-tasks"
327
386
  }
328
387
  }
@@ -330,9 +389,80 @@ Add to `claude_desktop_config.json`:
330
389
  }
331
390
  ```
332
391
 
333
- ### Cursor
392
+ **Cursor** — add to MCP settings or `.cursor/mcp.json`:
393
+
394
+ ```json
395
+ {
396
+ "mcpServers": {
397
+ "agent-task-manager-mcp": {
398
+ "command": "agent-task-manager-mcp",
399
+ "args": [],
400
+ "env": {
401
+ "STORAGE": "sqlite",
402
+ "SQLITE_PATH": "./data/agent-tasks.db"
403
+ }
404
+ }
405
+ }
406
+ }
407
+ ```
408
+
409
+ **PostgreSQL** (swarm of agents, production):
410
+
411
+ ```json
412
+ {
413
+ "mcpServers": {
414
+ "agent-task-manager-mcp": {
415
+ "command": "agent-task-manager-mcp",
416
+ "args": [],
417
+ "env": {
418
+ "STORAGE": "postgres",
419
+ "POSTGRES_URL": "postgresql://user:password@localhost:5432/agent_tasks"
420
+ }
421
+ }
422
+ }
423
+ }
424
+ ```
425
+
426
+ **No DB server?** Use SQLite or JSON:
427
+
428
+ ```json
429
+ {
430
+ "mcpServers": {
431
+ "agent-task-manager-mcp": {
432
+ "command": "agent-task-manager-mcp",
433
+ "args": [],
434
+ "env": {
435
+ "STORAGE": "json",
436
+ "JSON_STORAGE_PATH": "./data/agent-tasks.json"
437
+ }
438
+ }
439
+ }
440
+ }
441
+ ```
442
+
443
+ See **[docs/STORAGE.md](docs/STORAGE.md)** for per-backend setup, migration, and troubleshooting.
444
+
445
+ ---
446
+
447
+ ### Option 2: From path
448
+
449
+ **Production (compiled)** — run `npm run build` first, then use `node`:
450
+
451
+ ```json
452
+ {
453
+ "mcpServers": {
454
+ "agent-task-manager-mcp": {
455
+ "command": "node",
456
+ "args": ["C:/path/to/agent-task-manager-mcp/dist/index.js"],
457
+ "env": {
458
+ "MONGODB_URI": "mongodb://localhost:27017/agent-tasks"
459
+ }
460
+ }
461
+ }
462
+ }
463
+ ```
334
464
 
335
- Add to Cursor MCP settings (or `.cursor/mcp.json`):
465
+ **Development (source)** no build; uses `tsx` to run TypeScript directly:
336
466
 
337
467
  ```json
338
468
  {
@@ -350,6 +480,39 @@ Add to Cursor MCP settings (or `.cursor/mcp.json`):
350
480
 
351
481
  ---
352
482
 
483
+ ### Option 3: HTTP/HTTPS mode (ChatGPT Desktop, ngrok)
484
+
485
+ MCP Server URL requires an HTTP(S) endpoint. Supports HTTP, HTTPS, self-signed, mkcert, and user-provided certs.
486
+
487
+ **HTTP (with ngrok):**
488
+ ```bash
489
+ agent-task-manager-mcp --http
490
+ ngrok http 8000
491
+ # Connector URL: https://<subdomain>.ngrok.app/mcp
492
+ ```
493
+
494
+ **HTTPS (local, no ngrok):**
495
+ ```bash
496
+ # Auto-generated self-signed cert
497
+ agent-task-manager-mcp --https
498
+ # Connector URL: https://localhost:8443/mcp
499
+
500
+ # With mkcert (locally trusted)
501
+ mkcert -install && mkcert localhost 127.0.0.1
502
+ agent-task-manager-mcp --https --cert-key=./localhost+1.pem
503
+
504
+ # With your own cert and key
505
+ agent-task-manager-mcp --https --cert=./cert.pem --key=./key.pem
506
+ ```
507
+
508
+ **Host validation:** localhost, 127.0.0.1, ngrok domains (`*.ngrok-free.app`, `*.ngrok.app`), and `MCP_ALLOWED_HOSTS` (comma-separated env var).
509
+
510
+ **ChatGPT Desktop** — Settings → Apps & Connectors → Create:
511
+ - **Connector URL:** `https://localhost:8443/mcp` (HTTPS) or `https://<ngrok-subdomain>.ngrok.app/mcp` (HTTP + ngrok)
512
+ - **Authentication:** None
513
+
514
+ ---
515
+
353
516
  ## Tool Reference
354
517
 
355
518
  ### Task Tools (7)
@@ -433,7 +596,8 @@ Checkpoint
433
596
 
434
597
  | Issue | Check |
435
598
  | ----------------------------- | ------------------------------------------------------------------------ |
436
- | `MONGODB_URI is not set` | Ensure `.env` exists and is loaded; verify env in MCP config |
599
+ | `MONGODB_URI is not set` | When `STORAGE=mongodb`; or switch to `STORAGE=sqlite` or `STORAGE=json` |
600
+ | `Unknown STORAGE type` | Use `mongodb`, `sqlite`, or `json` |
437
601
  | Connection refused | MongoDB running? Correct host/port? |
438
602
  | Auth failed | Verify username/password; URL-encode special chars |
439
603
  | Tool returns `success: false` | Inspect `error` field in JSON response |
@@ -447,7 +611,8 @@ Checkpoint
447
611
  agent-task-manager-mcp/
448
612
  ├── src/
449
613
  │ ├── index.ts # MCP server entry point
450
- │ ├── db.ts # MongoDB connection
614
+ │ ├── db.ts # MongoDB connection (when STORAGE=mongodb)
615
+ │ ├── storage/ # Storage abstraction (MongoDB, SQLite, JSON)
451
616
  │ ├── models/
452
617
  │ │ ├── Task.ts
453
618
  │ │ ├── Subtask.ts
@@ -0,0 +1,11 @@
1
+ export type CertKeyPair = {
2
+ cert: string;
3
+ key: string;
4
+ };
5
+ export declare const loadCertKey: (opts: {
6
+ cert?: string;
7
+ key?: string;
8
+ certKey?: string;
9
+ }) => CertKeyPair;
10
+ export declare const generateSelfSigned: () => Promise<CertKeyPair>;
11
+ //# sourceMappingURL=certs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAkBvD,eAAO,MAAM,WAAW,GAAI,MAAM;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,KAAG,WAmBH,CAAA;AAED,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,WAAW,CAU9D,CAAA"}
package/dist/certs.js ADDED
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateSelfSigned = exports.loadCertKey = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_fs_2 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const selfsigned_1 = __importDefault(require("selfsigned"));
11
+ const PEM_PRIVATE_KEY = /-----BEGIN\s+(?:(?:RSA|EC)\s+)?PRIVATE KEY-----[\s\S]+?-----END\s+(?:(?:RSA|EC)\s+)?PRIVATE KEY-----/;
12
+ const PEM_CERTIFICATE = /-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/;
13
+ const loadFile = (path) => {
14
+ const resolved = (0, node_path_1.resolve)(path);
15
+ if (!(0, node_fs_2.existsSync)(resolved))
16
+ throw new Error(`File not found: ${resolved}`);
17
+ return (0, node_fs_1.readFileSync)(resolved, 'utf8');
18
+ };
19
+ const parseCombinedPem = (content) => {
20
+ const keyMatch = content.match(PEM_PRIVATE_KEY);
21
+ const certMatch = content.match(PEM_CERTIFICATE);
22
+ if (keyMatch && certMatch)
23
+ return { key: keyMatch[0], cert: certMatch[0] };
24
+ return null;
25
+ };
26
+ const loadCertKey = (opts) => {
27
+ const { cert, key, certKey } = opts;
28
+ if (cert && key) {
29
+ return { cert: loadFile(cert), key: loadFile(key) };
30
+ }
31
+ const path = certKey ?? cert;
32
+ if (path) {
33
+ const content = loadFile(path);
34
+ const parsed = parseCombinedPem(content);
35
+ if (parsed)
36
+ return parsed;
37
+ if (key)
38
+ return { cert: content, key: loadFile(key) };
39
+ throw new Error(`File ${path} must contain both PRIVATE KEY and CERTIFICATE PEM blocks, or use --key for separate key file`);
40
+ }
41
+ throw new Error('Certificate required for HTTPS. Use --cert, --key, or --cert-key');
42
+ };
43
+ exports.loadCertKey = loadCertKey;
44
+ const generateSelfSigned = async () => {
45
+ const attrs = [{ name: 'commonName', value: 'localhost' }];
46
+ const notAfter = new Date();
47
+ notAfter.setFullYear(notAfter.getFullYear() + 1);
48
+ const pems = await selfsigned_1.default.generate(attrs, {
49
+ keySize: 2048,
50
+ algorithm: 'sha256',
51
+ notAfterDate: notAfter,
52
+ });
53
+ return { cert: pems.cert, key: pems.private };
54
+ };
55
+ exports.generateSelfSigned = generateSelfSigned;
56
+ //# sourceMappingURL=certs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certs.js","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":";;;;;;AAAA,qCAAsC;AACtC,qCAAoC;AACpC,yCAAmC;AACnC,4DAAmC;AAInC,MAAM,eAAe,GAAG,sGAAsG,CAAA;AAC9H,MAAM,eAAe,GAAG,8DAA8D,CAAA;AAEtF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAU,EAAE;IACxC,MAAM,QAAQ,GAAG,IAAA,mBAAO,EAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,CAAC,IAAA,oBAAU,EAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAA;IACzE,OAAO,IAAA,sBAAY,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AACvC,CAAC,CAAA;AAED,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAsB,EAAE;IAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;IAChD,IAAI,QAAQ,IAAI,SAAS;QAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IAC1E,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAEM,MAAM,WAAW,GAAG,CAAC,IAI3B,EAAe,EAAE;IAChB,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAEnC,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAA;IACrD,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,IAAI,IAAI,CAAA;IAC5B,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC9B,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;QACxC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QACzB,IAAI,GAAG;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAA;QACrD,MAAM,IAAI,KAAK,CACb,QAAQ,IAAI,+FAA+F,CAC5G,CAAA;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAA;AACrF,CAAC,CAAA;AAvBY,QAAA,WAAW,eAuBvB;AAEM,MAAM,kBAAkB,GAAG,KAAK,IAA0B,EAAE;IACjE,MAAM,KAAK,GAAG,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAA;IAC3B,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAA;IAChD,MAAM,IAAI,GAAG,MAAM,oBAAU,CAAC,QAAQ,CAAC,KAAK,EAAE;QAC5C,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,QAAQ;QACnB,YAAY,EAAE,QAAQ;KACvB,CAAC,CAAA;IACF,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;AAC/C,CAAC,CAAA;AAVY,QAAA,kBAAkB,sBAU9B"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export type CliOptions = {
2
+ stdio: boolean;
3
+ http: boolean;
4
+ https: boolean;
5
+ port?: number;
6
+ cert?: string;
7
+ key?: string;
8
+ certKey?: string;
9
+ };
10
+ declare const DEFAULT_HTTP_PORT = 8000;
11
+ declare const DEFAULT_HTTPS_PORT = 8443;
12
+ export declare const parseCli: () => CliOptions;
13
+ export { DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT };
14
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,QAAA,MAAM,iBAAiB,OAAO,CAAA;AAC9B,QAAA,MAAM,kBAAkB,OAAO,CAAA;AAE/B,eAAO,MAAM,QAAQ,QAAO,UAsB3B,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAA"}
package/dist/cli.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_HTTPS_PORT = exports.DEFAULT_HTTP_PORT = exports.parseCli = void 0;
4
+ const getArg = (name) => {
5
+ const arg = process.argv.find((a) => a.startsWith(`${name}=`));
6
+ return arg?.slice(name.length + 1);
7
+ };
8
+ const hasArg = (name) => process.argv.includes(name);
9
+ const DEFAULT_HTTP_PORT = 8000;
10
+ exports.DEFAULT_HTTP_PORT = DEFAULT_HTTP_PORT;
11
+ const DEFAULT_HTTPS_PORT = 8443;
12
+ exports.DEFAULT_HTTPS_PORT = DEFAULT_HTTPS_PORT;
13
+ const parseCli = () => {
14
+ const httpMode = hasArg('--http');
15
+ const httpsMode = hasArg('--https');
16
+ const portArg = getArg('--port');
17
+ const port = portArg ? parseInt(portArg, 10) : undefined;
18
+ const cert = getArg('--cert');
19
+ const key = getArg('--key');
20
+ const certKey = getArg('--cert-key');
21
+ const stdio = !httpMode && !httpsMode;
22
+ const http = httpMode || httpsMode;
23
+ const https = httpsMode;
24
+ return {
25
+ stdio,
26
+ http,
27
+ https,
28
+ port,
29
+ cert,
30
+ key,
31
+ certKey,
32
+ };
33
+ };
34
+ exports.parseCli = parseCli;
35
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAAA,MAAM,MAAM,GAAG,CAAC,IAAY,EAAsB,EAAE;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAA;IAC9D,OAAO,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AACpC,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AAY5D,MAAM,iBAAiB,GAAG,IAAI,CAAA;AA2BrB,8CAAiB;AA1B1B,MAAM,kBAAkB,GAAG,IAAI,CAAA;AA0BH,gDAAkB;AAxBvC,MAAM,QAAQ,GAAG,GAAe,EAAE;IACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAChC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACxD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;IAEpC,MAAM,KAAK,GAAG,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAA;IACrC,MAAM,IAAI,GAAG,QAAQ,IAAI,SAAS,CAAA;IAClC,MAAM,KAAK,GAAG,SAAS,CAAA;IAEvB,OAAO;QACL,KAAK;QACL,IAAI;QACJ,KAAK;QACL,IAAI;QACJ,IAAI;QACJ,GAAG;QACH,OAAO;KACR,CAAA;AACH,CAAC,CAAA;AAtBY,QAAA,QAAQ,YAsBpB"}
@@ -0,0 +1,3 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ export declare const hostValidationMiddleware: (req: Request, res: Response, next: NextFunction) => void;
3
+ //# sourceMappingURL=hostValidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostValidation.d.ts","sourceRoot":"","sources":["../src/hostValidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAsB9D,eAAO,MAAM,wBAAwB,GACnC,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,SA+BnB,CAAA"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hostValidationMiddleware = void 0;
4
+ const LOCALHOST_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
5
+ const NGROK_SUFFIXES = ['.ngrok-free.app', '.ngrok.app', '.ngrok.io'];
6
+ const getAllowedHosts = () => {
7
+ const extra = process.env.MCP_ALLOWED_HOSTS;
8
+ if (!extra)
9
+ return LOCALHOST_HOSTS;
10
+ const hosts = new Set(LOCALHOST_HOSTS);
11
+ for (const h of extra.split(',').map((s) => s.trim()).filter(Boolean)) {
12
+ hosts.add(h);
13
+ }
14
+ return hosts;
15
+ };
16
+ const isHostAllowed = (hostname) => {
17
+ if (LOCALHOST_HOSTS.has(hostname))
18
+ return true;
19
+ if (NGROK_SUFFIXES.some((s) => hostname.endsWith(s)))
20
+ return true;
21
+ if (getAllowedHosts().has(hostname))
22
+ return true;
23
+ return false;
24
+ };
25
+ const hostValidationMiddleware = (req, res, next) => {
26
+ const hostHeader = req.headers.host;
27
+ if (!hostHeader) {
28
+ res.status(403).json({
29
+ jsonrpc: '2.0',
30
+ error: { code: -32000, message: 'Missing Host header' },
31
+ id: null,
32
+ });
33
+ return;
34
+ }
35
+ let hostname;
36
+ try {
37
+ hostname = new URL(`http://${hostHeader}`).hostname;
38
+ }
39
+ catch {
40
+ res.status(403).json({
41
+ jsonrpc: '2.0',
42
+ error: { code: -32000, message: `Invalid Host header: ${hostHeader}` },
43
+ id: null,
44
+ });
45
+ return;
46
+ }
47
+ if (!isHostAllowed(hostname)) {
48
+ res.status(403).json({
49
+ jsonrpc: '2.0',
50
+ error: { code: -32000, message: `Invalid Host: ${hostname}` },
51
+ id: null,
52
+ });
53
+ return;
54
+ }
55
+ next();
56
+ };
57
+ exports.hostValidationMiddleware = hostValidationMiddleware;
58
+ //# sourceMappingURL=hostValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostValidation.js","sourceRoot":"","sources":["../src/hostValidation.ts"],"names":[],"mappings":";;;AAEA,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;AACpE,MAAM,cAAc,GAAG,CAAC,iBAAiB,EAAE,YAAY,EAAE,WAAW,CAAC,CAAA;AAErE,MAAM,eAAe,GAAG,GAAgB,EAAE;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,eAAe,CAAA;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;IACtC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QACtE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACd,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAW,EAAE;IAClD,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA;IAC9C,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACjE,IAAI,eAAe,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA;IAChD,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAEM,MAAM,wBAAwB,GAAG,CACtC,GAAY,EACZ,GAAa,EACb,IAAkB,EAClB,EAAE;IACF,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAA;IACnC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE;YACvD,EAAE,EAAE,IAAI;SACT,CAAC,CAAA;QACF,OAAM;IACR,CAAC;IACD,IAAI,QAAgB,CAAA;IACpB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,GAAG,CAAC,UAAU,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAA;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,wBAAwB,UAAU,EAAE,EAAE;YACtE,EAAE,EAAE,IAAI;SACT,CAAC,CAAA;QACF,OAAM;IACR,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,QAAQ,EAAE,EAAE;YAC7D,EAAE,EAAE,IAAI;SACT,CAAC,CAAA;QACF,OAAM;IACR,CAAC;IACD,IAAI,EAAE,CAAA;AACR,CAAC,CAAA;AAlCY,QAAA,wBAAwB,4BAkCpC"}
@@ -0,0 +1,13 @@
1
+ declare const DEFAULT_HTTP_PORT = 8000;
2
+ declare const DEFAULT_HTTPS_PORT = 8443;
3
+ declare const findAvailablePort: (startPort: number) => Promise<number>;
4
+ export type HttpServerOptions = {
5
+ port?: number;
6
+ https?: boolean;
7
+ cert?: string;
8
+ key?: string;
9
+ certKey?: string;
10
+ };
11
+ declare const runHttpServer: (opts?: HttpServerOptions) => Promise<void>;
12
+ export { findAvailablePort, runHttpServer, DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT };
13
+ //# sourceMappingURL=http.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.server.d.ts","sourceRoot":"","sources":["../src/http.server.ts"],"names":[],"mappings":"AAaA,QAAA,MAAM,iBAAiB,OAAO,CAAA;AAC9B,QAAA,MAAM,kBAAkB,OAAO,CAAA;AAK/B,QAAA,MAAM,iBAAiB,GAAI,WAAW,MAAM,KAAG,OAAO,CAAC,MAAM,CAyBzD,CAAA;AAOJ,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AASD,QAAA,MAAM,aAAa,GAAU,OAAM,iBAAsB,kBAkJxD,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAA"}