@markcolabs/mcp 0.2.0 → 0.3.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/LICENSE +21 -0
- package/LICENSE-API.md +111 -0
- package/README.md +128 -205
- package/dist/engines/data/irs2026.d.ts +110 -3
- package/dist/engines/data/irs2026.d.ts.map +1 -1
- package/dist/engines/data/irs2026.js +86 -3
- package/dist/engines/data/irs2026.js.map +1 -1
- package/dist/engines/data/rmd2026.d.ts +59 -0
- package/dist/engines/data/rmd2026.d.ts.map +1 -0
- package/dist/engines/data/rmd2026.js +75 -0
- package/dist/engines/data/rmd2026.js.map +1 -0
- package/dist/engines/data/stateTax2026.d.ts +114 -0
- package/dist/engines/data/stateTax2026.d.ts.map +1 -0
- package/dist/engines/data/stateTax2026.js +348 -0
- package/dist/engines/data/stateTax2026.js.map +1 -0
- package/dist/engines/hsa.d.ts +110 -0
- package/dist/engines/hsa.d.ts.map +1 -0
- package/dist/engines/hsa.js +83 -0
- package/dist/engines/hsa.js.map +1 -0
- package/dist/engines/ira.d.ts +115 -0
- package/dist/engines/ira.d.ts.map +1 -0
- package/dist/engines/ira.js +127 -0
- package/dist/engines/ira.js.map +1 -0
- package/dist/engines/paycheck.d.ts +51 -16
- package/dist/engines/paycheck.d.ts.map +1 -1
- package/dist/engines/paycheck.js +53 -24
- package/dist/engines/paycheck.js.map +1 -1
- package/dist/engines/rmd.d.ts +107 -0
- package/dist/engines/rmd.d.ts.map +1 -0
- package/dist/engines/rmd.js +109 -0
- package/dist/engines/rmd.js.map +1 -0
- package/dist/engines/rothConversion.d.ts +124 -0
- package/dist/engines/rothConversion.d.ts.map +1 -0
- package/dist/engines/rothConversion.js +145 -0
- package/dist/engines/rothConversion.js.map +1 -0
- package/dist/index.d.ts +16 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +104 -6
- package/dist/index.js.map +1 -1
- package/dist/shared/bounds.d.ts +50 -0
- package/dist/shared/bounds.d.ts.map +1 -1
- package/dist/shared/bounds.js +85 -0
- package/dist/shared/bounds.js.map +1 -1
- package/dist/tools/hsa.d.ts +58 -0
- package/dist/tools/hsa.d.ts.map +1 -0
- package/dist/tools/hsa.js +129 -0
- package/dist/tools/hsa.js.map +1 -0
- package/dist/tools/ira.d.ts +55 -0
- package/dist/tools/ira.d.ts.map +1 -0
- package/dist/tools/ira.js +117 -0
- package/dist/tools/ira.js.map +1 -0
- package/dist/tools/paycheck.d.ts +14 -7
- package/dist/tools/paycheck.d.ts.map +1 -1
- package/dist/tools/paycheck.js +24 -11
- package/dist/tools/paycheck.js.map +1 -1
- package/dist/tools/rmd.d.ts +60 -0
- package/dist/tools/rmd.d.ts.map +1 -0
- package/dist/tools/rmd.js +130 -0
- package/dist/tools/rmd.js.map +1 -0
- package/dist/tools/rothConversion.d.ts +66 -0
- package/dist/tools/rothConversion.d.ts.map +1 -0
- package/dist/tools/rothConversion.js +141 -0
- package/dist/tools/rothConversion.js.map +1 -0
- package/package.json +18 -4
package/dist/tools/paycheck.js
CHANGED
|
@@ -6,11 +6,18 @@
|
|
|
6
6
|
* Per ADR-0039 § 3: returns ToolResult<PaycheckNetPayResult>.
|
|
7
7
|
* Per ADR-0039 § 4: failures funnel through ToolError; tools never throw.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* v0.3.0 (S141 Item #5):
|
|
10
|
+
* - MCP-AUDIT-011 fix: state-aware tax via Tax Foundation 2026 effective
|
|
11
|
+
* rates (was flat 5%).
|
|
12
|
+
* - MCP-AUDIT-012 fix: Additional Medicare 0.9% uses FICA wages base
|
|
13
|
+
* (gross − pre-tax cafeteria-plan deductions), not raw gross.
|
|
14
|
+
*
|
|
15
|
+
* YMYL note: state withholding varies by state. v0.3.0 returns $0 for the 9
|
|
16
|
+
* no-income-tax states and an effective-rate lookup (4 income tiers, Tax
|
|
17
|
+
* Foundation source) for all other states + DC. Per-state full-bracket
|
|
18
|
+
* simulation, SDI, and local-tax piggybacks (NYC, PA municipal EIT, etc.)
|
|
19
|
+
* are NOT modeled; callers needing precision should use the full site
|
|
20
|
+
* calculator at the methodology link.
|
|
14
21
|
*/
|
|
15
22
|
import { z } from "zod";
|
|
16
23
|
import { netPay, ENGINE_VERSION, } from "../engines/paycheck.js";
|
|
@@ -49,7 +56,11 @@ export const PaycheckNetPayInputSchema = z.object({
|
|
|
49
56
|
.int()
|
|
50
57
|
.min(PAYCHECK_BOUNDS.MIN_DEPENDENTS)
|
|
51
58
|
.max(PAYCHECK_BOUNDS.MAX_DEPENDENTS)
|
|
52
|
-
.
|
|
59
|
+
.default(0)
|
|
60
|
+
.describe("Number of dependents (Form W-4 line 3). Optional with default 0 as of v0.2.1. " +
|
|
61
|
+
"Currently has NO effect on the calculation — reserved for a future engine " +
|
|
62
|
+
"version that will wire Form W-4 line 3 dependent credits into the federal " +
|
|
63
|
+
"withholding math. See MCP-AUDIT-014 for the full-removal vs. wire-it-up decision."),
|
|
53
64
|
preTaxDeductionsAnnual: z
|
|
54
65
|
.number()
|
|
55
66
|
.min(PAYCHECK_BOUNDS.MIN_PRETAX_DEDUCTIONS)
|
|
@@ -63,11 +74,13 @@ export const PaycheckNetPayInputSchema = z.object({
|
|
|
63
74
|
});
|
|
64
75
|
export const TOOL_DESCRIPTION = "Estimate net (take-home) pay per paycheck using the IRS 2026 federal " +
|
|
65
76
|
"Percentage Method, FICA (Social Security 6.2% + Medicare 1.45% + Additional " +
|
|
66
|
-
"Medicare 0.9% above thresholds), and a
|
|
67
|
-
"for no-income-tax states;
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
77
|
+
"Medicare 0.9% above thresholds on FICA wages), and a state-aware tax " +
|
|
78
|
+
"estimate ($0 for the 9 no-income-tax states; Tax Foundation 2026 effective " +
|
|
79
|
+
"rates by income tier for all other states + DC). Returns gross/federal/FICA/" +
|
|
80
|
+
"state per-paycheck amounts plus annualized totals, plus the state-tax source " +
|
|
81
|
+
"citation, effective rate applied, and any state-specific caveats. Full " +
|
|
82
|
+
"per-state brackets, SDI, and local-tax piggybacks (NYC, PA EIT, etc.) are " +
|
|
83
|
+
"NOT modeled — see the methodology link for the full site calculator.";
|
|
71
84
|
export function execute(rawInput) {
|
|
72
85
|
const parsed = PaycheckNetPayInputSchema.safeParse(rawInput);
|
|
73
86
|
if (!parsed.success) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paycheck.js","sourceRoot":"","sources":["../../src/tools/paycheck.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"paycheck.js","sourceRoot":"","sources":["../../src/tools/paycheck.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool wrapper for `dc.calculator.rmd.distributionAmount`.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-0039 § 1: tool name locked.
|
|
5
|
+
* Per ADR-0039 § 2: Zod input with bounds from shared/bounds.ts; balance as USD.
|
|
6
|
+
* Per ADR-0039 § 3: returns ToolResult<RmdDistributionAmountResult>.
|
|
7
|
+
* Per ADR-0039 § 4: errors funnel through ToolError.
|
|
8
|
+
*
|
|
9
|
+
* Scope per S141 Wave 1B: single-year RMD distribution-amount only. Uniform
|
|
10
|
+
* Lifetime Table (IRS Pub. 590-B Table III) is the only table applied for v1
|
|
11
|
+
* to maintain parity with the site source. Joint Life Expectancy Table
|
|
12
|
+
* (Table II) is reserved for a future minor when the site engine adds it.
|
|
13
|
+
*/
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { type RmdDistributionAmountResult } from "../engines/rmd.js";
|
|
16
|
+
import { type ToolResult, type ToolError } from "../envelope.js";
|
|
17
|
+
/** Locked tool name per ADR-0039 § 1. */
|
|
18
|
+
export declare const TOOL_NAME = "dc.calculator.rmd.distributionAmount";
|
|
19
|
+
/**
|
|
20
|
+
* Zod input schema. Bounds come from shared/bounds.ts so engine and schema
|
|
21
|
+
* cannot drift. `spouseAge` and `isSpouseSoleBeneficiary` are accepted but
|
|
22
|
+
* ignored in v1 (reserved for future Joint Life Expectancy Table support
|
|
23
|
+
* once the site engine adds Table II).
|
|
24
|
+
*/
|
|
25
|
+
export declare const RmdDistributionAmountInputSchema: z.ZodObject<{
|
|
26
|
+
accountBalance: z.ZodNumber;
|
|
27
|
+
ownerAge: z.ZodNumber;
|
|
28
|
+
spouseAge: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
isSpouseSoleBeneficiary: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
}, "strip", z.ZodTypeAny, {
|
|
31
|
+
accountBalance: number;
|
|
32
|
+
ownerAge: number;
|
|
33
|
+
spouseAge?: number | undefined;
|
|
34
|
+
isSpouseSoleBeneficiary?: boolean | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
accountBalance: number;
|
|
37
|
+
ownerAge: number;
|
|
38
|
+
spouseAge?: number | undefined;
|
|
39
|
+
isSpouseSoleBeneficiary?: boolean | undefined;
|
|
40
|
+
}>;
|
|
41
|
+
export type RmdDistributionAmountToolInput = z.infer<typeof RmdDistributionAmountInputSchema>;
|
|
42
|
+
/** Tool description used in mcp.tools/list. */
|
|
43
|
+
export declare const TOOL_DESCRIPTION: string;
|
|
44
|
+
/**
|
|
45
|
+
* Execute the tool. Validation + engine call wrapped in the standard envelope.
|
|
46
|
+
*
|
|
47
|
+
* Tagged-union return:
|
|
48
|
+
* { ok: true, value: ToolResult<...> }
|
|
49
|
+
* { ok: false, error: ToolError }
|
|
50
|
+
*
|
|
51
|
+
* The MCP SDK adapter at src/index.ts maps `ok=false` to `isError: true`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function execute(rawInput: unknown): {
|
|
54
|
+
ok: true;
|
|
55
|
+
value: ToolResult<RmdDistributionAmountResult>;
|
|
56
|
+
} | {
|
|
57
|
+
ok: false;
|
|
58
|
+
error: ToolError;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=rmd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rmd.d.ts","sourceRoot":"","sources":["../../src/tools/rmd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,2BAA2B,EACjC,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,yCAAyC;AACzC,eAAO,MAAM,SAAS,yCAAyC,CAAC;AAQhE;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;EA+B3C,CAAC;AAEH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAClD,OAAO,gCAAgC,CACxC,CAAC;AAEF,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,QAYD,CAAC;AAE7B;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,QAAQ,EAAE,OAAO,GAEf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,2BAA2B,CAAC,CAAA;CAAE,GAC5D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAwDlC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool wrapper for `dc.calculator.rmd.distributionAmount`.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-0039 § 1: tool name locked.
|
|
5
|
+
* Per ADR-0039 § 2: Zod input with bounds from shared/bounds.ts; balance as USD.
|
|
6
|
+
* Per ADR-0039 § 3: returns ToolResult<RmdDistributionAmountResult>.
|
|
7
|
+
* Per ADR-0039 § 4: errors funnel through ToolError.
|
|
8
|
+
*
|
|
9
|
+
* Scope per S141 Wave 1B: single-year RMD distribution-amount only. Uniform
|
|
10
|
+
* Lifetime Table (IRS Pub. 590-B Table III) is the only table applied for v1
|
|
11
|
+
* to maintain parity with the site source. Joint Life Expectancy Table
|
|
12
|
+
* (Table II) is reserved for a future minor when the site engine adds it.
|
|
13
|
+
*/
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { distributionAmount, ENGINE_VERSION, } from "../engines/rmd.js";
|
|
16
|
+
import { RMD_BOUNDS } from "../shared/bounds.js";
|
|
17
|
+
import { YMYL_DISCLAIMER } from "../disclaimers/ymyl.js";
|
|
18
|
+
import { makeResult, makeError, } from "../envelope.js";
|
|
19
|
+
/** Locked tool name per ADR-0039 § 1. */
|
|
20
|
+
export const TOOL_NAME = "dc.calculator.rmd.distributionAmount";
|
|
21
|
+
/** Methodology pointer — ADR-0039 § 3. */
|
|
22
|
+
const METHODOLOGY = {
|
|
23
|
+
url: "https://www.digitalcalculator.info/rmd-calculator/",
|
|
24
|
+
version: "2026-05-27",
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Zod input schema. Bounds come from shared/bounds.ts so engine and schema
|
|
28
|
+
* cannot drift. `spouseAge` and `isSpouseSoleBeneficiary` are accepted but
|
|
29
|
+
* ignored in v1 (reserved for future Joint Life Expectancy Table support
|
|
30
|
+
* once the site engine adds Table II).
|
|
31
|
+
*/
|
|
32
|
+
export const RmdDistributionAmountInputSchema = z.object({
|
|
33
|
+
accountBalance: z
|
|
34
|
+
.number()
|
|
35
|
+
.min(RMD_BOUNDS.MIN_BALANCE)
|
|
36
|
+
.max(RMD_BOUNDS.MAX_BALANCE)
|
|
37
|
+
.describe("Prior year-end IRA / 401(k) / 403(b) / 457(b) balance, USD."),
|
|
38
|
+
ownerAge: z
|
|
39
|
+
.number()
|
|
40
|
+
.int()
|
|
41
|
+
.min(RMD_BOUNDS.MIN_OWNER_AGE)
|
|
42
|
+
.max(RMD_BOUNDS.MAX_OWNER_AGE)
|
|
43
|
+
.describe("Owner's age this calendar year. Must be >= 73 (SECURE 2.0 RMD age for the 1951-1959 birth-year cohort). Lower ages are pre-RMD; callers seeking projections for younger owners should use the calculator directly."),
|
|
44
|
+
spouseAge: z
|
|
45
|
+
.number()
|
|
46
|
+
.int()
|
|
47
|
+
.min(0)
|
|
48
|
+
.max(120)
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Optional spouse age. RESERVED for future Joint Life Expectancy Table support — v1 IGNORES this input and always applies the Uniform Lifetime Table (matches site parity)."),
|
|
51
|
+
isSpouseSoleBeneficiary: z
|
|
52
|
+
.boolean()
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Optional flag indicating spouse is the sole IRA beneficiary. RESERVED for future Joint Life Expectancy Table support — v1 IGNORES this input."),
|
|
55
|
+
});
|
|
56
|
+
/** Tool description used in mcp.tools/list. */
|
|
57
|
+
export const TOOL_DESCRIPTION = "Compute the required minimum distribution (RMD) for 2026 from a Traditional " +
|
|
58
|
+
"IRA / 401(k) / 403(b) / 457(b) account given the prior year-end balance and " +
|
|
59
|
+
"the owner's age. Applies the IRS Uniform Lifetime Table (Pub. 590-B Table III, " +
|
|
60
|
+
"post-2022 version) and reports the SECURE 2.0 §302 missed-RMD excise tax (25% " +
|
|
61
|
+
"default; reduced to 10% if corrected within the IRS correction window). " +
|
|
62
|
+
"SCOPE: single-year calculation only — multi-year projections are out of " +
|
|
63
|
+
"scope (use the calculator at /rmd-calculator/). The Joint Life Expectancy " +
|
|
64
|
+
"Table (Pub. 590-B Table II, applied when spouse is sole beneficiary and " +
|
|
65
|
+
"10+ years younger) is NOT implemented in v1; `spouseAge` and " +
|
|
66
|
+
"`isSpouseSoleBeneficiary` are accepted but ignored. Returns " +
|
|
67
|
+
"{ rmdAmount, distributionPeriod, lifeExpectancyFactor, tableUsed, " +
|
|
68
|
+
"penaltyIfMissed, meta }.";
|
|
69
|
+
/**
|
|
70
|
+
* Execute the tool. Validation + engine call wrapped in the standard envelope.
|
|
71
|
+
*
|
|
72
|
+
* Tagged-union return:
|
|
73
|
+
* { ok: true, value: ToolResult<...> }
|
|
74
|
+
* { ok: false, error: ToolError }
|
|
75
|
+
*
|
|
76
|
+
* The MCP SDK adapter at src/index.ts maps `ok=false` to `isError: true`.
|
|
77
|
+
*/
|
|
78
|
+
export function execute(rawInput) {
|
|
79
|
+
const parsed = RmdDistributionAmountInputSchema.safeParse(rawInput);
|
|
80
|
+
if (!parsed.success) {
|
|
81
|
+
const first = parsed.error.issues[0];
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
error: makeError({
|
|
85
|
+
code: "INPUT_VALIDATION",
|
|
86
|
+
message: first?.message ?? "Invalid input.",
|
|
87
|
+
field: first?.path.join(".") || undefined,
|
|
88
|
+
retriable: false,
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const input = parsed.data;
|
|
93
|
+
let payload;
|
|
94
|
+
try {
|
|
95
|
+
payload = distributionAmount(input);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
error: makeError({
|
|
101
|
+
code: "INTERNAL",
|
|
102
|
+
message: "Engine error computing RMD distribution amount.",
|
|
103
|
+
retriable: false,
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (!Number.isFinite(payload.rmdAmount) ||
|
|
108
|
+
!Number.isFinite(payload.distributionPeriod) ||
|
|
109
|
+
!Number.isFinite(payload.lifeExpectancyFactor) ||
|
|
110
|
+
!Number.isFinite(payload.penaltyIfMissed)) {
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
error: makeError({
|
|
114
|
+
code: "INTERNAL",
|
|
115
|
+
message: "RMD engine produced a non-finite result.",
|
|
116
|
+
retriable: false,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
ok: true,
|
|
122
|
+
value: makeResult({
|
|
123
|
+
result: payload,
|
|
124
|
+
methodology: METHODOLOGY,
|
|
125
|
+
engineVersion: ENGINE_VERSION,
|
|
126
|
+
disclaimer: YMYL_DISCLAIMER,
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=rmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rmd.js","sourceRoot":"","sources":["../../src/tools/rmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool wrapper for `dc.calculator.rothConversion.taxImpact`.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-0039 § 1: tool name locked.
|
|
5
|
+
* Per ADR-0039 § 2: Zod input with bounds from shared/bounds.ts; rate as
|
|
6
|
+
* whole-number Percent; enum for filing status.
|
|
7
|
+
* Per ADR-0039 § 3: returns ToolResult<RothConversionTaxImpactResult>.
|
|
8
|
+
* Per ADR-0039 § 4: errors funnel through ToolError.
|
|
9
|
+
*
|
|
10
|
+
* Scope per S141 Risk #2: SINGLE-CONVERSION tax impact only. Multi-year
|
|
11
|
+
* conversion-ladder optimization is a future tool. State tax and IRMAA tier
|
|
12
|
+
* impact are out of scope (documented in the tool description).
|
|
13
|
+
*/
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { type RothConversionTaxImpactResult } from "../engines/rothConversion.js";
|
|
16
|
+
import { type ToolResult, type ToolError } from "../envelope.js";
|
|
17
|
+
/** Locked tool name per ADR-0039 § 1. */
|
|
18
|
+
export declare const TOOL_NAME = "dc.calculator.rothConversion.taxImpact";
|
|
19
|
+
/**
|
|
20
|
+
* Zod input schema. Bounds come from shared/bounds.ts. Filing status uses
|
|
21
|
+
* the paycheck-engine FEDERAL_FILING_STATUS enum (single | married |
|
|
22
|
+
* marriedSeparate | headOfHousehold) for consistency with other federal-tax
|
|
23
|
+
* tools.
|
|
24
|
+
*/
|
|
25
|
+
export declare const RothConversionTaxImpactInputSchema: z.ZodObject<{
|
|
26
|
+
conversionAmount: z.ZodNumber;
|
|
27
|
+
age: z.ZodNumber;
|
|
28
|
+
filingStatus: z.ZodEnum<["single", "married", "marriedSeparate", "headOfHousehold"]>;
|
|
29
|
+
currentTaxableIncome: z.ZodNumber;
|
|
30
|
+
retirementMarginalRatePercent: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
expectedReturnPercent: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
age: number;
|
|
34
|
+
filingStatus: "single" | "married" | "marriedSeparate" | "headOfHousehold";
|
|
35
|
+
conversionAmount: number;
|
|
36
|
+
currentTaxableIncome: number;
|
|
37
|
+
retirementMarginalRatePercent?: number | undefined;
|
|
38
|
+
expectedReturnPercent?: number | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
age: number;
|
|
41
|
+
filingStatus: "single" | "married" | "marriedSeparate" | "headOfHousehold";
|
|
42
|
+
conversionAmount: number;
|
|
43
|
+
currentTaxableIncome: number;
|
|
44
|
+
retirementMarginalRatePercent?: number | undefined;
|
|
45
|
+
expectedReturnPercent?: number | undefined;
|
|
46
|
+
}>;
|
|
47
|
+
export type RothConversionTaxImpactToolInput = z.infer<typeof RothConversionTaxImpactInputSchema>;
|
|
48
|
+
/** Tool description used in mcp.tools/list. */
|
|
49
|
+
export declare const TOOL_DESCRIPTION: string;
|
|
50
|
+
/**
|
|
51
|
+
* Execute the tool. Validation + engine call wrapped in the standard envelope.
|
|
52
|
+
*
|
|
53
|
+
* Tagged-union return:
|
|
54
|
+
* { ok: true, value: ToolResult<...> }
|
|
55
|
+
* { ok: false, error: ToolError }
|
|
56
|
+
*
|
|
57
|
+
* The MCP SDK adapter at src/index.ts maps `ok=false` to `isError: true`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function execute(rawInput: unknown): {
|
|
60
|
+
ok: true;
|
|
61
|
+
value: ToolResult<RothConversionTaxImpactResult>;
|
|
62
|
+
} | {
|
|
63
|
+
ok: false;
|
|
64
|
+
error: ToolError;
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=rothConversion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rothConversion.d.ts","sourceRoot":"","sources":["../../src/tools/rothConversion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,6BAA6B,EACnC,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,yCAAyC;AACzC,eAAO,MAAM,SAAS,2CAA2C,CAAC;AAQlE;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;EA0C7C,CAAC;AAEH,MAAM,MAAM,gCAAgC,GAAG,CAAC,CAAC,KAAK,CACpD,OAAO,kCAAkC,CAC1C,CAAC;AAEF,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,QAOiB,CAAC;AAE/C;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,QAAQ,EAAE,OAAO,GAEf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,6BAA6B,CAAC,CAAA;CAAE,GAC9D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CA+DlC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool wrapper for `dc.calculator.rothConversion.taxImpact`.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-0039 § 1: tool name locked.
|
|
5
|
+
* Per ADR-0039 § 2: Zod input with bounds from shared/bounds.ts; rate as
|
|
6
|
+
* whole-number Percent; enum for filing status.
|
|
7
|
+
* Per ADR-0039 § 3: returns ToolResult<RothConversionTaxImpactResult>.
|
|
8
|
+
* Per ADR-0039 § 4: errors funnel through ToolError.
|
|
9
|
+
*
|
|
10
|
+
* Scope per S141 Risk #2: SINGLE-CONVERSION tax impact only. Multi-year
|
|
11
|
+
* conversion-ladder optimization is a future tool. State tax and IRMAA tier
|
|
12
|
+
* impact are out of scope (documented in the tool description).
|
|
13
|
+
*/
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { taxImpact, ENGINE_VERSION, } from "../engines/rothConversion.js";
|
|
16
|
+
import { ROTH_CONVERSION_BOUNDS } from "../shared/bounds.js";
|
|
17
|
+
import { FEDERAL_FILING_STATUS } from "../shared/bounds.js";
|
|
18
|
+
import { YMYL_DISCLAIMER } from "../disclaimers/ymyl.js";
|
|
19
|
+
import { makeResult, makeError, } from "../envelope.js";
|
|
20
|
+
/** Locked tool name per ADR-0039 § 1. */
|
|
21
|
+
export const TOOL_NAME = "dc.calculator.rothConversion.taxImpact";
|
|
22
|
+
/** Methodology pointer — ADR-0039 § 3. */
|
|
23
|
+
const METHODOLOGY = {
|
|
24
|
+
url: "https://www.digitalcalculator.info/roth-conversion-calculator/",
|
|
25
|
+
version: "2026-05-27",
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Zod input schema. Bounds come from shared/bounds.ts. Filing status uses
|
|
29
|
+
* the paycheck-engine FEDERAL_FILING_STATUS enum (single | married |
|
|
30
|
+
* marriedSeparate | headOfHousehold) for consistency with other federal-tax
|
|
31
|
+
* tools.
|
|
32
|
+
*/
|
|
33
|
+
export const RothConversionTaxImpactInputSchema = z.object({
|
|
34
|
+
conversionAmount: z
|
|
35
|
+
.number()
|
|
36
|
+
.min(ROTH_CONVERSION_BOUNDS.MIN_CONVERSION)
|
|
37
|
+
.max(ROTH_CONVERSION_BOUNDS.MAX_CONVERSION)
|
|
38
|
+
.describe("Conversion amount in USD."),
|
|
39
|
+
age: z
|
|
40
|
+
.number()
|
|
41
|
+
.int()
|
|
42
|
+
.min(ROTH_CONVERSION_BOUNDS.MIN_AGE)
|
|
43
|
+
.max(ROTH_CONVERSION_BOUNDS.MAX_AGE)
|
|
44
|
+
.describe("Current age. Drives the Roth 5-year-rule flag (applies if age < 59.5)."),
|
|
45
|
+
filingStatus: z
|
|
46
|
+
.enum(FEDERAL_FILING_STATUS)
|
|
47
|
+
.describe("Federal filing status: single | married | marriedSeparate | headOfHousehold."),
|
|
48
|
+
currentTaxableIncome: z
|
|
49
|
+
.number()
|
|
50
|
+
.min(ROTH_CONVERSION_BOUNDS.MIN_TAXABLE_INCOME)
|
|
51
|
+
.max(ROTH_CONVERSION_BOUNDS.MAX_TAXABLE_INCOME)
|
|
52
|
+
.describe("Current federal taxable income BEFORE adding the conversion, USD. Used as the lower bound for the incremental-tax bracket walk."),
|
|
53
|
+
retirementMarginalRatePercent: z
|
|
54
|
+
.number()
|
|
55
|
+
.min(ROTH_CONVERSION_BOUNDS.MIN_RETIREMENT_RATE_PERCENT)
|
|
56
|
+
.max(ROTH_CONVERSION_BOUNDS.MAX_RETIREMENT_RATE_PERCENT)
|
|
57
|
+
.optional()
|
|
58
|
+
.describe("Optional expected retirement marginal federal tax rate, whole-number percent (e.g., 12 for 12%). When omitted, breakEvenYears returns null."),
|
|
59
|
+
expectedReturnPercent: z
|
|
60
|
+
.number()
|
|
61
|
+
.min(ROTH_CONVERSION_BOUNDS.MIN_RETURN_PERCENT)
|
|
62
|
+
.max(ROTH_CONVERSION_BOUNDS.MAX_RETURN_PERCENT)
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Optional real annual return on the converted Roth balance, whole-number percent. Defaults to 7. Used only for the break-even calculation."),
|
|
65
|
+
});
|
|
66
|
+
/** Tool description used in mcp.tools/list. */
|
|
67
|
+
export const TOOL_DESCRIPTION = "Compute the federal income tax impact of a SINGLE Roth conversion using " +
|
|
68
|
+
"2026 IRS brackets. Returns the incremental tax owed, the top marginal " +
|
|
69
|
+
"bracket the conversion pushes you into, the effective rate, a Roth 5-year-" +
|
|
70
|
+
"rule flag, and optional break-even years if you provide your expected " +
|
|
71
|
+
"retirement marginal rate. SCOPE LIMITS: single-conversion only (multi-year " +
|
|
72
|
+
"optimization is a future tool); state tax and IRMAA tier impact are NOT " +
|
|
73
|
+
"modeled — caller is responsible for those.";
|
|
74
|
+
/**
|
|
75
|
+
* Execute the tool. Validation + engine call wrapped in the standard envelope.
|
|
76
|
+
*
|
|
77
|
+
* Tagged-union return:
|
|
78
|
+
* { ok: true, value: ToolResult<...> }
|
|
79
|
+
* { ok: false, error: ToolError }
|
|
80
|
+
*
|
|
81
|
+
* The MCP SDK adapter at src/index.ts maps `ok=false` to `isError: true`.
|
|
82
|
+
*/
|
|
83
|
+
export function execute(rawInput) {
|
|
84
|
+
const parsed = RothConversionTaxImpactInputSchema.safeParse(rawInput);
|
|
85
|
+
if (!parsed.success) {
|
|
86
|
+
const first = parsed.error.issues[0];
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
error: makeError({
|
|
90
|
+
code: "INPUT_VALIDATION",
|
|
91
|
+
message: first?.message ?? "Invalid input.",
|
|
92
|
+
field: first?.path.join(".") || undefined,
|
|
93
|
+
retriable: false,
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const input = parsed.data;
|
|
98
|
+
let payload;
|
|
99
|
+
try {
|
|
100
|
+
payload = taxImpact(input);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return {
|
|
104
|
+
ok: false,
|
|
105
|
+
error: makeError({
|
|
106
|
+
code: "INTERNAL",
|
|
107
|
+
message: "Engine error computing Roth conversion tax impact.",
|
|
108
|
+
retriable: false,
|
|
109
|
+
}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// Sanity check: NaN / non-finite results are an internal failure.
|
|
113
|
+
// breakEvenYears may legitimately be null (no retirement rate given) or
|
|
114
|
+
// Infinity (mathematically unreachable), both of which we allow.
|
|
115
|
+
const beOk = payload.breakEvenYears === null ||
|
|
116
|
+
payload.breakEvenYears === Infinity ||
|
|
117
|
+
Number.isFinite(payload.breakEvenYears);
|
|
118
|
+
if (!Number.isFinite(payload.taxOwed) ||
|
|
119
|
+
!Number.isFinite(payload.marginalRateOnConversion) ||
|
|
120
|
+
!Number.isFinite(payload.effectiveRateOnConversion) ||
|
|
121
|
+
!beOk) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
error: makeError({
|
|
125
|
+
code: "INTERNAL",
|
|
126
|
+
message: "Roth conversion engine produced a non-finite result.",
|
|
127
|
+
retriable: false,
|
|
128
|
+
}),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
ok: true,
|
|
133
|
+
value: makeResult({
|
|
134
|
+
result: payload,
|
|
135
|
+
methodology: METHODOLOGY,
|
|
136
|
+
engineVersion: ENGINE_VERSION,
|
|
137
|
+
disclaimer: YMYL_DISCLAIMER,
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=rothConversion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rothConversion.js","sourceRoot":"","sources":["../../src/tools/rothConversion.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markcolabs/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "Model Context Protocol server for digitalcalculator.info financial calculators. v0.
|
|
5
|
+
"description": "Model Context Protocol server for digitalcalculator.info financial calculators. v0.3.0 ships 9 calculator tools (mortgage monthlyPayment, compound-interest futureValue, retirement401k projection, Social Security estimatedBenefit, paycheck netPay, IRA contributionLimit, Roth conversion taxImpact, RMD distributionAmount, HSA contributionLimit). Per ADR-0039 + ADR-0041 contract reconciliation.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
-
"README.md"
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"LICENSE-API.md"
|
|
22
24
|
],
|
|
23
25
|
"dependencies": {
|
|
24
26
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
@@ -35,16 +37,28 @@
|
|
|
35
37
|
"keywords": [
|
|
36
38
|
"mcp",
|
|
37
39
|
"model-context-protocol",
|
|
40
|
+
"mcp-server",
|
|
41
|
+
"claude-mcp",
|
|
42
|
+
"anthropic",
|
|
38
43
|
"financial-calculator",
|
|
39
44
|
"mortgage",
|
|
40
45
|
"compound-interest",
|
|
41
46
|
"401k",
|
|
42
47
|
"social-security",
|
|
43
48
|
"paycheck",
|
|
44
|
-
"
|
|
49
|
+
"ira",
|
|
50
|
+
"roth-conversion",
|
|
51
|
+
"rmd",
|
|
52
|
+
"hsa",
|
|
53
|
+
"digitalcalculator",
|
|
54
|
+
"digitalcalculator.info"
|
|
45
55
|
],
|
|
46
56
|
"author": "Markcolabs LLC",
|
|
47
57
|
"license": "MIT",
|
|
58
|
+
"homepage": "https://www.digitalcalculator.info/mcp/",
|
|
59
|
+
"bugs": {
|
|
60
|
+
"url": "https://github.com/mark57-ux/digitalcalculator/issues"
|
|
61
|
+
},
|
|
48
62
|
"repository": {
|
|
49
63
|
"type": "git",
|
|
50
64
|
"url": "https://github.com/mark57-ux/digitalcalculator.git",
|