Files
openrusrouter-mcp/swarm-report/mcp-server-2026-10-24.md
T
vasyanskandClaude Sonnet 5 8675c6833e
CI / Test (push) Failing after 26s
CI / Publish to npm (push) Skipped
Зафиксируй результат живой проверки MCP-сервера
Все 6 инструментов проверены живым MCP-протоколом против прода
реальным ключом: баланс, каталог (включая speech без цены), подбор
модели, оценка стоимости, usage, список ключей. Секрет нигде не
утёк (stderr пуст). Каталог TTS-моделей на проде изменился со
вчерашнего дня — отражается верно, это не баг сервера.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-24 11:04:59 +07:00

4.7 KiB
Raw Blame History

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, которого у агента нет).