Skip to main content
Glama
boldcommerce

Magento 2 MCP Server

by boldcommerce

get_revenue

Calculate total revenue for a Magento 2 store within specified date ranges and order status filters, with tax inclusion options.

Instructions

Get the total revenue for a given date range

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
date_rangeYesDate range expression (e.g., 'today', 'yesterday', 'last week', 'this month', 'YTD', or a specific date range like '2023-01-01 to 2023-01-31')
statusNoFilter by order status (e.g., 'processing', 'complete', 'pending')
include_taxNoWhether to include tax in the revenue calculation (default: true)

Implementation Reference

  • mcp-server.js:851-938 (registration)
    Registration of the 'get_revenue' MCP tool using server.tool(), including description, Zod input schema, and the complete inline async handler function that implements the revenue calculation logic.
    server.tool(
      "get_revenue",
      "Get the total revenue for a given date range",
      {
        date_range: z.string().describe("Date range expression (e.g., 'today', 'yesterday', 'last week', 'this month', 'YTD', or a specific date range like '2023-01-01 to 2023-01-31')"),
        status: z.string().optional().describe("Filter by order status (e.g., 'processing', 'complete', 'pending')"),
        include_tax: z.boolean().optional().describe("Whether to include tax in the revenue calculation (default: true)")
      },
      async ({ date_range, status, include_tax = true }) => {
        try {
          // Parse the date range expression
          const dateRange = parseDateExpression(date_range);
          
          // Build the search criteria for the date range
          let searchCriteria = buildDateRangeFilter('created_at', dateRange.startDate, dateRange.endDate);
          
          // Add status filter if provided
          if (status) {
            searchCriteria += `&searchCriteria[filter_groups][2][filters][0][field]=status&` +
                              `searchCriteria[filter_groups][2][filters][0][value]=${encodeURIComponent(status)}&` +
                              `searchCriteria[filter_groups][2][filters][0][condition_type]=eq`;
          }
          
          // Fetch all orders using the helper function
          const allOrders = await fetchAllPages('/orders', searchCriteria);
          
          // Calculate total revenue
          let totalRevenue = 0;
          let totalTax = 0;
          let orderCount = 0;
          
          if (allOrders && Array.isArray(allOrders)) {
            orderCount = allOrders.length;
            
            allOrders.forEach(order => {
              // Use grand_total which includes tax, shipping, etc.
              totalRevenue += parseFloat(order.grand_total || 0);
              
              // Track tax separately
              totalTax += parseFloat(order.tax_amount || 0);
            });
          }
          
          // Adjust revenue if tax should be excluded
          const revenueWithoutTax = totalRevenue - totalTax;
          const finalRevenue = include_tax ? totalRevenue : revenueWithoutTax;
          
          // Format the response
          const result = {
            query: {
              date_range: dateRange.description,
              status: status || 'All',
              include_tax: include_tax,
              period: {
                start_date: format(dateRange.startDate, 'yyyy-MM-dd'),
                end_date: format(dateRange.endDate, 'yyyy-MM-dd')
              }
            },
            result: {
              revenue: parseFloat(finalRevenue.toFixed(2)),
              currency: 'USD', // This should be dynamically determined from the store configuration
              order_count: orderCount,
              average_order_value: orderCount > 0 ? parseFloat((finalRevenue / orderCount).toFixed(2)) : 0,
              tax_amount: parseFloat(totalTax.toFixed(2))
            }
          };
          
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(result, null, 2)
              }
            ]
          };
        } catch (error) {
          return {
            content: [
              {
                type: "text",
                text: `Error fetching revenue: ${error.message}`
              }
            ],
            isError: true
          };
        }
      }
    );
  • The core handler function for the get_revenue tool. Parses date range, applies filters, fetches all orders via Magento API, computes total revenue (with optional tax exclusion), order count, average order value, and returns structured JSON response.
    async ({ date_range, status, include_tax = true }) => {
      try {
        // Parse the date range expression
        const dateRange = parseDateExpression(date_range);
        
        // Build the search criteria for the date range
        let searchCriteria = buildDateRangeFilter('created_at', dateRange.startDate, dateRange.endDate);
        
        // Add status filter if provided
        if (status) {
          searchCriteria += `&searchCriteria[filter_groups][2][filters][0][field]=status&` +
                            `searchCriteria[filter_groups][2][filters][0][value]=${encodeURIComponent(status)}&` +
                            `searchCriteria[filter_groups][2][filters][0][condition_type]=eq`;
        }
        
        // Fetch all orders using the helper function
        const allOrders = await fetchAllPages('/orders', searchCriteria);
        
        // Calculate total revenue
        let totalRevenue = 0;
        let totalTax = 0;
        let orderCount = 0;
        
        if (allOrders && Array.isArray(allOrders)) {
          orderCount = allOrders.length;
          
          allOrders.forEach(order => {
            // Use grand_total which includes tax, shipping, etc.
            totalRevenue += parseFloat(order.grand_total || 0);
            
            // Track tax separately
            totalTax += parseFloat(order.tax_amount || 0);
          });
        }
        
        // Adjust revenue if tax should be excluded
        const revenueWithoutTax = totalRevenue - totalTax;
        const finalRevenue = include_tax ? totalRevenue : revenueWithoutTax;
        
        // Format the response
        const result = {
          query: {
            date_range: dateRange.description,
            status: status || 'All',
            include_tax: include_tax,
            period: {
              start_date: format(dateRange.startDate, 'yyyy-MM-dd'),
              end_date: format(dateRange.endDate, 'yyyy-MM-dd')
            }
          },
          result: {
            revenue: parseFloat(finalRevenue.toFixed(2)),
            currency: 'USD', // This should be dynamically determined from the store configuration
            order_count: orderCount,
            average_order_value: orderCount > 0 ? parseFloat((finalRevenue / orderCount).toFixed(2)) : 0,
            tax_amount: parseFloat(totalTax.toFixed(2))
          }
        };
        
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(result, null, 2)
            }
          ]
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `Error fetching revenue: ${error.message}`
            }
          ],
          isError: true
        };
      }
    }
  • Zod schema defining input parameters for the get_revenue tool: required date_range string, optional status and include_tax.
    {
      date_range: z.string().describe("Date range expression (e.g., 'today', 'yesterday', 'last week', 'this month', 'YTD', or a specific date range like '2023-01-01 to 2023-01-31')"),
      status: z.string().optional().describe("Filter by order status (e.g., 'processing', 'complete', 'pending')"),
      include_tax: z.boolean().optional().describe("Whether to include tax in the revenue calculation (default: true)")
    },
  • Helper function to parse natural language date range expressions into startDate, endDate (Date objects) and a human-readable description, used by get_revenue and similar tools.
    function parseDateExpression(dateExpression) {
      const now = new Date();
      const currentYear = now.getFullYear();
      const currentMonth = now.getMonth();
      const currentDay = now.getDate();
      
      // Normalize the date expression
      const normalizedExpression = dateExpression.toLowerCase().trim();
      
      // Handle relative date expressions
      switch (normalizedExpression) {
        case 'today':
          return {
            startDate: startOfDay(now),
            endDate: endOfDay(now),
            description: 'Today'
          };
        case 'yesterday':
          const yesterday = subDays(now, 1);
          return {
            startDate: startOfDay(yesterday),
            endDate: endOfDay(yesterday),
            description: 'Yesterday'
          };
        case 'this week':
          return {
            startDate: startOfWeek(now, { weekStartsOn: 1 }), // Week starts on Monday
            endDate: endOfDay(now),
            description: 'This week'
          };
        case 'last week':
          const lastWeekStart = subDays(startOfWeek(now, { weekStartsOn: 1 }), 7);
          const lastWeekEnd = subDays(endOfWeek(now, { weekStartsOn: 1 }), 7);
          return {
            startDate: lastWeekStart,
            endDate: lastWeekEnd,
            description: 'Last week'
          };
        case 'this month':
          return {
            startDate: startOfMonth(now),
            endDate: endOfDay(now),
            description: 'This month'
          };
        case 'last month':
          const lastMonth = new Date(currentYear, currentMonth - 1, 1);
          return {
            startDate: startOfMonth(lastMonth),
            endDate: endOfMonth(lastMonth),
            description: 'Last month'
          };
        case 'ytd':
        case 'this ytd':
        case 'this year to date':
        case 'year to date':
          return {
            startDate: startOfYear(now),
            endDate: endOfDay(now),
            description: 'Year to date'
          };
        case 'last year':
          const lastYear = new Date(currentYear - 1, 0, 1);
          return {
            startDate: startOfYear(lastYear),
            endDate: endOfYear(lastYear),
            description: 'Last year'
          };
        default:
          // Try to parse as ISO date or other common formats
          try {
            // Check if it's a single date (not a range)
            const parsedDate = parseISO(normalizedExpression);
            if (isValid(parsedDate)) {
              return {
                startDate: startOfDay(parsedDate),
                endDate: endOfDay(parsedDate),
                description: format(parsedDate, 'yyyy-MM-dd')
              };
            }
            
            // Check if it's a date range in format "YYYY-MM-DD to YYYY-MM-DD"
            const rangeParts = normalizedExpression.split(' to ');
            if (rangeParts.length === 2) {
              const startDate = parseISO(rangeParts[0]);
              const endDate = parseISO(rangeParts[1]);
              
              if (isValid(startDate) && isValid(endDate)) {
                return {
                  startDate: startOfDay(startDate),
                  endDate: endOfDay(endDate),
                  description: `${format(startDate, 'yyyy-MM-dd')} to ${format(endDate, 'yyyy-MM-dd')}`
                };
              }
            }
            
            // If we can't parse it, throw an error
            throw new Error(`Unable to parse date expression: ${dateExpression}`);
          } catch (error) {
            throw new Error(`Invalid date expression: ${dateExpression}. ${error.message}`);
          }
      }
    }
  • Helper to fetch and concatenate all paginated results from a Magento API endpoint, handling dynamic pagination based on total_count.
    async function fetchAllPages(endpoint, baseSearchCriteria) {
      const pageSize = 100; // Or make this configurable if needed
      let currentPage = 1;
      let allItems = [];
      let totalCount = 0;
      
      do {
        // Build search criteria for the current page, ensuring baseSearchCriteria doesn't already have pagination
        let currentPageSearchCriteria = baseSearchCriteria;
        if (!currentPageSearchCriteria.includes('searchCriteria[pageSize]')) {
          currentPageSearchCriteria += `&searchCriteria[pageSize]=${pageSize}`;
        }
        if (!currentPageSearchCriteria.includes('searchCriteria[currentPage]')) {
          currentPageSearchCriteria += `&searchCriteria[currentPage]=${currentPage}`;
        } else {
          // If currentPage is already there, replace it (less common case)
          currentPageSearchCriteria = currentPageSearchCriteria.replace(/searchCriteria\[currentPage\]=\d+/, `searchCriteria[currentPage]=${currentPage}`);
        }
    
        // Make the API call for the current page
        const responseData = await callMagentoApi(`${endpoint}?${currentPageSearchCriteria}`);
        
        if (responseData.items && Array.isArray(responseData.items)) {
          allItems = allItems.concat(responseData.items);
        }
        
        // Update total count (only needs to be set once)
        if (currentPage === 1) {
          totalCount = responseData.total_count || 0;
        }
        
        // Check if we need to fetch more pages
        if (totalCount <= allItems.length || !responseData.items || responseData.items.length < pageSize) {
          break; // Exit loop if all items are fetched or last page had less than pageSize items
        }
        
        currentPage++;
        
      } while (true); // Loop continues until break
      
      return allItems; // Return the aggregated list of items
    }
  • Helper to construct Magento API searchCriteria query string for filtering records by date range on a given field.
    function buildDateRangeFilter(field, startDate, endDate) {
      const formattedStartDate = formatDateForMagento(startDate);
      const formattedEndDate = formatDateForMagento(endDate);
      
      return [
        `searchCriteria[filter_groups][0][filters][0][field]=${field}`,
        `searchCriteria[filter_groups][0][filters][0][value]=${encodeURIComponent(formattedStartDate)}`,
        `searchCriteria[filter_groups][0][filters][0][condition_type]=gteq`,
        `searchCriteria[filter_groups][1][filters][0][field]=${field}`,
        `searchCriteria[filter_groups][1][filters][0][value]=${encodeURIComponent(formattedEndDate)}`,
        `searchCriteria[filter_groups][1][filters][0][condition_type]=lteq`
      ].join('&');
    }

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/boldcommerce/magento2-mcp'

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