Skip to main content
Glama
dsoziev1
by dsoziev1
README.md
# День 16 — Подключение MCP (Auth0 Management API v2)

Локальный **MCP-сервер**, который даёт доступ к **Auth0 Management API v2** в виде
набора инструментов, **сгруппированных по категориям документации**
(<https://auth0.com/docs/api/management/v2>), и минимальный **MCP-клиент**, который
подключается к серверу и выводит список инструментов.

Один и тот же сервер подключается и к **Claude Code** (через `.mcp.json`), и к
**нашему агенту** (через MCP-клиент / мост `mcp_tools.py`).

## Что внутри

| Файл | Роль |
|------|------|
| `server.py` | **MCP-сервер** (stdio). `list_tools` → каталог инструментов; `call_tool` → реальный GET к Auth0. |
| `client.py` | **Минимальный MCP-клиент** — РЕЗУЛЬТАТ дня: подключается и печатает список инструментов. |
| `categories.py` | Каталог категорий Management API v2 → инструменты. **Источник списка.** |
| `auth0_client.py` | Транспорт к Auth0: M2M-токен (client_credentials, с кэшем) + GET-запросы. |
| `config.py` | Учётные данные из `.env` или файла `auth0.settings`. |
| `mcp_tools.py` | Мост MCP → агент (async): инструменты в формате function-calling DeepSeek + вызов. |
| `mcp_bridge.py` | **Синхронная** обёртка над `mcp_tools` (фоновый loop) — для синхронного агента. |
| `.mcp.json` | Регистрация сервера в Claude Code. |
| `agent.py` / `agents.py` / `web.py` / … | Агент дня 15 (Auth0 FSM), **с встроенными инструментами Auth0 MCP**. |
| `day16.py` | CLI-демо: агент сам вызывает инструменты MCP и отвечает по реальному тенанту. |

## Объём инструментов (День 16: только чтение)

**37 категорий → 64 инструмента**, все **read-only** (только GET, ничего не меняют в
тенанте). Имя: `auth0_<категория>_<операция>`:

- `auth0_users_list` / `auth0_users_get` / `auth0_users_by_email_list`
- `auth0_clients_list` / `auth0_clients_get`, `auth0_client_grants_list`
- `auth0_connections_*`, `auth0_resource_servers_*`, `auth0_roles_*`,
  `auth0_organizations_*`, `auth0_grants_list`, `auth0_device_credentials_list`
- `auth0_actions_*`, `auth0_action_triggers_list`, `auth0_rules_*`,
  `auth0_rules_configs_list`, `auth0_hooks_*`, `auth0_flows_*`, `auth0_forms_*`
- `auth0_logs_*`, `auth0_log_streams_*`
- `auth0_email_templates_get`, `auth0_emails_get`, `auth0_branding_*`, `auth0_prompts_*`
- `auth0_attack_protection_*`, `auth0_anomaly_check_ip`, `auth0_blacklists_list`,
  `auth0_user_blocks_*`, `auth0_network_acls_*`
- `auth0_custom_domains_*`, `auth0_keys_*`, `auth0_guardian_*`
- `auth0_sessions_get`, `auth0_refresh_tokens_get`, `auth0_jobs_*`,
  `auth0_self_service_profiles_*`, `auth0_tenants_settings`, `auth0_stats_*`

Создание/изменение/удаление (POST/PATCH/DELETE) сознательно **не включены** —
добавим отдельным этапом.

## Установка

```bash
pip install -r requirements.txt        # mcp, httpx, python-dotenv
cp .env.example .env                   # впишите данные Auth0 M2M-приложения
```

`.env` (или файл `auth0.settings` рядом с проектом):

```
AUTH0_DOMAIN=dev-xxxx.us.auth0.com
AUTH0_CLIENT_ID=...
AUTH0_CLIENT_SECRET=...
```

M2M-приложение в Auth0 должно быть **авторизовано для «Auth0 Management API»**
(audience `https://<domain>/api/v2/`) с нужными read-scope (`read:users`,
`read:clients`, …). Секреты в репозиторий не попадают (`.env`, `auth0.settings`
в `.gitignore`).

## Где работает сервер, где клиент, как видеть логи

Есть ДВА транспорта — выбирайте по задаче:

### 1. stdio (по умолчанию; так работают Claude Code и наш агент)
Сервер **не висит постоянно** — клиент (или Claude Code, или агент) запускает
`server.py` как **дочерний подпроцесс** и общается с ним через stdin/stdout. Логи
сервера идут в его **stderr**. Чтобы видеть их отдельно — перенаправьте в файл и
смотрите `tail -f` во втором терминале:

```bash
# терминал 1 — «логи сервера» (вызовы инструментов + запросы к Auth0):
touch mcp_server.log && tail -f mcp_server.log

# терминал 2 — клиент; его собственные логи показывает флаг -v:
AUTH0_MCP_LOG=mcp_server.log python3 client.py -v --call auth0_clients_list --arg per_page=2
```
`[client]` — что делает клиент (initialize → list_tools → call_tool);
`[mcp]` / `[auth0]` — что делает сервер (◀ вызов инструмента → POST /oauth/token →
GET …/clients → HTTP 200 → ▶ результат).

### 2. HTTP (сервер — ОТДЕЛЬНЫЙ постоянный процесс в своём терминале)
Самый наглядный режим: сервер и клиент — два независимых процесса.

```bash
# ТЕРМИНАЛ 1 — СЕРВЕР (логи API видно прямо в консоли):
python3 server.py --http               # слушает http://127.0.0.1:8765/mcp

# ТЕРМИНАЛ 2 — КЛИЕНТ (подключается к запущенному серверу):
python3 client.py --http -v --call auth0_clients_list --arg per_page=2
```
В терминале 1 на каждый вызов видно цепочку:
```
◀ ВЫЗОВ ИНСТРУМЕНТА auth0_clients_list args={'per_page': 2}
→ POST /oauth/token (client_credentials, audience=…/api/v2/)
← токен получен, действует ~86400s
→ GET …/api/v2/clients  [per_page=2]
← HTTP 200 (136 байт) — список из 2 элементов
▶ РЕЗУЛЬТАТ auth0_clients_list: 179 символов JSON отдано клиенту
```

> Claude Code и агент (`mcp_bridge`) используют именно stdio — это стандарт для
> локальных MCP. HTTP-режим удобен, чтобы «вживую» наблюдать, как клиент дёргает
> сервер, а сервер — Auth0 API.

## Проверка (РЕЗУЛЬТАТ дня)

**1. Соединение + список инструментов** (учётные данные не требуются — сервер не
берёт токен, чтобы перечислить инструменты):

```bash
python3 client.py
```
Ожидается: `✅ MCP-соединение установлено` и `🧰 Инструментов получено: 64`,
сгруппированных по категориям.

**2. Живой вызов инструмента** (нужны учётные данные Auth0):

```bash
python3 client.py --call auth0_clients_list --arg per_page=2 --arg fields=name,app_type
python3 client.py --call auth0_tenants_settings
```

**3. Каталог без MCP/сети** (быстрый офлайн-просмотр):

```bash
python3 categories.py
```

**4. Что получит агент** (инструменты в формате DeepSeek tools):

```bash
python3 mcp_tools.py
```

## Подключение к Claude Code

Сервер зарегистрирован в `.mcp.json`. Claude Code обнаруживает его автоматически и
запрашивает подтверждение (`⏸ Pending approval`). Проверка/одобрение:

```bash
claude mcp list          # покажет: auth0: … (статус)
```
После одобрения инструменты `auth0_*` доступны прямо в Claude Code.

## Подключение к агенту (стиль дня 15) — ВСТРОЕНО

Агент дня 15 (Auth0 FSM, оркестратор + команда под-агентов) теперь **сам пользуется
инструментами Auth0 через MCP**. Точка интеграции — единственный вызов модели в
`Agent._run_stage`: добавлен tool-calling цикл (`Agent._chat_stage`). Пока модель
просит вызвать инструмент — агент исполняет его через MCP-мост, кладёт результат в
диалог и спрашивает снова (до 4 раз), затем выдаёт финальный ответ по фактам.

- `mcp_bridge.SyncAuth0MCP` — синхронный мост (фоновый event loop + одна MCP-сессия),
  чтобы синхронный агент мог звать async MCP без переписывания на async.
- `llm_client.chat(..., tools=...)` — добавлена поддержка function-calling: модель
  может вернуть `tool_calls`, клиент возвращает их в `ChatResult`.
- Инструменты передаются только на не-training этапах; они **read-only**, поэтому
  безопасны и согласуются с инвариантами дня 14.

Запуск с агентом:

```bash
python3 day16.py                 # CLI: агент отвечает по реальному тенанту через MCP
DEEPSEEK_DB=day16.db uvicorn web:app --reload   # веб: под ответом видно 🔧 вызовы Auth0 MCP
```

В вебе агент создаётся с общим мостом (`web._mcp`); если учётных данных Auth0 нет —
мост не поднимается, и агент работает как раньше, без инструментов.

Низкоуровневый async-доступ (тот же сервер, для своих сценариев):

```python
async with Auth0MCP() as mcp:
    tools = await mcp.deepseek_tools()        # спецификации tools для модели
    text = await mcp.call(name, arguments)    # выполнить tool_call от модели
```

## Архитектура (слои)

```
client.py / Claude Code / агент  ──MCP(stdio)──▶  server.py
                                                     │ categories.py (каталог)
                                                     ▼
                                                 auth0_client.py ──HTTPS──▶ Auth0 Management API v2
                                                     ▲
                                                 config.py (.env / auth0.settings)
```
`server.py` ничего не знает про конкретные эндпоинты — он разворачивает каталог
`categories.py` в инструменты и проксирует GET через `auth0_client.py`. Чтобы
добавить категорию/операцию — правим только `categories.py`.
```