DEV Community

Diya
Diya

Posted on

I built a self-hosted MCP server registry and proxy in TypeScript

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"
  }'
Enter fullscreen mode Exit fullscreen mode

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" } }'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
mehmetcanfarsak profile image
Mehmet Can Farsak

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.

Collapse
 
nazar_boyko profile image
Nazar Boyko

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?