Senaro Personal Finance
Server Details
Deterministic money math. Same inputs, same answer. Every number cites the rule it implements.
- Status
- Healthy
- Last Tested
- Transport
- Streamable HTTP
- URL
TDQS
Scored across 18 tools
Most tools have clearly distinct purposes (e.g., analyze_pmi_removal vs compare_mortgage_terms vs refi_breakeven). A few could be confused: calculate_loan_payoff and compound_interest overlap for simple savings cases, and optimize_401k_match vs payoff_vs_invest have different angles but may be mixed up in retirement scenarios. The detailed descriptions largely mitigate these overlaps.
All tool names consistently follow a snake_case verb_noun pattern: analyze_*, calculate_*, compare_*, optimize_*, payoff_*, refi_*, rent_*, list_*, server_info. No deviations, highly predictable.
18 tools is on the high side for a personal finance calculator set, but each tool covers a distinct calculation or comparison. Some peripheral tools like list_defaults and server_info could arguably be consolidated into metadata, making it slightly heavy.
The set covers a broad range of personal finance calculations: debt payoff, mortgage analysis, retirement, budgeting (emergency fund, runway), and decision comparisons. Missing pieces like a dedicated savings goal tracker or a full net worth projection are minor gaps that agents can work around with available tools.
Available Tools
18 toolsanalyze_cash_advanceCash Advance AnalyzerARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Deep analysis of a single card's cash advance showing payment allocation, CA interest cost, CA payoff months, and whether the CA is growing. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: purchase_balance: decimal >= 0 (REQUIRED) purchase_apr_pct: decimal 0-100 as percentage (REQUIRED) cash_advance_balance: decimal > 0 (REQUIRED) cash_advance_apr_pct: decimal > 0, <= 100 (REQUIRED). A cash advance always accrues interest immediately, so 0 is not a valid rate. total_monthly_payment: decimal > 0, at most 2 decimal places (REQUIRED) minimum_payment: decimal >= 0, at most 2 decimal places (optional, default auto-calculate). When supplied, this DOES bind: the per-month mandatory payment is min(max(the issuer minimum recomputed from the balance, minimum_payment), the remaining balance, total_monthly_payment). This differs from calculate_cc_payoff's default dynamic path, where the identically-named minimum_payment is parsed and validated but never applied unless fixed_payments = true: the two tools do not share behavior for this parameter, only its name. cash_advance_fee_pct: decimal >= 0 (optional, default 0). e.g. 5 for 5% cash_advance_fee_min: decimal >= 0 (optional, default 0). e.g. 10 for $10 chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the description is free to add genuinely new context: that output includes `chart_hints` rendering directives and that the `senaro-charts` MCP server renders them locally over stdio only. That cross-server dependency and the calculation-not-advice caveat are real additions beyond the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences: disclaimer first, then what the analysis produces, then the return-side chart_hints note and its server dependency. No filler, and the most safety-relevant sentence is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so — it enumerates the analysis outputs and the chart_hints field. The only gap is any guidance on input prerequisites or how this compares to calculate_cc_payoff, which would complete the picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the nested toolArguments object documents every field, including the notable distinction that minimum_payment binds here but not in calculate_cc_payoff. The description adds nothing beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Deep analysis of a single card's cash advance' with named outputs (payment allocation, CA interest cost, CA payoff months, growth). The 'single card' / 'CA' scoping does implicitly distinguish it from broader debt tools like calculate_cc_payoff, though it never names a sibling directly in the description.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only guidance is 'Calculation, not advice. Verify with a professional before acting,' which is a liability disclaimer rather than a when-to-use condition. It gives no criteria for choosing this tool over calculate_cc_payoff or compare_strategies, even though the schema itself flags a behavioral divergence from calculate_cc_payoff.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
analyze_pmi_removalPMI Removal AnalysisARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Compute every standard PMI-removal pathway (HPA automatic at 78% LTV, HPA borrower-requested at 80% LTV, optional re-appraisal at a simplified 75% of current market value; the actual Fannie Mae ceiling is seasoning- and property-type-dependent, 75% for a one-unit home seasoned two to five years, 80% for five-plus, and 70% for investment and two- to four-unit properties), current monthly PMI cost, total PMI dollars between now and automatic removal, and the effective annual return of paying the gap-to-80% (of the original value) as a lump sum today. Supplying original_loan_term_months and loan_age_months also applies the 12 U.S.C. 4902(c) statutory final-termination midpoint, which bounds automatic removal at the earlier of the 78% schedule and that midpoint where HPA applies and the borrower is current. Pairs with compare_mortgage_terms for the broader refinance / pay-extra / drop-PMI decision.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: current_balance: decimal > 0 (REQUIRED). Today's loan balance. original_purchase_price: decimal > 0 (REQUIRED). What you paid for the home (the purchase-price side of the HPA basis; when a closing appraisal is lower, see original_appraised_value). current_home_value: decimal > 0 (optional). When provided AND greater than the HPA original value (the lesser of purchase price and any closing appraisal), the response also computes the re-appraisal pathway (some lenders allow PMI removal based on current market value with a fresh appraisal). original_appraised_value: decimal > 0 (optional). The home's appraised value at closing. HPA sets the PMI trigger basis to the LESSER of purchase price and this appraisal (12 U.S.C. 4901); provide it when your closing appraisal came in below the purchase price. annual_pmi_rate_pct: decimal 0-5 (optional, default 0.5). Annual PMI as a percentage of the current loan balance. Typical conventional-loan PMI ranges from 0.3% to 1.5%. annual_rate_pct: decimal 0-20 (REQUIRED). Mortgage APR. monthly_payment: decimal > 0 (REQUIRED). Current P&I monthly payment (excluding tax/insurance/PMI). extra_monthly_payment: decimal >= 0 (optional, default 0). Extra principal each month beyond the regular payment. original_loan_term_months: integer 1-480 (optional). The loan's original term in months. Supplied together with loan_age_months, this computes the 12 U.S.C. 4902(c) statutory final-termination midpoint (12 U.S.C. 4901(7)) and bounds automatic_removal at the earlier of it and the 78% schedule date, where HPA applies and the borrower is current. Supplying either one without the other is rejected; both are required together. loan_age_months: integer 0-480 (optional). Months elapsed since origination. Cannot exceed original_loan_term_months when both are supplied. Supplying either one without the other is rejected; both are required together. See original_loan_term_months. Scope: conventional mortgages only. FHA loans use MIP (Mortgage Insurance Premium) with different rules. Typically MIP runs for the life of the loan when down payment < 10%. This tool does NOT model MIP. chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds genuinely useful behavioral context beyond that: the 'calculation, not advice' disclaimer, the rule that supplying original_loan_term_months or loan_age_months alone is rejected, and that the statutory midpoint only bounds removal where HPA applies and the borrower is current.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The critical disclaimer is front-loaded, which is good, but the body is a single dense paragraph with heavily nested parentheticals (the Fannie Mae ceiling breakdown is buried mid-sentence). Every fact earns its place, yet the structure makes it harder to scan than it needs to be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex financial calculation with no output schema, the description enumerates what the response computes and the conditions that unlock extra outputs (re-appraisal when current value exceeds the HPA basis; statutory midpoint when term and age are supplied). It is nearly self-sufficient, with only minor gaps in how results are presented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter including defaults, ranges, and the paired-parameter constraint. The description restates some of this (the term/age pairing and the statutory midpoint) but adds no syntax or format detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource – it computes PMI-removal pathways (HPA automatic at 78% LTV, borrower-requested at 80%, re-appraisal at 75%), monthly PMI cost, total PMI dollars, and effective return of paying the gap. It also names a sibling (compare_mortgage_terms) for the broader decision, so an agent can distinguish it without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit scope exclusion: conventional mortgages only, FHA/MIP is not modeled and runs for life when down payment < 10%. It also routes the agent to compare_mortgage_terms for the broader refinance/pay-extra/drop-PMI decision. No explicit when-not-to-use for the PMI pathways themselves, but context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_cc_payoffCredit Card Payoff CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Calculate credit card payoff timeline with month-by-month amortization. Supports dual APR segments (purchase + cash advance), two strategies (avalanche, snowball), fixed/dynamic payment modes, and an optional schedule of one-time windfalls (tax refund, bonus, inheritance) applied at specific months. Returns debt-free date, total interest, per-card payoff order, first_month_interest_ratio_frac (the first month's interest/payment fraction) and lifetime_interest_ratio_frac (whole-projection total_interest/total_paid fraction), domain warnings emitted as warnings[].type (DEATH_SPIRAL, CA_TRAP, MIN_PAYMENT_TRAP, DAY_ZERO_COST, DEBT_GROWING, PROMO_CLIFF, PREDATORY_RATE, SPEND_EXCEEDS_PAYDOWN, PLAN_TERM_ELAPSED_WITH_BALANCE), separately validation disclosures emitted as warnings[].code (MINIMUM_PAYMENT_NOT_BINDING on the default dynamic-budget path, MINIMUM_PAYMENT_NOT_BINDING_IN_BASELINE when fixed_payments = true; these two shapes coexist in the same warnings[] array but are distinguishable by which keys each entry carries), and when a plan exists (extra_monthly_payment > 0, windfalls present, or fixed_payments = true) a min_payments_only baseline block with interest_saved_vs_min_payments and months_saved_vs_min_payments quantifying the interest and time difference versus paying minimums only. When windfalls are also present the response additionally gains a baseline vs with_windfalls savings block. The response echoes strategy (canonical lowercase 'avalanche' | 'snowball', the strategy the plan was actually simulated under) at the top level. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only. Use output: 'summary' (default) for a compact response or 'inline' for the full payload. output: 'capture' writes the full payload to a file on this server's local disk and returns a capture_ref URI for chart rendering; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport, where a capture_ref would be a dead link for a remote caller. Top-level entered_starting_balance echoes the caller's supplied balances by segment type (total, purchase, cash_advance, balance_transfer, promotional, installment_plan), before any fee, recurring spend, or interest posts; total is the sum of the other five. Top-level total_purchase_segment_fees_paid reports the portion of card fees (plan_fees_monthly plus annual_fee accruals) charged to the purchase segment across the projection, also present on every monthly_totals[] and analysis.buckets[] row. These month counts are each a {status, value, explanation} object rather than a bare month count: months_to_payoff, min_payments_only.months, minimums_only_baseline.months, and, when windfalls are supplied, baseline.months and with_windfalls.months. status is "defined" with an integer value when that plan reaches a zero balance, and "none" with value null when it does not, in which case explanation says why. The per-card payoff month inside card_payoff_order[] does not use the {status, value, explanation} object. It is still a bare integer.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: cards (REQUIRED array, max 20): - name: string (optional, auto-generated if omitted) - purchase_balance: decimal >= 0 (REQUIRED unless segments[] is supplied) - purchase_apr_pct: decimal 0-100 as percentage, e.g. 24.99 not 0.2499 (REQUIRED unless segments[] is supplied) - cash_advance_balance: decimal >= 0 (optional, default 0) - cash_advance_apr_pct: decimal > 0, <= 100 (required only if cash_advance_balance > 0) - minimum_payment: decimal >= 0 (optional, omit or set 0 to auto-calculate). Binds ONLY when fixed_payments = true: the card is then locked at max(minimum_payment, that card's issuer minimum computed at month 1), and that locked amount is paid every month. On the DEFAULT path (fixed_payments = false), this value is NOT used: the plan recomputes each card's issuer minimum from its current balance every month, so the monthly budget is the sum of those recomputed minimums plus extra_monthly_payment. To hold a stated payment instead, set fixed_payments = true. - annual_fee: decimal >= 0 (optional, default 0). Charged at month 1 and every 12th month thereafter while the card has a balance. - plan_fees_monthly: decimal >= 0 (optional, default 0). Charged every month while the card has a balance (e.g. pay-over-time plan fee). - segments: array (OPTIONAL; when present, supersedes purchase_balance / cash_advance_balance). Max 100 segments total across all cards in the request. Per-card, per-type caps: 1 purchase, 1 cash_advance, 5 balance_transfer, 1 promotional, 10 installment_plan. Each item: - type: 'purchase' | 'cash_advance' | 'balance_transfer' | 'promotional' | 'installment_plan' (REQUIRED). Use 'promotional' for a balance whose 0% (or below-market) intro APR reverts to a standard rate later and is NOT a balance transfer, e.g. a 0% intro purchase APR; it validates and reverts identically to balance_transfer. - balance: decimal >= 0 (REQUIRED) - apr_pct: decimal 0-100 (REQUIRED for purchase / cash_advance / balance_transfer / promotional; must be 0 for installment_plan; for cash_advance, must be > 0 when balance > 0, since cash advances have no promotional 0% product) - revert_apr_pct: decimal 0-100 (REQUIRED for balance_transfer / promotional; APR after promo expires; not applicable to purchase / cash_advance (silently ignored); REJECTED on installment_plan (FIELD_NOT_ALLOWED_HERE) since installment_plan has no post-term-rate concept: an expired plan's residual keeps its existing rate) - promo_expires_month: int >= 1 (REQUIRED for balance_transfer / promotional; month at which apr_pct flips to revert_apr_pct) - monthly_fee: decimal >= 0 (REQUIRED for installment_plan; fixed fee charged each month while the plan's term is active; stops accruing once the term elapses) - plan_payment_due: decimal > 0 (REQUIRED for installment_plan; locked monthly payment, principal + monthly_fee; keeps being charged every month even after the term elapses, until the balance clears) - remaining_payments: int >= 0 (optional, installment_plan only). 0 means the plan's stated term has ALREADY ended: this is the correct, valid way to model an already-expired plan carrying a residual balance, and it is accepted regardless of balance (an expired plan's residual is a real state, not a data-entry error). When remaining_payments >= 1, it must be consistent with balance / plan_payment_due / monthly_fee: net = plan_payment_due - monthly_fee must be positive, or the plan could never amortize (rejected as INSTALLMENT_PLAN_NET_NOT_POSITIVE); balance must be <= remaining_payments * net (the plan must be able to clear within its stated term) and balance must be > (remaining_payments - 1) * net (the term must not be overstated), either violation rejected as INSTALLMENT_PLAN_TERM_MISMATCH. If a plan has already ended, enter remaining_payments as 0 rather than a positive count that cannot clear the balance. An expired plan (remaining_payments reaches 0 with a positive balance still owed, whether supplied that way or reached by simulation) does not freeze and is never repriced: it keeps receiving its locked plan_payment_due every month at its existing rate until the balance clears. One aggregated PLAN_TERM_ELAPSED_WITH_BALANCE warning fires per card (never one per segment), naming every affected plan on that card and its residual, plus the card total. - merchant_name: string (optional, installment_plan only) - min_payment_order: int >= 1 (optional; the minimum first pays any installment_plan segment's locked plan_payment_due in full, structurally, regardless of APR or this value; among the remaining (revolving) segments it then pays down the lowest-current-APR segment first, issuer practice, not statutorily regulated; this value only breaks a tie between segments that share both the exact same current APR AND the same installment-plan status, in which case the higher-balance segment wins; two segments on the same card sharing a value emit a DUPLICATE_PAYMENT_ORDER warning; a supplied value with no APR-tie partner to ever decide emits PAYMENT_ORDER_NOT_DECISIVE) - extra_payment_order: int >= 0 (optional; 0 = SKIP -- this segment never receives extra payment, the default for installment_plan; a positive value only breaks a tie between segments that share the exact same current APR, since the Credit CARD Act (TILA §164(b), 15 U.S.C. §1666c(b)) / 12 CFR §1026.53(a) always pays the highest-current-APR segment first regardless of this value; two segments on the same card sharing a positive value emit a DUPLICATE_PAYMENT_ORDER warning, duplicate 0s never warn; a supplied value with no APR-tie partner to ever decide emits PAYMENT_ORDER_NOT_DECISIVE -- this hits installment_plan hardest, since it is pinned at 0% APR (apr_pct is not read for this segment type), so a positive override on it can win the tie-break only against another segment also at exactly 0%; whenever any positive-APR segment shares the card, the plan stays ELIGIBLE and sorts LAST behind every positive-APR segment, receiving extra only once those higher-APR balances clear) Response gains per-card interest_saving_balance (sum of APR-bearing segments) and installment_balance_locked (sum of installment_plan segments) when segments[] is supplied. extra_monthly_payment: decimal >= 0 (optional, default 0) strategy: 'avalanche' | 'snowball' (optional, default 'avalanche') fixed_payments: bool (optional, default false). When true, each card's payment is locked at max(cards[].minimum_payment, that card's issuer minimum computed at month 1), and the total monthly budget (sum of those locked amounts plus extra_monthly_payment) is held constant for the whole payoff, so once a card is paid off its freed-up payment rolls forward onto the remaining cards. This is the ONLY mode in which cards[].minimum_payment affects the result; see the minimum_payment field above for what happens on the default path. apply_rate_cap: bool (optional, default false) full_schedule: bool (optional, default false). The per-card monthly_schedule is capped at 1000 rows total (cards x months); on a long multi-card payoff later months are omitted from monthly_schedule. The portfolio-level monthly_totals series is always complete, so read monthly_totals for the full timeline. per_segment: bool (optional, default true) include_card_timeline: bool (optional, default false) windfalls: array of one-time principal payments (optional, default empty, max 12 items). Each item: - month: int >= 0 (REQUIRED). 0 means applied before month 1's interest (same as reducing starting principal). N >= 1 applies at the END of calendar month N, so month N+1's interest is calculated on the post-windfall balance. - amount: decimal > 0 (REQUIRED). - label: string (optional). e.g. 'Tax refund', 'Year-end bonus'. When any windfalls are present the response gains: baseline, with_windfalls, months_saved_vs_baseline, interest_saved_vs_baseline, windfalls_applied[], windfalls_unused[]. Empty windfalls yields the same response shape as before. Min-payments-only baseline (v1.7, gap #593): when extra_monthly_payment > 0, windfalls are present, or fixed_payments = true, the response also gains: - min_payments_only: { months, interest_cost, amount_paid, payoff_date } - what happens paying minimums only - interest_saved_vs_min_payments: decimal - total interest saved vs paying minimums only (always >= 0) - months_saved_vs_min_payments: int - months saved vs paying minimums only (when minimums never pay off, capped at MaxMonths minus with-plan months) Trivial minimums-only calls (no extra, no windfalls, not fixed) keep their current response shape unchanged. Minimums-only baseline series (v1.9, B2; bucketed v2.5, #1108): under the same plan-exists condition as min_payments_only above, the response also gains minimums_only_baseline: { months, granularity, buckets[], payoff_date } - the minimums-only balance trajectory bucketed through the same shared aggregator as analysis.buckets[] (same bucket row shape: bucket_index, label, plus the 17 money fields), with granularity auto-selected from THIS series' own term, the same standard rule analysis.granularity itself uses. minimums_only_baseline.granularity is NOT guaranteed to equal analysis.granularity: each series auto-selects independently from its own term, so read each series' own granularity rather than assuming they match. Equal bucket-array length is NOT a valid signal that the two granularities match either: a 24-month primary run (monthly, 24 buckets) and a 24-year minimums-only baseline (yearly, 24 buckets) land on the SAME buckets[].length with DIFFERENT granularities. granularity is the only valid mismatch signal; length is not. Computed from the SAME gated simulation as min_payments_only, so months/payoff_date agree between the two blocks. Absent under the identical trivial-call condition as min_payments_only. chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. output: 'summary' | 'inline' | 'capture' (optional, default 'summary') 'capture' is available on the local stdio transport only; the hosted HTTP transport rejects it with a structured error naming 'summary' and 'inline' as the valid alternatives. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, so the bar is lower. The description adds real behavioral context: the transport-specific rejection of 'capture' on HTTP, the significance of {status, value, explanation} objects, the 1000-row full_schedule cap, and the coexistence of two warning shapes. It is verbose but informative rather than contradictory.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a wall of dense prose packing warning codes, ratio field names, and margin enumeration into continuous sentences. Front-loading is reasonable, but the sheer length and low signal-to-token ratio make it hard to scan; much of the response-shape detail belongs in an output-schema or structured doc rather than prose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and a single nested argument envelope, the description goes a long way to describing the return shape: payoff date, interest totals, warning arrays, baseline blocks, chart_hints, and output-mode behavior. The inclusion of all nine warning types plus validation codes is thorough, though scattered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents the single toolArguments envelope and all nested fields in depth. The description adds value on warning-shape coexistence and baseline blocks, but does not introduce parameter semantics beyond what the schema provides, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Calculate credit card payoff timeline with month-by-month amortization') and explicitly enumerates the distinguishing capabilities (dual APR segments, avalanche/snowball, fixed/dynamic payments, windfalls). An agent can immediately separate this from siblings like calculate_loan_payoff or compare_strategies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the tool's scope ('Calculation, not advice') and names the companion server senaro-charts for rendering, plus the transport-specific rules for 'capture'. However it does not explicitly state when to prefer this over calculate_loan_payoff or compare_strategies, so sibling routing is left implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_debt_to_incomeDebt-to-Income CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Calculate your debt-to-income ratio and check qualification for conventional, FHA, VA, and USDA mortgage programs. Accepts existing debts and an optional proposed new debt or home price. Returns current DTI, front-end and back-end ratios with proposed housing, maximum affordable home price, and what-if scenarios showing the resulting DTI and which programs would then qualify if a given debt were paid off, plus income-increase and home-price-reduction variants. Includes the 10-month rule (Fannie Mae) for debts near payoff. qualification..qualification_status is a tri-state verdict ('qualifies' | 'underwriting_dependent' | 'ineligible'): 'underwriting_dependent' means the manual-underwriting baseline is exceeded but further underwriting may still approve it, an automated-underwriting system for conventional and FHA, either automated or manual underwriting for USDA, or a supervisory underwriter's written justification under 38 CFR 36.4340(c)(2) for VA (never an automated decision), so qualification..qualifies=false does NOT by itself mean the borrower is blocked. Read qualification_status, not the bare qualifies boolean, for the real answer; qualification..note explains the specific underwriting or hard-cap context, naming which mechanism applies. VA's back-end overage alone never returns 'ineligible' either (38 CFR 36.4340(c)(2)/(c)(3) both contemplate approval above 41%), and conventional is now the only program that ever returns 'ineligible', since FHA, VA and USDA are each disclosure-only above their baselines.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: gross_monthly_income: decimal > 0 (REQUIRED; OR provide annual_income instead) annual_income: decimal > 0 (alternative to gross_monthly_income; divided by 12) additional_income: decimal >= 0 (optional, default 0; side income, rental income, bonuses. Monthly.) existing_debts: array of debt objects (optional, can be empty): - name: string (optional label, e.g. 'Car Loan') - type: 'auto' | 'student' | 'credit_card' | 'personal' | 'mortgage' | 'heloc' | 'child_support' | 'other' - monthly_payment: decimal > 0 (REQUIRED per debt) - balance: decimal (optional; for payoff cost analysis in what-if scenarios) - apr_pct: decimal 0-100 as PERCENTAGE (optional) - months_remaining: int (optional; used for 10-month rule exclusion) proposed_debt: object (optional; OR use proposed_home_price instead): - name: string (optional) - type: 'auto' | 'student' | 'credit_card' | 'personal' | 'mortgage' | 'heloc' | 'child_support' | 'other' (optional, default 'mortgage') - monthly_payment: decimal > 0 (REQUIRED) - includes_tax_insurance: bool (optional, default true; if false and type is mortgage, warns that lenders use PITI) proposed_home_price: decimal > 0 (optional; auto-calculates full PITI. Cannot combine with proposed_debt.) proposed_down_payment_pct: decimal 0-99.9 as PERCENTAGE (optional, default 20) proposed_rate_pct: decimal 0-20 as PERCENTAGE (optional, default 7.0 with warning) proposed_term_years: int 1-40 (optional, default 30) property_tax_annual: decimal >= 0 (optional. For the PITI estimate, uses 0.88% national average if omitted) home_insurance_annual: decimal >= 0 (optional. Uses 0.65% national average if omitted) pmi_monthly: decimal >= 0 (optional. Auto-estimated at 0.5% of loan when LTV > 80%. Feeds the conventional-basis PITI, so it moves with_proposed.front_end_dti, with_proposed.back_end_dti, with_proposed.front_end_breakdown, the conventional qualification row, and what_if.scenarios[].new_front_end_dti / new_back_end_dti. VA carries no PMI, and FHA/USDA always compute their own upfront-plus-annual mortgage insurance instead, at every LTV, never this override) hoa_monthly: decimal >= 0 (optional, default 0) include_what_if: bool (optional, default true; generate scenarios to improve DTI) transaction_purpose: 'purchase' | 'refinance' | 'streamlined_assist' (optional, default 'purchase') Affects USDA only, and only what is disclosed. USDA's 32% PITI and 44% Total Debt figures are purchase-transaction waiver conditions (HB-1-3555 11.3.A.2), disclosed rather than applied as ceilings: Senaro cannot observe how the file is underwritten, so a USDA ratio overage is never 'ineligible' on any transaction purpose. For a refinance, 11.3.B states debt ratios 'are not limited to the maximum purchase debt ratio thresholds', so where the note fires it names both figures and states that neither applies. Streamlined-assist refinances require no debt ratio calculation at all. Conventional, FHA and VA are unaffected. family_size: int 1-20 (optional; must be supplied together with property_state, or neither fires) property_state: two-letter USPS state code, or 'DC'/'PR'/'GU'/'VI'/'AS'/'MP' (optional; must be supplied together with family_size) Together these compute the VA residual income guideline (38 CFR 36.4340(e)) in va_residual_income_guideline: the dollar amount VA's tables require for this family size, region, and loan amount (derived from proposed_home_price; not computable without it), plus the 38 CFR 36.4340(c)(3) review-waiver figure. Computed only for family_size 1-7 and a property_state among the 50 states, DC, or PR (not GU, VI, AS, or MP; 38 CFR 36.4340(e) assigns no region to those four); outside those bounds, or without proposed_home_price, va_residual_income_guideline.status reads 'not_computable' with the reason instead. This block alone is a LOOKUP, not a verdict: it never compares against your actual residual income by itself. monthly_taxes_and_retirement_withholding: decimal >= 0 (optional; your federal, state, and FICA tax withholding, PLUS any amount paid or withheld for retirement, monthly. 38 CFR 36.4340(f)(13) treats these as one class of deduction from gross income.) monthly_maintenance_and_utilities: decimal >= 0 (optional; estimated monthly maintenance and utilities for the proposed property. 38 CFR 36.4340 calls for a realistic estimate of this figure for the property and local utility rates and sets no numeric multiplier itself, but VA underwriting guidance (the Lender's Handbook, Pamphlet 26-7) publishes a per-square-foot multiplier for this same estimate; applying it needs the property's square footage, which this tool does not currently collect, so Senaro has no default to offer here and you supply the aggregate monthly amount instead.) Supplying BOTH of these, together with proposed_home_price and a computable family_size/ property_state above, computes qualification.va.residual_income_comparison: your ACTUAL monthly residual income, its ratio to the va_residual_income_guideline figure, and whether residual_income_meets_review_waiver_margin (residual income at or above 120% of the guideline) is met. The shelter expense used here excludes any PMI (VA loans carry no monthly PMI; 38 CFR 36.4313(e) sets a funding fee instead, commonly financed into the loan -- see va_funding_fee_financed_monthly below). 38 CFR 36.4340(c)(3)'s review-waiver condition is CONJUNCTIVE: it also requires the back-end debt-to-income ratio (qualification.va.your_back_end) to exceed 41%, which this field does not by itself confirm -- check both fields together. Even when both hold, (c)(3) only WAIVES a second-level review requirement; it is not itself an approval. Whether this file is actually approved is an underwriting determination Senaro does not make and no input combination here determines. Missing any one of the needed inputs reads qualification.va.residual_income_comparison.status 'not_computable' with every reason named. va_funding_fee_financed_monthly: decimal >= 0 (optional; the additional monthly payment from financing a VA funding fee into the loan balance, if any. 38 CFR 36.4313(e)'s applicable percentage depends on down payment, prior VA-loan use, and service category, none of which Senaro collects, so there is no default; if omitted while any VA figure that depends on it is produced -- qualification.va.your_back_end and its verdict, any what_if VA ratio, what_if.max_affordable_home.va, or the residual-income comparison above -- a VA_FUNDING_FEE_NOT_MODELED warning discloses that no fee is assumed. The home-price-reduction what_if scenario's hypothetical price is fixed before the fee is considered, so a supplied fee is scaled to that EXACT hypothetical loan size, since 38 CFR 36.4313(e)'s fee is a percentage of loan principal. what_if.max_affordable_home.va is a two-pass approximation instead, so its supplied fee is scaled to an ESTIMATE of the hypothetical loan size, not the exact figure reported; the PMI, tax, and insurance reservation itself is an EXACT closed-form solve, so only this fee-scaling step is approximate. Without proposed_home_price there is no reference loan size to scale from either way, so the raw fee is reserved unscaled instead and a VA_FUNDING_FEE_NOT_SCALED warning discloses it -- mutually exclusive with VA_FUNDING_FEE_NOT_MODELED by construction, since one requires the fee omitted and the other requires it supplied.) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, the description adds substantial behavioral context: it states 'Calculation, not advice,' explains tri-state qualification_status semantics, clarifies that 'underwriting_dependent' and VA/FHA/USDA disclosure-only outcomes are not final denials, and documents regulatory caveats and warning conditions. This goes well beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and core return behavior, but it is extremely long and dense, with legal citations, nested caveats, and repeated edge-case explanations. Much of the detail is relevant because there is no output schema, yet the overall size and parsing burden exceed what is ideal for quick tool selection.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the absence of an output schema, and the 100% input schema coverage, the description is complete enough for an agent to understand return values, tri-state qualification logic, warning behavior, and regulatory limitations. It fully documents the output semantics that structured fields do not cover.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already provides detailed semantics for every input, including nested debt and PITI fields. The description summarizes that it accepts existing debts and an optional proposed new debt or home price, but it does not add meaningful parameter-level detail beyond what the schema already provides, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb-resource pair: 'Calculate your debt-to-income ratio and check qualification for conventional, FHA, VA, and USDA mortgage programs.' It also names the accepted inputs and the detailed return categories, so an agent can distinguish it from generic mortgage calculators like compare_mortgage_terms or refi_breakeven.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the core purpose ('Calculate your debt-to-income ratio...'), and the description notes what it accepts and returns, but it never explicitly says when to choose this tool over siblings or when not to use it. No alternatives such as compare_mortgage_terms or rent_vs_buy are named, so routing guidance is only contextual.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_emergency_fundEmergency Fund CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Size an emergency fund target based on the borrower's monthly essential expenses, job stability, dependents, and income redundancy. Returns a tier breakdown (minimum, target, conservative; the target row is omitted when it equals the 3-month minimum, and the conservative row is omitted when it equals the 12-month ceiling), the gap between current savings and the target, and time-to-target at the supplied monthly savings cadence. Pairs with debt-payoff content for the recurring 'save vs pay debt' question.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: monthly_essential_expenses: decimal > 0 (REQUIRED). Rent/mortgage + utilities + food + insurance + minimum debt payments. NOT discretionary spending. current_savings: decimal >= 0 (optional, default 0). What you have in liquid emergency-accessible savings today. job_stability: 'stable_w2' | 'variable_income' | 'self_employed' | 'between_jobs' (optional, default 'stable_w2'). Drives the target-months multiplier. stable_w2: salaried W-2 with consistent paycheck (+0 months). variable_income: W-2 with commission/bonus/shift-based pay (+1 month). self_employed: 1099 contractor / freelancer / sole proprietor (+3 months). between_jobs: actively job hunting, no current paycheck (+5 months). dependents: int >= 0 (optional, default 0). +1 target month per dependent, capped at +3. has_dual_income: bool (optional, default false). When true, partner income reduces the buffer by 1 month. monthly_savings_capacity: decimal >= 0 (optional, default 0). What you can contribute toward the gap each month. Drives months_to_target. Target months are clamped to [3, 12]: never below the 3-month personal-finance minimum, never above 12 (excess cash is better invested than parked). chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description goes further by disclosing the disclaimer/advice caveat, the exact tier structure with its row-omission rules, the clamping to [3,12] months, and what the gap and time-to-target outputs represent. This is rich behavior beyond what structured fields provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the disclaimer, then the purpose, then the return shape in fluid sentences. Slightly dense and leads with a caveat rather than the action, but every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of describing returns and does so completely – tier breakdown, omission rules, savings gap, and time-to-target. An agent has everything needed to call and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is effectively 100% – the nested toolArguments field fully documents each parameter, enumerates job_stability values, and states the clamping rule. The description adds conceptual framing (tiers, gap, time-to-target) but no syntax or defaults beyond the schema, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (size) and resource (emergency fund target) with the exact inputs that drive it: essential expenses, job stability, dependents, income redundancy. An agent can distinguish this from siblings like calculate_runway or payoff_vs_invest without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides contextual pairing guidance ('pairs with debt-payoff content for the recurring save vs pay debt question') but never states when to use this tool versus alternatives such as calculate_runway or payoff_vs_invest, nor any exclusions. Usage is implied rather than directed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_loan_payoffLoan Payoff CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Standard amortizing loan calculator. Returns monthly payment, total interest, a payoff date (null when the loan does not clear within its term), and a bucketed Analysis suitable for chart rendering. The Analysis includes KPIs, annotations (e.g. crossover month), and summary strings. When extra_monthly_payment is supplied, every computed figure in the response outside with_extra describes this loan without the extra payment, including monthly_payment, payoff_months, total_paid, total_interest, remaining_balance_at_term, payoff_date, months_to_halfway_principal, months_to_interest_flip, and every value under analysis; a warnings[] entry names this. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only. On the local stdio transport, use output: 'capture' when passing the result to a chart tool to avoid filling the LLM context with bucket data; the hosted HTTP transport rejects 'capture' with a structured error, so use 'summary' (default; the full payload is already returned inline) there instead. This tool does not support output: 'inline' on any transport.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: principal: decimal > 0 (REQUIRED) annual_rate_pct: decimal 0-100 as percentage, e.g. 6.5 not 0.065 (REQUIRED) term_months: int > 0 (REQUIRED) loan_type: 'personal' | 'auto' | 'student' | 'mortgage' (optional, default 'personal') extra_monthly_payment: decimal >= 0 (optional, default 0) chart_bucket: 'auto' | 'monthly' | 'quarterly' | 'yearly' | 'biennial' (optional, default 'auto') Controls the time-axis granularity of analysis.buckets[]. 'auto' selects based on term length: term <= 24 months -> monthly; <= 60 -> quarterly; <= 360 -> yearly; > 360 -> biennial. output: 'summary' | 'capture' (optional, default 'summary'). 'inline' is not a valid value for this tool on any transport. 'summary': full payload including analysis.buckets[] returned inline. 'capture': full payload written to ~/.senaro/captures/; capture_ref URI returned; analysis field stripped from wire response. Use when passing to a chart tool. Available on the local stdio transport only; the hosted HTTP transport rejects 'capture' with a structured error naming 'summary' as the only valid alternative. chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it explains that a payoff_date is null when the loan never clears, that with extra_monthly_payment every top-level figure and all analysis values describe the loan WITHOUT the extra payment (with a warnings[] entry noting it), that chart_hints are emitted, and that 'capture' writes to ~/.senaro/captures/ while the hosted transport rejects it. This is unusually rich disclosure for a read-only calculator.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but mostly front-loaded, leading with scope, then return shape, then parameter behavior, then transport rules. It loses a point for redundancy: the 'capture'/'inline' restrictions are restated three times across the description and input schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema available, the description carries the full burden of describing the return payload (KPI/annotation/bucket structure, chart_hints, warnings) and the transport constraints, and it does so completely. An agent has everything needed to call and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds real semantic value the schema does not: the non-obvious behavior of extra_monthly_payment (all figures outside with_extra ignore it) and the transport-specific legality of output values. chart_bucket and chart_title semantics are largely duplicated from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific resource and action ('Standard amortizing loan calculator') and enumerates concrete outputs (monthly payment, total interest, payoff date, bucketed Analysis). It implicitly distinguishes itself from revolving-debt siblings like calculate_cc_payoff by specifying 'amortizing,' but never names an alternative tool outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives strong contextual guidance for the transport-dependent output modes (use 'capture' on local stdio when feeding a chart tool; 'summary' on hosted HTTP) and sets the 'calculation, not advice' expectation. It does not, however, tell the agent when to pick this tool over siblings such as calculate_cc_payoff or compare_mortgage_terms.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_opportunity_costOpportunity Cost CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Calculate the true cost of recurring spending by showing what that money would be worth if invested. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: monthly_spending: decimal, at least 0.01 (REQUIRED). The opportunity cost of spending $0 is degenerate and is rejected. annual_return_pct: decimal 0-100 as percentage, e.g. 8 not 0.08, an EFFECTIVE ANNUAL rate; the monthly compounding step is (1+pct/100)^(1/12)-1 (REQUIRED) years: int > 0 (REQUIRED) label: string (optional). e.g. 'coffee' or 'streaming subscriptions' tax_bracket_pct: decimal 0-100 (optional) chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safe-read profile (readOnlyHint=true, idempotentHint=true, openWorldHint=false), so the safety burden is covered. The description adds genuinely non-obvious behavioral context: the response carries `chart_hints` rendering directives and depends on the `senaro-charts` MCP server rendering locally over stdio. That dependency and output-contract disclosure is real value beyond the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four compact sentences with no redundancy. The lead is a disclaimer rather than the purpose, which slightly delays the front-loaded statement of what the tool does, but otherwise every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description partially compensates by disclosing the `chart_hints` return element and the rendering server dependency. It does not describe the core numeric result, but for a single-argument calculator whose nested schema is fully documented, the coverage is adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the nested `toolArguments` object documents every parameter with types, constraints, and examples (e.g., annual_return_pct as an effective annual rate, monthly compounding formula, chart_title character limits). The description adds nothing to parameter meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: 'Calculate the true cost of recurring spending by showing what that money would be worth if invested.' This is clear and concrete. However, it does not differentiate from closely related siblings such as compound_interest, payoff_vs_invest, or compare_strategies, so an agent must reason about which one applies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only context is a disclaimer ('Calculation, not advice. Verify with a professional before acting'), which is not usage guidance. There is no statement of when to use this vs. compound_interest or payoff_vs_invest, and no exclusions or prerequisites beyond what the schema's required fields imply.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_runwayCash Runway CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Deterministic cash-runway calculator. Given your liquid savings, monthly essential expenses, optional ongoing inflows (partner income, side income, severance paid as a monthly stream, unemployment benefits), and an optional expense-inflation rate, computes how many months the fund lasts before it hits zero, plus a month-by-month drawdown schedule. Single scenario per call: to compare 'status quo' vs 'cutbacks' vs 'cutbacks + unemployment', call once per scenario with the matching expenses and inflows. When inflows meet or exceed expenses (and expenses are not inflating), the fund does not draw down and a self-describing does-not-deplete outcome is returned instead of a month. Yield on the fund is treated as 0% in v1 (conservative). All assumptions cite their source. HEAVY tool: use output='summary' (default) for the headline or output='inline' for the full schedule. output='capture' writes the full payload to a file on this server's local disk for the chart-render pipeline; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with parameters: REQUIRED: current_savings: decimal >= 0. Liquid fund available to draw down. 0 is valid (already-empty fund). monthly_essential_expenses: decimal > 0. Monthly outflow at the chosen expense basis. OPTIONAL: monthly_inflows: decimal >= 0 (default 0). Ongoing monthly income that continues during the drawdown (partner income, side income, unemployment benefit, severance paid monthly). Modeled as a flat monthly stream; a one-time severance lump and time-limited benefits are not modeled in v1. annual_inflation_rate_pct: decimal [0, 100) (default 0). When > 0, expenses grow each month by the monthly-equivalent of this annual rate. When 0, expenses are constant. use_essential_expenses: bool (default true). true = essential-only basis (survival runway); false = total-spend basis (current-pace runway). Labels the reported expense_basis. chart_title: string (optional). Reserved for the chart pipeline. Must not contain em-dashes or en-dashes. Max 120 characters. ENVELOPE: output: 'summary' (default) | 'inline' | 'capture' summary: headline scalars (depletion month / does-not-deplete) + citations; the schedule is stripped. inline: full payload including the month-by-month schedule[] (for chart rendering). capture: full payload written to ~/.senaro/captures/; capture_ref URI returned. Available on the local stdio transport only; the hosted HTTP transport rejects 'capture' with a structured error naming 'summary' and 'inline' as the valid alternatives. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description layers on substantial extra behavior: 0% yield assumption in v1, the does-not-deplete outcome when inflows cover expenses, the HEAVY classification with output sizing options, and the stdio-only 'capture' restriction with a structured error on HTTP. This is well beyond what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the disclaimer and the core purpose, and every sentence carries information (scenario modeling, yield assumption, output modes, transport gating). It is dense rather than bloated, though the transport and capture details make it longer than strictly necessary for the headline call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description carries the return-value burden and does so adequately (depletion month or self-describing does-not-deplete outcome, month-by-month schedule with inline, capture_ref URI with capture). Combined with the rich schema it covers everything an agent needs to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameter baseline is 3, but the description adds real meaning beyond the schema: the single-scenario-per-call constraint, the semantics of comparing status-quo vs cutbacks, the yield convention, and the transport-dependent behavior of output='capture'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Deterministic cash-runway calculator') and precisely scopes the inputs (liquid savings, essential expenses, inflows, inflation) and output (months until fund hits zero plus a drawdown schedule). This clearly distinguishes it from sibling tools like calculate_emergency_fund or calculate_cc_payoff.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent how to run comparisons ('call once per scenario with the matching expenses and inflows') and when to pick each output mode. It does not name sibling alternatives, so it stops short of full when/when-not/alternatives routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_debt_consolidationDebt Consolidation ComparisonARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Should you consolidate credit card debt with a personal loan? Compares keeping cards vs. consolidation loan vs. optional balance transfer offers (single offer or head-to-head multi-offer comparison via bt_offers[]). Supports partial balance transfers via bt_transfer_limit: transfers only up to that dollar amount (choosing cards by highest APR, highest balance, or manually), then runs a combined simulation of the BT card + remaining original-card balances together, so freed minimum payments are correctly redistributed. Shows total cost, interest saved, monthly payment change, origination fee breakeven, hidden risks (reracking), promo-trap detection per offer, and what-if scenarios. Works with multiple cards including cash advance balances. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only. HEAVY tool: use output='summary' (default) for the headline comparison or output='inline' for the full payload. output='capture' writes the full payload to a file on this server's local disk for the chart-render pipeline; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: cards (REQUIRED array, max 20): - name: string (optional) - purchase_balance: decimal >= 0 (REQUIRED) - purchase_apr_pct: decimal 0-100 as percentage, e.g. 22.99 (REQUIRED) - cash_advance_balance: decimal >= 0 (optional, default 0) - cash_advance_apr_pct: decimal > 0, <= 100 (required if cash_advance_balance > 0) - minimum_payment: decimal >= 0 (optional, 0 = auto-calculate). Used as the locked floor for the constant keep-cards payment: each card pays max(your minimum, the bank minimum), held constant and rolled forward as cards clear. - segments: NOT SUPPORTED by this tool (rejected with a parse_error if supplied). This tool always reads the flat purchase_balance / cash_advance_balance fields above, never segments[] balances; supply those instead. segments[] input is supported by calculate_cc_payoff and compare_strategies. - monthly_spend / stop_spend_month: NOT SUPPORTED by this tool (rejected with a validation error if supplied). Ongoing spend on cards a consolidation loan or transfer just paid off is not modeled by any arm here; supported by calculate_cc_payoff and compare_strategies. consolidation_loan (REQUIRED object): - annual_rate_pct: decimal 0-36 as percentage, e.g. 10.99 (REQUIRED) - term_months: int 12-84 (REQUIRED) - origination_fee_pct: decimal 0-10 (optional, default 0) - origination_fee_flat: decimal (optional, default 0, takes precedence if > pct-based fee) - include_fee_in_principal: bool (optional, default true) extra_monthly_payment: decimal >= 0 (optional, default 0) current_strategy: 'avalanche' | 'snowball' (optional, default 'avalanche') (Note: fixed_payments is NOT a parameter of this tool, unlike calculate_cc_payoff. The keep-cards baseline is always simulated under the canonical constant rolled-forward payment, see comparison_basis in the response. Passing fixed_payments returns an unknown_parameter error.) Balance transfer, SINGLE OFFER (legacy, all optional): include_balance_transfer: bool (default false) bt_apr_pct: decimal 0-100 (required if include_balance_transfer: true, use 0 for 0% promo) bt_promo_months: int 1-60 (optional, default 18) bt_regular_apr_pct: decimal 0-100 (optional, default 25.20) bt_fee_pct: decimal 0-10 (optional, default 3.0) Balance transfer, MULTI-OFFER (preferred when comparing two or more offers): bt_offers: array of objects (max 10), when supplied, takes precedence over the scalar bt_* fields Each object: - apr_pct: decimal 0-100 (REQUIRED) - promo_months: int 1-60 (optional, default 18) - regular_apr_pct: decimal 0-100 (optional, default 25.20) - fee_pct: decimal 0-10 (optional, default 3.0) - label: string (optional, defaults to "<apr_pct>% / <months>mo") The response includes a balance_transfer_offers block with per-offer simulation results, selected_offer_index, selected_offer_label, selected_offer_reason, and all_offers_trap. Partial balance transfer (use when the BT offer has a transfer limit < your total debt): bt_transfer_limit: decimal >= 0.01 (optional), cap on total transferred amount. When set, only this amount moves to the BT card; remaining balances stay on original cards. A combined simulation runs both halves together, correctly redistributing freed minimum payments. When omitted, the entire balance is transferred (legacy behavior). bt_transfer_strategy: 'highest_apr_first' | 'highest_balance_first' | 'manual' (optional, default 'highest_apr_first') highest_apr_first: transfer from highest-APR segments first (maximizes interest savings) highest_balance_first: transfer largest balances first manual: use bt_manual_transfers to specify exact amounts per card bt_manual_transfers: array of objects (required when bt_transfer_strategy='manual') Each object: - card_name: string (must match a card name in cards[]) - amount: decimal > 0 full_schedule: bool (optional, default false, compact schedule by default) windfalls: array of one-time principal payments (optional, default empty, max 12). Same shape as calculate_cc_payoff. Each item: - month: int >= 0 (REQUIRED). 0 means applied before month 1's interest. N >= 1 applies at the END of calendar month N. - amount: decimal > 0 (REQUIRED). - label: string (optional). e.g. 'Tax refund', 'Year-end bonus'. When non-empty the response adds windfalls_applied[] and windfalls_unused[] on keep_cards, on each balance_transfer scenario (and on each offer in balance_transfer_offers.offers[]), on consolidation_loan (single-row per windfall since the loan is a single-balance instrument), and on optimized_consolidation.keep_subset. All scenarios use with-windfalls totals so cross-option ranking stays apples-to-apples. chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. ENVELOPE: output: 'summary' (default) | 'inline' | 'capture' summary: compact response with a data_preview block. No heavy array exists on this response today, so summary and inline are currently identical in content; the envelope is wired ahead of the future chart-render pipeline. inline: full payload (currently identical to summary; will diverge once a heavy array is added for chart rendering). capture: full payload written to ~/.senaro/captures/; capture_ref URI returned. Available on the local stdio transport only; the hosted HTTP transport rejects 'capture' with a structured error naming 'summary' and 'inline' as the valid alternatives. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description still adds real context: it is a heavy computation, 'capture' writes a file to the server's local disk, and that mode is rejected with a structured error on the hosted HTTP transport. The chart_hints/senaro-charts stdio rendering note is also unique to the description rather than the schema. Much of the output-mode wording is, however, duplicated in the schema's envelope block.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Information-dense, but the highest-value position is spent on boilerplate ("Calculation, not advice. Verify with a professional before acting.") and a rhetorical question before the tool's actual function appears. Several statements (output modes, bt_offers precedence) restate the schema, inflating length and diluting the front-load.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden itself and does so: chart_hints, the balance_transfer_offers block (per-offer results, selected_offer_index/label/reason, all_offers_trap), windfalls_applied/windfalls_unused placement, and comparison_basis semantics for the keep-cards baseline. An agent has what it needs to call and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the embedded schema already documents nearly every field, so the baseline is 3. The description adds genuine semantic value on top: what bt_transfer_limit actually does (only the capped amount moves; the two halves are simulated together so freed minimum payments are correctly redistributed) and what a head-to-head multi-offer run produces.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific decision the tool answers ("Should you consolidate credit card debt with a personal loan?") and enumerates the exact arms compared: keep cards vs. consolidation loan vs. optional balance transfer offers. It explicitly differentiates itself from siblings by noting that segments[]/monthly_spend inputs belong to calculate_cc_payoff and compare_strategies, not here.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use routing: bt_offers[] when comparing two or more offers, bt_transfer_limit when the offer caps below total debt, output='summary' vs 'inline' vs 'capture' by payload need and transport. It also names the exclusion conditions (segments and monthly_spend rejected; fixed_payments not a parameter here unlike calculate_cc_payoff).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_mortgage_termsMortgage Terms ComparisonARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Compare two fixed-rate mortgage options side-by-side: 15 vs 30 year, different rates, points vs no points, or any two terms. Shows total interest, monthly payment breakdown (with tax, insurance, PMI, HOA), equity buildup, and, critically, what happens if you take the cheaper mortgage and invest the monthly savings. Finds the break-even investment return rate. Includes tax deduction analysis (itemizing vs standard deduction), PMI auto-removal tracking per the Homeowners Protection Act, and after-tax net worth comparison. Note: ARM (adjustable-rate) mortgages are not yet supported.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: home_price: decimal > 0, <= 1,000,000,000 (REQUIRED) down_payment_pct: decimal 0-100 as percentage (optional, default 20) down_payment_amount: decimal >= 0 (optional; overrides down_payment_pct if provided) option_a (REQUIRED object): - label: string (optional; auto-generated if omitted) - annual_rate_pct: decimal 0-20 as percentage, e.g. 6.25 (REQUIRED) - term_years: int 1-40 (REQUIRED) - is_arm: bool (optional, default false; ARM not yet supported) - points: decimal 0-4 (optional, default 0; discount points bought, each = 1% of loan) - points_rate_reduction_pct: decimal 0-1.0, PERCENTAGE POINTS reduction per point (optional, default 0.25) option_b (REQUIRED object): - same shape as option_a - Must differ from option_a on at least one of: term_years, annual_rate_pct, or points property_tax_annual: decimal >= 0 (optional, default 0; for true monthly cost) home_insurance_annual: decimal >= 0 (optional, default 0) pmi_monthly: decimal >= 0, <= 1,000,000,000 (optional, default 0; PMI if < 20% down) pmi_removal_ltv_pct: decimal 50-100 (optional). When omitted, PMI is modeled as removed at the 78% HPA automatic-termination threshold. Provide a value (e.g. 80) to model borrower-requested removal at that LTV (whichever of 78% or your value is reached first). Either way PMI also stops at the statutory amortization midpoint of each option's own term (12 U.S.C. §4901(7), §4902(c)), which this value cannot postpone. hoa_monthly: decimal >= 0 (optional, default 0) invest_the_difference: bool (optional, default true). When true, both options deploy the same total budget every month: the higher option's P&I plus any extra_monthly_payment plus the month-1 PMI both carry. The cheaper-mortgage holder invests the payment gap each month; an option that stops paying PMI earlier invests the freed cash; the option with the lower upfront points cost invests the difference at month 0; after payoff the full budget goes to investments. See comparison_basis in the response. investment_return_pct: decimal 0-30 as percentage, an EFFECTIVE ANNUAL rate; the monthly compounding step is (1+pct/100)^(1/12)-1 (optional; defaults to the cited Senaro long-run S&P 500 nominal return, about 10%) tax_bracket_pct: decimal 0-50 as percentage (optional; enables after-tax investment return and mortgage interest deduction analysis; the after-tax comparison credits each option's annual deduction savings to its investments at year end) standard_deduction: decimal (optional. Defaults to the IRS basic standard deduction for tax_year + filing_status. TY2026: 16100 single, 32200 married, 24150 head_of_household. TY2025: 15750 single, 31500 married, 23625 head_of_household. Source: Rev. Proc. 2025-32) filing_status: 'single' | 'married' | 'head_of_household' (optional) tax_year: int, 2025 or 2026 (optional, default 2026; selects the IRS standard-deduction table for the itemize-vs-standard analysis) extra_monthly_payment: decimal >= 0, <= 1,000,000,000 (optional, default 0; extra principal applied equally to BOTH options) time_horizon_years: int 1-40 (optional; default: max of both term_years) full_schedule: bool (optional, default false; compact amortization by default) closing_cost_pct: decimal 0-20 as percentage of loan amount (optional, default: Urban Institute loan-size regressive schedule (~4.6% at $97K loan down to ~1.4% at $679K), points excluded. Pass 0 to model zero closing costs) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (readOnly, idempotent, non-destructive), so the description carries the rest and does so well: it discloses the 'calculation, not advice' posture, the break-even investment framing, PMI auto-removal behavior, and tax-deduction analysis. Much of the deeper behavioral detail (comparison basis, effective annual return compounding) lives in the schema rather than the description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the most decision-relevant information: the 'calculation, not advice' caveat, the comparison scope, and the outputs, ending with the ARM limitation. It is dense but nearly every clause earns its place; slightly long overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by enumerating what is returned (total interest, monthly payment breakdown, equity buildup, break-even return, after-tax net worth). Combined with the rich input schema, an agent has enough to select and call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema is extremely detailed, so the parameter contract is fully carried there. The description adds no syntax or format detail beyond it, which is the expected baseline for a high-coverage schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Compare two fixed-rate mortgage options side-by-side') and enumerates concrete comparison axes (15 vs 30 year, rates, points). It is clearly distinguishable from siblings like payoff_vs_invest, rent_vs_buy, and refi_breakeven.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for when to use it ('any two terms', 15 vs 30, points vs no points) and an explicit scope exclusion ('ARM mortgages are not yet supported'). It does not, however, name which sibling tool to use instead for ARM analysis or for related-but-distinct questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_strategiesPayoff Strategy ComparisonARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Compare avalanche and snowball payoff strategies side-by-side. Returns months, total interest, payoff order, savings, total_balance, weighted_average_apr_pct, monthly_interest_now, and cost_breakdown array. When an arm is not projected to reach a zero balance, the savings.* fields for that arm carry status: "none" with value: null and an explanation, not a number. savings.strategies_convergence separately discloses the avalanche/snowball arms' own convergence: "both_converge" (ordinary case), "worst_never_amortizes" (the losing strategy arm does not reach a zero balance in this projection but the winning arm does, so savings.best_vs_worst_months/interest carry status: "none"), or "neither_converges" (the WINNING strategy arm does not reach a zero balance either, so no dollar or month figure derived from either strategy arm is reportable). lower_total_interest_strategy names whichever of avalanche or snowball has the lower total interest, or "tie" when the two arms' total interest and months are exactly equal. A "tie" can co-occur with savings.strategies_convergence="neither_converges". It reports only that comparison, never that either arm pays off. chart_hints.title and chart_hints.annotations[0].label report a dollar figure only when the comparison they describe is Defined, and otherwise state plainly that no figure is reportable, matching the "none" status on the corresponding savings.* field. Unlike chart_hints, summary and savings.savings_summary hedge rather than decline a figure, and the two always carry the same sentence as each other: when the compared arm does not converge (savings.baseline_never_amortizes=true, or savings.strategies_convergence=worst_never_amortizes) but the winning side still does, both report a figure hedged as a floor, "saves at least $X and N months ..., so the true saving could be higher than reported". Only when strategies_convergence=neither_converges do summary and savings.savings_summary also state that no figure is reportable. No savings.* sentinel object carries a hedged floor in its value key; the only place a floor ever appears is the savings.savings_summary sentence. This tool carries no domain-shaped warnings[].type entries (unlike calculate_cc_payoff); warnings[] here is exclusively validation disclosures emitted as warnings[].code, e.g. MINIMUM_PAYMENT_NOT_BINDING_IN_BASELINE plus the general portfolio findings (MANY_CARDS, HIGH_CARD_BALANCE, etc.) shared with every card-based tool. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only. Use output: 'summary' (default) for a compact response or 'inline' for the full payload. output: 'capture' writes the full payload to a file on this server's local disk and returns a capture_ref URI for chart rendering; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport, where a capture_ref would be a dead link for a remote caller.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: cards (REQUIRED array, max 20): same format as calculate_cc_payoff - name, purchase_balance, purchase_apr_pct (REQUIRED) - cash_advance_balance, cash_advance_apr_pct (optional) - minimum_payment (OPTIONAL, omit or 0 to auto-calculate) - annual_fee: decimal >= 0 (optional, default 0). Charged at month 1 and every 12th month thereafter. - plan_fees_monthly: decimal >= 0 (optional, default 0). Charged every month while the card has a balance. - segments: array (OPTIONAL; when present, supersedes purchase_balance / cash_advance_balance). Max 100 segments total across all cards in the request. Per-card, per-type caps: 1 purchase, 1 cash_advance, 5 balance_transfer, 1 promotional, 10 installment_plan. Same per-segment shape as calculate_cc_payoff; see that tool's segments[] documentation for the full field list. extra_monthly_payment: decimal >= 0 (optional, default 0) (Note: fixed_payments is NOT a parameter of this tool, unlike calculate_cc_payoff. Avalanche and snowball are always compared under the canonical constant rolled-forward payment, see comparison_basis in the response. Passing fixed_payments returns an unknown_parameter error.) apply_rate_cap: bool (optional, default false) chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. output: 'summary' | 'inline' | 'capture' (optional, default 'summary') 'capture' is available on the local stdio transport only; the hosted HTTP transport rejects it with a structured error naming 'summary' and 'inline' as the valid alternatives. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the readOnly/idempotent annotations: it discloses the 'none' sentinel semantics for non-converging arms, the strategies_convergence states (both_converge / worst_never_amortizes / neither_converges), how summary/savings_summary hedge as floors while chart_hints decline figures, that warnings[] carries only validation codes, and the capture transport restriction. This is exactly the kind of mutation/edge-case context annotations cannot supply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded well with 'Calculation, not advice' followed by the purpose, but the remainder is a dense wall of sentinel-status prose for a single-parameter tool. Most sentences carry technical weight, yet the reconstruction of return-field behavior is verbose enough to impede scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully carries the return-value burden: it enumerates returned fields and exhaustively documents the sentinel, convergence, hedging, and chart_hints semantics. An agent has everything needed to interpret responses correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it explains that fixed_payments is intentionally absent (returns unknown_parameter), the semantics of each output mode, and the chart_title dash/length constraint. The 'capture on stdio only' detail materially clarifies the output parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Compare avalanche and snowball payoff strategies side-by-side.' It also names the concrete sibling it is not (calculate_cc_payoff), noting fixed_payments is not a parameter here, so an agent can distinguish it from the single-strategy payoff tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for the output modes ('summary' for compact, 'inline' for full, 'capture' for file rendering) and states the transport constraint on 'capture' (stdio only, rejected on HTTP). It also distinguishes itself from calculate_cc_payoff via the fixed_payments exclusion. It stops short of an explicit 'use this instead of X when Y' routing statement against the broader sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compound_interestCompound Interest CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Standard compound interest calculator. Returns future value, total contributions, interest earned, effective annual rate, and milestones. The response includes chart_hints with rendering directives any client can use. The senaro-charts MCP server renders them locally over stdio only.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: principal: decimal >= 0 (REQUIRED) annual_rate_pct: decimal 0-100 as percentage, e.g. 7 not 0.07 (REQUIRED) years: int >= 1 (REQUIRED) monthly_contribution: decimal >= 0 (optional, default 0) compounds_per_year: int > 0 (optional, default 12) inflation_rate_pct: decimal >= 0 (optional, default 0 = NO real-value overlay; >0 = explicit percentage e.g. 3.5; -1 = deprecated suppress, same as 0) apply_default_inflation: bool (optional, default false; when true and inflation_rate_pct=0, auto-selects inflation via MacroeconomicDefaults.ForHorizon; ignored when inflation_rate_pct>0 or rate_convention='real') rate_convention: 'nominal'|'real' (optional, default 'nominal'; 'real' unconditionally suppresses the inflation overlay; use when annual_rate_pct is already inflation-adjusted) chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a read-only, idempotent, non-destructive, closed-world calculation. The description adds useful context beyond annotations: it lists the return fields, mentions chart_hints rendering directives, and clarifies that senaro-charts renders locally over stdio only.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and efficient, but it front-loads legal disclaimers before the primary purpose statement. The remaining sentences are concise and each supports selection or invocation, though the chart_hints rendering detail is secondary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a calculation tool with a fully described input schema and rich annotations, the description covers outputs, chart_hints behavior, and the local rendering constraint. No output schema exists, but the description compensates by naming the returned values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema fully documents all parameters. The description adds no additional parameter meaning beyond what the schema provides, making the baseline score of 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies this as a standard compound interest calculator and lists the outputs (future value, contributions, interest, EAR, milestones). It is specific about the resource and calculation type, though it does not explicitly differentiate itself from the many sibling financial calculators.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this calculator versus alternatives such as payoff_vs_invest or calculate_opportunity_cost. It only includes a general disclaimer ('Calculation, not advice') and no use-case context or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_defaultsDefault Assumptions CatalogARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting.
Returns named default values used by Senaro Finance tools with source citations. Use before calling other tools to understand what assumptions apply automatically. This tool does not accept an 'output' parameter; it always returns inline JSON.
JSON parameters (all optional): category: string. Filter entries by category: the canonical MCP tool name that consumes the default, or "shared" for a default consumed by two or more tools (or not yet wired to a specific tool). Case-insensitive. The 14 valid values: calculate_cc_payoff, calculate_debt_to_income, calculate_emergency_fund, calculate_opportunity_cost, calculate_runway, compare_debt_consolidation, compare_mortgage_terms, compare_strategies, compound_interest, optimize_401k_match, payoff_vs_invest, refi_breakeven, rent_vs_buy, shared. An unrecognized value returns validation_error listing the accepted set. name: string. Return one full entry. Requires category. Returns validation_error if not found. verbose: boolean. Return all 10 citation fields per entry instead of just category+name. Ignored when name is also present (single entry always includes all fields). Omit category to get the full verbose catalog.
Default (no args): index mode. Every entry with just category and name fields (~20 KB).
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Optional: return one full entry. Requires category. Returns validation_error if not found. | |
| verbose | No | Optional: return all 10 citation fields per entry instead of just category+name. | |
| category | No | Optional: filter entries by category, the canonical MCP tool name (e.g. "rent_vs_buy") or "shared". Case-insensitive. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive. The description adds genuinely new behavioral context: the tool never accepts an 'output' parameter and always returns inline JSON, the ~20 KB size of default index mode, the validation_error contract for bad categories, and the verbose-ignored-when-name-present rule. Slightly verbose but substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The behavioral/citation framing is front-loaded and useful, but the parameter block is long and partly duplicative of the schema, and enumerating 14 category values inline inflates the description. Every sentence earns its place, but it is not tightly trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-param, no-output-schema read-only catalog, the description covers invocation modes, error contracts, and scope thoroughly. It omits an explicit statement of what a 'default' entry actually contains beyond 'citation fields', which is the only notable gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (baseline 3), and the description still adds cross-parameter semantics the schema lacks: name requires category, the 14 canonical enum values, the case-insensitive matching, and the interaction between verbose and name. This exceeds what the flat schema communicates.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: returns named default values used by Senaro Finance tools with source citations. Distinguishes itself from the calculate_/compare_ siblings by being a metadata/catalog tool rather than a calculator, and explicitly positions itself as a pre-step ('Use before calling other tools').
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance: 'Use before calling other tools to understand what assumptions apply automatically.' Also explains the index-vs-detail modes and the no-args default behavior, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_401k_match401(k) Match OptimizerARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Deterministic 401(k) employer-match optimizer. Given your annual salary, pay frequency, current contribution percent, and your employer's match formula (as a named preset or a custom tier list), computes: the annual match you are capturing today; the maximum you could capture (full match entitlement); the match forfeited at your current rate; the minimum contribution percent to capture the full match; whether front-loading contributions would forfeit match at a no-true-up plan; and a per-period schedule showing level vs. front-load paths side by side. IRS limits (402(g) elective deferral, 401(a)(17) compensation cap, 415(c) annual additions) are applied and cited in provenance. Catch-up contribution ceilings for ages 50+ and 60-63 (SECURE 2.0) are computed when participant_age is provided; when a catch-up allowance applies, applied_caps[].cap_name reads '402(g) elective deferral plus 414(v) catch-up' and limit_value carries the combined ceiling, not the bare 402(g) amount. HEAVY tool: use output='summary' (default) for the headline scalars or output='inline' for the full per-period schedule. output='capture' writes the full payload to a file on this server's local disk for the chart-render pipeline; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with parameters: REQUIRED: annual_salary: decimal > 0. Annual gross salary. pay_periods_per_year: integer in [1, 365]. Pay periods per year (12=monthly, 24=semi-monthly, 26=biweekly, 52=weekly). contribution_pct: decimal in [0, 100]. Current employee contribution as a percent of gross pay. MATCH FORMULA (exactly one required): match_preset: one of 'safe_harbor_basic' (100% of first 3% + 50% of next 2%), 'safe_harbor_enhanced_simple' (100% of first 4%), 'qaca' (100% of first 1% + 50% of next 5%), 'fifty_pct_of_first_six_pct' (50% of first 6%). match_tiers: array of tier objects [{ match_frac: decimal (0,1], up_to_deferral_pct: decimal > 0 }, ...]. match_frac is the employer fraction (0.5 = 50%). up_to_deferral_pct is the tier width as a percent of pay. Example: [{ match_frac: 1.0, up_to_deferral_pct: 3 }, { match_frac: 0.5, up_to_deferral_pct: 2 }] = safe_harbor_basic. OPTIONAL: has_true_up: bool (default false). Whether the plan provides an annual true-up. false is the conservative assumption: surfaces front-loading forfeiture risk. participant_age: integer >= 0 (optional). Determines which catch-up limit applies (age 50+, or age 60-63 SECURE 2.0 super catch-up). Omit when age is unknown or participant is under 50. chart_title: string (optional). Reserved for the chart pipeline. Must not contain em-dashes or en-dashes. Max 120 characters. ENVELOPE: output: 'summary' (default) | 'inline' | 'capture' summary: headline scalars (match captured/forfeited, full-match threshold, front-load flag, applied_caps, citations); the per-period period_schedule is stripped. inline: full payload including the period_schedule[] (for chart rendering). capture: full payload written to ~/.senaro/captures/; capture_ref URI returned. Available on the local stdio transport only; the hosted HTTP transport rejects 'capture' with a structured error naming 'summary' and 'inline' as the valid alternatives. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description adds substantive behavior on top: determinism, that IRS limits are applied and cited in provenance, the combined 402(g)+414(v) catch-up ceiling naming in applied_caps, the front-load forfeiture risk surfaced by the default has_true_up=false, and the structured-error behavior of output='capture' on the hosted HTTP transport. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the disclaimer and one-sentence purpose before the capability list, and the output-mode guidance is placed at the end where an agent making the call will find it. The prose is dense and long, with some redundancy between the description and the schema's toolArguments text (the 402(g) catch-up and capture-transport caveats appear twice), but every section carries real information for a heavy calculator.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description correctly carries the return-value burden: it enumerates the headline scalars, notes that period_schedule is stripped in 'summary', and describes the capture_ref URI. Combined with the annotation coverage and full schema descriptions, an agent has everything needed to select the right output mode and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds derived semantics beyond a plain field list: it explains the interaction between participant_age and the resulting applied_caps[].cap_name/limit_value, why has_true_up defaults false (conservative forfeiture modeling), and what each output mode does to the payload. It largely mirrors the schema's own param text, which caps the score below 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Deterministic 401(k) employer-match optimizer') and enumerates exactly what it computes: match captured, max entitlement, forfeited match, full-match threshold, front-load forfeiture, and a per-period schedule. This is unmistakably distinct from sibling calculators like calculate_emergency_fund or compare_strategies because the resource and outputs are named concretely.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operational context: which output mode to pick ('summary' default for headline scalars, 'inline' for the schedule, 'capture' for the file pipeline) and the transport restriction that capture is stdio-only. It also flags the tool as HEAVY and adds a 'calculation, not advice' caveat. It stops short of naming a sibling alternative or an explicit when-not-to-use condition, so it is context-rich but not fully routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
payoff_vs_investDebt Payoff vs. InvestARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Should you pay extra on debt or invest the difference? Compares the guaranteed return of debt payoff against expected investment returns over a time horizon. Accounts for post-payoff investing, tax implications, and finds the break-even investment return rate. Works for credit cards, auto loans, student loans, personal loans, and mortgages. The response echoes debt_type (canonical lowercase enum the projection was computed for) and debt_type_label (display-ready string, e.g. 'student loan') at the top level. HEAVY tool: use output='summary' (default) for the headline comparison or output='inline' for the full month-by-month schedule. output='capture' writes the full payload to a file on this server's local disk for the chart-render pipeline; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport. At extreme inputs (very long horizon, very high rate, or very large amounts) the response may instead be { meta, not_representable: { code, explanation } } when no projection can be computed.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: debt_type: 'credit_card' | 'auto' | 'student' | 'personal' | 'mortgage' (REQUIRED) debt_balance: decimal > 0 (REQUIRED) debt_apr_pct: decimal 0-100 as percentage, e.g. 6.5 not 0.065 (REQUIRED) extra_monthly: decimal > 0. The amount in question (REQUIRED) minimum_payment: decimal >= 0 (optional; auto-calculated for loans when 0) term_months_remaining: int > 0. Required for non-credit-card debt types investment_return_pct: decimal 0-30 as percentage, an EFFECTIVE ANNUAL rate; the monthly compounding step is (1+pct/100)^(1/12)-1 (optional; defaults to the cited long-run S&P 500 nominal return, about 10%) investment_volatility_pct: decimal (optional; adds volatility risk note) tax_bracket_pct: decimal 0-100 as percentage (optional; enables after-tax comparison) investment_tax_advantaged: bool (optional, default false; set true for 401k/IRA) time_horizon_years: int > 0 (optional; default max(payoff years, 10)) full_schedule: bool (optional, default false; returns compact schedule by default) chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. ENVELOPE: output: 'summary' (default) | 'inline' | 'capture' summary: headline comparison scalars + milestones + citations; monthly_schedule is stripped. inline: full payload including the month-by-month monthly_schedule[] (for chart rendering). capture: full payload written to ~/.senaro/captures/; capture_ref URI returned. Available on the local stdio transport only; the hosted HTTP transport rejects 'capture' with a structured error naming 'summary' and 'inline' as the valid alternatives. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial behavior: 'HEAVY tool' cost warning, transport-specific capture rejection with a structured error, and the not_representable fallback shape at extreme inputs. These are non-obvious failure and cost characteristics an agent could not infer from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the disclaimer and the core question well, but the output-mode paragraph duplicates material already spelled out in the envelope schema (summary/inline/capture and the stdio-only capture restriction), adding length without new information. The most useful edge-case detail (not_representable) is buried at the very end.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden and does so: it names the echoed response fields, describes the summary vs full-schedule return difference, the capture_ref URI, and the alternate error payload. An agent has enough to invoke correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including the nested envelope and defaults is already documented in the schema; the description largely restates the envelope semantics (summary/inline/capture) rather than adding new meaning. It does add the echoed debt_type/debt_type_label return fields, but those concern output, not parameter behavior. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific comparison task with a clear verb and resource: 'Compares the guaranteed return of debt payoff against expected investment returns over a time horizon' and 'finds the break-even investment return rate'. This is distinguishable from siblings like calculate_opportunity_cost or compare_strategies, and it enumerates supported debt types.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Frames the decision question ('Should you pay extra on debt or invest the difference?') and gives explicit guidance on output mode selection (summary vs inline vs capture) and the transport restriction on capture. However, it never names a sibling tool as the alternative or states when NOT to use this tool, so routing is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refi_breakevenRefinance Break-Even AnalysisARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Deterministic mortgage refinance break-even analysis. Given your current loan (balance, rate, remaining term) and a refinance offer (new rate, new term, closing costs, optional points), computes: monthly P&I savings; the cash-flow break-even month (total refinance cost divided by monthly savings, CFPB convention); the lifetime interest delta over your remaining-term horizon; a term-matched scenario that isolates the rate cut from a term reset; a term-reset-trap flag (lower payment but higher lifetime interest from extending the term); and the economic break-even (net-worth crossover) month using an equal-outflow invest-the-savings model. Rate-and-term refis only (cash-out and tax effects are out of scope). All defaults cite primary sources (LodeStar/ALTA closing-cost data, CFPB break-even convention). Scalar output, no chart series.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with these parameters: REQUIRED: current_balance: decimal > 0. Outstanding principal you would refinance. current_annual_rate_pct: decimal [0, 20] as a percentage, e.g. 6.5 not 0.065. remaining_term_months: int [1, 480]. Months left on the current loan. new_annual_rate_pct: decimal [0, 20] as a percentage. The offered rate. new_term_months: int [1, 480]. The new loan term. OPTIONAL: current_monthly_payment: decimal > 0. Your actual statement P&I payment; overrides the formula-derived payment when supplied (match your statement). closing_costs: decimal >= 0. Explicit closing costs in dollars; overrides the cited default (0.67% of loan, LodeStar 2026). Excludes points -- total upfront cost is closing_costs + points cost. An IMMEDIATE break-even requires total upfront cost to be zero (or non-positive) AND monthly_savings to be non-negative, i.e. closing_costs AND points both 0, not closing_costs alone; a zero-total-cost refi into a worse deal (negative monthly_savings) reports NEAR_ZERO_OR_NEGATIVE_SAVINGS instead. points: decimal [0, 4] (default 0). Discount points at closing (1.0 = 1% of loan). roll_costs_into_loan: bool (default false). When true, closing costs + points are added to the new principal instead of paid upfront; cash-flow break-even then reports COSTS_ROLLED_INTO_LOAN. investment_return_pct: decimal [0, 30], an EFFECTIVE ANNUAL rate; the monthly compounding step is (1+pct/100)^(1/12)-1 (default: ~10.0%, the cited long-run S&P 500 nominal total-return default; call list_defaults for the exact current value). Annual return used for the economic (invest-the-savings) break-even. compute_economic_break_even: bool (default true). When false, only the cash-flow break-even and interest delta are returned (economic break-even reports NOT_REQUESTED). chart_title: string (optional). Reserved for the chart pipeline. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare it read-only/idempotent, and the description adds substantial behavior beyond that: deterministic computation, cited primary-source defaults, the CFPB break-even convention, the term-reset-trap flag, the economic (invest-the-savings) model, and edge-case reporting states (COSTS_ROLLED_INTO_LOAN, NOT_REQUESTED).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the mandatory disclaimer, then the purpose, then outputs, then scope — a logical order with no filler. It is dense and somewhat long, but each clause carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of describing return values, and it enumerates every scalar output plus non-numeric status flags. Scope limits and default provenance are also covered, leaving nothing an agent needs before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the parameters are exhaustively documented in the schema itself. The description reinforces the two-sided (current vs. offer) framing and cites where defaults come from, but adds no syntax or format detail beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Deterministic mortgage refinance break-even analysis') and enumerates the exact scalar outputs it computes. An agent can distinguish it from siblings like compare_mortgage_terms or calculate_loan_payoff from the description alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly scopes the tool ('Rate-and-term refis only; cash-out and tax effects are out of scope') and describes required inputs (current loan + refinance offer). It does not, however, name the sibling to use instead for those excluded cases or contrast against compare_mortgage_terms.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rent_vs_buyRent vs. Buy CalculatorARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting. Deterministic rent-vs-buy decision model. Given a home price, monthly rent, and mortgage rate, computes the breakeven month (when BUY net worth first equals or exceeds RENT net worth), per-horizon net-worth comparison (years 5, 10, 30 + user horizon), and the full year-by-year cost/wealth series for both paths. Includes carrying costs (property tax, insurance, maintenance, PMI, HOA) on the BUY path and opportunity-cost investing on the RENT path. Optional federal tax benefit model (Tier-3: apply_tax_benefit=true) with TY2025/TY2026 SALT caps, mortgage interest deduction, PMI deductibility, and marginal-excess formula. All assumptions cite primary sources (FHFA, BLS, Harvard JCHS, IRS Pub 936, OBBBA Pub. L. 119-21) and can be overridden. HEAVY tool: use output='summary' (default) for scalar headline or output='inline' for chart series. output='capture' writes the full payload to a file on this server's local disk for the chart-render pipeline; available on the local stdio transport only, and rejected with a structured error on the hosted HTTP transport.
| Name | Required | Description | Default |
|---|---|---|---|
| toolArguments | Yes | JSON object with parameters: TIER 0 - REQUIRED (the instant answer renders from these three): home_price: decimal > 0 monthly_rent: decimal >= 0 (0 is valid for free-housing baseline) mortgage_rate_pct: decimal in (0, 100]; e.g. 6.75 for 6.75%. Never cached; provide current rate. TIER 1 - PRE-FILLED (defaults are cited; omit to use the default): down_payment_pct: decimal [0, 100] (default: 20%). 0 is valid (zero-down programs). loan_term_months: int > 0 (default: 360 = 30-year fixed) horizon_years: int [1, 40] (default: returns snapshots at years 5, 10, 30) hoa_monthly: decimal >= 0 (default: 0) TIER 2 - SOFT OVERRIDES (defaults from cited national sources; override for your market): home_appreciation_pct: decimal. Annual home price appreciation % (default: 4.25%, FHFA HPI). rent_growth_pct: decimal. Annual rent escalation % (default: 3.4%, BLS CPI ROPR). maintenance_pct: decimal. Annual maintenance as % of home value (default: 1.5%, Harvard JCHS). sell_side_pct: decimal. Sell-side transaction cost % of sale price (default: 7.5%, Redfin post-NAR). property_tax_pct: decimal. Annual property tax as % of home value (default: 0.88%). home_insurance_pct: decimal. Annual insurance as % of home value (default: 0.65%). pmi_pct: decimal. Annual PMI rate as % of loan (default: 0.5%). Removal threshold is set by pmi_removal_ltv_pct (below). pmi_removal_ltv_pct: decimal 50-100 (optional). Sets the loan-balance trigger for PMI removal: omitted, it is the 78% HPA automatic-termination threshold; provided (e.g. 80), it is whichever of 78% or your value is reached first. Either way PMI also stops at the statutory amortization midpoint of the original term (12 U.S.C. §4901(7), §4902(c)), which this value cannot postpone. investment_return_pct: decimal. RENT path annual return %, an EFFECTIVE ANNUAL rate; the monthly compounding step is (1+pct/100)^(1/12)-1 (default: 10.0%). inflation_pct: decimal. Inflation % for real-terms toggle (default: 2.5%). real_terms: bool. Deflate the output series for real-terms view (default: false). basis_capitalizable_pct_override: decimal [0, 100]. Fraction of the buy-side closing cost that is capitalizable into the §121 adjusted basis (IRS Pub 523 split: abstract fees, title search, recording fees, survey fees, transfer taxes, owner's title insurance). Default: 50% (Senaro deterministic midpoint). Supply your actual HUD-1 split when available. 0 = HomePrice-only basis; 100 = full closing cost in basis. TIER 3 - TAX REFINEMENT (only used when apply_tax_benefit = true): apply_tax_benefit: bool (default: false). The §121 home-sale gain exclusion applies only at sale points 24 months or more after purchase (IRC §121(a) 2-of-5-year test); year 1 of yearly_series, months 1-23 in monthly_series, and any horizon under 24 months use no exclusion. Separately, IRC §1222(3) makes a holding period of 12 months or less short-term, taxed at ordinary rates instead of the long-term rates otherwise applied, on the home-sale gain and the renter's portfolio gain alike (24 months vs. 12 months are two different thresholds); this tool applies that split exactly to the home-sale gain, and to the renter's portfolio at annual grain: prior years' contributions are compounded together as one long-term lot rather than aged individually, so months inside a year understate short-term gain. filing_status: 'Single' | 'MFJ' | 'MFS' | 'HoH' (REQUIRED when apply_tax_benefit = true) tax_year: 2025 | 2026 (REQUIRED when apply_tax_benefit = true) annual_gross_income: decimal >= 0 (REQUIRED when apply_tax_benefit = true; MAGI proxy for bracket/SALT) state_local_tax: decimal >= 0 (optional, default 0; SALT for the SALT cap, state income or sales tax paid) charitable: decimal >= 0 (optional, default 0; charitable contributions. TY2026+: 0.5%-AGI floor per OBBBA §70111) other_itemizable: decimal >= 0 (optional, default 0; medical above 7.5% AGI, casualty losses, etc.) age_65_plus_count: int 0 to 2 (optional; adds additional standard deduction per qualifying filer) blind_count: int 0 to 2 (optional; adds additional standard deduction per qualifying blind filer) loan_origination_date: string YYYY-MM-DD (optional; pre-12/15/2017 gets $1M cap, post gets $750k) pmi_annual: decimal >= 0 (optional; if omitted, derived from pmi_pct x average loan balance) purchase_year_points: decimal >= 0 (optional; discount points at origination, % of loan; paid in cash at closing and deducted in year 1) ENVELOPE: output: 'summary' (default) | 'inline' | 'capture' summary: headline scalars + per-horizon snapshots; heavy series stripped (chart-friendly) inline: full payload including yearly_series[] + monthly_series[] (for chart rendering) capture: full payload written to ~/.senaro/captures/; capture_ref URI returned. Available on the local stdio transport only; the hosted HTTP transport rejects 'capture' with a structured error naming 'summary' and 'inline' as the valid alternatives. chart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations: it discloses that this is deterministic (not advice), that all assumptions are cited and overridable, that output='capture' writes a payload to local disk, and that the hosted HTTP transport rejects 'capture' with a structured error. The file-writing behavior of capture is a side effect not captured by readOnlyHint/idempotentHint, and the description surfaces it proactively.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence front-loads the disclaimer and the core purpose, and each sentence carries information. It is long, and the transport/capture constraints are stated redundantly (once in the description, once in the envelope schema), which costs it the top score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description fully compensates by enumerating the return values (breakeven month, year 5/10/30 snapshots, yearly and monthly series) and how output mode shapes them. Combined with the annotations and the complete parameter documentation, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the tiered parameter documentation already does the heavy lifting and sets a baseline of 3. The description adds real meaning on top: it flags the federal tax model (TY2025/TY2026 SALT caps, mortgage interest and PMI deductibility) and the source citations behind defaults, giving the agent context for which parameters matter and why.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and artifact: a deterministic rent-vs-buy model computing the breakeven month, per-horizon net-worth comparisons, and a year-by-year series for both BUY and RENT paths. That specificity is enough to distinguish it from siblings like refi_breakeven or compare_mortgage_terms without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives solid guidance on output modes ('use output=summary for scalar headline, inline for chart series') and transport availability, and marks the tool as HEAVY so the agent knows to prefer lightweight outputs. However, it never states when to choose this tool over siblings such as calculate_opportunity_cost, payoff_vs_invest, or compare_mortgage_terms, so sibling routing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
server_infoSenaro Server InfoARead-onlyIdempotentInspect
Calculation, not advice. Verify with a professional before acting.
Returns metadata about the running Senaro MCP server: version, contract version, build commit, build timestamp, and the full list of supported tools. Call this once per session before drafting any content to verify the running process is not stale after a deploy. Idempotent, no side effects, < 50 ms. If server_version is below the minimum required by your skill, STOP and ask the user to restart Claude Desktop.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false, and openWorldHint=false. The description reinforces idempotency and adds value beyond the annotations with 'no side effects' and a latency bound ('< 50 ms'), plus the staleness-check workflow. It does not add auth or rate-limit context, but the annotation coverage is strong, so a 4 is warranted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The return fields and the once-per-session guidance are front-loaded and efficient. The leading 'Calculation, not advice. Verify with a professional before acting.' is boilerplate disclaimer that is relevant but not strictly about this tool, keeping it short of a perfect 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-value burden, and it lists all returned fields explicitly. For a zero-parameter, read-only diagnostic tool, this is fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the rubric the baseline is 4. The description correctly adds no parameter guidance because none is needed, and schema coverage is 100%.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Returns metadata about the running Senaro MCP server') and enumerates exactly what is returned: version, contract version, build commit, build timestamp, and supported tools. This clearly distinguishes it from the financial-calculation siblings, none of which are server/diagnostic tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit timing ('Call this once per session before drafting any content') and the reason ('to verify the running process is not stale after a deploy'). It even prescribes a conditional action on the result: if server_version is below the required minimum, STOP and ask the user to restart. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
18 tool updates
- First observed
analyze_cash_advance - First observed
analyze_pmi_removal - First observed
calculate_cc_payoff - First observed
calculate_debt_to_income - First observed
calculate_emergency_fund - First observed
calculate_loan_payoff - First observed
calculate_opportunity_cost - First observed
calculate_runway - First observed
compare_debt_consolidation - First observed
compare_mortgage_terms - First observed
compare_strategies - First observed
compound_interest - First observed
list_defaults - First observed
optimize_401k_match - First observed
payoff_vs_invest - First observed
refi_breakeven - First observed
rent_vs_buy - First observed
server_info
Related MCP Connectors
Free, deterministic 530A (Trump Account) projections, verified rules, and searchable guides.
Finance canon lookup plus 30 deterministic formulas, each with a verifiable receipt.
Deterministic signed verification of numeric & financial claims for AI agents & spreadsheets.
Verifiable, deterministic risk math for autonomous agents; re-runnable proof on every answer.
Related MCP Servers
- AlicenseAqualityBmaintenanceUS federal student loan repayment math for AI agents, from a parity-verified engine rather than estimated. RAP, IBR, ICR, PAYE and tiered Standard payments with forgiveness timing and tax on forgiveness, plus the plans a borrower is excluded from and the rule why, such as Parent PLUS not qualifying for RAP. No key to start; keyed answers at mcp.finology.tech/mcp add citations.3926MIT
- AlicenseAqualityBmaintenanceDeterministic day-count and accrued-interest engine. Six ISDA/ICMA conventions, proven exact against QuantLib over 3,600 date pairs. Stops the AI guessing your interest math.31471MIT
- FlicenseNot gradedqualityCmaintenanceEnables precise financial analysis of AI agent costs, including token pricing, multi-step run estimates, model comparison, and ROI versus human labor, with deterministic decimal math.-
- AlicenseCqualityBmaintenanceDeterministic Odoo ERP calculators: implementation, migration and upgrade cost, ROI and TCO, US/Canada/EU sales tax and VAT, Canadian payroll source deductions, and inventory maths (reorder point, safety stock, EOQ, landed cost, OEE). 24 tools, each a pure function, the numbers are arithmetic rather than a model's guess. Hosted remote server, no install and no API key; a stdio bridge is included24MIT