
Your agent needs to read and write Xero: pull a profit and loss report, raise an invoice when a deal closes, reconcile a payment on behalf of an accountant. Xero now ships two ways to do that. There is an official MCP server, and there is the REST API the platform has run for years. They are not the same object; one runs locally against a single organisation, the other is a multi-tenant HTTP API you authenticate per user. Picking the wrong one shows up late, usually the first time a second customer connects. Here is how to choose.
Before comparing them, it helps to be precise about the two things on the table. One is a process you run on a machine. The other is an HTTP surface you call over the network. The difference is not cosmetic; it decides how your agent authenticates and where it can run.
The Xero has an official MCP Server, open-source implementation, written in TypeScript and shipped under the @xeroapi/xero-mcp-server package. It is part of Xero's Agentic Toolkit. It runs locally over STDIO; Xero's own guidance states it works with any MCP client that supports local or STDIO servers, and the documented setup launches it through npx inside a client such as Claude Desktop or Cursor. There is no remote, Xero-hosted endpoint to point an agent at.
Authentication comes in two modes. Custom Connections use a XERO_CLIENT_ID and XERO_CLIENT_SECRET scoped to one specific organisation; this is the recommended mode for desktop clients. Bearer Token mode takes a XERO_CLIENT_BEARER_TOKEN your client obtains itself, which is how you support multiple Xero accounts at runtime.
The Xero REST API is the surface every Xero integration has used for years. The Accounting API is globally available; Payroll is a separate, region-specific API for AU, UK, and NZ; and Files, Assets, Projects, and Bank Feeds are their own APIs again. Requests are JSON, and every call carries a Xero-Tenant-Id header identifying the organisation.
Authentication is OAuth 2.0. The grant types are Authorization Code Flow (with PKCE for public clients) for per-user, multi-tenant access, and Client Credentials via Custom Connections for single-organisation machine access. A single OAuth connection can be authorized for multiple tenants, listed through the GET /connections endpoint.
Both paths reach the same underlying Xero data, but the MCP server exposes a deliberately smaller slice of it. The gap is not obscure edge cases; it is core accounting write operations your agent will reach for on day two. The table below covers the actions that matter most for agent use cases.
The official server ships create, read, and update tools, plus a set of payroll timesheet actions. What it does not ship is telling. Its update-invoice command updates a draft only; there is no authorise, void, or delete for invoices. Purchase orders, batch payments, repeating invoices, overpayments, prepayments, bank transfers, and invoice attachments are absent. Its report coverage stops at profit and loss, balance sheet, trial balance, and aged receivables and payables. For an interactive assistant answering questions about one business, that surface is enough. For an agent that manages an invoice lifecycle end to end, it is not.
The Scalekit Xero connector is an API-based connector, not a wrapper around the local MCP server. It exposes 94 tools over Xero's OAuth 2.0 surface, including the operations the MCP server omits: xero_invoice_delete to void an invoice, xero_purchase_order_create, xero_batch_payment_create, xero_repeating_invoice_create, and the full report set through tools like xero_report_profit_and_loss and xero_report_balance_sheet. It also removes a piece of manual work: on the first tool call it fetches the tenant ID from GET /connections and caches it, so you never pass xero_tenant_id by hand.
Capability decides what your agent can do. Auth decides whether it can run for more than one customer. This is where the two paths diverge most sharply, and where the local-only nature of the MCP server has consequences.
A Custom Connection is machine-to-machine and tied to one organisation; the client credentials you configure authorise that organisation and no other. For a solo operator wiring Claude Desktop to their own books, that is the fast path. For a product serving many customers, it does not compose: one client secret per organisation is not a model you scale to hundreds of tenants.
Bearer Token mode lifts the single-organisation limit, but it moves the work to you. The server does not run the OAuth flow; your MCP client has to obtain the token, which means you build and operate the Authorization Code or PKCE flow, then feed the result in as an environment variable per session.
The REST API's Authorization Code Flow is the model designed for multi-tenant products. Each user consents through a browser redirect, your backend exchanges the code for tokens, and each connection can span multiple Xero organisations, resolved per call through the Xero-Tenant-Id header. Request offline_access and you receive a refresh token to keep acting after the user's session ends.
The catch is lifecycle. Xero access tokens expire after 30 minutes and refresh tokens after 60 days, so a background agent constantly meets expired tokens with no user present to re-authenticate. Uncertified apps are also capped at 25 connected organisations until they pass Xero's certification. The path gives you a token per user; it does not store, refresh, or revoke it. That part is infrastructure, and it is the same whether you chose MCP or the API. For a deeper look at how to handle token refresh for AI agents, the lifecycle problem is well worth understanding before committing to either path.
The comparison that matters in production is not features; it is the maintenance surface. The question is simple: what breaks, what needs your attention, and who owns fixing it.
With the local MCP server, you own the process. That means a Node runtime per environment, a way to launch and route STDIO servers, and, for Custom Connections, one client secret per organisation. There is no hosted infrastructure to lean on and no per-user OAuth flow to inherit. Tool schemas also move underneath you: they update when Xero publishes a new version of the package, without a versioning contract you control.
With the REST API, you own the full stack. Token storage, proactive refresh against the 30-minute expiry, Xero-Tenant-Id injection, pagination that varies by endpoint, and rate limits all become your code. Those limits are strict: 5 concurrent calls, 60 calls per minute, and 5,000 calls per day per tenant, with a 10,000-per-minute ceiling across all tenants. Exceed one and Xero returns HTTP 429 with a Retry-After header. Webhooks add HMAC-SHA256 validation on a short response window. None of it is exotic; all of it is yours to build and keep working. The hidden cost of building OAuth internally for AI agents adds up quickly once rate limits, token storage, and webhook validation are all on your plate.
This is the layer Scalekit's connector replaces. It runs the per-user Authorization Code Flow, stores tokens in a per-user, per-tool vault, refreshes them before they expire, and injects the tenant ID automatically. Credentials never touch the agent runtime. You still write your agent; you stop writing the token lifecycle.
Neither path is universally correct. The decision turns on how many organisations your agent serves and whether a person is present when it runs.
If the API is your path, the work is auth and tool schemas, not accounting logic. Scalekit's connector gives your agent authenticated, per-user access to Xero and returns tool definitions in your model's native format, so you write neither. The pattern is always the same three steps: discovery, scope, then execution. The example below uses Python and the Claude SDK.
The sequence starts with discovery, and discovery is the point worth reading closely. Your agent is not loading a flat catalog of every Xero tool. It is loading only the tools the current user's connected account is authorized to call. That is the distinction between a per-user agent and a shared-credential one. First set up the connection and connect a user.
The identifier represents the current person in your own system. In production it comes from your authenticated session, never from the client.
list_scoped_tools returns only the tools this user's Xero connection authorizes, already in Anthropic's native format. The connection_names filter must match the connection name you created in the Scalekit dashboard, character for character; a mismatch returns an empty list with no error.
This is the standard Claude tool-use loop. Send the conversation, check stop_reason, execute each requested tool through Scalekit with the user's identifier, then append the results and continue. Scalekit looks up the stored token for that user and makes the real Xero call.
The same connector works with LangChain, CrewAI, Google ADK, and the Vercel AI SDK; the connected-account pattern does not change. Install the SDK with pip install scalekit-sdk-python anthropic, and keep credentials in a .env file loaded via dotenv.
The auth divergence between MCP and the API is real, but it hides a problem that sits under both choices. Whichever path you take, you end up holding credentials you have to manage.
Both paths hand you a token or credential per organisation. The MCP server gives you a Custom Connection secret or a bearer token; the REST API gives you an OAuth token per user. In a multi-tenant product that is N credentials, each with a 30-minute access token, a 60-day refresh token, and its own revocation event when a customer churns. Storage, rotation, and revocation are yours in both cases. The path changes the token type. It does not change the infrastructure required. Understanding who holds the token across agent tool-calling patterns is a foundational question regardless of which Xero integration path you choose.
Scalekit's Xero connector handles the OAuth flow, token storage, refresh, and tenant-ID injection for the API path, so the MCP-vs-API decision no longer changes your auth infrastructure.
Once an agent acts on real books, "which agent did what, for which user, when" stops being a nice-to-have. It is the question a security reviewer or an auditor asks first, and neither raw path answers it well.
The local MCP server runs on a machine and logs to that machine. The REST API records requests on Xero's side, tied to the token, not to the person in your system who triggered the agent. Neither gives you a queryable record that links a specific user, a specific agent run, and a specific tool call.
Because every tool call routes through Scalekit, each one produces an entry in auth logs: which user initiated it, which connected account acted, which tool ran, and when. That is an immutable trail across every downstream Xero call, queryable when a reviewer asks, without instrumenting your agent by hand. Audit trails for agent auth in B2B SaaS explains why this layer matters and what it takes to build it correctly.
There is a way to get MCP ergonomics without the local server's limits, and without handing an agent every tool a connector exposes. This is the payoff for going through Scalekit rather than pointing at a raw server.
A full connector surface is both a security and a cost problem. An agent that only needs to read reports should not hold xero_invoice_delete; every extra tool widens the blast radius if something goes wrong. It is also tokens: 40 tools at roughly 200 tokens each is about 8,000 tokens burned before the agent does any work, on every run. The fix is not better prompting. It is surface reduction.
Virtual MCP servers solve both at once. You declare one server per agent role, listing exactly which connections and which tools it exposes, and you get a static endpoint. Scoping from 40 tools to 5–10 cuts token overhead by around 80 percent and sharpens tool selection. Per-user isolation is handled by session tokens: one definition serves all users, and each run mints a short-lived token scoped to that user's connected accounts. No credential sharing, no per-user server to host. That is the multi-tenant model the local Xero MCP server cannot provide. This is the same architectural thinking behind how tool calling auth changes when you move from single-tenant to multi-tenant.
If your agent is a single-organisation, interactive assistant and one Custom Connection is enough, the official Xero MCP server is a legitimate, fast path; run it locally and accept its coverage. If your agent is multi-tenant, background, or needs the write operations the MCP server omits, build against the Xero REST API. The deciding question is whether your agent acts for more than one customer organisation with independent tokens and revocation. If yes, it is the API. Either way, the credential lifecycle is the same problem, and that is the part worth putting on production-grade infrastructure rather than rebuilding per tool.
Recommended reading: QuickBooks MCP vs QuickBooks API for AI Agents, the same decision for Xero's closest competitor.
Explore the connector, then wire it into your agent. See the Scalekit Xero connector and the connector setup docs for the full tool list and quickstart. For a finance-agent pattern to start from, look at the revenue forecast commentary agent, and check pricing when you are ready to scale.
Building a Xero agent and want another set of eyes? Join the Scalekit Slack community, or use the talk to us page for immediate help.