feat: персональные MCP-ключи — выпуск в SPA, роль владельца у тула
Решение владельца (2026-10-04):
- Каждый пользователь выпускает себе MCP-ключ на новой странице /mcp-keys
  (доступна любой роли); plaintext показывается один раз, в БД — sha256 + hint.
- Ключ действует ролью владельца на момент выпуска (снейпшот system_role):
  admin/superadmin — полный каталог тулов (35), user — только личный набор
  (me, my_events_list, my_push_subscriptions_list, my_push_subscription_delete).
- Статический MCP_TOKEN из .env остаётся суперадмин-бэкдором; /mcp монтируется
  безусловно (персональные ключи работают и без env-токена).

Backend:
- таблица mcp_tokens (миграция 0008 c9a2d6e71f43) — зеркало ApiKey;
- app/mcp/context.py — ContextVar пользователя, resolve_personal_token;
- McpTokenGuard резолвит стат.токен или mcp_* в БД, пишет last_used_at,
  401 на промахе (чистый ASGI, SSE не трогает);
- тулы: user=current_mcp_user() вместо синтетического MCP_USER; админ-тулы
  под _admin_run — для user-ключа ToolError с {"error": 403} (не return-данные:
  FastMCP валидирует вывод по аннотации, list-тулы бы отвергли dict);
- HTTP: GET/POST /api/v1/me/mcp_tokens (+/revoke), GET/POST
  /api/v1/admin/mcp_tokens[.../revoke], лимит 10 активных на пользователя.

SPA: страница McpKeysView (свои ключи + как подключить агент; админ — все
ключи и отзыв), маршрут /mcp-keys (userOk), пункт в навигации обеих ролей.

Доки: docs/07 переписан (три вида доступа, 35 тулов), CLAUDE.md,
docs/08 (каталог 35), .env.example (MCP_TOKEN опционален).

E2e на живом стеке: user-ключ — 403 на админ-тулах и рабочий личный набор;
admin-ключ — полный каталог; last_used_at; бэкдор = superadmin; отзыв -> 401.

Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 2b86b4b commit f13a251a04486285d6beacfa3378ee84a060e150
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 10 hours ago
Showing 19 changed files
View
.env.example
View
CLAUDE.md
View
alembic/versions/20261004_0008_mcp_tokens.py 0 → 100644
View
app/api/admin_routes.py
View
app/api/admin_schemas.py
View
app/api/me_routes.py
View
app/auth/apikeys.py
View
app/main.py
View
app/mcp/context.py 0 → 100644
View
app/mcp/server.py
View
app/mcp/tools.py
View
app/models/__init__.py
View
app/models/dicts.py
View
docs/07-mcp.md
View
docs/08-deploy-runbook.md
View
frontend/src/App.vue
View
frontend/src/api.js
View
frontend/src/router.js
View
frontend/src/views/McpKeysView.vue 0 → 100644