Skip to main content
Glama

mcpstead

CI npm version Crates.io License

MCP 网关

一个下游 /mcp 端点,作为多个上游 MCP 服务器的前端。提供持久的上游连接及重连机制、带限定名称的工具注册、根据客户端 Accept 头返回 JSON 或 SSE 响应、针对每个上游的身份验证以及 Prometheus 指标。

安装

# npm (macOS, Linux, WSL)
npm i -g @ahkohd/mcpstead

# homebrew (macOS, Linux)
brew install ahkohd/tap/mcpstead

# cargo
cargo install mcpstead --locked --force

# verify
mcpstead --version

Related MCP server: Mavryn

快速开始

# 1. write a config
mkdir -p ~/.config/mcpstead
cat > ~/.config/mcpstead/config.yaml <<'EOF'
host: 0.0.0.0
port: 8766

mcp:
  auth:
    mode: none

servers:
  - name: example
    url: http://127.0.0.1:3000/mcp
    protocol: streamable
    auth: none
EOF

# 2. run
mcpstead --config ~/.config/mcpstead/config.yaml

然后将任何 MCP 客户端指向 http://127.0.0.1:8766/mcp

Docker

docker build -t mcpstead .
docker run --rm \
  -p 8766:8766 \
  -v "$PWD/config:/etc/mcpstead:ro" \
  mcpstead

Dockerfile 从 crates.io 进行安装。

HTTP API

方法

路径

用途

POST

/mcp

基于 HTTP JSON-RPC 的 MCP

GET

/mcp

返回 405

DELETE

/mcp

终止下游会话

GET

/health

上游状态、工具计数、最后可见时间、重连次数

GET

/metrics

Prometheus 文本格式

POST

/-/reload

无需重启即可重新加载配置

MCP 客户端设置

本地,无认证:

mcpstead:
  url: http://127.0.0.1:8766/mcp
  tools:
    resources: false
    prompts: false

Bearer 认证:

mcpstead:
  url: http://127.0.0.1:8766/mcp
  headers:
    Authorization: Bearer ${MCPSTEAD_BEARER_TOKEN}
  tools:
    resources: false
    prompts: false

工具以限定名称显示 - <server>__<tool> - 因此多个上游可以提供重名的工具而不会发生冲突。

身份验证

下游(客户端到 mcpstead)

默认为无认证:

mcp:
  auth:
    mode: none

Bearer 认证:

mcp:
  auth:
    mode: bearer

令牌来自环境变量:

export MCPSTEAD_BEARER_TOKEN='replace-with-strong-secret'
mcpstead --config ~/.config/mcpstead/config.yaml

客户端发送 Authorization: Bearer <token>。缺少或错误的令牌将返回 401。配置中的 mcp.auth.bearer_token 在启动时会被拒绝。

无论认证模式如何,/health/metrics 始终保持开放 - 以便在不暴露令牌的情况下进行监控。

上游(mcpstead 到 MCP 服务器)

servers 列表中针对每个服务器进行配置。有三种模式:

servers:
  - name: local
    url: http://127.0.0.1:3000/mcp
    auth: none

  - name: workflow
    url: https://workflow.example/mcp-server/http
    auth:
      type: bearer
      token_env: WORKFLOW_TOKEN

  - name: custom
    url: https://api.example/mcp
    headers:
      X-API-Key: '${EXAMPLE_KEY}'

token_env 在启动和配置重新加载时解析指定的环境变量。

配置

使用 --config <path>MCPSTEAD_CONFIG 环境变量设置配置文件路径。

host: 0.0.0.0
port: 8766

mcp:
  auth:
    mode: none           # none | bearer
  session:
    idle_ttl_seconds: 3600
    gc_interval_seconds: 60
    shutdown_grace_seconds: 5

servers:
  - name: local
    url: http://127.0.0.1:3000/mcp
    protocol: streamable # streamable | sse | auto
    required: false      # if true, gateway won't start without this upstream
    auth: none
    reconnect:
      max_attempts: 0    # 0 = infinite
      backoff_base_ms: 1000
      backoff_max_ms: 30000
    tools:
      ttl_seconds: 300
    tls_skip_verify: false
    quirks:
      normalize_sse_events: true
      inject_accept_header: 'application/json, text/event-stream'

metrics:
  enabled: true

logging:
  level: info

热重载

mcpstead 在以下情况下无需重启即可重新加载配置:

  • SIGHUP (systemctl reload mcpsteadkill -HUP <pid>)

  • POST /-/reload (在 bearer 模式下受 bearer 令牌保护)

可热重载的内容:

  • 上游列表

  • 每个上游的认证、请求头、特性(quirks)、重连、工具、URL、协议和 TLS 设置

  • mcp.auth.modeMCPSTEAD_BEARER_TOKEN

  • metrics.enabled

需要重启的内容:

  • host

  • port

  • logging.level

  • mcp.session.*

重载是尽力而为的。错误的配置会被拒绝并忽略;运行中的配置保持不变。检查日志和 mcpstead_config_reloads_total{result="error"} 以查看失败情况。

MCP 会话配置键

  • mcp.session.idle_ttl_seconds - 在此秒数后清除不活跃的会话(默认 3600

  • mcp.session.gc_interval_seconds - 空闲会话 GC 唤醒间隔(默认 60

  • mcp.session.shutdown_grace_seconds - 最大关闭清理时间(默认 5

每个上游的配置键

  • name - 必需,用作工具前缀

  • url - 必需,MCP 端点

  • protocol - streamable | sse | auto(默认 auto

  • required - 如果上游初始化失败则阻止启动(默认 false

  • auth - nonebearer(配合 token_env),或 headers 映射

  • reconnect.max_attempts - 0 = 无限(默认)

  • reconnect.backoff_base_ms / backoff_max_ms - 指数退避边界

  • tools.ttl_seconds - 在此间隔后刷新缓存的 tools/list

  • tls_skip_verify - 禁用此上游的 TLS 证书检查(默认 false,仅用于受信任的本地网络)

  • quirks.normalize_sse_events - 从上游 SSE 响应中剥离 event:

  • quirks.inject_accept_header - 覆盖发送到上游的 Accept 请求头

可观测性

指标

/metrics 暴露 Prometheus 格式的计数器、仪表和直方图。标签基数假设上游和工具的数量较小且有限;工具调用序列由 (server, tool) 键控。

mcpstead_build_info{version="...",rust_version="...",git_sha="..."}
mcpstead_start_time_seconds
mcpstead_uptime_seconds
mcpstead_process_resident_memory_bytes
mcpstead_process_virtual_memory_bytes
mcpstead_process_cpu_seconds_total
mcpstead_process_open_fds
mcpstead_process_max_fds
mcpstead_process_threads
mcpstead_upstream_connected{server="..."}
mcpstead_upstream_tools_count{server="..."}
mcpstead_upstream_reconnects_total{server="..."}
mcpstead_upstream_last_seen_seconds{server="..."}
mcpstead_upstream_initialize_total{server="...",result="success|error"}
mcpstead_upstream_initialize_duration_seconds_bucket{server="...",le="..."}
mcpstead_upstream_health_checks_total{server="...",result="success|failure"}
mcpstead_upstream_reconnect_attempts_total{server="...",result="success|error"}
mcpstead_upstream_backoff_seconds_total{server="..."}
mcpstead_upstream_in_backoff{server="..."}
mcpstead_upstream_current_backoff_seconds{server="..."}
mcpstead_upstream_session_resets_total{server="...",reason="unknown_session|expired|terminated"}
mcpstead_upstream_tools_refresh_total{server="...",result="success|error"}
mcpstead_upstream_tools_refresh_duration_seconds_bucket{server="...",le="..."}
mcpstead_upstream_tools_last_refresh_timestamp_seconds{server="..."}
mcpstead_upstream_bytes_total{server="...",direction="sent|received"}
mcpstead_downstream_sessions_active
mcpstead_downstream_sessions_total
mcpstead_downstream_session_duration_seconds_bucket{le="..."}
mcpstead_downstream_session_terminations_total{reason="..."}
mcpstead_mcp_requests_total{method="...",result="success|error"}
mcpstead_mcp_request_duration_seconds_bucket{method="...",le="..."}
mcpstead_mcp_auth_attempts_total{result="success|failure"}
mcpstead_mcp_auth_failures_total{reason="..."}
mcpstead_config_reloads_total{result="success|error"}
mcpstead_config_last_reload_timestamp_seconds
mcpstead_tool_calls_total{server="...",tool="..."}
mcpstead_tool_call_errors_total{server="...",tool="...",reason="..."}
mcpstead_tool_call_duration_seconds_bucket{server="...",tool="...",le="..."}

抓取配置

- job_name: mcpstead
  metrics_path: /metrics
  static_configs:
    - targets: ['mcpstead:8766']

健康检查

curl http://127.0.0.1:8766/health

返回 JSON:每个上游的连接状态、工具计数、最后成功联系时间、重连次数、最后错误。

故障排除

  • 所有工具列表为空 - 至少有一个上游未能 initialize。检查 /health 获取每个服务器的状态;检查上游 URL、认证和可达性。

  • 零星的 SSE parse failed - 上游发送了 mcpstead 无法识别的 SSE 方言。尝试为该服务器设置 quirks.normalize_sse_events: true,或设置 quirks.inject_accept_header: 'application/json' 以强制使用 JSON。

  • tools/call 返回认证错误 - 上游拒绝了 bearer 令牌。确认 token_env 在启动时解析为正确的值;检查上游预期的请求头名称。

  • 针对自签名上游的 TLS 握手错误 - 在该服务器上设置 tls_skip_verify: true。仅在受信任的本地网络上安全。

  • 在 bearer 模式下从 /mcp 返回 401 - 客户端缺少或发送了错误的 Authorization: Bearer <token>。验证 MCPSTEAD_BEARER_TOKEN 是否与客户端发送的内容匹配。

  • 上游在 /health 中反复变红 - 检查 mcpstead_upstream_reconnects_totalmcpstead_upstream_last_seen_seconds。如果上游需要更长的恢复时间,请调整 reconnect.backoff_max_ms

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A gateway that aggregates multiple MCP servers into a single endpoint, namespacing their tools and forwarding calls, so an agent connects to one MCP to access the entire stack.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Centralized MCP control plane that proxies multiple upstream MCP servers with tool namespacing, filtering, policy enforcement, audit logging, and health checks.
    5 npm
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    A generic MCP gateway that aggregates multiple upstream MCP servers into a single FastMCP endpoint, configured via servers.json with support for tool subsetting, renaming, multi-instance routing, and pluggable authentication.
    -