@integrity-labs/xero-broker
v0.1.4
Published
Xero Broker — MCP server that routes money- and ledger-touching Xero writes through approval-core (HITL). Sibling to cloud-broker / channel-broker; the only write path for an agent once the vendor xero-mcp-server's write tools are stripped. ENG-4922.
Readme
@integrity-labs/xero-broker
Xero Broker — an MCP server that routes money- and ledger-touching Xero
writes through @augmented/approval-core so a human
approves them before they hit the books. Sibling to cloud-broker and
channel-broker.
Why
Vendor MCP servers like @integrity-labs/xero-mcp-server run on the agent
host and talk to Claude Code over stdio. Their tool calls never transit the
central Augmented API, so the generic HITL resolver can't gate them
(ENG-6029). For read-only Xero that's fine; for writes that move money or
mutate the ledger it isn't.
This broker is the per-vendor mitigation. When an agent is provisioned with
the xero-broker integration, the provisioner launches the vendor Xero
server read-only (XERO_WRITES_VIA_BROKER=true strips its
Create/Update/Delete tools), making this broker the only path the agent
has to a Xero write — there is no ungated lane to the same operation.
Gated verbs
| Verb | Risk tier | Why |
| -- | -- | -- |
| xero.payment.create | write_high_risk | Moves money out — irreversible at the bank layer |
| xero.bill.create | write | Creates a payable obligation |
| xero.bill.approve | write_high_risk | Draft → approved is the gate before payment |
| xero.invoice.void | write_destructive | Cannot be undone in Xero |
| xero.contact.merge | write_destructive | Irreversible |
| xero.bank_transaction.delete | write_destructive | Audit-trail loss |
Tools
xero_preview_request({ verb, payload })— dry-run:auto_approve/route_to_approver/hard_denyplus the resolvedrisk_tier. No side effects.xero_request_approval({ verb, payload, reason, ttl_seconds?, source_context? })— submit. On approval the broker executes the Xero REST call server-side and returns the result.statusisauto_approve/active(done),pending(human paged), ordenied.xero_poll_decision({ request_id })— single-shot status check (escape hatch; resolution is normally pushed via direct-chat).xero_await_decision({ request_id, max_wait_seconds? })— long-poll fallback.
Always include payload.tenant_id (the Xero organisation the write lands in —
the Xero-Tenant-Id header value, not the Augmented team).
Env contract
Spawned as a stdio child by the runtime adapter. Same env as the other brokers:
| Var | Purpose |
| -- | -- |
| AGT_HOST | Augmented API base URL |
| AGT_AGENT_ID | Agent UUID (defaulted into xero_request_approval) |
| AGT_RUN_ID | Run UUID (defaulted into xero_request_approval) |
| AGT_TOKEN | Initial JWT (preferred) |
| AGT_API_KEY | tlk_… — refresh path when AGT_TOKEN expires |
All calls route under /xero-broker on the API; the team is derived
server-side from agent_id.
