Skip to main content
Glama
BKSLab

vera_mcp_service

by BKSLab

vera_mcp_service

MCP Tools Server — инструментальный слой между Agent Service и конкретными сервисами проекта «Работа для всех». Принимает вызовы по MCP-протоколу, выполняет узкие бизнес-процессы и возвращает типизированный результат. Не оркестрирует диалог и не хранит состояние сессии. Для формирования документов может использовать собственный узкий LLM-процесс: структурирование уже готовой консультации без изменения её смысла.

Роль в системе

Последний из трёх сервисов архитектуры ассистента (AGENT_VERA_ARCHITECTURE.md): Agent Service (vera_agent_service, оркестратор, production-ready) → MCP Tools Server (этот репозиторий) → RAG Service (vera_rag_service, семантический поиск по базе знаний, production-ready). Оба соседних контракта уже зафиксированы кодом по обе стороны — этот сервис реализует тонкую прослойку по готовому ТЗ, а не проектирует контракт с нуля.

Сервис предоставляет два инструмента:

  • vera_rag_kb — поиск по базе знаний Vera RAG;

  • send_consultation_email — структурирование готовой консультации, формирование доступного PDF и отправка по email.

История базовой реализации находится в MCP_SERVICE_PLAN.md, реализация консультации — в CONSULTATION_EMAIL_TOOL_PLAN.md.

Related MCP server: MCP Enterprise Tools Server

Как это работает

  1. Приём вызоваFastMCP (mcp.server.fastmcp), транспорт streamable-http, работает автономно (mcp.run(transport="streamable-http")) — без FastAPI, по образцу проверенного на масштабе in-house проекта tools-mcp (см. план, раздел 0.1). Agent Service подключается через MultiServerMCPClient на /mcp.

  2. Инструмент vera_rag_kb (app/tools/vera_rag_kb.py) — тонкий адаптер: валидация непустого query через Pydantic-схему MCP, затем вызов RagClient.search(). Роль пользователя в поисковый контракт не входит: RAG получает запрос без audience и ищет по всему корпусу. При сбое RAG Service исключение всплывает как есть: Agent Service (handle_tool_errors=False) ждёт именно исключение MCP-уровня, не dict с полем ошибки.

  3. Инструмент send_consultation_email (app/tools/send_consultation_email.py) — тонкая MCP-граница над ConsultationDeliveryService. Email валидируется внутри тела тула, поэтому ошибка возвращается словарём, а не ToolError.

  4. Подготовка консультации — общий LlmClient получает исходный текст как данные и структурирует его без изменения темы, которую передал Agent Service. Jinja подставляет результат в фирменный HTML-бланк, WeasyPrint формирует tagged PDF/UA с Unicode-текстом. Прикладных ограничений длины текста и max_completion_tokens нет.

  5. ОтправкаSmtpClient собирает multipart/alternative с PDF-вложением и выполняет только внутренние ограниченные ретраи временных SMTP-сбоев. Один Message-ID сохраняется на всех попытках. PDF существует только в памяти.

  6. Реестр тулов (app/tools/__init__.py::register_all_tools) — единая точка регистрации, покрытая meta-тестом.

  7. Клиент RAG Service (app/clients/rag_client.py) — POST /api/v1/search с X-API-Key, без собственного слоя ретраев.

  8. GET /health проверяет RAG. Платные LLM-запросы и SMTP-login из health-check не выполняются.

  9. Наблюдаемость — OpenTelemetry → общий Arize Phoenix project. Spans содержат длины, размеры и outcomes, но не текст консультации, email, PDF или секреты.

Стек

mcp (FastMCP, streamable-http) · httpx · pydantic / pydantic-settings · Jinja2 · WeasyPrint · aiosmtplib · OpenTelemetry → Arize Phoenix · Docker Compose. FastAPI сервису не нужен.

Контракты

Подробности, JSON-примеры и обоснования — MCP_SERVICE_PLAN.md, раздел 3.

Контракт

Кто использует

Кратко

Тул vera_rag_kb (MCP, streamable-http)

Agent Service → этот сервис

vera_rag_kb(query: str) -> {"chunks": [...]} — пустой список chunks валиден («нет ответа»), не ошибка. При сбое — исключение MCP-уровня, не dict с полем ошибки

Тул send_consultation_email

Agent Service → этот сервис

send_consultation_email(consultation_text: str, consultation_topic: str, email: str) -> dict. consultation_topic — краткая тема, из которой сервис сам формирует заголовок и русское имя PDF. Успех: status, document_name, message; входной email обратно не возвращается. Предусмотренная ошибка: status="error", стабильные code и message

POST /api/v1/search

Этот сервис → RAG Service

{"query", "top_k"}{"chunks": [...]}, заголовок X-API-Key. audience намеренно не передаётся, поэтому RAG ищет по всему корпусу; его собственная опциональная поддержка фильтра остаётся доступной для будущих сценариев

OpenAI-compatible Chat Completions

Этот сервис → LLM API

Базовый LLM_API_URL дополняется /chat/completions; structured output валидируется через FormattedConsultation, а тема добавляется сервисом отдельно

SMTP TLS

Этот сервис → почтовый сервер

Отправка EmailMessage с plain/html телом и application/pdf вложением; подтверждённые бизнес-сбои возвращаются словарём

GET /health

Оркестратор/мониторинг

{"status": "ok", "rag_service": "ok"|"unreachable"} — код ответа всегда 200

Запуск локально

cp .env.example .env
# заполнить .env — RAG, LLM и SMTP-реквизиты

docker compose up -d --build

Сервис

Адрес

MCP Tools Server (streamable-http)

http://localhost:9000/mcp

GET /health

http://localhost:9000/health

Общий Phoenix (трейсы) — поднимается из vera_agent_service/docker-compose.yml (http://localhost:6006), не из этого репозитория (план, Этап 8.3 — единственный общий инстанс на все три сервиса).

Роль MCP в распределённом trace

MCP сохраняет продуктовую границу между Agent и retrieval:

tool.vera_rag_kb               vera_agent_service
└── mcp.execute.vera_rag_kb    vera_mcp_service
    └── rag.search             vera_rag_service

tool.send_consultation_email
└── mcp.execute.send_consultation_email
    ├── consultation.format
    ├── consultation.pdf.render
    └── consultation.email.send

Все сервисы должны использовать одинаковый PHOENIX_PROJECT_NAME, но одного общего Phoenix недостаточно: дерево связывается динамической W3C propagation на обоих сетевых переходах. Span MCP содержит только технические атрибуты и длину query, без текста запроса или чанков. При завершении процесса общий HTTP-клиент закрывается, затем выполняются force_flush и shutdown tracing.

Локально без Docker (venv):

Перед запуском переключить endpoint-блок в .env: закомментировать активные production-адреса и раскомментировать строки из секции Local endpoints.

python -m venv venv
venv\Scripts\activate                # Windows; source venv/bin/activate — Linux/macOS
pip install -r requirements-dev.txt

python -m app.main

Совместный запуск с Agent Service/RAG Service

Общая внешняя Docker-сеть больше не используется. Все сервисы развёртываются на production-хосте 91.218.115.104 и обращаются друг к другу через его опубликованные порты: Agent → MCP — http://91.218.115.104:9000/mcp, MCP → RAG — http://91.218.115.104:8002, MCP → Phoenix — http://91.218.115.104:6006/v1/traces.

В .env активна секция Production endpoints; секция Local endpoints предназначена только для запуска python -m app.main непосредственно на хосте.

Тестирование

pytest tests/                # юнит + интеграционные, без внешней инфраструктуры
ruff check .                 # линтер

Интеграционные тесты поднимают настоящий FastMCP-сервер на свободном порту и подключаются настоящим MultiServerMCPClient. Реальные LLM/SMTP в автоматических тестах не вызываются. Локальный SMTP contract-тест отправляет настоящее MIME-письмо через loopback TCP-сокет без внешней почты. Text-layer тест WeasyPrint запускается, когда в системе доступен Pango; в Windows без Pango он пропускается, а перед production должен быть выполнен в Linux-контейнере.

Документация

  • MCP_SERVICE_PLAN.md — план реализации по этапам, зафиксированные технические решения, контракты, находки, конвенции для будущих тулов, соответствие WBS

  • CONSULTATION_EMAIL_TOOL_PLAN.md — контракт и устройство отправки PDF-консультации

  • LLM_CLIENT_REFERENCE.md — эталон общего OpenAI-compatible LLM-клиента

  • AGENT_VERA_ARCHITECTURE.md — исходная архитектурная концепция трёх сервисов

  • FASTAPI_PATTERNS.md — эталонные паттерны кода проекта (частично применимо — этот сервис не на FastAPI, см. план, раздел 0.1)

Как добавить новый тул

  1. Новый файл app/tools/<name>.py<name>(...) + register_<name>(mcp, ...) с развёрнутым description (перечислением каждого параметра текстом — влияет на выбор тула LLM).

  2. Одна строка в app/tools/__init__.py::register_all_tools.

  3. Классифицировать тул как read-only или мутирующий. Для мутирующего тула явно определить внутренние/внешние retries и риск дубликатов до реализации.

  4. Бизнес-процесс размещать в app/services/, оставляя MCP-функцию тонкой.

  5. Юнит-тесты тула, обновить tests/unit/tools/test_registry.py (новое имя — в ожидаемый набор).

  6. Ручной OpenTelemetry span, если тул делает внешний вызов помимо уже покрытых.

Чеклист перед production-развёртыванием

Локально и функционально всё готово и проверено (см. «Статус» ниже) — но это не значит готовность к реальному прод-деплою. По приоритету, сверху вниз:

P0 — открытых блокеров нет:

  • Провижининг БД RAG исправлен; production health-check RAG возвращает database=ok.

  • Реальный RAG_SERVICE_API_KEY задан в локальном production .env (само значение не коммитится). Плейсхолдер в .env.example оставлен намеренно как безопасный шаблон.

  • LLM и SMTP-реквизиты находятся в игнорируемом .env; перед деплоем проверить их тестовым вызовом без пользовательских данных.

P1 — инфраструктура сейчас dev-уровня, не прод:

  • Нет Nginx/TLS перед сервисом — MCP-эндпоинт сейчас голый HTTP на 9000.

  • Лимит памяти в docker-compose.yml (512M) — placeholder-значение, не проверено нагрузочным тестированием.

  • Agent Service должен отключить внешний retry для send_consultation_email и назначить отдельный увеличенный timeout.

P2 — не верифицировано мной фактическим прогоном:

  • CI (.github/workflows/ci.yml) написан и локально согласован с реальной инфраструктурой, но реальный прогон на GitHub Actions не проверялся — нет доступа к Actions из этой среды. Проверить на первом push/PR.

  • Единое дерево трейса через все три сервиса в живом Phoenix требует проверки после production-деплоя Agent Service.

  • Полный путь Agent → MCP → RAG с реальным контентом требует отдельного E2E-прогона после production-деплоя Agent Service.

  • PDF/UA необходимо проверить валидатором и вручную скринридером в Linux-контейнере; локальная Windows-среда не содержит Pango.

  • Реальную SMTP-доставку проверить в безопасный тестовый ящик.

Семантика доставки: SMTP обеспечивает at-least-once, а не строгую exactly-once-гарантию. Повторы находятся только внутри SmtpClient, один Message-ID переиспользуется; долговременный outbox в текущую версию не входит.

Статус

Реализованы vera_rag_kb и send_consultation_email. Unit- и contract/integration-тесты не требуют внешней инфраструктуры; ruff check . должен оставаться чистым. Для консультации остаются эксплуатационные проверки: реальный LLM structured output, PDF/UA в контейнере, SMTP в тестовый ящик и сквозной Agent Service без внешнего retry.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP server exposing employee info retrieval and web search tools, designed to be consumed by a LangChain agent for decoupled tool execution.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server exposing a RAG knowledge base as read-only tools (search_knowledge_base, ask_knowledge_base, kb_stats, kb_diagnostic) for AI clients like Claude Desktop and Cursor, enabling token-efficient document retrieval and Q&A.
    -