Зафиксируй результат живой проверки MCP-сервера
CI / Test (push) Failing after 26s
CI / Publish to npm (push) Skipped

Все 6 инструментов проверены живым MCP-протоколом против прода
реальным ключом: баланс, каталог (включая speech без цены), подбор
модели, оценка стоимости, usage, список ключей. Секрет нигде не
утёк (stderr пуст). Каталог TTS-моделей на проде изменился со
вчерашнего дня — отражается верно, это не баг сервера.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
vasyanskandClaude Sonnet 5 committed 2026-10-24 11:04:59 +07:00
1 parent f836e0a489
commit 8675c6833e
1 file changed
+61
+61
View File
@@ -0,0 +1,61 @@
# Feature: клиентский MCP-сервер для openrusrouter.ru
Дата: 2026-10-24
## Задача
Клиентский MCP-сервер (TypeScript/Node, npm-пакет, stdio) для быстрой настройки
интеграции и выбора модели прямо из Claude Desktop/Code/Cursor/OpenCode.
## Research (консилиум)
- architect/api/security/devops. Ключевая находка security-агента: Bearer-ключ
сам по себе НЕ read-only (доступны платежи/промокоды/тикеты) — периметр
«только чтение» держится ИСКЛЮЧИТЕЛЬНО дисциплиной самого MCP-пакета
(узкий HTTP-клиент на 7 строго заданных GET-методов, без универсального
`fetch(url, method)`).
- Мутации API-ключей (создание/отзыв) физически недоступны Bearer-ключом —
серверный инвариант `cabinet.sessionOnly`, не наше решение, а факт из кода
бэкенда (`cabinet/middleware.go:118`).
- Решение владельца: список ВСЕХ ключей аккаунта показывать (поля обрезаны,
секрет никогда не возвращается).
## Plan
Детальный план по файлам (Plan-агент), с уточнениями по факту:
`/api/keys` и `/v1/auth/key` оборачивают массив/объект в `{keys:[...]}`/`{data:{...}}`
(не так, как в OpenAPI-спеке бэкенда — расхождение зафиксировано в коде и README).
## Реализация (3 волны, параллельные exec-агенты)
- Волна 1: репозиторий `pub/openrusrouter-mcp`, живые проверки 7 эндпоинтов
с фикстурами, package.json/tsconfig/eslint, утилиты (config/redact/errors/
money/sanitize/cache) с тестами.
- Волна 2: `client.ts` (заморожен, ровно 7 методов, никакого произвольного
HTTP), `catalog.ts` (join `/api/models`+`/v1/models`), 6 MCP-инструментов
(list_models, pick_model, estimate_cost, get_balance, get_usage,
list_api_keys), entry point с перенаправлением console в stderr.
- Волна 3: README (быстрый старт для 4 клиентов, явный блок «чего тут нет и
почему»), CHANGELOG, CI (`.gitea/workflows/ci.yaml`: test на каждый push,
publish только по тегу `v*`, секрет `NPM_TOKEN` в `env:` шага).
## Validation
- `npm run typecheck && npm test && npm run build && npm run lint && npm pack --dry-run`
— чисто, 64/64 теста.
- **Живой smoke-тест через настоящий MCP-протокол** (`StdioClientTransport`)
против `https://openrusrouter.ru` реальным ключом:
- `get_balance` — сходится с кабинетом.
- `list_models` (text, speech) — корректные данные, у speech `price_note`
без цифр.
- `pick_model` — работает.
- `estimate_cost` — верно отказывает для speech-модели и несуществующего
id, верно считает для текстовой модели (сверено вручную).
- `get_usage` — реальные данные за 7 дней, совпадают со вчерашними TTS-
тестами (elevenlabs, whisper).
- `list_api_keys` — показывает все ключи аккаунта, `is_current_key` верно
определяет используемый, секрет нигде не виден.
- stderr пуст, ключ нигде не утёк (`KEY_LEAK_IN_STDERR: false`).
- Побочно замечено: каталог TTS-моделей на проде изменился со вчера (Gemini/
voxtral пропали из списка speech) — это действие администратора в кабинете,
не баг MCP-сервера; подтверждено, что `estimate_cost`/`list_models` честно
отражают актуальный каталог, а не кэш старых данных.
## Статус
Done (код + живая проверка). НЕ запушено в удалённый репозиторий, НЕ опубликовано
в npm — оба действия требуют отдельного подтверждения (публикация —
необратимое публичное действие, нужен секрет `NPM_TOKEN`, которого у агента нет).