mcp-proxy
mcp-proxy
1つ以上の上流MCPサーバーの前に配置され、指定されたプロファイルが参照・呼び出しを許可されたツールのみを公開する、堅牢化MCPプロキシです。
1つの設定ファイルに実際のサーバー(GitHub、filesystem、Slack、…)とプロファイル(reviewer、implementer、ci-bot、…)を記述します。各エージェントは --profile <name> を付けてプロキシのコピーを起動するか、serve モードでは単一の共有HTTPサーバーが各接続を認証経由でプロファイルにマッピングし、それらのサーバーのフィルタリング済みかつ強制適用されたビューを取得します。これによりコンテキストトークンを節約し、危険なツール呼び出しを構造的に防ぎます。
mcp-proxy を使う理由
公式MCPサーバーはすべてのツールをすべてのエージェントに公開します。クライアントは tools/list を取得し、毎回のターンですべてのツールのスキーマをプロンプトに注入するため、コンテキストトークンを消費します。また、表示されているツールは呼び出せるツールであり、そこに厳格な境界はありません。
mcp-proxy は両方の問題を同時に解決します:
トークン節約 — プロファイルは明示的に許可したツールだけを宣伝するため、そのスキーマだけがエージェントのコンテキストに入ります。
厳格なガードレール — 許可されていないツールは一覧表示も呼び出しもされません。幻覚による呼び出しでさえ、メニューから隠すだけでなく実行時に拒否されます。
Related MCP server: Mavryn
メリット
メリット | 効果 |
🔒 フェイルクローズのガードレール |
|
📉 トークン節約 | フィルタリングされた |
👥 1つの設定で複数のエージェント | レビュアー、実装者、CIボットは同じ |
🧩 マルチサーバー集約 | 複数の上流サーバー(stdio + HTTP)を単一のMCPエンドポイントの背後に統合します。 |
🔐 シークレットをリポジトリ外に保持 |
|
♻️ 耐障害性 | 指数バックオフによる自動再接続。ライブの |
🛡️ 引数検証 |
|
📊 可観測性 |
|
🌐 共有サーバーモード |
|
🏷️ 衝突安全 | サーバー間で名前が重複するツールは自動的にプレフィックスが付き( |
動作の仕組み
アーキテクチャ
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)です。プロファイルに含まれないサーバーは、そのツールを一切公開しません。
例: 3つのプロファイルの実測
同じプロキシを3つのプロファイルで実行し、実際の @modelcontextprotocol/server-filesystem 上流サーバー(14ツール)に対して実行しました。デモではトークンが不要なように、2つ目の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(すべてブロック): (なし)
注目すべき2つの詳細:
衝突時の自動プレフィックス付与 —
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 モード)
プロキシを1つのプロセスから多くのエージェントにサービスを提供する共有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 を実行して多くのエージェントが共有する1つのStreamable HTTPサーバーを公開します。各接続は認証ヘッダーからプロファイルにマッピングされます:
node dist/cli/index.js serve --config mcp-proxy.yaml
# options: --host, --port (override http.host/http.port)エンドポイント:
パス | 用途 |
| Streamable HTTP MCPエンドポイント(接続ごとにセッション) |
| 死活監視 — プロセスが起動していれば常に |
| 準備完了 — すべてのプロファイルの上流サーバーが接続されている場合のみ |
| Prometheusテキストメトリクス(ツールの一覧表示/呼び出し/ブロック、レイテンシ、上流状態) |
接続ごとのプロファイル解決はフェイルクローズです。使用可能なセレクターがない接続は、http.auth.defaultProfile が設定されていない限り (401 で) 拒否され、未知のプロファイルにマッピングされるセレクターは (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 を付けて実行すると、構造化されたJSON-linesログが stderr に出力されます(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 モードでは、Prometheusのカウンター、ゲージ、ヒストグラムを取得するために /metrics をスクレイプします: 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 → 最大15秒、無限リトライ)で再接続します。
ライブツール更新 — 上流サーバーが
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