24 KiB
Декомпозиция модулей
1. Цель документа
Этот документ фиксирует детальную структуру проекта до начала активной разработки. Его задача - заранее ограничить ответственность каждого компонента, избежать разрастания mcpaas-core, не допустить появления "универсальных" структур на все случаи жизни и сохранить понятные границы между доменной логикой, runtime, адаптерами, API и UI.
Основной принцип: каждый crate отвечает за один слой системы. Внутри crate модули должны быть маленькими, тематическими и с минимальным количеством публичных сущностей.
2. Общие архитектурные правила
2.1. Что считается правильной декомпозицией
coreсодержит только базовую доменную модель, идентификаторы, типы ошибок и общие контракты.registryотвечает только за хранение и загрузку конфигурации операций.runtimeисполняет операции, но не знает о способе их хранения.- адаптеры знают только свой протокол и общий контракт runtime.
admin-apiоркестрирует use case для UI, но не содержит протокольной логики.mcp-serverпубликует tools и вызывает runtime, но не содержит бизнес-логики конфигурирования.uiне знает внутреннюю реализацию runtime и работает только через HTTP API.
2.2. Что запрещено
- помещать SQL, HTTP-клиенты или gRPC-клиенты в
mcpaas-core; - хранить в
core"общие утилиты", не относящиеся к доменной модели; - делать
runtime, который напрямую читает БД; - писать mapping-логику внутри REST, GraphQL или gRPC адаптеров;
- дублировать доменные типы в
admin-api,mcp-serverи адаптерах; - создавать большие структуры вида
AppState, в которые складывается все подряд; - создавать большие enum или config-объекты, содержащие поля всех протоколов одновременно без выделенных вложенных типов.
2.3. Предпочтительный стиль
- узкие интерфейсы;
- маленькие DTO;
- отдельные типы для draft, published и runtime-view сущностей;
- отдельные модули для чтения, записи, валидации и исполнения;
- композиция из небольших сервисов вместо одного глобального сервиса.
3. Workspace-структура
Рекомендуемая структура:
mcpaas/
apps/
admin-api/
mcp-server/
ui/
crates/
mcpaas-core/
mcpaas-registry/
mcpaas-runtime/
mcpaas-adapter-rest/
mcpaas-adapter-graphql/
mcpaas-adapter-grpc/
mcpaas-mapping/
mcpaas-schema/
mcpaas-proto/
Дополнительные crates mcpaas-mapping, mcpaas-schema и mcpaas-proto нужны затем, чтобы не перегружать mcpaas-core.
4. Детальная декомпозиция по crate
4.1. mcpaas-core
Назначение:
- базовые доменные типы;
- идентификаторы;
- метаданные операций;
- общие контракты и ошибки верхнего уровня.
Что должно лежать в crate:
mcpaas-core/
src/
lib.rs
ids.rs
protocol.rs
operation/
mod.rs
model.rs
status.rs
target.rs
metadata.rs
auth/
mod.rs
profile.rs
secret_ref.rs
errors/
mod.rs
domain.rs
validation.rs
runtime.rs
Описание модулей:
ids.rs- типыOperationId,DescriptorId,ToolIdи другие идентификаторы.protocol.rs- enum протоколов и общие protocol capability flags.operation/model.rs- основная доменная модель операции без технических деталей хранения.operation/status.rs- типы состояний операции.operation/target.rs- базовые protocol-specific target structs.operation/metadata.rs- описание tool, display name, version, tags.auth/profile.rs- типы auth-профилей без привязки к конкретному клиенту.auth/secret_ref.rs- ссылки на секреты, а не сами секреты.errors/*- типизированные ошибки доменного слоя.
Что не должно лежать в crate:
- JSON Schema реализация;
- mapping engine;
- SQL-модели;
- HTTP DTO;
- protobuf parsing;
reqwest,sqlx,tonic,axum.
Причина:
mcpaas-core должен быть максимально стабильным и независимым. Если положить туда все подряд, он станет точкой связности всей системы.
4.2. mcpaas-schema
Назначение:
- внутренняя модель схем;
- нормализация входа и выхода;
- представление полей для UI и runtime;
- преобразование схем из разных источников в единый вид.
Структура:
mcpaas-schema/
src/
lib.rs
schema/
mod.rs
model.rs
field.rs
scalar.rs
object.rs
collection.rs
oneof.rs
enums.rs
normalize/
mod.rs
json.rs
graphql.rs
protobuf.rs
validate/
mod.rs
input.rs
output.rs
Описание:
schema/model.rs- корневая структура схемы.field.rs- описание поля, nullable, required, description.scalar.rs- базовые scalar types.object.rs- вложенные объекты.collection.rs- массивы и map-подобные структуры.oneof.rs- представление protobufoneof.enums.rs- enum-значения и метаданные.normalize/*- преобразование GraphQL и protobuf моделей в единую схему.normalize/json.rs- нормализация загруженных JSON-примеров во внутреннюю schema model.validate/*- проверка JSON относительно внутренней схемы.
Почему отдельный crate:
Схемы будут использоваться почти везде, но это не повод тащить их в core. Иначе core станет тяжелым и начнет менять версию при каждом изменении схемной логики.
4.3. mcpaas-mapping
Назначение:
- описание mapping DSL;
- компиляция mappings в runtime-представление;
- применение mappings к входу и выходу;
- автогенерация чернового mapping по загруженным примерам;
- трассировка ошибок маппинга.
Структура:
mcpaas-mapping/
src/
lib.rs
model/
mod.rs
mapping.rs
source.rs
target.rs
transform.rs
parser/
mod.rs
jsonpath.rs
compile/
mod.rs
plan.rs
infer/
mod.rs
from_samples.rs
from_schema.rs
execute/
mod.rs
input.rs
output.rs
errors.rs
Описание:
model/mapping.rs- описание одного правила mapping.model/source.rs- откуда берем данные:mcp,response,constant.model/target.rs- куда кладем данные:request.path,request.query,request.body,output.model/transform.rs- ограниченный набор допустимых преобразований.parser/jsonpath.rs- единый parser и validator дляJSONPathвыражений.compile/plan.rs- предварительно скомпилированный план маппинга.infer/from_samples.rs- генерация чернового mapping по загруженным примерам JSON.infer/from_schema.rs- генерация чернового mapping по нормализованной схеме.execute/input.rs- применение mappings к запросу.execute/output.rs- применение mappings к ответу.
Антипаттерн, которого нужно избежать:
не помещать mapping-правила в строковые поля, которые потом интерпретируются каждым адаптером по-своему. Mapping должен быть единым движком.
4.4. mcpaas-proto
Назначение:
- работа с
.protoи descriptor set; - извлечение services, methods и message schemas;
- преобразование protobuf metadata во внутренние типы.
Структура:
mcpaas-proto/
src/
lib.rs
descriptor/
mod.rs
loader.rs
source.rs
registry.rs
reflect/
mod.rs
client.rs
model/
mod.rs
service.rs
method.rs
message.rs
field.rs
convert/
mod.rs
to_schema.rs
to_json.rs
from_json.rs
errors.rs
Описание:
descriptor/loader.rs- загрузка descriptor set.descriptor/source.rs- типы источников: upload, file, reflection.descriptor/registry.rs- индексирование описаний для поиска services/methods.reflect/client.rs- клиент server reflection, если будет добавлен.model/*- protobuf-ориентированная промежуточная модель.convert/to_schema.rs- перевод protobuf message вmcpaas-schema.convert/to_json.rsиfrom_json.rs- преобразование runtime payload.
Почему отдельный crate:
protobuf-логика объемная и быстро начнет загрязнять gRPC adapter, если не отделить ее сразу.
4.5. mcpaas-registry
Назначение:
- хранение операций, схем, descriptor links и статусов;
- выдача draft/published представлений;
- поиск активных операций для runtime и MCP server.
Структура:
mcpaas-registry/
src/
lib.rs
model/
mod.rs
record.rs
draft.rs
published.rs
repo/
mod.rs
operation_repo.rs
descriptor_repo.rs
service/
mod.rs
create_operation.rs
update_operation.rs
publish_operation.rs
list_operations.rs
get_runtime_view.rs
storage/
mod.rs
sqlite.rs
postgres.rs
cache/
mod.rs
runtime_cache.rs
errors.rs
Описание:
model/record.rs- DB-aligned record model.model/draft.rs- модель черновика.model/published.rs- модель опубликованной операции.repo/*- контракты репозиториев.service/*- use case операции над реестром.storage/*- реализации репозиториев наsqlx.cache/runtime_cache.rs- кэш активных операций.
Правило:
registry не выполняет операции и не знает о reqwest/tonic. Он только хранит и отдает согласованные представления.
4.6. mcpaas-runtime
Назначение:
- исполнение операций;
- orchestration между схемой, mapping и адаптерами;
- выдача нормализованного результата.
Структура:
mcpaas-runtime/
src/
lib.rs
executor/
mod.rs
operation_executor.rs
input_prepare.rs
output_finalize.rs
adapter/
mod.rs
traits.rs
dispatch.rs
context/
mod.rs
execution_context.rs
model/
mod.rs
runtime_operation.rs
prepared_request.rs
adapter_response.rs
errors.rs
Описание:
executor/operation_executor.rs- основной orchestration use case.executor/input_prepare.rs- валидация входа и применение input mapping.executor/output_finalize.rs- обработка adapter response и output mapping.adapter/traits.rs- общий контракт для протокольных адаптеров.adapter/dispatch.rs- выбор адаптера по протоколу.context/execution_context.rs- correlation id, deadlines, tracing data.model/runtime_operation.rs- runtime-ready представление операции.
Правило:
runtime не должен знать, где хранится операция. Он получает уже готовую runtime_operation.
4.7. mcpaas-adapter-rest
Назначение:
- построение и выполнение REST-вызовов.
Структура:
mcpaas-adapter-rest/
src/
lib.rs
client.rs
request/
mod.rs
build.rs
path.rs
query.rs
headers.rs
body.rs
response/
mod.rs
decode.rs
normalize.rs
errors.rs
Правило:
REST adapter не валидирует MCP input и не знает о registry. Он получает уже подготовленный request contract.
4.8. mcpaas-adapter-graphql
Назначение:
- построение и выполнение GraphQL-вызовов.
Структура:
mcpaas-adapter-graphql/
src/
lib.rs
client.rs
request/
mod.rs
build.rs
variables.rs
response/
mod.rs
decode.rs
extract.rs
errors.rs
Правило:
GraphQL adapter не занимается introspection по умолчанию и не содержит редактор схем. Он только исполняет подготовленный operation template.
Дополнительное ограничение:
один GraphQL tool соответствует одному заранее определенному query или mutation. Адаптер не должен принимать от LLM произвольный GraphQL-документ, потому что в MCP-модели операция должна оставаться узкой, предсказуемой и валидируемой по фиксированной схеме.
4.9. mcpaas-adapter-grpc
Назначение:
- выполнение unary gRPC-вызовов на основе уже выбранного метода и descriptor metadata.
Структура:
mcpaas-adapter-grpc/
src/
lib.rs
channel.rs
invoke/
mod.rs
unary.rs
request/
mod.rs
build.rs
response/
mod.rs
decode.rs
errors.rs
Правило:
gRPC adapter не должен сам парсить .proto. Этим занимается mcpaas-proto. Иначе в адаптере смешаются discovery и execution.
Дополнительное ограничение:
adapter поддерживает только unary RPC. Streaming-вызовы не реализуются, потому что целевая модель MCP tool в проекте соответствует сценарию запрос -> ответ, а не долгоживущей сессии обмена сообщениями.
4.10. admin-api
Назначение:
- HTTP API для UI;
- координация use case создания, редактирования, тестирования и публикации.
Структура:
apps/admin-api/
src/
main.rs
app.rs
state.rs
router.rs
http/
mod.rs
dto/
mod.rs
operation.rs
mapping.rs
test_run.rs
handlers/
mod.rs
create_operation.rs
update_operation.rs
publish_operation.rs
list_operations.rs
test_operation.rs
export_operation_yaml.rs
import_operation_yaml.rs
upload_json_samples.rs
upload_proto.rs
list_grpc_services.rs
response.rs
services/
mod.rs
operation_service.rs
descriptor_service.rs
config_portability_service.rs
test_service.rs
errors.rs
Правила:
- HTTP DTO не должны протекать в доменный слой;
- handlers должны быть тонкими;
- orchestration должна жить в
services/*; state.rsне должен разрастаться в огромную структуру. Лучше использовать вложенные state-компоненты или отдельные service bundles.- import/export конфигурации в
YAMLдолжен быть отдельным use case, а не побочным эффектом обычного CRUD.
4.11. mcp-server
Назначение:
- публикация MCP tools;
- вызов runtime по имени tool;
- обновление активного списка tools.
Структура:
apps/mcp-server/
src/
main.rs
app.rs
state.rs
tools/
mod.rs
list.rs
call.rs
cache.rs
translate/
mod.rs
to_mcp_tool.rs
from_mcp_input.rs
to_mcp_output.rs
errors.rs
Правило:
mcp-server не должен реализовывать business rules публикации. Он читает уже опубликованные операции и транслирует их в MCP.
4.12. ui
Назначение:
- интерфейс оператора.
Предлагаемая frontend-структура:
apps/ui/
src/
main.tsx
app/
router.tsx
providers.tsx
pages/
operation-list/
operation-create/
operation-edit/
operation-test/
grpc-browser/
features/
operation-form/
mapping-editor/
sample-upload/
grpc-method-picker/
schema-viewer/
publish-operation/
entities/
operation/
descriptor/
shared/
api/
lib/
ui/
config/
Правило:
UI должен декомпозироваться по пользовательским сценариям, а не по типам файлов уровня "все компоненты в одной папке".
5. Правила зависимостей между crate
Целевой граф зависимостей:
mcpaas-core
mcpaas-schema -> mcpaas-core
mcpaas-mapping -> mcpaas-core
mcpaas-proto -> mcpaas-core, mcpaas-schema
mcpaas-registry -> mcpaas-core, mcpaas-schema, mcpaas-mapping
mcpaas-adapter-rest -> mcpaas-core
mcpaas-adapter-graphql -> mcpaas-core
mcpaas-adapter-grpc -> mcpaas-core, mcpaas-proto
mcpaas-runtime -> mcpaas-core, mcpaas-schema, mcpaas-mapping, adapters
admin-api -> mcpaas-core, mcpaas-schema, mcpaas-mapping, mcpaas-proto, mcpaas-registry, mcpaas-runtime
mcp-server -> mcpaas-core, mcpaas-registry, mcpaas-runtime
Критические ограничения:
mcpaas-coreни от кого не зависит;- адаптеры не зависят от
registry; runtimeне зависит отadmin-apiиmcp-server;registryне зависит от адаптеров;uiзависит только от HTTP API.
6. Границы публичных API модулей
Чтобы структура не разъехалась, нужно заранее ограничить публичность.
Рекомендуемое правило:
- наружу экспортируются только корневые доменные типы, service-интерфейсы и ошибки;
- внутренние DTO, record-модели и промежуточные builder-структуры остаются
pub(crate); - не реэкспортировать целые деревья модулей без необходимости;
- не делать
mod utils, если можно назвать модуль по смыслу.
Пример плохого решения:
pub mod common;pub mod helpers;pub struct AppContext { ... 25 полей ... }
Пример правильного решения:
pub struct OperationExecutorpub trait OperationRepositorypub struct RuntimeOperation
7. Какие большие структуры точно не нужны
Ниже список сущностей, которые легко превращаются в антипаттерн:
- одна гигантская
Operation, содержащая сразу все REST, GraphQL и gRPC поля; - один
MappingConfig, содержащий и input, и output, и transforms, и validation rules без разделения; - единый
AppStateсо всеми репозиториями, клиентами, кэшами и конфигами; - один
ProtocolAdapterс ветвлениемmatch protocolвнутри на сотни строк; - один
SchemaFieldбез выделения object/array/enum/oneof вариантов.
Правильный подход:
- отдельные target-типы по протоколам;
- отдельные input/output mapping модели;
- отдельные bounded state-наборы для каждого приложения;
- отдельные adapter crates;
- выделенная иерархия schema types.
8. Порядок реализации без архитектурного долга
Рекомендуемый порядок разработки:
mcpaas-coremcpaas-schemamcpaas-mappingmcpaas-registrymcpaas-adapter-restmcpaas-runtimeadmin-apiuimcpaas-protomcpaas-adapter-grpcmcpaas-adapter-graphqlmcp-server
Причина такого порядка:
- сначала фиксируется доменная модель;
- затем схема и mapping как самые чувствительные части;
- затем реестр и базовое выполнение REST;
- после этого можно собирать UI и только потом наращивать сложные протоколы.
9. Практический итог
Если придерживаться этой декомпозиции, то:
mcpaas-coreостанется маленьким и стабильным;- schema и mapping не смешаются с transport-логикой;
- protobuf discovery не загрязнит gRPC runtime;
admin-apiиmcp-serverостанутся тонкими входными слоями;- добавление нового протокола не потребует переписывать половину проекта.
Это и есть целевая архитектурная дисциплина проекта: отдельные слои, отдельные модели, минимально необходимая публичность и отсутствие "универсальных" структур, в которые со временем начинает стекаться вся система.