@markcolabs/mcp 0.3.0 → 0.4.1
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/README.md +126 -186
- package/dist/index.d.ts +9 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -284
- package/dist/index.js.map +1 -1
- package/package.json +15 -13
- package/LICENSE-API.md +0 -111
- package/dist/disclaimers/ymyl.d.ts +0 -16
- package/dist/disclaimers/ymyl.d.ts.map +0 -1
- package/dist/disclaimers/ymyl.js +0 -20
- package/dist/disclaimers/ymyl.js.map +0 -1
- package/dist/engines/compoundInterest.d.ts +0 -75
- package/dist/engines/compoundInterest.d.ts.map +0 -1
- package/dist/engines/compoundInterest.js +0 -74
- package/dist/engines/compoundInterest.js.map +0 -1
- package/dist/engines/data/federalTax.d.ts +0 -47
- package/dist/engines/data/federalTax.d.ts.map +0 -1
- package/dist/engines/data/federalTax.js +0 -111
- package/dist/engines/data/federalTax.js.map +0 -1
- package/dist/engines/data/irs2026.d.ts +0 -137
- package/dist/engines/data/irs2026.d.ts.map +0 -1
- package/dist/engines/data/irs2026.js +0 -113
- package/dist/engines/data/irs2026.js.map +0 -1
- package/dist/engines/data/rmd2026.d.ts +0 -59
- package/dist/engines/data/rmd2026.d.ts.map +0 -1
- package/dist/engines/data/rmd2026.js +0 -75
- package/dist/engines/data/rmd2026.js.map +0 -1
- package/dist/engines/data/ssa.d.ts +0 -39
- package/dist/engines/data/ssa.d.ts.map +0 -1
- package/dist/engines/data/ssa.js +0 -55
- package/dist/engines/data/ssa.js.map +0 -1
- package/dist/engines/data/stateTax2026.d.ts +0 -114
- package/dist/engines/data/stateTax2026.d.ts.map +0 -1
- package/dist/engines/data/stateTax2026.js +0 -348
- package/dist/engines/data/stateTax2026.js.map +0 -1
- package/dist/engines/hsa.d.ts +0 -110
- package/dist/engines/hsa.d.ts.map +0 -1
- package/dist/engines/hsa.js +0 -83
- package/dist/engines/hsa.js.map +0 -1
- package/dist/engines/ira.d.ts +0 -115
- package/dist/engines/ira.d.ts.map +0 -1
- package/dist/engines/ira.js +0 -127
- package/dist/engines/ira.js.map +0 -1
- package/dist/engines/mortgage.d.ts +0 -70
- package/dist/engines/mortgage.d.ts.map +0 -1
- package/dist/engines/mortgage.js +0 -60
- package/dist/engines/mortgage.js.map +0 -1
- package/dist/engines/paycheck.d.ts +0 -128
- package/dist/engines/paycheck.d.ts.map +0 -1
- package/dist/engines/paycheck.js +0 -142
- package/dist/engines/paycheck.js.map +0 -1
- package/dist/engines/retirement401k.d.ts +0 -109
- package/dist/engines/retirement401k.d.ts.map +0 -1
- package/dist/engines/retirement401k.js +0 -130
- package/dist/engines/retirement401k.js.map +0 -1
- package/dist/engines/rmd.d.ts +0 -107
- package/dist/engines/rmd.d.ts.map +0 -1
- package/dist/engines/rmd.js +0 -109
- package/dist/engines/rmd.js.map +0 -1
- package/dist/engines/rothConversion.d.ts +0 -124
- package/dist/engines/rothConversion.d.ts.map +0 -1
- package/dist/engines/rothConversion.js +0 -145
- package/dist/engines/rothConversion.js.map +0 -1
- package/dist/engines/socialSecurity.d.ts +0 -63
- package/dist/engines/socialSecurity.d.ts.map +0 -1
- package/dist/engines/socialSecurity.js +0 -139
- package/dist/engines/socialSecurity.js.map +0 -1
- package/dist/envelope.d.ts +0 -76
- package/dist/envelope.d.ts.map +0 -1
- package/dist/envelope.js +0 -34
- package/dist/envelope.js.map +0 -1
- package/dist/shared/bounds.d.ts +0 -133
- package/dist/shared/bounds.d.ts.map +0 -1
- package/dist/shared/bounds.js +0 -206
- package/dist/shared/bounds.js.map +0 -1
- package/dist/tools/compoundInterest.d.ts +0 -48
- package/dist/tools/compoundInterest.d.ts.map +0 -1
- package/dist/tools/compoundInterest.js +0 -107
- package/dist/tools/compoundInterest.js.map +0 -1
- package/dist/tools/hsa.d.ts +0 -58
- package/dist/tools/hsa.d.ts.map +0 -1
- package/dist/tools/hsa.js +0 -129
- package/dist/tools/hsa.js.map +0 -1
- package/dist/tools/ira.d.ts +0 -55
- package/dist/tools/ira.d.ts.map +0 -1
- package/dist/tools/ira.js +0 -117
- package/dist/tools/ira.js.map +0 -1
- package/dist/tools/mortgage.d.ts +0 -51
- package/dist/tools/mortgage.d.ts.map +0 -1
- package/dist/tools/mortgage.js +0 -112
- package/dist/tools/mortgage.js.map +0 -1
- package/dist/tools/paycheck.d.ts +0 -61
- package/dist/tools/paycheck.d.ts.map +0 -1
- package/dist/tools/paycheck.js +0 -135
- package/dist/tools/paycheck.js.map +0 -1
- package/dist/tools/retirement401k.d.ts +0 -85
- package/dist/tools/retirement401k.d.ts.map +0 -1
- package/dist/tools/retirement401k.js +0 -141
- package/dist/tools/retirement401k.js.map +0 -1
- package/dist/tools/rmd.d.ts +0 -60
- package/dist/tools/rmd.d.ts.map +0 -1
- package/dist/tools/rmd.js +0 -130
- package/dist/tools/rmd.js.map +0 -1
- package/dist/tools/rothConversion.d.ts +0 -66
- package/dist/tools/rothConversion.d.ts.map +0 -1
- package/dist/tools/rothConversion.js +0 -141
- package/dist/tools/rothConversion.js.map +0 -1
- package/dist/tools/socialSecurity.d.ts +0 -51
- package/dist/tools/socialSecurity.d.ts.map +0 -1
- package/dist/tools/socialSecurity.js +0 -117
- package/dist/tools/socialSecurity.js.map +0 -1
- package/dist/util/zod-to-json-schema.d.ts +0 -28
- package/dist/util/zod-to-json-schema.d.ts.map +0 -1
- package/dist/util/zod-to-json-schema.js +0 -98
- package/dist/util/zod-to-json-schema.js.map +0 -1
package/dist/tools/paycheck.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP tool wrapper for `dc.calculator.paycheck.netPay`.
|
|
3
|
-
*
|
|
4
|
-
* Per ADR-0039 § 1: tool name is locked.
|
|
5
|
-
* Per ADR-0039 § 2: Zod input schema with bounds from shared/bounds.ts.
|
|
6
|
-
* Per ADR-0039 § 3: returns ToolResult<PaycheckNetPayResult>.
|
|
7
|
-
* Per ADR-0039 § 4: failures funnel through ToolError; tools never throw.
|
|
8
|
-
*
|
|
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.
|
|
21
|
-
*/
|
|
22
|
-
import { z } from "zod";
|
|
23
|
-
import { netPay, ENGINE_VERSION, } from "../engines/paycheck.js";
|
|
24
|
-
import { PAYCHECK_BOUNDS, PAYCHECK_PAY_FREQUENCY, FEDERAL_FILING_STATUS, } from "../shared/bounds.js";
|
|
25
|
-
import { YMYL_DISCLAIMER } from "../disclaimers/ymyl.js";
|
|
26
|
-
import { makeResult, makeError, } from "../envelope.js";
|
|
27
|
-
/** Locked tool name per ADR-0039 § 1. */
|
|
28
|
-
export const TOOL_NAME = "dc.calculator.paycheck.netPay";
|
|
29
|
-
const METHODOLOGY = {
|
|
30
|
-
url: "https://www.digitalcalculator.info/paycheck-calculator/methodology/",
|
|
31
|
-
version: "2026-05-09",
|
|
32
|
-
};
|
|
33
|
-
const PAY_FREQUENCY_LABELS = Object.keys(PAYCHECK_PAY_FREQUENCY);
|
|
34
|
-
const FILING_STATUS_LABELS = [
|
|
35
|
-
FEDERAL_FILING_STATUS[0],
|
|
36
|
-
...FEDERAL_FILING_STATUS.slice(1),
|
|
37
|
-
];
|
|
38
|
-
export const PaycheckNetPayInputSchema = z.object({
|
|
39
|
-
grossAnnualSalary: z
|
|
40
|
-
.number()
|
|
41
|
-
.min(PAYCHECK_BOUNDS.MIN_GROSS_ANNUAL_SALARY)
|
|
42
|
-
.max(PAYCHECK_BOUNDS.MAX_GROSS_ANNUAL_SALARY)
|
|
43
|
-
.describe("Gross annual salary in USD."),
|
|
44
|
-
payFrequency: z
|
|
45
|
-
.enum(PAY_FREQUENCY_LABELS)
|
|
46
|
-
.describe("Pay frequency: weekly | biweekly | semimonthly | monthly | quarterly | annual."),
|
|
47
|
-
federalFilingStatus: z
|
|
48
|
-
.enum(FILING_STATUS_LABELS)
|
|
49
|
-
.describe("Federal filing status: single | married | marriedSeparate | headOfHousehold."),
|
|
50
|
-
state: z
|
|
51
|
-
.string()
|
|
52
|
-
.length(2)
|
|
53
|
-
.describe("Two-letter state code (e.g., 'CA', 'TX'). Used for no-income-tax detection."),
|
|
54
|
-
dependents: z
|
|
55
|
-
.number()
|
|
56
|
-
.int()
|
|
57
|
-
.min(PAYCHECK_BOUNDS.MIN_DEPENDENTS)
|
|
58
|
-
.max(PAYCHECK_BOUNDS.MAX_DEPENDENTS)
|
|
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."),
|
|
64
|
-
preTaxDeductionsAnnual: z
|
|
65
|
-
.number()
|
|
66
|
-
.min(PAYCHECK_BOUNDS.MIN_PRETAX_DEDUCTIONS)
|
|
67
|
-
.max(PAYCHECK_BOUNDS.MAX_PRETAX_DEDUCTIONS)
|
|
68
|
-
.describe("Total pre-tax deductions per year (401k, HSA, FSA, etc.) in USD."),
|
|
69
|
-
postTaxDeductionsAnnual: z
|
|
70
|
-
.number()
|
|
71
|
-
.min(PAYCHECK_BOUNDS.MIN_POSTTAX_DEDUCTIONS)
|
|
72
|
-
.max(PAYCHECK_BOUNDS.MAX_POSTTAX_DEDUCTIONS)
|
|
73
|
-
.describe("Total post-tax deductions per year (Roth contributions, garnishments, etc.) in USD."),
|
|
74
|
-
});
|
|
75
|
-
export const TOOL_DESCRIPTION = "Estimate net (take-home) pay per paycheck using the IRS 2026 federal " +
|
|
76
|
-
"Percentage Method, FICA (Social Security 6.2% + Medicare 1.45% + Additional " +
|
|
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.";
|
|
84
|
-
export function execute(rawInput) {
|
|
85
|
-
const parsed = PaycheckNetPayInputSchema.safeParse(rawInput);
|
|
86
|
-
if (!parsed.success) {
|
|
87
|
-
const first = parsed.error.issues[0];
|
|
88
|
-
return {
|
|
89
|
-
ok: false,
|
|
90
|
-
error: makeError({
|
|
91
|
-
code: "INPUT_VALIDATION",
|
|
92
|
-
message: first?.message ?? "Invalid input.",
|
|
93
|
-
field: first?.path.join(".") || undefined,
|
|
94
|
-
retriable: false,
|
|
95
|
-
}),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
const input = parsed.data;
|
|
99
|
-
let payload;
|
|
100
|
-
try {
|
|
101
|
-
payload = netPay(input);
|
|
102
|
-
}
|
|
103
|
-
catch (err) {
|
|
104
|
-
return {
|
|
105
|
-
ok: false,
|
|
106
|
-
error: makeError({
|
|
107
|
-
code: "INTERNAL",
|
|
108
|
-
message: "Engine error computing paycheck net pay.",
|
|
109
|
-
retriable: false,
|
|
110
|
-
}),
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
if (!Number.isFinite(payload.netPay) ||
|
|
114
|
-
!Number.isFinite(payload.federalTax) ||
|
|
115
|
-
!Number.isFinite(payload.ficaTax)) {
|
|
116
|
-
return {
|
|
117
|
-
ok: false,
|
|
118
|
-
error: makeError({
|
|
119
|
-
code: "INTERNAL",
|
|
120
|
-
message: "Paycheck engine produced a non-finite result.",
|
|
121
|
-
retriable: false,
|
|
122
|
-
}),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
ok: true,
|
|
127
|
-
value: makeResult({
|
|
128
|
-
result: payload,
|
|
129
|
-
methodology: METHODOLOGY,
|
|
130
|
-
engineVersion: ENGINE_VERSION,
|
|
131
|
-
disclaimer: YMYL_DISCLAIMER,
|
|
132
|
-
}),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=paycheck.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paycheck.js","sourceRoot":"","sources":["../../src/tools/paycheck.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP tool wrapper for `dc.calculator.retirement401k.projection`.
|
|
3
|
-
*
|
|
4
|
-
* Per ADR-0039 § 1: tool name is locked.
|
|
5
|
-
* Per ADR-0039 § 2: Zod input schema with bounds from shared/bounds.ts.
|
|
6
|
-
* Per ADR-0039 § 3: returns ToolResult<Retirement401kProjectionResult>.
|
|
7
|
-
* Per ADR-0039 § 4: failures funnel through ToolError; tools never throw.
|
|
8
|
-
*/
|
|
9
|
-
import { z } from "zod";
|
|
10
|
-
import { type Retirement401kProjectionResult } from "../engines/retirement401k.js";
|
|
11
|
-
import { type ToolResult, type ToolError } from "../envelope.js";
|
|
12
|
-
/** Locked tool name per ADR-0039 § 1 (corrected v0.2.0 per ADR-0041 D2). */
|
|
13
|
-
export declare const TOOL_NAME = "dc.calculator.retirement401k.projection";
|
|
14
|
-
/**
|
|
15
|
-
* Zod input schema. Bounds come from shared/bounds.ts so engine + schema cannot drift.
|
|
16
|
-
*/
|
|
17
|
-
export declare const Retirement401kProjectionInputSchema: z.ZodEffects<z.ZodObject<{
|
|
18
|
-
currentBalance: z.ZodNumber;
|
|
19
|
-
annualSalary: z.ZodNumber;
|
|
20
|
-
contributionPercent: z.ZodNumber;
|
|
21
|
-
employerMatchPercent: z.ZodNumber;
|
|
22
|
-
employerMatchLimitPercent: z.ZodNumber;
|
|
23
|
-
annualSalaryGrowthPercent: z.ZodNumber;
|
|
24
|
-
annualReturnPercent: z.ZodNumber;
|
|
25
|
-
currentAge: z.ZodNumber;
|
|
26
|
-
retirementAge: z.ZodNumber;
|
|
27
|
-
catchUpEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
28
|
-
}, "strip", z.ZodTypeAny, {
|
|
29
|
-
currentBalance: number;
|
|
30
|
-
annualSalary: number;
|
|
31
|
-
contributionPercent: number;
|
|
32
|
-
employerMatchPercent: number;
|
|
33
|
-
employerMatchLimitPercent: number;
|
|
34
|
-
annualSalaryGrowthPercent: number;
|
|
35
|
-
annualReturnPercent: number;
|
|
36
|
-
currentAge: number;
|
|
37
|
-
retirementAge: number;
|
|
38
|
-
catchUpEnabled?: boolean | undefined;
|
|
39
|
-
}, {
|
|
40
|
-
currentBalance: number;
|
|
41
|
-
annualSalary: number;
|
|
42
|
-
contributionPercent: number;
|
|
43
|
-
employerMatchPercent: number;
|
|
44
|
-
employerMatchLimitPercent: number;
|
|
45
|
-
annualSalaryGrowthPercent: number;
|
|
46
|
-
annualReturnPercent: number;
|
|
47
|
-
currentAge: number;
|
|
48
|
-
retirementAge: number;
|
|
49
|
-
catchUpEnabled?: boolean | undefined;
|
|
50
|
-
}>, {
|
|
51
|
-
currentBalance: number;
|
|
52
|
-
annualSalary: number;
|
|
53
|
-
contributionPercent: number;
|
|
54
|
-
employerMatchPercent: number;
|
|
55
|
-
employerMatchLimitPercent: number;
|
|
56
|
-
annualSalaryGrowthPercent: number;
|
|
57
|
-
annualReturnPercent: number;
|
|
58
|
-
currentAge: number;
|
|
59
|
-
retirementAge: number;
|
|
60
|
-
catchUpEnabled?: boolean | undefined;
|
|
61
|
-
}, {
|
|
62
|
-
currentBalance: number;
|
|
63
|
-
annualSalary: number;
|
|
64
|
-
contributionPercent: number;
|
|
65
|
-
employerMatchPercent: number;
|
|
66
|
-
employerMatchLimitPercent: number;
|
|
67
|
-
annualSalaryGrowthPercent: number;
|
|
68
|
-
annualReturnPercent: number;
|
|
69
|
-
currentAge: number;
|
|
70
|
-
retirementAge: number;
|
|
71
|
-
catchUpEnabled?: boolean | undefined;
|
|
72
|
-
}>;
|
|
73
|
-
export type Retirement401kProjectionToolInput = z.infer<typeof Retirement401kProjectionInputSchema>;
|
|
74
|
-
export declare const TOOL_DESCRIPTION: string;
|
|
75
|
-
/**
|
|
76
|
-
* Execute the tool. Validation + engine call wrapped in the standard envelope.
|
|
77
|
-
*/
|
|
78
|
-
export declare function execute(rawInput: unknown): {
|
|
79
|
-
ok: true;
|
|
80
|
-
value: ToolResult<Retirement401kProjectionResult>;
|
|
81
|
-
} | {
|
|
82
|
-
ok: false;
|
|
83
|
-
error: ToolError;
|
|
84
|
-
};
|
|
85
|
-
//# sourceMappingURL=retirement401k.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"retirement401k.d.ts","sourceRoot":"","sources":["../../src/tools/retirement401k.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,8BAA8B,EACpC,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,4EAA4E;AAC5E,eAAO,MAAM,SAAS,4CAA4C,CAAC;AAOnE;;GAEG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmE5C,CAAC;AAEL,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CACrD,OAAO,mCAAmC,CAC3C,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAKI,CAAC;AAElC;;GAEG;AACH,wBAAgB,OAAO,CACrB,QAAQ,EAAE,OAAO,GAEf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,8BAA8B,CAAC,CAAA;CAAE,GAC/D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAwDlC"}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP tool wrapper for `dc.calculator.retirement401k.projection`.
|
|
3
|
-
*
|
|
4
|
-
* Per ADR-0039 § 1: tool name is locked.
|
|
5
|
-
* Per ADR-0039 § 2: Zod input schema with bounds from shared/bounds.ts.
|
|
6
|
-
* Per ADR-0039 § 3: returns ToolResult<Retirement401kProjectionResult>.
|
|
7
|
-
* Per ADR-0039 § 4: failures funnel through ToolError; tools never throw.
|
|
8
|
-
*/
|
|
9
|
-
import { z } from "zod";
|
|
10
|
-
import { projection, ENGINE_VERSION, } from "../engines/retirement401k.js";
|
|
11
|
-
import { RETIREMENT_401K_BOUNDS } from "../shared/bounds.js";
|
|
12
|
-
import { YMYL_DISCLAIMER } from "../disclaimers/ymyl.js";
|
|
13
|
-
import { makeResult, makeError, } from "../envelope.js";
|
|
14
|
-
/** Locked tool name per ADR-0039 § 1 (corrected v0.2.0 per ADR-0041 D2). */
|
|
15
|
-
export const TOOL_NAME = "dc.calculator.retirement401k.projection";
|
|
16
|
-
const METHODOLOGY = {
|
|
17
|
-
url: "https://www.digitalcalculator.info/401k-retirement-calculator/methodology/",
|
|
18
|
-
version: "2026-05-09",
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Zod input schema. Bounds come from shared/bounds.ts so engine + schema cannot drift.
|
|
22
|
-
*/
|
|
23
|
-
export const Retirement401kProjectionInputSchema = z
|
|
24
|
-
.object({
|
|
25
|
-
currentBalance: z
|
|
26
|
-
.number()
|
|
27
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_CURRENT_BALANCE)
|
|
28
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_CURRENT_BALANCE)
|
|
29
|
-
.describe("Current 401(k) balance in USD."),
|
|
30
|
-
annualSalary: z
|
|
31
|
-
.number()
|
|
32
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_ANNUAL_SALARY)
|
|
33
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_ANNUAL_SALARY)
|
|
34
|
-
.describe("Current annual gross salary in USD."),
|
|
35
|
-
contributionPercent: z
|
|
36
|
-
.number()
|
|
37
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_CONTRIBUTION_PERCENT)
|
|
38
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_CONTRIBUTION_PERCENT)
|
|
39
|
-
.describe("Employee contribution as percent of salary (whole-number percent, e.g., 6 for 6%)."),
|
|
40
|
-
employerMatchPercent: z
|
|
41
|
-
.number()
|
|
42
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_EMPLOYER_MATCH_PERCENT)
|
|
43
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_EMPLOYER_MATCH_PERCENT)
|
|
44
|
-
.describe("Employer match percent (e.g., 50 means $0.50 employer match per $1 employee contribution)."),
|
|
45
|
-
employerMatchLimitPercent: z
|
|
46
|
-
.number()
|
|
47
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_EMPLOYER_MATCH_LIMIT_PERCENT)
|
|
48
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_EMPLOYER_MATCH_LIMIT_PERCENT)
|
|
49
|
-
.describe("Cap on employee contribution percent the employer matches (e.g., 6 means up to 6% of salary)."),
|
|
50
|
-
annualSalaryGrowthPercent: z
|
|
51
|
-
.number()
|
|
52
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_SALARY_GROWTH_PERCENT)
|
|
53
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_SALARY_GROWTH_PERCENT)
|
|
54
|
-
.describe("Annual salary growth percent (e.g., 3 for 3%/yr; 0 mirrors flat-salary site engine)."),
|
|
55
|
-
annualReturnPercent: z
|
|
56
|
-
.number()
|
|
57
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_RETURN_PERCENT)
|
|
58
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_RETURN_PERCENT)
|
|
59
|
-
.describe("Annual investment return percent (e.g., 7 for 7%/yr)."),
|
|
60
|
-
currentAge: z
|
|
61
|
-
.number()
|
|
62
|
-
.int()
|
|
63
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_AGE)
|
|
64
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_AGE)
|
|
65
|
-
.describe("Current age in whole years."),
|
|
66
|
-
retirementAge: z
|
|
67
|
-
.number()
|
|
68
|
-
.int()
|
|
69
|
-
.min(RETIREMENT_401K_BOUNDS.MIN_AGE)
|
|
70
|
-
.max(RETIREMENT_401K_BOUNDS.MAX_AGE)
|
|
71
|
-
.describe("Target retirement age in whole years (must be > currentAge)."),
|
|
72
|
-
catchUpEnabled: z
|
|
73
|
-
.boolean()
|
|
74
|
-
.optional()
|
|
75
|
-
.describe("Whether to apply IRS catch-up contributions when age is in the 50+ window. Defaults to true."),
|
|
76
|
-
})
|
|
77
|
-
.refine((v) => v.retirementAge > v.currentAge, {
|
|
78
|
-
message: "retirementAge must be greater than currentAge",
|
|
79
|
-
path: ["retirementAge"],
|
|
80
|
-
});
|
|
81
|
-
export const TOOL_DESCRIPTION = "Project a 401(k) account balance through retirement, including employee + " +
|
|
82
|
-
"employer contributions and compounded growth. Honors IRS 2026 contribution " +
|
|
83
|
-
"limits (incl. catch-up for ages 50+ and SECURE 2.0 super-catch-up for ages " +
|
|
84
|
-
"60-63). Returns { futureBalance, totalContributions, employerContribTotal, " +
|
|
85
|
-
"growthEarned, yearByYear[] }.";
|
|
86
|
-
/**
|
|
87
|
-
* Execute the tool. Validation + engine call wrapped in the standard envelope.
|
|
88
|
-
*/
|
|
89
|
-
export function execute(rawInput) {
|
|
90
|
-
const parsed = Retirement401kProjectionInputSchema.safeParse(rawInput);
|
|
91
|
-
if (!parsed.success) {
|
|
92
|
-
const first = parsed.error.issues[0];
|
|
93
|
-
return {
|
|
94
|
-
ok: false,
|
|
95
|
-
error: makeError({
|
|
96
|
-
code: "INPUT_VALIDATION",
|
|
97
|
-
message: first?.message ?? "Invalid input.",
|
|
98
|
-
field: first?.path.join(".") || undefined,
|
|
99
|
-
retriable: false,
|
|
100
|
-
}),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
const input = parsed.data;
|
|
104
|
-
let payload;
|
|
105
|
-
try {
|
|
106
|
-
payload = projection(input);
|
|
107
|
-
}
|
|
108
|
-
catch (err) {
|
|
109
|
-
return {
|
|
110
|
-
ok: false,
|
|
111
|
-
error: makeError({
|
|
112
|
-
code: "INTERNAL",
|
|
113
|
-
message: "Engine error computing 401(k) projection.",
|
|
114
|
-
retriable: false,
|
|
115
|
-
}),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (!Number.isFinite(payload.futureBalance) ||
|
|
119
|
-
!Number.isFinite(payload.totalContributions) ||
|
|
120
|
-
!Number.isFinite(payload.employerContribTotal) ||
|
|
121
|
-
!Number.isFinite(payload.growthEarned)) {
|
|
122
|
-
return {
|
|
123
|
-
ok: false,
|
|
124
|
-
error: makeError({
|
|
125
|
-
code: "INTERNAL",
|
|
126
|
-
message: "401(k) 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=retirement401k.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"retirement401k.js","sourceRoot":"","sources":["../../src/tools/retirement401k.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/rmd.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
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
|
package/dist/tools/rmd.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/tools/rmd.js
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
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
|
package/dist/tools/rmd.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rmd.js","sourceRoot":"","sources":["../../src/tools/rmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,66 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|