Headless Targets
Headless targets let a package expose tools, actions, workflows, or background behavior without mounting a browser surface.
Each target has its own runtime assumptions. Code shared with a webview target must avoid browser APIs unless it is behind a target-specific adapter.
Host Bootstrap
The host installs the supported SDK capability session before evaluating the selected expose. Your module imports the public SDK normally:
Do not read or install the bootstrap value yourself. Its storage and transport are host implementation details, not a package API.
If reading an sdk property reports that the environment is unsupported, the expose is running outside its host bootstrap or was assigned to the wrong target runtime.
QuickJS
QuickJS exposes do not receive browser or server globals by default. Avoid assumptions about window, document, process, Buffer, fetch, sockets, and timers. Use SDK capabilities for supported host effects.
Build it as a distinct target graph:
The build rejects ambient globals that are unavailable in the QuickJS contract.
Packaged MCP Servers
A package-runtime mcp.server contribution uses one server-specific Module
Federation expose on every target that implements it. The expose name is
derived from the signed contribution ID:
The expose exports one typed server definition. The MVP runtime supports MCP
tools; the host derives server and consumer identity from the verified package
graph, so neither value is supplied to defineMcpServer:
Use the named mcpServer export. A package MCP expose is not a normal miniapp
default export and its tools are never registered as ordinary package tools.
The tools-only MVP accepts API version 1 and pure QuickJS execution only:
package MCP server/tool authorization actions or effects fail activation, and
the miniapp host-action SDK is unavailable while an MCP tool runs. Use an
ordinary package tool contribution when work needs reviewed host actions.
For a server contribution whose ID is catalog, the descriptor target and
build configuration must both select ./mcp/catalog. A package with several
servers gives each server its own ./mcp/<server-contribution-id> expose; do
not combine them behind ./tap/mcp.
The descriptor declares both the server's maximum audience and every runtime tool that may appear in its live catalog:
The runtime tools keys and the owning server's mcp.tool names must match
one-to-one. Missing, extra, or renamed tools fail package activation.
contributionIds names exact eligible contributions in the same installed
package. External entries are closed consumer classes, not wildcard grants.
The host must narrow every declared class to selected specialist, chat,
workflow, miniapp, or platform identities before use. Both lists default empty,
which denies every consumer.
The current desktop MVP wires only exact selected-specialist consumers. In
Settings → Miniapps → Installed, open the owning package details and grant
the server to a canonical specialist slug such as chloe (not a versioned
manifest ID such as chloe@1.0.0). The package detail establishes which
installation registered the server, and an empty grant set remains deny-all.
The other external consumer classes are signed schema maxima for later trusted
call sites; declaring them does not make chat, workflows, miniapps, or platform
services live consumers in this MVP.
TAP persists that narrowing as an audited selection on the server package's
installation record: the exact server contribution, exact consumer target,
granting human, and grant time. A package consumer is stored only as an
installation ID plus contribution ID. It cannot persist its own miniapp,
specialist, or workflow classification; the host re-derives that closed
class from the referenced installation's verified descriptor.
This expose packages the server implementation into the verified target graph. It does not register a server from package code. During verified desktop package reconciliation, the host now derives an immutable, deny-by-default registration with package, installation, release, host-local delivery generation, target, integrity, server, and child-catalog provenance. It prepares a complete desired snapshot and atomically commits, replaces, or removes that snapshot in the canonical MCP owner. Failed candidate validation leaves the prior release intact, and restart reconstruction comes from the package installation database rather than the user MCP configuration file.
Reconciliation loads grants across the complete enabled, account-visible
installation graph, then re-resolves package consumers against the exact subset
that passed the final QuickJS, checkpoint, UI, entitlement, and provenance
readiness barrier. Missing, disabled, unusable, or failed contributions and
installations, cross-scope package references, duplicates, invalid identities,
and selections outside the signed maximum fail closed instead of producing a
partial audience. With no persisted selections, the projected audience is
DenyAll.
For a workspace-scoped installation, grant replacement must name the
authoritative active workspace and pass the platform mcp:manage policy check;
an authenticated account or renderer-provided workspace id alone is not
authority. User-scoped replacement is instead bound to the exact active account
and canonical granting human. Account and workspace transitions run the same
guarded reconciliation, withdrawing projections outside the newly active scope.
The verified QuickJS host loads each expected mcpServer, validates its live
tool names against the exact descriptor-declared mcp.tool children, and
rejects a missing, extra, duplicated, or renamed tool before the package MCP
generation becomes visible. Runtime descriptions and input schemas are bounded
and validated at the isolate boundary. The descriptor remains authority for
server ownership, contribution identity, timeout, target, and release.
The canonical registry issues a provisional access lease for an exact consumer and exact descriptor-declared tool. An authorized specialist receives only those package MCP tools in its private per-turn catalog; they are never copied into the global tool registry or the user's MCP server store. Immediately before QuickJS dispatch, the host reacquires the package projection gate and revalidates the activation, audience, and child membership. Audience narrowing therefore revokes an already-discovered tool even when the server generation is unchanged, and an A-to-B-to-A replacement cannot revive an old lease. Existing specialist-authored tool policy and delegation scope remain additional upper bounds: an MCP grant supplies authority, but does not widen a specialist that was explicitly configured with a narrower tool set.
This projection is desktop-only in the current host. Mobile and other non-desktop hosts accept an authoritative empty MCP snapshot, but fail package activation closed when the snapshot contains any MCP declaration; declarations are never silently ignored.
The production MVP is intentionally tools-only and package-runtime-only. Chat turns use the exact specialist identity that performs the turn; there is no second broad "chat" grant on a specialist call. The same consumer-scoped host API can be adopted by direct chat, workflows, miniapps, and platform services when those owners have a trusted identity-bearing call site, but those call sites are not implied by descriptor acceptance.
Model-facing package tool names are host-generated, provider-safe aliases. The host preserves ordinary tools and fails the package tool closed if an exact or provider-sanitized name would collide; package authority is always checked by the exact registration and contribution lease, never by a name prefix.
Stdio and Streamable HTTP server declarations are host-declarative and do not
select a Module Federation expose. They enter the same non-live immutable
registration projection, but the host does not connect them until command
review and credential-binding authority exist. mcp.prompt, mcp.resource,
mcp.resource-template, and mcp.app also remain declaration-only until their
canonical read/render paths preserve the same lease and provenance contract.
Worker, Node, and Workflow Host
- Use
workerfor code compatible with the supported worker runtime. - Use
nodefor contributions that require the supported Node.js module profile. - Use
workflow-hostfor contributions evaluated by the workflow runtime.
Declare a separate expose for each runtime. Do not point several incompatible target entries at a bundle compiled for one environment.
Multi-Target Packages
Compile every target into its own staging root, then call assembleTapPackage once with an exact target map. The assembler rejects missing, extra, overlapping, or invalid target roots and preserves the previous complete output if assembly fails.
See Build and Module Federation for a complete multi-target configuration.