Skip to main content
Glama

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

メリット

メリット

効果

🔒 フェイルクローズのガードレール

block が優先されます。未知のツールは既定で拒否されます。可視性と呼び出し可能性は同期が保たれます。

📉 トークン節約

フィルタリングされた tools/list により、プロンプトが小さくなり、より安価で焦点を絞ったセッションになります。

👥 1つの設定で複数のエージェント

レビュアー、実装者、CIボットは同じ servers ブロックを共有しつつ、--profile で異なるプロファイルを取得します。

🧩 マルチサーバー集約

複数の上流サーバー(stdio + HTTP)を単一のMCPエンドポイントの背後に統合します。

🔐 シークレットをリポジトリ外に保持

${VAR} プレースホルダーと .env を使用。ローダーは変数が欠けていると即座に失敗します。

♻️ 耐障害性

指数バックオフによる自動再接続。ライブの tools/list_changed 更新は再フィルタリングされて下流に伝播します。

🛡️ 引数検証

tools/call の引数は転送前に上流の inputSchema に対して検証されます。

📊 可観測性

--verbose はリクエストごとの相関IDを持つ構造化JSON-linesログを出力します。共有サーバーは Prometheus /metrics も公開します。

🌐 共有サーバーモード

serve は多数のエージェント向けに1つの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)です。プロファイルに含まれないサーバーは、そのツールを一切公開しません。


例: 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 ハンドシェイクで測定した結果:

プロファイル

公開ツール数

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 (すべてブロック): (なし)

注目すべき2つの詳細:

  • 衝突時の自動プレフィックス付与read_file は両方のサーバーに存在するため、filesystem__read_filegithub__read_file になります。一方 write_file/edit_filefilesystem でブロックされるため素の名前のままとなり、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 モード)

プロキシを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)

エンドポイント:

パス

用途

/mcp

Streamable HTTP MCPエンドポイント(接続ごとにセッション)

/health

死活監視 — プロセスが起動していれば常に 200

/ready

準備完了 — すべてのプロファイルの上流サーバーが接続されている場合のみ 200

/metrics

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.mdcontext/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/listtools/call エントリにはMCPリクエストの correlationId が含まれるため、単一のリクエストをプロキシとその上流サーバーにわたって追跡できます。

プロファイルのコンテキストコストを確認するには、プロファイル間でツール数と tools/list ペイロードサイズを比較してください(前述の実測例を参照)。宣伝されるツールが少ないほど、毎ターンプロンプトに注入されるスキーマが少なくなります。

serve モードでは、Prometheusのカウンター、ゲージ、ヒストグラムを取得するために /metrics をスクレイプします: mcp_proxy_tools_listed_totalmcp_proxy_tools_called_totalmcp_proxy_tools_blocked_totalmcp_proxy_tool_call_duration_secondsmcp_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 — 環境変数テンプレート。

Maintenance

ActivityMaintained
ResponsivenessSyncing

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

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Self-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.
    16
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Centralized MCP control plane that proxies multiple upstream MCP servers with tool namespacing, filtering, policy enforcement, audit logging, and health checks.
    16
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    An 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
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables 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

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