# Foundry Data Product bindings `NDC Foundry Binding` is a deploy/control-plane operation. Realtime facts do not pass through the node: Foundry persists an approved page-slot binding and its server-owned consumer reads snapshot and durable patch from External Data Plane. The same-origin BFF serves the persisted projection and bounded history without exposing the reader grant. ## Private workload API ```text GET /internal/foundry/v1/data-products POST /internal/foundry/v1/data-product-bindings Authorization: Bearer ndc_fndbg_ ``` The POST body is `nodedc.foundry.binding-upsert/v1`. It contains only application, page, binding, Data Product projection and a stable idempotency key. Provider, tenant, connection, endpoint, URL, raw payload and credentials are rejected. This credential is not a Foundry MCP `fnd1.*` capability. MCP capabilities are short-lived interactive grants for AI Workspace. It is also not `NODEDC_INTERNAL_ACCESS_TOKEN`, a browser session, or an EDP writer/reader grant. ## Workload grant The opaque value never enters a Foundry env file or application manifest. Foundry hashes it with SHA-256 and resolves a root-owned, non-writable record from `NODEDC_FOUNDRY_BINDING_GRANTS_DIR` on every request. Removing or replacing the record therefore revokes or rotates access immediately. A `nodedc.module-foundry.binding-grant.v1` record fixes: - expiry and actions (`catalog.read`, `map-data-product.upsert`); - actor and owner used by the existing replay-safe Foundry write path; - exact allowlisted tuples of application, page, binding, slot, Data Product, semantic types and field projection. No authorization claim is accepted from request headers or workflow data. Before persisting a binding, Foundry verifies that the target-specific EDP reader grant exists, is active, permits the selected product and exposes a `snapshot+patch` product. The workload API remains fail-closed: if the grant is not ready, POST fails with `409 data_product_reader_grant_not_ready`; an unusable visual binding is never saved. The Foundry MCP consumer lifecycle owns managed grant creation. Its safe `plan` asks EDP to resolve unique active writer coverage by Data Product id. The response contains no provider, tenant or connection. Exact `apply` generates an opaque target token inside the persistent Foundry runtime and sends only its SHA-256 digest in a request signed by a dedicated Foundry Ed25519 service identity. EDP persists a durable, explicitly revocable reader binding. The signing private key is runner-managed and distinct from Engine; EDP mounts only its public trust copy. Legacy root-owned deployment grants are read-only compatibility fallback, not the normal lifecycle. The canonical Map entity-stream slot is `points`. Other templates may define their own typed slots, but the workload grant must name them explicitly. ## Server-owned consumer lifecycle An approved binding is the only addressable consumer target. Foundry persists consumer state under the runtime volume, keyed by application/page/binding; it stores the binding identity, Data Product version, policy version, cursor, snapshot generation, safe subjects, presentation status and reconnect metadata. It never stores the reader capability value or EDP endpoint. Foundry MCP exposes exact `plan`/`apply`, safe `status`, bounded `accept` and non-destructive `rollback` for this target. A missing legacy consumer record is bootstrapped lazily from the already approved binding; a missing target grant appears as the explicit `ensure-target-scoped-reader-grant` plan effect. An existing Map Page therefore does not require a new provider workflow, native n8n credential or manual pin migration. Snapshot replacement and patch application are atomic per target. Cursor is committed before browser fan-out. Patch replay is idempotent; a gap causes snapshot rebase. One active upstream stream is shared by every viewer of the same target and is closed after the final viewer releases it. Temporary source or network failure preserves subjects. Stale and removal use the versioned provider-neutral policy registry: removal is allowed only by authoritative snapshot absence or canonical tombstone/revocation.