actual-mcp
Version:
Actual Budget MCP server exposing API functionality
179 lines • 9.71 kB
JavaScript
import { z } from 'zod';
// Type definitions for tool arguments
export const GetTransactionsArgsSchema = z.object({
accountId: z.string(),
startDate: z.string().optional(),
endDate: z.string().optional(),
minAmount: z.number().optional(),
maxAmount: z.number().optional(),
categoryName: z.string().optional(),
payeeName: z.string().optional(),
limit: z.number().optional(),
});
export const SpendingByCategoryArgsSchema = z.object({
startDate: z.string().optional(),
endDate: z.string().optional(),
accountId: z.string().optional(),
includeIncome: z.boolean().optional(),
});
export const MonthlySummaryArgsSchema = z.object({
months: z.number().optional().default(3),
accountId: z.string().optional(),
});
export const BalanceHistoryArgsSchema = z.object({
accountId: z.string(),
includeOffBudget: z.boolean().optional().default(false),
months: z.number().optional().default(3),
});
export const FinancialInsightsArgsSchema = z.object({
startDate: z.string().optional(),
endDate: z.string().optional(),
});
export const BudgetReviewArgsSchema = z.object({
months: z.number().optional().default(3),
});
export const UpdateSubtransactionSchema = z.object({
id: z
.string()
.optional()
.describe('The ID of an existing subtransaction to update. Omit to add a new subtransaction.'),
amount: z.number().describe('Required for subtransactions. A currency amount as an integer'),
category: z.string().optional().describe('The ID of the category for this subtransaction'),
notes: z.string().optional().describe('Any additional notes for this subtransaction'),
});
export const UpdateTransactionArgsSchema = z.object({
id: z.string().describe('Required. The ID of the transaction to update'),
account: z.string().optional().describe('The ID of the account to move this transaction to'),
date: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/, 'date must be in YYYY-MM-DD format')
.optional()
.describe('Transaction date in YYYY-MM-DD format'),
amount: z
.number()
.optional()
.describe('A currency amount as an integer representing the value without decimal places. For example, USD amount of $120.30 would be 12030'),
payee: z.string().optional().describe('An existing payee ID'),
payee_name: z
.string()
.optional()
.describe('If given, a payee will be created with this name. If this matches an already existing payee, that payee will be used.'),
imported_payee: z
.string()
.optional()
.describe('This can be anything. Meant to represent the raw description when importing, allowing the user to see the original value'),
category: z.string().optional().describe('The ID of the category to assign to this transaction'),
notes: z.string().optional().describe('Any additional notes for the transaction'),
imported_id: z
.string()
.optional()
.describe('A unique id usually given by the bank, if importing. Use this to avoid duplicate transactions'),
cleared: z.boolean().optional().describe('A flag indicating if the transaction has cleared or not'),
subtransactions: z
.array(UpdateSubtransactionSchema)
.optional()
.describe("An array of subtransactions for a split transaction. Replaces existing subtransactions. If amounts don't equal total amount, API call will succeed but error will show in app"),
});
// Schema for update data passed to the API (without id, which is passed separately)
export const UpdateTransactionDataSchema = UpdateTransactionArgsSchema.omit({ id: true });
export const SubtransactionSchema = z.object({
amount: z.number().describe('Required for subtransactions. A currency amount as an integer'),
category: z.string().optional().describe('The ID of the category for this subtransaction'),
notes: z.string().optional().describe('Any additional notes for this subtransaction'),
});
export const CreateTransactionArgsSchema = z.object({
account: z.string().describe('Required. The ID of the account this transaction belongs to'),
date: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/, 'date must be in YYYY-MM-DD format')
.describe('Required. Transaction date in YYYY-MM-DD format'),
amount: z
.number()
.describe('Required. A currency amount as an integer representing the value without decimal places. For example, USD amount of $120.30 would be 12030'),
payee: z.string().optional().describe('An existing payee ID. This overrides payee_name if both are provided.'),
payee_name: z
.string()
.optional()
.describe('If given, a payee will be created with this name. If this matches an already existing payee, that payee will be used.'),
imported_payee: z
.string()
.optional()
.describe('This can be anything. Meant to represent the raw description when importing, allowing the user to see the original value'),
category: z.string().optional().describe('Recommended. The ID of the category to assign to this transaction'),
notes: z.string().optional().describe('Any additional notes for the transaction'),
imported_id: z
.string()
.optional()
.describe('A unique id usually given by the bank, if importing. Use this to avoid duplicate transactions'),
transfer_id: z
.string()
.optional()
.describe('If a transfer, the id of the corresponding transaction in the other account. Only set this when importing'),
transfer_account_id: z
.string()
.optional()
.describe('The ID of the destination account for a transfer. When provided, the transfer payee is automatically resolved and the counterpart transaction is created in the destination account. The amount should be negative (money leaving the source account).'),
cleared: z.boolean().optional().describe('A flag indicating if the transaction has cleared or not'),
subtransactions: z
.array(SubtransactionSchema)
.optional()
.describe("An array of subtransactions for a split transaction. If amounts don't equal total amount, API call will succeed but error will show in app"),
});
// Schema for transaction data passed to the API (without account and transfer_account_id, which are handled separately)
export const TransactionDataSchema = CreateTransactionArgsSchema.omit({ account: true, transfer_account_id: true });
// Subtransaction schema for imports — amount is a decimal (e.g. 3.24), converted to integer by the API wrapper
export const ImportSubtransactionSchema = z.object({
amount: z
.number()
.describe('Required. Amount as a decimal number (e.g. 3.24 for $3.24). Negative for expenses, positive for income.'),
category: z.string().optional().describe('The ID of the category for this subtransaction'),
notes: z.string().optional().describe('Any additional notes for this subtransaction'),
});
// Schema for a single transaction item in a bulk import.
// Accepts decimal amounts (e.g. 3.24) which are converted to integers by the API wrapper.
export const ImportTransactionItemSchema = z.object({
date: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/, 'date must be in YYYY-MM-DD format')
.describe('Required. Transaction date in YYYY-MM-DD format'),
amount: z
.number()
.describe('Required. Amount as a decimal number (e.g. 3.24 for $3.24). Negative for expenses, positive for income.'),
payee: z.string().optional().describe('An existing payee ID. This overrides payee_name if both are provided.'),
payee_name: z
.string()
.optional()
.describe('If given, a payee will be created with this name. If this matches an already existing payee, that payee will be used.'),
imported_payee: z
.string()
.optional()
.describe('This can be anything. Meant to represent the raw description when importing, allowing the user to see the original value'),
category: z.string().optional().describe('Recommended. The ID of the category to assign to this transaction'),
notes: z.string().optional().describe('Any additional notes for the transaction'),
imported_id: z
.string()
.optional()
.describe('A unique id usually given by the bank, if importing. Use this to avoid duplicate transactions'),
transfer_id: z
.string()
.optional()
.describe('If a transfer, the id of the corresponding transaction in the other account. Only set this when importing'),
cleared: z.boolean().optional().describe('A flag indicating if the transaction has cleared or not'),
subtransactions: z
.array(ImportSubtransactionSchema)
.optional()
.describe("An array of subtransactions for a split transaction. If amounts don't equal total amount, API call will succeed but error will show in app"),
});
export const ImportTransactionsArgsSchema = z.object({
accountId: z.string().describe('Required. The ID of the account to import transactions into'),
transactions: z
.array(ImportTransactionItemSchema)
.min(1)
.describe('Required. List of transactions to import. Use imported_id to avoid duplicate imports on repeated runs.'),
defaultCleared: z
.boolean()
.optional()
.describe('Default cleared state for all imported transactions (can be overridden per transaction)'),
dryRun: z.boolean().optional().describe('If true, validate and preview the import without persisting any changes'),
});
//# sourceMappingURL=types.js.map