New crate bridging MCP Apps (the Nov 2025 in-chat-UI standard) to joule-ui's
metered, sealed interaction lifecycle. MCP Apps render interactive UI and let
actions flow back as calls — but those interactions are unmetered and unsealed;
the host runs them and forgets. This adapter runs an MCP App component action
through joule-ui unchanged, so every fired action becomes a hash-chained
transaction: who fired it (actor did:key, mandatory), on which component, what
it cost (real joules), and whether a capability allowed it.
- McpAppAction models the inbound event; its component identity hashes to the
joule-ui surface, the action to the verb, the payload to content-addressed
inputs.
- meter_mcp_action hands off to run_interaction unchanged — no re-implementation
of either side, so MCP Apps stays the UI source of truth and joule-ui the
accountability one. A denied action's handler never runs.
- McpAppLog wraps joule-ui's InteractionLog: an in-chat app session becomes a
signed, hash-chained ledger that verify_chain checks; excise/reorder/mutate
breaks it. describe() surfaces actor/verdict/joules per action.
- 3 tests: a metered+sealed+attributed action; a denied action whose handler
never runs; a session of actions that chains and verifies. clippy clean.
The field's MCP Apps render UI; this makes every interaction on it an
energy-accounted, capability-gated, signed receipt.
Co-Authored-By: Claude Opus 4.8 <[email protected]>