Сервис с MCP-функционалом — сам себе MCP-сервер; доступ — через персональные ключи сервиса (не access-токены gnexus-auth), каждый ключ принадлежит пользователю сервиса. Канон = реализация Gnexus Synapse (docs/07-mcp.md, app/mcp/server.py, страница /mcp-keys); авторизация на тулах — снейпшот роли владельца, вместо набора scopes.
/mcp-protocol/, слэш в конце значим — реверс-прокси не буферизует и не переписывает тело). Legacy HTTP/SSE-адаптер — только для клиентов без streamable HTTP. stdio не используется: агент и сервис на разных хостах.Authorization (у Synapse: персональный mcp_…; исторический /mcp — alias к /mcp-protocol/)./mcp-keys): имя ключа («агент Navi rei»), plaintext показывается ровно один раз при создании, в БД — только sha256-хэш (уникальный) и хвост-хинт (последние символы — опознание ключа в списке).system_role в строке токена): роль admin+ — весь каталог тулов, роль user — только личный набор («me, свои списки»); админ-тул для user-ключа отвечает {"error": 403, "detail": …}. Смена роли на gnexus-auth не дотягивается до выпущенного ключа — старый отзывают, выпускают заново.revoked_at); списки показывают и отозванные (с хвост-хинтом), plaintext никогда не возвращается.user.blocked/deleted/ archived → локальный флаг) гасит все его личные ключи: гард отвечает тем же 401, что и при неверном токене — не раскрывать статус блокировки. SSO-логаут MCP-токены не трогает — это самостоятельные креды (у Synapse так сделано потому, что SSO-сервер не отзывает выданные сервисом ключи).Authorization: Bearer на каждом запросе (хэш-lookup), 401 + www-authenticate: Bearer при промахе, обновляет last_used_at.{"error": 403|409, "detail": "…"}) — агент читает причину и исправляет.MCP_TOKEN из .env — суперадмин-бэкдор: сохраняет совместимость с существующими сценариями агентов. Опционален (пусто — работают только персональные ключи); держать в .env + gnexus-creds.{
"mcpServers": {
"<сервис>": {
"type": "streamable-http",
"url": "https://<сервис>.gnexus.space/mcp-protocol/",
"headers": { "Authorization": "Bearer mcp_<персональный ключ>" }
}
}
}
Claude Code:
claude mcp add --transport http <сервис> https://<сервис>.gnexus.space/mcp-protocol/ \ --header "Authorization: Bearer mcp_<персональный ключ>"
mcp_tokens)user_id (sub gnexus-auth владельца — ключ выпускает сам себе), name (человекочитаемое назначение), user_email (снейпшот для списков), system_role (снейпшот роли выпуска), token_hash (sha256, unique), token_hint (хвост), created_at, last_used_at, revoked_at.
docs/07-mcp.md (архитектура гейта и каталог тулов), app/mcp/server.py (McpTokenGuard), страница /mcp-keys, resolve_personal_token; таблица mcp_tokens (docs/04-database.md).gnexus_creds/mcp*.py, страница Tokens): те же принципы хранения, но вместо снейпшота роли — scopes (read/reveal/write): приемлемая альтернатива там, где нужны градации внутри одного класса доступа.mcp_* (страница «MCP-ключи»)
.env. Особенности: каталог тулов у всех ключей единый (данные панели общие); тулы — чтение плюс управление серверами/сервисами, запись открыта всем валидным ключам (модель доступа панели «любая сессия = админ»), запись лимитирована, ошибки — как данные. Снейпшот роли записывается в токен, но тулов «только для админа» нет: FastMCP 1.x не пробрасывает HTTP-контекст в тулы, поэтому роль владельца внутри тула не видна.