Skip to main content
Glama

mcp-proxy

一个加固型 MCP 代理,位于一个或多个上游 MCP 服务器之前,只暴露给定配置文件允许查看和调用的工具。

一个配置文件描述你的真实服务器(GitHub、filesystem、Slack 等)以及配置文件(reviewer、implementer、ci-bot 等)。每个代理使用 --profile <name> 启动自己的代理副本——或者,在 serve 模式下,一个共享的 HTTP 服务器通过认证将每个连接映射到配置文件——并获得这些服务器的过滤后、强制执行的视图,从而节省上下文令牌并从构造上防止危险的工具调用。


为什么使用 mcp-proxy?

官方 MCP 服务器将所有工具暴露给每个代理。客户端获取 tools/list 并将每个工具的模式注入到提示中,在每一轮都如此,消耗上下文令牌。而且,可见的工具就是可调用的工具——没有硬性边界。

mcp-proxy 一次性解决这两个问题:

  • 令牌节省 —— 配置文件只宣传你明确允许的工具,因此只有这些模式会进入代理的上下文。

  • 硬性护栏 —— 不允许的工具既不会被列出,也不会被调用:即使是幻觉调用也会在执行时被拒绝,而不仅仅是从菜单中隐藏。


Related MCP server: sovereign-mcp-gateway

优势

优势

帮助方式

🔒 故障关闭护栏

block 优先;未知工具默认拒绝。可见性和可调用性保持同步。

📉 令牌节省

过滤后的 tools/list 意味着更小的提示和更便宜、更专注的会话。

👥 一个配置,多个代理

Reviewer、implementer 和 CI bot 共享相同的 servers 块,但通过 --profile 获得不同的配置文件。

🧩 多服务器聚合

在单个 MCP 端点后面合并多个上游(stdio + HTTP)。

🔐 密钥不进入仓库

${VAR} 占位符 + .env;加载器在缺少变量时快速失败。

♻️ 弹性

自动重连,指数退避;实时 tools/list_changed 更新被重新过滤并传播到下游。

🛡️ 参数验证

tools/call 参数在转发前根据上游 inputSchema 进行验证。

📊 可观测性

--verbose 输出结构化 JSON 行日志,带有每个请求的相关性 ID;共享服务器还暴露 Prometheus /metrics。

🌐 共享服务器模式

serve 运行一个 Streamable HTTP 服务器供多个代理使用;每个连接的认证将令牌/头映射到配置文件。

🏷️ 冲突安全

跨服务器共享名称的工具自动加前缀(github__read_file),其他工具保留裸名称。


工作原理

架构

flowchart TB
    subgraph agents["🤖 Agents (MCP clients)"]
        direction LR
        A1["reviewer agent<br/><code>--profile reviewer</code>"]
        A2["implementer agent<br/><code>--profile implementer</code>"]
    end

    subgraph proxy["mcp-proxy — one stdio process per agent"]
        direction TB
        D1["stdio transport"]
        D2["tool filter<br/>(allow/block · globs + regex)"]
        D3["call-time guardrail<br/>+ argument validation"]
        D4["upstream registry<br/>(discovery · reconnect · list_changed)"]
    end

    subgraph up["Upstream MCP servers"]
        direction LR
        U1["filesystem<br/>(stdio)"]
        U2["github<br/>(HTTP)"]
        U3["slack<br/>(HTTP)"]
    end

    A1 -->|"stdin/stdout"| D1
    A2 -->|"stdin/stdout"| D1
    D1 --> D2 --> D3 --> D4
    D4 -->|"spawn"| U1
    D4 -->|"connect"| U2
    D4 -->|"connect"| U3

每个代理将代理作为子进程通过 stdio 生成。代理连接到所选配置文件中列出的每个上游,获取每个 tools/list,应用配置文件的允许/阻止规则,并仅重新暴露存活的工具。

请求流程

sequenceDiagram
    autonumber
    participant A as Agent
    participant P as mcp-proxy
    participant U as Upstream MCP server

    A->>P: tools/list
    P->>U: tools/list (every upstream in profile)
    U-->>P: full tool set
    P->>P: filter + collision resolve
    P-->>A: allowed tools only

    A->>P: tools/call (allowed tool)
    P->>P: guardrail re-check<br/>+ schema validation
    P->>U: forward call
    U-->>P: result
    P-->>A: result

    A->>P: tools/call (blocked tool)
    P-->>A: ❌ rejected with error

    U-->>P: notifications/tools/list_changed
    P->>U: re-fetch tools/list
    P->>P: re-filter
    P-->>A: notifications/tools/list_changed

过滤决策

只有当工具通过以下优先级链时,它才被允许:

flowchart LR
    T["tool name"] --> B{"matches a<br/><code>block</code> pattern?"}
    B -- "yes" --> DENY["🔒 DENY"]
    B -- "no" --> A{"matches an<br/><code>allow</code> pattern?"}
    A -- "yes" --> OK["✅ ALLOW"]
    A -- "no" --> D["fallback:<br/>server <code>default</code><br/>→ profile <code>default</code><br/>→ <code>block</code>"]
    D --> F{"fallback is <code>allow</code>?"}
    F -- "yes" --> OK
    F -- "no" --> DENY

block 始终优先。模式是通配符(read_*、{get,list}_*)或正则表达式(/.*delete.*/i)。配置文件中省略的服务器不会暴露其任何工具。


示例:三个配置文件,实时测量

同一个代理通过三个配置文件驱动,针对真实的 @modelcontextprotocol/server-filesystem 上游(14 个工具)运行。第二个 filesystem 实例代替 HTTP GitHub 服务器,因此演示不需要令牌——每个服务器的过滤行为对任何上游都是相同的。

# mcp-proxy.yaml (demo)
version: 1
servers:
  filesystem:
    type: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/data"]
  github:                     # HTTP in real life; filesystem stand-in in this demo
    type: http
    url: https://api.github.com/mcp
    headers: { Authorization: "${GITHUB_TOKEN}" }

profiles:
  reviewer:
    default: block
    servers:
      filesystem:
        allow: ["read_file", "list_directory", "search_files", "directory_tree", "get_file_info"]
      github:
        block: ["**"]          # GitHub fully disabled for this agent

  implementer:
    default: allow
    servers:
      filesystem:
        block: ["/.*delete.*/i", "remove_*", "edit_file", "write_file"]
      github: {}               # all GitHub tools allowed

  noTools:
    default: block
    servers:
      filesystem: { block: ["**"] }
      github: { block: ["**"] }

在实时 tools/list 握手中测量:

配置文件

暴露的工具

tools/list 负载

~令牌

reviewer

5

2,926 字符

~732

implementer

26

15,762 字符

~3,941

noTools

0

2 字符

~1

令牌使用 ~4 字符/令牌的启发式方法;真正的节省是代理每轮重新加载到上下文中的模式表面。

每个配置文件实际收到的工具:

  • reviewer(只读,GitHub 被阻止): read_file、list_directory、directory_tree、search_files、get_file_info

  • implementer(拒绝列表,GitHub 允许): filesystem__read_file、github__read_file、filesystem__read_text_file、github__read_text_file、 filesystem__read_media_file、github__read_media_file、filesystem__read_multiple_files、github__read_multiple_files、 filesystem__create_directory、github__create_directory、filesystem__list_directory、github__list_directory、 filesystem__list_directory_with_sizes、github__list_directory_with_sizes、filesystem__directory_tree、github__directory_tree、 filesystem__move_file、github__move_file、filesystem__search_files、github__search_files、 filesystem__get_file_info、github__get_file_info、filesystem__list_allowed_directories、github__list_allowed_directories、 write_file、edit_file

  • noTools(所有内容被阻止):(无)

两个值得注意的细节:

  • 冲突自动加前缀 —— read_file 存在于两个服务器上,因此它变成 filesystem__read_file 和 github__read_file。但 write_file/edit_file 保留其裸名称,因为它们在 filesystem 上被阻止,留下 github 作为唯一来源。

  • 空配置文件视图是有效的 —— noTools(或任何带有 block: ["**"] 的配置文件,或省略的服务器)暴露零个工具;代理仍然连接,只是没有可调用的内容。


快速开始

1. 安装并构建

npm install
npm run build          # compiles TypeScript to dist/

2. 将密钥放入 .env(切勿放入配置中)

cp .env.example .env   # then fill in your tokens

3. 编写 mcp-proxy.yaml

version: 1

servers:
  filesystem:
    type: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/repo"]
    env:
      ROOT: "C:/repo"

  github:
    type: http
    url: https://api.github.com/mcp
    headers:
      Authorization: "${GITHUB_TOKEN}"   # env-var reference, not a literal secret

profiles:
  reviewer:                 # read-only, fail-closed
    description: "Read-only agent"
    default: block
    servers:
      filesystem:
        allow: ["read_file", "list_directory", "directory_tree", "get_file_info"]
      github:
        allow: ["get_*", "list_*", "search_*"]

  implementer:              # deny-list, fail-open minus dangerous ops
    description: "Full access minus destructive ops"
    default: allow
    servers:
      filesystem:
        block: ["/.*delete.*/i", "edit_file", "write_file"]
      github:
        block: ["merge_pull_request", "delete_*"]

defaultProfile: reviewer

4. 运行

node dist/cli/index.js --profile reviewer
# add --verbose for structured debug logging
node dist/cli/index.js --profile reviewer --verbose

配置文件优先级:--profile > MCP_PROFILE > defaultProfile。


配置参考

servers —— 上游 MCP 服务器

stdio(作为子进程生成):

filesystem:
  type: stdio
  command: npx
  args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/repo"]
  env: { ROOT: "C:/repo" }
  prefix: fs__          # optional: override collision-prefix namespace

http(Streamable HTTP):

github:
  type: http
  url: https://api.github.com/mcp
  headers:
    Authorization: "${GITHUB_TOKEN}"
  prefix: gh__          # optional

profiles —— 命名工具视图

profiles:
  my-profile:
    description: "..."           # optional
    default: allow               # allow | block (fallback when no rule matches)
    servers:
      github:
        allow: ["get_*"]         # optional allow-list
        block: ["delete_*"]      # optional block-list (always wins)
        default: block           # optional per-server fallback override
      # filesystem omitted → none of its tools are exposed

http —— Streamable HTTP 下游(serve 模式)

可选的顶级块,将代理变成共享 HTTP 服务器,从一个进程服务多个代理。请参阅 共享服务器(HTTP)。

http:
  host: 0.0.0.0             # default 127.0.0.1
  port: 3000                # default 3000
  path: /mcp                # MCP endpoint (default /mcp)
  metricsPath: /metrics     # Prometheus metrics (default /metrics)
  healthPath: /health       # liveness (default /health)
  readyPath: /ready         # readiness (default /ready)
  auth:
    header: authorization   # selector header (default authorization)
    scheme: Bearer          # optional prefix to strip
    tokens:                 # token -> profile map (values may use ${VAR})
      tok-reviewer: reviewer
      tok-impl: implementer
    defaultProfile: reviewer # optional fallback (fail-closed without it)

当设置了 tokens 时,去除方案后的头值在映射中查找。没有 tokens 时,去除方案后的头值直接用作配置文件名称。缺失/未知的选择器回退到 defaultProfile,如果没有适用则被拒绝(401/403)。

密钥

${VAR} 占位符在加载时从环境(或 .env)解析。YAML 只保存变量名称,因此提交是安全的。缺少变量会使加载器快速失败——不会出现静默空头。


连接到你的代理

代理就是一个通过 stdio 的 MCP 服务器。将你的代理指向代理入口点,而不是真实服务器,并传递配置文件标志。

// .mcp.json — reviewer agent
{
  "mcpServers": {
    "proxy": {
      "command": "node",
      "args": ["C:/Dev/mcp-proxy/dist/cli/index.js", "--profile", "reviewer"]
    }
  }
}
// .mcp.json — implementer agent (same proxy, different profile)
{
  "mcpServers": {
    "proxy": {
      "command": "node",
      "args": ["C:/Dev/mcp-proxy/dist/cli/index.js", "--profile", "implementer"]
    }
  }
}

每个代理都有自己的 stdio 进程,因此配置文件在每个代理之间完全隔离,凭据永远不会跨进程边界。

共享服务器(HTTP)

对于集中部署,运行 serve 以暴露一个 Streamable HTTP 服务器,供多个代理共享。每个连接根据其认证头映射到配置文件:

node dist/cli/index.js serve --config mcp-proxy.yaml
# options: --host, --port (override http.host/http.port)

端点:

路径

用途

/mcp

Streamable HTTP MCP 端点(每个连接一个会话)

/health

存活——进程启动后始终 200

/ready

就绪——仅当每个配置文件的上游都连接时返回 200

/metrics

Prometheus 文本指标(列出的/调用的/阻止的工具、延迟、上游状态)

每个连接的配置文件解析是故障关闭的:没有可用选择器的连接被拒绝(401),除非设置了 http.auth.defaultProfile,并且映射到未知配置文件的选择器被拒绝(403)。

共享部署的客户端配置(任何支持 Streamable-HTTP 的客户端):

// .mcp.json — reviewer agent (token maps to the `reviewer` profile)
{
  "mcpServers": {
    "proxy": {
      "type": "http",
      "url": "https://proxy.example.com/mcp",
      "headers": { "Authorization": "Bearer ${PROXY_TOKEN}" }
    }
  }
}
// .mcp.json — implementer agent (same server, different token/profile)
{
  "mcpServers": {
    "proxy": {
      "type": "http",
      "url": "https://proxy.example.com/mcp",
      "headers": { "Authorization": "Bearer ${PROXY_TOKEN_IMPL}" }
    }
  }
}

Copilot 编码代理读取仓库的 .mcp.json;对于其他代理,使用其原生 MCP 服务器字段(请参阅 context/AGENT-SETUP.md 和 context/VENDOR-AGENTS.md)。


可观测性

使用 --verbose 运行以向 stderr 输出结构化 JSON 行日志(保持 MCP stdio 通道在 stdout 上干净):

{"timestamp":"2026-08-23T17:22:26.976Z","level":"info","message":"connected to upstream","server":"filesystem","tools":14}
{"timestamp":"2026-08-23T17:22:26.980Z","level":"debug","message":"tools/call","correlationId":"42","tool":"read_file","server":"filesystem"}

每个 tools/list 和 tools/call 条目都携带 MCP 请求的 correlationId,因此可以在代理及其上游之间跟踪单个请求。

要查看配置文件的上下文成本,请比较不同配置文件之间的工具数量和 tools/list 负载大小(请参阅上面的测量示例):宣传的工具越少,意味着每轮注入到提示中的模式越少。

在 serve 模式下,抓取 /metrics 获取 Prometheus 计数器、仪表和直方图:mcp_proxy_tools_listed_total、mcp_proxy_tools_called_total、mcp_proxy_tools_blocked_total、mcp_proxy_tool_call_duration_seconds 和 mcp_proxy_upstream_connections(全部按 profile/server/tool 标记)。


弹性

  • 自动重连 —— 如果上游(尤其是生成的 stdio 进程)死亡,代理以指数退避重连(500ms → 15s 上限,无限重试)。

  • 实时工具更新 —— 当上游发出 notifications/tools/list_changed 时,代理重新获取、重新过滤并将更改转发到下游,因此代理始终看到准确的工具列表。

  • 参数验证 —— tools/call 参数在转发前根据上游的 inputSchema 进行检查;无效调用在本地被拒绝。


开发

npm run typecheck    # tsc --noEmit
npm test             # vitest (unit + integration + filesystem smoke)
npm run build        # tsc → dist/

更多

Maintenance

ActivityStale
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • 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.
    6 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides a governance proxy layer for MCP servers, enforcing per-tool allowlists, human approval for write operations, quotas, secret redaction, and a hash-chained audit log of all calls.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Fronts many downstream MCP servers through one session, presenting a unified tool namespace with collision resolution, fleet-wide allow/deny/hide policy, per-tool rate limits, centralized audit logging, Prometheus metrics, and bearer-key auth at the edge. Supports both stdio drop-in and Streamable HTTP deployment so agents point at a single endpoint instead of N servers.
    MIT