The official MCP registry is written in Go and cloud-hosted.
I wanted something I could self-host, written in TypeScript,
that my team could run inside our own infra.
So I built mcp-hub.
What it does
- Register any MCP server (SSE, HTTP, stdio transports)
- Proxy all tool calls through one endpoint with auth forwarding
- Stream every tool call live via WebSocket (Socket.io)
- Monitor server health async via BullMQ jobs
Stack
- NestJS — API framework
- PostgreSQL — server registry + tool call logs
- Redis — WebSocket pub/sub + BullMQ transport
- BullMQ — async health check queue
- Socket.io — real-time log streaming
How it works
Register a server once:
curl -X POST http://localhost:3000/api/v1/servers \
-H 'Content-Type: application/json' \
-d '{
"name": "github-mcp",
"url": "http://my-mcp-server:8080",
"transport": "http"
}'
Then proxy any tool call through mcp-hub:
curl -X POST http://localhost:3000/api/v1/proxy/{serverId}/call \
-H 'Content-Type: application/json' \
-d '{ "tool": "create_issue", "input": { "title": "Bug" } }'
Every call is logged to PostgreSQL and streamed live over WebSocket.
Run it in one command
git clone https://github.com/DIYA73/mcp-hub
cd mcp-hub
cp .env.example .env
docker compose up
API at http://localhost:3000/api/v1
WebSocket at ws://localhost:3000/logs
Why I built this
I'm running multiple MCP servers locally and needed a central
place to register them, forward calls, and see what's happening
in real time. Nothing TypeScript-native existed.
GitHub: https://github.com/DIYA73/mcp-hub
Feedback welcome — especially if you're running MCP servers in prod.
Top comments (2)
Nice work on the MCP hub — self-hosting MCP infra is exactly what teams need. One issue I've hit with agent tooling is agents jumping into execution mode when they should still be brainstorming. Built a small plugin (Brainstorm-Mode by mehmetcanfarsak on GitHub) that uses PreToolUse hooks to keep agents in ideation mode — could pair nicely with an MCP proxy for managing agent behavior at the infra layer.
Nice! A single audited choke point for tool calls is the right shape for a team. Two things I'd be curious about once stdio transport is in the mix: the hub now owns those child processes' lifecycle, so what happens when a stdio server hangs mid-call instead of crashing, do the BullMQ health checks kill and respawn it, or just mark it unhealthy? And since every call carries forwarded auth through one endpoint, that Postgres call log is now your most sensitive table are tool inputs stored raw, or is there redaction before they hit it?