search_transactions
Find specific payments or payees by searching across transaction descriptions, merchant names, and references using full-text matching.
Instructions
Full-text search across transaction descriptions, merchant names, and references. Use for finding specific payments or payees.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search text — matched against description, merchant name, and reference. | |
| connectionId | No | ||
| dateFrom | No | ||
| dateTo | No | ||
| limit | No | Max results. Default 50. |
Implementation Reference
- src/tools/search-transactions.ts:14-33 (handler)The searchTransactions handler function. Fetches all transactions via listTransactions for the given date range, then filters locally by performing a case-insensitive substring match on description, merchantName, and reference fields. Returns up to 'limit' matches (default 50).
export async function searchTransactions( args: z.infer<typeof searchTransactionsSchema>, ): Promise<unknown> { // Fetch all transactions for the date range, then filter locally const transactions = await listTransactions({ connectionId: args.connectionId, dateFrom: args.dateFrom, dateTo: args.dateTo, }); const q = args.query.toLowerCase(); const limit = args.limit || 50; const matches = transactions.filter((t) => { const fields = [t.description, t.merchantName, t.reference].filter(Boolean); return fields.some((f) => f!.toLowerCase().includes(q)); }); return matches.slice(0, limit); } - Zod schema for search_transactions input: query (required string), connectionId (optional), dateFrom/dateTo (optional strings), limit (optional number, default 50).
export const searchTransactionsSchema = z.object({ query: z .string() .describe("Search text — matched against description, merchant name, and reference."), connectionId: z.string().optional(), dateFrom: z.string().optional(), dateTo: z.string().optional(), limit: z.number().optional().describe("Max results. Default 50."), }); - src/server.ts:37-42 (registration)Tool registration in the TOOLS array: name 'search_transactions', description, and inputSchema derived from searchTransactionsSchema.
{ name: "search_transactions", description: "Full-text search across transaction descriptions, merchant names, and references. Use for finding specific payments or payees.", inputSchema: z.toJSONSchema(searchTransactionsSchema), }, - src/server.ts:63-64 (registration)Handler mapping: the 'search_transactions' key maps to the searchTransactions function, parsing args with searchTransactionsSchema.
search_transactions: (args) => searchTransactions(searchTransactionsSchema.parse(args)), - The listTransactions helper function that searchTransactions delegates to. Fetches transactions from provider(s) across connections/accounts with caching, date range filtering, and local post-filters (amount, type).
export async function listTransactions( args: z.infer<typeof listTransactionsSchema>, ): Promise<Transaction[]> { const config = loadConfig(); const dateFrom = args.dateFrom || defaultDateFrom(config.defaults.transactionDays); const dateTo = args.dateTo || today(); const filter: TransactionFilter = { dateFrom, dateTo, amountMin: args.amountMin, amountMax: args.amountMax, type: args.type, limit: args.limit, }; // Resolve which connections and accounts to query const connections = args.connectionId ? [getConnection(config, args.connectionId)] : getAllConnections(config); const allTx: Transaction[] = []; for (const conn of connections) { const provider = getProvider(conn.provider); // Get account list (may come from cache) let accountIds: string[]; if (args.accountId) { accountIds = [args.accountId]; } else { const accounts = await provider.listAccounts(conn.config); accountIds = accounts.map((a) => a.uid); } for (const accId of accountIds) { const cacheKey = `tx:${conn.id}:${accId}:${dateFrom}:${dateTo}`; const cached = cache.get<Transaction[]>(cacheKey); if (cached) { allTx.push(...applyLocalFilters(cached, filter)); continue; } const transactions = await provider.listTransactions( conn.config, accId, { dateFrom, dateTo }, ); cache.set(cacheKey, transactions, TTL.TRANSACTIONS); allTx.push(...applyLocalFilters(transactions, filter)); } } // Sort by date descending (most recent first) allTx.sort((a, b) => b.date.localeCompare(a.date)); return args.limit ? allTx.slice(0, args.limit) : allTx; }