Canadian ACB and capital gains: average-cost, per-disposition gains, superficial-loss detection.
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.
| Tool | What it does |
|---|---|
calculate_acb | Full calculation: current holdings (shares, total ACB, ACB per share), every disposition with proceeds/ACB/outlays/gain, per-year summaries, and warnings. |
acb_summary | Just current holdings and their book cost (handy for unrealized gains against a market price). |
capital_gains_report | A Schedule-3-style report for one tax year: each disposition plus totals, net capital gain, and taxable gain (50% inclusion). |
schedule3_summary | 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. |
check_superficial_losses | Flags losses caught by the 30-day rule, with the denied (deferred) amount per event. |
unrealized_gains | 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). |
normalize_broker_csv | 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.
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+.
Works with MCP Python SDK 1.x and 2.x (mcp>=1.2.0,<3): the 2.0 rename of FastMCP to MCPServer is handled by an import shim, and CI runs the test suite on both majors.
uv tool install acb-tax-mcp # or: pip install acb-tax-mcp
Run from source without installing:
git clone https://github.com/haiiibin/acb-tax-mcp
cd acb-tax-mcp
uv run acb-tax-mcp
In claude_desktop_config.json:
{
"mcpServers": {
"acb-tax": {
"command": "acb-tax-mcp"
}
}
}
claude mcp add acb-tax -- acb-tax-mcp
Give the tools a list of transactions (or a path to a .csv / .json file).
| Field | Required | Notes |
|---|---|---|
date | yes | YYYY-MM-DD |
action | yes | buy or sell |
security | yes | ticker / symbol (pooled by this key) |
shares | yes | positive number |
price | yes | price per share, in the trade currency |
commission | no | trade commission (default 0) |
currency | no | e.g. USD (default CAD) |
fx_rate | no | trade currency to CAD, e.g. 1.35 for USD (default 1) |
note | 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.
~/trades.csv."// 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
}
}
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.
Read these before relying on the output.
security key you provide.uv venv
uv pip install -e ".[dev]"
uv run pytest
MIT. See LICENSE.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
uvx acb-tax-mcpMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-haiiibin-acb-tax-mcp": {
"command": "uvx",
"args": [
"acb-tax-mcp"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceio.github.haiiibin/acb-tax-mcp works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.