20 KiB
Модель данных
1. Назначение документа
Этот документ фиксирует формальную модель данных платформы. Его цель - определить такие структуры, которые можно без существенных изменений перенести в:
- Rust domain types,
- HTTP DTO,
- структуру таблиц БД,
- runtime-представление operation,
- UI-формы и конфигурационные экраны.
Документ не привязан к конкретной СУБД, но задает каноническую JSON-модель сущностей.
2. Общие принципы модели
2.1. Одна операция - один tool
Каждая Operation соответствует одному MCP tool. Это особенно важно для:
- GraphQL, где одна operation соответствует одному конкретному
queryилиmutation; - gRPC, где одна operation соответствует одному unary-методу;
- REST, где одна operation соответствует одному endpoint-сценарию.
2.2. Внутренний транспортный формат - JSON
Независимо от внешнего протокола внутри системы данные должны быть представлены в JSON-ориентированном виде. Даже если внешний вызов работает с protobuf, runtime, mapping и UI опираются на нормализованный JSON.
2.3. Mapping всегда явный
Даже если система умеет строить черновой mapping по примерам данных, итоговая конфигурация mapping должна быть явно сохранена в operation. Нельзя полагаться на неявную "магию" сопоставления во время выполнения.
2.4. JSONPath как единый язык адресации
Для input и output mapping используется JSONPath. Это позволяет единообразно ссылаться на вложенные поля во входе, промежуточном представлении запроса и нормализованном ответе.
2.5. YAML как формат обмена конфигурацией
Помимо канонической JSON-модели система должна поддерживать импорт и экспорт конфигураций в YAML. Это внешний формат обмена, а не отдельная доменная модель.
3. Корневая сущность Operation
Operation - основная конфигурационная сущность платформы.
Поля
id- уникальный идентификатор операции.name- стабильное внутреннее имя.display_name- отображаемое имя в UI.protocol-rest,graphql,grpc.status-draft,testing,published,archived.version- версия конфигурации операции.target- описание внешней операции.input_schema- схема MCP-входа.output_schema- схема MCP-выхода.input_mapping- правила подготовки внешнего запроса.output_mapping- правила формирования MCP-ответа.execution_config- auth, headers, timeout, retries и protocol-specific execution settings.tool_description- описание tool для MCP и LLM.samples- загруженные образцы JSON и schema artifacts.generated_draft- автоматически построенный черновик схем и mappings.config_export- опциональные метаданные экспортируемой конфигурации.created_atupdated_atpublished_at
Пример
{
"id": "op_01hr7w0m6p8x9z4n7s2k3q5t6u",
"name": "crm_create_lead",
"display_name": "Create Lead",
"protocol": "rest",
"status": "draft",
"version": 3,
"target": {
"kind": "rest",
"base_url": "https://api.example.com",
"method": "POST",
"path_template": "/v1/leads"
},
"input_schema": {
"type": "object",
"fields": {
"name": {
"type": "string",
"required": true
},
"email": {
"type": "string",
"required": true
}
}
},
"output_schema": {
"type": "object",
"fields": {
"id": {
"type": "string",
"required": true
},
"status": {
"type": "string",
"required": true
}
}
},
"input_mapping": {
"rules": [
{
"source": "$.mcp.name",
"target": "$.request.body.name"
},
{
"source": "$.mcp.email",
"target": "$.request.body.email"
}
]
},
"output_mapping": {
"rules": [
{
"source": "$.response.body.id",
"target": "$.output.id"
},
{
"source": "$.response.body.status",
"target": "$.output.status"
}
]
},
"execution_config": {
"timeout_ms": 10000,
"auth_profile_ref": "auth_01hr7x8rj2d8nq8v0c4m4t1r9e"
},
"tool_description": {
"title": "Create CRM lead",
"description": "Creates a new lead in CRM by name and email."
},
"samples": {
"input_json_sample_ref": "file_01hr7xj7z4k1t0qm0cxsw6f1wx",
"output_json_sample_ref": "file_01hr7xkvt3m1p6ms3m7r2dr8wz"
},
"generated_draft": {
"status": "available",
"source_types": ["input_json_sample", "output_json_sample"]
},
"config_export": {
"format_version": "1",
"export_mode": "portable"
},
"created_at": "2026-03-25T08:00:00Z",
"updated_at": "2026-03-25T08:10:00Z",
"published_at": null
}
4. Target
Target описывает конкретный внешний вызов. Это discriminated union по протоколу.
4.1. RestTarget
{
"kind": "rest",
"base_url": "https://api.example.com",
"method": "PATCH",
"path_template": "/v1/users/{userId}",
"static_headers": {
"X-App-Source": "mcpaas"
}
}
Поля:
kindbase_urlmethodpath_templatestatic_headers
4.2. GraphqlTarget
{
"kind": "graphql",
"endpoint": "https://api.example.com/graphql",
"operation_type": "mutation",
"operation_name": "CreateLead",
"query_template": "mutation CreateLead($input: LeadInput!) { createLead(input: $input) { id status } }",
"response_path": "$.response.body.data.createLead"
}
Поля:
kindendpointoperation_typeoperation_namequery_templateresponse_path
4.3. GrpcTarget
{
"kind": "grpc",
"server_addr": "https://grpc.example.com:443",
"package": "crm.v1",
"service": "LeadService",
"method": "CreateLead",
"descriptor_ref": "desc_01hr7yn4d6g1x6vwt7h9n0e7ab"
}
Поля:
kindserver_addrpackageservicemethoddescriptor_ref
5. Schema
Schema - нормализованное описание входа или выхода. Это не JSON Schema в полном объеме, а внутренняя структурная модель, удобная для UI и runtime.
Базовая форма
{
"type": "object",
"description": "Lead input",
"fields": {
"name": {
"type": "string",
"required": true,
"description": "Lead full name"
},
"tags": {
"type": "array",
"required": false,
"items": {
"type": "string"
}
}
}
}
Поддерживаемые типы
objectarraystringintegernumberbooleanenumnulloneof
Модель поля
{
"type": "string",
"required": true,
"nullable": false,
"description": "User email",
"default": null
}
Тип объекта:
{
"type": "object",
"required": true,
"fields": {
"email": {
"type": "string",
"required": true
}
}
}
Тип массива:
{
"type": "array",
"required": false,
"items": {
"type": "object",
"fields": {
"id": {
"type": "string",
"required": true
}
}
}
}
Нормализация protobuf-структур
Для protobuf -> schema bridge дополнительно фиксируются такие правила:
repeatedполе преобразуется вarray;enumпреобразуется вtype: enumсо спискомenum_values;map<K, V>преобразуется вarrayобъектов{ key, value };oneofпреобразуется вtype: oneof, где каждый вариант представлен объектом с одним допустимым полем.
6. MappingSet и MappingRule
MappingSet - набор правил преобразования между внутренним MCP input/output и protocol-specific request/response model.
MappingSet
{
"rules": [
{
"source": "$.mcp.user_id",
"target": "$.request.path.userId"
}
]
}
MappingRule
Поля:
source-JSONPathв исходном контексте.target-JSONPathв целевом контексте.required- обязательно ли правило для корректного вызова.default_value- значение по умолчанию.transform- встроенное преобразование.condition- условие применения правила.notes- служебное описание для UI.
Пример:
{
"source": "$.mcp.profile.email",
"target": "$.request.body.contact.email",
"required": true,
"default_value": null,
"transform": {
"kind": "identity"
},
"condition": null,
"notes": "Map email to CRM contact payload"
}
Контексты source и target
Для input mapping:
$.mcp.*$.request.path.*$.request.query.*$.request.headers.*$.request.body.*$.request.variables.*$.request.grpc.*
Для output mapping:
$.response.body.*$.response.data.*$.response.grpc.*$.output.*
Transform
Для MVP transformations должны быть ограничены:
identityto_stringto_numberto_booleanjoinsplitwrap_arrayunwrap_singleton
Пример:
{
"kind": "to_string"
}
7. ExecutionConfig
ExecutionConfig задает параметры выполнения operation.
{
"timeout_ms": 10000,
"retry_policy": {
"max_attempts": 1
},
"auth_profile_ref": "auth_01hr7x8rj2d8nq8v0c4m4t1r9e",
"headers": {
"X-Client": "mcpaas"
},
"protocol_options": {
"rest": null,
"graphql": null,
"grpc": {
"use_tls": true
}
}
}
Поля:
timeout_msretry_policyauth_profile_refheadersprotocol_options
Важно:
- здесь хранятся execution settings, а не описание бизнес-схемы;
protocol_optionsдолжны оставаться узкими и протокол-специфичными;- секреты не хранятся внутри operation, только ссылки на secret store или auth profile.
8. AuthProfile
AuthProfile - переиспользуемая конфигурация аутентификации для внешних вызовов.
Operation ссылается на auth profile через auth_profile_ref, а не хранит секреты внутри себя.
Базовая форма
{
"id": "auth_01hr7x8rj2d8nq8v0c4m4t1r9e",
"name": "crm-prod-bearer",
"kind": "bearer",
"config": {
"header_name": "Authorization",
"secret_ref": "secret://auth/crm-prod-token"
},
"created_at": "2026-03-25T08:00:00Z",
"updated_at": "2026-03-25T08:10:00Z"
}
Поддерживаемые виды
bearerbasicapi_key_headerapi_key_query
MVP-решение по секретам
Для MVP секреты должны храниться не в open text внутри operation version, а в отдельном secret storage слое.
Рекомендуемое решение:
- логическая ссылка в формате
secret://...; - реальное значение хранится в приложении либо в зашифрованном хранилище, либо в env-backed secret store;
- в документации и YAML export секреты всегда представляются только через
secret_ref.
9. ToolDescription
ToolDescription задает MCP-представление operation.
{
"title": "Get customer profile",
"description": "Returns a customer profile by external customer identifier.",
"tags": ["crm", "customer"],
"examples": [
{
"input": {
"customer_id": "123"
}
}
]
}
Поля:
titledescriptiontagsexamples
10. Samples
Samples связывает operation с загруженными артефактами, на основе которых может быть построен черновик.
{
"input_json_sample_ref": "file_01hr7xj7z4k1t0qm0cxsw6f1wx",
"output_json_sample_ref": "file_01hr7xkvt3m1p6ms3m7r2dr8wz",
"proto_file_ref": null,
"descriptor_ref": null
}
Поля:
input_json_sample_refoutput_json_sample_refproto_file_refdescriptor_ref
Примечания:
- для REST чаще всего используются входной и выходной JSON samples;
- для GraphQL чаще всего полезен sample ответа;
- для gRPC основным artifact остается
.protoили descriptor set, но input/output JSON samples тоже могут использоваться для MCP-facing модели.
11. GeneratedDraft
GeneratedDraft хранит результат автоматической генерации схем и mappings.
{
"status": "available",
"source_types": ["input_json_sample", "output_json_sample"],
"generated_at": "2026-03-25T08:05:00Z",
"input_schema_generated": true,
"output_schema_generated": true,
"input_mapping_generated": true,
"output_mapping_generated": true,
"warnings": [
"Field $.response.body.meta was not mapped automatically"
]
}
Поля:
status-none,available,stale,failedsource_typesgenerated_atinput_schema_generatedoutput_schema_generatedinput_mapping_generatedoutput_mapping_generatedwarnings
Важно:
- generated draft - это не runtime-источник истины;
- runtime использует только сохраненные
input_schema,output_schema,input_mapping,output_mapping; - generated draft нужен как вспомогательный слой для UI и ускорения конфигурирования.
12. Runtime view
Для исполнения operation должно существовать упрощенное runtime-представление без UI-специфики.
{
"id": "op_01hr7w0m6p8x9z4n7s2k3q5t6u",
"protocol": "rest",
"target": {
"kind": "rest",
"base_url": "https://api.example.com",
"method": "POST",
"path_template": "/v1/leads"
},
"input_schema": { "type": "object", "fields": {} },
"output_schema": { "type": "object", "fields": {} },
"input_mapping": { "rules": [] },
"output_mapping": { "rules": [] },
"execution_config": {
"timeout_ms": 10000
}
}
Runtime view должно:
- не содержать UI draft metadata;
- не зависеть от raw uploaded files;
- быть готовым к немедленному исполнению адаптером.
13. YAML-конфигурация
Для импорта и экспорта система должна поддерживать YAML-представление operation.
Принцип:
- внутренняя доменная модель одна;
JSONиYAML- это два способа сериализации одной и той же конфигурации;- runtime не зависит от конкретного формата файла;
YAMLнужен для переносимости и ручного редактирования.
Базовая структура YAML
format_version: "1"
kind: operation
operation:
id: op_01hr7w0m6p8x9z4n7s2k3q5t6u
name: crm_create_lead
display_name: Create Lead
protocol: rest
status: draft
version: 3
target:
kind: rest
base_url: https://api.example.com
method: POST
path_template: /v1/leads
input_schema:
type: object
fields:
name:
type: string
required: true
email:
type: string
required: true
output_schema:
type: object
fields:
id:
type: string
required: true
status:
type: string
required: true
input_mapping:
rules:
- source: $.mcp.name
target: $.request.body.name
- source: $.mcp.email
target: $.request.body.email
output_mapping:
rules:
- source: $.response.body.id
target: $.output.id
- source: $.response.body.status
target: $.output.status
execution_config:
timeout_ms: 10000
auth_profile_ref: auth_01hr7x8rj2d8nq8v0c4m4t1r9e
tool_description:
title: Create CRM lead
description: Creates a new lead in CRM by name and email.
Требования к YAML import/export
- формат должен быть детерминированным;
- структура должна быть человекочитаемой;
- импорт должен валидировать схему, mapping и protocol-specific target;
- экспорт не должен включать секреты в открытом виде;
- ссылки на внешние артефакты допустимы, но режим экспорта должен быть явным.
Режимы экспорта
Минимально стоит предусмотреть два режима:
portable- экспорт только конфигурации operation и ссылок на внешние артефакты;bundle- экспорт конфигурации operation вместе с вложенными sample metadata и descriptor metadata, если это допустимо.
Для MVP можно начать только с portable.
14. Что важно не допустить
- одну гигантскую
Operation, в которой protocol-specific поля лежат вперемешку; - неявный mapping, который не сохраняется после генерации черновика;
- смешивание uploaded artifacts и runtime-ready configuration;
- хранение секретов внутри operation;
- хранение реальных auth credentials внутри YAML export;
- произвольные пользовательские скрипты в mapping;
- YAML-экспорт, который становится отдельной несовместимой моделью по отношению к доменной структуре.
15. Практический итог
Эта модель задает основу для:
- Rust structs в
mcpaas-core,mcpaas-schema,mcpaas-mapping; - DTO для
admin-api; - таблиц
operations,operation_versions,operation_samples,operation_descriptors; - import/export layer для
YAMLконфигураций; - runtime view, который будет передаваться в
mcpaas-runtime.
Следующим логическим шагом после этого документа должна стать схема БД, в которой эти сущности будут разложены по таблицам и связям.