Skip to main content
Glama
crazyrabbitLTC

Brex MCP Server

get_card_transactions

Retrieve and list primary card transactions from Brex financial platform with filtering options for user IDs, date ranges, and expanded merchant details.

Instructions

LIST: Primary card transactions. Returns complete transaction objects. Example: {"limit":10,"posted_at_start":"2025-08-01T00:00:00Z","expand":["merchant"]}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cursorNoPagination cursor
limitNoItems per page (default 50)
user_idsNoOptional filter by user IDs
posted_at_startNoISO timestamp to start from
expandNoFields to expand

Implementation Reference

  • Main execution logic for the get_card_transactions tool: parameter validation, API call to Brex client, response projection and summarization if token limit exceeded, formatted JSON output.
    registerToolHandler("get_card_transactions", async (request: ToolCallRequest) => {
      try {
        const params = validateParams(request.params.arguments);
        const client = getBrexClient();
    
        // Do not pass expand parameter to card transactions API
        // The endpoint doesn't support it and returns 400 errors
        const resp = await client.getCardTransactions({
          cursor: params.cursor,
          limit: params.limit,
          user_ids: params.user_ids,
          posted_at_start: params.posted_at_start
          // expand is intentionally omitted - not supported by this endpoint
        });
    
        const items = Array.isArray(resp.items) ? resp.items : [];
        // Project via limiter infra (wrap items into Expense type-compatible projection path names kept simple)
        const projectionFields = params.fields && params.fields.length ? params.fields : DEFAULT_TX_FIELDS;
        const payloadText = JSON.stringify(items);
        const tooBig = estimateTokens(payloadText) > 24000;
        const summarized = params.summary_only || tooBig;
        const outputItems = summarized
          ? items.map((t: any) => {
              const out: any = {};
              projectionFields.forEach((p) => {
                const parts = p.split('.');
                let cur: any = t;
                for (const part of parts) {
                  cur = cur?.[part];
                  if (cur === undefined) break;
                }
                if (cur !== undefined) {
                  let o: any = out;
                  for (let i = 0; i < parts.length - 1; i++) {
                    o[parts[i]] = o[parts[i]] ?? {};
                    o = o[parts[i]];
                  }
                  o[parts[parts.length - 1]] = cur;
                }
              });
              return out;
            })
          : items;
    
        return {
          content: [{
            type: "text",
            text: JSON.stringify({
              transactions: outputItems,
              meta: {
                count: outputItems.length,
                next_cursor: (resp as any).next_cursor || null,
                summary_applied: summarized
              }
            }, null, 2)
          }]
        };
      } catch (error) {
        logError(`Error in get_card_transactions: ${error instanceof Error ? error.message : String(error)}`);
        throw error;
      }
    });
  • TypeScript interface defining the input parameters for the get_card_transactions tool.
    interface GetCardTransactionsParams {
      cursor?: string;
      limit?: number;
      user_ids?: string[];
      posted_at_start?: string;
      expand?: string[]; // Kept for interface compatibility but not used
      summary_only?: boolean;
      fields?: string[];
    }
  • Registration function that adds the get_card_transactions handler to the toolHandlers map, called during server initialization.
    export function registerGetCardTransactions(_server: Server): void {
      registerToolHandler("get_card_transactions", async (request: ToolCallRequest) => {
        try {
          const params = validateParams(request.params.arguments);
          const client = getBrexClient();
    
          // Do not pass expand parameter to card transactions API
          // The endpoint doesn't support it and returns 400 errors
          const resp = await client.getCardTransactions({
            cursor: params.cursor,
            limit: params.limit,
            user_ids: params.user_ids,
            posted_at_start: params.posted_at_start
            // expand is intentionally omitted - not supported by this endpoint
          });
    
          const items = Array.isArray(resp.items) ? resp.items : [];
          // Project via limiter infra (wrap items into Expense type-compatible projection path names kept simple)
          const projectionFields = params.fields && params.fields.length ? params.fields : DEFAULT_TX_FIELDS;
          const payloadText = JSON.stringify(items);
          const tooBig = estimateTokens(payloadText) > 24000;
          const summarized = params.summary_only || tooBig;
          const outputItems = summarized
            ? items.map((t: any) => {
                const out: any = {};
                projectionFields.forEach((p) => {
                  const parts = p.split('.');
                  let cur: any = t;
                  for (const part of parts) {
                    cur = cur?.[part];
                    if (cur === undefined) break;
                  }
                  if (cur !== undefined) {
                    let o: any = out;
                    for (let i = 0; i < parts.length - 1; i++) {
                      o[parts[i]] = o[parts[i]] ?? {};
                      o = o[parts[i]];
                    }
                    o[parts[parts.length - 1]] = cur;
                  }
                });
                return out;
              })
            : items;
    
          return {
            content: [{
              type: "text",
              text: JSON.stringify({
                transactions: outputItems,
                meta: {
                  count: outputItems.length,
                  next_cursor: (resp as any).next_cursor || null,
                  summary_applied: summarized
                }
              }, null, 2)
            }]
          };
        } catch (error) {
          logError(`Error in get_card_transactions: ${error instanceof Error ? error.message : String(error)}`);
          throw error;
        }
      });
    }
  • Top-level import and registration call for the get_card_transactions tool during registerTools(server). Note: import at line 18, call at line 56.
    import { registerGetCardTransactions } from "./getCardTransactions.js";
    import { registerGetCashAccountStatements } from "./getCashAccountStatements.js";
    import { registerGetExpenseById } from "./getExpenseById.js";
    import { registerGetCardExpenseById } from "./getCardExpenseById.js";
    import { registerGetCardStatementsPrimary } from "./getCardStatementsPrimary.js";
    import { registerGetCashTransactions } from "./getCashTransactions.js";
    import { registerGetBudgets } from "./getBudgets.js";
    import { registerGetBudgetById } from "./getBudgetById.js";
    import { registerGetSpendLimits } from "./getSpendLimits.js";
    import { registerGetSpendLimitById } from "./getSpendLimitById.js";
    import { registerGetBudgetPrograms } from "./getBudgetPrograms.js";
    import { registerGetBudgetProgramById } from "./getBudgetProgramById.js";
    import { logError } from "../utils/logger.js";
    import { ExpenseType, ExpenseStatus, ExpensePaymentStatus } from "../services/brex/expenses-types.js";
    
    // Minimal request shape passed to individual tool handlers
    export type ToolCallRequest = { params: { name?: string; arguments?: Record<string, unknown> } };
    
    // Store tool handlers
    export const toolHandlers = new Map<string, (request: ToolCallRequest) => Promise<unknown>>();
    
    /**
     * Registers all tools with the server
     * @param server The MCP server instance
     */
    export function registerTools(server: Server): void {
      // Register tool handlers
      registerGetTransactions(server);
      registerGetExpenses(server);
      registerGetAccountDetails(server);
      registerUploadReceipt(server);
      registerMatchReceipt(server);
      registerUpdateExpense(server);
      
      // Register pagination-aware tool handlers
      registerGetAllAccounts(server);
      registerGetAllExpenses(server);
      registerGetAllCardExpenses(server);
      registerGetCardTransactions(server);
  • Input validation and normalization function for tool parameters, including type coercion, range checks, and date parsing.
    function validateParams(input: unknown): GetCardTransactionsParams {
      const raw = (input || {}) as Record<string, unknown>;
      const out: GetCardTransactionsParams = {};
      if (raw.cursor !== undefined) out.cursor = String(raw.cursor);
      if (raw.limit !== undefined) {
        const n = parseInt(String(raw.limit), 10);
        if (isNaN(n) || n <= 0 || n > 100) throw new Error("Invalid limit (1..100)");
        out.limit = n;
      }
      if (raw.user_ids !== undefined) out.user_ids = Array.isArray(raw.user_ids) ? raw.user_ids.map(String) : [String(raw.user_ids)];
      if (raw.posted_at_start !== undefined) out.posted_at_start = new Date(String(raw.posted_at_start)).toISOString();
      // NOTE: expand parameter is intentionally ignored for card transactions
      // The Brex card transactions API endpoint does not support expand parameters
      // and will return 400 "Unsupported entity expansion" if expand is passed.
      // Merchant information is always included by default in the response.
      if (raw.expand !== undefined) out.expand = Array.isArray(raw.expand) ? raw.expand.map(String) : [String(raw.expand)];
      if (raw.summary_only !== undefined) out.summary_only = Boolean(raw.summary_only);
      if (raw.fields !== undefined) out.fields = Array.isArray(raw.fields) ? raw.fields.map(String) : [String(raw.fields)];
      return out;
    }
  • Brex API client method that performs the HTTP GET to /v2/transactions/card/primary, handling pagination params and error logging.
    async getCardTransactions(options?: {
      cursor?: string;
      limit?: number;
      user_ids?: string[];
      posted_at_start?: string;
      expand?: string[];
    }): Promise<PageCardTransaction> {
      try {
        const params: Record<string, unknown> = {};
        if (options) {
          if (options.cursor) params.cursor = options.cursor;
          if (options.limit) params.limit = options.limit;
          if (options.user_ids && options.user_ids.length > 0) params.user_ids = options.user_ids;
          if (options.posted_at_start) params.posted_at_start = options.posted_at_start;
          if (options.expand && options.expand.length > 0) params['expand[]'] = options.expand;
        }
    
        logDebug('Fetching card transactions from Brex API');
        const response = await this.client.get('/v2/transactions/card/primary', { params });
        logDebug(`Successfully fetched ${response.data.items.length} card transactions`);
        return response.data;
      } catch (error) {
        this.handleApiError(error, 'GET', '/v2/transactions/card/primary');
        throw error;
      }
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/crazyrabbitLTC/mcp-brex-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server