@calltelemetry/ct-lab-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/dist/bin/ct-lab-mcp.d.ts +60 -0
- package/dist/bin/ct-lab-mcp.d.ts.map +1 -0
- package/dist/bin/ct-lab-mcp.js +261 -0
- package/dist/bin/ct-lab-mcp.js.map +1 -0
- package/dist/bin/proxmox-mcp.d.ts +58 -0
- package/dist/bin/proxmox-mcp.d.ts.map +1 -0
- package/dist/bin/proxmox-mcp.js +248 -0
- package/dist/bin/proxmox-mcp.js.map +1 -0
- package/dist/src/appliance/commands.d.ts +33 -0
- package/dist/src/appliance/commands.d.ts.map +1 -0
- package/dist/src/appliance/commands.js +241 -0
- package/dist/src/appliance/commands.js.map +1 -0
- package/dist/src/appliance/executor.d.ts +34 -0
- package/dist/src/appliance/executor.d.ts.map +1 -0
- package/dist/src/appliance/executor.js +214 -0
- package/dist/src/appliance/executor.js.map +1 -0
- package/dist/src/appliance/index.d.ts +8 -0
- package/dist/src/appliance/index.d.ts.map +1 -0
- package/dist/src/appliance/index.js +8 -0
- package/dist/src/appliance/index.js.map +1 -0
- package/dist/src/appliance/mock.d.ts +66 -0
- package/dist/src/appliance/mock.d.ts.map +1 -0
- package/dist/src/appliance/mock.js +339 -0
- package/dist/src/appliance/mock.js.map +1 -0
- package/dist/src/appliance/types.d.ts +83 -0
- package/dist/src/appliance/types.d.ts.map +1 -0
- package/dist/src/appliance/types.js +58 -0
- package/dist/src/appliance/types.js.map +1 -0
- package/dist/src/credentials/doppler.d.ts +25 -0
- package/dist/src/credentials/doppler.d.ts.map +1 -0
- package/dist/src/credentials/doppler.js +68 -0
- package/dist/src/credentials/doppler.js.map +1 -0
- package/dist/src/credentials/index.d.ts +4 -0
- package/dist/src/credentials/index.d.ts.map +1 -0
- package/dist/src/credentials/index.js +4 -0
- package/dist/src/credentials/index.js.map +1 -0
- package/dist/src/credentials/resolver.d.ts +36 -0
- package/dist/src/credentials/resolver.d.ts.map +1 -0
- package/dist/src/credentials/resolver.js +427 -0
- package/dist/src/credentials/resolver.js.map +1 -0
- package/dist/src/credentials/types.d.ts +73 -0
- package/dist/src/credentials/types.d.ts.map +1 -0
- package/dist/src/credentials/types.js +5 -0
- package/dist/src/credentials/types.js.map +1 -0
- package/dist/src/guardrails/index.d.ts +3 -0
- package/dist/src/guardrails/index.d.ts.map +1 -0
- package/dist/src/guardrails/index.js +3 -0
- package/dist/src/guardrails/index.js.map +1 -0
- package/dist/src/guardrails/safety.d.ts +45 -0
- package/dist/src/guardrails/safety.d.ts.map +1 -0
- package/dist/src/guardrails/safety.js +217 -0
- package/dist/src/guardrails/safety.js.map +1 -0
- package/dist/src/guardrails/types.d.ts +36 -0
- package/dist/src/guardrails/types.d.ts.map +1 -0
- package/dist/src/guardrails/types.js +20 -0
- package/dist/src/guardrails/types.js.map +1 -0
- package/dist/src/hypervisors/esxi/client.d.ts +103 -0
- package/dist/src/hypervisors/esxi/client.d.ts.map +1 -0
- package/dist/src/hypervisors/esxi/client.js +395 -0
- package/dist/src/hypervisors/esxi/client.js.map +1 -0
- package/dist/src/hypervisors/esxi/mock.d.ts +45 -0
- package/dist/src/hypervisors/esxi/mock.d.ts.map +1 -0
- package/dist/src/hypervisors/esxi/mock.js +202 -0
- package/dist/src/hypervisors/esxi/mock.js.map +1 -0
- package/dist/src/hypervisors/index.d.ts +10 -0
- package/dist/src/hypervisors/index.d.ts.map +1 -0
- package/dist/src/hypervisors/index.js +10 -0
- package/dist/src/hypervisors/index.js.map +1 -0
- package/dist/src/hypervisors/manager.d.ts +78 -0
- package/dist/src/hypervisors/manager.d.ts.map +1 -0
- package/dist/src/hypervisors/manager.js +415 -0
- package/dist/src/hypervisors/manager.js.map +1 -0
- package/dist/src/hypervisors/proxmox/client.d.ts +29 -0
- package/dist/src/hypervisors/proxmox/client.d.ts.map +1 -0
- package/dist/src/hypervisors/proxmox/client.js +278 -0
- package/dist/src/hypervisors/proxmox/client.js.map +1 -0
- package/dist/src/hypervisors/proxmox/mock.d.ts +17 -0
- package/dist/src/hypervisors/proxmox/mock.d.ts.map +1 -0
- package/dist/src/hypervisors/proxmox/mock.js +26 -0
- package/dist/src/hypervisors/proxmox/mock.js.map +1 -0
- package/dist/src/hypervisors/types.d.ts +159 -0
- package/dist/src/hypervisors/types.d.ts.map +1 -0
- package/dist/src/hypervisors/types.js +6 -0
- package/dist/src/hypervisors/types.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/proxmox/client.d.ts +37 -0
- package/dist/src/proxmox/client.d.ts.map +1 -0
- package/dist/src/proxmox/client.js +282 -0
- package/dist/src/proxmox/client.js.map +1 -0
- package/dist/src/proxmox/index.d.ts +53 -0
- package/dist/src/proxmox/index.d.ts.map +1 -0
- package/dist/src/proxmox/index.js +109 -0
- package/dist/src/proxmox/index.js.map +1 -0
- package/dist/src/proxmox/mock.d.ts +40 -0
- package/dist/src/proxmox/mock.d.ts.map +1 -0
- package/dist/src/proxmox/mock.js +362 -0
- package/dist/src/proxmox/mock.js.map +1 -0
- package/dist/src/proxmox/poller.d.ts +29 -0
- package/dist/src/proxmox/poller.d.ts.map +1 -0
- package/dist/src/proxmox/poller.js +107 -0
- package/dist/src/proxmox/poller.js.map +1 -0
- package/dist/src/server/index.d.ts +2 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +2 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/mcp-server.d.ts +5 -0
- package/dist/src/server/mcp-server.d.ts.map +1 -0
- package/dist/src/server/mcp-server.js +5 -0
- package/dist/src/server/mcp-server.js.map +1 -0
- package/dist/src/server.d.ts +35 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +95 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/slot/gc.d.ts +42 -0
- package/dist/src/slot/gc.d.ts.map +1 -0
- package/dist/src/slot/gc.js +79 -0
- package/dist/src/slot/gc.js.map +1 -0
- package/dist/src/slot/index.d.ts +4 -0
- package/dist/src/slot/index.d.ts.map +1 -0
- package/dist/src/slot/index.js +4 -0
- package/dist/src/slot/index.js.map +1 -0
- package/dist/src/slot/manager.d.ts +92 -0
- package/dist/src/slot/manager.d.ts.map +1 -0
- package/dist/src/slot/manager.js +650 -0
- package/dist/src/slot/manager.js.map +1 -0
- package/dist/src/slot/types.d.ts +184 -0
- package/dist/src/slot/types.d.ts.map +1 -0
- package/dist/src/slot/types.js +67 -0
- package/dist/src/slot/types.js.map +1 -0
- package/dist/src/tools/appliance-exec.d.ts +81 -0
- package/dist/src/tools/appliance-exec.d.ts.map +1 -0
- package/dist/src/tools/appliance-exec.js +134 -0
- package/dist/src/tools/appliance-exec.js.map +1 -0
- package/dist/src/tools/claim-slot.d.ts +5 -0
- package/dist/src/tools/claim-slot.d.ts.map +1 -0
- package/dist/src/tools/claim-slot.js +5 -0
- package/dist/src/tools/claim-slot.js.map +1 -0
- package/dist/src/tools/index.d.ts +26 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +63 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/list-hosts.d.ts +41 -0
- package/dist/src/tools/list-hosts.d.ts.map +1 -0
- package/dist/src/tools/list-hosts.js +91 -0
- package/dist/src/tools/list-hosts.js.map +1 -0
- package/dist/src/tools/list-inventory.d.ts +50 -0
- package/dist/src/tools/list-inventory.d.ts.map +1 -0
- package/dist/src/tools/list-inventory.js +112 -0
- package/dist/src/tools/list-inventory.js.map +1 -0
- package/dist/src/tools/list-slots.d.ts +5 -0
- package/dist/src/tools/list-slots.d.ts.map +1 -0
- package/dist/src/tools/list-slots.js +5 -0
- package/dist/src/tools/list-slots.js.map +1 -0
- package/dist/src/tools/provision-tools.d.ts +231 -0
- package/dist/src/tools/provision-tools.d.ts.map +1 -0
- package/dist/src/tools/provision-tools.js +289 -0
- package/dist/src/tools/provision-tools.js.map +1 -0
- package/dist/src/tools/release-slot.d.ts +5 -0
- package/dist/src/tools/release-slot.d.ts.map +1 -0
- package/dist/src/tools/release-slot.js +5 -0
- package/dist/src/tools/release-slot.js.map +1 -0
- package/dist/src/tools/slot-tools.d.ts +173 -0
- package/dist/src/tools/slot-tools.d.ts.map +1 -0
- package/dist/src/tools/slot-tools.js +296 -0
- package/dist/src/tools/slot-tools.js.map +1 -0
- package/dist/src/tools/vm-action.d.ts +189 -0
- package/dist/src/tools/vm-action.d.ts.map +1 -0
- package/dist/src/tools/vm-action.js +300 -0
- package/dist/src/tools/vm-action.js.map +1 -0
- package/dist/src/transports/index.d.ts +3 -0
- package/dist/src/transports/index.d.ts.map +1 -0
- package/dist/src/transports/index.js +3 -0
- package/dist/src/transports/index.js.map +1 -0
- package/dist/src/transports/sse.d.ts +38 -0
- package/dist/src/transports/sse.d.ts.map +1 -0
- package/dist/src/transports/sse.js +167 -0
- package/dist/src/transports/sse.js.map +1 -0
- package/dist/src/transports/stdio.d.ts +15 -0
- package/dist/src/transports/stdio.d.ts.map +1 -0
- package/dist/src/transports/stdio.js +34 -0
- package/dist/src/transports/stdio.js.map +1 -0
- package/dist/src/types/config.d.ts +17 -0
- package/dist/src/types/config.d.ts.map +1 -0
- package/dist/src/types/config.js +5 -0
- package/dist/src/types/config.js.map +1 -0
- package/dist/src/types/index.d.ts +4 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +4 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/mcp.d.ts +38 -0
- package/dist/src/types/mcp.d.ts.map +1 -0
- package/dist/src/types/mcp.js +46 -0
- package/dist/src/types/mcp.js.map +1 -0
- package/dist/src/types/proxmox.d.ts +181 -0
- package/dist/src/types/proxmox.d.ts.map +1 -0
- package/dist/src/types/proxmox.js +5 -0
- package/dist/src/types/proxmox.js.map +1 -0
- package/dist/src/types/slot.d.ts +5 -0
- package/dist/src/types/slot.d.ts.map +1 -0
- package/dist/src/types/slot.js +5 -0
- package/dist/src/types/slot.js.map +1 -0
- package/dist/src/utils/formatters.d.ts +71 -0
- package/dist/src/utils/formatters.d.ts.map +1 -0
- package/dist/src/utils/formatters.js +480 -0
- package/dist/src/utils/formatters.js.map +1 -0
- package/dist/src/utils/index.d.ts +6 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +6 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/logger.d.ts +28 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +74 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/mutex.d.ts +32 -0
- package/dist/src/utils/mutex.d.ts.map +1 -0
- package/dist/src/utils/mutex.js +86 -0
- package/dist/src/utils/mutex.js.map +1 -0
- package/dist/src/utils/redact.d.ts +6 -0
- package/dist/src/utils/redact.d.ts.map +1 -0
- package/dist/src/utils/redact.js +6 -0
- package/dist/src/utils/redact.js.map +1 -0
- package/dist/src/utils/redactor.d.ts +50 -0
- package/dist/src/utils/redactor.d.ts.map +1 -0
- package/dist/src/utils/redactor.js +170 -0
- package/dist/src/utils/redactor.js.map +1 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Call Telemetry / Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# @calltelemetry/ct-lab-mcp
|
|
2
|
+
|
|
3
|
+
> **Model Context Protocol (MCP) Server for Unified Call Telemetry Lab, Fleet, and Appliance Management across Proxmox VE and VMware ESXi**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@calltelemetry/ct-lab-mcp)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
|
|
10
|
+
`@calltelemetry/ct-lab-mcp` exposes high-level multi-hypervisor management (Proxmox VE & VMware ESXi), automated disposable VM provisioning, an atomic 8GB slot capacity allocation engine, and secure remote appliance CLI diagnostics to AI agents, Claude Desktop, Cursor, and other MCP clients.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
AI Clients (Claude Desktop / Cursor / Web / AI Agents)
|
|
18
|
+
│
|
|
19
|
+
▼
|
|
20
|
+
[MCP Server / Transports]
|
|
21
|
+
├── Stdio Transport (stdout JSON-RPC, stderr SafeLogger)
|
|
22
|
+
└── Express SSE Transport (/sse, /messages, /health)
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
[MCP Tool Registry]
|
|
26
|
+
├── list_hosts (Proxmox + ESXi capacity, health & 8GB slot quotas)
|
|
27
|
+
├── list_inventory (Unified VM fleet inventory with Linear tags)
|
|
28
|
+
├── claim_slot (8GB slot leases with TTL & Linear issue tracking)
|
|
29
|
+
├── release_slot (Release lease + optional automated VM destruction)
|
|
30
|
+
├── provision_vm (Disposable VM provisioning on Proxmox/ESXi)
|
|
31
|
+
├── vm_action (Power lifecycle with non-bypassable safety guardrails)
|
|
32
|
+
└── appliance_exec (Mediated cli.sh commands over SSH:2222 with redaction)
|
|
33
|
+
│
|
|
34
|
+
┌───────────────┼───────────────┬───────────────────┐
|
|
35
|
+
▼ ▼ ▼ ▼
|
|
36
|
+
[MultiHypervisor] [Slot Engine] [Safety Guardrails] [Appliance SSH]
|
|
37
|
+
├── Proxmox VE ├── ProxmoxLab ├── Proxmox fixtures ├── ssh2 port 2222
|
|
38
|
+
│ (2x8GB) │ (2x8GB max) │ (100-104, 9000s) ├── cli.sh / db vacuum
|
|
39
|
+
└── VMware ESXi ├── ProxmoxMini └── ESXi fixtures ├── migrate / logs
|
|
40
|
+
(8x8GB) │ (4x8GB max) (CUCM, CUBE, └── Redaction Engine
|
|
41
|
+
└── ESXi (8x8GB) Runners, K8s)
|
|
42
|
+
│
|
|
43
|
+
▼
|
|
44
|
+
[Lab Credential Resolver]
|
|
45
|
+
├── Tier 1: Process Environment (LAB_PROXMOX_*, GOVC_*, LAB_VM_*)
|
|
46
|
+
├── Tier 2: Doppler REST API v3 (DOPPLER_TOKEN)
|
|
47
|
+
└── Tier 3: In-Memory Mock Fallback / Offline Dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Key Features
|
|
53
|
+
|
|
54
|
+
- **Multi-Hypervisor Fleet Management**: Polymorphic abstraction unifying Proxmox VE clusters (`proxmox-lab`, `proxmox-mini`) and VMware ESXi hosts (`esxi-intel-192-168-123-176`).
|
|
55
|
+
- **Disposable VM Provisioning**: Clone test VMs from hypervisor templates, configure static IP/VLAN networking, and bind 8GB slot leases in one atomic tool invocation.
|
|
56
|
+
- **Global 8GB Slot Allocation Engine**:
|
|
57
|
+
- `proxmox-lab`: Strictly capped at **2 concurrent 8GB slots** (16 GB allocated, 16 GB reserved for CUCM & core fixtures).
|
|
58
|
+
- `proxmox-mini`: Strictly capped at **4 concurrent 8GB slots** (32 GB allocated).
|
|
59
|
+
- `esxi-intel-192-168-123-176`: Managed candidate slot ranking with **8 concurrent 8GB slots** and datastore space checks.
|
|
60
|
+
- **Non-Bypassable Safety Guardrails**: Hard protection preventing destructive actions (`destroy`, `stop`, `reboot`) against core infrastructure:
|
|
61
|
+
- Cisco Unified Communications Manager (CUCM 14 / 15 publishers and subscribers)
|
|
62
|
+
- Cisco CUBE Voice Gateways / Cat8000v
|
|
63
|
+
- GitHub Actions CI Runners (`GH-Runner`)
|
|
64
|
+
- Lab Kubernetes Clusters (`LAB-K8S`)
|
|
65
|
+
- VM Templates (VMIDs `9000`–`9999` or template flags)
|
|
66
|
+
- **Remote Appliance CLI Control**: Mediated execution of `cli.sh` commands over SSH (port 2222) for status inspection, health diagnostics, Ecto migrations, table vacuums, and container logs.
|
|
67
|
+
- **Dynamic Secret Redaction**: Real-time masking prevents passwords, Doppler API tokens, and private keys from leaking into MCP responses or stderr logs.
|
|
68
|
+
- **Dual Transports**: Clean standard I/O transport (`stdio`) and Express HTTP/SSE transport (`sse`) with `/health`, `/sse`, and `/messages` endpoints.
|
|
69
|
+
- **3-Tier Credential Resolution**:
|
|
70
|
+
1. *Tier 1*: Direct Environment Variables (`LAB_PROXMOX_*`, `GOVC_*`, `LAB_VM_CREDENTIALS_*`)
|
|
71
|
+
2. *Tier 2*: Doppler Secrets REST API v3 (`DOPPLER_TOKEN`)
|
|
72
|
+
3. *Tier 3*: In-Memory Mock Hypervisor & Appliance Fallback (for offline test suites)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Global installation
|
|
80
|
+
npm install -g @calltelemetry/ct-lab-mcp
|
|
81
|
+
|
|
82
|
+
# Or run directly with npx
|
|
83
|
+
npx @calltelemetry/ct-lab-mcp
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## CLI Usage
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
ct-lab-mcp [options]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Command-Line Options
|
|
95
|
+
|
|
96
|
+
| Flag | Description | Default | Environment Variable |
|
|
97
|
+
|------|-------------|---------|----------------------|
|
|
98
|
+
| `-t, --transport <type>` | Transport mode (`stdio` or `sse`) | `stdio` | `CT_LAB_MCP_TRANSPORT` |
|
|
99
|
+
| `-p, --port <number>` | HTTP port for SSE transport | `3000` | `PORT` |
|
|
100
|
+
| `-H, --host <string>` | Host interface to bind SSE server | `127.0.0.1` | `HOST` |
|
|
101
|
+
| `-c, --config <path>` | Path to optional JSON configuration file | *None* | *None* |
|
|
102
|
+
| `--doppler-token <token>` | Doppler service or personal API token | *None* | `DOPPLER_TOKEN` |
|
|
103
|
+
| `--doppler-project <name>`| Doppler project name | *None* | `DOPPLER_PROJECT` |
|
|
104
|
+
| `--doppler-config <name>` | Doppler environment / config | *None* | `DOPPLER_CONFIG` |
|
|
105
|
+
| `--force-mock` | Force in-memory mock hypervisor & appliance mode | `false` | `CT_LAB_MOCK_MODE` |
|
|
106
|
+
| `--redact-secrets` | Enforce strict secret redaction on all logs | `true` | *None* |
|
|
107
|
+
| `-v, --version` | Output the current version | *None* | *None* |
|
|
108
|
+
| `-h, --help` | Display CLI help text | *None* | *None* |
|
|
109
|
+
|
|
110
|
+
### Examples
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Run over stdio (default for Claude Desktop and Cursor)
|
|
114
|
+
ct-lab-mcp
|
|
115
|
+
|
|
116
|
+
# Run SSE server on port 3001
|
|
117
|
+
ct-lab-mcp --transport sse --port 3001 --host 0.0.0.0
|
|
118
|
+
|
|
119
|
+
# Run with Doppler credentials
|
|
120
|
+
ct-lab-mcp --doppler-token "dp.st.prd.xxx" --doppler-project "calltelemetry-lab" --doppler-config "prd"
|
|
121
|
+
|
|
122
|
+
# Offline mock mode for development / unit testing
|
|
123
|
+
ct-lab-mcp --force-mock
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## MCP Tools Reference
|
|
129
|
+
|
|
130
|
+
The server registers 7 comprehensive tools conforming to the MCP JSON Schema specification:
|
|
131
|
+
|
|
132
|
+
### 1. `list_hosts`
|
|
133
|
+
Query capacity, health, CPU/RAM/Disk metrics, and 8GB slot limits across Proxmox VE (`proxmox-lab`, `proxmox-mini`) and VMware ESXi (`esxi-intel-192-168-123-176`).
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"host": "all", // "proxmox-lab" | "proxmox-mini" | "esxi-intel-192-168-123-176" | "all"
|
|
138
|
+
"hypervisorType": "all", // "proxmox" | "esxi" | "all"
|
|
139
|
+
"refresh": false // boolean: force live hypervisor API poll
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 2. `list_inventory`
|
|
144
|
+
Query unified fleet inventory across Proxmox VE and VMware ESXi VMs with power status, IP addresses, VLAN, protected flags, release version, and Linear lease tags.
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"hypervisor": "all", // "proxmox" | "esxi" | "all"
|
|
149
|
+
"host": "proxmox-mini", // optional host filter
|
|
150
|
+
"status": "all", // "all" | "running" | "stopped" | "claimed" | "disposable"
|
|
151
|
+
"includeTemplates": false, // boolean (default: false)
|
|
152
|
+
"filter": "0.8.7-stable", // text search across name, ID, IP, Linear issue, tags
|
|
153
|
+
"tags": ["uat", "disposable"]
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 3. `claim_slot`
|
|
158
|
+
Lease an 8GB appliance slot on a specified or least-loaded auto-selected host with lease TTL and Linear issue tracking.
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"tag": "CTUAT-693", // required string: issue tag or session identifier
|
|
163
|
+
"linearIssue": "CTUAT-693", // Linear issue key
|
|
164
|
+
"host": "auto", // "proxmox-lab" | "proxmox-mini" | "esxi-intel-192-168-123-176" | "auto"
|
|
165
|
+
"hypervisorType": "any", // "proxmox" | "esxi" | "any"
|
|
166
|
+
"durationMinutes": 60, // integer (1 - 1440 minutes / 24 hours, default: 60)
|
|
167
|
+
"purpose": "UAT Testing" // optional description
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
*Enforces strict capacity quotas: Attempting to claim a 3rd slot on `proxmox-lab` or a 5th slot on `proxmox-mini` is strictly rejected.*
|
|
172
|
+
|
|
173
|
+
### 4. `release_slot`
|
|
174
|
+
Release an active 8GB slot claim by `claimId`, `tag`, `requester`, or `linearIssue`, with optional automatic destruction of attached test VMs.
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"claimId": "claim-a1b2c3d4", // optional string: specific claim ID
|
|
179
|
+
"linearIssue": "CTUAT-693", // optional string: release all claims matching Linear issue
|
|
180
|
+
"destroyVm": true // boolean: automatically destroy attached test VM
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 5. `provision_vm`
|
|
185
|
+
Provision a new disposable Call Telemetry appliance VM on Proxmox VE or VMware ESXi from a base template with IP/VLAN networking and auto-attached 8GB slot lease.
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"sourceVmIdOrName": 9000, // template VMID or template name
|
|
190
|
+
"newVmName": "ct-appliance-uat-105", // name for the new VM
|
|
191
|
+
"targetHost": "proxmox-mini", // optional host (auto-placed if omitted)
|
|
192
|
+
"vlan": 124, // optional VLAN tag
|
|
193
|
+
"ipAddress": "192.168.124.105", // optional static IP
|
|
194
|
+
"linearIssue": "CTUAT-693", // Linear issue tag
|
|
195
|
+
"startOnDeploy": true // power on immediately after cloning
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 6. `vm_action`
|
|
200
|
+
Execute power lifecycle operations across Proxmox and ESXi with non-bypassable guardrails protecting core infrastructure.
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"vmIdOrName": "ct-appliance-uat-105", // VMID or VM name/path
|
|
205
|
+
"host": "proxmox-mini", // target host name
|
|
206
|
+
"action": "start", // "start" | "stop" | "reboot" | "shutdown" | "reset" | "status" | "destroy"
|
|
207
|
+
"force": false // boolean: force immediate action (guardrails cannot be bypassed)
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
*Destructive actions on protected VMs (CUCM, CUBE, base templates, K8s) are strictly denied with `PROTECTED_VM_ACTION_DENIED`.*
|
|
212
|
+
|
|
213
|
+
### 7. `appliance_exec`
|
|
214
|
+
Execute mediated Call Telemetry appliance CLI operations over secure SSH on Port 2222 with output sanitization and secret redaction.
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"targetIp": "192.168.124.105", // appliance IP or hostname
|
|
219
|
+
"port": 2222, // SSH port (default: 2222)
|
|
220
|
+
"action": "db_vacuum", // "status" | "health" | "diag" | "db_vacuum" | "migrate" | "docker" | "logs" | "version"
|
|
221
|
+
"args": {
|
|
222
|
+
"table": "cdr_records",
|
|
223
|
+
"vacuumFull": true,
|
|
224
|
+
"vacuumAnalyze": true
|
|
225
|
+
},
|
|
226
|
+
"timeoutMs": 30000
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Client Configuration
|
|
233
|
+
|
|
234
|
+
### Claude Desktop Configuration
|
|
235
|
+
|
|
236
|
+
Add the server to your `claude_desktop_config.json`:
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"mcpServers": {
|
|
241
|
+
"calltelemetry-lab": {
|
|
242
|
+
"command": "npx",
|
|
243
|
+
"args": ["-y", "@calltelemetry/ct-lab-mcp"],
|
|
244
|
+
"env": {
|
|
245
|
+
"DOPPLER_TOKEN": "dp.st.prd.your_token_here",
|
|
246
|
+
"DOPPLER_PROJECT": "calltelemetry-lab",
|
|
247
|
+
"DOPPLER_CONFIG": "prd"
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Cursor Configuration
|
|
255
|
+
|
|
256
|
+
Add to `.cursor/mcp.json` or Cursor Settings > MCP:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"mcpServers": {
|
|
261
|
+
"calltelemetry-lab": {
|
|
262
|
+
"command": "ct-lab-mcp",
|
|
263
|
+
"args": ["--transport", "stdio"],
|
|
264
|
+
"env": {
|
|
265
|
+
"DOPPLER_TOKEN": "dp.st.prd.your_token_here"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Programmatic TypeScript Usage
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { createMcpServer, startStdioServer, SlotManager, MultiHypervisorManager } from "@calltelemetry/ct-lab-mcp";
|
|
278
|
+
|
|
279
|
+
const server = createMcpServer({
|
|
280
|
+
name: "custom-lab-mcp",
|
|
281
|
+
version: "1.0.0",
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
await startStdioServer(server);
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Development & Verification
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Typecheck TypeScript source
|
|
293
|
+
npm run typecheck
|
|
294
|
+
|
|
295
|
+
# Run full Vitest test suite
|
|
296
|
+
npm test
|
|
297
|
+
|
|
298
|
+
# Build production distribution to dist/
|
|
299
|
+
npm run build
|
|
300
|
+
|
|
301
|
+
# Verify npm bundle package
|
|
302
|
+
npm pack --dry-run
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT © 2026 [Call Telemetry](https://calltelemetry.com) / Contributors
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Call Telemetry Lab & Fleet MCP Server CLI
|
|
4
|
+
*
|
|
5
|
+
* Command-line runner supporting Stdio and HTTP/SSE transports,
|
|
6
|
+
* Doppler credential resolution cascade, multi-hypervisor management
|
|
7
|
+
* across Proxmox VE and VMware ESXi, remote appliance CLI control,
|
|
8
|
+
* and graceful lifecycle management.
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
+
import { SseServerInstance } from "../src/transports/sse.js";
|
|
14
|
+
import { ServerConfig } from "../src/types/config.js";
|
|
15
|
+
export declare const VERSION = "0.1.0";
|
|
16
|
+
export interface CliOptions {
|
|
17
|
+
transport: "stdio" | "sse";
|
|
18
|
+
port: number;
|
|
19
|
+
host: string;
|
|
20
|
+
config?: string;
|
|
21
|
+
dopplerToken?: string;
|
|
22
|
+
dopplerProject?: string;
|
|
23
|
+
dopplerConfig?: string;
|
|
24
|
+
forceMock?: boolean;
|
|
25
|
+
redactSecrets?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface CliExecutionResult {
|
|
28
|
+
server: McpServer;
|
|
29
|
+
transport: StdioServerTransport | SseServerInstance;
|
|
30
|
+
close: () => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export interface RunCliOptions {
|
|
33
|
+
installSignalHandlers?: boolean;
|
|
34
|
+
suppressLogs?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Builds the Commander CLI program definition.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildCli(exitOverride?: boolean): Command;
|
|
40
|
+
/**
|
|
41
|
+
* Parses and validates command-line arguments.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseCliOptions(argv?: string[], exitOverride?: boolean): {
|
|
44
|
+
options: CliOptions;
|
|
45
|
+
program: Command;
|
|
46
|
+
raw: Record<string, any>;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Loads and validates a JSON configuration file if specified.
|
|
50
|
+
*/
|
|
51
|
+
export declare function loadConfigFile(configPath: string): Partial<ServerConfig>;
|
|
52
|
+
/**
|
|
53
|
+
* Runs the Call Telemetry Lab MCP Server CLI.
|
|
54
|
+
*/
|
|
55
|
+
export declare function runCli(argv?: string[], runOptions?: RunCliOptions): Promise<CliExecutionResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Detects whether this file was executed directly as the main Node.js entrypoint.
|
|
58
|
+
*/
|
|
59
|
+
export declare function isMainModule(metaUrl: string): boolean;
|
|
60
|
+
//# sourceMappingURL=ct-lab-mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-lab-mcp.d.ts","sourceRoot":"","sources":["../../bin/ct-lab-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAIjF,OAAO,EAAmB,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAqB,MAAM,wBAAwB,CAAC;AAQzE,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,GAAG,KAAK,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,oBAAoB,GAAG,iBAAiB,CAAC;IACpD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,YAAY,UAAQ,GAAG,OAAO,CAmCtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,GAAE,MAAM,EAAiB,EAC7B,YAAY,UAAQ,GACnB;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAkDrE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAuBxE;AAED;;GAEG;AACH,wBAAsB,MAAM,CAC1B,IAAI,GAAE,MAAM,EAAiB,EAC7B,UAAU,GAAE,aAAkB,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CAmI7B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiBrD"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Call Telemetry Lab & Fleet MCP Server CLI
|
|
4
|
+
*
|
|
5
|
+
* Command-line runner supporting Stdio and HTTP/SSE transports,
|
|
6
|
+
* Doppler credential resolution cascade, multi-hypervisor management
|
|
7
|
+
* across Proxmox VE and VMware ESXi, remote appliance CLI control,
|
|
8
|
+
* and graceful lifecycle management.
|
|
9
|
+
*/
|
|
10
|
+
import process from "node:process";
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { Command } from "commander";
|
|
15
|
+
import dotenv from "dotenv";
|
|
16
|
+
import { createMcpServer } from "../src/server.js";
|
|
17
|
+
import { credentialResolver } from "../src/credentials/resolver.js";
|
|
18
|
+
import { startStdioServer } from "../src/transports/stdio.js";
|
|
19
|
+
import { createSseServer } from "../src/transports/sse.js";
|
|
20
|
+
// Load environment variables from .env if present
|
|
21
|
+
dotenv.config();
|
|
22
|
+
export const VERSION = "0.1.0";
|
|
23
|
+
/**
|
|
24
|
+
* Builds the Commander CLI program definition.
|
|
25
|
+
*/
|
|
26
|
+
export function buildCli(exitOverride = false) {
|
|
27
|
+
const program = new Command();
|
|
28
|
+
program
|
|
29
|
+
.name("ct-lab-mcp")
|
|
30
|
+
.description("Expanded Model Context Protocol (MCP) server for Call Telemetry lab, fleet, and appliance management across Proxmox VE and VMware ESXi.")
|
|
31
|
+
.version(VERSION, "-v, --version", "Output the current version")
|
|
32
|
+
.helpOption("-h, --help", "Display help for command")
|
|
33
|
+
.option("-t, --transport <type>", "Transport mode: 'stdio' or 'sse'", process.env.CT_LAB_MCP_TRANSPORT || process.env.PROXMOX_MCP_TRANSPORT || "stdio")
|
|
34
|
+
.option("-p, --port <number>", "Port for SSE transport (default: 3000 or PORT env var)", process.env.PORT || "3000")
|
|
35
|
+
.option("-H, --host <string>", "Host interface for SSE (default: '127.0.0.1' or HOST env var)", process.env.HOST || "127.0.0.1")
|
|
36
|
+
.option("-c, --config <path>", "Path to optional JSON configuration file")
|
|
37
|
+
.option("--doppler-token <token>", "Doppler API token override")
|
|
38
|
+
.option("--doppler-project <project>", "Doppler project override")
|
|
39
|
+
.option("--doppler-config <config>", "Doppler environment/config override")
|
|
40
|
+
.option("--force-mock", "Force in-memory mock hypervisor & appliance mode (for testing/offline dev)")
|
|
41
|
+
.option("--redact-secrets", "Enable strict secret redaction mode across all logs");
|
|
42
|
+
if (exitOverride) {
|
|
43
|
+
program.exitOverride();
|
|
44
|
+
}
|
|
45
|
+
return program;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parses and validates command-line arguments.
|
|
49
|
+
*/
|
|
50
|
+
export function parseCliOptions(argv = process.argv, exitOverride = false) {
|
|
51
|
+
const program = buildCli(exitOverride);
|
|
52
|
+
program.parse(argv);
|
|
53
|
+
const raw = program.opts();
|
|
54
|
+
const transportSource = program.getOptionValueSource("transport");
|
|
55
|
+
const portSource = program.getOptionValueSource("port");
|
|
56
|
+
const hostSource = program.getOptionValueSource("host");
|
|
57
|
+
// Validate transport
|
|
58
|
+
const rawTransport = String(raw.transport || "stdio").toLowerCase();
|
|
59
|
+
if (rawTransport !== "stdio" && rawTransport !== "sse") {
|
|
60
|
+
throw new Error(`Invalid transport mode: '${raw.transport}'. Supported transports are 'stdio' and 'sse'.`);
|
|
61
|
+
}
|
|
62
|
+
const transport = rawTransport;
|
|
63
|
+
// Validate port (allow 0 for ephemeral OS port allocation)
|
|
64
|
+
const parsedPort = parseInt(String(raw.port), 10);
|
|
65
|
+
if (isNaN(parsedPort) || parsedPort < 0 || parsedPort > 65535) {
|
|
66
|
+
throw new Error(`Invalid port number: '${raw.port}'. Port must be an integer between 0 and 65535.`);
|
|
67
|
+
}
|
|
68
|
+
const host = String(raw.host || "127.0.0.1");
|
|
69
|
+
const options = {
|
|
70
|
+
transport,
|
|
71
|
+
port: parsedPort,
|
|
72
|
+
host,
|
|
73
|
+
config: raw.config ? String(raw.config) : undefined,
|
|
74
|
+
dopplerToken: raw.dopplerToken ? String(raw.dopplerToken) : undefined,
|
|
75
|
+
dopplerProject: raw.dopplerProject ? String(raw.dopplerProject) : undefined,
|
|
76
|
+
dopplerConfig: raw.dopplerConfig ? String(raw.dopplerConfig) : undefined,
|
|
77
|
+
forceMock: Boolean(raw.forceMock),
|
|
78
|
+
redactSecrets: Boolean(raw.redactSecrets),
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
options,
|
|
82
|
+
program,
|
|
83
|
+
raw: {
|
|
84
|
+
...raw,
|
|
85
|
+
transportSource,
|
|
86
|
+
portSource,
|
|
87
|
+
hostSource,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Loads and validates a JSON configuration file if specified.
|
|
93
|
+
*/
|
|
94
|
+
export function loadConfigFile(configPath) {
|
|
95
|
+
const resolvedPath = path.resolve(process.cwd(), configPath);
|
|
96
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
97
|
+
throw new Error(`Configuration file not found: '${configPath}' (resolved to '${resolvedPath}')`);
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const rawContent = fs.readFileSync(resolvedPath, "utf-8");
|
|
101
|
+
const parsed = JSON.parse(rawContent);
|
|
102
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
103
|
+
throw new Error(`Configuration file '${configPath}' must contain a valid JSON object.`);
|
|
104
|
+
}
|
|
105
|
+
return parsed;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
if (err instanceof SyntaxError) {
|
|
109
|
+
throw new Error(`Failed to parse configuration file '${configPath}': Invalid JSON - ${err.message}`);
|
|
110
|
+
}
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Runs the Call Telemetry Lab MCP Server CLI.
|
|
116
|
+
*/
|
|
117
|
+
export async function runCli(argv = process.argv, runOptions = {}) {
|
|
118
|
+
const { options, raw } = parseCliOptions(argv);
|
|
119
|
+
// Load config file if specified
|
|
120
|
+
let fileConfig = {};
|
|
121
|
+
if (options.config) {
|
|
122
|
+
fileConfig = loadConfigFile(options.config);
|
|
123
|
+
}
|
|
124
|
+
// Precedence: CLI flag > Config file > Environment variables > Defaults
|
|
125
|
+
const effectiveTransport = raw.transportSource === "cli"
|
|
126
|
+
? options.transport
|
|
127
|
+
: fileConfig.transport || options.transport || "stdio";
|
|
128
|
+
const effectivePort = raw.portSource === "cli"
|
|
129
|
+
? options.port
|
|
130
|
+
: fileConfig.port !== undefined
|
|
131
|
+
? fileConfig.port
|
|
132
|
+
: options.port;
|
|
133
|
+
const effectiveHost = raw.hostSource === "cli"
|
|
134
|
+
? options.host
|
|
135
|
+
: fileConfig.host || options.host || "127.0.0.1";
|
|
136
|
+
const effectiveForceMock = options.forceMock || fileConfig.mockMode || false;
|
|
137
|
+
let credentialsResult;
|
|
138
|
+
let hostConfigs = fileConfig.hosts;
|
|
139
|
+
if (!hostConfigs || hostConfigs.length === 0) {
|
|
140
|
+
credentialsResult = await credentialResolver.resolve({
|
|
141
|
+
env: process.env,
|
|
142
|
+
dopplerToken: options.dopplerToken || fileConfig.doppler?.token,
|
|
143
|
+
dopplerProject: options.dopplerProject || fileConfig.doppler?.project,
|
|
144
|
+
dopplerConfig: options.dopplerConfig || fileConfig.doppler?.config,
|
|
145
|
+
forceMock: effectiveForceMock,
|
|
146
|
+
});
|
|
147
|
+
hostConfigs = credentialsResult.proxmoxHosts || credentialsResult.hosts;
|
|
148
|
+
}
|
|
149
|
+
// Create the MCP server instance
|
|
150
|
+
const server = createMcpServer({
|
|
151
|
+
credentials: credentialsResult,
|
|
152
|
+
proxmoxConfigs: hostConfigs,
|
|
153
|
+
esxiConfigs: credentialsResult?.esxiHosts,
|
|
154
|
+
forceMock: effectiveForceMock,
|
|
155
|
+
});
|
|
156
|
+
const installSignals = runOptions.installSignalHandlers !== false;
|
|
157
|
+
if (effectiveTransport === "sse") {
|
|
158
|
+
const slotManager = server._context
|
|
159
|
+
?.slotManager;
|
|
160
|
+
const hypervisorManager = server._context
|
|
161
|
+
?.hypervisorManager;
|
|
162
|
+
const sseServer = createSseServer(server, {
|
|
163
|
+
port: effectivePort,
|
|
164
|
+
host: effectiveHost,
|
|
165
|
+
slotManager,
|
|
166
|
+
hypervisorManager,
|
|
167
|
+
});
|
|
168
|
+
await sseServer.listen(effectivePort, effectiveHost);
|
|
169
|
+
const close = async () => {
|
|
170
|
+
if (!runOptions.suppressLogs) {
|
|
171
|
+
console.error("[ct-lab-mcp] Shutting down SSE server...");
|
|
172
|
+
}
|
|
173
|
+
await sseServer.close();
|
|
174
|
+
await server.close();
|
|
175
|
+
};
|
|
176
|
+
if (installSignals) {
|
|
177
|
+
const handleSig = async (sig) => {
|
|
178
|
+
console.error(`[ct-lab-mcp] Received ${sig}, terminating...`);
|
|
179
|
+
try {
|
|
180
|
+
await close();
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
console.error("[ct-lab-mcp] Error during shutdown:", err);
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
process.exit(0);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
process.once("SIGINT", () => handleSig("SIGINT"));
|
|
190
|
+
process.once("SIGTERM", () => handleSig("SIGTERM"));
|
|
191
|
+
}
|
|
192
|
+
return { server, transport: sseServer, close };
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// Default stdio transport
|
|
196
|
+
let activeTransport;
|
|
197
|
+
const close = async () => {
|
|
198
|
+
if (!runOptions.suppressLogs) {
|
|
199
|
+
console.error("[ct-lab-mcp] Shutting down stdio server...");
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
await server.close();
|
|
203
|
+
}
|
|
204
|
+
catch { }
|
|
205
|
+
try {
|
|
206
|
+
if (activeTransport) {
|
|
207
|
+
await activeTransport.close();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch { }
|
|
211
|
+
};
|
|
212
|
+
if (installSignals) {
|
|
213
|
+
const handleSig = async (sig) => {
|
|
214
|
+
console.error(`[ct-lab-mcp] Received ${sig}, terminating...`);
|
|
215
|
+
try {
|
|
216
|
+
await close();
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
console.error("[ct-lab-mcp] Error during shutdown:", err);
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
process.exit(0);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
process.once("SIGINT", () => handleSig("SIGINT"));
|
|
226
|
+
process.once("SIGTERM", () => handleSig("SIGTERM"));
|
|
227
|
+
}
|
|
228
|
+
activeTransport = await startStdioServer(server, { installSignalHandlers: false });
|
|
229
|
+
return { server, transport: activeTransport, close };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Detects whether this file was executed directly as the main Node.js entrypoint.
|
|
234
|
+
*/
|
|
235
|
+
export function isMainModule(metaUrl) {
|
|
236
|
+
if (!process.argv[1])
|
|
237
|
+
return false;
|
|
238
|
+
try {
|
|
239
|
+
const scriptPath = fs.realpathSync(process.argv[1]);
|
|
240
|
+
const modulePath = fs.realpathSync(fileURLToPath(metaUrl));
|
|
241
|
+
return scriptPath === modulePath;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
const raw = process.argv[1];
|
|
245
|
+
return (raw.endsWith("ct-lab-mcp") ||
|
|
246
|
+
raw.endsWith("ct-lab-mcp.ts") ||
|
|
247
|
+
raw.endsWith("ct-lab-mcp.js") ||
|
|
248
|
+
raw.endsWith("proxmox-mcp") ||
|
|
249
|
+
raw.endsWith("proxmox-mcp.ts") ||
|
|
250
|
+
raw.endsWith("proxmox-mcp.js"));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Auto-run if executed as CLI entrypoint
|
|
254
|
+
if (isMainModule(import.meta.url)) {
|
|
255
|
+
runCli().catch((err) => {
|
|
256
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
257
|
+
console.error(`[ct-lab-mcp] Fatal error: ${msg}`);
|
|
258
|
+
process.exit(1);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=ct-lab-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-lab-mcp.js","sourceRoot":"","sources":["../../bin/ct-lab-mcp.ts"],"names":[],"mappings":"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"}
|