19 KiB
NDC Module Foundry — базовый MCP-контур
Назначение
NDC Module Foundry — модульный контур поверх канонического NODE.DC Design Guideline. Он создаёт и редактирует экземпляры готовых страниц в Applications; сам Page Library и его шаблоны остаются неизменяемым каноном.
MCP не вводит новую оркестрацию. Доступ выдаётся уже существующему AI Workspace Assistant через его generic entitlement adapter. Поэтому ассистент может продолжать работать с Engine, Ops, Ontology и другими подключёнными модулями по действующим правилам платформы, а Foundry определяет только границы действий внутри Foundry.
Границы v0.1
| Разрешено | Не разрешено |
|---|---|
| Просматривать Page Library и экземпляры Applications | Менять канонический Page Library или дизайн-компоненты |
| Создавать application instance | Удалять application instance через MCP |
| Изменять название, slug и описание instance | Создавать свободный canvas или произвольный React-интерфейс |
| Добавлять повторные instances зарегистрированной страницы | Вызывать Engine, provider API или произвольный внешний endpoint из Foundry MCP |
| Создавать/обновлять provider-neutral map pin bindings | Хранить provider tokens, transport payload или credentials в manifest |
| Связывать versioned data product с approved Map entity-stream slot | Хранить provider ID, tenant/connection, endpoint или credential в data binding |
| Управлять server-owned consumer только для persisted approved binding | Передавать reader capability, EDP URL или raw provider payload через MCP |
Каждая запись требует idempotencyKey. Операция сохраняется в persistent runtime volume и повторный вызов с тем же ключом и тем же входом вернёт исходный результат без дублирования. Повтор ключа с иным входом завершается конфликтом.
MCP endpoint
POST /api/mcp
Поддерживается MCP protocol 2025-06-18. Endpoint принимает JSON-RPC initialize, tools/list, tools/call и ping.
Обязательные HTTP-заголовки каждого вызова:
Authorization: Bearer <Foundry capability or Foundry Agent credential>
MCP-Protocol-Version: 2025-06-18
Endpoint поддерживает два существующих контура входа, не смешивая их:
- AI Workspace получает короткоживущую Foundry capability после штатной
entitlement-проверки. Она подписана существующим внутренним service
credential, привязана к
actorIdиownerKey, живёт не более 10 минут и не раскрывает platform credential worker-у; - внешний Codex получает отдельный durable Foundry Agent credential через
настройки текущего пользователя Foundry. Credential действует до явного
revokeи не является AI Workspace capability.
Заголовки с actor/owner от клиента не принимаются: пользовательский контекст извлекается только из проверенной capability или server-side записи Agent.
Доступные инструменты:
foundry_statusfoundry_list_applicationsfoundry_get_applicationfoundry_create_applicationfoundry_update_application_metadatafoundry_add_page_instancefoundry_upsert_map_pin_bindingfoundry_upsert_map_data_product_bindingfoundry_plan_map_data_product_consumerfoundry_apply_map_data_product_consumerfoundry_get_map_data_product_consumer_statusfoundry_accept_map_data_product_consumerfoundry_rollback_map_data_product_consumer
foundry_upsert_map_pin_binding хранит только визуальную, provider-neutral привязку elevated-spike: стабильный id, subject, координаты, semantic status и ссылку на источник сущности. Поток живых данных не передаётся в MCP по одной позиции: визуальная привязка и поток данных будут связываться следующими contract/ontology слоями.
foundry_upsert_map_data_product_binding сохраняет только декларацию
data product → Map entity-stream slot: versioned data product id, semantic
types и допустимую field projection. Endpoint, provider, tenant, connection,
token, credential и raw payload валидатор отклоняет. Page runtime получает
scoped snapshot/patch поток через Platform, но не через Foundry MCP.
Пять consumer-инструментов управляют тем же runtime, который обслуживает Map
Page. plan проверяет persisted binding, Data Product version/delivery,
versioned policy и безопасно показывает readerGrantAction=ensure|reuse.
Если grant отсутствует, EDP сам разрешает единственный active writer scope по
Data Product id; provider/tenant/connection в Foundry не возвращаются. apply
принимает exact planId, подписанно передаёт EDP только SHA-256 digest нового
target-scoped token, коммитит snapshot и включает consumer; status возвращает только safe cursor,
счётчики subject/status/reconnect и количество viewers/upstream streams;
accept берёт bounded diagnostic lease; rollback останавливает consumer, но
сохраняет последний safe snapshot. Capability value, grant path, internal URL и
fact attributes в MCP diagnostics не возвращаются.
Runtime data-product boundary
Для Map Page Foundry предоставляет только same-origin runtime routes:
GET /api/applications/:applicationId/pages/:pageId/data-bindings/:bindingId/snapshot
GET /api/applications/:applicationId/pages/:pageId/data-bindings/:bindingId/history?from=:iso&to=:iso&resolutionMs=:ms&sourceIds=:ids&limit=:n&cursor=:opaque
GET /api/applications/:applicationId/pages/:pageId/data-bindings/:bindingId/stream?after=:cursor
Маршрут разрешает persisted binding, а затем server-owned consumer находит
opaque EDP reader grant по sha256(applicationId/pageId/bindingId). Нормальный
grant создаётся внутри persistent private runtime Foundry; runner монтирует
отдельный Ed25519 private key только для подписи digest-only provisioner
request, а EDP получает только public trust. Старый root-owned read-only grant
directory остаётся fallback для уже выданных grant. Сам token передаётся
только как Authorization во внутренний External Data Plane и никогда не
попадает в browser, manifest, MCP или лог. В browser отдаётся только safe Foundry projection канонического data-product envelope:
snapshot, bounded nodedc.data-product.history/v1, safe
nodedc.data-product.patch/v1 upserts и cursor. History query проходит через
тот же exact binding/read grant и не создаёт L2 execution на каждого viewer.
Last-Event-ID
авторитетнее старого after при автоматическом SSE reconnect.
Consumer state хранится отдельно от application manifest в persistent runtime volume. Snapshot atomically заменяет subject projection, включая явный empty snapshot. Patch применяется только от exact previous cursor; новый cursor и semantic state сначала сохраняются, затем fan-out отправляется browsers. Повторный cursor идемпотентно игнорируется, gap вызывает snapshot rebase. Несколько viewers одного binding делят один upstream EDP stream; закрытие последнего viewer закрывает subscription, но не влияет на независимый producer в Engine L2.
Freshness и remove принадлежат versioned provider-neutral policy из
registry/data-product-consumer-policies.json. Stale вычисляется по
observedAt; terminal statuses сохраняются. Временная transport/credential
ошибка не удаляет subject. Удаление допустимо только при отсутствии в
авторитетном snapshot rebase или по canonical tombstone/revoked operation.
Renderer получает стабильный sourceId + semanticType, persisted coordinates
и Foundry-owned presentationStatus; provider identity на стиль и lifecycle не
влияет.
Внешний Codex: Foundry + отдельная Ontology MCP
В профиле Foundry раздел Настройки → Codex Agent API создаёт Agent текущего
пользователя и выдаёт одноразовую setup-команду. Команда устанавливает в Codex
две независимые MCP-конфигурации:
nodedc_module_foundry → POST /api/mcp
nodedc_ontology → POST /api/ontology-mcp
Это одна операция установки, но не одна MCP. Foundry credential принимается
только /api/mcp, Ontology credential — только /api/ontology-mcp; их
перекрёстное использование отклоняется. Ontology route после своей проверки
проксирует MCP JSON-RPC во внутренний Ontology Core /mcp с уже существующим
server-only NODEDC_INTERNAL_ACCESS_TOKEN. Foundry не импортирует ontology
tools в свой список и не становится маршрутизатором платформенных MCP.
Agent credentials не имеют календарного срока жизни: они валидны до явного
отзыва Agent. Setup code одноразовый и живёт 15 минут. Raw credentials
возвращаются только в момент redeem; в Foundry runtime сохраняются только
SHA-256 digests, device metadata и bounded audit. Один revoke закрывает обе
credentials конкретного Agent.
Первый срез намеренно ограничен текущим аутентифицированным пользователем: Codex может создавать и настраивать его Applications средствами Foundry MCP и читать общую Ontology через отдельную read-only MCP. Sharing, роли, межпользовательская видимость, release/publication и новые product ACL в этот срез не входят.
Установщик идемпотентно обновляет только блоки nodedc_module_foundry и
nodedc_ontology в ~/.codex/config.toml, сохраняет остальные MCP (включая
Engine и Ops), делает backup конфигурации и устанавливает skill
foundry-context. Перед успешным завершением он выполняет initialize и
tools/list для обеих MCP. После установки Codex Desktop нужно полностью
перезапустить.
Entitlement для AI Workspace
POST /api/ai-workspace/entitlements
Endpoint предназначен для уже существующего AI Workspace generic adapter. Он принимает его штатный request-контракт и выдаёт динамический MCP grant только если совпала одна из политик:
FOUNDRY_ALLOW_ALL_AUTHENTICATED=true— временно разрешает всем уже аутентифицированным пользователям;FOUNDRY_ALLOWED_OWNER_IDS— список дополнительных разрешённых user id / owner key;FOUNDRY_ALLOWED_OWNER_GROUPS— список дополнительных разрешённых групп.
По умолчанию доступ получает user_root (dcctouch@gmail.com) и техническая
группа Authentik nodedc:module-foundry:access. В Launcher эта группа выдаёт
роль сервиса member; все остальные пользователи получают «нет доступа» до
явной выдачи права администратором Hub. Многопользовательское владение
Applications в v0.1 не вводится: это общий внутренний контур с аудитом actor id.
Для production предпочтительны явно заданные users/groups; режим ALLOW_ALL_AUTHENTICATED допустим только для внутренней песочницы.
Штатный запрос adapter выглядит так:
{
"schemaVersion": "ai-workspace.entitlement-request.v1",
"appId": "module-foundry",
"owner": {
"userId": "authenticated-user-id",
"key": "owner-or-workspace-key",
"groups": ["optional-group"]
},
"activeContext": {},
"runContext": {},
"requestedAt": "2026-07-13T00:00:00.000Z"
}
Server-side configuration
Все значения находятся только в server environment. В browser bundle не передаются tokens, entitlement keys и runtime volume paths.
FOUNDRY_PUBLIC_URL=https://<future-foundry-domain>
FOUNDRY_MCP_URL=https://<future-foundry-domain>/api/mcp
# Existing NODE.DC server-to-server credential; never send it to a browser or worker.
NODEDC_INTERNAL_ACCESS_TOKEN=<existing-platform-service-value>
# Internal-only Ontology Core address; never expose the Core directly.
NODEDC_ONTOLOGY_CORE_URL=http://ontology-core:8080
FOUNDRY_MCP_CAPABILITY_TTL_MS=600000
# Optional exceptional identities, not the default dcctouch superadmin grant.
FOUNDRY_ALLOWED_OWNER_IDS=<comma-separated-extra-ids>
FOUNDRY_ALLOWED_OWNER_GROUPS=<comma-separated-extra-groups>
FOUNDRY_ALLOW_ALL_AUTHENTICATED=false
FOUNDRY_MCP_ALLOWED_ORIGINS=https://<ai-workspace-domain>
Foundry не требует у пользователя вводить platform secret.
NODEDC_INTERNAL_ACCESS_TOKEN — уже существующий server-to-server credential
платформы: он находится только в server environment и используется для
Launcher/Authentiк handoff, внутренней entitlement-проверки и server-side
Ontology Core proxy. AI Workspace worker получает лишь короткоживущую
capability; внешний Codex — отдельные Agent credentials, но не internal token.
После появления домена в deployment AI Workspace добавляется только штатная настройка adapter; новый worker, отдельная оркестрация или специальный bridge не нужны:
AI_WORKSPACE_ENTITLEMENT_ADAPTERS_JSON='{"module-foundry":{"url":"https://<future-foundry-domain>/api/ai-workspace/entitlements","required":false}}'
Если в переменной уже есть другие adapters, module-foundry добавляется в тот же JSON-объект — существующие ops, engine, launcher и другие grants не заменяются.
Deployment package
Foundry подготовлен к отдельному deployment как stateless server + один named persistent volume. Runtime volume содержит Applications, Design Profiles, idempotency audit, data-product consumer state/cursors, media uploads, Agent/device records, setup-code digests и Agent audit. Он является единственным источником изменяемого Foundry state; Git не используется для runtime-данных и tile cache. Raw Foundry/Ontology Agent credentials и EDP reader capabilities в volume не записываются.
cp .env.example .env
# использовать уже имеющийся NODEDC_INTERNAL_ACCESS_TOKEN из server environment
docker compose --env-file .env -f infra/docker-compose.module-foundry.yml up -d --build
curl http://127.0.0.1:9920/healthz
Внешний маршрут подготовлен: https://foundry.nodedc.ru → 172.22.0.222:9920 → container :3333. Compose на NAS должен слушать именно 172.22.0.222:9920, а не все интерфейсы. До запуска Foundry proxy закономерно возвращает 502; это проверяемый признак, что DNS/TLS/proxy уже доходят до внутреннего destination. Публикация допустима только после проверки Launcher's handoff, server-side session revalidation, синхронизации Authentik-группы и выдачи Hub access. Только после этого добавляется Foundry entitlement adapter в platform AI Workspace deployment.
Следующие слои
- Онтологический contract приложения, страницы, page instance, Map Page и visual entities.
- Runtime adapter между ontology/gateway потоками и сохранёнными visual bindings.
- Реальные
elevated-spike, targets, zones, routes и toolbar commands на instance Map Page. - Access/Hub registration и публикация module route.
- Отдельная пустая программируемая страница — только после того, как готовые page templates и их MCP-контуры отработаны.