Skip to main content
Glama
akutishevsky

LunchMoney MCP Server

get_transactions

Retrieve financial transactions from LunchMoney within specified date ranges using filters for tags, categories, accounts, and status to analyze spending patterns.

Instructions

Retrieve transactions within a date range with optional filters

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
inputYes

Implementation Reference

  • Handler function that constructs API parameters from input, fetches transactions from Lunchmoney API, and returns JSON response.
        async ({ input }) => {
            const { baseUrl, lunchmoneyApiToken } = getConfig();
    
            const params = new URLSearchParams({
                start_date: input.start_date,
                end_date: input.end_date,
            });
    
            if (input.tag_id !== undefined)
                params.append("tag_id", input.tag_id.toString());
            if (input.recurring_id !== undefined)
                params.append("recurring_id", input.recurring_id.toString());
            if (input.plaid_account_id !== undefined)
                params.append(
                    "plaid_account_id",
                    input.plaid_account_id.toString()
                );
            if (input.category_id !== undefined)
                params.append("category_id", input.category_id.toString());
            if (input.asset_id !== undefined)
                params.append("asset_id", input.asset_id.toString());
            if (input.is_group !== undefined)
                params.append("is_group", input.is_group.toString());
            if (input.status !== undefined)
                params.append("status", input.status);
            if (input.offset !== undefined)
                params.append("offset", input.offset.toString());
            if (input.limit !== undefined)
                params.append("limit", input.limit.toString());
            if (input.debit_as_negative !== undefined)
                params.append(
                    "debit_as_negative",
                    input.debit_as_negative.toString()
                );
    
            const response = await fetch(`${baseUrl}/transactions?${params}`, {
                headers: {
                    Authorization: `Bearer ${lunchmoneyApiToken}`,
                },
            });
    
            if (!response.ok) {
                return {
                    content: [
                        {
                            type: "text",
                            text: `Failed to get transactions: ${response.statusText}`,
                        },
                    ],
                };
            }
    
            const data = await response.json();
            const transactions: Transaction[] = data.transactions;
    
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify({
                            transactions,
                            has_more: data.has_more,
                        }),
                    },
                ],
            };
        }
    );
  • Zod input schema defining parameters for filtering and paginating transactions.
    input: z.object({
        start_date: z
            .string()
            .describe("Start date in YYYY-MM-DD format"),
        end_date: z.string().describe("End date in YYYY-MM-DD format"),
        tag_id: z.number().optional().describe("Filter by tag ID"),
        recurring_id: z
            .number()
            .optional()
            .describe("Filter by recurring expense ID"),
        plaid_account_id: z
            .number()
            .optional()
            .describe("Filter by Plaid account ID"),
        category_id: z
            .number()
            .optional()
            .describe("Filter by category ID"),
        asset_id: z.number().optional().describe("Filter by asset ID"),
        is_group: z
            .boolean()
            .optional()
            .describe("Filter by transaction groups"),
        status: z
            .string()
            .optional()
            .describe("Filter by status: cleared, uncleared, pending"),
        offset: z
            .number()
            .optional()
            .describe("Number of transactions to skip"),
        limit: z
            .number()
            .optional()
            .describe(
                "Maximum number of transactions to return (max 500)"
            ),
        debit_as_negative: z
            .boolean()
            .optional()
            .describe("Pass true to return debit amounts as negative"),
    }),
  • Registration of the get_transactions tool using server.tool, including name, description, schema, and handler.
    server.tool(
        "get_transactions",
        "Retrieve transactions within a date range with optional filters",
        {
            input: z.object({
                start_date: z
                    .string()
                    .describe("Start date in YYYY-MM-DD format"),
                end_date: z.string().describe("End date in YYYY-MM-DD format"),
                tag_id: z.number().optional().describe("Filter by tag ID"),
                recurring_id: z
                    .number()
                    .optional()
                    .describe("Filter by recurring expense ID"),
                plaid_account_id: z
                    .number()
                    .optional()
                    .describe("Filter by Plaid account ID"),
                category_id: z
                    .number()
                    .optional()
                    .describe("Filter by category ID"),
                asset_id: z.number().optional().describe("Filter by asset ID"),
                is_group: z
                    .boolean()
                    .optional()
                    .describe("Filter by transaction groups"),
                status: z
                    .string()
                    .optional()
                    .describe("Filter by status: cleared, uncleared, pending"),
                offset: z
                    .number()
                    .optional()
                    .describe("Number of transactions to skip"),
                limit: z
                    .number()
                    .optional()
                    .describe(
                        "Maximum number of transactions to return (max 500)"
                    ),
                debit_as_negative: z
                    .boolean()
                    .optional()
                    .describe("Pass true to return debit amounts as negative"),
            }),
        },
        async ({ input }) => {
            const { baseUrl, lunchmoneyApiToken } = getConfig();
    
            const params = new URLSearchParams({
                start_date: input.start_date,
                end_date: input.end_date,
            });
    
            if (input.tag_id !== undefined)
                params.append("tag_id", input.tag_id.toString());
            if (input.recurring_id !== undefined)
                params.append("recurring_id", input.recurring_id.toString());
            if (input.plaid_account_id !== undefined)
                params.append(
                    "plaid_account_id",
                    input.plaid_account_id.toString()
                );
            if (input.category_id !== undefined)
                params.append("category_id", input.category_id.toString());
            if (input.asset_id !== undefined)
                params.append("asset_id", input.asset_id.toString());
            if (input.is_group !== undefined)
                params.append("is_group", input.is_group.toString());
            if (input.status !== undefined)
                params.append("status", input.status);
            if (input.offset !== undefined)
                params.append("offset", input.offset.toString());
            if (input.limit !== undefined)
                params.append("limit", input.limit.toString());
            if (input.debit_as_negative !== undefined)
                params.append(
                    "debit_as_negative",
                    input.debit_as_negative.toString()
                );
    
            const response = await fetch(`${baseUrl}/transactions?${params}`, {
                headers: {
                    Authorization: `Bearer ${lunchmoneyApiToken}`,
                },
            });
    
            if (!response.ok) {
                return {
                    content: [
                        {
                            type: "text",
                            text: `Failed to get transactions: ${response.statusText}`,
                        },
                    ],
                };
            }
    
            const data = await response.json();
            const transactions: Transaction[] = data.transactions;
    
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify({
                            transactions,
                            has_more: data.has_more,
                        }),
                    },
                ],
            };
        }
    );
  • src/index.ts:26-26 (registration)
    Top-level call to registerTransactionTools which includes the get_transactions tool.
    registerTransactionTools(server);

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/akutishevsky/lunchmoney-mcp'

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