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: Mavryn

Преимущества

Преимущество

Как помогает

🔒 Защита fail-closed

Правило block имеет приоритет; неизвестные инструменты по умолчанию запрещены. Видимость и возможность вызова синхронизированы.

📉 Экономия токенов

Отфильтрованный tools/list означает более короткие промпты и более дешёвые, сфокусированные сессии.

👥 Один конфиг, много агентов

Reviewer, implementer и CI-бот используют один и тот же блок servers, но получают разные профили через --profile.

🧩 Агрегация нескольких серверов

Объединение нескольких вышестоящих серверов (stdio + HTTP) за одной MCP-конечной точкой.

🔐 Секреты не попадают в репозиторий

Плейсхолдеры ${VAR} + .env; загрузчик быстро завершается с ошибкой при отсутствующей переменной.

♻️ Устойчивость

Автопереподключение с экспоненциальной задержкой; живые обновления tools/list_changed повторно фильтруются и передаются дальше по цепочке.

🛡️ Проверка аргументов

Аргументы tools/call проверяются по inputSchema вышестоящего сервера перед пересылкой.

📊 Наблюдаемость

--verbose выводит структурированные журналы в формате JSON-lines с идентификаторами корреляции на каждый запрос; общий сервер также предоставляет 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 всегда побеждает. Шаблоны — это glob-выражения (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 хранится только имя переменной, поэтому его безопасно коммитить. Отсутствующая переменная заставляет загрузчик быстро завершаться с ошибкой — никаких молча пустых заголовков.


Подключите его к своему агенту

Прокси является MCP-сервером через stdio. Направьте своего агента на точку входа прокси вместо реального сервера, передав флаг профиля.

// .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

Конечная точка MCP Streamable HTTP (сессия на каждое подключение)

/health

Живучесть — всегда 200, как только процесс запущен

/ready

Готовность — 200, только когда все вышестоящие серверы каждого профиля подключены

/metrics

Текстовые метрики Prometheus (перечисленные/вызванные/заблокированные инструменты, задержка, состояние вышестоящих серверов)

Разрешение профиля на каждое подключение работает по принципу fail-closed: подключение без пригодного селектора отклоняется (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, чтобы выводить структурированные журналы 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 несёт correlationId MCP-запроса, поэтому отдельный запрос можно проследить через прокси и его вышестоящие серверы.

Чтобы оценить стоимость профиля в контексте, сравните количество инструментов и размер полезной нагрузки 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-процесс) умирает, прокси переподключается с экспоненциальной задержкой (500 мс → максимум 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