add_txn
Add a single stock transaction (buy, sell, deposit, dividend, or tax) with ticker, date, shares, price, currency, and optional reason for trading.
Instructions
Insert one stock transaction. For bulk imports: first show the user your detected column mapping and total row count, wait for their confirmation, then call once per row in chronological order (average cost depends on insertion order). Types: buy/sell move shares; deposit adds shares (set price=0 for grants/transfers, or actual cost basis); dividend/tax record cash events (price = total amount, shares = 1). For buy/sell, capture the user's reason (the why behind the trade) when they share it — even one short sentence helps later analysis cross-check thesis vs outcome. The currency arg is the trade's native currency, not the user's home currency.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ticker | Yes | Stock ticker symbol (e.g. AAPL) | |
| date | Yes | Transaction date (YYYY-MM-DD) | |
| type | Yes | ||
| shares | Yes | ||
| price | Yes | Price per share in USD (use 0 for price=unknown deposits) | |
| currency | No | USD | |
| reason | No | Why this trade? (free-form). Most useful on buy/sell — leave blank for dividends/grants/etc. |
Implementation Reference
- apps/mcp/src/tools/mutate.ts:30-46 (handler)Handler for the 'add_txn' tool. Inserts a single transaction into the database with the provided ticker, date, type, shares, price, currency, and optional reason. Returns the inserted record's id and details.
async ({ ticker, date, type, shares, price, currency, reason }) => { const db = getDb(); const result = db .insert(transactions) .values({ ticker: ticker.toUpperCase(), date, type, shares, price, currency, reason: reason ?? null, }) .returning({ id: transactions.id }) .get(); return ok({ id: result?.id, ticker: ticker.toUpperCase(), date, type, shares, price }); }, - apps/mcp/src/tools/mutate.ts:17-29 (schema)Zod schema for 'add_txn' input validation: ticker (string), date (string YYYY-MM-DD), type (enum: buy/sell/deposit/dividend/tax), shares (positive number), price (non-negative number), currency (default USD), reason (optional string).
ticker: z.string().describe('Stock ticker symbol (e.g. AAPL)'), date: z.string().describe('Transaction date (YYYY-MM-DD)'), type: z.enum(['buy', 'sell', 'deposit', 'dividend', 'tax']), shares: z.number().positive(), price: z.number().min(0).describe('Price per share in USD (use 0 for price=unknown deposits)'), currency: z.string().default('USD'), reason: z .string() .optional() .describe( 'Why this trade? (free-form). Most useful on buy/sell — leave blank for dividends/grants/etc.', ), }, - apps/mcp/src/tools/mutate.ts:13-47 (registration)Registration of 'add_txn' as an MCP tool via server.tool() on the McpServer instance, called from registerMutateTools().
server.tool( 'add_txn', "Insert one stock transaction. For bulk imports: first show the user your detected column mapping and total row count, wait for their confirmation, then call once per row in chronological order (average cost depends on insertion order). Types: buy/sell move shares; deposit adds shares (set price=0 for grants/transfers, or actual cost basis); dividend/tax record cash events (price = total amount, shares = 1). For buy/sell, capture the user's reason (the why behind the trade) when they share it — even one short sentence helps later analysis cross-check thesis vs outcome. The currency arg is the trade's native currency, not the user's home currency.", { ticker: z.string().describe('Stock ticker symbol (e.g. AAPL)'), date: z.string().describe('Transaction date (YYYY-MM-DD)'), type: z.enum(['buy', 'sell', 'deposit', 'dividend', 'tax']), shares: z.number().positive(), price: z.number().min(0).describe('Price per share in USD (use 0 for price=unknown deposits)'), currency: z.string().default('USD'), reason: z .string() .optional() .describe( 'Why this trade? (free-form). Most useful on buy/sell — leave blank for dividends/grants/etc.', ), }, async ({ ticker, date, type, shares, price, currency, reason }) => { const db = getDb(); const result = db .insert(transactions) .values({ ticker: ticker.toUpperCase(), date, type, shares, price, currency, reason: reason ?? null, }) .returning({ id: transactions.id }) .get(); return ok({ id: result?.id, ticker: ticker.toUpperCase(), date, type, shares, price }); }, ); - apps/mcp/src/index.ts:21-21 (registration)Entry point where registerMutateTools is called, which registers 'add_txn' (and other mutate tools) on the MCP server.
registerMutateTools(server); - apps/mcp/src/helpers.ts:67-69 (helper)Helper function 'ok' used to format successful responses as MCP content blocks.
export const ok = (data: unknown) => ({ content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }], });