Зафиксируй результат живой проверки MCP-сервера
Все 6 инструментов проверены живым MCP-протоколом против прода реальным ключом: баланс, каталог (включая speech без цены), подбор модели, оценка стоимости, usage, список ключей. Секрет нигде не утёк (stderr пуст). Каталог TTS-моделей на проде изменился со вчерашнего дня — отражается верно, это не баг сервера. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f836e0a489
commit
8675c6833e
1 file changed
+61
@@ -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`, которого у агента нет).
|
||||||
Reference in new issue
Block a user