VuNet MCP HTTP Server
README.md
# VuNet MCP HTTP Server
A **Model Context Protocol (MCP) server** for [VuNet vuSmartMaps](https://www.vunetsystems.com/) using the **Streamable HTTP transport**. Connects AI assistants (VS Code Copilot, ChatGPT, Claude Desktop, etc.) directly to live VuNet observability data.
---
## Features
- **HTTP-based MCP** — works with any MCP client that supports Streamable HTTP (VS Code, ChatGPT, Claude)
- **Multi-environment** — run one server process per VuNet tenant (UAT, production, sandbox) each on its own port
- **Auto-authentication** — logs in to VuNet automatically, caches session for 1 hour
- **HTTPS-ready** — pass cert/key in config for direct TLS, or put NGINX in front
## Tools Exposed
| Tool | Description |
|------|-------------|
| `vunet_get_status` | Check connection status and VuNet tenant info |
| `vunet_query_metric` | Query any VuNet data model/metric with time range and filters |
| `vunet_fetch_datamodels` | Browse/search available signals (Metric, Event, Log) from the live tenant |
| `vunet_list_data_models` | Static reference list of common signal categories |
---
## Prerequisites
- **Node.js 18+** — [download](https://nodejs.org/)
- A running **VuNet vuSmartMaps** instance with API access
- (For HTTPS) A valid TLS certificate for your domain
---
## Quick Start
### 1. Get the package
**Option A — Clone the repo:**
```bash
git clone https://github.com/mithung-vunet/vunet-mcp-http.git
cd vunet-mcp-http
npm install
```
**Option B — Extract the release zip:**
```bash
unzip vunet-mcp-deploy.zip
cd vunet-mcp-deploy
npm install
```
### 2. Configure environments
Copy the example config and fill in your VuNet credentials:
```bash
cp config.example.json config.json
```
Edit `config.json`:
```json
{
"environments": {
"production": {
"label": "VuNet Production",
"tenant_url": "https://your-vunet-host.example.com",
"username": "your-username",
"password": "your-password",
"bu_id": "1",
"verify_ssl": true,
"port": 3001,
"ssl_cert": "",
"ssl_key": ""
},
"uat": {
"label": "VuNet UAT",
"tenant_url": "https://your-vunet-uat-host.example.com",
"username": "your-username",
"password": "your-password",
"bu_id": "1",
"verify_ssl": true,
"port": 3002,
"ssl_cert": "",
"ssl_key": ""
}
}
}
```
> **Note:** `config.json` is git-ignored — never commit real credentials.
### 3. Start the server
**Single environment:**
```bash
VUNET_ENV=production node index.js
# Windows:
set VUNET_ENV=production && node index.js
```
**All environments at once (one process per env):**
```bash
node start-all.js
```
Output:
```
[Vunet MCP] VuNet Production
[Vunet MCP] Listening on http://127.0.0.1:3001/mcp
[Vunet MCP] Tenant: https://your-vunet-host.example.com
[Vunet MCP] Mode: HTTP (no TLS)
```
---
## Configuration Options
### `config.json` fields
| Field | Required | Description |
|-------|----------|-------------|
| `label` | No | Human-readable name shown in logs |
| `tenant_url` | **Yes** | Base URL of your VuNet vuSmartMaps instance |
| `username` | **Yes** | VuNet login username |
| `password` | **Yes** | VuNet login password |
| `bu_id` | No | Business Unit ID (default: `"1"`) |
| `verify_ssl` | No | Set `false` to skip SSL verification for self-signed certs |
| `port` | No | Port to listen on (default: `3000`) |
| `ssl_cert` | No | Path to TLS certificate (enables HTTPS if set with `ssl_key`) |
| `ssl_key` | No | Path to TLS private key |
### Environment variable overrides
All settings can be overridden via environment variables (useful for Docker/CI):
| Variable | Override |
|----------|----------|
| `VUNET_ENV` | Which environment block to load from `config.json` |
| `VUNET_TENANT_URL` | `tenant_url` |
| `VUNET_USERNAME` | `username` |
| `VUNET_PASSWORD` | `password` |
| `VUNET_BU_ID` | `bu_id` |
| `VUNET_VERIFY_SSL` | `verify_ssl` (`false` to disable) |
| `VUNET_BIND_HOST` | Bind address (default `127.0.0.1`, use `0.0.0.0` for external) |
| `VUNET_CONFIG` | Path to a custom config file |
| `PORT` | Override port |
**Pure env-var mode (no config.json):**
```bash
VUNET_TENANT_URL=https://vunet.example.com \
VUNET_USERNAME=admin \
VUNET_PASSWORD=secret \
VUNET_BIND_HOST=0.0.0.0 \
node index.js
```
---
## Production Deployment (Linux + NGINX)
### Run as a background service
```bash
# Start all environments in background
VUNET_ENV=production VUNET_BIND_HOST=0.0.0.0 nohup node index.js > prod.log 2>&1 &
VUNET_ENV=uat VUNET_BIND_HOST=0.0.0.0 nohup node index.js > uat.log 2>&1 &
```
### NGINX reverse proxy with HTTPS
Install NGINX and configure it to terminate TLS and proxy to Node:
```nginx
server {
listen 443 ssl;
server_name mcp.your-domain.com;
ssl_certificate /path/to/fullchain.crt; # leaf + intermediate concatenated
ssl_certificate_key /path/to/server.key;
# Route /production/ → Node port 3001
location /production/ {
proxy_pass http://127.0.0.1:3001/mcp;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
}
# Route /uat/ → Node port 3002
location /uat/ {
proxy_pass http://127.0.0.1:3002/mcp;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
}
}
```
> **Important:** Include the full certificate chain (leaf + intermediate) in your `ssl_certificate` file. Missing intermediates will cause ChatGPT and other clients to reject the TLS connection.
>
> Concatenate them:
> ```bash
> cat server.crt intermediate.crt > fullchain.crt
> ```
Enable and reload:
```bash
sudo ln -s /etc/nginx/sites-available/mcp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
---
## MCP Client Configuration
### VS Code (GitHub Copilot)
Add to your workspace `.vscode/mcp.json`:
```json
{
"servers": {
"vunet-production": {
"type": "http",
"url": "https://mcp.your-domain.com/production/"
},
"vunet-uat": {
"type": "http",
"url": "https://mcp.your-domain.com/uat/"
}
}
}
```
Then use **Ctrl+Shift+P → MCP: List Servers** to connect.
### ChatGPT
1. Go to **chatgpt.com → Apps (beta) → New App**
2. Set **MCP Server URL** to `https://mcp.your-domain.com/uat/`
3. Set **Authentication** to `No Auth`
4. Check the acknowledgment and click **Create**
### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"vunet": {
"type": "http",
"url": "https://mcp.your-domain.com/production/"
}
}
}
```
---
## Verify the Server
Test the MCP handshake with curl:
```bash
curl https://mcp.your-domain.com/uat/ \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
```
Expected response:
```
event: message
data: {"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"vunet-mcp-server","version":"1.0.0"}},"jsonrpc":"2.0","id":1}
```
---
## Troubleshooting
| Symptom | Cause | Fix |
|---------|-------|-----|
| `Not Acceptable: Client must accept text/event-stream` | Missing `Accept` header | Normal in browser — MCP clients send the right headers automatically |
| `Already connected to a transport` | Old server version | Upgrade to v1.1+ which creates a fresh Server per connection |
| `Error creating connector` (ChatGPT) | Certificate chain incomplete | Concatenate leaf + intermediate into `fullchain.crt` |
| `502 Bad Gateway` | Server can't reach VuNet tenant | Check `tenant_url`, network, and `verify_ssl` setting |
| `Verify return code: 21` | Missing intermediate cert | Download and concatenate the CA intermediate cert |
| `Unable to verify certificate` | Self-signed cert | Set `"verify_ssl": false` in config |
---
## Security Notes
- `config.json` is **git-ignored** — never commit it
- Use environment variables instead of config files in containerized deployments
- Restrict `VUNET_BIND_HOST` to `127.0.0.1` when running behind NGINX (don't expose Node directly)
- Use a reverse proxy (NGINX) to handle TLS — avoid putting private keys in app config where possible
---
## License
MIT — © VuNet Systems
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues