Claude Desktop / MCP
The MCP server is the agent surface of the Tab Authority. Four tools, stdio transport by default, SSE with --sse [port]. Build it once with pnpm build.
Configuration
Any MCP client works. Hermes Agent (~/.hermes/config.yaml, then /reload-mcp):
mcp_servers:
molt:
command: "node"
args: ["/path/to/molt/apps/mcp-server/dist/index.js"]
env:
MOLT_API_URL: "https://moltprotocol.dev"
MOLT_AGENT_KEY: "molt_sk_test_..."
MOLT_SHIPPING_PROFILE: '{"email":"you@example.com","first_name":"Ada","last_name":"Lovelace","address1":"Teststr. 1","city":"Munich","zip":"80331","country_code":"DE"}'Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"molt": {
"command": "node",
"args": ["/path/to/molt/apps/mcp-server/dist/index.js"],
"env": {
"MOLT_API_URL": "https://moltprotocol.dev",
"MOLT_AGENT_KEY": "molt_sk_test_...",
"MOLT_SHIPPING_PROFILE": "{\"email\":\"you@example.com\",\"first_name\":\"Ada\",\"last_name\":\"Lovelace\",\"address1\":\"Teststr. 1\",\"city\":\"Munich\",\"zip\":\"80331\",\"country_code\":\"DE\"}"
}
}
}
}MOLT_API_URL points at the Tab Authority you use: the hosted beta (moltprotocol.dev) or your own instance (http://localhost:3000 with docker compose). Optional: MOLT_STOREFRONT_PASSWORDS (host|password pairs for password-protected dev stores), MOLT_BOGUS_GATEWAY_HOSTS, MOLT_EVIDENCE_DIR, MOLT_CHECKOUT_TIMEOUT_MS, MOLT_AUDIT_LOG_PATH; MOLT_WALLET_PATH + MOLT_WALLET_PASSPHRASE for the x402 rung (see agent wallet). The agent key is scoped to one tab; the key prefix is enforced to be a test key at boot.
The four tools
open_tab(): returns the ceremony URL for the human. The agent can never self-authorize a tab.resolve_merchant(url): classifies the platform (shopify / x402 / unknown) and recommends the execution rung.purchase(tab_id, merchant_url, items, max_amount_minor, reason, mandate_id?): quotes the real checkout total with no card involved, mints a child mandate scoped to exactly that cart, gets a single-use card, checks out behind an exact-total preflight, files a dual-signed receipt.get_receipts(tab_id): every receipt with rung, rail, amounts, evidence hashes and the mandate chain.
Purchase outcomes the agent must handle
purchased: done; the receipt is in the result and verifiable offline.step_up_pending: the purchase is held; the user got an email (the Tap). Retry later with the returnedmandate_id.handoff_l3: no supported checkout protocol; give the human the link.already_purchased: this exact cart was bought on this tab before; the double order is refused before anything is minted.refused: the Tab Authority said no (limits, policy, narrowing). Do not retry unchanged.failed: checkout aborted; the shell was shed, the budget refunded, nothing was charged.
Remote clients (Claude Cowork connectors)
Cowork and Claude.ai reach custom connectors from Anthropic's cloud, so they need a public HTTPS URL - unlike Hermes or Claude Desktop, which start the server locally. The Molt server must stay on your machine anyway (it drives real browsers and your wallet keys never leave it), so the shape is: run it locally, expose it through a tunnel.
pnpm serve:remote
That starts the server, opens a tunnel, and prints the URL and token to paste into Customize → Connectors → + (URL ends in /mcp, token goes in an Authorization: Bearer … header). No agent key is involved in the setup: you paste the key into the chat afterwards and the agent calls connect_tab, exactly as with a local host. Ctrl+C tears it all down again.
Treat that URL like a credential. Anyone holding it and the token can spend the tab it is configured for - bounded by the tab's limits, which is the point, but bounded is not the same as harmless. Stop the tunnel when you are done, and revoke the tab's agent key if the URL leaked.
Starting without a key works
You can register the server before any tab exists: leave MOLT_AGENT_KEY out entirely. open_tab and resolve_merchant work immediately;purchase answers with instructions instead of failing silently, so the agent itself walks you through the ceremony, and once you hand it the key panel's config block it completes its own setup. No file editing, no system prompt.
Key lifecycle, plainly
- One key belongs to exactly one tab and inherits its limits; that is the blast-radius model, not an inconvenience. Several tabs mean several molt entries in your config, each with its own key.
- Nothing about expiry lives in your config. When a tab expires or is revoked, the key simply starts answering
tab_not_active; your agent reports it and you remove the entry (or ask the agent to). - Creating a new key for a tab kills the previous one immediately. Lost keys are not recoverable, only replaceable.
Recommended agent instructions
The tool descriptions already teach the mechanics; these standing instructions make any agent behave well on top. Paste them into your agent's system prompt or project instructions and fill in the tab id:
You can buy things through Molt under a spending tab the user approved with their passkey. Rules: - Before buying at a store, call resolve_merchant on its URL once. - Buy one cart per store visit with purchase(). Set max_amount_minor to the exact price you expect in cents. Give a short honest reason per purchase. - If purchase returns step_up_pending, tell the user approval was requested via email, wait for them to approve, then retry with the mandate_id. - If a purchase is refused or fails, report the structured reason and stop. Never retry a refused request unchanged. Never work around a limit. - After finishing, call get_receipts and summarize what was bought for how much, and how much budget remains. The tab id is: <TAB_ID>
Every automated request carries an RFC 9421 signature and an honest user agent. If a merchant blocks automation, the purchase fails with blocked_by_merchant; there is no stealth mode to turn on.