mcp-proxy
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: Mavryn
优势
优势 | 帮助方式 |
🔒 故障关闭护栏 |
|
📉 令牌节省 | 过滤后的 |
👥 一个配置,多个代理 | Reviewer、implementer 和 CI bot 共享相同的 |
🧩 多服务器聚合 | 在单个 MCP 端点后面合并多个上游(stdio + HTTP)。 |
🔐 密钥不进入仓库 |
|
♻️ 弹性 | 自动重连,指数退避;实时 |
🛡️ 参数验证 |
|
📊 可观测性 |
|
🌐 共享服务器模式 |
|
🏷️ 冲突安全 | 跨服务器共享名称的工具自动加前缀( |
工作原理
架构
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" --> DENYblock 始终优先。模式是通配符(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 握手中测量:
配置文件 | 暴露的工具 |
| ~令牌 |
| 5 | 2,926 字符 | ~732 |
| 26 | 15,762 字符 | ~3,941 |
| 0 | 2 字符 | ~1 |
令牌使用 ~4 字符/令牌的启发式方法;真正的节省是代理每轮重新加载到上下文中的模式表面。
每个配置文件实际收到的工具:
reviewer(只读,GitHub 被阻止):read_file、list_directory、directory_tree、search_files、get_file_infoimplementer(拒绝列表,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_filenoTools(所有内容被阻止):(无)
两个值得注意的细节:
冲突自动加前缀 ——
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 tokens3. 编写 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: reviewer4. 运行
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 namespacehttp(Streamable HTTP):
github:
type: http
url: https://api.github.com/mcp
headers:
Authorization: "${GITHUB_TOKEN}"
prefix: gh__ # optionalprofiles —— 命名工具视图
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 exposedhttp —— 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)端点:
路径 | 用途 |
| Streamable HTTP MCP 端点(每个连接一个会话) |
| 存活——进程启动后始终 |
| 就绪——仅当每个配置文件的上游都连接时返回 |
| 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/更多
context/DESIGN.md —— 完整设计、决策和权衡。
context/SETUP.md —— 真实 stdio + HTTP 服务器的逐步设置。
context/ROADMAP.md —— v1.0 已发布(HTTP 下游、每连接配置文件、可观测性、打包)。
mcp-proxy.yaml—— 工作示例配置。.env.example—— 环境变量模板。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
MCP Gateway: wrap any MCP server with cold-start retries, uptime SLA, and per-execution MPP billing.
Remote MCP server exposing SMI Aware tools, resources, and skills over Streamable HTTP.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceSelf-hosted MCP proxy and aggregation platform. Register multiple upstream MCP servers and expose them through a single unified endpoint with namespace routing, multi-transport support (HTTP/SSE, stdio, OpenAPI→MCP), per-tool overrides, and a web admin UI.16MIT
- AlicenseNot gradedqualityBmaintenanceCentralized MCP control plane that proxies multiple upstream MCP servers with tool namespacing, filtering, policy enforcement, audit logging, and health checks.16MIT
- AlicenseNot gradedqualityAmaintenanceAn authorizing reverse proxy for MCP servers that enforces per-call policy rules on tool arguments with audit logging, dry-run, and rate limiting.Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables serving multiple MCP toolkits behind one server with capability-based access control, so different callers see and can call only the tools they are authorized for, over stdio or streamable HTTP with bearer-token auth.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/DawidNowak/mcp-proxy'
If you have feedback or need assistance with the MCP directory API, please join our Discord server