Skip to main content
Glama
crazyrabbitLTC

Brex MCP Server

get_all_expenses

Retrieve and filter expense data from Brex with pagination, supporting parameters like status, date ranges, amount thresholds, and expense types for financial analysis.

Instructions

LIST: Paginated expenses with filters. Returns complete expense objects. Example: {"page_size":5,"max_items":5,"status":["APPROVED"],"window_days":7,"min_amount":100}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
page_sizeNoNumber of items per page (default: 50, max: 100)
max_itemsNoMaximum total number of items to retrieve across all pages
expense_typeNoFilter expenses by type
statusNoFilter expenses by status
payment_statusNoFilter expenses by payment status
start_dateNoFilter expenses created on or after this date (ISO format)
end_dateNoFilter expenses created on or before this date (ISO format)
window_daysNoOptional batching window in days to split large date ranges
min_amountNoClient-side minimum purchased_amount.amount filter
max_amountNoClient-side maximum purchased_amount.amount filter
expandNoFields to expand (e.g., merchant, receipts)

Implementation Reference

  • The primary tool handler for 'get_all_expenses'. Validates parameters, fetches expenses using pagination and filters via Brex API, handles errors, and returns formatted JSON response with metadata.
    registerToolHandler("get_all_expenses", async (request: ToolCallRequest) => {
      try {
        // Validate parameters
        const params = validateParams(request.params.arguments);
        logDebug(`Getting all expenses with params: ${JSON.stringify(params)}`);
        
        // Get Brex client
        const brexClient = getBrexClient();
        
        try {
          // Fetch all expenses with pagination
          const allExpenses = await fetchAllExpenses(brexClient, params);
          
          logDebug(`Successfully fetched ${allExpenses.length} total expenses`);
          
          // Return raw results with pagination metadata
          const result = {
            expenses: allExpenses,
            meta: {
              total_count: allExpenses.length,
              requested_parameters: params
            }
          };
          
          return {
            content: [{
              type: "text",
              text: JSON.stringify(result, null, 2)
            }]
          };
        } catch (apiError) {
          logError(`Error calling Brex API: ${apiError instanceof Error ? apiError.message : String(apiError)}`);
          throw new Error(`Failed to get expenses: ${apiError instanceof Error ? apiError.message : String(apiError)}`);
        }
      } catch (error) {
        logError(`Error in get_all_expenses tool: ${error instanceof Error ? error.message : String(error)}`);
        throw error;
      }
    });
  • JSON Schema definition for the 'get_all_expenses' tool input parameters, provided in the MCP listTools response.
    name: "get_all_expenses",
    description: "LIST: Paginated expenses with filters. Returns complete expense objects. Example: {\"page_size\":5,\"max_items\":5,\"status\":[\"APPROVED\"],\"window_days\":7,\"min_amount\":100}",
    inputSchema: {
      type: "object",
      properties: {
        page_size: {
          type: "number",
          description: "Number of items per page (default: 50, max: 100)"
        },
        max_items: {
          type: "number",
          description: "Maximum total number of items to retrieve across all pages"
        },
        expense_type: {
          type: "array",
          items: {
            type: "string",
            enum: Object.values(ExpenseType)
          },
          description: "Filter expenses by type"
        },
        status: {
          type: "array",
          items: {
            type: "string",
            enum: Object.values(ExpenseStatus)
          },
          description: "Filter expenses by status"
        },
        payment_status: {
          type: "array",
          items: {
            type: "string",
            enum: Object.values(ExpensePaymentStatus)
          },
          description: "Filter expenses by payment status"
        },
        start_date: {
          type: "string",
          description: "Filter expenses created on or after this date (ISO format)"
        },
        end_date: {
          type: "string",
          description: "Filter expenses created on or before this date (ISO format)"
        },
        window_days: {
          type: "number",
          description: "Optional batching window in days to split large date ranges"
        },
        min_amount: {
          type: "number",
          description: "Client-side minimum purchased_amount.amount filter"
        },
        max_amount: {
          type: "number",
          description: "Client-side maximum purchased_amount.amount filter"
        },
        expand: {
          type: "array",
          items: { type: "string" },
          description: "Fields to expand (e.g., merchant, receipts)"
        }
      }
    }
  • Registration function that sets up the 'get_all_expenses' tool handler using the shared registerToolHandler mechanism.
    export function registerGetAllExpenses(_server: Server): void {
      registerToolHandler("get_all_expenses", async (request: ToolCallRequest) => {
        try {
          // Validate parameters
          const params = validateParams(request.params.arguments);
          logDebug(`Getting all expenses with params: ${JSON.stringify(params)}`);
          
          // Get Brex client
          const brexClient = getBrexClient();
          
          try {
            // Fetch all expenses with pagination
            const allExpenses = await fetchAllExpenses(brexClient, params);
            
            logDebug(`Successfully fetched ${allExpenses.length} total expenses`);
            
            // Return raw results with pagination metadata
            const result = {
              expenses: allExpenses,
              meta: {
                total_count: allExpenses.length,
                requested_parameters: params
              }
            };
            
            return {
              content: [{
                type: "text",
                text: JSON.stringify(result, null, 2)
              }]
            };
          } catch (apiError) {
            logError(`Error calling Brex API: ${apiError instanceof Error ? apiError.message : String(apiError)}`);
            throw new Error(`Failed to get expenses: ${apiError instanceof Error ? apiError.message : String(apiError)}`);
          }
        } catch (error) {
          logError(`Error in get_all_expenses tool: ${error instanceof Error ? error.message : String(error)}`);
          throw error;
        }
      });
    } 
  • Invocation of the registration function during overall tools setup in registerTools.
    registerGetAllExpenses(server);
  • Helper function implementing the core logic for fetching all expenses with pagination, date window batching, API filtering, and client-side amount filtering.
    async function fetchAllExpenses(client: BrexClient, params: GetAllExpensesParams): Promise<unknown[]> {
      const pageSize = params.page_size || 50;
      const maxItems = params.max_items || 100; // Default to reasonable limit instead of Infinity
      let allExpenses: unknown[] = [];
      
      const start = params.start_date ? new Date(params.start_date) : undefined;
      const end = params.end_date ? new Date(params.end_date) : undefined;
      const windowDays = params.window_days && start && end ? params.window_days : undefined;
      
      const windows: Array<{ start?: string; end?: string }> = [];
      if (windowDays && start && end) {
        const cursorStart = new Date(start);
        while (cursorStart <= end && allExpenses.length < maxItems) {
          const cursorEnd = new Date(cursorStart);
          cursorEnd.setUTCDate(cursorEnd.getUTCDate() + windowDays);
          if (cursorEnd > end) cursorEnd.setTime(end.getTime());
          windows.push({ start: cursorStart.toISOString(), end: cursorEnd.toISOString() });
          // advance by windowDays
          cursorStart.setUTCDate(cursorStart.getUTCDate() + windowDays);
        }
      } else {
        windows.push({ start: params.start_date, end: params.end_date });
      }
      
      for (const w of windows) {
        let cursor: string | undefined = undefined;
        let hasMore = true;
        while (hasMore && allExpenses.length < maxItems) {
          try {
            const limit = Math.min(pageSize, maxItems - allExpenses.length);
            const requestParams: ListExpensesParams = {
              limit,
              cursor,
              expand: params.expand || [] // Use provided expand array or default to empty
            };
            if (params.expense_type) requestParams.expense_type = params.expense_type;
            if (params.status) requestParams.status = params.status;
            if (params.payment_status) requestParams.payment_status = params.payment_status;
            if (w.start) requestParams.updated_at_start = w.start;
            if (w.end) requestParams.updated_at_end = w.end;
            
            logDebug(`Fetching expenses page (window ${w.start || 'none'}..${w.end || 'none'}) cursor: ${cursor || 'initial'}`);
            const response = await client.getExpenses(requestParams);
            
            let validExpenses = response.items.filter(isExpense);
            
            // Client-side end_date filtering if needed
            if (w.end && !('updated_at_end' in requestParams)) {
              const endDate = new Date(w.end).getTime();
              validExpenses = validExpenses.filter(expense => new Date(expense.updated_at).getTime() <= endDate);
            }
            
            // Client-side amount thresholds
            if (params.min_amount !== undefined) {
              validExpenses = validExpenses.filter(e => typeof e.purchased_amount?.amount === 'number' && e.purchased_amount.amount >= (params.min_amount as number));
            }
            if (params.max_amount !== undefined) {
              validExpenses = validExpenses.filter(e => typeof e.purchased_amount?.amount === 'number' && e.purchased_amount.amount <= (params.max_amount as number));
            }
            
            allExpenses = allExpenses.concat(validExpenses);
            logDebug(`Retrieved ${validExpenses.length} expenses (total: ${allExpenses.length})`);
            cursor = response.nextCursor;
            hasMore = !!cursor;
          } catch (error) {
            logError(`Error fetching expenses page: ${error instanceof Error ? error.message : String(error)}`);
            throw error;
          }
        }
        if (allExpenses.length >= maxItems) break;
      }
      return allExpenses;
    }

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