Topline Docs

Build MCP

Build cookbook: Security and runtime boundaries

Private routes, secrets, viewer identity and the runtime boundaries an artifact app must keep.

Security and Runtime Boundaries

Treat the artifact package as an untrusted application boundary with only declared platform capabilities. A successful local build does not authorize a cloud, database, identity, or publish operation.

Viewer and routes

Set viewerPolicy to private or tenant. Route APIs under /_artifact/* and call them relatively from browser code (./_artifact/...) so draft, live, and immutable-version paths continue to work. Never call platform /api/*, use a root-absolute artifact fetch, or add an undeclared absolute URL.

The viewer-scoped binding path is intentionally narrow: it requires a signed-in viewer, resource: "customers", and emailField: "email"; the runtime filters to the matching viewer. It is not a replacement for arbitrary source ACLs.

Data, secrets, and private state

Use catalog/read-only tools and bounded declared datasets for source data. Do not put database URLs, source API credentials, keys, passwords, bearer tokens, or cloud credentials in source, manifests, browser bundles, or ordinary env variables. The app runtime must not connect directly to Postgres.

For a third-party API, declare an exact region-matching Secrets Manager ARN in secretBindings[]. The runtime receives the ARN and resolves the value with its least-privilege role (platformSecrets.get(...) in Node or get_secret(...) in Python). Keep vendor calls server-side behind a declared artifact route.

When a private tool needs its own durable state during authoring, use the guarded run_artifact_workspace_sql namespace for that task/artifact. Source and analytics reads remain on run_psql; workspace-table writes must be derived or operator-provided and documented. Do not use it as an unscoped platform database escape hatch.

Webhooks and Bedrock

An ordinary private API route depends on the platform viewer/session check. External provider webhooks are not artifact-native today: raw function URLs require AWS IAM, stable routes authorize a viewer, required provider headers are not a general forwarding contract, and no transactional ingress-idempotency store is declared by the manifest. Route webhook ingestion to a reviewed platform service; an artifact may visualize its approved status data later.

The narrow machine-ingress exception is a validated, promoted kind: "mcp_server" deployment at exact /_artifact/mcp. It uses FastMCP 3.4.7 Streamable HTTP with stateless JSON responses. Topline creates and keeps the bearer private, IAM-signs the Lambda request, and forwards only bounded MCP protocol headers plus a trusted platform claim. The artifact never declares, reads, rotates, or receives that credential. A workspace manager connects the live artifact in Developer Access, reviews every tool, and explicitly enables chat and/or coding agents before use.

For simple chat, use one bounded server-side Bedrock Converse call per turn on a private /_artifact/api/* route. Use the platform-injected platform_artifact_inference.BedrockInference helper and PLATFORM_ARTIFACT_BEDROCK_MODEL_ID. The helper assumes the model-scoped Topline production inference role with in-memory temporary credentials; customer data and secret clients retain workload IAM. Customers never enable models in their own AWS accounts. Validate/bound messages, mock the call in local tests, and return a clear 503 if the model setting is absent. Do not hardcode a model ID, request a Bedrock API key, put Bedrock in browser code, or silently add tools, memory, streaming, history, or an agent loop.

Operator boundary

The sandbox must not run direct cloud deploy, IAM, database-write, or secret commands. Use bridge tools for the documented artifact lifecycle. If the needed bridge capability is absent, stop and name the missing tool; do not substitute an unapproved route.