MCP Hub

Un MCP Hub ligero para centralizar tus servidores M

Documentación

MCP-Hub

Docker Hub Docker Pulls Docker Image Size Build Status

Un hub basado en Go que agrega múltiples servidores MCP (Model Context Protocol) y expone sus herramientas a través de una API HTTP unificada.

Características

  • Protocolo MCP estándar: Soporte completo para la especificación MCP 2024-11-05
  • Múltiples tipos de transporte:
    • Stdio: Para servidores MCP locales (Node.js, Python, etc.)
    • HTTP/SSE: Para servidores MCP remotos
  • Basado en configuración: Configuración JSON compatible con el formato de Cursor/VSCode
  • Listo para Docker: Despliegue fácil en contenedores con montajes de volúmenes
  • Agregación de herramientas: Combina herramientas de múltiples servidores MCP en un solo lugar
  • API HTTP: Endpoints RESTful para descubrimiento y ejecución de herramientas

Inicio Rápido

1. Compilar

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

2. Crear Configuración

Crea un archivo config.json (consulta config.example.json para una plantilla):

{
  "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}"
      }
    }
  }
}

3. Ejecutar

# Using default config.json
./mcp-hub

# Or specify a config file
./mcp-hub --config /path/to/config.json

Notas:

  • La dirección de escucha HTTP se puede sobrescribir con la variable de entorno MCP_HUB_PORT o PORT. Si el valor contiene dos puntos, se trata como una dirección completa (por ejemplo, 0.0.0.0:8080); de lo contrario, se trata como un puerto y se le antepone dos puntos.
  • El binario acepta un flag --config (por defecto: config.json).

4. Usar la API

Listar todas las herramientas disponibles:

curl http://localhost:8080/mcp/tools

Ejecutar una herramienta:

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"}
  }'

Listar servidores conectados:

curl http://localhost:8080/mcp/servers

Formato de Configuración

El archivo de configuración utiliza el formato estándar mcpServers compatible con Cursor, VSCode y Claude Desktop.

Servidores Stdio (Locales)

Para servidores MCP que se ejecutan como procesos locales:

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

Campos:

  • command: Ejecutable a ejecutar (requerido)
  • args: Argumentos de línea de comandos (opcional)
  • env: Variables de entorno (opcional, admite expansión de ${VAR})
  • timeout: Tiempo de espera de solicitud en segundos (opcional, por defecto: 30)
  • disabled: Establecer en true para deshabilitar un servidor (opcional)

Servidores HTTP (Remotos)

Para servidores MCP accesibles vía HTTP:

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

Campos:

  • type: Establecer en "http" para transporte HTTP (o auto-detectado desde url)
  • url: URL del endpoint HTTP (requerido)
  • headers: Cabeceras HTTP a incluir (opcional, admite expansión de ${VAR})
  • timeout: Tiempo de espera de solicitud en segundos (opcional, por defecto: 30)

Variables de Entorno

Las variables de entorno en la configuración se expanden usando la sintaxis ${VAR_NAME}. Por ejemplo:

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

Luego ejecuta:

GITHUB_TOKEN=your_token_here ./mcp-hub

Despliegue con Docker

Variantes de Imagen

El repositorio proporciona dos variantes de imagen Docker, optimizadas para diferentes casos de uso:

1. Imagen Estándar (Dockerfile / mcp-hub:latest)

  • Tamaño: ~47MB
  • Incluye: Alpine Linux + CLI de Docker + binario mcp-hub
  • Úsala cuando: Necesites transporte Docker para ejecutar servidores MCP en contenedores, o transportes mixtos
  • Mejor para: Despliegues de producción con servidores MCP basados en contenedores

2. Imagen de Servidores MCP Locales (Dockerfile.local / mcp-hub:local)

  • Tamaño: ~800MB
  • Incluye: Node.js 20, Python 3, uv, curl, git y binario mcp-hub
  • Úsala cuando: Quieras ejecutar servidores MCP locales basados en stdio (Node.js, Python) en el mismo contenedor
  • Mejor para: Despliegues autocontenidos donde el hub y todos los servidores MCP se ejecutan juntos

Compilar Imagen Docker

Para compilar una imagen específica localmente:

# 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 .

Ejecutar con Docker

# 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

Docker Compose

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}

Referencia de la API HTTP

GET /mcp/tools

Lista todas las herramientas disponibles de todos los servidores MCP conectados.

Respuesta:

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

POST /mcp/execute

Ejecuta una herramienta en un servidor MCP específico.

Solicitud:

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

Respuesta: Resultado de la llamada a la herramienta MCP (el formato depende de la herramienta)

GET /mcp/servers

Lista todos los servidores MCP conectados.

Respuesta:

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

GET /mcp/stream

Flujo de eventos enviados por el servidor (Server-Sent Events) de actualizaciones del registro de herramientas (para descubrimiento de herramientas en tiempo real).

Ejemplos

Ejemplo 1: Usando Servidores MCP Oficiales

{
  "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}"
      }
    }
  }
}

Ejemplo 2: Servidor MCP Python Personalizado

{
  "mcpServers": {
    "custom-tools": {
      "command": "python3",
      "args": ["/app/plugins/custom_mcp_server.py"]
    }
  }
}

Ejemplo 3: Servidores Mixtos Locales y Remotos

{
  "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}"
      }
    }
  }
}

Desarrollo

Estructura del Proyecto

.
├── 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

Agregar Nuevos Tipos de Transporte

Implementa la interfaz Transport en internal/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
}

Solución de Problemas

El servidor no se inicia

Revisa los registros para mensajes de error específicos. Problemas comunes:

  • Falta npx o python3 en PATH
  • Nombres de paquetes de servidor MCP inválidos
  • Variables de entorno faltantes
  • Rutas de archivo incorrectas en la configuración

La ejecución de herramientas falla

  • Verifica que el servidor MCP esté correctamente inicializado (revisa /mcp/servers)
  • Asegúrate de que los argumentos de la herramienta coincidan con el esquema esperado
  • Revisa los registros del servidor (la salida de stderr es visible en los registros del hub)

Errores de tiempo de espera

Aumenta el valor de timeout en la configuración del servidor:

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

Licencia

MIT

Servidores Docker (Contenedorizados)

Para servidores MCP que se ejecutan en contenedores Docker:

{
  "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
    }
  }
}

Campos:

  • type: Establecer en "docker" para transporte Docker (o auto-detectado desde image)
  • image: Nombre de la imagen Docker (requerido)
  • args: Argumentos de comando para pasar al entrypoint del contenedor (opcional)
  • env: Variables de entorno (opcional, admite expansión de ${VAR})
  • volumes: Montajes de volúmenes como asignaciones de host:container (opcional, admite expansión de ${VAR})
  • network: Red Docker a la que conectarse (opcional)
  • timeout: Tiempo de espera de solicitud en segundos (opcional, por defecto: 30)

Beneficios del Transporte Docker:

  • No es necesario instalar Node.js, Python u otros runtimes en el host del hub
  • Dependencias aisladas por servidor MCP
  • Gestión de versiones fácil con etiquetas Docker
  • Entorno consistente en todos los despliegues

Compilación de Imágenes Docker para Servidores MCP

Puedes contenerizar cualquier servidor MCP para evitar instalar sus dependencias en el host del hub.

Ejemplo: Dockerizando un Servidor MCP Python

Dockerfile:

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"]

Compilar y usar:

# Build the image
docker build -t my-mcp-server:latest .

# Add to config.json
{
  "mcpServers": {
    "my-server": {
      "image": "my-mcp-server:latest"
    }
  }
}

Ejemplo: Dockerizando un Servidor MCP Node.js

Dockerfile:

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"]

Notas Importantes para Servidores MCP Docker

  1. Usa el flag -i: El hub ejecuta contenedores con docker run -i para stdin/stdout interactivo
  2. Salida sin buffer: Asegúrate de que las salidas de tu servidor no tengan buffer (usa python -u o flush())
  3. Solo stdin/stdout: El protocolo MCP usa stdin para entrada y stdout para salida
  4. stderr para registros: Usa stderr para registro (visible en los registros del hub)
  5. Limpieza: Los contenedores se ejecutan con --rm para limpieza automática

Imágenes de Servidores MCP Precompiladas

Crea un registro de imágenes Docker para servidores MCP comunes:

# 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 .

Luego úsalo:

{
  "mcpServers": {
    "echo": {
      "image": "mcp-echo:latest"
    }
  }
}

Comparación de Transportes

TransporteCaso de UsoVentajasDesventajas
stdioServidores MCP locales con acceso directoRápido, baja sobrecargaRequiere runtime (Node.js/Python) instalado
DockerServidores MCP aislados y reproduciblesSin dependencias de runtime, versionado fácilSobrecarga ligeramente mayor, requiere Docker
HTTPServidores MCP remotos/alojados en la nubeEscalable, puede equilibrarse la cargaLatencia de red, requiere infraestructura de servidor

Cuándo Usar Transporte Docker

Elige transporte Docker cuando:

  • ✅ Quieras evitar instalar Node.js, Python u otros runtimes en tu host del hub
  • ✅ Necesites entornos consistentes y reproducibles en todos los despliegues
  • ✅ Quieras gestión de versiones fácil con etiquetas Docker
  • ✅ Estés ejecutando el hub en un entorno contenerizado (Kubernetes, Docker Compose)
  • ✅ Necesites aislar dependencias de servidores
  • ✅ Quieras usar imágenes de servidores MCP precompiladas de un registro

Elige transporte stdio cuando:

  • ✅ Estés desarrollando localmente y quieras iteración más rápida
  • ✅ Las dependencias de runtime ya estén instaladas
  • ✅ Necesites la latencia más baja posible

Elige transporte HTTP cuando:

  • ✅ Los servidores MCP estén alojados remotamente
  • ✅ Necesites escalar servidores de forma independiente
  • ✅ Quieras usar servicios de servidores MCP gestionados

Ejemplo: Configuración Docker Completa

Aquí hay un ejemplo completo ejecutando múltiples servidores MCP en 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

Esta configuración te ofrece:

  • ✨ Sin dependencias de runtime en el host del hub
  • ✨ Entornos aislados para cada servidor MCP
  • ✨ Actualizaciones fáciles cambiando etiquetas de imágenes Docker
  • ✨ Despliegues reproducibles

Despliegue Contenerizado

El propio mcp-hub puede ejecutarse en un contenedor Docker. Consulta DOCKER_DEPLOYMENT.md para la guía de despliegue completa.

Despliegue Docker Rápido

# 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

O usa Docker Compose

docker-compose up -d

Tamaños de Imagen:

  • Estándar (con CLI de Docker): ~47MB
  • Mínima (solo stdio/HTTP): ~6MB

Las variables de entorno se pasan automáticamente y se expanden en tu configuración.

Vigilancia del Archivo de Configuración

El MCP Hub vigila automáticamente el archivo de configuración para detectar cambios y actualiza el registro en consecuencia. Cuando modificas config.json, el hub:

  • Agrega nuevos servidores: Inicia automáticamente cualquier servidor MCP recién agregado
  • Elimina servidores: Detiene servidores que se eliminan de la configuración o se deshabilitan
  • Recarga servidores: Reinicia servidores cuya configuración ha cambiado
  • Actualiza el registro: Mantiene el registro de herramientas sincronizado con los servidores activos

Cómo Funciona

El vigilante usa fsnotify para monitorear el archivo de configuración en busca de eventos de escritura. Cuando se detectan cambios:

  1. Se carga y valida la nueva configuración
  2. Se comparan los cambios con la configuración anterior
  3. Se toman las acciones apropiadas (iniciar/detener/recargar servidores)
  4. El registro se actualiza automáticamente
  5. Los cambios se registran para visibilidad

Debounce

Para evitar procesar cambios rápidos sucesivos (por ejemplo, cuando los editores escriben múltiples veces), el vigilante incluye un retraso de debounce de 500ms. Esto asegura que la configuración solo se recargue una vez después de que termines de editar.

Ejemplo

# 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)"

Manejo de Errores

Si la nueva configuración contiene errores:

  • JSON inválido: Los cambios se rechazan, el hub continúa con la configuración anterior
  • Campos requeridos faltantes: Los cambios se rechazan con error de validación
  • Fallos de inicio de servidores: Se registran como advertencias, otros servidores continúan ejecutándose