NODEDC_DESIGN_GUIDELINE/docs/MODULE_FOUNDRY_MCP.md

253 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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-заголовки каждого вызова:
```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_status`
- `foundry_list_applications`
- `foundry_get_application`
- `foundry_create_application`
- `foundry_update_application_metadata`
- `foundry_add_page_instance`
- `foundry_upsert_map_pin_binding`
- `foundry_upsert_map_data_product_binding`
- `foundry_plan_map_data_product_consumer`
- `foundry_apply_map_data_product_consumer`
- `foundry_get_map_data_product_consumer_status`
- `foundry_accept_map_data_product_consumer`
- `foundry_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:
```text
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-конфигурации:
```text
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 выглядит так:
```json
{
"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.
```dotenv
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 не нужны:
```text
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 не записываются.
```bash
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.
## Следующие слои
1. Онтологический contract приложения, страницы, page instance, Map Page и visual entities.
2. Runtime adapter между ontology/gateway потоками и сохранёнными visual bindings.
3. Реальные `elevated-spike`, targets, zones, routes и toolbar commands на instance Map Page.
4. Access/Hub registration и публикация module route.
5. Отдельная пустая программируемая страница — только после того, как готовые page templates и их MCP-контуры отработаны.