28 KiB
Архитектура
1. Назначение проекта
Проект представляет собой платформу для динамической публикации внешних API в виде MCP tools. Пользователь конфигурирует операцию через административный UI вместо написания отдельного backend-обработчика. Платформа сохраняет конфигурацию, валидирует ее, позволяет выполнить тестовый вызов и публикует операцию для использования LLM через MCP.
Главная инженерная цель проекта - представить разные протоколы как единый набор операций с точки зрения MCP-слоя.
2. Ключевой принцип проектирования
Центральная абстракция системы - Operation.
Каждая операция описывает один вызываемый элемент независимо от протокола:
name- внутреннее уникальное имя.display_name- имя, отображаемое в UI.protocol-rest,graphqlилиgrpc.target- хост и протокол-специфичное описание назначения.input_schema- нормализованный входной контракт.input_mapping- правила отображения MCP-входа в поля целевого запроса.execution_config- auth-профиль, таймауты, заголовки и протокол-специфичные параметры.output_mapping- правила отображения ответа внешней системы в нормализованный выход.tool_description- метаданные для MCP и LLM.status- draft, testing, published, archived.
MCP server должен понимать только нормализованный контракт. Протокольные адаптеры должны преобразовывать нормализованную модель в конкретный REST, GraphQL или gRPC вызов и затем возвращать ответ обратно в нормализованный JSON.
3. Границы продукта
Входит в MVP
- Административный UI для создания и редактирования операций.
- Динамический реестр операций.
- Runtime-выполнение REST операций.
- Runtime-выполнение GraphQL операций.
- Runtime-выполнение unary gRPC методов.
- Загрузка примеров
JSONдля ускоренного создания схем и mappings. - Импорт и экспорт конфигураций в
YAML. - Тестирование операций до публикации.
- Публикация MCP tools на основе данных из реестра.
- Hot reload опубликованных операций без изменения backend-кода.
Не входит в MVP
- gRPC streaming.
- Полноценный импорт OpenAPI с автоматической генерацией маппинга.
- Полноценный визуальный конструктор GraphQL-запросов.
- SOAP.
- Выполнение произвольного кода внутри mapping-правил.
- Оркестрация нескольких операций в виде workflow.
- Мультитенантность и биллинг.
4. Пользовательский сценарий
Сценарий работы оператора должен быть одинаковым для всех протоколов:
- Выбрать протокол.
- Указать целевой хост или сервер.
- Выбрать или описать внешнюю операцию.
- Определить MCP-входные параметры.
- Сопоставить MCP-вход с внешним запросом.
- Сопоставить внешний ответ с MCP-выходом.
- Добавить описание для MCP и LLM.
- Выполнить тестовый вызов.
- Опубликовать операцию.
UI должен максимально скрывать протокольную сложность. REST endpoint, GraphQL operation и gRPC method должны отображаться для оператора как "операция с входными и выходными параметрами".
5. Стратегия по протоколам
REST
REST-адаптер является базовым и должен реализовываться первым.
Поддержка в MVP:
GETPOSTPUTPATCHDELETE- path parameters
- query parameters
- headers
- JSON request body
- JSON response body
- аутентификация
Bearer,Basicи API key
Пользователь настраивает:
- base URL,
- HTTP method,
- path template,
- request mapping,
- response mapping.
GraphQL
Поддержка GraphQL в MVP должна быть намеренно упрощена.
Поддержка в MVP:
querymutation- endpoint URL
- request headers
- operation template
- variables mapping
- извлечение результата из
data
Пользователь настраивает:
- GraphQL endpoint,
- шаблон операции,
- схему переменных,
- маппинг переменных,
- путь к нужным данным в ответе.
Introspection может быть добавлен позже как вспомогательная функция UI, но первая рабочая версия системы не должна от него зависеть.
Ключевое ограничение GraphQL в проекте: одна MCP operation должна соответствовать одному конкретному GraphQL-запросу или mutation с заранее определенным selection set. Платформа не должна пытаться передавать LLM всю гибкость GraphQL, потому что LLM не должен формировать произвольный набор полей и произвольную структуру параметров для одного и того же tool.
С точки зрения MCP GraphQL в этой системе намеренно превращается в более жесткий интерфейс:
- один tool;
- один шаблон
queryилиmutation; - фиксированный набор входных параметров;
- один предсказуемый формат ответа.
Фактически на слое MCP "универсальность" GraphQL сознательно сужается до модели, близкой к RPC или REST operation. Это делается для того, чтобы tool оставался понятным для LLM, валидируемым, предсказуемым по структуре ответа и пригодным для явного mapping.
gRPC
gRPC - наиболее сложный протокол в этом проекте, поэтому его нужно ограничить на раннем этапе.
Поддержка в MVP:
- только unary RPC,
- загрузка
.proto, - загрузка descriptor set,
- опционально server reflection на более позднем этапе,
- преобразование между нормализованным JSON и protobuf-сообщениями.
Рекомендуемый путь реализации:
- Принимать descriptor set как основной машинно-читаемый источник схемы.
- Опционально принимать
.protoдля удобства оператора. - Парсить descriptor во внутреннюю модель схемы, удобную для UI.
- Показывать services, methods, входные поля и выходные поля в виде структурированной формы.
- Позволять пользователю настраивать input и output mapping.
Такой подход превращает gRPC для оператора в тот же опыт, что и REST: выбрать метод, посмотреть параметры, сопоставить поля, протестировать, опубликовать.
Streaming gRPC сознательно не входит в рамки проекта. Платформа ориентирована на MCP tool invocation, а MCP tool в этой системе моделируется как сценарий запрос -> один ответ. LLM не работает с долгоживущими транспортными сессиями и не нуждается в обработке потока сообщений для такого типа интеграции. Поэтому server streaming, client streaming и bidirectional streaming исключаются как архитектурно избыточные для выбранной модели взаимодействия.
Тот же принцип применяется и к GraphQL: даже если внешний GraphQL endpoint допускает очень гибкий способ получения данных, в MCP публикуются только заранее зафиксированные операции с контролируемым входом и контролируемым ответом.
6. Работа с файлами и автогенерация черновика
Для упрощения конфигурирования система должна поддерживать загрузку файлов и примеров данных, из которых можно собрать стартовую конфигурацию operation.
Поддерживаемые источники:
- пример входного
JSON; - пример выходного
JSON; .proto;descriptor set.
Ожидаемый сценарий:
- Оператор загружает пример входных данных и пример ответа.
- Система строит черновую схему входа и выхода.
- Система предлагает стартовый mapping по совпадающим или близким по структуре полям.
- Оператор вручную корректирует результат.
- Для точечной настройки используется
JSONPath. - Готовую конфигурацию можно экспортировать в
YAMLили импортировать обратно.
Для gRPC источником структуры является не пример JSON-сообщения, а .proto или descriptor set. Однако после преобразования protobuf-схемы во внутреннюю JSON-ориентированную модель пользовательский опыт должен оставаться тем же: видим структуру полей, получаем стартовый mapping, затем уточняем его вручную.
YAML используется как человекочитаемое представление конфигурации operation для:
- переноса между окружениями;
- резервного копирования;
- хранения в git;
- редактирования вне UI;
- пакетного импорта нескольких operation.
Storage backend для sample-файлов, .proto, descriptor set и YAML import payload в MVP должен быть локальным файловым хранилищем приложения с явным storage_ref. В дальнейшем этот слой можно заменить на S3-compatible storage без изменения доменной модели.
7. Внутренняя модель данных
Система должна приводить все данные к JSON-ориентированным структурам, чтобы UI, registry и MCP runtime работали с единым контрактом.
Operation
idnamedisplay_nameprotocolstatustargetinput_schemaoutput_schemainput_mappingoutput_mappingexecution_configtool_descriptioncreated_atupdated_at
Target
REST target:
base_urlmethodpath_template
GraphQL target:
endpointoperation_typeoperation_namequery_template
gRPC target:
server_addrpackageservicemethoddescriptor_refdescriptor_set_b64
Schema
Нормализованный формат схемы должен поддерживать:
- скалярные поля,
- вложенные объекты,
- массивы,
- enum,
- nullable-поля,
oneofдля схем, пришедших из protobuf.
Транспортный формат между внутренними компонентами должен оставаться JSON, даже если конкретный адаптер под капотом работает с protobuf.
8. Модель маппинга
Платформе нужен отдельный слой маппинга, потому что MCP-facing параметры не совпадают напрямую с payload внешнего API.
Начальная версия mapping-системы должна оставаться простой, но при этом достаточно выразительной для работы со вложенными структурами:
- сопоставление поле-в-поле по
JSONPath, - константы,
- значения по умолчанию,
- извлечение вложенных полей из ответа.
Примеры:
$.mcp.user_id -> $.request.path.userId$.mcp.limit -> $.request.query.limit$.response.data.user.name -> $.output.name$.response.user.email -> $.output.email
JSONPath используется как единый способ адресации вложенных значений в input/output mapping. Это позволяет управлять структурой и вложенностью без написания пользовательского кода.
Для MVP mapping engine не должен поддерживать произвольные скрипты. Достаточно единого движка JSONPath, констант, defaults и ограниченного набора встроенных преобразований.
Черновой mapping может генерироваться автоматически на основе загруженных примеров данных, но итоговая конфигурация всегда остается явной и редактируемой оператором.
Для MVP допустима простая стратегия draft generation:
- искать уникальные leaf-поля с одинаковыми именами;
- предлагать только однозначные соответствия;
- не пытаться автоматически разрешать конфликты и неоднозначности.
Каноническая логическая модель остается общей для runtime и БД, но система должна уметь сериализовать и десериализовать ее также в YAML.
9. Основные компоненты
mcpaas-core
Ответственность:
- общие доменные типы,
- идентификаторы,
- статусы и базовые protocol-specific target types,
- общие ошибки.
mcpaas-schema
Ответственность:
- нормализованные схемы входа и выхода,
- представление типов и полей для UI и runtime,
- валидация JSON относительно внутренней схемы.
mcpaas-mapping
Ответственность:
- модель mapping-правил,
JSONPathparser и validator,- применение input/output mapping,
- генерация чернового mapping по sample-данным и схемам.
mcpaas-proto
Ответственность:
- загрузка
.protoиdescriptor set, - protobuf discovery,
- извлечение services, methods и message schemas,
- преобразование protobuf metadata в нормализованные схемы.
mcpaas-registry
Ответственность:
- постоянное хранение операций,
- CRUD для draft и published операций,
- выдача списка активных tools,
- инвалидация кэша и сигналы на reload.
mcpaas-runtime
Ответственность:
- выполнение нормализованных операций,
- выбор нужного протокольного адаптера,
- применение input mapping,
- применение output mapping,
- единообразные runtime-ошибки.
mcpaas-adapter-rest
Ответственность:
- сборка HTTP-запроса из нормализованного входа,
- отправка запроса через
reqwest, - нормализация HTTP-ответа в JSON.
mcpaas-adapter-graphql
Ответственность:
- формирование GraphQL payload,
- подстановка переменных,
- отправка запроса,
- извлечение
dataи ошибок из GraphQL-ответа.
mcpaas-adapter-grpc
Ответственность:
- сборка protobuf request message из нормализованного JSON,
- вызов unary RPC метода,
- преобразование protobuf response обратно в нормализованный JSON.
mcpaas-admin-api
Ответственность:
- CRUD endpoints для UI,
- создание и управление version snapshots,
- import/export конфигураций в
YAML, - загрузка sample JSON,
- загрузка
.protoи descriptor set, - endpoints для тестового выполнения операций,
- discovery endpoints для gRPC metadata.
mcpaas-mcp-server
Ответственность:
- список доступных MCP tools из registry,
- валидация входа tool по нормализованной схеме,
- делегирование выполнения в runtime,
- возврат нормализованного результата MCP-клиенту.
mcpaas-ui
Ответственность:
- wizard создания сервиса и операции,
- editor для mapping,
- загрузка sample-файлов и schema artifacts,
- экран тестового вызова,
- браузер gRPC схемы,
- import/export конфигураций,
- workflow публикации и отображение статуса.
Deployment layer
Ответственность:
- контейнерная упаковка приложений;
- orchestration через
docker-compose; - reverse proxy routing;
- healthchecks и delivery pipeline.
Этот слой не должен влиять на доменную модель и application contracts.
10. Предлагаемая структура репозитория
Для реализации рекомендуется workspace-структура:
mcpaas/
apps/
admin-api/
mcp-server/
ui/
crates/
mcpaas-core/
mcpaas-schema/
mcpaas-mapping/
mcpaas-proto/
mcpaas-registry/
mcpaas-runtime/
mcpaas-adapter-rest/
mcpaas-adapter-graphql/
mcpaas-adapter-grpc/
docs/
Такая структура позволяет держать протокольные адаптеры независимыми и отдельно тестируемыми.
11. Технологический стек
Backend
- Rust
tokioкак async runtimeaxumдля HTTP APIserdeиserde_jsonsqlxдля PostgreSQLreqwestдля REST и GraphQL транспортаtonicиprostдля работы с gRPCtowerдля middlewaretracingдля логирования и диагностики
Frontend
- TypeScript
- React
- Vite
- React Router
- TanStack Query
- React Hook Form
- Zod
Этот стек прагматичен для внутреннего административного UI: быстрая итерация, удобная работа с формами, понятная интеграция с API и отсутствие лишней сложности.
12. Почему React + Vite для UI
Frontend в этом проекте - это операторская консоль, а не контентный сайт. Server-side rendering здесь не требуется. Основные требования:
- динамические формы,
- schema-driven рендеринг,
- экраны тестирования и предпросмотра,
- адаптивные административные страницы,
- высокая скорость локальной разработки.
React + TypeScript + Vite хорошо подходит под эти условия, потому что позволяет развивать frontend независимо от Rust-сервисов и быстро собирать сложные формы вроде mapping editor и gRPC method inspector.
13. Почему Axum для backend
axum выбран как основной backend-фреймворк по следующим причинам:
- он построен поверх
towerи хорошо согласуется с современным async-стеком Rust, - он естественно интегрируется с
tokio,hyperи middleware-композицией, - он лучше подходит для модульной структуры с несколькими сервисами,
- он удобен для typed handlers, shared state и собственных extractors,
- он лучше сочетается с
tonic, который используется для gRPC.
Детальная декомпозиция crates и модулей вынесена в docs/module-decomposition.md.
Формальная модель данных вынесена в docs/data-model.md.
Схема БД и versioning описаны в docs/database-schema.md.
HTTP-контракты административного API описаны в docs/admin-api.md.
Диаграммы компонентов, сущностей и потоков вынесены в docs/diagrams.md.
MCP transport и способ публикации tools описаны в docs/mcp-interface.md.
Стратегия тестирования описана в docs/testing-strategy.md, а runtime-конфигурация и storage assumptions - в docs/runtime-config.md.
Rust-oriented распределение методов, impl, trait и service-слоя описано в docs/rust-design.md.
Правила разработки и TDD-процесс описаны в docs/development-rules.md, а последовательность модулей и фич - в docs/implementation-plan.md.
Rust-specific правила кода, linting и toolchain описаны в docs/rust-code-rules.md.
Требования и ограничения по конкретным протоколам вынесены в docs/protocols/rest.md, docs/protocols/graphql.md и docs/protocols/grpc.md.
14. Runtime-поток
Создание операции
- UI отправляет draft операции в admin API.
- Admin API валидирует схему и mappings.
- Registry сохраняет draft.
- UI запускает тестовый вызов через runtime.
- Оператор публикует операцию.
- Registry помечает операцию как active.
- MCP server перезагружает активные операции.
Выполнение tool
- MCP client вызывает tool.
- MCP server берет определение tool из памяти.
- Runtime валидирует вход относительно нормализованной схемы.
- Runtime применяет input mapping.
- Runtime вызывает нужный протокольный адаптер.
- Runtime применяет output mapping.
- MCP server возвращает нормализованный результат.
Эта последовательность соответствует модели один запрос -> один ответ. Именно поэтому поддержка streaming-протоколов не рассматривается как часть MVP: она не соответствует целевой модели вызова tools со стороны LLM.
По этой же причине GraphQL tools должны быть заранее специализированы под конкретный сценарий вызова, а не представлять собой общий конструктор запросов для LLM.
15. Нефункциональные требования
- Новые операции должны добавляться без изменения backend-кода.
- Опубликованные операции должны становиться видимыми для MCP-клиентов без пересборки сервиса.
- Runtime-ошибки должны быть наблюдаемыми и различимыми по этапам.
- Система должна оставаться детерминированной и пригодной для аудита.
- Протокольные адаптеры должны тестироваться независимо.
- Все опубликованные операции должны укладываться в модель синхронного или квазисинхронного вызова
запрос -> ответ. - Все опубликованные GraphQL operations должны иметь фиксированный шаблон запроса и фиксированную структуру ожидаемого результата.
16. Основные риски
- Динамическая работа с protobuf заметно сложнее, чем REST и GraphQL.
- UX для маппинга может стать слишком тяжелым, если не ограничить его заранее.
- Нормализация схем может стать непоследовательной без строгой внутренней модели.
- Попытка поддержать слишком много возможностей протоколов замедлит реализацию.
- Попытка сохранить всю динамическую гибкость GraphQL на уровне MCP приведет к слишком широким и плохо управляемым tools.
Поэтому проект должен в первую очередь реализовать один чистый end-to-end сценарий, а не широкий, но поверхностный охват возможностей.
SOAP в этой версии проекта сознательно отложен. Это не забытый протокол, а отдельное направление развития, которое потребует самостоятельного XML/WSDL слоя, отдельной схемной модели и отдельного адаптера.