badger-websocket-mcp
v1.1.0
Published
MCP server that streams WebSocket logs to Cursor for debugging
Readme
WebSocket MCP Server
MCP server that connects to a WebSocket and exposes live log entries to Cursor (or any MCP client) for debugging. It supports two transports:
Install: npm install badger-websocket-mcp or run with npx badger-websocket-mcp
- stdio (recommended for Cursor): Cursor spawns the server and passes config via
mcp.jsonenv. All credentials stay in mcp.json. - SSE: The server runs as an HTTP process and Cursor connects via URL. New messages are pushed via MCP resource subscriptions over SSE.
Repository: github.com/ajgreyling/badger-websocket-mcp
Architecture
sequenceDiagram
participant Cursor
participant MCP as MCP_Server
participant WS as WebSocket
Cursor->>MCP: resources/list
MCP-->>Cursor: logs resource
Cursor->>MCP: resources/subscribe (ws-log://logs)
MCP-->>Cursor: subscribed
MCP->>WS: connect (wss + Basic auth)
WS-->>MCP: log message
MCP->>MCP: append to buffer, emit resources/updated
MCP->>Cursor: notifications/resources/updated (ws-log://logs)
Cursor->>MCP: resources/read (ws-log://logs)
MCP-->>Cursor: current log buffer (text)Prerequisites
- Node.js 18 or later
- Cursor with MCP support (or another MCP client)
- Credentials for the WebSocket (username and password)
Using the NPM package
No clone or build needed. Install and run directly:
npm install badger-websocket-mcpOr use npx (no install):
npx badger-websocket-mcpFor Cursor stdio mode, add to mcp.json and point at the package:
- npx:
"command": "npx","args": ["-y", "badger-websocket-mcp"] - Installed:
"command": "node","args": ["${workspaceFolder}/node_modules/badger-websocket-mcp/build/index.js"]
See Cursor configuration for full examples.
Configuration: credentials and WebSocket URL
The server expects configuration from the MCP server config only. Set WS_URL, WS_USER, and WS_PASSWORD (or WS_AUTH) in the env block of .cursor/mcp.json. Cursor passes these into the process when it spawns the server.
| Variable | Required | Description |
| ---------------------------- | -------- | --------------------------------------------------------------------------- |
| WS_URL | Yes | WebSocket endpoint, e.g. wss://helium.mezzanineware.com/api/ws2/logging?appId=YOUR_APP_ID |
| WS_USER | Yes | Username for Basic auth (same as wscat -c ... --auth $u:$p) |
| WS_PASSWORD | Yes | Password for Basic auth |
| OUTPUT_TO_CURSOR_DEBUG_LOG | No | Set to "true" to pipe websocket output to a file for Cursor Debug mode |
| DEBUG_LOG_FILE | No* | Path for the debug log file (e.g. "${workspaceFolder}/.cursor/debug.log") |
*DEBUG_LOG_FILE is required when OUTPUT_TO_CURSOR_DEBUG_LOG is true. Cursor resolves ${workspaceFolder} when used in mcp.json.
Alternative: Use WS_AUTH=username:password instead of WS_USER and WS_PASSWORD.
You can use literal values in mcp.json or Cursor’s interpolation (e.g. "WS_USER": "${env:HELIUM_USER}") to read from your shell environment. Do not commit mcp.json if it contains secrets; it is gitignored in this repo.
Output to Cursor Debug log
When debugging with Cursor, you can pipe websocket output to a formatted file that the agent can read.
- Set
OUTPUT_TO_CURSOR_DEBUG_LOGto"true"inmcp.jsonenv. - Set
DEBUG_LOG_FILEto the output path, e.g."${workspaceFolder}/.cursor/debug.log".
Example mcp.json env block:
"env": {
"MCP_TRANSPORT": "stdio",
"WS_URL": "wss://helium.mezzanineware.com/api/ws2/logging?appId=YOUR_APP_ID",
"WS_USER": "your-username",
"WS_PASSWORD": "your-password",
"OUTPUT_TO_CURSOR_DEBUG_LOG": "true",
"DEBUG_LOG_FILE": "${workspaceFolder}/.cursor/debug.log"
}Log messages in Helium JSON format are parsed and written as: {local timestamp} - {LEVEL} - {message}. Timestamps use the system's local timezone. For example:
2026-02-13T12:45:18.651+02:00 - WARN - WaterMapCurrent:feature groups fallback for layer=vw_geo_wa_pipe_fullConnection lifecycle events (open, close, error) are also written. Non-JSON or malformed messages are written unchanged.
Setup
From source, clone the repo and install:
git clone https://github.com/ajgreyling/badger-websocket-mcp.git
cd badger-websocket-mcpInstall dependencies
npm installSet configuration (see Configuration above): set
WS_URL,WS_USER, andWS_PASSWORD(orWS_AUTH) inmcp.jsonenv. For SSE mode, export them in your shell when starting the server.Optional: Set
PORT(default:3000) for the HTTP server in SSE mode.Build and run
npm run build npm startThe server listens on
http://127.0.0.1:3000(or yourPORT). Endpoints:- GET /mcp — SSE stream (Cursor connects here)
- POST /messages — JSON-RPC messages (used by the client with
?sessionId=...)
For development (run TypeScript without building):
npm run devTo run the test script (
node test-get-logs.mjs), setWS_USERandWS_PASSWORDin your environment (e.g.export WS_USER=... WS_PASSWORD=...).
Cursor configuration
Option A: stdio (config in mcp.json)
Configure the WebSocket URL and credentials in mcp.json so Cursor spawns the server. No separate server process needed.
- Open Cursor Settings → Features → MCP.
- Add to your
mcp.json(project:.cursor/mcp.jsonor global:~/.cursor/mcp.json).
Using npx (no install, NPM package):
{
"mcpServers": {
"helium-logs": {
"command": "npx",
"args": ["-y", "badger-websocket-mcp"],
"env": {
"MCP_TRANSPORT": "stdio",
"WS_URL": "wss://helium.mezzanineware.com/api/ws2/logging?appId=YOUR_APP_ID",
"WS_USER": "your-username",
"WS_PASSWORD": "your-password",
"OUTPUT_TO_CURSOR_DEBUG_LOG": "true",
"DEBUG_LOG_FILE": "${workspaceFolder}/.cursor/debug.log"
}
}
}
}Using installed NPM package:
{
"mcpServers": {
"helium-logs": {
"command": "node",
"args": ["${workspaceFolder}/node_modules/badger-websocket-mcp/build/index.js"],
"env": {
"MCP_TRANSPORT": "stdio",
"WS_URL": "wss://helium.mezzanineware.com/api/ws2/logging?appId=YOUR_APP_ID",
"WS_USER": "your-username",
"WS_PASSWORD": "your-password",
"OUTPUT_TO_CURSOR_DEBUG_LOG": "true",
"DEBUG_LOG_FILE": "${workspaceFolder}/.cursor/debug.log"
}
}
}
}Testing from source (cloned repo, after npm run build):
{
"mcpServers": {
"helium-logs": {
"command": "node",
"args": ["${workspaceFolder}/build/index.js"],
"env": {
"MCP_TRANSPORT": "stdio",
"WS_URL": "wss://helium.mezzanineware.com/api/ws2/logging?appId=YOUR_APP_ID",
"WS_USER": "your-username",
"WS_PASSWORD": "your-password",
"OUTPUT_TO_CURSOR_DEBUG_LOG": "true",
"DEBUG_LOG_FILE": "${workspaceFolder}/.cursor/debug.log"
}
}
}
}OUTPUT_TO_CURSOR_DEBUG_LOG and DEBUG_LOG_FILE are optional; omit them or set OUTPUT_TO_CURSOR_DEBUG_LOG to "false" to disable piping logs to a file.
- Restart Cursor or reload MCP servers.
Option B: SSE (standalone HTTP server)
- Start the server (see Setup above) so it is listening before Cursor connects.
- Open Cursor Settings → Features → MCP.
- Configure:
- Transport: SSE (or select URL-based / remote server).
- URL:
http://127.0.0.1:3000/mcp
(Use yourPORTif you changed it.)
Example mcp.json entry (server must be running with env vars set):
{
"mcpServers": {
"websocket-logs": {
"url": "http://127.0.0.1:3000/mcp"
}
}
}Run the server with the WebSocket URL and credentials before connecting Cursor:
export WS_URL="wss://helium.mezzanineware.com/api/ws2/logging?appId=09a1e3ab-6219-4206-99fb-c5c68de47382"
export WS_USER="your-username"
export WS_PASSWORD="your-password"
npm startUsage in Cursor
- Resource: In the MCP / context UI, open the resource WebSocket logs (
ws-log://logs). Subscribe to it so Cursor refreshes when new log lines arrive. - Tool: The agent can call get_ws_logs to fetch log entries from the in-memory buffer. All parameters are optional and can be combined:
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| lines | integer | Return only the last N rows (applied after any time filter) |
| from_time | ISO 8601 string | Return entries at or after this timestamp, e.g. "2026-03-13T08:00:00+02:00" |
| to_time | ISO 8601 string | Return entries at or before this timestamp |
Examples:
- Last 100 entries:
{ "lines": 100 } - Entries between two times:
{ "from_time": "2026-03-13T08:00:00+02:00", "to_time": "2026-03-13T09:00:00+02:00" } - Last 50 entries within a window:
{ "from_time": "2026-03-13T08:00:00+02:00", "lines": 50 } - All buffered entries:
{}(no arguments)
Output is formatted — Helium JSON entries are rendered as {timestamp} - {key} - {value}. Invalid timestamp strings return a structured error.
Cursor 401 (wscat/terminal works, Cursor gets 401)
When Cursor spawns the MCP, the WebSocket connection can get 401 even though the same credentials work from the terminal. Workaround: run the server from the terminal and have Cursor connect via URL:
- Start the server from a terminal (credentials work there):
cd badger-websocket-mcp ./scripts/start-munic-chat-logs.sh # for munic-chat (port 3000) # or ./scripts/start-sams-logs.sh # for sams (port 3001) - Keep it running. In
mcp.jsonuse URL transport:"munic-chat-logs": { "url": "http://127.0.0.1:3000/mcp" } "sams-logs": { "url": "http://127.0.0.1:3001/mcp" } - Restart Cursor.
Override credentials with env: WS_USER=... WS_PASSWORD=... ./scripts/start-munic-chat-logs.sh
Troubleshooting
WebSocket error: Unexpected server response: 401 — The server rejected the credentials. The client sends Basic auth correctly; a 401 means the username/password are not accepted for this endpoint. Verify from the command line:
wscat -c "wss://helium.mezzanineware.com/api/ws2/logging?appId=YOUR_APP_ID" --auth "USERNAME:PASSWORD"If wscat also gets 401, the credentials are wrong or not allowed for the logging API (e.g. different environment, password changed, or API access not granted). Confirm with your admin.
Security
- Do not commit credentials. Set
WS_USERandWS_PASSWORD(orWS_AUTH) only in yourmcp.jsonor, if using${env:...}interpolation, in your shell environment. Do not commitmcp.jsonif it contains secrets; it is gitignored in this repo.
