Схема, применённая в gnexus-creds: сервис — сам MCP-сервер, доступ — через собственные API-токены сервиса (не через access-токены gnexus-auth), каждый токен принадлежит пользователю сервиса.
/mcp-protocol/, слэш в конце значим — реверс-прокси не буферизует и не переписывает тело). Legacy HTTP/SSE-адаптер — только для клиентов без streamable HTTP. stdio не используется: агент и сервис на разных хостах.Authorization.last_used_at. Токен показывается ровно один раз при создании, в БД — только хэш.channel=mcp), а недействительный/заблокированный пользователь gnexus-auth блокирует и его токены (403).| Скоупы | Доступ |
|---|---|
mcp, read |
чтение/поиск метаданных |
mcp, read, reveal |
+ расшифровка секретов |
mcp, read, reveal, write |
полный MCP (создание/обновление) |
read/reveal/write наполняются в контексте конкретного сервиса; без скоупа mcp всё закрыто 403.
{
"mcpServers": {
"<сервис>": {
"type": "streamable-http",
"url": "https://<сервис>.gnexus.space/mcp-protocol/",
"headers": { "Authorization": "Bearer <api-token-сервиса>" }
}
}
}
gnexus_creds/mcp*.py, страница Tokens в UI)/mcp-keys в UI, plaintext один раз, sha256 в mcp_tokens, лимит ≤10 активных, admin-обзор и отзыв чужих), отличия: вместо scopes — снейпшот роли владельца на момент выпуска токена (role user видит только личные тулы, admin+ — весь каталог); исторический маршрут /mcp остаётся alias'ом к /mcp-protocol/, заблокированный в gnexus-auth пользователь гасит свои MCP-токены одним флагом из вебхука user.blocked (user_prefs.blocked; гард отвечает тем же 401, что и при неверном токене — не раскрывать статус блокировки), а самопривязка SSO-логаут MCP-токены не трогает.