Capxul Docs
For agents

MCP server

The @capxul/mcp server exposes Capxul financial operations — auth, account readiness, balances, testnet faucet, payments — as MCP tools over Streamable HTTP.

@capxul/mcp is a runnable Model Context Protocol server that exposes Capxul's financial operations as tools any MCP client (Claude, Cursor, other agents) can call. The package ships a CLI, not a library: the published artifact is the capxul-mcp executable. Like the SDK, the tool surface speaks money — tool results carry Money values, labels, and opaque ids, never custody internals.

Alpha surface

The MCP surface ships on the 1.0.0-alpha.x train and is still moving. Tool names, inputs, and gating may change between alpha releases. Pin an exact version, and treat the startup banner — which prints the exact tool set the running server registered — as the authority for your launch.

Install and run

# one-off, via npx
npx @capxul/mcp serve --mode live

# or install globally
npm i -g @capxul/mcp
capxul-mcp serve --mode live
Usage:
  capxul-mcp serve [--mode live|dev] [--port <port>] [--approval-url <url>] [--stdio]

Options:
  --mode live|dev       Launch mode. Defaults to live. There is no env-var mode selector.
  --port <port>         Bind port. Defaults to CAPXUL_MCP_PORT or 8788. (HTTP transport only.)
  --approval-url <url>  Approval app base URL. Defaults to CAPXUL_MCP_APPROVAL_URL or http://localhost:5998.
  --stdio               Serve over stdio (local spawn) instead of HTTP. Defaults to off (HTTP).
  --help                Show this help.

The server speaks MCP over Streamable HTTP at POST /mcp — a fresh, stateless server instance per request, with shared state (sessions, approvals) held in the process. Pass --stdio to serve over stdio instead, for clients that spawn the server locally.

On startup the banner prints the bound URL, the mode, whether the faucet is enabled, and the full list of registered tools. That list is computed from the live registry at boot, so it never drifts from what the server actually exposes.

Auth model

There are two independent layers:

Transport auth — OAuth bearer. An in-memory PKCE OAuth provider gates POST /mcp when CAPXUL_MCP_OAUTH_REQUIRED=1. The server publishes the standard discovery documents (/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server) and the /oauth/authorize and /oauth/token endpoints. A proof-issuer secret (CAPXUL_MCP_OAUTH_PROOF_ISSUER_SECRET) can mint bearer tokens for automated probes — and is currently required whenever OAuth is required, because external-issuer validation is not implemented yet. Stdio mode skips OAuth entirely: a local spawn is trusted IO with no bearer-token surface.

Financial auth — email OTP sessions. Signing in to Capxul happens through tools: auth.requestOtp emails a one-time code, auth.verifyOtp exchanges it for an opaque sessionToken that every session-scoped tool takes as an argument. The OTP travels only as a tool argument, and no other credential — no backend JWT, no key material — ever appears in a tool result.

The dev-mode custody gate

The --mode flag decides how money-moving operations get signed:

  • --mode live (default) uses the production signer path. Full account activation needs a one-time human approval in the browser: account.ensureReady with requirement deployed returns { status: "pending", approvalUrl, approvalId } — open approvalUrl (the dedicated Approval app), complete the approval there, then poll account.deploymentStatus with the approvalId. The server itself never holds key material.
  • --mode dev runs against a deterministic dev signer seed (CAPXUL_MCP_DEV_SIGNER_SEED) and a dev backend deployment, so agent journeys can be exercised headlessly, without live custody. Dev mode is also the gate for the payment tools — see tool gating below.

Runtime configuration

Environment is read lazily on the first authenticated tool call, so liveness (system.ping) needs no secrets. A missing variable surfaces as a structured ENV_MISSING tool error naming the exact variable. Notable variables:

VariablePurpose
CAPXUL_MCP_PORTBind port (default 8788; 0 = ephemeral).
CAPXUL_FAUCET_ENABLED1 or true to register the testnet faucet tool.
CAPXUL_MCP_DEV_SIGNER_SEEDDeterministic dev signer seed (--mode dev).
CAPXUL_MCP_OAUTH_REQUIRED1 to require an OAuth bearer token on POST /mcp.
CAPXUL_MCP_OAUTH_PROOF_ISSUER_SECRETSecret to mint proof bearer tokens.
CAPXUL_MCP_APPROVAL_URLBase URL of the Approval app for activation approvals.

Which tools are registered

Three tiers, decided at launch:

  1. Always registered — system, auth, account, identity, and payee tools.
  2. Faucetfaucet.fundTestnet registers only when CAPXUL_FAUCET_ENABLED is set. Otherwise it is absent from tools/list.
  3. Payments and the wider financial-ops set — payments, payment documents, orgs, payment requests, the draft workbench, and the account/org projection tools register only when the payments gate is on: --mode dev and the faucet enabled. In --mode live these tools are absent today.

A typical first session, in order: system.pingauth.requestOtpauth.verifyOtp (returns sessionToken) → account.ensureReadyaccount.balance.

Tool reference

Inputs marked ? are optional. sessionToken is always the opaque token returned by auth.verifyOtp.

System and auth

ToolInputWhat it does
system.pingecho?Liveness probe; echoes back the optional value. Needs no auth and no secrets.
auth.requestOtpemailEmail a one-time sign-in code. Works for new and returning users alike.
auth.verifyOtpemail, otpVerify the emailed code and start a session. Returns the opaque sessionToken.
auth.statussessionToken?Report whether the session is authenticated, and for whom.
auth.signOutsessionTokenEnd the session and revoke the token.

Account readiness and balance

ToolInputWhat it does
account.statussessionTokenReadiness ladder: loading, settingUp (with the current step), ready (with accountId and canTransact), or failed.
account.ensureReadysessionToken, requirement? (provisioned or deployed)Run account setup to completion; idempotent. With deployed, may return pending plus an approvalUrl for the one-time browser approval.
account.deploymentStatusapprovalIdPoll the activation approval started by account.ensureReady. pending until it completes, then ready with canTransact.
account.balancesessionTokenThe account's balance and available balance, as Money.

Identity and payees

ToolInputWhat it does
me.getsessionTokenThe authenticated identity: authUserId, email, displayName.
me.depositInstructionssessionTokenInstructions for depositing money into the account.
handles.resolvesessionToken, handleResolve a Capxul handle or org handle to its current payment destination.
payees.createsessionToken, label, recipient, handle?Save a recipient as a Payee. The recipient must resolve by email or org handle.
payees.getsessionToken, payeeIdLoad a saved Payee by id.
payees.resolvesessionToken, recipientResolve an email, handle, org handle, or Payee id to a payment destination.

Faucet

Registered only when CAPXUL_FAUCET_ENABLED is set. Test environments only — the same guardrails as the Sandbox CLI apply: never wire the faucet into production UX.

ToolInputWhat it does
faucet.fundTestnetsessionToken, amount { value, currency?, decimals? }Mint test money into the session's account (testnet only). value is a decimal string, e.g. "10" for $10. Returns { status: "funded" } — no settlement internals.

Payments

Registered only when the payments gate is on (--mode dev + faucet enabled). Money-moving tools require the account to be ready with canTransact: true, or they fail with a wrong-state error. Amounts are Money strings such as "2 USDX". Recipients (to) are always validated — a handle, email, org handle, or Payee id, never a raw address — except payments.withdraw, whose entire purpose is an external destination.

ToolInputWhat it does
payments.paysessionToken, to, amount, document?, release?, lineItems?Pay a validated recipient. An optional release clause (scheduled or stream) turns the payment into a recoverable Commitment. Returns a Payment record.
payments.withdrawsessionToken, to, amount, documentCash out to an external wallet. Requires a Withdrawal payment document; the result redacts the destination to a short label.
payments.listsessionTokenList your payments, most recent first, each with its live vesting read-model (released, availableToClaim).
payments.getsessionToken, paymentIdOne payment by id with its vesting read-model.
payments.claimsessionToken, paymentIdClaim the vested-and-unclaimed amount of a Commitment you are the recipient of.
payments.cancelsessionToken, paymentId, document?Cancel a Commitment you created. Reclaims only the unvested remainder.
payments.redirectsessionToken, paymentId, to, document?Redirect a Commitment to a new validated recipient before any claim.
paymentDocuments.verifysessionToken, documentHashRe-derive a stored payment document's hash and confirm it matches the committed documentHash.
paymentDocuments.rendersessionToken, documentHashRender a stored document to HTML for the user; the model receives metadata only.

The wider dev-mode surface

The same payments gate also registers these tool families. They mirror the SDK's org, receivables, and projection surfaces; expect them to evolve the fastest of anything on this page.

FamilyToolsWhat it covers
Draft workbenchpayments.draft, payments.simulate, approvals.request, approvals.status, approvals.cancel, payments.executeThe decomposed payment flow: the agent drafts and simulates, a human mints a one-time approval in the browser, execution consumes it.
Organizationsorg.create, org.list, org.members, org.roles, org.invite, org.assignRole, org.removeMember, org.spendViaPayments, org.batchPayrollCreate and administer orgs, and spend from an org treasury under role caps.
Payment requestspaymentRequests.create, .markSent, .markViewed, .cancel, .collect, .list, .get, .reconcileThe receivables lifecycle: request, share a link, collect, reconcile.
Address bookaccount.addressBook.* and org.addressBook.* (list, get, add, hide, unhide, label)Relationship entries per actor scope, refs and labels only.
Requests and inboxaccount.requests.*, org.requests.* (issue, list, get, cancel, reconcile); account.inbox.*, org.inbox.* (list, approve, decline)Issue requests to payers; list, approve, or decline payable items.
Insightsaccount.insights.summary, account.insights.history, and org equivalentsRead-only finance summary and payment-history projections.
Destinations and payoutsdestinations.add, destinations.list, destinations.remove, payments.payout, subAccounts.transferSaved payout destinations, payouts to them, and transfers between sub-accounts.
Payrollorg.payroll.roster.add, .list, .update, .remove, org.payroll.runRoster management and payroll runs.

The capability constraints on the equivalent SDK surfaces apply here too — check Capability status before building a product flow on any of them.

What never crosses the wire

Tool results are leak-safe by design: they carry Money values, validated recipient labels, opaque ids, and committed document hashes. Settlement internals — transaction hashes, account addresses, raw minor units, approval token values — stay server-side. If you find one in a tool result, that is a defect worth reporting, not a feature to depend on.

On this page