From 8675c6833eb05e60ddaf0e846584f1ffaee3aac4 Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Sat, 24 Oct 2026 11:04:59 +0700 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D1=84=D0=B8=D0=BA=D1=81=D0=B8?= =?UTF-8?q?=D1=80=D1=83=D0=B9=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82?= =?UTF-8?q?=D0=B0=D1=82=20=D0=B6=D0=B8=D0=B2=D0=BE=D0=B9=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20MCP-=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Все 6 инструментов проверены живым MCP-протоколом против прода реальным ключом: баланс, каталог (включая speech без цены), подбор модели, оценка стоимости, usage, список ключей. Секрет нигде не утёк (stderr пуст). Каталог TTS-моделей на проде изменился со вчерашнего дня — отражается верно, это не баг сервера. Co-Authored-By: Claude Sonnet 5 --- swarm-report/mcp-server-2026-10-24.md | 61 +++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 swarm-report/mcp-server-2026-10-24.md diff --git a/swarm-report/mcp-server-2026-10-24.md b/swarm-report/mcp-server-2026-10-24.md new file mode 100644 index 0000000..f4daada --- /dev/null +++ b/swarm-report/mcp-server-2026-10-24.md @@ -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`, которого у агента нет).