acb-tax-mcp
This MCP server calculates Canadian adjusted cost base (ACB) and capital gains from trade history using CRA average-cost and superficial-loss rules, and helps clean broker exports.
calculate_acb: Full ACB/capital-gains calculation: current holdings, per-disposition gains, superficial-loss adjustments, and per-tax-year summaries.
acb_summary: Current holdings only (shares, total ACB, ACB per share).
capital_gains_report: Schedule-3-style report for one tax year with per-disposition details and taxable gain (50% inclusion).
schedule3_summary: Aggregated per-security filing lines in Schedule 3 column shape.
check_superficial_losses: Flags losses denied/deferred under the 30-day (61-day window) rule.
unrealized_gains: Computes unrealized gains/losses by comparing ACB to supplied market prices.
normalize_broker_csv: Converts raw broker exports (aliased headers, formatted numbers) into clean transactions, reporting skipped rows.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@acb-tax-mcp What are my capital gains for 2024?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
acb-tax-mcp
An MCP server that computes Canadian adjusted cost base (ACB) and capital gains from your trade history: average-cost tracking, per-disposition gains, and superficial-loss detection, returned as structured JSON.
Ask your assistant "what are my capital gains for 2024?" or "did I trigger any superficial losses?" and it runs the CRA rules over your transactions instead of you wrestling a spreadsheet.
⚠️ This is a calculation aid, not tax advice. Verify every number before you file, and consult a professional for anything non-trivial. See Limitations.

Works with Claude Desktop, Claude Code, Cursor, or any MCP-compatible client.
Features
Tool | What it does |
| Full calculation: current holdings (shares, total ACB, ACB per share), every disposition with proceeds/ACB/outlays/gain, per-year summaries, and warnings. |
| Just current holdings and their book cost (handy for unrealized gains against a market price). |
| A Schedule-3-style report for one tax year: each disposition plus totals, net capital gain, and taxable gain (50% inclusion). |
| One aggregated row per security in the exact Schedule 3 column shape: shares, gross proceeds, ACB, outlays (commissions), gain/loss after the superficial-loss rule, acquisition years, and totals -- the lines you actually transcribe when filing. |
| Flags losses caught by the 30-day rule, with the denied (deferred) amount per event. |
| Current holdings' ACB against market prices you supply: per-position and total unrealized gain in dollars and percent (foreign-quoted securities take a price + fx_rate pair). |
| Turns a raw broker activity export into clean transactions: maps common column aliases ("Trade Date", "Activity Type", "Quantity"...), keeps buy/sell rows (DRIP counts as a buy), cleans "$1,200"/"(9.95)" formats, and reports every skipped row with a reason. |
Implements the CRA average-cost method (all shares of a security pool into one ACB; gains are against the average, not FIFO) and the superficial-loss rule (loss denied and deferred into the ACB of substitute shares bought within 30 days before or after the sale). Commissions and per-trade CAD FX conversion are handled.
Related MCP server: data-profiler-mcp
Install
No install needed to try it: open the Glama server page and use Try in Browser to call the tools against a sandbox with a couple of sample transactions.
Requires Python 3.10+.
Requires MCP Python SDK 2.x (mcp>=2,<3). SDK 1.x is feature-frozen upstream and no longer supported here; 0.4.0 is the last release that ran on it.
uv tool install acb-tax-mcp # or: pip install acb-tax-mcpRun from source without installing:
git clone https://github.com/haiiibin/acb-tax-mcp
cd acb-tax-mcp
uv run acb-tax-mcpConfigure your client
Claude Desktop
In claude_desktop_config.json:
{
"mcpServers": {
"acb-tax": {
"command": "acb-tax-mcp"
}
}
}Claude Code
claude mcp add acb-tax -- acb-tax-mcpTransactions
Give the tools a list of transactions (or a path to a .csv / .json file).
Field | Required | Notes |
| yes |
|
| yes |
|
| yes | ticker / symbol (pooled by this key) |
| yes | positive number |
| yes | price per share, in the trade currency |
| no | trade commission (default 0) |
| no | e.g. |
| no | trade currency to CAD, e.g. |
| no | free text |
CSV uses the same column names as a header row. If your broker's export uses different headers ("Trade Date", "Activity Type", "Symbol", "Quantity"...), run it through normalize_broker_csv first.
Want something to try immediately? examples/sample_trades.csv is a ready-made broker-style export with aliased headers, $-formatted numbers, a DRIP row, a dividend row (skipped with a reason), a USD trade with FX, and a superficial-loss scenario. Ask your assistant to clean it with normalize_broker_csv and run calculate_acb on the result.
Usage
"Calculate the ACB and capital gains for the trades in
~/trades.csv.""What's my capital-gains report for 2024?"
"Did any of these sales trigger a superficial loss?"
"What's my current book cost for XEQT?"
"Here's my RBC activity export -- clean it up and compute my ACB."
"XEQT is at $35.20 and VTI at $305.40 USD (1.37 CAD): what are my unrealized gains?"
Example
// calculate_acb with:
// buy 100 XYZ @ $10, buy 100 XYZ @ $20, sell 100 XYZ @ $25
{
"holdings": [
{ "security": "XYZ", "shares": 100.0, "total_acb": 1500.0, "acb_per_share": 15.0 }
],
"dispositions": [
{ "date": "2024-03-01", "security": "XYZ", "shares_sold": 100.0,
"proceeds": 2500.0, "acb": 1500.0, "capital_gain": 1000.0,
"is_superficial_loss": false }
],
"summary": {
"by_tax_year": [
{ "tax_year": 2024, "net_capital_gain": 1000.0, "taxable_capital_gain": 500.0 }
],
"inclusion_rate": 0.5
}
}Superficial loss example
Buy 100 @ $10, sell 100 @ $8 (a $200 loss), then rebuy 100 @ $8 nine days later:
{ "gain_before_superficial": -200.0, "superficial_loss_denied": 200.0,
"capital_gain": 0.0, "is_superficial_loss": true }The $200 loss is denied and added to the ACB of the repurchased shares (new ACB per share becomes $10), so it is recovered on a future sale.
Limitations
Read these before relying on the output.
Average-cost, per identical property. Feed all trades of the same security across your accounts together, since the CRA rule pools identical property at the taxpayer level. The tool pools by the
securitykey you provide.Superficial losses use the standard least-of-three test with a single forward pass. Deeply chained or overlapping superficial losses can need case-by-case professional judgment.
Not yet handled: return of capital, reinvested/notional distributions (ETF phantom distributions), stock splits, options, and other corporate actions. These affect ACB and are on the roadmap.
FX must be supplied per transaction (use the transaction-date rate). The tool does not fetch exchange rates.
Registered accounts (TFSA/RRSP) do not have capital gains; this tool is for non-registered (taxable) accounts.
Not tax advice.
Development
uv venv
uv pip install -e ".[dev]"
uv run pytestLicense
MIT. See LICENSE.
Available Tools
7 toolsacb_summaryA
Show current holdings: shares, total ACB and ACB per share for each security.
A lighter view than calculate_acb when you only want the current book cost of what is still held (for example to compute an unrealized gain against a market price). Accepts inline 'transactions' or a 'csv_path'. Each transaction is an object: date (YYYY-MM-DD), action ('buy' or 'sell'), security (ticker/symbol), shares, price (per share), and optionally commission, currency, fx_rate (trade-currency to CAD, e.g. 1.35 for USD), and note.
Inputs: csv_path, transactions.
calculate_acbA
Compute adjusted cost base and capital gains for a set of trades (Canadian rules).
Runs the full calculation and returns: current holdings (shares, total ACB, ACB per share) per security; every disposition with proceeds, ACB, outlays, the gain before and after the superficial-loss rule, and whether it was a superficial loss; per-tax-year summaries with net and taxable capital gain; and any warnings.
Uses the CRA average-cost method (all shares of a security pool into one ACB; gains are computed against the average, not FIFO). Pass trades either inline as 'transactions' or as a file path in 'csv_path' (CSV or JSON). Each transaction is an object: date (YYYY-MM-DD), action ('buy' or 'sell'), security (ticker/symbol), shares, price (per share), and optionally commission, currency, fx_rate (trade-currency to CAD, e.g. 1.35 for USD), and note.
This is a calculation aid, not tax advice; verify results before filing.
Inputs: csv_path, transactions.
capital_gains_reportA
Produce a capital-gains report for a single tax year (Schedule 3 style).
Returns every disposition dated in 'tax_year' with proceeds, ACB, outlays and the allowable capital gain/loss, plus totals: total proceeds, total ACB, net capital gain, and the taxable capital gain (net gain times the 50% inclusion rate). Superficial losses are already applied. Accepts inline 'transactions' or a 'csv_path'. Each transaction is an object: date (YYYY-MM-DD), action ('buy' or 'sell'), security (ticker/symbol), shares, price (per share), and optionally commission, currency, fx_rate (trade-currency to CAD, e.g. 1.35 for USD), and note.
This is a calculation aid, not tax advice; verify results before filing.
Inputs: tax_year (required), csv_path, transactions.
check_superficial_lossesA
Flag superficial losses under the CRA 30-day (61-day window) rule.
Scans dispositions for losses where the same security was bought within 30 days before or after the sale and still held at the end of that window. For each, reports the security, date, the denied (deferred) loss amount and the allowable portion. The denied amount is added to the ACB of the substitute shares. Accepts inline 'transactions' or a 'csv_path'. Each transaction is an object: date (YYYY-MM-DD), action ('buy' or 'sell'), security (ticker/symbol), shares, price (per share), and optionally commission, currency, fx_rate (trade-currency to CAD, e.g. 1.35 for USD), and note.
Inputs: csv_path, transactions.
normalize_broker_csvA
Convert a raw broker activity export into transactions the other tools accept.
Broker exports rarely match the documented headers. This tool maps common column aliases ("Trade Date", "Activity Type", "Symbol", "Quantity", ...), keeps only buy/sell rows (reinvestment/DRIP rows count as buys, since they add to ACB), cleans number formats ("1,200", "$9.99", parenthesized negatives, signed quantities), and returns ready-to-use 'transactions' plus a per-row 'skipped' list (dividends, deposits, transfers, unparseable rows) with reasons, so nothing is dropped silently. Pass the export as 'csv_path' (CSV/TSV/JSON) or inline as 'rows'. Feed the returned transactions straight into calculate_acb, capital_gains_report or unrealized_gains.
Inputs: rows, csv_path.
schedule3_summaryA
One row per security in the shape of Schedule 3's publicly traded shares section.
Aggregates dispositions (optionally limited to 'tax_year') into one line per security with the columns transcribed onto Schedule 3: number of shares, proceeds of disposition (gross, before commissions), adjusted cost base, outlays and expenses (sale commissions), and gain or loss with the superficial-loss rule already applied, plus acquisition years, per-column totals, and the list of years that have dispositions. capital_gains_report lists every individual disposition; use this tool when the user wants the aggregated filing lines instead. Accepts inline 'transactions' or a 'csv_path'. Each transaction is an object: date (YYYY-MM-DD), action ('buy' or 'sell'), security (ticker/symbol), shares, price (per share), and optionally commission, currency, fx_rate (trade-currency to CAD, e.g. 1.35 for USD), and note.
This is a calculation aid, not tax advice; verify results before filing.
Inputs: csv_path, tax_year, transactions.
unrealized_gainsA
Compute unrealized gains: current holdings' book cost (ACB) against market prices.
For each security still held, returns shares, total ACB, current market value and the unrealized gain in dollars and percent, plus portfolio totals. 'market_prices' maps each security to its current price: either a number already in CAD (e.g. {"XEQT": 35.20}) or, for foreign-quoted securities, an object with the trade-currency price and the CAD exchange rate (e.g. {"VTI": {"price": 305.40, "fx_rate": 1.37}}). Held securities without a price are listed in 'missing_prices' and excluded from totals. Accepts inline 'transactions' or a 'csv_path'. Each transaction is an object: date (YYYY-MM-DD), action ('buy' or 'sell'), security (ticker/symbol), shares, price (per share), and optionally commission, currency, fx_rate (trade-currency to CAD, e.g. 1.35 for USD), and note.
Inputs: market_prices (required), csv_path, transactions.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
Each tool has a clear purpose: calculate_acb runs the full computation, acb_summary gives a lighter holdings view, capital_gains_report lists dispositions per year, schedule3_summary provides aggregated filing lines, check_superficial_losses handles a specific rule, unrealized_gains handles market comparison, and normalize_broker_csv handles data ingestion. There is some overlap between acb_summary and calculate_acb, and between capital_gains_report and schedule3_summary, but each serves a distinct user need.
The naming mixes verb_noun patterns (calculate_acb, check_superficial_losses, normalize_broker_csv) with noun phrases (acb_summary, capital_gains_report, schedule3_summary, unrealized_gains). This is inconsistent but still readable and mostly clear.
7 tools is within the typical range. Each tool has a distinct purpose and covers the domain of ACB/tax calculations well. Not too many, not too few.
The toolset covers input normalization, full ACB calculation, summaries, per-year reports, Schedule 3 aggregation, superficial loss checking, and unrealized gains. Gaps might include things like ACB adjustment events (e.g., return of capital) or tax-loss harvesting suggestions, but for the stated purpose of ACB/tax calculations, it's fairly complete.
Maintenance
Related MCP Connectors
Trading MCP server for AI agents, with live market data, account reads and controlled execution.
MCP server for Financial Modeling Prep API with 250+ financial data tools
MCP server for stocksense-ai documentation, generated by doc2mcp.
Multi-tenant FastMCP server for Charles Schwab brokerage data, monetized via DPYC Tollbooth
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceAn MCP server that turns Interactive Brokers into a question-answering portfolio analyst.4-
- AlicenseAqualityCmaintenanceEnables LLMs to profile and analyze tabular data files (CSV, Parquet, Excel, JSON) by extracting schema, statistics, data quality issues, and dtype suggestions, returning structured JSON.737 PyPI3MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for personal finance management. Enables natural language expense logging, budgeting, recurring charge detection, and statement import with deterministic local calculations.-
- FlicenseAqualityDmaintenanceMCP server providing portfolio analytics tools: beta to a benchmark, sector correlation, and FIFO trade matching with realized/unrealized P&L using Yahoo Finance prices.3-