calcuris-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/index.js +303 -0
- package/dist/lib/au-income-tax-data.js +17 -0
- package/dist/lib/au-income-tax-math.js +110 -0
- package/dist/lib/au-stamp-duty-data.js +22 -0
- package/dist/lib/au-stamp-duty-math.js +129 -0
- package/dist/lib/ca-income-tax-data.js +49 -0
- package/dist/lib/ca-income-tax-math.js +95 -0
- package/dist/lib/income-tax-math.js +54 -0
- package/dist/lib/paycheck-math.js +52 -0
- package/dist/lib/property-tax-math.js +16 -0
- package/dist/lib/uk-dividend-tax-data.js +22 -0
- package/dist/lib/uk-dividend-tax-math.js +110 -0
- package/dist/lib/us-federal-tax-data.js +65 -0
- package/dist/lib/us-fica-data.js +23 -0
- package/dist/lib/us-state-income-brackets-2026.js +191 -0
- package/dist/lib/us-state-property-tax-2026.js +58 -0
- package/dist/lib/us-state-tax-data.js +101 -0
- package/dist/lib/us-tax-engine.js +44 -0
- package/package.json +52 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-07-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release of `calcuris-mcp`, an MCP stdio server exposing the
|
|
13
|
+
Calcuris (calcuris.com) tax engines. Seven tools:
|
|
14
|
+
- `us_income_tax` — US federal (2026 IRS brackets, post-OBBBA) + estimated
|
|
15
|
+
state income tax, with progressive bracket breakdown.
|
|
16
|
+
- `us_paycheck` — US take-home pay per pay period (federal withholding,
|
|
17
|
+
Social Security, Medicare, Additional Medicare, state tax).
|
|
18
|
+
- `us_property_tax` — annual/monthly US property tax from a home value and
|
|
19
|
+
either a custom rate or a state's real 2026 effective rate.
|
|
20
|
+
- `ca_income_tax` — Canadian federal + provincial/territorial income tax,
|
|
21
|
+
CPP/QPP + CPP2/QPP2, EI/QPIP, net take-home pay; optional
|
|
22
|
+
`compareAllProvinces`.
|
|
23
|
+
- `au_income_tax` — Australian resident income tax (2025-26 ATO brackets)
|
|
24
|
+
+ Medicare levy, Medicare Levy Surcharge, LITO, HELP/HECS repayment.
|
|
25
|
+
- `au_stamp_duty` — Australian state/territory stamp duty with
|
|
26
|
+
first-home-buyer concessions and foreign purchaser surcharge; optional
|
|
27
|
+
`compareAllStates`.
|
|
28
|
+
- `uk_dividend_tax` — UK dividend tax (HMRC stacking method, tapered
|
|
29
|
+
Personal Allowance, £500 dividend allowance, year-over-year comparison).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tresor4k
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# calcuris-mcp
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
An MCP (Model Context Protocol) server that exposes the tax engines behind
|
|
7
|
+
[Calcuris](https://calcuris.com) — real 2026 US income tax & paycheck math, US
|
|
8
|
+
state property tax, Canadian federal + provincial income tax, Australian
|
|
9
|
+
income tax & stamp duty, and UK dividend tax. No API key, no network calls:
|
|
10
|
+
every number is computed locally from data sourced from the IRS, Tax
|
|
11
|
+
Foundation, CRA/Revenu Québec, the ATO and state revenue offices, and HMRC.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Run directly with `npx` — no install required.
|
|
16
|
+
|
|
17
|
+
### Claude Desktop / Claude Code
|
|
18
|
+
|
|
19
|
+
Add to your MCP config (`claude_desktop_config.json` or `.mcp.json`):
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"mcpServers": {
|
|
24
|
+
"calcuris": {
|
|
25
|
+
"command": "npx",
|
|
26
|
+
"args": ["-y", "calcuris-mcp"]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Cursor
|
|
33
|
+
|
|
34
|
+
Add to `.cursor/mcp.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"calcuris": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "calcuris-mcp"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Tools
|
|
48
|
+
|
|
49
|
+
Every response includes a `source` note and a `reference_url` pointing to the
|
|
50
|
+
live calculator on [calcuris.com](https://calcuris.com) that uses the same
|
|
51
|
+
engine.
|
|
52
|
+
|
|
53
|
+
| Tool | Description | Example call | Example response (excerpt) |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `us_income_tax` | US federal (2026 IRS brackets, post-OBBBA) + estimated state income tax, with a full progressive bracket breakdown. | `{ "grossIncome": 95000, "filingStatus": "single", "stateCode": "CA" }` | `{ "federalTax": 12070, "stateTax": 4758.42, "totalTax": 16828.42, "marginalRate": 0.22, "takeHome": 78171.58 }` |
|
|
56
|
+
| `us_paycheck` | US take-home pay per pay period: federal withholding, Social Security, Medicare (+ Additional Medicare), state tax, net pay. | `{ "payType": "salary", "annualSalary": 80000, "payFrequency": "biweekly", "filingStatus": "single", "stateCode": "TX" }` | `{ "net": { "annual": 65110, "perPeriod": 2504.23 }, "federal": { "annual": 8770 }, "socialSecurity": { "annual": 4960 } }` |
|
|
57
|
+
| `us_property_tax` | Annual/monthly property tax from a home value and either a custom rate or a state's real 2026 effective rate. | `{ "homeValue": 450000, "stateCode": "TX" }` | `{ "annualTax": 6300, "monthlyTax": 525, "effectiveRatePct": 1.4 }` |
|
|
58
|
+
| `ca_income_tax` | Canadian federal + provincial/territorial income tax, CPP/QPP (+ CPP2/QPP2), EI/QPIP, and net take-home pay. Optional `compareAllProvinces`. | `{ "grossIncome": 75000, "provinceCode": "ON", "rrspContribution": 0 }` | `{ "federalTax": 8468.74, "provincialTax": 3696.06, "netIncome": 57465.69 }` |
|
|
59
|
+
| `au_income_tax` | Australian resident income tax (2025-26 ATO brackets) + Medicare levy, Medicare Levy Surcharge, LITO offset, HELP/HECS repayment. | `{ "taxableIncome": 95000, "privateHospitalCover": true, "hasHelpDebt": false }` | `{ "incomeTax": 19288, "medicareLevy": 1900, "totalTax": 21188, "takeHome": 73812 }` |
|
|
60
|
+
| `au_stamp_duty` | Australian state/territory stamp duty, including first-home-buyer concessions and the foreign purchaser surcharge. Optional `compareAllStates`. | `{ "propertyValue": 750000, "stateCode": "NSW", "firstHomeBuyer": false, "foreignResident": false, "principalResidence": true }` | `{ "baseDuty": 28162.5, "totalDuty": 28162.5, "effectiveRate": 3.755 }` |
|
|
61
|
+
| `uk_dividend_tax` | UK dividend tax with HMRC's stacking method (dividends sit on top of other income), tapered Personal Allowance, £500 dividend allowance, year-over-year comparison. | `{ "otherIncome": 40000, "dividends": 15000, "year": "2026/27" }` | `{ "dividendTax": 2741.25, "totalTax": 8227.25, "extraVsPrior": 290 }` |
|
|
62
|
+
|
|
63
|
+
Each tool's `inputSchema` documents every field (types, enums, defaults) and
|
|
64
|
+
is discoverable via `tools/list` — see the source in
|
|
65
|
+
[`src/index.ts`](./src/index.ts) for the full parameter set.
|
|
66
|
+
|
|
67
|
+
## Data sources & freshness
|
|
68
|
+
|
|
69
|
+
All engines target **tax year 2026** (UK: 2026/27, with 2025/26 comparison
|
|
70
|
+
built in). Rates and brackets are sourced from:
|
|
71
|
+
|
|
72
|
+
- **US** — IRS Rev. Proc. 2025-32 (federal brackets, standard deduction,
|
|
73
|
+
Child Tax Credit), SSA/IRS FICA wage base and rates, Tax Foundation (state
|
|
74
|
+
income tax brackets and property tax effective rates), state revenue
|
|
75
|
+
offices.
|
|
76
|
+
- **Canada** — CRA (federal brackets, BPA, CPP/CPP2), Revenu Québec (QPP,
|
|
77
|
+
QPIP, Quebec abatement), provincial finance ministries.
|
|
78
|
+
- **Australia** — ATO (2025-26 individual tax rates, Medicare levy, LITO,
|
|
79
|
+
HELP/HECS repayment thresholds), state and territory revenue offices
|
|
80
|
+
(stamp duty schedules and first-home-buyer concessions).
|
|
81
|
+
- **UK** — HMRC (Personal Allowance, dividend allowance, Income Tax bands and
|
|
82
|
+
dividend rates for 2025/26 and 2026/27).
|
|
83
|
+
|
|
84
|
+
These are the same datasets that power the live calculators:
|
|
85
|
+
|
|
86
|
+
- [calcuris.com](https://calcuris.com)
|
|
87
|
+
- [US income tax calculator](https://calcuris.com/us/income-tax-calculator/)
|
|
88
|
+
- [US paycheck calculator](https://calcuris.com/us/paycheck-calculator/)
|
|
89
|
+
- [Canada income tax calculator](https://calcuris.com/ca/income-tax-calculator/)
|
|
90
|
+
- [Australia stamp duty calculator](https://calcuris.com/au/stamp-duty-calculator/)
|
|
91
|
+
|
|
92
|
+
## Disclaimer
|
|
93
|
+
|
|
94
|
+
Results are **estimates for guidance only** and do not constitute tax,
|
|
95
|
+
legal, or financial advice. Tax situations vary by individual (local taxes,
|
|
96
|
+
deductions, credits, and edge cases are not exhaustively modeled). Always
|
|
97
|
+
confirm figures with a qualified tax professional or the relevant government
|
|
98
|
+
authority before making financial decisions.
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm install
|
|
104
|
+
npm run build # compiles src/ → dist/ with tsc
|
|
105
|
+
npm test # spawns the built server and runs the smoke test
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT © 2026 tresor4k
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// calcuris-mcp — MCP stdio server exposing the Calcuris tax engines (calcuris.com).
|
|
3
|
+
// All math is copied verbatim from the production site (src/lib/*.ts) — no rates are
|
|
4
|
+
// re-derived here. This file only wires zod input schemas to the pure functions and
|
|
5
|
+
// shapes the JSON response.
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { computeIncomeTax } from "./lib/income-tax-math.js";
|
|
10
|
+
import { computePaycheck } from "./lib/paycheck-math.js";
|
|
11
|
+
import { computePropertyTax } from "./lib/property-tax-math.js";
|
|
12
|
+
import { STATE_PROPERTY_TAX_2026 } from "./lib/us-state-property-tax-2026.js";
|
|
13
|
+
import { computeCaIncomeTax, compareProvinces } from "./lib/ca-income-tax-math.js";
|
|
14
|
+
import { computeAuIncomeTax } from "./lib/au-income-tax-math.js";
|
|
15
|
+
import { computeAuStampDuty, compareStates } from "./lib/au-stamp-duty-math.js";
|
|
16
|
+
import { computeDividendTax } from "./lib/uk-dividend-tax-math.js";
|
|
17
|
+
const FOOTER = "Estimate for guidance — 2026 rates from official sources (IRS/Tax Foundation/CRA/ATO/state revenue offices/HMRC).";
|
|
18
|
+
// ---- Enum tables shared by multiple tools ----
|
|
19
|
+
const US_STATE_CODES = [
|
|
20
|
+
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA",
|
|
21
|
+
"KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM",
|
|
22
|
+
"NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA",
|
|
23
|
+
"WV", "WI", "WY",
|
|
24
|
+
];
|
|
25
|
+
const CA_PROVINCE_CODES = [
|
|
26
|
+
"AB", "BC", "MB", "NB", "NL", "NS", "NT", "NU", "ON", "PE", "QC", "SK", "YT",
|
|
27
|
+
];
|
|
28
|
+
const AU_STATE_CODES = ["NSW", "VIC", "QLD", "WA", "SA", "TAS", "ACT", "NT"];
|
|
29
|
+
const FILING_STATUSES = ["single", "mfj", "hoh", "mfs"];
|
|
30
|
+
const PAY_FREQUENCIES = ["weekly", "biweekly", "semimonthly", "monthly"];
|
|
31
|
+
function usStateEnumSchema(optional) {
|
|
32
|
+
const base = z
|
|
33
|
+
.enum(US_STATE_CODES)
|
|
34
|
+
.describe(`Two-letter US state code (or DC for the District of Columbia). Valid codes: ${US_STATE_CODES.join(", ")}.`);
|
|
35
|
+
return optional ? base.optional() : base;
|
|
36
|
+
}
|
|
37
|
+
function unknownCodeError(kind, code, valid) {
|
|
38
|
+
throw new Error(`Unknown ${kind} code "${code}". Valid codes: ${valid.join(", ")}.`);
|
|
39
|
+
}
|
|
40
|
+
const server = new McpServer({
|
|
41
|
+
name: "calcuris-mcp",
|
|
42
|
+
version: "0.1.0",
|
|
43
|
+
});
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// 1) us_income_tax
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
server.registerTool("us_income_tax", {
|
|
48
|
+
title: "US federal + state income tax",
|
|
49
|
+
description: "Computes US federal income tax (2026 IRS brackets, post-OBBBA) plus an estimated state income tax, " +
|
|
50
|
+
"with a full progressive bracket breakdown. Example: { grossIncome: 95000, filingStatus: \"single\", " +
|
|
51
|
+
"stateCode: \"CA\" }. " +
|
|
52
|
+
FOOTER,
|
|
53
|
+
inputSchema: {
|
|
54
|
+
grossIncome: z.number().nonnegative().describe("Gross annual income in USD."),
|
|
55
|
+
filingStatus: z
|
|
56
|
+
.enum(FILING_STATUSES)
|
|
57
|
+
.describe("IRS filing status: single, mfj (married filing jointly), hoh (head of household), mfs (married filing separately)."),
|
|
58
|
+
stateCode: usStateEnumSchema(true).describe("Optional two-letter state code to also estimate state income tax. Omit to skip state estimation."),
|
|
59
|
+
preTaxContributions: z
|
|
60
|
+
.number()
|
|
61
|
+
.nonnegative()
|
|
62
|
+
.default(0)
|
|
63
|
+
.describe("Annual pre-tax 401(k)/traditional IRA contributions, reduces taxable income."),
|
|
64
|
+
useItemized: z.boolean().default(false).describe("Use itemized deductions instead of the standard deduction."),
|
|
65
|
+
itemizedAmount: z.number().nonnegative().default(0).describe("Total itemized deductions in USD (only used if useItemized is true and it exceeds the standard deduction)."),
|
|
66
|
+
dependents: z.number().int().nonnegative().default(0).describe("Number of qualifying children for the Child Tax Credit."),
|
|
67
|
+
},
|
|
68
|
+
}, async (args) => {
|
|
69
|
+
const stateCode = args.stateCode ?? "";
|
|
70
|
+
const inputs = {
|
|
71
|
+
filingStatus: args.filingStatus,
|
|
72
|
+
grossIncome: args.grossIncome,
|
|
73
|
+
preTaxContributions: args.preTaxContributions,
|
|
74
|
+
useItemized: args.useItemized,
|
|
75
|
+
itemizedAmount: args.itemizedAmount,
|
|
76
|
+
dependents: args.dependents,
|
|
77
|
+
stateCode,
|
|
78
|
+
taxYear: 2026,
|
|
79
|
+
};
|
|
80
|
+
const result = computeIncomeTax(inputs);
|
|
81
|
+
return jsonResult({
|
|
82
|
+
result,
|
|
83
|
+
source: "Calcuris US income tax engine — IRS Rev. Proc. 2025-32 (federal), Tax Foundation (state).",
|
|
84
|
+
reference_url: "https://calcuris.com/us/income-tax-calculator/",
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// 2) us_paycheck
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
server.registerTool("us_paycheck", {
|
|
91
|
+
title: "US paycheck / take-home pay",
|
|
92
|
+
description: "Computes US take-home pay per pay period: federal withholding, Social Security, Medicare (+ Additional " +
|
|
93
|
+
"Medicare), state tax, and net pay, for salaried or hourly workers. Example: { payType: \"salary\", " +
|
|
94
|
+
"annualSalary: 80000, payFrequency: \"biweekly\", filingStatus: \"single\", stateCode: \"TX\" }. " +
|
|
95
|
+
FOOTER,
|
|
96
|
+
inputSchema: {
|
|
97
|
+
payType: z.enum(["salary", "hourly"]).describe("Whether pay is a fixed annual salary or an hourly rate."),
|
|
98
|
+
annualSalary: z.number().nonnegative().default(0).describe("Annual salary in USD (used when payType is \"salary\")."),
|
|
99
|
+
hourlyRate: z.number().nonnegative().default(0).describe("Hourly rate in USD (used when payType is \"hourly\")."),
|
|
100
|
+
hoursPerWeek: z.number().nonnegative().default(40).describe("Hours worked per week (used when payType is \"hourly\", or to derive an hourly-equivalent when salaried)."),
|
|
101
|
+
payFrequency: z.enum(PAY_FREQUENCIES).describe("Pay period frequency."),
|
|
102
|
+
filingStatus: z.enum(FILING_STATUSES).describe("IRS filing status used for federal withholding."),
|
|
103
|
+
stateCode: usStateEnumSchema(true).describe("Optional two-letter state code to also withhold state tax. Omit to skip."),
|
|
104
|
+
preTaxRetirement: z.number().nonnegative().default(0).describe("Pre-tax 401(k) contribution PER PAY PERIOD (reduces federal/state taxable income, not FICA)."),
|
|
105
|
+
preTaxHealth: z.number().nonnegative().default(0).describe("Pre-tax health/HSA (section 125) contribution PER PAY PERIOD (reduces federal/state AND FICA taxable income)."),
|
|
106
|
+
dependents: z.number().int().nonnegative().default(0).describe("Number of dependents (informational, not withheld via CTC in this engine)."),
|
|
107
|
+
extraWithholding: z.number().nonnegative().default(0).describe("Additional federal withholding requested PER PAY PERIOD (W-4 line 4c)."),
|
|
108
|
+
},
|
|
109
|
+
}, async (args) => {
|
|
110
|
+
const stateCode = args.stateCode ?? "";
|
|
111
|
+
const inputs = {
|
|
112
|
+
payType: args.payType,
|
|
113
|
+
annualSalary: args.annualSalary,
|
|
114
|
+
hourlyRate: args.hourlyRate,
|
|
115
|
+
hoursPerWeek: args.hoursPerWeek,
|
|
116
|
+
payFrequency: args.payFrequency,
|
|
117
|
+
filingStatus: args.filingStatus,
|
|
118
|
+
stateCode,
|
|
119
|
+
preTaxRetirement: args.preTaxRetirement,
|
|
120
|
+
preTaxHealth: args.preTaxHealth,
|
|
121
|
+
dependents: args.dependents,
|
|
122
|
+
extraWithholding: args.extraWithholding,
|
|
123
|
+
taxYear: 2026,
|
|
124
|
+
};
|
|
125
|
+
const result = computePaycheck(inputs);
|
|
126
|
+
return jsonResult({
|
|
127
|
+
result,
|
|
128
|
+
source: "Calcuris US paycheck engine — IRS Rev. Proc. 2025-32, SSA/IRS FICA limits 2026, Tax Foundation (state).",
|
|
129
|
+
reference_url: "https://calcuris.com/us/paycheck-calculator/",
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// 3) us_property_tax
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
server.registerTool("us_property_tax", {
|
|
136
|
+
title: "US property tax",
|
|
137
|
+
description: "Estimates annual/monthly US property tax from a home value and either a custom rate or a state's real " +
|
|
138
|
+
"2026 effective property tax rate. Example: { homeValue: 350000, stateCode: \"NJ\" }. " +
|
|
139
|
+
FOOTER,
|
|
140
|
+
inputSchema: {
|
|
141
|
+
homeValue: z.number().nonnegative().describe("Market value of the home in USD."),
|
|
142
|
+
stateCode: usStateEnumSchema(true).describe("Optional two-letter state code. When provided (and ratePct is not), the state's real 2026 effective property tax rate is used automatically."),
|
|
143
|
+
ratePct: z.number().nonnegative().optional().describe("Optional custom effective property tax rate (%). Overrides the state's rate if both are given."),
|
|
144
|
+
exemption: z.number().nonnegative().default(0).describe("Homestead exemption amount in USD, subtracted from the assessed value."),
|
|
145
|
+
assessmentRatioPct: z.number().positive().default(100).describe("Percent of market value actually assessed (default 100; some states assess less than market value)."),
|
|
146
|
+
},
|
|
147
|
+
}, async (args) => {
|
|
148
|
+
let ratePct = args.ratePct;
|
|
149
|
+
let stateRow;
|
|
150
|
+
if (args.stateCode) {
|
|
151
|
+
stateRow = STATE_PROPERTY_TAX_2026[args.stateCode];
|
|
152
|
+
if (!stateRow)
|
|
153
|
+
unknownCodeError("US state", args.stateCode, US_STATE_CODES);
|
|
154
|
+
if (ratePct === undefined)
|
|
155
|
+
ratePct = stateRow.effRatePct;
|
|
156
|
+
}
|
|
157
|
+
if (ratePct === undefined) {
|
|
158
|
+
throw new Error("Provide either stateCode (to use the state's real effective rate) or ratePct.");
|
|
159
|
+
}
|
|
160
|
+
const result = computePropertyTax({
|
|
161
|
+
homeValue: args.homeValue,
|
|
162
|
+
ratePct,
|
|
163
|
+
exemption: args.exemption,
|
|
164
|
+
assessmentRatioPct: args.assessmentRatioPct,
|
|
165
|
+
});
|
|
166
|
+
return jsonResult({
|
|
167
|
+
result,
|
|
168
|
+
stateBaseline: stateRow
|
|
169
|
+
? { stateCode: args.stateCode, effectiveRatePct: stateRow.effRatePct, medianTaxUsd: stateRow.medianTaxUsd, medianHomeUsd: stateRow.medianHomeUsd }
|
|
170
|
+
: undefined,
|
|
171
|
+
source: "Calcuris US property tax engine — state effective rates from Tax Foundation / Census ACS 2026 dataset.",
|
|
172
|
+
reference_url: "https://calcuris.com/us/property-tax-calculator/",
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// 4) ca_income_tax
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
server.registerTool("ca_income_tax", {
|
|
179
|
+
title: "Canada federal + provincial income tax",
|
|
180
|
+
description: "Computes Canadian federal + provincial/territorial income tax, CPP/QPP (+ CPP2/QPP2), EI/QPIP, and net " +
|
|
181
|
+
"take-home pay for a given province, 2026 rates. Example: { grossIncome: 75000, provinceCode: \"ON\" }. " +
|
|
182
|
+
"Set compareAllProvinces: true to get every province/territory side by side. " +
|
|
183
|
+
FOOTER,
|
|
184
|
+
inputSchema: {
|
|
185
|
+
grossIncome: z.number().nonnegative().describe("Annual employment income in CAD."),
|
|
186
|
+
provinceCode: z.enum(CA_PROVINCE_CODES).describe(`Two-letter province/territory code. Valid codes: ${CA_PROVINCE_CODES.join(", ")}.`),
|
|
187
|
+
rrspContribution: z.number().nonnegative().default(0).describe("Annual RRSP contribution in CAD (deducted from taxable income)."),
|
|
188
|
+
compareAllProvinces: z.boolean().default(false).describe("If true, also return the same calculation for every province/territory (ignores provinceCode for the comparison table, but a single result for provinceCode is still returned as \"result\")."),
|
|
189
|
+
},
|
|
190
|
+
}, async (args) => {
|
|
191
|
+
const result = computeCaIncomeTax({
|
|
192
|
+
grossIncome: args.grossIncome,
|
|
193
|
+
provinceCode: args.provinceCode,
|
|
194
|
+
rrspContribution: args.rrspContribution,
|
|
195
|
+
});
|
|
196
|
+
const comparison = args.compareAllProvinces
|
|
197
|
+
? compareProvinces(args.grossIncome, args.rrspContribution, [...CA_PROVINCE_CODES])
|
|
198
|
+
: undefined;
|
|
199
|
+
return jsonResult({
|
|
200
|
+
result,
|
|
201
|
+
comparison,
|
|
202
|
+
source: "Calcuris Canada income tax engine — CRA / Revenu Québec 2026 brackets and payroll rates.",
|
|
203
|
+
reference_url: "https://calcuris.com/ca/income-tax-calculator/",
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// 5) au_income_tax
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
server.registerTool("au_income_tax", {
|
|
210
|
+
title: "Australia resident income tax",
|
|
211
|
+
description: "Computes Australian resident income tax (2025-26 ATO brackets) plus Medicare levy, Medicare levy " +
|
|
212
|
+
"surcharge, LITO offset, and HELP/HECS repayment. Example: { taxableIncome: 95000, privateHospitalCover: " +
|
|
213
|
+
"true, hasHelpDebt: false }. " +
|
|
214
|
+
FOOTER,
|
|
215
|
+
inputSchema: {
|
|
216
|
+
taxableIncome: z.number().nonnegative().describe("Annual taxable income in AUD."),
|
|
217
|
+
privateHospitalCover: z.boolean().default(true).describe("True if covered by private hospital insurance (avoids the Medicare Levy Surcharge)."),
|
|
218
|
+
hasHelpDebt: z.boolean().default(false).describe("True if the taxpayer has an outstanding HELP/HECS debt (triggers compulsory repayment)."),
|
|
219
|
+
},
|
|
220
|
+
}, async (args) => {
|
|
221
|
+
const result = computeAuIncomeTax(args);
|
|
222
|
+
return jsonResult({
|
|
223
|
+
result,
|
|
224
|
+
source: "Calcuris Australia income tax engine — ATO 2025-26 individual tax rates, Medicare levy, LITO, HELP repayment thresholds.",
|
|
225
|
+
reference_url: "https://calcuris.com/au/income-tax-calculator/",
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
// 6) au_stamp_duty
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
server.registerTool("au_stamp_duty", {
|
|
232
|
+
title: "Australia stamp duty (land transfer duty)",
|
|
233
|
+
description: "Computes Australian state/territory stamp duty on a property purchase, including first-home-buyer " +
|
|
234
|
+
"concessions and the foreign purchaser surcharge where applicable. Example: { propertyValue: 750000, " +
|
|
235
|
+
"stateCode: \"NSW\", firstHomeBuyer: false, foreignResident: false, principalResidence: true }. Set " +
|
|
236
|
+
"compareAllStates: true to compare every state/territory for the same property value. " +
|
|
237
|
+
FOOTER,
|
|
238
|
+
inputSchema: {
|
|
239
|
+
propertyValue: z.number().nonnegative().describe("Purchase price / property value in AUD."),
|
|
240
|
+
stateCode: z.enum(AU_STATE_CODES).describe(`State/territory code. Valid codes: ${AU_STATE_CODES.join(", ")}.`),
|
|
241
|
+
firstHomeBuyer: z.boolean().default(false).describe("True if the buyer qualifies as a first home buyer (applies concession where available)."),
|
|
242
|
+
foreignResident: z.boolean().default(false).describe("True if the buyer is a foreign person (applies the foreign purchaser surcharge)."),
|
|
243
|
+
principalResidence: z.boolean().default(true).describe("True if this will be the buyer's principal place of residence (owner-occupier); false for an investment purchase."),
|
|
244
|
+
compareAllStates: z.boolean().default(false).describe("If true, also return the same calculation for every state/territory."),
|
|
245
|
+
},
|
|
246
|
+
}, async (args) => {
|
|
247
|
+
const result = computeAuStampDuty({
|
|
248
|
+
propertyValue: args.propertyValue,
|
|
249
|
+
stateCode: args.stateCode,
|
|
250
|
+
firstHomeBuyer: args.firstHomeBuyer,
|
|
251
|
+
foreignResident: args.foreignResident,
|
|
252
|
+
principalResidence: args.principalResidence,
|
|
253
|
+
});
|
|
254
|
+
const comparison = args.compareAllStates
|
|
255
|
+
? compareStates(args.propertyValue, { firstHomeBuyer: args.firstHomeBuyer, foreignResident: args.foreignResident, principalResidence: args.principalResidence }, [...AU_STATE_CODES])
|
|
256
|
+
: undefined;
|
|
257
|
+
return jsonResult({
|
|
258
|
+
result,
|
|
259
|
+
comparison,
|
|
260
|
+
source: "Calcuris Australia stamp duty engine — state/territory revenue office schedules 2026.",
|
|
261
|
+
reference_url: "https://calcuris.com/au/stamp-duty-calculator/",
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
// 7) uk_dividend_tax
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
server.registerTool("uk_dividend_tax", {
|
|
268
|
+
title: "UK dividend tax",
|
|
269
|
+
description: "Computes UK dividend tax using HMRC's stacking method (dividends sit on top of other income), including " +
|
|
270
|
+
"the tapered Personal Allowance and the £500 dividend allowance, with a year-over-year comparison. " +
|
|
271
|
+
"Example: { otherIncome: 40000, dividends: 15000, year: \"2026/27\" }. " +
|
|
272
|
+
FOOTER,
|
|
273
|
+
inputSchema: {
|
|
274
|
+
otherIncome: z.number().nonnegative().describe("Salary / other taxable income in GBP, excluding dividends."),
|
|
275
|
+
dividends: z.number().nonnegative().describe("Gross dividends received in GBP."),
|
|
276
|
+
year: z.enum(["2026/27", "2025/26"]).describe("UK tax year."),
|
|
277
|
+
},
|
|
278
|
+
}, async (args) => {
|
|
279
|
+
const result = computeDividendTax(args);
|
|
280
|
+
return jsonResult({
|
|
281
|
+
result,
|
|
282
|
+
source: "Calcuris UK dividend tax engine — HMRC dividend allowance, Personal Allowance taper, Income Tax bands.",
|
|
283
|
+
reference_url: "https://calcuris.com/uk/dividend-tax-calculator/",
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
function jsonResult(payload) {
|
|
287
|
+
return {
|
|
288
|
+
content: [
|
|
289
|
+
{
|
|
290
|
+
type: "text",
|
|
291
|
+
text: JSON.stringify(payload, null, 2),
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async function main() {
|
|
297
|
+
const transport = new StdioServerTransport();
|
|
298
|
+
await server.connect(transport);
|
|
299
|
+
}
|
|
300
|
+
main().catch((err) => {
|
|
301
|
+
console.error("calcuris-mcp fatal error:", err);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const AU_INCOME_2026 = {
|
|
2
|
+
brackets: [{ rate: 0, lower: 0, upper: 18200 }, { rate: 0.16, lower: 18200, upper: 45000 }, { rate: 0.3, lower: 45000, upper: 135000 }, { rate: 0.37, lower: 135000, upper: 190000 }, { rate: 0.45, lower: 190000, upper: null }],
|
|
3
|
+
medicareLevy: { rate: 0.02, lowerSingle: 28011, upperSingle: 35013, phaseInRate: 0.1 },
|
|
4
|
+
lito: { max: 700, taper1Start: 37500, taper1Rate: 0.05, taper2Start: 45000, taper2Rate: 0.015, cutout: 66667 },
|
|
5
|
+
help: { system: "marginal", thresholds: [{ rate: 0, lower: 0, upper: 67000 }, { rate: 0.15, lower: 67000, upper: 125000 }, { rate: 0.17, lower: 125000, upper: 179285 }, { rate: 0.1, lower: 179285, upper: null }] },
|
|
6
|
+
mls: { thresholds: [{ rate: 0, lower: 0, upper: 101000 }, { rate: 0.01, lower: 101000, upper: 118000 }, { rate: 0.0125, lower: 118000, upper: 158000 }, { rate: 0.015, lower: 158000, upper: null }] },
|
|
7
|
+
superGuaranteeRate: 0.12,
|
|
8
|
+
};
|
|
9
|
+
export const AU_INCOME_AS_OF = "2025-26";
|
|
10
|
+
export const AU_INCOME_SOURCES = [
|
|
11
|
+
{ label: "ATO - Tax rates - Australian residents (2025-26 resident brackets)", url: "https://www.ato.gov.au/tax-rates-and-codes/tax-rates-australian-residents" },
|
|
12
|
+
{ label: "ATO - Study and training support loans rates and repayment thresholds (2025-26 marginal HELP)", url: "https://www.ato.gov.au/tax-rates-and-codes/study-and-training-support-loans-rates-and-repayment-thresholds" },
|
|
13
|
+
{ label: "ATO - Medicare levy reduction for low-income earners (2025-26 single thresholds)", url: "https://www.ato.gov.au/individuals-and-families/medicare-and-private-health-insurance/medicare-levy/medicare-levy-reduction/medicare-levy-reduction-for-low-income-earners" },
|
|
14
|
+
{ label: "ATO - Medicare levy surcharge income, thresholds and rates (2025-26 singles)", url: "https://www.ato.gov.au/individuals-and-families/medicare-and-private-health-insurance/medicare-levy-surcharge/medicare-levy-surcharge-income-thresholds-and-rates" },
|
|
15
|
+
{ label: "ATO - Low income tax offset (LITO)", url: "https://www.ato.gov.au/individuals-and-families/income-deductions-offsets-and-records/tax-offsets/low-income-tax-offset" },
|
|
16
|
+
{ label: "ATO - How much super to pay (Super Guarantee 12% from 1 Jul 2025)", url: "https://www.ato.gov.au/businesses-and-organisations/super-for-employers/paying-super-contributions/how-much-super-to-pay" },
|
|
17
|
+
];
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Moteur income tax / take-home Australie (résident, 2025-26) — impôt sur le revenu (barème ATO) + Medicare
|
|
2
|
+
// levy (2 % avec phase-in low-income) + LITO + remboursement HELP/HECS (système marginal 2025-26) + Medicare
|
|
3
|
+
// levy surcharge (optionnel) + info Superannuation Guarantee. Logique PURE, testable. Réutilise le cœur
|
|
4
|
+
// progressif partagé (us-tax-engine). Couche "estimate" honnête : résident, employé, déductions standard ;
|
|
5
|
+
// pas de gains en capital / déductions individuelles. SG = sur le brut (à la charge de l'employeur), non retenue.
|
|
6
|
+
import { applyBrackets, effectiveRate } from "./us-tax-engine.js";
|
|
7
|
+
import { AU_INCOME_2026 } from "./au-income-tax-data.js";
|
|
8
|
+
// LITO 2025-26 : 700 $ max, réduit de 5c/$ entre 37 500 et 45 000, puis 1,5c/$ entre 45 000 et 66 667.
|
|
9
|
+
export function litoFor(income) {
|
|
10
|
+
const l = AU_INCOME_2026.lito;
|
|
11
|
+
if (income <= l.taper1Start)
|
|
12
|
+
return l.max;
|
|
13
|
+
if (income <= l.taper2Start)
|
|
14
|
+
return Math.max(l.max - l.taper1Rate * (income - l.taper1Start), 0);
|
|
15
|
+
if (income <= l.cutout) {
|
|
16
|
+
const afterTaper1 = l.max - l.taper1Rate * (l.taper2Start - l.taper1Start);
|
|
17
|
+
return Math.max(afterTaper1 - l.taper2Rate * (income - l.taper2Start), 0);
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
// Medicare levy : 0 sous le seuil bas, phase-in 10c/$ entre les seuils, plein 2 % au-dessus du seuil haut.
|
|
22
|
+
export function medicareLevyFor(income) {
|
|
23
|
+
const m = AU_INCOME_2026.medicareLevy;
|
|
24
|
+
if (income <= m.lowerSingle)
|
|
25
|
+
return 0;
|
|
26
|
+
if (income >= m.upperSingle)
|
|
27
|
+
return income * m.rate;
|
|
28
|
+
return (income - m.lowerSingle) * m.phaseInRate;
|
|
29
|
+
}
|
|
30
|
+
// HELP/HECS 2025-26 (système marginal) : nil sous le 1ᵉʳ seuil, marginal sur les bandes intermédiaires ; la
|
|
31
|
+
// dernière bande (upper=null) = 10 % du revenu de remboursement TOTAL (pas marginal), conformément à l'ATO.
|
|
32
|
+
export function helpRepaymentFor(income) {
|
|
33
|
+
const t = AU_INCOME_2026.help.thresholds;
|
|
34
|
+
const last = t[t.length - 1];
|
|
35
|
+
if (income > last.lower)
|
|
36
|
+
return income * last.rate; // 10 % du revenu total
|
|
37
|
+
let rep = 0;
|
|
38
|
+
for (const b of t) {
|
|
39
|
+
if (income <= b.lower)
|
|
40
|
+
break;
|
|
41
|
+
if (b.upper === null)
|
|
42
|
+
break;
|
|
43
|
+
rep += (Math.min(income, b.upper) - b.lower) * b.rate;
|
|
44
|
+
}
|
|
45
|
+
return rep;
|
|
46
|
+
}
|
|
47
|
+
// Medicare levy surcharge : taux plat sur le revenu total selon la tranche (singles), seulement sans couverture.
|
|
48
|
+
export function mlsFor(income) {
|
|
49
|
+
const t = AU_INCOME_2026.mls.thresholds;
|
|
50
|
+
let rate = 0;
|
|
51
|
+
for (const b of t) {
|
|
52
|
+
if (b.upper === null || income <= b.upper) {
|
|
53
|
+
rate = b.rate;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return income * rate;
|
|
58
|
+
}
|
|
59
|
+
function helpMarginal(income) {
|
|
60
|
+
const t = AU_INCOME_2026.help.thresholds;
|
|
61
|
+
const last = t[t.length - 1];
|
|
62
|
+
if (income > last.lower)
|
|
63
|
+
return 0; // au-dessus = 10 % du total (pas de marginal au sens dérivée)
|
|
64
|
+
for (const b of t) {
|
|
65
|
+
if (b.upper !== null && income > b.lower && income <= b.upper)
|
|
66
|
+
return b.rate;
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
export function computeAuIncomeTax(inp) {
|
|
71
|
+
const income = Math.max(inp.taxableIncome || 0, 0);
|
|
72
|
+
const prog = applyBrackets(income, AU_INCOME_2026.brackets);
|
|
73
|
+
const incomeTax = prog.tax;
|
|
74
|
+
const lito = litoFor(income);
|
|
75
|
+
const taxAfterOffsets = Math.max(incomeTax - lito, 0);
|
|
76
|
+
const medicareLevy = medicareLevyFor(income);
|
|
77
|
+
const medicareLevySurcharge = inp.privateHospitalCover ? 0 : mlsFor(income);
|
|
78
|
+
const helpRepayment = inp.hasHelpDebt ? helpRepaymentFor(income) : 0;
|
|
79
|
+
const totalTax = taxAfterOffsets + medicareLevy + medicareLevySurcharge + helpRepayment;
|
|
80
|
+
const takeHome = income - totalTax;
|
|
81
|
+
// Taux marginal combiné : barème + Medicare (phase-in 10 % ou 2 %) + taper LITO + HELP.
|
|
82
|
+
const m = AU_INCOME_2026.medicareLevy;
|
|
83
|
+
const l = AU_INCOME_2026.lito;
|
|
84
|
+
let medMarg = 0;
|
|
85
|
+
if (income > m.lowerSingle && income < m.upperSingle)
|
|
86
|
+
medMarg = m.phaseInRate;
|
|
87
|
+
else if (income >= m.upperSingle)
|
|
88
|
+
medMarg = m.rate;
|
|
89
|
+
let litoMarg = 0;
|
|
90
|
+
if (income > l.taper1Start && income <= l.taper2Start)
|
|
91
|
+
litoMarg = l.taper1Rate;
|
|
92
|
+
else if (income > l.taper2Start && income <= l.cutout)
|
|
93
|
+
litoMarg = l.taper2Rate;
|
|
94
|
+
const marginalRate = prog.marginalRate + medMarg + litoMarg + (inp.hasHelpDebt ? helpMarginal(income) : 0);
|
|
95
|
+
return {
|
|
96
|
+
taxableIncome: income,
|
|
97
|
+
incomeTax,
|
|
98
|
+
lito,
|
|
99
|
+
taxAfterOffsets,
|
|
100
|
+
medicareLevy,
|
|
101
|
+
medicareLevySurcharge,
|
|
102
|
+
helpRepayment,
|
|
103
|
+
totalTax,
|
|
104
|
+
takeHome,
|
|
105
|
+
marginalRate,
|
|
106
|
+
averageRate: effectiveRate(totalTax, income),
|
|
107
|
+
superGuarantee: income * AU_INCOME_2026.superGuaranteeRate,
|
|
108
|
+
slices: prog.slices,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// 8 juridictions (6 États + 2 Territoires). Barèmes 2025-26.
|
|
2
|
+
export const AU_STAMP_DUTY_2026 = {
|
|
3
|
+
NSW: { code: "NSW", name: "New South Wales", brackets: [{ rate: 0.0125, lower: 0, upper: 17000 }, { rate: 0.015, lower: 17000, upper: 37000 }, { rate: 0.0175, lower: 37000, upper: 99000 }, { rate: 0.035, lower: 99000, upper: 372000 }, { rate: 0.045, lower: 372000, upper: 1240000 }, { rate: 0.055, lower: 1240000, upper: 3721000 }, { rate: 0.07, lower: 3721000, upper: null }], foreignSurchargeRate: 0.09, firstHome: { fullExemptThreshold: 800000, concessionUpper: 1000000, method: "linear", note: "First Home Buyers Assistance Scheme: full duty exemption on a new or existing home valued at or under $800,000, with a concessional reduced rate from $800,000 to $1,000,000 (eligible first home buyers only)." } },
|
|
4
|
+
VIC: { code: "VIC", name: "Victoria", brackets: [{ rate: 0.014, lower: 0, upper: 25000 }, { rate: 0.024, lower: 25000, upper: 130000 }, { rate: 0.06, lower: 130000, upper: 960000 }], pprBrackets: [{ rate: 0.014, lower: 0, upper: 25000 }, { rate: 0.024, lower: 25000, upper: 130000 }, { rate: 0.05, lower: 130000, upper: 440000 }, { rate: 0.06, lower: 440000, upper: 550000 }], pprUpper: 550000, flatBand: { lower: 960000, upper: 2000000, rate: 0.055, aboveRate: 0.065 }, foreignSurchargeRate: 0.08, firstHome: { fullExemptThreshold: 600000, concessionUpper: 750000, method: "linear", note: "First home buyer: full duty exemption up to $600,000 and a tapering concession from $600,001 to $750,000 (no concession above $750,000). Applies to your principal place of residence." } },
|
|
5
|
+
QLD: { code: "QLD", name: "Queensland", brackets: [{ rate: 0, lower: 0, upper: 5000 }, { rate: 0.015, lower: 5000, upper: 75000 }, { rate: 0.035, lower: 75000, upper: 540000 }, { rate: 0.045, lower: 540000, upper: 1000000 }, { rate: 0.0575, lower: 1000000, upper: null }], homeConcessionBrackets: [{ rate: 0.01, lower: 0, upper: 350000 }, { rate: 0.035, lower: 350000, upper: 540000 }, { rate: 0.045, lower: 540000, upper: 1000000 }, { rate: 0.0575, lower: 1000000, upper: null }], foreignSurchargeRate: 0.08, firstHome: { fullExemptThreshold: 700000, concessionUpper: 800000, method: "linear", note: "Established first home: home concession rate minus a tapered first-home concession, so duty is $0 up to $700,000 and phases out by $800,000. A first home that is a new home or vacant land (eligible from 1 May 2025) gets a full, uncapped concession." } },
|
|
6
|
+
WA: { code: "WA", name: "Western Australia", brackets: [{ rate: 0.019, lower: 0, upper: 120000 }, { rate: 0.0285, lower: 120000, upper: 150000 }, { rate: 0.038, lower: 150000, upper: 360000 }, { rate: 0.0475, lower: 360000, upper: 725000 }, { rate: 0.0515, lower: 725000, upper: null }], foreignSurchargeRate: 0.07, firstHome: { fullExemptThreshold: 500000, concessionUpper: 700000, method: "linear", note: "First home owner rate of duty (from 21 March 2025): no duty up to $500,000, a concessional rate from $500,000 to $700,000 (Perth metro and Peel; $750,000 outside metro/Peel); vacant land no duty up to $350,000, concession to $450,000." } },
|
|
7
|
+
SA: { code: "SA", name: "South Australia", brackets: [{ rate: 0.01, lower: 0, upper: 12000 }, { rate: 0.02, lower: 12000, upper: 30000 }, { rate: 0.03, lower: 30000, upper: 50000 }, { rate: 0.035, lower: 50000, upper: 100000 }, { rate: 0.04, lower: 100000, upper: 200000 }, { rate: 0.0425, lower: 200000, upper: 250000 }, { rate: 0.0475, lower: 250000, upper: 300000 }, { rate: 0.05, lower: 300000, upper: 500000 }, { rate: 0.055, lower: 500000, upper: null }], foreignSurchargeRate: 0.07, firstHome: { fullExemptThreshold: 0, concessionUpper: 0, method: "newOnly", note: "From 13 February 2025: full stamp duty relief with no value cap, but only for eligible new homes, off-the-plan apartments or vacant land to build a principal place of residence. Established/existing homes are not eligible. No relief applies to the foreign ownership surcharge." } },
|
|
8
|
+
TAS: { code: "TAS", name: "Tasmania", brackets: [{ rate: 0, lower: 0, upper: 3000 }, { rate: 0.0175, lower: 3000, upper: 25000 }, { rate: 0.0225, lower: 25000, upper: 75000 }, { rate: 0.035, lower: 75000, upper: 200000 }, { rate: 0.04, lower: 200000, upper: 375000 }, { rate: 0.0425, lower: 375000, upper: 725000 }, { rate: 0.045, lower: 725000, upper: null }], baseFee: 50, foreignSurchargeRate: 0.08, firstHome: { fullExemptThreshold: 750000, concessionUpper: 750000, method: "cliff", note: "100% duty exemption for first home buyers of established homes valued at $750,000 or less, for transactions settling between 18 February 2024 and 30 June 2026 (the scheme closes 30 June 2026). Full duty applies above $750,000." } },
|
|
9
|
+
ACT: { code: "ACT", name: "Australian Capital Territory", brackets: [{ rate: 0.0028, lower: 0, upper: 260000 }, { rate: 0.022, lower: 260000, upper: 300000 }, { rate: 0.034, lower: 300000, upper: 500000 }, { rate: 0.0432, lower: 500000, upper: 750000 }, { rate: 0.059, lower: 750000, upper: 1000000 }, { rate: 0.064, lower: 1000000, upper: 1455000 }], investmentBrackets: [{ rate: 0.012, lower: 0, upper: 200000 }, { rate: 0.022, lower: 200000, upper: 300000 }, { rate: 0.034, lower: 300000, upper: 500000 }, { rate: 0.0432, lower: 500000, upper: 750000 }, { rate: 0.059, lower: 750000, upper: 1000000 }, { rate: 0.064, lower: 1000000, upper: 1455000 }], flatAbove: { threshold: 1455000, rate: 0.0454 }, foreignSurchargeRate: 0, firstHome: { fullExemptThreshold: 1020000, concessionUpper: 1455000, method: "incomeTest", note: "Home Buyer Concession Scheme is income-tested (not value-tested): full duty concession ($0 duty) if total household taxable income is at or under the threshold (e.g. $250,000 with no dependent children, rising with children). There is no property-value cap on eligibility." } },
|
|
10
|
+
NT: { code: "NT", name: "Northern Territory", brackets: null, ntFormula: { a: 0.06571441, b: 15, vDivisor: 1000, cutoff: 525000, flatTiers: [[3000000, 0.0495], [5000000, 0.0575], [null, 0.0595]] }, foreignSurchargeRate: 0, firstHome: { fullExemptThreshold: 0, concessionUpper: 0, method: "none", note: "No general first-home stamp duty concession. Support is a cash grant (HomeGrown Territory: $50,000 for first home buyers building/buying a new home) plus the House and Land Package Exemption for new house-and-land packages. No foreign purchaser surcharge in the NT." } },
|
|
11
|
+
};
|
|
12
|
+
export const AU_STAMP_DUTY_AS_OF = "2025-26";
|
|
13
|
+
export const AU_STAMP_DUTY_SOURCES = [
|
|
14
|
+
{ label: "Revenue NSW - Transfer duty rates, surcharge purchaser duty, FHBAS (2025-26)", url: "https://www.revenue.nsw.gov.au/taxes-duties-levies-royalties/transfer-duty" },
|
|
15
|
+
{ label: "State Revenue Office Victoria - Land transfer duty current rates, PPR rates, FHB exemption/concession, foreign purchaser additional duty", url: "https://www.sro.vic.gov.au/land-transfer-duty" },
|
|
16
|
+
{ label: "Queensland Revenue Office - Transfer duty rates, home concession, first home concession, AFAD", url: "https://qro.qld.gov.au/duties/transfer-duty/" },
|
|
17
|
+
{ label: "Government of WA (RevenueWA) - Transfer duty general rate, first home owner rate, foreign transfer duty", url: "https://www.wa.gov.au/organisation/department-of-treasury-and-finance/transfer-duty-assessment" },
|
|
18
|
+
{ label: "RevenueSA - Rate of stamp duty (conveyance), first home buyer relief, foreign ownership surcharge", url: "https://revenuesa.sa.gov.au/stamp-duty/rate-of-stamp-duty" },
|
|
19
|
+
{ label: "State Revenue Office Tasmania - Property transfer duty rates, first home (established) duty relief, foreign investor duty surcharge", url: "https://www.sro.tas.gov.au/property-transfer-duties/rates-of-duty" },
|
|
20
|
+
{ label: "ACT Revenue Office - Conveyance duty for non-commercial property (from 1 July 2025), Home Buyer Concession Scheme", url: "https://www.revenue.act.gov.au/rates-and-property-charges/conveyance-duty-stamp-duty/conveyance-duty-for-non-commercial-property" },
|
|
21
|
+
{ label: "NT Territory Revenue Office - Stamp duty (Stamp Duty Act 1978 conveyance formula + flat tiers)", url: "https://treasury.nt.gov.au/dtf/territory-revenue-office/stamp-duty" },
|
|
22
|
+
];
|