# MCP: мультиюзер доступ для ИИ-агентов

Схема, применённая в gnexus-creds: сервис — сам MCP-сервер, доступ — через
собственные API-токены сервиса (не через access-токены gnexus-auth), каждый
токен принадлежит пользователю сервиса.

## Правила
- Сервис с MCP-функционалом предоставляет **streamable HTTP** эндпоинт
  (`/mcp-protocol/`, слэш в конце значим — реверс-прокси не буферизует и не
  переписывает тело). Legacy HTTP/SSE-адаптер — только для клиентов без
  streamable HTTP. `stdio` не используется: агент и сервис на разных хостах.
- Авторизация MCP — **Bearer токен сервиса** в заголовке `Authorization`.
- Токены выдаются в UI на **отдельной странице «Токены»**: имя, набор scopes,
  ревок, `last_used_at`. Токен показывается ровно один раз при создании,
  в БД — только хэш.
- Токен привязан к пользователю: действия через MCP выполняются от его имени
  и видны в аудите (`channel=mcp`), а недействительный/заблокированный
  пользователь gnexus-auth блокирует и его токены (403).
- Доступ ограничивается scopes; лишний scope не выдавать. Чего не хватит —
  403, а не молчаливое сужение выдачи.
- Rate-limit на чувствительные операции.

## Scopes (паттерн gnexus-creds)
| Скоупы | Доступ |
|---|---|
| `mcp, read` | чтение/поиск метаданных |
| `mcp, read, reveal` | + расшифровка секретов |
| `mcp, read, reveal, write` | полный MCP (создание/обновление) |

`read`/`reveal`/`write` наполняются в контексте конкретного сервиса; без
скоупа `mcp` всё закрыто 403.

## Подключение агента
```json
{
  "mcpServers": {
    "<сервис>": {
      "type": "streamable-http",
      "url": "https://<сервис>.gnexus.space/mcp-protocol/",
      "headers": { "Authorization": "Bearer <api-token-сервиса>" }
    }
  }
}
```

## Ссылки
- Референс: gnexus-creds (`gnexus_creds/mcp*.py`, страница Tokens в UI)
- hard-panel пока на едином Bearer GHARD_ADMIN_TOKEN — при переходе на
  мультиюзер: токены по этой конвенции, страница «Токены» в UI (см.
  [auth.md](auth.md) про матрицу доступа).
- **Gnexus Synapse** — второй референс с допустимым вариантом: те же принципы
  (страница `/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-токены не трогает.