add_txns
Bulk-insert multiple transactions in one call for imports of over 5 rows. Automatically sorts by date and returns a per-ticker summary for confirmation.
Instructions
Bulk-insert transactions in one call. Use this for any import larger than ~5 rows (CSV / brokerage export / paste). Sorts by date ascending automatically — average cost depends on insertion order. Returns a per-ticker / per-type summary so you can confirm the import to the user. For one-off entries during conversation, prefer add_txn.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| transactions | Yes |
Implementation Reference
- apps/mcp/src/tools/mutate.ts:299-348 (handler)Handler function for the add_txns tool. Sorts transactions by date ascending, iterates over each transaction, inserts it into the database using db.insert(transactions).values(...).run(), tracks per-ticker and per-type counts, and returns a summary with inserted count, first/last dates, by_ticker, and by_type.
server.tool( 'add_txns', 'Bulk-insert transactions in one call. Use this for any import larger than ~5 rows (CSV / brokerage export / paste). Sorts by date ascending automatically — average cost depends on insertion order. Returns a per-ticker / per-type summary so you can confirm the import to the user. For one-off entries during conversation, prefer add_txn.', { transactions: z .array( z.object({ ticker: z.string(), date: z.string().describe('YYYY-MM-DD'), type: z.enum(['buy', 'sell', 'deposit', 'dividend', 'tax']), shares: z.number().positive(), price: z.number().min(0), currency: z.string().default('USD'), reason: z.string().optional(), }), ) .min(1), }, async ({ transactions: txns }) => { const db = getDb(); const sorted = [...txns].sort((a, b) => a.date.localeCompare(b.date)); const byTicker = new Map<string, number>(); const byType = new Map<string, number>(); for (const t of sorted) { const ticker = t.ticker.toUpperCase(); db.insert(transactions) .values({ ticker, date: t.date, type: t.type, shares: t.shares, price: t.price, currency: t.currency ?? 'USD', reason: t.reason ?? null, }) .run(); byTicker.set(ticker, (byTicker.get(ticker) ?? 0) + 1); byType.set(t.type, (byType.get(t.type) ?? 0) + 1); } return ok({ inserted: sorted.length, first_date: sorted[0].date, last_date: sorted[sorted.length - 1].date, by_ticker: Object.fromEntries(byTicker), by_type: Object.fromEntries(byType), }); }, ); - apps/mcp/src/tools/mutate.ts:302-316 (schema)Input schema for add_txns: takes an array (min 1) of transaction objects with fields ticker, date (YYYY-MM-DD), type (buy/sell/deposit/dividend/tax), shares (positive number), price (>=0), currency (default USD), and optional reason.
{ transactions: z .array( z.object({ ticker: z.string(), date: z.string().describe('YYYY-MM-DD'), type: z.enum(['buy', 'sell', 'deposit', 'dividend', 'tax']), shares: z.number().positive(), price: z.number().min(0), currency: z.string().default('USD'), reason: z.string().optional(), }), ) .min(1), }, - apps/mcp/src/tools/mutate.ts:299-348 (registration)Tool registration via server.tool('add_txns', ...) inside registerMutateTools function.
server.tool( 'add_txns', 'Bulk-insert transactions in one call. Use this for any import larger than ~5 rows (CSV / brokerage export / paste). Sorts by date ascending automatically — average cost depends on insertion order. Returns a per-ticker / per-type summary so you can confirm the import to the user. For one-off entries during conversation, prefer add_txn.', { transactions: z .array( z.object({ ticker: z.string(), date: z.string().describe('YYYY-MM-DD'), type: z.enum(['buy', 'sell', 'deposit', 'dividend', 'tax']), shares: z.number().positive(), price: z.number().min(0), currency: z.string().default('USD'), reason: z.string().optional(), }), ) .min(1), }, async ({ transactions: txns }) => { const db = getDb(); const sorted = [...txns].sort((a, b) => a.date.localeCompare(b.date)); const byTicker = new Map<string, number>(); const byType = new Map<string, number>(); for (const t of sorted) { const ticker = t.ticker.toUpperCase(); db.insert(transactions) .values({ ticker, date: t.date, type: t.type, shares: t.shares, price: t.price, currency: t.currency ?? 'USD', reason: t.reason ?? null, }) .run(); byTicker.set(ticker, (byTicker.get(ticker) ?? 0) + 1); byType.set(t.type, (byType.get(t.type) ?? 0) + 1); } return ok({ inserted: sorted.length, first_date: sorted[0].date, last_date: sorted[sorted.length - 1].date, by_ticker: Object.fromEntries(byTicker), by_type: Object.fromEntries(byType), }); }, ); - apps/mcp/src/tools/mutate.ts:12-12 (registration)The export function registerMutateTools is the registration entry point that registers add_txns along with other tools (add_txn, edit_txn, add_balances) on the McpServer.
export function registerMutateTools(server: McpServer): void {