MCP Hub

by amir-the-h

Not rated
GitHub

About

A lightweight MCP Hub to centralize your MCP servers in one place.

Details

Author
amir-the-h
Categories
Other, Developer Tools

Setup

Install MCP Hub in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/amir-the-h/mcp-hub

Follow the installation instructions in the repository README, then restart your MCP client.

A Go-based hub that aggregates multiple MCP (Model Context Protocol) servers and exposes their tools through a unified HTTP API.

- Standard MCP Protocol: Full support for MCP 2024-11-05 specification
- Multiple Transport Types:

- Stdio: For local MCP servers (Node.js, Python, etc.)
- HTTP/SSE: For remote MCP servers

cd cmd/mcp-hub go build -o ../../mcp-hub

Create aconfig.jsonfile (seeconfig.example.jsonfor a template):

{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }, "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } } } }
# Using default config.json ./mcp-hub # Or specify a config file ./mcp-hub --config /path/to/config.json

- The HTTP listen address can be overridden with theMCP_HUB_PORTorPORTenvironment variable. If the value contains a colon it is treated as a full address (e.g.0.0.0.0:8080), otherwise it is treated as a port and is prefixed with a colon.
- The binary accepts a--configflag (default:config.json).

curl -X POST http://localhost:8080/mcp/execute \ -H 'Content-Type: application/json' \ -d '{ "plugin_id": "filesystem", "tool_name": "read_file", "arguments": {"path": "/tmp/test.txt"} }'

The configuration file uses the standardmcpServersformat compatible with Cursor, VSCode, and Claude Desktop.

For MCP servers that run as local processes:

{ "mcpServers": { "server-name": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-package"], "env": { "API_KEY": "${YOUR_API_KEY}" }, "timeout": 30 } } }

- command: Executable to run (required)
- args: Command line arguments (optional)
- env: Environment variables (optional, supports${VAR}expansion)
- timeout: Request timeout in seconds (optional, default: 30)
- disabled: Set totrueto disable a server (optional)

{ "mcpServers": { "remote-server": { "type": "http", "url": "http://localhost:3000/mcp", "headers": { "Authorization": "Bearer ${API_TOKEN}" }, "timeout": 45 } } }

- type: Set to"http"for HTTP transport (or auto-detected fromurl)
- url: HTTP endpoint URL (required)
- headers: HTTP headers to include (optional, supports${VAR}expansion)
- timeout: Request timeout in seconds (optional, default: 30)

Environment variables in the configuration are expanded using${VAR_NAME}syntax. For example:

{ "mcpServers": { "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } } } }

The repository provides two Docker image variants, optimized for different use cases:

1.Standard Image(Dockerfile/mcp-hub:latest)

- Size: ~47MB
- Includes: Alpine Linux + Docker CLI + mcp-hub binary
- Use when: You need Docker transport for running MCP servers in containers, or mixed transports
- Best for: Production deployments with container-based MCP servers

2.Local MCP Servers Image(Dockerfile.local/mcp-hub:local)

- Size: ~800MB
- Includes: Node.js 20, Python 3, uv, curl, git, and mcp-hub binary
- Use when: You want to run local stdio-based MCP servers (Node.js, Python) in the same container
- Best for: Self-contained deployments where the hub and all MCP servers run together

# Standard image (with Docker CLI) docker build -t mcp-hub:latest . # Local MCP servers image (with Node.js, Python, uv) docker build -f Dockerfile.local -t mcp-hub:local .
# Create a config directory mkdir -p config # Put your config.json in the config directory cp config.json config/ # Run the container docker run -d \ -p 8080:8080 \ -v $(pwd)/config:/config:ro \ -e GITHUB_TOKEN=${GITHUB_TOKEN} \ mcp-hub
version: '3.8' services: mcp-hub: build: . ports: - "8080:8080" volumes: - ./config:/config:ro - ./plugins:/plugins:ro # Optional: mount custom plugins environment: - GITHUB_TOKEN=${GITHUB_TOKEN} - BRAVE_API_KEY=${BRAVE_API_KEY}

List all available tools from all connected MCP servers.

[ { "id": "read_file", "name": "read_file", "description": "Read contents of a file", "plugin_id": "filesystem" } ]

Execute a tool on a specific MCP server.

{ "plugin_id": "filesystem", "tool_name": "read_file", "arguments": { "path": "/tmp/test.txt" } }

Response:MCP tool call result (format depends on the tool)

{ "servers": ["filesystem", "github", "brave-search"] }

Server-Sent Events stream of tool registry updates (for real-time tool discovery).

{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/documents"] }, "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } }, "brave-search": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-brave-search"], "env": { "BRAVE_API_KEY": "${BRAVE_API_KEY}" } } } }
{ "mcpServers": { "custom-tools": { "command": "python3", "args": ["/app/plugins/custom_mcp_server.py"] } } }

Example 3: Mixed Local and Remote Servers

{ "mcpServers": { "local-filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"] }, "remote-api": { "type": "http", "url": "https://api.example.com/mcp", "headers": { "Authorization": "Bearer ${API_TOKEN}" } } } }
. ├── cmd/ │ └── mcp-hub/ │ └── main.go # Entry point ├── internal/ │ ├── config/ │ │ └── config.go # Configuration parsing │ ├── mcp/ │ │ └── protocol.go # MCP protocol structures │ ├── plugin/ │ │ └── manager.go # Server management │ ├── registry/ │ │ └── registry.go # Tool registry │ ├── server/ │ │ └── server.go # HTTP server │ └── transport/ │ ├── transport.go # Transport interface │ ├── stdio.go # Stdio transport │ └── http.go # HTTP transport ├── config.example.json # Example configuration └── README.md

Implement theTransportinterface ininternal/transport/:

type Transport interface { Start(ctx context.Context) error SendRequest(ctx context.Context, req interface{}) (json.RawMessage, error) SendNotification(ctx context.Context, notification interface{}) error Close() error IsConnected() bool }

Check logs for specific error messages. Common issues:

- Missingnpxorpython3in PATH
- Invalid MCP server package names
- Missing environment variables
- Incorrect file paths in configuration

- Verify the MCP server is properly initialized (check/mcp/servers)
- Ensure tool arguments match the expected schema
- Check server logs (stderr output is visible in hub logs)

Increase thetimeoutvalue in server configuration:

{ "mcpServers": { "slow-server": { "command": "...", "timeout": 120 } } }

For MCP servers running in Docker containers:

{ "mcpServers": { "containerized-server": { "type": "docker", "image": "my-mcp-server:latest", "args": ["--option", "value"], "env": { "API_KEY": "${YOUR_API_KEY}" }, "volumes": { "/host/path": "/container/path", "${HOME}/data": "/data" }, "network": "mcp-network", "timeout": 60 } } }

- type: Set to"docker"for Docker transport (or auto-detected fromimage)
- image: Docker image name (required)
- args: Command arguments to pass to container entrypoint (optional)
- env: Environment variables (optional, supports${VAR}expansion)
- volumes: Volume mounts ashost:containermappings (optional, supports${VAR}expansion)
- network: Docker network to connect to (optional)
- timeout: Request timeout in seconds (optional, default: 30)

- No need to install Node.js, Python, or other runtimes on the hub host
- Isolated dependencies per MCP server
- Easy version management with Docker tags
- Consistent environment across deployments

You can containerize any MCP server to avoid installing its dependencies on the hub host.

Example: Dockerizing a Python MCP Server

FROM python:3.11-slim WORKDIR /app # Install dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy MCP server code COPY mcp_server.py . # Run as non-root user RUN useradd -m -u 1000 mcpuser && chown -R mcpuser:mcpuser /app USER mcpuser # The server should read from stdin and write to stdout ENTRYPOINT ["python", "-u", "mcp_server.py"]
# Build the image docker build -t my-mcp-server:latest . # Add to config.json { "mcpServers": { "my-server": { "image": "my-mcp-server:latest" } } }

Example: Dockerizing a Node.js MCP Server

FROM node:20-alpine WORKDIR /app # Install dependencies COPY package*.json ./ RUN npm ci --production # Copy server code COPY . . # Run as non-root user RUN addgroup -g 1000 mcpuser && \ adduser -D -u 1000 -G mcpuser mcpuser && \ chown -R mcpuser:mcpuser /app USER mcpuser ENTRYPOINT ["node", "server.js"]

- Use-iflag: The hub runs containers withdocker run -ifor interactive stdin/stdout
- Unbuffered output: Ensure your server outputs are unbuffered (usepython -uorflush())
- Stdin/Stdout only: The MCP protocol uses stdin for input and stdout for output
- Stderr for logs: Use stderr for logging (visible in hub logs)
- Cleanup: Containers are run with--rmfor automatic cleanup

Create a registry of Docker images for common MCP servers:

# Example: Build an echo server image cd examples/plugins cat > Dockerfile << 'DOCKERFILE' FROM python:3.11-slim COPY mcp_echo.py /app/server.py WORKDIR /app RUN chmod +x server.py ENTRYPOINT ["python", "-u", "server.py"] DOCKERFILE docker build -t mcp-echo:latest .
{ "mcpServers": { "echo": { "image": "mcp-echo:latest" } } }

- ✅ You want to avoid installing Node.js, Python, or other runtimes on your hub host
- ✅ You need consistent, reproducible environments across deployments
- ✅ You want easy version management with Docker tags
- ✅ You're running the hub in a containerized environment (Kubernetes, Docker Compose)
- ✅ You need to isolate server dependencies
- ✅ You want to use pre-built MCP server images from a registry

- ✅ You're developing locally and want faster iteration
- ✅ Runtime dependencies are already installed
- ✅ You need the absolute lowest latency

- ✅ MCP servers are hosted remotely
- ✅ You need to scale servers independently
- ✅ You want to use managed MCP server services

Here's a complete example running multiple MCP servers in Docker:

# 1. Build your custom MCP server image docker build -t my-mcp-server:v1.0 ./my-server # 2. Create Docker network for inter-container communication docker network create mcp-network # 3. Configure servers cat > config.json << 'JSON' { "mcpServers": { "echo": { "image": "mcp-echo:latest" }, "custom-tools": { "image": "my-mcp-server:v1.0", "env": { "API_KEY": "${MY_API_KEY}" }, "volumes": { "/host/data": "/data" } } } } JSON # 4. Run the hub MY_API_KEY=secret123 ./mcp-hub --config config.json

- ✨ No runtime dependencies on the hub host
- ✨ Isolated environments for each MCP server
- ✨ Easy updates by changing Docker image tags
- ✨ Reproducible deployments

The mcp-hub itself can run in a Docker container. SeeDOCKER_DEPLOYMENT.mdfor complete deployment guide.

# Build the image docker build -t mcp-hub:latest . # Run with your config docker run -d \ --name mcp-hub \ -p 8080:8080 \ -v $(pwd)/config.json:/app/config.json:ro \ -v /var/run/docker.sock:/var/run/docker.sock \ -e GITHUB_TOKEN=${GITHUB_TOKEN} \ mcp-hub:latest

- Standard (with Docker CLI): ~47MB
- Minimal (stdio/HTTP only): ~6MB

Environment variables are automatically passed through and expanded in your configuration.

The MCP Hub automatically watches the configuration file for changes and updates the registry accordingly. When you modifyconfig.json, the hub will:

- Add new servers: Automatically start any newly added MCP servers
- Remove servers: Stop servers that are removed from config or disabled
- Reload servers: Restart servers whose configuration has changed
- Update registry: Keep the tool registry in sync with active servers

The watcher usesfsnotifyto monitor the config file for write events. When changes are detected:
- The new config is loaded and validated
- Changes are compared with the previous configuration
- Appropriate actions are taken (start/stop/reload servers)
- The registry is automatically updated
- Changes are logged for visibility

To avoid processing rapid successive changes (e.g., when editors write multiple times), the watcher includes a 500ms debounce delay. This ensures the config is only reloaded once after you finish editing.

# Start mcp-hub ./mcp-hub --config=config.json # In another terminal, edit config.json vim config.json # The hub will automatically detect changes and log: # "config file changed, reloading..." # "adding server: new-server" # "loaded MCP server: new-server (stdio transport)"

- Invalid JSON: Changes are rejected, hub continues with previous config
- Missing required fields: Changes are rejected with validation error
- Server startup failures: Logged as warnings, other servers continue running

Chia Health MCP Server — Patient workflow integration for a licensed US telehealth platform. Browse GLP-1 medications (semaglutide, tirzepatide), peptide therapies (sermorelin, NAD+, glutathione), and longevity treatments. Check eligibility, complete intake, sign consents, and manage treatment plans. 30 tools, HIPAA-compliant. All prescriptions evaluated by licensed US healthcare providers and delivered from FDA-regulated pharmacies across 50 states + DC.

Broker + MCP server for last-bidder-wins games on Solana — agents register, auto-fund a Privy wallet, and bid via streamable HTTP

AI-powered no-code app builder with 17 MCP tools — create projects, generate pages from natural language, AI text/image generation (GPT, Claude, Gemini, 14+ models), page CRUD, workflow execution, publish & version control. SSE transport, API key auth.

An mcp server for your food ordering needs.

Agent-to-Agent handoff certification for multi-agent systems — validates context preservation, verifies agent capabilities before handoff, logs transfer chains, and ensures no data loss in agent orchestration.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.