How to Connect an AI Agent to Brex Expense Data via MCP: A Production Quickstart
Learn how to connect an AI agent to Brex expense data using an end-to-end MCP quickstart. Handle OAuth, cursor pagination, dynamic schemas, and rate limits.
Giving a Large Language Model (LLM) read and write access to Brex means much more than simply wrapping a REST API. You need a Model Context Protocol (MCP) server that translates natural language intent into standardized JSON-RPC tool calls, manages complex OAuth token lifecycles, respects Brex's granular scopes, and explicitly normalizes pagination and rate limits.
The demand for intelligent financial automation is accelerating rapidly. The AI-driven expense report automation market is projected to reach $3.22 billion in 2026, growing at a 14.2% CAGR. Corporate finance is being fundamentally rewired around autonomous agents, replacing rigid, rules-only tools that historically failed to handle edge cases. Competitors like Ramp (see our guide on connecting Ramp to ChatGPT), Navan, and Airwallex are already positioning AI as the core of their expense management platforms. Capital One's massive $5.15 billion acquisition of Brex in April 2026 only accelerated this trend, signaling a massive consolidation of corporate spend management and automated financial infrastructure.
If you are a product manager or engineering leader building B2B SaaS, your customers now expect this level of automation. They want AI agents capable of monitoring budgets, issuing virtual cards, writing compliant transaction descriptions, and reconciling transactions automatically.
The critical question for engineering leaders is no longer whether to expose Brex to AI agents, but how to do so securely—without inheriting a maintenance nightmare. This quickstart guide walks through the architecture and the exact steps required to make a Brex MCP server work securely and at scale in production, without hand-coding a connector every time a new frontier model ships.
Why Point-to-Point Brex API Integrations Fail for AI
Point-to-point integration refers to hardcoding custom REST API wrappers for specific LLMs to talk to specific endpoints. When applied to AI agents and financial data, this approach fails spectacularly.
Building a point-to-point integration for an LLM means you are effectively writing a fragile state machine to babysit non-deterministic output against a strictly deterministic financial API. It is a miserable experience for engineering teams. A one-off Brex client works fine in a local script until you hit the reality of production:
- Schema Drift Mutates Prompts: Brex updates their API schema constantly. New fields appear on transactions, expenses, and budgets. If your agent relies on a hardcoded system prompt and tool definition, it will hallucinate deprecated parameters. The API rejects the payload, and the agent gets confused and loops endlessly.
- OAuth State Management is Fiddly: Brex uses OAuth 2.0. Access tokens last for exactly one hour and then must be refreshed. Scopes must be declared at authorization time—they cannot be added to an existing token. If your agent attempts to execute a tool call during a token refresh window, the call fails. You end up building a complex queueing system just to hold agent requests while background workers negotiate new tokens.
- Partner Registration is a Wall: You must be a registered Brex partner to obtain OAuth credentials. Static user tokens work for internal tools but simply do not scale to a multi-tenant B2B product where hundreds of customers need to connect their own Brex accounts.
- Pagination Black Holes: Brex uses cursor-based pagination. LLMs are notoriously bad at handling raw, opaque cursor strings. Unless you explicitly engineer the tool schema to force the LLM to pass the cursor back completely unmodified, the agent will attempt to parse, decode, or guess the next page, breaking the integration and missing critical financial records.
- Moving URLs: As of January 1, 2026, Brex transitioned its base URLs to
api.brex.comandapi-staging.brex.com. Any hardcoded host in your integration layer is future technical debt waiting to break. - Framework Dialects: Claude Desktop, Cursor, Codex, Windsurf, LangChain, and LlamaIndex all want tools in slightly different shapes. Writing five different adapters is not engineering; it's plumbing.
To solve this, the industry has standardized on the Model Context Protocol (MCP). Instead of writing custom API wrappers, you deploy a documentation-driven MCP server that turns Brex's REST surface into typed tools the moment your schema changes, without shipping new code.
For a deeper dive into this architectural shift, read our guide on AI-ready integrations now supported by Truto.
Understanding the Brex MCP Server Architecture
A production-grade Brex MCP server sits directly between your AI agent (the client) and the Brex REST API (the upstream provider). It handles the protocol handshake, exposes available financial tools via JSON Schemas, and normalizes the execution of those tools on behalf of a specific authenticated user.
Here is how the architecture flows in a production environment:
sequenceDiagram
participant Agent as "AI Agent (Claude / Cursor / Custom)"
participant MCP as "Brex MCP Server"
participant Auth as "OAuth Token Store"
participant Brex as "Brex REST API"
Agent->>MCP: POST /mcp/<token> (initialize)
MCP-->>Agent: Returns capabilities & protocol version
Agent->>MCP: tools/list
MCP-->>Agent: Returns list_all_brex_transactions, create_expense, etc.
Note over Agent,MCP: Agent decides to fetch expenses
Agent->>MCP: tools/call (list_all_brex_transactions, {limit: "50"})
Note over MCP,Auth: MCP checks token validity
MCP->>Auth: Fetch access token (refresh if needed)
Auth-->>MCP: Valid Bearer token
MCP->>Brex: GET /v2/transactions/card/primary?limit=50
Brex-->>MCP: 200 OK + JSON payload + rate limit headers + next_cursor
MCP-->>Agent: Returns standardized JSON-RPC resultThree properties matter immensely for making this architecture production-safe:
- Tenant Isolation: Each MCP URL must be strictly bound to a single connected Brex account. When using Truto to host this infrastructure, the platform issues an MCP URL that carries a cryptographic, revocable token tied to one integrated account, one environment, and one team. The URL alone is enough to authenticate and serve tools, keeping the client side completely stateless. Anyone with the URL only sees that specific tenant's data.
- Dynamic Tool Generation: Tools are derived directly from Brex's resource definitions and documentation, not hand-authored. If Brex adds a new endpoint, a new tool is automatically generated.
- Protocol Conformance: The server must handle
initialize,tools/list,tools/call,notifications/initialized, andpingcleanly according to the JSON-RPC 2.0 specification. Anything less breaks MCP clients silently.
For architectural context on how Brex reads and writes fit together at the API layer, see the companion post How to Connect AI Agents to Brex: Automate Expense Management via MCP.
Step 1: Setting up OAuth 2.0 and Scopes for Brex
Brex supports two authentication modes: user tokens (for internal, single-account tools) and OAuth 2.0 (for partner applications serving multiple customers). For any B2B SaaS use case, OAuth is the only viable path.
Prerequisites:
- An account admin or card admin must accept the Developer API agreement in the Brex dashboard under Settings > Developer.
- They must then enable the beta features in Settings > Beta features and explicitly select "Brex" in the AI assistants section.
- You need a registered Brex partner OAuth client (Client ID and Client Secret).
- A redirect URI that matches exactly one of the addresses provided to Brex when the credentials were set up.
Minimum scopes for expense automation:
| Scope | Purpose |
|---|---|
openid |
Required for OpenID Connect and identity verification. |
offline_access |
Required to receive a long-lived refresh token. |
expenses / expenses.readonly |
Read and write expense records, upload receipts. |
transactions.readonly |
List historical card and cash transactions for reconciliation. |
cards / cards.readonly |
Read card details, check limits, and issue new virtual cards. |
budgets / budgets.readonly |
Manage spend limits and check available budgets before purchases. |
team / team.readonly |
Look up users, departments, and reporting structures. |
Request every scope the AI agent could plausibly need at initial consent. If a scope is omitted (for example, cards.readonly), the corresponding tools will be entirely unavailable to the agent, and the MCP server will never attempt to access resources outside what the token permits. This is a feature, not a bug—the failure mode is deny-by-default.
Token Lifecycle Management:
Instead of building your own database tables and mutexes to store Brex access_token and refresh_token pairs, Truto manages the entire OAuth lifecycle. Access tokens expire after one hour. Refresh tokens are long-lived but single-use per refresh cycle. Truto automatically refreshes tokens shortly before they expire and injects the valid token into the Authorization header of the proxy API request.
(Note: If you are building this entirely yourself, you must put your refresh logic behind a strict mutex per integrated account. Two concurrent refreshes will race, Brex will invalidate the older refresh token, and your user will be silently logged out.)
Securing the MCP Endpoint
By default, an MCP server's token URL is the only authentication required. Anyone with the URL can call the tools. For sensitive financial data, this is often insufficient.
Truto supports a require_api_token_auth configuration flag. When enabled, the MCP client must provide a valid Truto API token (as a Bearer token) in addition to the URL token. This ensures that even if the MCP URL leaks in a configuration or log file, the caller must still be authenticated within your SaaS environment to execute Brex API calls.
Step 2: Generating MCP Tools from Brex Schemas
Hand-writing and maintaining tool definitions for Brex's roughly 40 resources is a massive liability and a waste of engineering time. If Brex adds a new required field to their /v1/expenses endpoint and your hardcoded tool schema doesn't reflect it, the agent's API calls will fail in production.
The scalable pattern is documentation-driven tool generation. Tools are never cached or pre-built. They are generated dynamically on every tools/list request based on the integration's resource definitions and JSON schemas.
The Quality Gate
Each Brex resource (expenses, transactions, cards, budgets) is declared once with its methods (list, get, create, update). A tool only appears in the Brex MCP server if it has a corresponding documentation record. This acts as a strict quality gate. If an endpoint lacks a clear JSON schema or human-readable description, the LLM cannot see it or call it.
When the agent requests available tools, the platform iterates over every configured Brex resource, standardizes the required fields, and generates a descriptive, snake_case tool name (e.g., list_all_brex_transactions, get_single_brex_expense_by_id, create_a_brex_expense).
Here is an example of what the dynamically generated tool definition looks like to the model:
{
"name": "list_all_brex_transactions",
"description": "List card and cash transactions for the connected Brex account. Supports filtering by posted_at_start, user_ids, and status.",
"inputSchema": {
"type": "object",
"properties": {
"posted_at_start": {
"type": "string",
"format": "date-time",
"description": "Filter transactions posted after this ISO 8601 date."
},
"status": {
"type": "string",
"enum": ["PENDING", "POSTED"]
},
"limit": {
"type": "string",
"description": "The number of records to fetch"
},
"next_cursor": {
"type": "string",
"description": "The cursor to fetch the next set of records. Always send back exactly the cursor value you received without decoding, modifying, or parsing it."
}
}
}
}Notice the explicit instruction on next_cursor. By injecting this natural language constraint directly into the dynamically generated JSON Schema, we prevent the LLM from hallucinating pagination parameters.
Tag-Based Filtering
Tag-based filtering lets you scope one MCP server to "expense reviewer" tools and another to "finance ops" tools without maintaining two separate codebases. You can optionally apply a filter (e.g., config: { tags: ["expenses", "receipts"], methods: ["read"] }). Truto validates at creation time that the filter intersects at least one real tool, ensuring you cannot ship an empty MCP server by accident.
Step 3: Handling Pagination and Rate Limits Correctly
Financial integrations live and die by how they handle edge cases. When an AI agent attempts to analyze a year's worth of corporate spend, it will inevitably trigger pagination loops and rate limits.
Explicit Cursor Management
Brex relies strictly on cursor-based pagination for all list endpoints. You must iterate next_cursor until it returns null. Two things trip up naive implementations:
- Models love to "correct" or clean up opaque base64 cursors. Do not let them.
- Result completeness matters for reconciliation. If your agent stops at page one, your Profit & Loss statement is wrong.
Because query parameters and body parameters share a flat input namespace in the MCP protocol, Truto's proxy API handlers split the agent's arguments based on the underlying schemas. The agent simply passes next_cursor: "eyJvZmZzZXQiOjEwMH0=" in its next tool call, and the platform correctly maps it to the Brex query parameter, fetching the next page seamlessly.
The Reality of Rate Limits
Brex's API imposes per-app and per-token limits, and burst behavior differs by endpoint. Let's be radically honest about rate limits: Truto does not magically absorb or silently retry rate limit errors for you.
When a vendor API returns an HTTP 429 (Too Many Requests), attempting to hide that failure from the AI agent is an architectural mistake. If the infrastructure silently retries the request with exponential backoff, the LLM client will likely time out waiting for the tool call to complete. Furthermore, a silent retry on a create_a_brex_expense call can produce duplicate expenses if the original request actually succeeded but the response was lost.
Instead, Truto passes the HTTP 429 error directly back to the caller. Crucially, Truto normalizes the upstream rate limit information into standardized IETF headers, regardless of how Brex originally formatted them:
ratelimit-limit: 100
ratelimit-remaining: 0
ratelimit-reset: 15flowchart LR
A["Agent tool call"] --> B["Truto MCP Server"]
B --> C{"Brex REST API Response"}
C -->|"200 OK"| D["Return result + next_cursor"]
C -->|"429 Too Many Requests"| E["Return error + ratelimit-* headers"]
E --> F["Agent/Orchestrator applies backoff"]
F --> AWhen the AI agent receives the error and these headers, it has the exact context it needs. You can prompt your agent with instructions like: "If a tool call fails with a rate limit error, read the ratelimit-reset value and pause for that many seconds before continuing." This puts the retry and backoff logic exactly where it belongs: in the agent's execution loop, because only the caller knows whether the workflow is user-facing (retry fast) or a nightly reconciliation batch (back off aggressively).
Step 4: Connecting to Unified Accounting Models
Pulling Brex transactions is only half the battle. The true value of an AI agent is its ability to orchestrate workflows across multiple disparate systems.
Once your agent has extracted an expense from Brex via the MCP server, it almost always needs to reconcile that expense in an ERP or accounting system like QuickBooks Online, Xero, or NetSuite (as detailed in our step-by-step developer guide to MCP and Brex integration). Using Truto's Unified Accounting API, your agent doesn't need to learn the proprietary schemas of three different accounting platforms. It can use a single, normalized create_an_expense tool.
Intelligent Expense Parsing Workflow:
- A Slackbot agent ingests a receipt image from an employee.
- The agent uses a vision model to extract the total amount, tax, and vendor name.
- The agent calls the Brex MCP tool
list_all_brex_transactionsto find the matching card swipe. - The agent calls the Truto Unified Accounting tool
list_all_accountsto find the correct General Ledger code (e.g., "Meals & Entertainment"). - The agent calls
create_an_expenseto push the balanced journal entry into QuickBooks or NetSuite, attaching the receipt image.
By combining the Brex MCP server with unified models, you eliminate the need for integration-specific code entirely. The agent operates purely on generalized financial concepts.
Deploying Your Brex AI Agent in Production
Once the MCP server is configured, distribution is as simple as providing a single URL. Every MCP-compatible client—Claude Desktop, Claude Code, Cursor, Codex, Windsurf, VS Code, LangChain, or your custom client—accepts a remote MCP endpoint.
To deploy this architecture securely, follow this production checklist:
- Scope MCP URLs to one connected account: Never mint a URL that spans multiple tenants. Call the Truto API to generate an MCP server for a specific integrated account:
POST /integrated-account/:id/mcp. - Rotate tokens: Ship a
PATCHendpoint to change theexpires_atvalue. Truto tokens support Time-To-Live (TTL) out of the box, with automatic cleanup once the TTL elapses. - Log every tool call: Truto includes a
request_idon every response. Log this so you can correlate against Brex's server logs when financial disputes happen. - Turn on the extra auth layer: For finance teams that push MCP URLs into config files, require a second bearer token (
require_api_token_auth) so the URL alone is not sufficient to access data. - Version your tool schema: When Brex adds a field, regenerate schemas and diff them. Ship changes to your agent prompts on a cadence, not a whim.
The honest trade-off: MCP is not free. You are trusting a documentation-driven tool surface to remain accurate, and you are handing a probabilistic planner access to real corporate money. The mitigations—method filtering, tag scoping, TTL, second-factor auth, explicit cursor instructions, and passing 429s through—matter immensely. Skip them, and you will find out why the hard way.
What you get in exchange is powerful: a single URL that any AI client can consume, with financial tools that update the moment your schema does, tenant isolation baked directly into the token, and zero custom connector code to maintain per model provider.
FAQ
- How do I connect an AI agent to Brex expense data?
- Deploy an MCP server bound to a single Brex integrated account, complete the OAuth 2.0 flow with required scopes, and paste the MCP URL into your AI client. The server translates the agent's natural language intent into JSON-RPC tool calls, managing Brex's tokens and schemas automatically.
- What Brex API scopes do I need for an AI agent?
- At minimum, you need openid and offline_access for the auth flow, plus resource scopes such as expenses, transactions.readonly, cards, budgets, and team. Scopes cannot be added to an existing token, so request everything the agent could plausibly need at initial consent.
- Does the MCP server automatically retry Brex rate limit errors?
- No. Truto normalizes Brex's rate limits into standard IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) and passes HTTP 429 errors directly to the caller. Retry and backoff logic belongs in your agent orchestrator, not the MCP layer.
- How are Brex MCP tools generated for the AI agent?
- Tools are dynamically generated from Brex API documentation and resource schemas on every request. The server enumerates resources, checks for documentation, and auto-injects required parameters like limit and next_cursor, ensuring your agent always has accurate definitions.
- How do I paginate Brex transactions from an AI agent?
- Brex uses cursor-based pagination on all list endpoints. The MCP server exposes next_cursor as a tool input with explicit instructions for the model to send the cursor back verbatim without decoding it. The agent loops until next_cursor is null to guarantee completeness.