mcp-gateway
MCP Gateway
Лёгкий агрегирующий MCP-шлюз для самостоятельного развёртывания: один публичный MCP-эндпоинт перед любым количеством защищённых внутренних MCP-серверов, а также совместимый со спецификацией OAuth 2.1 сервер авторизации, обращённый к MCP-клиенту, — именно то, чего недостаёт большинству существующих шлюзов.
Claude Code / Claude.ai ──OAuth 2.1 (DCR/CIMD + PKCE)──▶ MCP Gateway ──own credentials──▶ GitHub MCP
│ ▶ Microsoft Learn MCP
└── /mcp (Streamable HTTP) ▶ …more backendsРаботает на FastAPI + FastMCP, настраивается одним YAML-файлом, хранит своё состояние в одной зашифрованной SQLite-базе и распространяется в виде одного небольшого автономного контейнера — обратный прокси не требуется, хотя при желании его можно поставить перед шлюзом для TLS.
Возможности
Клиентская часть (спецификация авторизации MCP, 2025-11-25):
Поток авторизации по коду OAuth 2.1 с обязательным PKCE (S256)
Динамическая регистрация клиента (RFC 7591) на
/register—claude mcp addработает без предварительно согласованных учётных данныхДокументы метаданных идентификатора клиента (CIMD) — HTTPS-URL в качестве идентификаторов клиента, включая аутентификацию клиента
private_key_jwt, публикуются черезclient_id_metadata_document_supported: trueМетаданные сервера авторизации (RFC 8414) + псевдоним обнаружения OIDC
Метаданные защищённого ресурса (RFC 9728); ответы 401 содержат
WWW-Authenticate: Bearer resource_metadata="…", как того требует коннектор ClaudeИндикаторы ресурса (RFC 8707) принимаются и привязываются к выдаваемым токенам
Недолговечные непрозрачные токены доступа, ротация refresh-токенов, одноразовые коды авторизации — всё хранится в виде хешей; записи клиентов зашифрованы при хранении
Loopback-URI перенаправления сопоставляются независимо от порта (CLI Claude Code регистрирует один порт, а авторизуется с другим); для не-loopback URI требуется точная регистрация
Небольшой интерфейс входа и согласия на Svelte 5 (единственная локальная учётная запись из конфигурационного файла)
Бэкендная часть:
none— публичные серверы (например, Microsoft Learn MCP)bearer— подстановка статического токена (Authorization: Bearer …, например, PAT)headers— произвольные статические заголовки (ключи API)oauth— полноценный OAuth-клиент по спецификации MCP: обнаружение метаданных, CIMD, если вышестоящий AS это поддерживает (шлюз размещает собственный документ метаданных клиента), запасной вариант DCR, PKCE, автоматическое обновление токенов. Подключение выполняется однократно через браузер; токены сохраняются в SQLite в зашифрованном виде (Fernet).Токен шлюза, выданный MCP-клиенту, никогда не передаётся на бэкенды (без сквозной передачи токенов, как требует спецификация); бэкенды видят только те учётные данные, которые хранятся в самом шлюзе.
Агрегация:
Инструменты/ресурсы/промпты изолированы по пространству имён каждого бэкенда:
github_create_issue,msdocs_microsoft_docs_search, …Проксирование в реальном времени через Streamable HTTP; недоступный или ещё не подключённый бэкенд просто убирает свои инструменты, а не роняет весь шлюз
Встроенный инструмент
gateway_status
Related MCP server: MCP OAuth Test
Быстрый старт
cp config.example.yaml config.yaml
$EDITOR config.yaml # set public_url, users, backends
cp .env.example .env
$EDITOR .env # set MCP_GATEWAY_ENCRYPTION_KEY (openssl rand -base64 32)
docker compose up -dШлюз работает автономно и слушает порт :8000; docker compose автоматически берёт MCP_GATEWAY_ENCRYPTION_KEY из .env. Разместите его за обратным прокси по своему выбору для TLS или откройте порт напрямую.
Сгенерируйте хеш пароля для конфигурационного файла:
docker compose run --rm mcp-gateway mcp-gateway hash-passwordПодключение Claude Code (CLI)
claude mcp add --transport http gateway https://mcp.example.com/mcpClaude Code обнаруживает сервер авторизации шлюза, регистрируется через DCR (или использует свой CIMD-идентификатор клиента) и открывает ваш браузер: войдите с пользователем из config.yaml, подтвердите согласие — готово. Вставлять токены не нужно.
Подключение Claude.ai / Claude Code web (пользовательский коннектор)
Добавьте https://mcp.example.com/mcp как пользовательский коннектор. Перенаправление браузера на https://claude.ai/api/mcp/auth_callback проходит через тот же поток входа и согласия.
Подключение OAuth-бэкендов
Откройте https://mcp.example.com/ui/backends, войдите и нажмите Подключить рядом с нужным OAuth-бэкендом (например, GitHub MCP). Один раз вас перенаправит на сервер авторизации бэкенда; дальше шлюз автоматически обновляет токены.
Конфигурация
Всё находится в одном YAML-файле (см. config.example.yaml). Значения поддерживают подстановку ${ENV_VAR} / ${ENV_VAR:-default}.
server:
public_url: https://mcp.example.com # behind your reverse proxy
auth:
encryption_key: ${MCP_GATEWAY_ENCRYPTION_KEY} # encrypts secrets at rest
users:
- username: admin
password_hash: "$2b$12$…" # mcp-gateway hash-password
access_token_expiry_seconds: 3600
refresh_token_expiry_seconds: 2592000
storage:
path: /data/gateway.db # SQLite; the only state
backends:
github: # → tools namespaced github_*
url: https://api.githubcopilot.com/mcp/
auth:
type: oauth
# GitHub's authorization server supports neither CIMD nor DCR, so
# register a GitHub OAuth App and provide its credentials directly:
client_id: ${GITHUB_OAUTH_CLIENT_ID}
client_secret: ${GITHUB_OAUTH_CLIENT_SECRET}
microsoft-docs: # → tools namespaced microsoft-docs_*
url: https://learn.microsoft.com/api/mcp
auth: { type: none }
something-with-a-pat:
url: https://example.com/mcp
auth: { type: bearer, token: "${SOME_PAT}" }Добавление бэкенда — это только изменение конфигурации, без правок кода.
Справочник по аутентификации бэкендов
тип | поля | поведение |
| — | учётные данные не отправляются |
|
|
|
|
| статические заголовки (ключи API и т.п.) |
|
| полный OAuth-клиент: CIMD → запасной вариант DCR, PKCE, обновление токенов, зашифрованное хранение |
Для бэкендов oauth шлюз публикует собственный документ метаданных клиента (Client ID Metadata Document) по адресу <public_url>/oauth/client-metadata.json и использует его как идентификатор клиента в тех случаях, когда вышестоящий AS заявляет поддержку CIMD (требуется public_url через HTTPS); в остальных случаях применяется резервный путь через Dynamic Client Registration. Если же вышестоящий AS не поддерживает ни то, ни другое (как, например, GitHub), задайте client_id (и client_secret, если приложение конфиденциально), чтобы использовать предварительно зарегистрированный OAuth-клиент, — тогда CIMD/DCR не используются вовсе.
Логирование
Шлюз пишет логи в stdout/stderr (docker logs, docker compose logs -f), по умолчанию на уровне INFO: запуск/остановка, сводка конфигурации, попытки входа, события авторизации/согласия/выдачи токенов OAuth, подключение/отключение вышестоящих бэкендов и статус подключения. DEBUG добавляет более детальную информацию (конструирование клиентов, ротация токенов, обновление CIMD, обслуживание хранилища). Никакие учётные данные и токены не логируются ни на каком уровне.
Уровень задаётся переменной окружения MCP_GATEWAY_LOG_LEVEL (debug, info, warning, error или critical):
# .env (picked up by docker compose)
MCP_GATEWAY_LOG_LEVEL=debug# or inline
docker compose run --rm -e MCP_GATEWAY_LOG_LEVEL=debug mcp-gatewaydocker-compose.yml уже передаёт эту переменную в контейнер; если она не задана, по умолчанию используется info.
Вне Docker флаг --log-level у команды mcp-gateway run работает так же и приоритетнее переменной окружения:
mcp-gateway run -c config.yaml --log-level debugЭндпоинты
Путь | Назначение |
| MCP-эндпоинт (Streamable HTTP) |
| метаданные защищённого ресурса (RFC 9728) |
| метаданные AS (RFC 8414) + псевдоним OIDC |
| эндпоинты OAuth 2.1 (PKCE, DCR, revoking) |
| вход и согласие (Svelte 5) |
| статус подключения бэкендов / подключение / отключение |
| собственный CIMD-документ шлюза (вышестоящее звено) |
| поток подключения вышестоящего OAuth |
| проверка жизнеспособности |
Замечания по безопасности
PKCE (S256) обязателен; коды авторизации одноразовые и истекают через 5 минут.
Refresh-токены ротируются при каждом использовании (требование OAuth 2.1 для публичных клиентов).
Токены доступа, refresh-токены и коды авторизации хранятся только в виде SHA-256-хешей.
Зарегистрированные клиентские записи и учётные данные вышестоящих серверов зашифрованы при хранении (Fernet): используется
auth.encryption_key, парольные фразы растягиваются через scrypt с солью, уникальной для каждой базы.Экран согласия показывает имя клиента и точный адрес перенаправления, а при loopback- redirect предупреждает (в соответствии с рекомендациями CIMD о защите от подмены localhost).
Токены, выданные MCP-клиентам, никогда не передаются на бэкенды, и учётные данные бэкендов никогда не попадают к MCP-клиентам.
Сессии подписаны (
itsdangerous), сHttpOnly,SameSite=Lax, а на HTTPS — ещё иSecure.Учётные данные не логируются.
Разработка
uv venv && uv pip install -e ".[dev]" # or: pip install -e ".[dev]"
(cd ui && npm install && npm run build) # build the Svelte UI
pytest # 35 tests incl. full e2e OAuth flows
mcp-gateway run -c config.yamlТестовый набор запускает реальные шлюзы (и второй экземпляр в роли защищённого через OAuth вышестоящего сервера) и выполняет полные потоки DCR/CIMD + PKCE через HTTP.
Архитектура
src/mcp_gateway/oauth_server.py— сервер авторизации для клиентской стороны. Строится на обработчиках авторизационного сервера из MCP SDK и на CIMD-менеджере FastMCP, а не на собственной реализации протокола; шлюз добавляет хранение в SQLite, транзакционный поток login/consent и политику выдачи/ротации токенов.src/mcp_gateway/upstream.py— клиенты бэкендов. OAuth-бэкенды используют официальный SDKOAuthClientProvider(discovery, CIMD/DCR, refresh) с зашифрованным хранением токенов в SQLite и процессом подключения через браузер.src/mcp_gateway/gateway.py— FastMCP-сервер; каждый бэкенд монтируется как прокси в реальном времени в своём пространстве имён.src/mcp_gateway/app.py/web.py— FastAPI-приложение: JSON API для UI, callback от вышестоящего сервера, CIMD-документ, статический Svelte; приложение FastMCP (MCP-эндпоинт + OAuth-маршруты + well-known) смонтировано в корне.ui/— SPA на Svelte 5 + Vite (вход, согласие, бэкенды).
Однозначная архитектура по замыслу (SQLite + потоки подключения в памяти). Работает автономно; если нужен TLS, ставьте перед ним свой обратный прокси, а в качестве резервной копии сохраняйте один файл.
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
One MCP endpoint for your company's tools, with per-person sign-in, policy and audit.
Self-hosted federated MCP gateway: one OAuth 2.1 MCP server in front of N apps, user-level scopes.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceAggregates multiple MCP servers behind a single, secure endpoint with unified tool/resource discovery, OAuth authentication, and resilient request routing. Enables users to manage and interact with multiple MCP backends through one centralized interface with load balancing and circuit breakers.2-
- FlicenseNot gradedqualityDmaintenanceMulti-tenant MCP server with OAuth 2.1 authorization, enabling tenant-scoped tool access and audit logging.-
- AlicenseAqualityCmaintenanceA federated MCP gateway that consolidates multiple plain-HTTP backends into a single, OAuth-protected MCP server, enabling agents to access diverse tools through one endpoint with centralized authentication and audit.512MIT
- AlicenseNot gradedqualityDmaintenanceAuthenticating reverse proxy for MCP servers providing credential isolation, OAuth2 token management, and composite tool aggregation.BSD Zero Clause