# RateAPI — live US mortgage, auto, HELOC, personal & deposit rates (remote · mcp.rateapi.dev)

Live US mortgage, auto, HELOC, personal & deposit rates with evidence, plus who can join each lender

- Trust score: 83/100 (high trust)
- Change this week: +3
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-21

## Components

- remote · `mcp.rateapi.dev`: 83/100 (this document), [markdown](https://verifymcp.io/servers/dev-rateapi-mcp/mcp.md), [page](https://verifymcp.io/servers/dev-rateapi-mcp/mcp)

## Channel facts

- Endpoint: `https://mcp.rateapi.dev/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `1.0.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-21.

- **Endpoint Security**: 78/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS enforcement could not be verified: the plaintext port answered with HTTP 405, which proves neither a plaintext path nor enforcement.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server offers only Dynamic Client Registration (RFC 7591), which MCP 2026-07-28 deprecated in favour of Client ID Metadata Documents.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 79/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 21726 tokens (~188/item across 115 items; 89 tools + 26 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 80/100
  - Stability observed for 24 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 98/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 95% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - All 10 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.
  - An AI judge read all 91 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 60/100
  - Spec-recency check failed: implements MCP spec 2025-03-26; the latest is 2026-07-28.
  - Supports UI / widget rendering.

## Install

### How do I install the RateAPI — live US mortgage, auto, HELOC, personal… MCP server?

RateAPI — live US mortgage, auto, HELOC, personal… is a hosted endpoint at https://mcp.rateapi.dev/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add --transport http dev-rateapi-mcp 'https://mcp.rateapi.dev/mcp'
```

### Cursor

```json
{
  "mcpServers": {
    "dev-rateapi-mcp": {
      "url": "https://mcp.rateapi.dev/mcp"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "dev-rateapi-mcp": {
      "type": "http",
      "url": "https://mcp.rateapi.dev/mcp"
    }
  }
}
```

### Codex

```toml
[mcp_servers.dev-rateapi-mcp]
url = "https://mcp.rateapi.dev/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "dev-rateapi-mcp": {
      "type": "remote",
      "url": "https://mcp.rateapi.dev/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add dev-rateapi-mcp --url 'https://mcp.rateapi.dev/mcp' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  dev-rateapi-mcp:
    url: "https://mcp.rateapi.dev/mcp"
```

### Netclaw

```json
{
  "McpServers": {
    "dev-rateapi-mcp": {
      "Transport": "http",
      "Url": "https://mcp.rateapi.dev/mcp"
    }
  }
}
```

### Vellum

```bash
assistant mcp add dev-rateapi-mcp -t streamable-http -u 'https://mcp.rateapi.dev/mcp'
```

### Other

```json
{
  "mcpServers": {
    "dev-rateapi-mcp": {
      "type": "http",
      "url": "https://mcp.rateapi.dev/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-21 (score 83, +1)

No change was recorded against any check on this day. Stability & Change Management went from 77 to 80. That category is still filling its 30-day observation window: 23 days of observed history at the previous scan, 24 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-19 (score 82, +1)

- [functional regression] Resource “Quickstart: your first RateAPI call” was removed
- [functional] New resource “Quickstart: choose the CLI, MCP, or REST”

### 2026-09-17 (score 81, +1)

No change was recorded against any check on this day. Stability & Change Management went from 63 to 67. That category is still filling its 30-day observation window: 19 days of observed history at the previous scan, 20 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-14 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 53 to 57. That category is still filling its 30-day observation window: 16 days of observed history at the previous scan, 17 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-12 (score 79, +1)

No change was recorded against any check on this day. Stability & Change Management went from 47 to 50. That category is still filling its 30-day observation window: 14 days of observed history at the previous scan, 15 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-10 (score 78, +1)

No change was recorded against any check on this day. Stability & Change Management went from 40 to 43. That category is still filling its 30-day observation window: 12 days of observed history at the previous scan, 13 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-08 (score 77, +1)

- [security] The server rewrote its instructions, which are the text every model session reads
- [security] Tool “get_eligibility_coverage” rewrote its description, which is the text the model reads
- [security] Tool “search_eligibility_entities” rewrote its description, which is the text the model reads
- [cosmetic] “search_eligibility_entities” reworded the description of “query”
- [cosmetic] “search_eligibility_entities” made “query” optional

### 2026-09-07 (score 76, 0)

- [security] The server rewrote its instructions, which are the text every model session reads
- [security] Tool “find_reachable_offers” rewrote its description, which is the text the model reads
- [functional] New tool “compare_personal_access_catalogs”
- [functional] New tool “compare_reachable_offers”
- [functional] New tool “evaluate_eligibility_cohort”
- [functional] New tool “get_eligibility_changes”
- [functional] New tool “get_personal_access_catalog”
- [functional] New tool “get_product_access_envelopes”
- [functional] New tool “resolve_eligibility_entities”
- [functional] New tool “search_eligibility_entities”
- [cosmetic] “check_membership_eligibility” added an optional parameter “association_org_ids”
- [cosmetic] “check_membership_eligibility” added an optional parameter “employer_org_ids”
- [cosmetic] “check_membership_eligibility” added an optional parameter “relative_association_org_ids”
- [cosmetic] “check_membership_eligibility” added an optional parameter “relative_employer_org_ids”
- [cosmetic] “check_membership_eligibility” added an optional parameter “relative_school_org_ids”
- [cosmetic] “check_membership_eligibility” added an optional parameter “school_org_ids”
- [cosmetic] “check_membership_eligibility” added an optional parameter “worship_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “association_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “employer_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “relative_association_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “relative_employer_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “relative_school_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “school_org_ids”
- [cosmetic] “find_eligible_credit_unions” added an optional parameter “worship_org_ids”
- [cosmetic] “find_reachable_offers” reworded the description of “person”

## MCP tools (89)

### `get_financing_decision` (~1257 tokens)

RECOMMENDED WHEN SHOPPING: Get personalized financing recommendations for ANY loan or credit product across every major type: mortgages (30yr/15yr/20yr/10yr fixed and ARMs), auto loans (new/used/CPO, 36-84 month terms), RV/boat/motorcycle/powersports loans, HELOCs (fixed/variable), personal loans (secured/unsecured), student loans, equipment loans, and credit cards (rewards, cash_back, secured, balance_transfer, low_rate, business, platinum, student). Analyzes current market offers and returns actionable recommendations with explanations. Use this instead of looking up raw rates when the user is asking "what rate can I get?" and does NOT yet have an offer. IMPORTANT: if the user ALREADY has a quoted rate and is asking whether it is good/fair/competitive ("I was quoted 6.9%, is that any good?"), call rate_sanity_check instead — it returns a percentile verdict on their specific number, which is what that question is actually asking. Provide the user's state, intent (purchase/refinance/cash_out/balance_transfer/new_credit), and amount for personalized advice.

Input parameters:

- `amount` (number, required): Loan amount in dollars (minimum 1000). Required.
- `county` (string): User's county for membership-eligibility matching (credit union field-of-membership). Helps flag which lenders the user can actually join.
- `credit_score` (number): Borrower's credit score (300-850). Highly recommended for accurate rate matching.
- `current_apr` (number): Current offer APR if refinancing (percentage).
- `current_rate` (number): Current offer rate if refinancing (percentage, e.g., 6.5 for 6.5%).
- `eligible_only` (boolean): BETA (annotation-only): eligible_only is in beta pending identity-verification thresholds; offers are annotated, not filtered. Setting true adds an eligible_only_status notice to the response — eligi…
- `employer` (string): User's employer, matched against credit union employer/SEG membership lists for eligibility.
- `include_institution_context` (boolean): Optional: Include compact NCUA quarterly facts on each final offer (members, locations, assets, year opened, and selected relationship services).
- `include_out_of_state` (boolean): Optional: Include documented out-of-state open or multi-state credit-union candidates. Defaults to false, which preserves the requested-state candidate set.
- `intent` (string, required): The loan intent. For mortgages, use "purchase" or "refinance". For auto loans, use "purchase" (new/used car) or "refinance" (existing auto loan). Required.
- `max_providers` (number): Maximum number of providers to return (1-5). Defaults to 5.
- `military_status` (string): User's military affiliation. Annotates offers with eligible_via_military where the credit union has a military field of membership.
- `no_points` (boolean): If true, prefer no-points loans only. Applies to mortgages.
- `product_type` (string): Type of financing product: "mortgage" (FIXED-rate home purchase/refinance), "mortgage_arm" (ADJUSTABLE-rate mortgage), "auto_loan" (vehicle financing), "heloc" (home equity line of credit), "personal…
- `school` (string): User's school/college/university. Supply school_relationship too; a school name alone does not affirm a typed eligibility path.
- `school_relationship` (string): How the user relates to the named school. Required with school to affirm a typed student, alumni, or school-employee path.
- `state` (string, required): Valid 50-state/DC code (2-letter, e.g., CA, TX, NY). Required; lowercase is accepted and normalized.
- `term_months` (number): Loan term in months (12-480). Defaults to 360 (30-year) for mortgages, 60 (5-year) for auto loans. Common auto loan terms: 36, 48, 60, 72, 84 months. Common mortgage terms: 180 (15-year), 360 (30-yea…
- `vehicle_condition` (string): AUTO LOANS ONLY: Condition of the vehicle being purchased or refinanced. Affects rate eligibility.
- `vehicle_type` (string): AUTO LOANS ONLY: Type of vehicle being financed. Some lenders offer specialized rates by vehicle type.
- `vehicle_year` (number): AUTO LOANS ONLY: Model year of the vehicle (e.g., 2024, 2020). Used to determine age-based rate tiers.
- `worship` (string): User's place of worship, used to annotate offers with worship-org-affinity eligibility.
- `zip` (string): User's US 5-digit ZIP or ZIP+4. Resolves to a county server-side for membership-eligibility matching; its crosswalk state must agree with state.

Output parameters:

- `rate_range` (object): Span of rates across the offers considered, for framing how much shopping around is worth.
- `recommendation` (object): The recommended course of action and how strongly it is held.
- `request_id` (string|null): Opaque identifier for this call, useful only for support or debugging; never show it to the user.
- `resolved_county` (object): County the supplied ZIP was resolved to, used for eligibility and local branch matching.
- `summary` (string|null): Headline verdict for the user in one line, e.g. 'Shop Around - Better rates available'.
- `top_offers` (array): Best live published offers for this scenario, already sorted best-first.
- `tradeoffs` (array): Costs, caveats, and conditions the user should weigh before acting, such as closing costs or membership requirements.
- `why` (array): Ordered reasons supporting the recommendation, each already written as a user-facing sentence.

### `list_credit_unions` (~142 tokens)

Reference tool: Discover credit unions by state or nearest to a 5-digit ZIP. State listings include rate availability, member count, and reported location count. ZIP discovery ranks NCUA-reported branches by estimated straight-line miles from the ZIP center. For personalized rate recommendations, use get_financing_decision instead.

Input parameters:

- `state` (string): Optional: Filter to a specific state (2-letter code). If not provided, returns all states.
- `zip` (string): Optional: Find the closest credit unions by NCUA-reported branch location. Distances are ZIP-centroid straight-line estimates. When supplied, ZIP discovery takes precedence over state listing.

Output parameters:

- `credit_unions` (array): The credit unions in this state, alphabetical by name.
- `state` (string|null): Lower-cased two-letter state code the listing is scoped to.
- `state_name` (string|null): Full state name, e.g. 'California'.
- `summary` (string|null): One-sentence plain-English summary of this result, safe to quote directly to the user.
- `total_credit_unions` (number|null): Number of credit unions known in this state, including those with no published rates.
- `verified_last_7_days` (number|null): How many have had their rates re-scraped and confirmed in the past 7 days; the rest may be staler.
- `with_rates` (number|null): How many of those credit unions currently have published rate data — always smaller than total_credit_unions.

### `find_credit_unions_near_zip` (~144 tokens)

Use when someone asks for "credit unions near me," the closest credit union, local credit-union branches, or nearby alternatives to a bank. Given a 5-digit ZIP, returns credit unions ordered by the estimated straight-line distance to each institution's closest NCUA-reported branch. Includes approximate miles, branch address, and profile identifiers for checking rates, services, and membership. Distances use ZIP centers and are not driving distance.

Input parameters:

- `max_results` (number): Maximum credit unions to return (1-25, default 10).
- `zip` (string, required): Five-digit US ZIP code used as the center of the nearest-branch search.

Output parameters:

- `credit_unions` (array): Nearest credit unions, closest first.
- `disclosure` (string|null): Precision and methodology caveat for the distances and locations above; carry it into any answer that quotes them.
- `match_quality` (string|null): How precise the proximity ranking is overall, e.g. 'ZIP-centroid straight-line estimate'. Distances are as-the-crow-flies, not driving distance.
- `query` (object): The lookup that was performed, echoed back.
- `summary` (string|null): One-sentence plain-English summary of this result, safe to quote directly to the user.

### `find_product_rates_near_zip` (~244 tokens)

Use when someone asks for the best mortgage, auto-loan, HELOC, personal-loan, student-loan, equipment-loan, or credit-card rates near them and provides a ZIP. Finds the nearest NCUA-reported branch set, keeps credit unions with a current product-matched published rate, and ranks those offers by lowest APR with approximate distance as a tie-breaker. HELOC matching excludes closed-end home-equity loans. This is a local shopping shortlist: distance is straight-line, membership is not guaranteed, and published APR is not personalized approval.

Input parameters:

- `max_offers` (number): Maximum product-matched offers to return (1-8, default 5).
- `product_type` (string, required): Product whose current published rates should be compared.
- `term_months` (number): Optional comparable loan term. For fixed mortgages, under 300 months selects the 15-year market and 300+ selects 30-year.
- `vehicle_condition` (string): Auto loans only. Omit to use the new-auto market.
- `zip` (string, required): Five-digit US ZIP code used as the center of the nearby-branch search.

Output parameters:

- `disclosure` (string|null): Precision and methodology caveat for the distances and locations above; carry it into any answer that quotes them.
- `nearby_credit_union_count` (number|null): How many credit unions were found near this ZIP before filtering to those publishing this product; `offers` is usually shorter.
- `offers` (array): Published offers from nearby credit unions, ordered by the rule in `ranked_by`.
- `precision` (string|null): Overall precision of the distance estimates, e.g. 'ZIP-centroid straight-line estimate'.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `ranked_by` (string|null): The ordering rule applied to `offers`, e.g. lowest APR among credit unions with nearby reported branches — proximity filters the set, price sorts it.
- `unavailable_reason` (string|null): Why `offers` is empty, present only when it is — e.g. no credit union near that ZIP publishes the requested product. Quote this rather than telling the user no rates exist.
- `zip` (string|null): Five-digit ZIP code the search was centered on.

### `get_credit_union` (~149 tokens)

Reference tool: Get a credit union's rates, membership eligibility, and source-labelled NCUA quarterly profile: members, assets, year opened, charter, reported services, and branch locations. Eligibility annotates published criteria and never asserts that an individual is ineligible; profile facts are regulatory snapshots, not live prices. Use this when a user asks about a specific credit union. For personalized rate recommendations, use get_financing_decision instead.

Input parameters:

- `slug` (string, required): Credit union slug (URL-friendly name, e.g., "navy-federal-credit-union"). Required.
- `state` (string, required): US state code (2-letter, e.g., CA, TX, NY). Required.

Output parameters:

- `all_rates` (array): Every rate currently on file for this credit union, deposits and loans together.
- `best_rate` (object): The single most attractive rate on file for this credit union across every product it publishes — it may be a deposit product, so check `product` before calling it a loan rate.
- `credit_union` (object): Core identity and freshness facts for this credit union.
- `eligibility` (object): Who may join this credit union, derived from its published membership criteria — guidance, not an underwriting decision.
- `ncua_profile` (object): Institution facts from the NCUA quarterly call report — regulator-filed data, independent of the scraped rates.
- `summary` (string|null): One-sentence plain-English summary of this result, safe to quote directly to the user.
- `widget` (object): Pre-built embeddable rendering of this credit union's rates for UI surfaces; ignore it when composing a text answer.

### `check_membership_eligibility` (~2215 tokens)

\`relative_memberships` carries confirmed current/deceased relative membership scoped to one exact target credit union; one institution is never reused for another. Check whether a user can JOIN specific credit unions (field-of-membership eligibility). Batch-friendly: pass 1-50 credit_union_ids (from get_financing_decision offers, list_credit_unions, or get_credit_union) plus whatever is known about the user (home, worksite, and payroll geography are independent facts; employer, occupation, military_status, school plus school_relationship, and worship are also supported). City facts require their same-role state or a recognized same-role ZIP that uniquely identifies one state, and are accepted only when the closed Census gazetteer resolves them. Returns one row for every requested credit union. Positive outcomes include open_to_anyone, likely_eligible, eligible_via_employer, and eligible_via_military. A school name alone is not a positive signal: school_relationship is required to affirm a typed student, alumni, or school-employee path. Only a graph carrying exact active-publication lineage governs the top compatibility verdict; a publication-less shadow graph remains diagnostic and cannot replace the flat result. A non-match is returned as unknown, with `unknown_reason: fom_completeness_unaffirmed` when the published field-of-membership corpus is not attested complete. The legacy `geo_mismatch` enum value is reserved for wire compatibility and is not emitted by this MCP boundary without a future typed closed-world attestation. Verdicts are guidance based on each credit union's published membership criteria; the final membership determination is always the institution's. Non-matches carry `missing_facts` for the named institutions: the exact question to ask next, the `fact_field` an answer populates, and the institution's own words. A check that returns unknown for all of them and a question for each is a SUCCESSFUL call, not a failure — ask the questions, merge the…

Input parameters:

- `applicant_kind` (string): What the applicant IS. Some charters admit entities as well as people. Absent means a natural person; a person is never rejected by an entity-only door, only left unknown.
- `asserted_org_qualifiers` (array): Narrowings the user asserts about themselves, quoted back from a missing_facts question (e.g. "assigned as Recruiters or ROTC Instructors within the State of Arkansas"). Absence caps a narrowed door…
- `association_org_ids` (array): Canonical association ids selected through resolve_eligibility_entities; each is type- and publication-revalidated.
- `county` (string): User's home county for residence matching. Original name; home_county is an equivalent merge-and-retry alias.
- `credit_union_ids` (array, required): Credit union ids to check (1-50), e.g. from get_financing_decision offers or list_credit_unions. Required.
- `employer` (string): User's employer, matched against credit union employer/SEG membership lists.
- `employer_org_ids` (array): Canonical employer ids selected through resolve_eligibility_entities. The API revalidates entity type and active-publication authority before use.
- `facility_city` (string): Census-recognized city where the user's business maintains a location. Requires facility_state or a recognized facility_zip that uniquely identifies one state.
- `facility_county` (string): County where the user's business maintains a location.
- `facility_state` (string): State where the user's business maintains a location.
- `facility_zip` (string): ZIP where the user's business maintains a location. Distinct from the worksite ZIP.
- `family_relation` (string): How the user relates to a RELATIVE whose own affiliations may qualify them (e.g. 'spouse', 'child', 'immediate family'). Required alongside relative_employers/relative_schools/relative_associations —…
- `home_city` (string): User's Census-recognized home city. Requires state or a recognized zip that uniquely identifies one state; unresolved labels are rejected rather than guessed.
- `home_county` (string): Alias for county, accepted so missing_facts can be merged into this same tool request. Conflicting duplicate forms are rejected.
- `home_state` (string): Alias for state, accepted so missing_facts can be merged into this same tool request. Conflicting duplicate forms are rejected.
- `home_zip` (string): Alias for zip, accepted so missing_facts can be merged into this same tool request. It must agree with state/home_state when either is supplied; conflicting duplicate forms are rejected.
- `military_service_state` (string): The state the user serves, or served, in. State National Guard doors ("Oklahoma National Guard") need this; without it such a door reads unknown.
- `military_status` (string): User's military affiliation, matched against military field-of-membership (yields eligible_via_military).
- `occupation` (string): User's occupation, matched against trade/industry/profession (TIP) charters.
- `payroll_city` (string): Census-recognized payroll city. Requires payroll_state or a recognized payroll_zip that uniquely identifies one state.
- `payroll_county` (string): County from which the user's employer issues payroll. This is distinct from work_county.
- `payroll_state` (string): Valid state code from which the user's employer issues payroll. This is distinct from work_state.
- `payroll_zip` (string): ZIP from which the user's employer issues payroll. This is distinct from the worksite ZIP.
- `property_city` (string): Census-recognized city where the user owns real property. Requires property_state or a recognized property_zip that uniquely identifies one state.
- `property_county` (string): County where the user owns real property. Distinct from home_county.
- `property_state` (string): State where the user owns real property. Distinct from home_state.
- `property_zip` (string): ZIP where the user OWNS REAL PROPERTY. A door of its own — never inferred from where they live, and an absentee owner qualifies.
- `relative_association_org_ids` (array): Canonical association ids for the relative named by family_relation, never for the applicant.
- `relative_associations` (array): Associations the RELATIVE named by family_relation belongs to. Optional; same unknown-by-default contract as relative_employers.
- `relative_employer_org_ids` (array): Canonical employer ids for the relative named by family_relation, never for the applicant.
- `relative_employers` (array): Employers of the RELATIVE named by family_relation (not the user's own employer). Optional; omitting it leaves compound family doors undecided (unknown), never negative.
- `relative_memberships` (array): Confirmed relative memberships scoped to one exact credit union. A membership at one institution is never reused for another; omit unconfirmed memberships and the corresponding family door remains un…
- `relative_school_org_ids` (array): Canonical school ids for the relative named by family_relation, never for the applicant.
- `relative_schools` (array): Schools the RELATIVE named by family_relation attends. Optional; same unknown-by-default contract as relative_employers.
- `school` (string): User's school/college/university. Supply school_relationship too; the school name alone does not affirm eligibility.
- `school_org_ids` (array): Canonical school ids selected through resolve_eligibility_entities; never populate these from prose extraction.
- `school_relationship` (string): How the user relates to the named school. Required with school to affirm a typed student, alumni, or school-employee path.
- `state` (string): User's valid 50-state/DC code for geographic field-of-membership matching. Lowercase is accepted and normalized.
- `work_city` (string): Census-recognized city where the user works. Requires work_state or a recognized work_zip that uniquely identifies one state.
- `work_county` (string): County where the user works, for work-area membership matching.
- `work_state` (string): Valid 50-state/DC code where the user works, for work-area membership matching. Lowercase is accepted and normalized.
- `work_zip` (string): User's US 5-digit work ZIP or ZIP+4. Resolves to a work county server-side; when work_state is supplied, the crosswalk must agree with it.
- `worship` (string): User's place of worship, matched against worship-org affinity lists (yields likely_eligible).
- `worship_org_ids` (array): Canonical worship-organization ids selected through resolve_eligibility_entities.
- `zip` (string): User's US 5-digit ZIP or ZIP+4. Resolves to a county server-side; when state is supplied, the ZIP crosswalk must agree with it.

Output parameters:

- `checked` (number|null): Number of credit unions evaluated in this call, matching the length of `verdicts`.
- `engine` (string|null): `eligibility_publication_v1` when at least one verdict was decided from an exact active publication; `legacy+graph_shadow` for compatibility output.
- `note` (string|null): Required caveat that eligibility is guidance from published criteria and the credit union makes the final decision.
- `summary` (string|null): One-sentence plain-English summary of this result, safe to quote directly to the user.
- `verdicts` (array): One eligibility assessment per credit union requested, in the order supplied.

### `find_eligible_credit_unions` (~2434 tokens)

\`relative_memberships` carries confirmed current/deceased relative membership scoped to one exact target credit union; one institution is never reused for another. `next_questions.unlocks_cu_count` counts membership decisions an answer may clarify, never guaranteed products. Discovery tool: find candidate credit unions a person may be able to JOIN, from their own facts rather than from a list of institutions. Pass any combination of home, worksite, or payroll geography (these are independent), occupation, employer, school (+school_relationship), associations, military_status, and worship; at least one discriminating fact is required, or pass willing_to_join_association=true as the sole discriminator to search documented joinable-association paths. City facts require their same-role state or a recognized same-role ZIP that uniquely identifies one state, and are accepted only when the closed Census gazetteer resolves them. This evaluates a bounded, prioritized candidate set, not the entire credit-union fleet: read `candidate_limit`, `candidate_set_truncated`, and `candidate_sources`, and never interpret an absent institution as unavailable or ineligible. Returns four buckets within that candidate set — eligible (a verified path already applies), conditionally_eligible (one more step, e.g. joining an association, with the cost and join URL when known), possibly_eligible (a path may apply but a requirement could not be confirmed), and unknown (we could not decide — either we hold no rules for the institution or the supplied facts cannot decide the rules we hold). Every non-positive entry carries a machine-readable `unknown_reason`: `geo_inputs_missing` / `org_inputs_missing` / `inputs_missing` mean ONE MORE FACT FROM THE USER would resolve it, so ask for it and call again; `no_rules` means we hold nothing for that institution and asking will not help; `incomplete_fom`, `fom_completeness_unaffirmed`, `low_confidence_rules` and `unmodeled_condition` mean we hold rules bu…

Input parameters:

- `applicant_kind` (string): What the applicant IS. Some charters admit entities as well as people. Absent means a natural person; a person is never rejected by an entity-only door, only left unknown.
- `asserted_org_qualifiers` (array): Narrowings the user asserts about themselves, quoted back from a missing_facts question (e.g. "assigned as Recruiters or ROTC Instructors within the State of Arkansas"). Absence caps a narrowed door…
- `association_org_ids` (array): Canonical association ids selected through resolve_eligibility_entities; each is type- and publication-revalidated.
- `associations` (array): Associations, unions, or member organizations the user already belongs to.
- `employer` (string): User's employer, resolved to a canonical organization for SEG matching.
- `employer_org_ids` (array): Canonical employer ids selected through resolve_eligibility_entities. The API revalidates entity type and active-publication authority before use.
- `facility_city` (string): Census-recognized city where the user's business maintains a location. Requires facility_state or a recognized facility_zip that uniquely identifies one state.
- `facility_county` (string): County where the user's business maintains a location.
- `facility_state` (string): State where the user's business maintains a location.
- `facility_zip` (string): ZIP where the user's business maintains a location. Distinct from the worksite ZIP.
- `family_relation` (string): How the user relates to a RELATIVE whose own affiliations may qualify them (e.g. 'spouse', 'child', 'immediate family'). Required alongside relative_employers/relative_schools/relative_associations —…
- `home_city` (string): User's Census-recognized home city. Requires home_state or a recognized home_zip that uniquely identifies one state; unresolved labels are rejected rather than guessed.
- `home_county` (string): User's county. Wins over the ZIP-derived counties when supplied.
- `home_state` (string): User's valid 50-state/DC code (e.g., CA, TX, NY). Lowercase is accepted and normalized.
- `home_zip` (string): User's US 5-digit home ZIP or ZIP+4. Resolves to candidate counties; when home_state is supplied, the crosswalk must agree with it.
- `limit` (number): Maximum entries per bucket (1-200). Default 50.
- `military_service_state` (string): The state the user serves, or served, in. State National Guard doors ("Oklahoma National Guard") need this; without it such a door reads unknown.
- `military_status` (string): User's military affiliation, matched against military fields of membership.
- `occupation` (string): User's occupation, matched against trade, industry, and profession fields of membership.
- `payroll_city` (string): Census-recognized city from which payroll is issued. Requires payroll_state or a recognized payroll_zip that uniquely identifies one state.
- `payroll_county` (string): County from which the user's employer issues payroll; distinct from work_county.
- `payroll_state` (string): State from which the user's employer issues payroll; distinct from work_state.
- `payroll_zip` (string): ZIP from which the user's employer issues payroll; distinct from the worksite ZIP. When payroll_state is supplied, the ZIP must agree with it.
- `property_city` (string): Census-recognized city where the user owns real property. Requires property_state or a recognized property_zip that uniquely identifies one state.
- `property_county` (string): County where the user owns real property. Distinct from home_county.
- `property_state` (string): State where the user owns real property. Distinct from home_state.
- `property_zip` (string): ZIP where the user OWNS REAL PROPERTY. A door of its own — never inferred from where they live, and an absentee owner qualifies.
- `relative_association_org_ids` (array): Canonical association ids for the relative named by family_relation, never for the applicant.
- `relative_associations` (array): Associations the RELATIVE named by family_relation belongs to. Optional; same unknown-by-default contract as relative_employers.
- `relative_employer_org_ids` (array): Canonical employer ids for the relative named by family_relation, never for the applicant.
- `relative_employers` (array): Employers of the RELATIVE named by family_relation (not the user's own employer). Optional; omitting it leaves compound family doors undecided (unknown), never negative.
- `relative_memberships` (array): Confirmed relative memberships scoped to one exact credit union. A membership at one institution is never reused for another; omit unconfirmed memberships and the corresponding family door remains un…
- `relative_school_org_ids` (array): Canonical school ids for the relative named by family_relation, never for the applicant.
- `relative_schools` (array): Schools the RELATIVE named by family_relation attends. Optional; same unknown-by-default contract as relative_employers.
- `school` (string): User's school/college/university, resolved to a canonical organization. Supply school_relationship too; a name alone is not a positive match.
- `school_org_ids` (array): Canonical school ids selected through resolve_eligibility_entities; never populate these from prose extraction.
- `school_relationship` (string): How the user relates to the school. Required with school to affirm a typed student, alumni, or school-employee path.
- `willing_to_join_association` (boolean): Set true to search documented joinable-association paths (valid as the sole discriminator). Set false only to suppress paths that require joining an association; false alone is not a discriminating s…
- `work_city` (string): Census-recognized city where the user works. Requires work_state or a recognized work_zip that uniquely identifies one state.
- `work_county` (string): County where the user works. Wins over work-ZIP-derived counties when supplied.
- `work_state` (string): Valid 50-state/DC code where the user works (e.g., CA, TX, NY). Lowercase is accepted and normalized.
- `work_zip` (string): User's US 5-digit work ZIP or ZIP+4. Resolves to candidate work counties; when work_state is supplied, the crosswalk must agree with it.
- `worship` (string): User's place of worship, resolved to a canonical organization.
- `worship_org_ids` (array): Canonical worship-organization ids selected through resolve_eligibility_entities.

Output parameters:

- `candidate_limit` (number|null): Maximum unique candidates this search can accept for evaluation (currently 400).
- `candidate_set_truncated` (boolean|null): True when the overall candidate cap or any source-query cap may have omitted additional institutions; absence from the response is never a negative verdict.
- `candidate_sources` (object): Unique candidates accepted in deterministic priority order from each narrowing source.
- `candidates_evaluated` (number|null): How many credit unions in the bounded, prioritized candidate set were evaluated; not the number of institutions in the fleet.
- `conditionally_eligible` (array): Credit unions joinable after one more step, with its cost when known.
- `counts` (object): Size of each bucket within the bounded candidate set before the per-bucket `limit` is applied; not fleet-wide totals.
- `disclosure` (string|null): Required disclosure that eligibility is guidance and the institution decides.
- `eligible` (array): Credit unions with a verified membership path that already applies to this person.
- `engine` (string|null): Which engines produced these verdicts.
- `limit` (number|null): Maximum entries returned per bucket for this call.
- `missing_facts_truncated` (boolean|null): True when a size cap dropped a question that could otherwise have been asked (3 per institution, 5 in the rollup, 20 unlock ids per rollup entry). The same honesty convention as candidate_set_truncat…
- `next_questions` (array|null): Questions ranked across every institution evaluated, by how many each unlocks. Ask the top one to three, merge the answers into the same request body, and call again. Stop when this is empty, when th…
- `note` (string|null): Liability framing to surface alongside any eligibility claim.
- `possibly_eligible` (array): Credit unions where a path may apply but a requirement could not be confirmed.
- `resolved` (object): Canonical organizations and geography keys resolved from the supplied facts.
- `unanswerable` (array|null): What no question can fix, and why. Do not ask the user about these. Absent when everything unresolved is askable.
- `unknown` (array): Credit unions whose rules could not be decided from the supplied facts. Never an assertion of ineligibility.

### `find_reachable_offers` (~321 tokens)

Find the best fresh, evidence-backed credit-union rates reachable from this person’s membership facts. This composed graph-first operation evaluates the complete active US credit-union fleet BEFORE rates are queried, so a strong out-of-state employer, association, school, military, family, property, work/payroll, or facility door is not lost behind a candidate cap or state-only rate search. `reachable_now` requires a verified membership path, satisfied supplied product dimensions, and fresh evidenced published pricing; `reachable_after_action` requires the same product proof plus a documented membership action. Unknown or mismatched term, intent, vehicle condition, or occupancy remains `unresolved`, never silently matched. `no_published_offer` means no matching fresh evidenced rate was found. Deposits rank published APY only. Lending ranks published APR rows first and separately labeled nominal-rate rows second, never comparing APR and rate as one measure. Every price includes verbatim evidence and as_of, and routed membership results preserve graph/publication lineage and source proof. Use product-aware questions only as bounded facts that may clarify. Published pricing is not approval or guaranteed final availability.

Input parameters:

- `limit` (number): Visible offers per bucket, 1-50. Candidate intersection happens before this cap.
- `person` (object, required): Confirmed person facts accepted by find_eligible_credit_unions, including canonical *_org_ids selected through resolve_eligibility_entities. Unknown facts stay absent and canonical ids are revalidate…
- `product` (object, required): The financial product and matching attributes to route.

Output parameters:

- `as_of` (string|null): Most recent observation timestamp among returned rates.
- `completeness` (object): Honest evaluation and display-cap metadata, including current-publication-only membership proof semantics.
- `counts` (object): Full pre-display-cap counts for each reachability bucket.
- `disclosure` (string|null): Required distinction between evidence-backed routing, published pricing, final availability, and approval.
- `discovery` (object): Graph retrieval telemetry. candidate_scope=active_fleet and candidate_set_truncated=false prove exhaustive evaluation.
- `eligibility_snapshot` (object): Immutable eligibility graph generation and pinned rules clock used for this result when snapshot serving is available.
- `no_published_offer` (array): Graph-positive institutions without a matching fresh evidenced rate; absence remains unknown.
- `product` (object): Normalized product request used for matching.
- `ranking_basis` (string|null): Deposits rank by higher published APY. Lending ranks published APR rows first by lower APR, then separately labeled nominal-rate rows by lower rate; APR and rate are never numerically compared. Membe…
- `reachable_after_action` (array): Offers with a documented membership action and a fresh, evidenced published rate.
- `reachable_now` (array): Offers with a verified membership path and a fresh, evidenced published rate.
- `semantics` (string|null): The positive-evidence-only interpretation contract.
- `unresolved` (array): Published-rate matches whose membership or rate proof remains incomplete, or whose membership path is only possible; unknown is not unavailable.

### `get_personal_access_catalog` (~209 tokens)

Evaluate one person across 1-19 explicit loan or deposit selectors using one exhaustive eligibility snapshot. Returns separate membership, published availability, product suitability, published pricing, underwriting, and approval layers. Lead only with reachable_now or reachable_after_action; unresolved and no_published_price are unknown, never a denial. Published APY, APR, or clearly labeled nominal rate is not a personalized quote, underwriting result, preapproval, commitment, or guarantee. Every returned published price carries source evidence and as_of.

Input parameters:

- `limit_per_product` (integer): Maximum detail rows for each selector, subject to the total and plan caps. Default 5.
- `person` (object, required): Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.
- `products` (array, required): One to nineteen unique explicit product selectors. Do not invent missing scenario facts.
- `total_limit` (integer): Maximum detail rows across all selectors; must be at least the selector count. Default 50.

Output parameters:

- `catalog_version` (string|null): Stable access-catalog response contract version.
- `completeness` (object): Fleet, selector, evaluation-strategy, cap, and truncation disclosure.
- `disclosure` (string|null): Required separation of membership, suitability, published pricing, underwriting, and approval.
- `products` (array): One result per selector in request order.
- `questions` (object): Membership questions shared across selectors.
- `semantics` (string|null): Positive-evidence-only interpretation contract; unknown never means ineligible.
- `snapshot` (object): Eligibility generation, rules clock, returned-price observation range, and generation time.

### `compare_personal_access_catalogs` (~190 tokens)

Compare baseline and candidate confirmed person facts across the same 1-19 explicit products. Both catalogs use one pinned immutable eligibility graph snapshot; rate rows retain independent evidence and as_of. Returns access, membership-path, and like-for-like published-price basis-point deltas: APY for deposits, APR for lending when both sides publish APR, otherwise nominal rate only when both sides publish nominal rate. It never mixes APR and nominal rate. Never describe missing access as denial or infer savings, underwriting, approval, or final terms.

Input parameters:

- `baseline_person` (object, required): Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.
- `candidate_person` (object, required): Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.
- `limit_per_product` (integer)
- `products` (array, required)
- `total_limit` (integer)

Output parameters:

- `baseline` (object): Full baseline access catalog.
- `candidate` (object): Full candidate access catalog.
- `comparison_version` (string|null): Stable comparison response contract version.
- `deltas` (object): Per-product and portfolio reachability, membership-path, and published-price deltas. Per-product and portfolio reachable_now_counts contain exact baseline, candidate, and net product-offer-row counts…
- `disclosure` (string|null): No savings, underwriting, approval, denial, or final-terms claim.
- `semantics` (string|null): Positive-evidence-only interpretation; absence is not denial.
- `snapshot` (object): Pinned eligibility rules time and immutable graph generation; rates retain independent row as_of.

### `search_eligibility_entities` (~198 tokens)

Browse or search canonical employers, associations, schools, or worship organizations that appear in positive conditions in current active eligibility publications. Omit query to browse by active-publication graph connectivity; that order is NOT popularity, quality, or a recommendation. With query, normalized exact matches rank before bounded prefix matches. A returned organization is a selectable fact, NOT proof that this person can join any credit union; use resolve_eligibility_entities for authoritative selection, then pass the returned org_id in the matching *_org_ids field to an eligibility tool. This authenticated discovery never loads a client-side corpus and accepts no personal profile.

Input parameters:

- `limit` (integer): Maximum results; the response discloses truncation.
- `query` (string): Optional organization name or prefix, 2-120 characters. Omit to browse by active-publication connectivity.
- `types` (array): Exact public organization types to search. Omit for all four types.

Output parameters:

- `disclosure` (string|null): Required warning that organization discovery does not prove eligibility.
- `normalized_query` (string|null): Canonical normalized text used for indexed exact and prefix matching.
- `query` (string|null): Trimmed search text supplied by the caller.
- `query_truncated` (boolean|null): Whether the accepted query text was truncated; currently always false because oversized input is rejected.
- `result_limit` (number|null): Requested result cap.
- `result_mode` (string|null): search for text-ranked results or most_connected for query-less graph-connectivity browse; neither is an eligibility verdict.
- `results` (array): Deterministically ranked canonical entity matches; these do not imply personal eligibility.
- `results_truncated` (boolean|null): True when more authorized matches existed than were returned.
- `semantics` (string|null): Machine-readable organization-discovery-not-eligibility contract.
- `types` (array): Exact public entity types included in the search.

### `resolve_eligibility_entities` (~128 tokens)

Resolve up to 50 typed organization names for canonical eligibility input. Only one exact normalized active-publication match with confidence of at least 0.8 is authoritative (`resolved`); a lower-confidence exact match remains `unresolved`, multiple exact matches are `ambiguous`, and prefix candidates are suggestions only. Never convert an unresolved, ambiguous, or suggested candidate into a person fact. Resolution identifies an organization and never establishes eligibility.

Input parameters:

- `candidate_limit` (integer): Maximum exact matches or prefix suggestions returned per input.
- `inputs` (array, required): Typed values to resolve in stable input order.

Output parameters:

- `disclosure` (string|null): Required warning that resolution does not prove eligibility.
- `prefix_candidates_are_suggestions` (boolean|null): True: prefix results must never be silently promoted to facts.
- `resolution_method` (string|null): Authority rule: one normalized-exact match with confidence of at least 0.8.
- `results` (array): One resolution result per input in the same order.
- `semantics` (string|null): Machine-readable organization-resolution-not-eligibility contract.

### `compare_reachable_offers` (~169 tokens)

Compare one baseline person-fact panel with one candidate panel against the same active eligibility snapshot and exact product request. Use this for explicit what-if questions such as adding a confirmed employer or association. Newly reachable means current positive evidence now proves a path; no_longer_reachable or absence never proves ineligibility. Supply only facts the person confirmed, preferably canonical *_org_ids from resolve_eligibility_entities. Person facts are forwarded transiently and are not stored by this tool.

Input parameters:

- `baseline_person` (object, required): Confirmed facts before the proposed change.
- `candidate_person` (object, required): Confirmed facts after the proposed change.
- `limit` (integer): Visible items per bucket and delta list.
- `product` (object, required): Exact product request used for both eligibility-backed rate evaluation and ranking.

Output parameters:

- `baseline` (object): Eligibility-backed offer buckets for the baseline facts.
- `candidate` (object): Eligibility-backed offer buckets for the candidate facts.
- `deltas` (object): Newly reachable, no-longer-reachable-or-unknown, changed-path, and best-offer comparisons with truncation flags.
- `disclosure` (string|null): Required limits on interpreting missing or changed results.
- `product` (object): Exact product request shared by both evaluations.
- `semantics` (string|null): Positive-evidence-only and unknown-is-never-ineligible contract.
- `snapshot` (object): Shared rules clock, serving-generation context, publication identities, and stated database consistency boundary.

### `get_product_access_envelopes` (~100 tokens)

Get non-personal, evidence-bound membership-access metadata for up to 50 exact deposit product references. Returns active-publication path kinds and documented joinable-association actions alongside the current evidenced product rate. This does NOT decide whether a person is eligible, easy to qualify, approved, or within a published balance/audience constraint; unavailable evidence stays unavailable.

Input parameters:

- `products` (array, required): Exact deposit product references; no fuzzy product matching is performed.

Output parameters:

- `counts` (object): Requested product and distinct institution counts.
- `disclosure` (string|null): Required warning against interpreting access metadata as personal eligibility or approval.
- `envelopes` (array): One access envelope per input in stable order.
- `semantics` (string|null): Non-personal, positive-documented-paths-only contract.

### `evaluate_eligibility_cohort` (~163 tokens)

Evaluate a caller-supplied panel of 1-10 named fact profiles for one exact product against one serving snapshot, deduplicating reachable institutions and exact offers. This is descriptive only for the supplied panel: never call it a population estimate, conversion rate, approval forecast, or negative eligibility result. Use neutral profile labels instead of names, emails, account numbers, or other direct identifiers. Profiles are forwarded transiently and are not stored by this tool; unknown remains unknown.

Input parameters:

- `limit` (integer): Maximum aggregate institutions and deduplicated offers returned.
- `product` (object, required): Exact product request used for both eligibility-backed rate evaluation and ranking.
- `profiles` (array, required): Caller-supplied named panel. Names must be unique within this request.

Output parameters:

- `aggregate` (object): Deduplicated reachable institutions and exact offers, profile reach, counts, and truncation flags.
- `disclosure` (string|null): Required warning that the panel is not a population estimate, conversion rate, approval forecast, or rejection.
- `methodology` (object): Panel size/source, deduplication identities, and explicit no-extrapolation/no-conversion semantics.
- `product` (object): Exact product request evaluated for the panel.
- `profiles` (array): Per-profile counts, best evidenced offer, and observation timestamp.
- `semantics` (string|null): Positive-evidence-only and unknown-is-never-ineligible contract.
- `snapshot` (object): Shared rules clock and database observation boundaries.

### `get_eligibility_changes` (~122 tokens)

Read the bounded, cursor-paginated feed of currently active eligibility publication replacements since an ISO timestamp. Use it to invalidate caches keyed by credit_union_id or publication identity. It exposes aggregate publication metadata only: no personal facts, no historical verdict, and no claim that a person is eligible or ineligible.

Input parameters:

- `cursor` (string): Opaque next_cursor from the prior page; do not construct or modify it.
- `limit` (integer): Maximum publication changes returned.
- `since` (string, required): Exclusive ISO 8601 activation boundary with an offset.

Output parameters:

- `changes` (array): Active publication replacements in stable ascending order.
- `disclosure` (string|null): Required warning that this is not a personal eligibility verdict or full history.
- `has_more` (boolean|null): Whether another page is available.
- `next_cursor` (string|null): Opaque cursor for the next page, or null.
- `ordering` (array): Stable ordering columns.
- `returned` (number|null): Number of changes in this page.
- `semantics` (string|null): Active-publication incremental cache-invalidation contract.
- `since` (string|null): Normalized exclusive activation boundary.

### `extract_eligibility_facts` (~319 tokens)

Turn a person's own words about themselves into the structured facts the eligibility tools accept. Pass their sentence verbatim ("I'm a nurse at a Tulsa hospital, I live in Broken Arrow, my late father was a TTCU member") and this returns each fact it could read, with the exact words it read it from, a confidence, and a needs_confirmation flag. THIS DOES NOT DECIDE ELIGIBILITY and never returns a credit union: it only fills in fields. Show the extracted facts to the user and get confirmation on every fact with needs_confirmation=true (family relationships, relatives' employers and associations, applicant kind, and asserted qualifiers are always flagged, because a wrong reading of those changes the answer). Then pass `person_search_body` — plus whatever the user confirmed — to find_eligible_credit_unions, which is what actually decides. If extraction is unavailable you get facts: [] and no eligibility signal at all; ask the user for fields directly instead. `confidence` is the extraction model's own uncalibrated self-report and gates only autofill — quote `evidence.quote` to the user, not the number. This call costs 3 API units.

Input parameters:

- `known_facts` (object): Optional. Fields you already know, in PersonSearch shape. These are echoed as source="supplied" and never overwritten.
- `text` (string, required): The person's own words, up to 2000 characters. Do not paraphrase or pre-structure it — the extractor needs the original sentence to anchor evidence spans.

Output parameters:

- `billed_units` (number|null): API units billed for this call: 3 for a live extraction, 0 for a sandbox fixture.
- `confidence_is_model_self_reported` (boolean|null): Always true when present. A standing warning that 'confidence' is the model's own number, not a measured accuracy.
- `confirmation_required` (boolean|null): True when anything needs confirming. Show the facts to the user before searching.
- `extraction_available` (boolean|null): False when extraction was unavailable. That carries no eligibility signal whatsoever - ask the user for fields directly, never read it as a negative answer.
- `extractor_version` (string|null): Version of the extractor's prompt and post-processing.
- `facts` (array): Facts read from the person's words, each returned FOR CONFIRMATION. Never a decision, and never a credit union.
- `model` (string|null): Extraction model identifier.
- `note` (string|null): Standing disclosure plus the next step: confirm the flagged facts, then call find_eligible_credit_unions.
- `person_search_body` (object|null): A ready-to-send argument set for find_eligible_credit_unions, containing only confirmed-or-supplied facts. Add the user's confirmations to it before calling.
- `sandbox` (boolean|null): True when this is the frozen sandbox fixture rather than a real extraction.
- `unparsed_spans` (array): Phrases recognized as meaningful but not mapped to a field, including anything said in the past tense or hypothetically. Ask about these.

### `create_monitor` (~185 tokens)

Create a new decision monitor that watches for rate changes and sends webhook notifications when conditions are met. Returns the monitor with a webhook_signing_secret for verifying webhook payloads.

Input parameters:

- `conditions` (array, required): Array of conditions that must be met to trigger the monitor. Required.
- `cooldown_hours` (number): Minimum hours between webhook triggers (1-168). Defaults to 24.
- `decision_context` (object, required): The context for evaluating rate changes. Required.
- `name` (string, required): A descriptive name for the monitor. Required.
- `subscribed_product_types` (array): Optional array of product types to monitor (e.g., ["30yr_fixed", "15yr_fixed"]).
- `subscribed_states` (array): Optional array of state codes to monitor. If not provided, monitors all states.
- `webhook_url` (string, required): The URL to send webhook notifications to. Required.

Output parameters:

- `important` (string): Warning that the signing secret will not be shown again.
- `monitor` (object): The created monitor.
- `summary` (string): One-line confirmation naming the monitor that was created.

### `create_competitor_monitor` (~279 tokens)

Subscribe a monitor to a SPECIFIC named credit union's published rate and alert via webhook when that CU changes its rate (vs the aggregate market-best decision). Returns the monitor with a webhook_signing_secret (shown once) and a baseline snapshot of the CU's current rate.

Input parameters:

- `audience` (string): Scope offers by WHO they are for: 'business' returns business-audience products (DSCR mortgages, commercial vehicle loans, SBA); 'consumer' excludes them. Omit for both.
- `conditions` (object): Alert conditions on the named CU rate. Default: any change.
- `cooldown_hours` (number): 1-168, default 24.
- `loan_program` (string): e.g. '30-year-fixed'.
- `name` (string, required): Descriptive monitor name. Required.
- `occupancy` (string): MORTGAGE/HELOC: property occupancy. 'investment' returns investor / non-owner-occupied / DSCR pricing; 'secondary' second-home pricing. Omit for standard primary-residence offers.
- `product_type` (string): Default mortgage.
- `state` (string): 2-letter state for the CU published rate.
- `target_credit_union` (object, required): The specific credit union whose published rate to watch. Required.
- `webhook_url` (string, required): HTTPS webhook. Required.

Output parameters:

- `disclosures` (array): Scope caveats about what this monitor does and does not alert on.
- `important` (string): Warning that the signing secret is shown only once.
- `monitor` (object): The created competitor monitor.
- `next_actions` (array): Suggested follow-up tool names.
- `summary` (string): One-line confirmation naming the monitor and the credit union it watches.
- `webhook_signing_secret` (string|null): Full HMAC signing secret. Shown once, at creation.

### `list_monitors` (~77 tokens)

List all monitors associated with your API key. Supports pagination and filtering by status.

Input parameters:

- `limit` (number): Maximum number of monitors to return (1-100). Defaults to 20.
- `offset` (number): Number of monitors to skip for pagination. Defaults to 0.
- `status` (string): Filter monitors by status.

Output parameters:

- `monitors` (array): The monitors on this page (a condensed view — call get_monitor for full conditions).
- `pagination` (object): Page position.
- `summary` (string): Human-readable count of total, active, and paused monitors.

### `get_monitor` (~35 tokens)

Get detailed information about a specific monitor by its ID.

Input parameters:

- `monitor_id` (string, required): The unique identifier of the monitor. Required.

Output parameters:

- `error` (string|null): Present and set to 'not_found' when the monitor id does not exist.
- `monitor` (object): The monitor. Absent when not found.
- `summary` (string): Monitor name and status, or a not-found message.

### `update_monitor` (~101 tokens)

Update an existing monitor. Only provided fields will be updated.

Input parameters:

- `conditions` (array): New array of conditions.
- `cooldown_hours` (number): New cooldown period in hours (1-168).
- `monitor_id` (string, required): The unique identifier of the monitor to update. Required.
- `name` (string): New name for the monitor.
- `status` (string): New status for the monitor.
- `webhook_url` (string): New webhook URL.

Output parameters:

- `error` (string|null): Present and set to 'not_found' when the monitor id does not exist.
- `monitor` (object): The monitor after the update. Absent when not found.
- `summary` (string): Confirmation naming the monitor and which fields changed, or a not-found message.

### `delete_monitor` (~38 tokens)

Permanently delete a monitor. This action cannot be undone.

Input parameters:

- `monitor_id` (string, required): The unique identifier of the monitor to delete. Required.

Output parameters:

- `deleted` (boolean): True when the monitor was deleted. Absent on not-found.
- `error` (string|null): Present and set to 'not_found' when the monitor id does not exist.
- `monitor_id` (string): The id that was deleted.
- `summary` (string): Confirmation of deletion, or a not-found message.

### `simulate_monitor` (~136 tokens)

Test a monitor with a simulated rate change to see if it would trigger. No webhook is sent. It is not a pure dry run: the simulation IS recorded, as a monitor_evaluations row (and a webhook audit row) flagged is_simulation = 1, so it appears in the monitor's history clearly marked as a simulation. It does not touch the monitor's cooldown or last_triggered_at. Use deliver_test_webhook to actually send a test webhook.

Input parameters:

- `monitor_id` (string, required): The unique identifier of the monitor to simulate. Required.
- `rate_change` (object, required): The simulated rate change event. Required.

Output parameters:

- `error` (string|null): Present and set to 'not_found' when the monitor id does not exist.
- `evaluation` (object): Why the monitor did or did not fire.
- `rate_change` (object): The simulated change, echoed back with rates pre-formatted as percent strings.
- `summary` (string): Plain-language verdict on whether the monitor would fire, or a not-found message.
- `would_trigger` (boolean): Whether the monitor's conditions are satisfied by the supplied change.

### `deliver_test_webhook` (~129 tokens)

Send a test webhook for a monitor using a simulated rate change. This actually delivers an HTTP request to the monitor's configured webhook URL. IMPORTANT: a test delivery is NOT signed with the monitor's signing secret — only a hash of that secret is stored, so test deliveries use a placeholder and will FAIL signature verification. Use this to test payload handling, not signature verification. Only use when the user explicitly requests a test webhook delivery.

Input parameters:

- `monitor_id` (string, required): The unique identifier of the monitor to test. Required.
- `rate_change` (object, required): The simulated rate change event. Required.

Output parameters:

- `error` (string|null): Present and set to 'not_found' when the monitor id does not exist.
- `evaluation` (object): Why the monitor did or did not fire.
- `rate_change` (object): The simulated change, with rates pre-formatted as percent strings.
- `summary` (string): Whether the test webhook was delivered and whether the monitor would have triggered, or a not-found message.
- `webhook_delivery` (object|null): Outcome of the HTTP POST to the monitor's webhook URL. Omitted when the backend reported no delivery attempt.
- `would_trigger` (boolean): Whether the monitor's conditions were satisfied by the supplied change.

### `list_webhook_deliveries` (~228 tokens)

Org-scoped webhook delivery observability for the authenticated API key. Lists the per-event webhook delivery log for your monitors — each row shows status (delivered/failed/pending), HTTP response code, error, response time, the destination URL, and timestamp — with a roll-up summary (total/delivered/failed/pending). Use this to surface SILENT webhook failures (a delivery that never reached your endpoint). Filter by monitor_id and/or status. To replay a failed (or any) delivery, set redeliver_id to that row's id; the original payload is re-sent verbatim and the replay is itself audited. Distinct from deliver_test_webhook, which sends a brand-new simulated event.

Input parameters:

- `limit` (integer)
- `monitor_id` (string): Filter to one monitor.
- `offset` (integer)
- `redeliver_id` (integer): If set, replay the delivery with this audit-log id instead of listing (maps to action:redeliver, delivery_id).
- `status` (string): Filter by delivery outcome.

Output parameters:

- `content` (array): MCP content blocks carrying a one-line human summary of the deliveries or the redelivery.
- `disclosures` (array): Scoping and replay-semantics caveats.
- `next_actions` (array): Suggested follow-up tool names.
- `structuredContent` (object): The raw /v1/webhook-deliveries payload. In list mode: deliveries, summary, limit, offset. In redelivery mode: redelivered, delivery_id, new_status, delivery_status_code, response_time_ms, error.

### `get_eligibility_coverage` (~194 tokens)

Enterprise RateAPI Routes coverage: how many US credit unions RateAPI holds live, verbatim-evidenced membership rules for (and what share of the active fleet that is), how the rules split by kind, how many counties, states and employers they name, verification status, and freshness. The `authority` object distinguishes exact immutable active publications from older graph and flat compatibility records; `evidence_sources` reports the public source mix. Returns a dated `headline` sentence that can be quoted verbatim. Use this BEFORE find_eligible_credit_unions or check_membership_eligibility when the user asks how complete, authoritative, or fresh the eligibility data is. Aggregate only — no institution-level rows; those come from the eligibility tools. Never reports credit data: the rule schema has no condition kind for credit score, income or debt. An institution absent from the graph is undecided, never ineligible.

Output parameters:

- `as_of` (string|null): Most recent rule confirmation across the live graph (ISO 8601) — the moment the data last moved.
- `authority` (object|null): Serving-authority adoption. Exact immutable publications are separated from older graph and flat compatibility records.
- `by_kind` (array|null): Live rules and distinct institutions per rule kind, largest first.
- `credit_data` (object|null): Explicit statement that no rule condition references credit data.
- `disclosure` (string|null): Statement that must accompany any consumer-facing use of eligibility data.
- `evidence_sources` (array|null): Live rule counts by recorded evidence source class; institution counts may overlap.
- `fleet` (object|null): The denominator: active institutions and how many the graph holds live rules for.
- `generated_at` (string|null): When the aggregate was computed (ISO 8601). Edge-cached for an hour.
- `headline` (string|null): One dated sentence carrying every headline number next to its denominator. Quote it verbatim.
- `pipeline` (array|null): Institutions by eligibility pipeline status — why an institution may be absent from the graph (no source found, needs review, pending).
- `population` (object|null): Population disclosure: graph inventory, not a personal eligibility decision or reachable-offer count.
- `reach` (object|null): How specific the rules are: distinct places and organizations named, and institutions carrying each path type.
- `rules` (object|null): Live rule counts, verification split and freshness.
- `semantics` (string|null): How to read the counts: live rules only; absence from the graph is undecided, never ineligible; where row-level verdicts live.

### `get_extraction_stats` (~174 tokens)

Get data extraction statistics showing the scale and health of rate data collection. Use this to understand extraction volumes, product coverage, and data freshness. Supports filtering by date range and product type. Great for building transparency dashboards or monitoring data collection health.

Input parameters:

- `endTime` (string): End of the time range. Supports ISO8601 or relative times. Defaults to "now".
- `product_type` (string): Filter statistics to a specific product type. If omitted, returns stats for all product types.
- `startTime` (string): Start of the time range. Supports ISO8601 (e.g., "2024-01-15T00:00:00Z") or relative times ("now-24h", "now-7d", "now-1m"). Defaults to "now-24h".

Output parameters:

- `coverage` (object): Breadth of the dataset.
- `dataQuality` (object|null): Data-health indicators, passed through unchanged from /v1/stats.
- `generatedAt` (string|null): ISO-8601 time the stats were computed.
- `hourlyTrendSample` (array): First six hourly buckets of the trend series (a sample, not the full series).
- `products` (array): Full product-type breakdown.
- `query` (object|null): The resolved time window and filters the stats were computed over.
- `stats` (object): Headline counters. Note the string formatting.
- `summary` (string): One-line headline of rates extracted, per-hour throughput, and institution count.
- `topProducts` (string): Pre-rendered 'name: count (pct%)' string for the three largest product types.

### `get_benchmarks` (~174 tokens)

Get rate benchmark statistics (min/median/max APR) across all institutions. Use this for market analysis, comparing user quotes against market rates, or building benchmark dashboards. Returns statistics for mortgages (30yr fixed, 15yr fixed, and `mortgage_arm` — one bucket covering every adjustable-rate mortgage regardless of initial fixed period), auto loans (new/used — cars only), RV/boat/motorcycle/powersports (first-class vehicle categories), HELOCs, and personal loans. Each product shows the lowest APR institution, median APR, and count of institutions.

Input parameters:

- `product_type` (string): Filter to a specific product type. If omitted, returns benchmarks for all product types.
- `state` (string): Filter to a specific US state (2-letter code). If omitted, returns nationwide benchmarks.

Output parameters:

- `benchmarks` (array): Formatted per-product benchmark rows, one per product category, ready to present.
- `generatedAt` (string|null): UTC timestamp when this benchmark response was assembled; the underlying rates are older, see each row's asOf.
- `rawData` (array): The same benchmarks as unformatted numbers, for calculation rather than display.
- `stateFilter` (string|null): Scope of the benchmark set as a label — 'Nationwide' when no state narrowing was applied. Check this before describing the numbers as local.
- `summary` (string|null): Plain-English headline of the benchmark set, e.g. the range of 30-year fixed APRs and how many credit unions publish them.
- `totalInstitutions` (string|null): Number of institutions behind the benchmark set, returned as a string rather than a number.

### `compare_products` (~268 tokens)

Compare the best real rates across MULTIPLE lending products in a single call — e.g. show a buyer mortgage vs HELOC, or new vs used auto. Runs the decision engine for each product and returns a ranked, true-cost (APR + fees) table. Use this instead of calling get_financing_decision repeatedly. Each product returns its top offer with rate, APR, and monthly payment.

Input parameters:

- `amount` (number, required): Loan/credit amount in dollars
- `credit_score` (number): Optional borrower credit score
- `intent` (string): purchase | refinance | cash_out | balance_transfer | new_credit
- `product_types` (array, required): Products to compare, e.g. ["mortgage","heloc"]. Any of: mortgage, mortgage_arm, auto, rv, boat, motorcycle, powersports, heloc, personal_loan, credit_card, student_loan. "mortgage" is fixed-rate and…
- `state` (string, required): US state code, e.g. "CA"
- `term_months` (number): Optional loan term in months

Output parameters:

- `amount` (number|null): Loan amount in dollars every product was priced at, so the rows are comparable.
- `best_overall` (string|null): Product type with the lowest true cost across the compared rows, e.g. 'heloc'.
- `intent` (string|null): Borrowing purpose the pricing assumes, e.g. 'purchase' or 'refinance'.
- `note` (string|null): Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.
- `products` (array): One row per requested product type, each showing that product's single best lender.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.

### `refinance_break_even` (~164 tokens)

Tell a borrower whether refinancing is worth it. Compares their current rate against the best real market offer and returns monthly savings, lifetime savings, and break-even months. Use for 'should I refinance?' questions.

Input parameters:

- `balance` (number, required): Current loan balance in dollars
- `closing_costs` (number): Lender fees / closing costs in dollars (default 0)
- `credit_score` (number): Optional borrower credit score
- `current_rate` (number, required): Borrower's current interest rate, e.g. 7.25
- `product_type` (string, required): mortgage | auto | heloc | personal_loan | student_loan
- `state` (string, required): US state code
- `term_months` (number, required): Remaining or new term in months

Output parameters:

- `assumed_defaults` (object): Inputs filled in because the caller did not supply them; the break-even is only as good as these.
- `best_lender` (string|null): Credit union publishing that best market rate.
- `best_market_rate` (string|null): Best live published rate available for this product and state, as a percent string.
- `break_even_months` (number|null): Months of savings needed to repay the closing costs. Refinancing only pays off if the borrower keeps the loan longer than this.
- `closing_costs` (string|null): Assumed cost in dollars to close the refinance, as a formatted string.
- `current_monthly_payment` (string|null): Principal-and-interest payment in dollars on the existing loan, as a formatted string.
- `current_rate` (string|null): The borrower's existing rate as a percent string.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `lifetime_savings` (string|null): Total interest saved in dollars over the full term, before subtracting closing costs.
- `monthly_savings` (string|null): Reduction in the monthly payment in dollars; the difference between the two payments above.
- `net_lifetime_savings` (string|null): Lifetime savings after subtracting closing costs — the honest headline number.
- `new_monthly_payment` (string|null): Principal-and-interest payment in dollars after refinancing at the best market rate.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `reason` (string|null): Why refinancing is not worth it, present only when `refinance_worth_it` is false — e.g. 'No qualifying market offer beats the current rate.' Its absence means a viable refinance was found.
- `refinance_worth_it` (boolean|null): True when the refinance clears its costs on the assumptions shown; it does not account for how long the borrower actually plans to stay.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.

### `optimize_buydown` (~165 tokens)

Given a discount-points / lender-credit tradeoff menu for a candidate loan, returns break-even months, lifetime savings, and the optimal point-spend. The points analog of refinance_break_even.

Input parameters:

- `base_rate` (number, required): The no-points (par) interest rate, percent, e.g. 6.75.
- `hold_months` (number): Expected time-in-loan horizon for lifetime savings; defaults to term_months.
- `loan_amount` (number, required): Loan principal in dollars (>0).
- `options` (array, required): Points/lender-credit tradeoff menu to evaluate.
- `state` (string): Optional 2-letter state (validated only if supplied).
- `term_months` (number, required): Loan term in months, e.g. 360.

Output parameters:

- `assumed_defaults` (object): Inputs filled in because the caller did not supply them, notably the holding period that decides the winner.
- `base_monthly_payment` (string|null): Monthly principal-and-interest payment in dollars at the base rate.
- `base_rate` (string|null): The no-points starting rate as a percent string, the baseline every option is measured against.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `hold_months` (number|null): How long the borrower is assumed to keep the loan. Buying points only wins if this exceeds the option's break-even.
- `loan_amount` (string|null): Loan amount in dollars as a formatted string; point costs are a percentage of this.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `optimal` (object): The option that maximizes net savings over the assumed holding period.
- `options` (array): Each points/rate combination modeled, including negative points (lender credits) where supplied.
- `reason` (string|null): Why no buydown option was recommended, present only in that case — e.g. 'No option produces positive net savings over the hold horizon; paying par (no points) is best.'
- `recommendation` (string|null): The action implied by the analysis, e.g. 'buy_points', 'no_points', or 'take_credit'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `term_months` (number|null): Loan term in months (360 = 30 years, 180 = 15 years, 60 = 5 years).

### `max_loan` (~205 tokens)

Estimate the largest loan a borrower can afford from income and a target debt-to-income (DTI) ratio. Returns max monthly payment, max loan amount, and the rate used. If no rate is supplied, the current best market rate for the product/state is used.

Input parameters:

- `dti` (number, required): Target debt-to-income ratio as a decimal, e.g. 0.36
- `existing_monthly_debt` (number): Optional existing monthly debt payments to subtract
- `income_annual` (number, required): Gross annual income in dollars
- `product_type` (string): Product for the market-rate lookup, default mortgage
- `rate` (number): Optional annual interest rate, e.g. 6.5. If omitted, best market rate is used.
- `state` (string): US state code (used to look up a market rate when rate is omitted)
- `term_months` (number, required): Loan term in months (e.g. 360)

Output parameters:

- `assumptions` (object): The inputs the calculation rests on; state them alongside the number.
- `max_loan_amount` (string|null): Largest loan principal in dollars that payment supports at the rate and term used. This is a loan amount, not a home price.
- `max_monthly_payment` (string|null): Largest monthly payment in dollars the income supports at the target DTI, after subtracting existing debts.
- `note` (string|null): Required caveat that this uses income and DTI only; lenders also weigh credit, down payment, and reserves.
- `rate_source` (string|null): Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.
- `rate_used` (string|null): Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.

### `estimate_affordability` (~258 tokens)

Borrower-facing home affordability estimate: given gross income, existing monthly debts, down payment, and front-end/back-end DTI caps, compute the max monthly payment, max loan amount, and max home price. Surfaces the max_loan annuity engine. If no rate is supplied, the current best market rate for the state is used.

Input parameters:

- `back_end_dti` (number): Total-debt DTI cap as a decimal. Default 0.36.
- `down_payment` (number): Cash down payment in dollars. Default 0.
- `front_end_dti` (number): Housing-payment DTI cap as a decimal. Default 0.28.
- `income_annual` (number, required): Gross annual income in dollars
- `monthly_debts` (number): Existing recurring monthly debt payments. Default 0.
- `product_type` (string): Product for the market-rate lookup. Default mortgage.
- `rate` (number): Optional annual interest rate, e.g. 6.5. If omitted, best market rate is used.
- `state` (string): US state code for the market-rate lookup. Default CA.
- `term_months` (number): Loan term in months. Default 360.

Output parameters:

- `affordable` (boolean|null): True when the income supports a meaningful loan after debts; false means the DTI budget is exhausted, not that nothing is purchasable.
- `assumed_defaults` (object): Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.
- `back_end_budget_value` (number|null): Total monthly debt budget in dollars under the back-end DTI cap, including existing debts. Compare with max_payment_value to see the headroom.
- `binding_constraint` (string|null): Which limit caps the budget: 'front_end_dti' (housing payment alone) or 'back_end_dti' (all debts). This tells the user what to fix to buy more.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `down_payment` (string|null): Down payment in dollars assumed, as a formatted string.
- `max_home_price` (string|null): Largest purchase price in dollars, being the max loan amount plus the down payment.
- `max_loan_amount` (string|null): Largest loan principal in dollars that payment supports at the rate and term used.
- `max_monthly_payment` (string|null): Largest housing payment in dollars supported by the binding DTI constraint, as a formatted string.
- `max_payment_value` (number|null): The same maximum housing payment as a raw number in dollars, for further math.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `note` (string|null): Explanation of how the front-end and back-end DTI caps interact and which one binds.
- `rate_source` (string|null): Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.
- `rate_used` (string|null): Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.
- `reason` (string|null): Why the affordable amount is constrained or zero, present only in that case — e.g. 'Existing debts exceed the back-end DTI budget.'

### `estimate_monthly_cost` (~310 tokens)

Total monthly housing cost (PITI): principal+interest plus property tax, homeowners insurance, PMI, and HOA, so affordability reflects real monthly outlay. If no rate is supplied, the current best market rate for the state is used.

Input parameters:

- `annual_insurance` (number): Homeowners insurance in dollars/year. Default max(800, 0.35% of home price).
- `credit_score` (number): Optional borrower credit score, used for the market-rate lookup.
- `down_payment` (number): Cash down payment in dollars. Default 0. loan_amount = home_price - down_payment.
- `home_price` (number): Purchase price in dollars. Required unless loan_amount is given.
- `loan_amount` (number): Optional explicit loan amount; overrides home_price - down_payment.
- `monthly_hoa` (number): HOA dues in dollars/month. Default 0.
- `pmi_rate` (number): Annual PMI as % of loan balance. Default 0.5, applied only when LTV > 80%.
- `property_tax_rate` (number): Annual property tax as % of home value. Default 1.1.
- `rate` (number): Annual interest rate, e.g. 6.5. If omitted, best market rate for the state is used.
- `state` (string): 2-letter US state code for the market-rate lookup. Default CA.
- `term_months` (number): Loan term in months. Default 360.

Output parameters:

- `annual_total` (string|null): Twelve months of the total monthly payment, in dollars.
- `assumed_defaults` (object): Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.
- `breakdown` (object): Share of the total monthly payment taken by each component, as percent strings.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `down_payment` (string|null): Cash in dollars put down at closing.
- `home_price` (string|null): Purchase price in dollars, as a formatted string.
- `loan_amount` (string|null): Amount borrowed in dollars, being the home price less the down payment.
- `ltv` (string|null): Loan-to-value ratio as a percent string. PMI generally applies above 80%.
- `monthly_hoa` (string|null): Monthly HOA dues in dollars, as supplied or defaulted.
- `monthly_insurance` (string|null): Monthly homeowners insurance in dollars, one twelfth of the annual premium used.
- `monthly_pmi` (string|null): Monthly private mortgage insurance in dollars. $0 when LTV is at or below 80%.
- `monthly_property_tax` (string|null): Estimated monthly property tax in dollars, derived from the assumed tax rate rather than an actual county assessment.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `pmi_applies` (boolean|null): True when the LTV requires private mortgage insurance.
- `principal_and_interest` (string|null): Monthly principal-and-interest payment in dollars — only part of the total housing cost.
- `rate_source` (string|null): Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.
- `rate_used` (string|null): Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.
- `total_monthly_payment` (string|null): Full monthly housing cost in dollars: principal, interest, taxes, insurance, plus PMI and HOA where they apply.

### `analyze_rent_vs_buy` (~512 tokens)

Compare projected cost of renting vs buying a home over a holding period, anchored to LIVE market mortgage rates. Given home price, down payment, monthly rent, and a holding period, returns year-by-year cumulative cost of each path (rent vs PITI), equity built, net cost of owning after sale, and the breakeven year where buying becomes cheaper than renting. If no rate is supplied, the current best market rate for the state is used. Use for 'should I rent or buy?' questions.

Input parameters:

- `annual_insurance` (number): Homeowners insurance in dollars/year. Default max(800, 0.35% of home price).
- `closing_cost_pct` (number): Buying closing costs as % of home price. Default 3.0.
- `down_payment` (number): Cash down payment in dollars. Default 20% of home_price.
- `holding_period_years` (number): How many years you plan to own. Default 7.
- `home_appreciation_rate` (number): Annual home appreciation as %. Default 3.0.
- `home_price` (number, required): Purchase price in dollars. Required.
- `investment_return_rate` (number): Opportunity cost return on invested savings as %. Default 5.0.
- `maintenance_rate` (number): Annual maintenance as % of home value. Default 1.0.
- `marginal_tax_rate` (number): Marginal tax rate as %, used to model mortgage-interest/property-tax deduction. Default 0 (no deduction).
- `monthly_hoa` (number): HOA dues in dollars/month. Default 0.
- `monthly_rent` (number, required): Current monthly rent in dollars. Required.
- `pmi_rate` (number): Annual PMI as % of loan balance. Default 0.5, applied only when LTV > 80%.
- `property_tax_rate` (number): Annual property tax as % of home value. Default 1.1.
- `rate` (number): Annual interest rate, e.g. 6.5. If omitted, best market rate for the state is used.
- `rent_growth_rate` (number): Annual rent growth as %. Default 3.0.
- `selling_cost_pct` (number): Selling costs as % of sale price. Default 6.0.
- `state` (string): 2-letter US state code for the market-rate lookup. Default CA.
- `term_months` (number): Loan term in months. Default 360.

Output parameters:

- `assumed_defaults` (array): Every input that was defaulted rather than supplied. Rent-vs-buy swings hard on these, so surface them.
- `breakeven` (object): When buying overtakes renting on the assumptions used.
- `buy` (object): The full economics of buying over the holding period.
- `confidence` (string|null): Qualitative confidence in the recommendation — 'high' when the margin is wide relative to the assumptions.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `rate_source` (string|null): Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.
- `rate_used` (number|null): Mortgage rate in percent used for the buy path (6 = 6.00%). Check rate_source to see whether it was supplied or resolved from live market data.
- `recommendation` (string|null): Which path the model favors on these assumptions: 'buy' or 'rent'.
- `rent` (object): The full economics of renting over the same holding period.
- `summary_note` (string|null): One-sentence bottom line with the dollar gap between the two paths, safe to quote.

### `project_pmi_removal` (~278 tokens)

For low-down-payment borrowers (LTV > 80%): projects when private mortgage insurance (PMI) drops off, the total PMI paid until then, and how much extra monthly principal cancels PMI sooner. Reuses the same amortization + PMI logic as estimate_monthly_cost. If no rate is supplied, the current best market rate for the state is used. Use for 'when does my PMI go away / how do I get rid of PMI faster?' questions.

Input parameters:

- `credit_score` (number): Optional, for market-rate lookup.
- `down_payment` (number): Cash down, dollars. Default 0.
- `extra_monthly_payment` (number): Optional extra principal/month to model faster cancel. Default 0.
- `home_price` (number): Purchase/appraised price. Required unless loan_amount given.
- `loan_amount` (number): Optional explicit loan; overrides home_price - down_payment.
- `pmi_rate` (number): Annual PMI as % of loan balance. Default 0.5.
- `rate` (number): Annual rate %, e.g. 6.5. Omit -> best market rate for state.
- `state` (string): 2-letter code for market-rate lookup. Default CA.
- `term_months` (number): Loan term in months. Default 360.

Output parameters:

- `assumed_defaults` (object): Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `down_payment` (string|null): Cash in dollars put down at closing.
- `extra_needed` (array): How much extra principal per month would be required to hit 80% LTV by various target dates.
- `home_price` (string|null): Purchase price in dollars, as a formatted string.
- `loan_amount` (string|null): Amount borrowed in dollars.
- `monthly_pi` (string|null): Monthly principal-and-interest payment in dollars, excluding PMI.
- `monthly_pmi_initial` (string|null): Monthly PMI premium in dollars at the start, before the balance amortizes down.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `pmi_applies` (boolean|null): True when PMI is required at origination; false means the rest of this projection is moot.
- `pmi_drop` (object): The two dates PMI can come off: the earlier one the borrower must request, the later one is automatic.
- `rate_source` (string|null): Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.
- `rate_used` (string|null): Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.
- `starting_ltv` (string|null): Loan-to-value at origination as a percent string. PMI applies above 80%.
- `total_pmi_paid` (string|null): Total PMI in dollars paid before it drops off, on the scheduled payments alone.
- `with_extra_payment` (object): How the caller's extra monthly principal payment accelerates PMI removal.

### `get_usage` (~44 tokens)

Check the calling account's API usage and remaining quota for this month (tier, used, remaining, limit, reset date). Use BEFORE running many calls to avoid hitting rate limits.

Output parameters:

- `limit` (number|null): Monthly request allowance for the org's tier.
- `remaining` (number|null): Requests left this month. Null on an unlimited plan.
- `requests_this_month` (number): Requests since the start of the current month — the number metered against the limit.
- `requests_today` (number): Requests since midnight.
- `reset_date` (string|null): When the monthly counter resets.
- `total_requests` (number): All-time request count across the org's keys.

### `get_monitor_stats` (~35 tokens)

Get rollup stats for the account's rate monitors: total, active, and webhooks sent. Complements list_monitors.

Output parameters:

- `active_monitors` (number): Monitors in 'active' status.
- `reset_date` (string|null): When the monthly counter resets.
- `total_monitors` (number): Monitors on the account.
- `webhooks_sent_this_month` (number): Webhooks sent this month.
- `webhooks_sent_today` (number): Webhooks sent today.

### `save_scenario` (~111 tokens)

Save a rate comparison for a named client so it can be recalled later (a lightweight CRM for loan officers). Pass the client label and the inputs/results you want to keep.

Input parameters:

- `client_name` (string, required): Client/scenario label, e.g. "Smith — $400k purchase, CA"
- `input` (object, required): The scenario inputs (product, amount, state, term, etc.)
- `result_snapshot` (required): The comparison result to store (object from get_financing_decision/compare_products)

Output parameters:

- `clientName` (string): Client label for the scenario.
- `createdAt` (string|null): ISO-8601 creation timestamp.
- `id` (string): Scenario id — pass to get_scenario, generate_share_link, or generate_client_report.
- `input` (object|null): The decision inputs that produced the snapshot (product, amount, state, term).
- `resultSnapshot`: The decision result captured at save time. Shape mirrors a /v1/decisions response.

### `list_scenarios` (~21 tokens)

List saved client scenarios for the account, newest first.

Output parameters:

- `count` (number|null): Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.
- `scenarios` (array): The scenarios visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.

### `get_scenario` (~31 tokens)

Get a single saved scenario by id (inputs + stored comparison).

Input parameters:

- `id` (string, required): Scenario id

Output parameters:

- `clientName` (string): Client label.
- `createdAt` (string|null): ISO-8601 creation timestamp.
- `error` (string|null): Present when the scenario was not found.
- `id` (string): Scenario id.
- `input` (object|null): The decision inputs that produced the snapshot.
- `resultSnapshot`: The decision result captured at save time; ranked offers live at actions[0].offers[].

### `delete_scenario` (~25 tokens)

Delete a saved scenario by id.

Input parameters:

- `id` (string, required): Scenario id

Output parameters:

- `success` (boolean): True when the scenario was deleted.

### `list_decision_logs` (~86 tokens)

Recall past financing decisions made on this account (audit log). Filter by request_id to look up a specific prior decision, or paginate with limit/offset.

Input parameters:

- `limit` (number): Max rows (default 20, max 100)
- `offset` (number): Pagination offset
- `request_id` (string): Optional: look up a specific decision by its request_id

Output parameters:

- `has_more` (boolean): True when further pages exist.
- `logs` (array): Audit rows, newest first.
- `total` (number): Total matching rows across all pages.

### `generate_client_report` (~123 tokens)

Produce a clean, client-facing markdown rate comparison report a loan officer can share with a buyer. Pass either a saved scenario_id, or an inline client_name + comparison result (from get_financing_decision/compare_products).

Input parameters:

- `advisor_name` (string): Optional advisor/company name for the report header
- `client_name` (string): Client label, if not using scenario_id
- `result` (object): The comparison result to format, if not using scenario_id
- `scenario_id` (string): Optional: a saved scenario id to build the report from

Output parameters:

- `format` (string): Always 'markdown'.
- `markdown` (string): The full report: heading, advisor byline, scenario line, a ranked offer table of up to five lenders, and a not-an-offer-of-credit footer.

### `rate_sanity_check` (~1052 tokens)

RECOMMENDED WHEN THE USER ALREADY HAS A QUOTE: answers "is this rate any good?" for a specific number a borrower was offered. Use this whenever someone says they were quoted / offered / approved at a rate and wants to know if it is fair, good, competitive, high, or a rip-off — e.g. "I got offered 6.9% on a 30-year in Ohio, is that fair?", "my dealer quoted 8.4% on a used car loan", "is 7.1% high for a HELOC in TX?". Given a product_type, state, and rate (and optional apr/fees/amount/term_months), returns the percentile of the quote within the live market distribution, a verdict (market_leading, plausible, suspicious_low, overpriced), whether it falls below the known product rate floor, and the market min/median/max with an as_of date. Prefer this over get_financing_decision for quote-in-hand questions: the user wants a verdict on THEIR number, not a list of other offers. Set include_better_offers=true to get named statewide lenders beating the quote. When the user provides a ZIP, set include_nearby_offers=true to pair product-matched rates with the closest credit unions by NCUA-reported branch location; distances are straight-line ZIP-center estimates, never driving distance. Every response also returns `share_url` — a link to this same check on rateapi.dev that the borrower can send to their lender or broker. Surface it whenever the user might act on the result; it re-runs against live rates when opened, so it never goes stale. NOTE: this is the BORROWER-side tool; check_competitive_position is the lender-side equivalent for benchmarking a lender's own published pricing. If the quote is an ADJUSTABLE-rate mortgage (the user says ARM / adjustable / "5/1" / "5/5" / "7/1"), pass product_type=mortgage_arm rather than mortgage — ARMs are scored against their own market. Caveat to surface to the user: the comparison does not currently segment by credit score, LTV, or points, and quoted fees are not folded into the APR comparison.

Input parameters:

- `amount` (number): Loan amount in dollars. Optional — also sharpens better-offer payment math.
- `apr` (number): The quoted APR as a percentage. Optional — falls back to rate if omitted.
- `credit_score` (number): Borrower's credit score (300-850). Optional; improves better-offer matching.
- `fees` (number): Quoted fees in dollars. Optional, used only for the note.
- `include_better_offers` (boolean): Set TRUE for negotiation questions. Adds `better_offers`: named lenders currently beating the quote, each with the APR gap in basis points, estimated monthly savings, and `can_you_join` (yes / likely…
- `include_nearby_offers` (boolean): Set true with zip to return product-matched rates from credit unions ranked by the closest NCUA-reported branch. Results include approximate straight-line miles, branch details, and the basis-point d…
- `max_offers` (number): How many better offers to return (1-5, default 3). Only applies with include_better_offers.
- `product_type` (string, required): Type of financing product the quote is for. Pick `mortgage_arm` — NOT `mortgage` — whenever the user names an adjustable-rate mortgage: "ARM", "adjustable", or a slash pair like "5/1", "5/5", "7/1",…
- `rate` (number, required): The quoted interest rate as a percentage (e.g., 4.25). Required.
- `state` (string, required): US state code (2-letter, e.g., CA, TX). Required.
- `term_months` (number): Loan term in months. For MORTGAGES this selects which market the quote is scored against: pass 180 for a 15-year and 360 for a 30-year. 15-year rates run structurally lower, so omitting it on a 15-ye…
- `zip` (string): Borrower ZIP code. Optional; sharpens membership eligibility and enables include_nearby_offers.

Output parameters:

- `below_product_floor` (boolean|null): True when the quote is implausibly low for this product, suggesting a teaser, a promotional tier, or a misread number rather than a real offer.
- `better_offers` (array): Statewide published offers that beat the quote, best first. Empty means nothing tracked beats it.
- `better_offers_meta` (object): The assumptions used to compute the savings figures on the better offers.
- `classification` (string|null): Verdict on the quote: 'market_leading', 'plausible', 'suspicious_low', 'overpriced', or 'unknown' when there is too little data to judge.
- `compared_against` (string|null): The market segment the quote was matched to, e.g. 'mortgage_30yr'. If this is not the borrower's actual product, the verdict does not apply.
- `market` (object): Live market distribution the quote was scored against.
- `nearby_offers` (array): Product-matched offers from credit unions with branches near the supplied ZIP, closest first. Included only when the caller asked for nearby offers.
- `nearby_offers_meta` (object): Context and caveats for the nearby-offer list.
- `note` (string|null): Ready-to-quote sentence explaining the verdict in the borrower's terms.
- `percentile` (number|null): Where the quote sits in the live market distribution, 0-100, lower being cheaper. 100 means every tracked offer is cheaper than this quote.
- `product_floor` (number|null): Lowest rate in percent considered plausible for this product; quotes under it trip below_product_floor.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `quote` (object): The rate the borrower was quoted, echoed back as supplied.
- `share_url` (string|null): Link to this same check on rateapi.dev that the borrower can send to a lender or broker; it re-runs against live rates when opened, so it never goes stale.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.

### `get_coverage` (~213 tokens)

Introspect what mortgage/loan data the API covers BEFORE scanning — which states, lenders, and product types are present, row counts per segment, and last-updated freshness per segment. Returns a coverage matrix so an agent can pick a scannable state/product before calling scan_savings or get_financing_decision. Mirrors the /meta global counts, expanded into a per-segment matrix. Boats, RVs, motorcycles, and powersports are first-class product categories; auto means cars.

Input parameters:

- `freshness_days` (number): Optional uniform staleness window in days (1-90). OMIT to use per-category freshness windows — supplying a value overrides every category and is echoed back as freshness_mode=override.
- `group_by` (string): Optional segmentation axis. Default 'state'.
- `product_category` (string): Optional. Restrict the matrix to one product category. Omit for all.
- `state` (string): Optional 2-letter US state code to scope the matrix to a single state.

Output parameters:

- `coverage` (object): Which states and product types appear in the data, as flat lists.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `freshness_days` (number|null): Age limit in days a rate must be within to be counted here; rows older than this are excluded from the totals.
- `freshness_mode` (string|null): How the freshness window was chosen: 'per_category' applies a category-specific window instead of one global value.
- `generated_at` (string|null): UTC timestamp when this coverage snapshot was computed.
- `institution_profiles` (object): Coverage of the NCUA institution reference data that backs lender context, separate from rate coverage.
- `next_actions` (array): Suggested follow-up tools given this coverage picture, as bare tool names.
- `note` (string|null): Plain-English description of how this coverage matrix is grouped and what it totals.
- `segments` (array): Coverage broken down by the requested grouping, largest first.
- `totals` (object): Overall size of the covered dataset within the freshness window.

### `check_competitive_position` (~191 tokens)

LENDER-side 'is my offer competitive' check — input your OWN published rate for a state+product, get the market percentile, bps vs the state median, and a leading/competitive/overpriced verdict. This is for a loan officer or credit union benchmarking their published pricing against the live market distribution. Do NOT use this for a consumer's quote: if the user is a BORROWER asking whether a rate they were offered is fair, use rate_sanity_check instead.

Input parameters:

- `apr` (number): The lender's published APR. Optional — falls back to rate.
- `product` (string, required): Mortgage product the lender publishes. Required.
- `rate` (number, required): The lender's OWN published note rate as a percentage (e.g. 6.49). Required.
- `state` (string, required): US state code (2-letter, e.g. CA, TX). Required.

Output parameters:

- `bps_vs_median` (number|null): Distance from the market median in basis points (-4 = 4 basis points below, i.e. better than median).
- `market` (object): Distribution of live offers this position was measured against.
- `note` (string|null): Ready-to-quote sentence stating how this offer ranks against live offers and by how many basis points.
- `percentile` (number|null): Where this offer sits in the market distribution, 0-100, lower being cheaper. 43 means about 43% of live offers are cheaper than it.
- `product` (string|null): Product key the offer was compared against, e.g. '30yr_fixed'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `verdict` (string|null): Qualitative placement of the offer against the market, e.g. 'competitive', 'above_market', 'market_leading'.
- `your_offer` (object): The rate and APR the caller supplied for comparison.

### `scan_savings` (~132 tokens)

Scan a list of existing debts and find, for EACH debt, the best qualifying market refinance offer. Returns a ranked "savings stack" with monthly and lifetime savings (net of typical closing costs) per debt plus whether refinancing is worth it, and overall totals. Use this to find refinance opportunities across a borrower's whole debt portfolio.

Input parameters:

- `credit_score` (number): Borrower's credit score (300-850). Recommended for accurate matching.
- `debts` (array, required): List of existing debts to evaluate for refinancing.
- `state` (string, required): US state code (2-letter, e.g., TX). Required.

Output parameters:

- `stack` (array): The user's debts ordered by refinancing opportunity, biggest saving first.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `totals` (object): Combined opportunity across every debt in the stack.

### `get_league_table` (~235 tokens)

Loan-officer competitive-landscape report: ranked roster of the top N lenders publishing a given mortgage product in a state today — per-lender rows (name, best APR/rate, product, position, bps above the leader) — plus the market min/median/max. The market median is INSTITUTION-level — one vote per lender, using each lender's best APR (basis = total_lenders, not market.count) — so a lender publishing a large rate matrix cannot pull it. Extends get_benchmarks (which returns only min/median/max + the single lowest institution) with the full ranked table.

Input parameters:

- `include_institution_context` (boolean): Include compact NCUA member, location, asset, founding-year, and selected service facts per lender.
- `limit` (number): Top N lenders to return (default 10, clamped 1..50)
- `metric` (string): Rank by apr (default) or rate
- `product` (string, required): Mortgage product
- `state` (string, required): 2-letter US state code, e.g. CA, TX, NY

Output parameters:

- `as_of` (string|null): UTC timestamp of the underlying rate data. This is when the rates were last scraped from lender sites, not when this call ran.
- `count` (number|null): Rows actually returned in `table`.
- `limit` (number|null): Maximum rows the caller asked for.
- `market` (object): Distribution across all lenders publishing this product, including those below the table cutoff.
- `metric` (string|null): Value the ranking is sorted by — 'apr' ranks by true cost including fees, 'rate' by the note rate alone.
- `note` (string|null): Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.
- `product` (string|null): Product key the table ranks, e.g. '30yr_fixed'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `table` (array): Lenders ranked best-first by the chosen metric.
- `total_lenders` (number|null): Number of lenders publishing this product in this state. `count` is the visible top slice of this larger set.

### `get_deposit_benchmarks` (~264 tokens)

Best/median/spread credit-union deposit APY by product, term, and state, with per-CU peer ranking. Pass the MCP field `product` using one exact underscore value: savings, cd, share_certificate, money_market, ira_cd, ira, or share_savings. The MCP server translates it to REST `product_category`; do not send `product_category`, `mma`, or `money-market` to this tool. Deposits quote APY (no APR); CDs/share certificates include term. Current + recent data; history is retention-bounded.

Input parameters:

- `limit` (number): Top N credit unions to rank (default 10, clamp 1..50).
- `metric` (string): Deposits rank by APY, highest first. No APR.
- `product` (string): MCP field for the deposit product category. Use an exact enum value such as `money_market`; do not use REST field name `product_category`, `mma`, or `money-market`. Omit for all deposit types.
- `state` (string): 2-letter US state code; omit for nationwide.
- `term_months` (number): For CD/share_certificate/ira_cd: filter to a specific term (savings_term_months).

Output parameters:

- `as_of` (string|null): UTC timestamp of the underlying rate data. This is when the rates were last scraped from lender sites, not when this call ran.
- `benchmark_balance`: Deposit balance in dollars the rates are quoted at. Null means no balance tier was applied, so tiered rates may not be comparable.
- `best` (object): The single highest-yielding offer found.
- `count` (number|null): Number of rows returned in `table`, capped by the caller's limit.
- `market` (object): Distribution of APYs across the market for this product, for context around `best`.
- `note` (string|null): Data caveats for this response, including that APY is shown rather than APR and that history is retention-bounded.
- `product_category` (string|null): Deposit product benchmarked, e.g. 'cd', 'savings', 'money_market'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `table` (array): Ranked deposit offers, highest APY first.
- `term_months` (number|null): Certificate term in months these rows are scoped to. Null for non-term products like savings.
- `total_credit_unions` (number|null): Number of credit unions publishing this deposit product in scope — larger than `count` when the table is truncated.

### `get_deposit_beta` (~229 tokens)

Deposit beta (repricing sensitivity) = change in deposit APY per 100bps change in a benchmark/market rate — the core credit-union/bank ALM & interest-rate-risk (IRR) model input. Pass the MCP field `product` using an exact underscore value such as `money_market`; do not send `product_category`, `mma`, or `money-market`. Derived from RateAPI's retained published deposit-rate history. SHORT-WINDOW / retention-bounded: full-cycle beta needs multi-year history (roadmap) — results ship with an explicit confidence/depth caveat. Deposits quote APY, never APR. Aggregate published rates only — never member/borrower data.

Input parameters:

- `benchmark` (string)
- `group_by` (string)
- `product` (string, required): Required MCP product field. Use one exact underscore enum value; money market is `money_market`, never `mma` or `money-market`.
- `state` (string): 2-letter US state code
- `term_months` (number)
- `window` (string)

Output parameters:

- `benchmark_requested` (string|null): The benchmark the caller asked deposit rates to be measured against, e.g. 'cd_top_quartile'.
- `benchmark_used` (string|null): The benchmark actually used, which can differ from benchmark_requested when the requested one lacked data.
- `confidence` (string|null): Qualitative reliability of the beta estimate — 'low' when the history window is short relative to a full rate cycle.
- `data_source` (string|null): Internal backing store that served this query ('clickhouse'); operational detail, not something to report to the user.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `group_by` (string|null): How results are grouped, e.g. 'cu' for one segment per credit union.
- `history_depth_days` (number|null): Days of retained rate history available for this calculation. 0 means no usable history, so every beta is null.
- `note` (string|null): Methodology caveat explaining that this is a short-window beta from retained published history, not a full-cycle beta.
- `peer` (object): Distribution of beta across the peer group.
- `product` (string|null): Deposit product the beta was computed for, e.g. 'savings' or 'cd'.
- `segments` (array): One beta result per group. An empty array means the retained history was too shallow to compute any beta, not that beta is zero.
- `state`: Two-letter state code the analysis was scoped to. Null means nationwide.
- `term_months`: Certificate term in months the analysis was scoped to. Null for non-term products.
- `window` (string|null): Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.

### `explain_ranking` (~194 tokens)

Explain WHY each top lender ranked where it did for a financing decision. Takes a full decision scenario (same shape as get_financing_decision) and returns a structured per-offer cost breakdown (rate, points, fees, lifetime interest), scoring signals, how much each offer beats the next by, and a plain-language summary of the ranking weights. Use this when a user asks why one lender beat another.

Input parameters:

- `amount` (number, required): Loan amount in dollars. Required.
- `credit_score` (number): Borrower's credit score (300-850).
- `intent` (string, required): The loan intent.
- `max_providers` (number): Maximum number of lenders to explain (1-5). Defaults to 5.
- `product_type` (string): Type of financing product.
- `state` (string, required): US state code (2-letter). Required.
- `term_months` (number): Loan term in months.

Output parameters:

- `offers` (array): Ranked offers with the scoring inputs that produced each position.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `request_id` (string|null): Opaque identifier for this call, useful only for support or debugging; never show it to the user.
- `summary` (string|null): Plain-English statement of the weighting scheme used and what separated the top offers; quote this when explaining the ranking.

### `simulate_decision` (~124 tokens)

Run a what-if sweep over a financing decision. Holds a scenario fixed while sweeping one input (credit_score, down_payment_percent, or rate_shift_bps) across a from/to/step range, returning a grid of best_lender / best_apr / monthly_payment at each value plus any flip_points where the winning lender changes. Use this to show how rate eligibility or affordability changes with credit score, down payment, or a market rate shift.

Input parameters:

- `scenario` (object, required): The fixed financing scenario.
- `sweep` (object, required): The input to sweep and its range.

Output parameters:

- `flip_points` (array): Values of the swept input where the winning lender or recommended action changes. Empty means the outcome is stable across the whole sweep.
- `grid` (array): One row per swept value, showing how the outcome changes.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `sweep_field` (string|null): The input that was varied across the grid, e.g. 'credit_score'.

### `build_amortization_schedule` (~275 tokens)

Build a year-by-year amortization / payoff schedule for a loan: total lifetime interest, principal/interest split per period, and a what-if extra-payment accelerator showing months saved and interest saved. Resolves the market rate from real credit-union offers when no rate is provided.

Input parameters:

- `credit_score` (number): Optional borrower credit score used to qualify the market offer.
- `extra_monthly_payment` (number): Optional extra principal paid each month. Drives the payoff-acceleration analysis (months saved, interest saved).
- `extra_one_time_payment` (number): Optional one-time extra principal payment.
- `loan_amount` (number, required): Loan principal in dollars (required, > 0).
- `product_type` (string): Loan product; required only when rate is omitted. Default mortgage.
- `rate` (number): Annual interest rate as a percent (e.g. 6.5). If omitted, the market rate is resolved from real credit-union offers via the decision engine.
- `schedule_granularity` (string): Schedule row granularity. Default year.
- `state` (string): 2-letter US state code; required only when rate is omitted (for market-rate lookup).
- `term_months` (number, required): Loan term in months, e.g. 360 or 180 (required).

Output parameters:

- `assumed_defaults` (object): Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.
- `baseline` (object): The loan as scheduled, with no extra payments.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `loan_amount` (number|null): Principal in dollars the schedule amortizes.
- `market_lender`: Credit union whose published rate was used when the rate came from market data. Null when the caller supplied the rate.
- `monthly_payment` (number|null): Scheduled principal-and-interest payment in dollars, excluding any extra payment.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `rate` (number|null): Annual note rate in percent used for the schedule.
- `rate_source` (string|null): Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.
- `reason` (string|null): Why no schedule could be built, present only in that case — e.g. no qualifying market offer for that product and state, in which case supply an explicit rate and retry.
- `schedule` (array): The amortization rows at the requested granularity (per month or per year).
- `term_months` (number|null): Loan term in months (360 = 30 years, 180 = 15 years, 60 = 5 years).
- `with_extra` (object): The same loan with the caller's extra monthly principal payment applied.

### `compare_total_cost` (~181 tokens)

Apples-to-apples multi-lender ranking by TOTAL cost of a loan (upfront origination/lender fees + lifetime interest over the holding period), not just the headline rate. Re-ranks real credit union offers and flags when the lowest-rate lender is not the cheapest overall.

Input parameters:

- `amount` (number, required): Loan principal
- `credit_score` (number)
- `down_payment_percent` (number)
- `fees` (object)
- `holding_period_months` (number): Horizon for total-cost; defaults to term_months
- `intent` (string): default purchase
- `max_lenders` (number): cap on ranked rows (default 10, max 25)
- `product_type` (string, required): Loan product to rank
- `state` (string, required): 2-letter US state
- `term_months` (number)

Output parameters:

- `amount` (number|null): Loan amount in dollars used for every lender in the comparison.
- `cheapest` (object): The lender with the lowest total cost over the holding period.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `holding_period_months` (number|null): How long the borrower is assumed to keep the loan. Total cost is measured over this period, not the full term, so a shorter hold favors low-fee lenders.
- `intent` (string|null): Borrowing purpose the pricing assumes, e.g. 'purchase' or 'refinance'.
- `next_actions` (array): Suggested follow-up tools, as bare tool names.
- `note` (string|null): Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `ranked` (array): Lenders ordered cheapest-first by total cost over the holding period.
- `ranked_by` (string|null): The metric the list is sorted by — 'total_cost' means cheapest over the holding period, which can differ from the lowest rate.
- `rate_leader` (object): The lender with the lowest headline APR, which is not always the cheapest overall.
- `reranked` (boolean|null): True when accounting for fees changed the winner from the headline rate leader — the key finding to surface when it is true.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `term_months` (number|null): Loan term in months (360 = 30 years, 180 = 15 years, 60 = 5 years).

### `batch_decisions` (~117 tokens)

Score an array of inline financing scenarios in one stateless call; returns ranked decisions and top offers per item — no persisted cohorts, no per-borrower HTTP loops.

Input parameters:

- `credit_score` (number): Optional default credit score applied to scenarios lacking one
- `max_providers` (number): Top-N offers returned per scenario (default 3)
- `scenarios` (array, required): Inline scenarios to score in one stateless call (no persisted cohorts).
- `state` (string): Optional 2-letter default state applied to scenarios lacking one

Output parameters:

- `count` (number|null): Number of scenarios evaluated in this batch.
- `results` (array): One result per scenario, ordered by rank rather than by the order submitted — match them back with `id`.
- `totals` (object): Batch-level tallies across all scenarios.

### `get_rate_delta` (~143 tokens)

Compare the LIVE market rate distribution now vs ~1/2/4 weeks ago for a product and state. Returns now/then min, median, max, count plus the median and min delta and a direction (down/up/flat). Bounded by data retention — if no comparable historical snapshot exists, then is null with an explanatory note. Use this to show how rates have moved recently.

Input parameters:

- `product_type` (string, required): Type of financing product. Required.
- `since` (string): How far back to compare against. Defaults to "1w".
- `state` (string, required): US state code (2-letter, e.g., CA, TX). Required.

Output parameters:

- `change` (object): Movement from `then` to `now`.
- `data_source` (string|null): Internal backing store that served this query ('clickhouse'); operational detail, not something to report to the user.
- `note` (string|null): Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.
- `now` (object): Current market snapshot for this product and state.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `then` (object): Snapshot at the start of the window, for comparison against `now`.
- `window` (string|null): Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.

### `list_rates` (~222 tokens)

List and filter raw rate rows (the core data primitive) by product, state, lender, and term with limit/offset pagination. Boats, RVs, motorcycles, and powersports are first-class product types; auto_loan means cars.

Input parameters:

- `audience` (string): WHO the product is for, orthogonal to product type: 'business' returns business-audience products across every category (DSCR mortgages, business deposits, SBA loans); 'consumer' excludes them.
- `lender` (string): Filter by credit-union name (substring, case-insensitive)
- `limit` (number): 1-500, default 50
- `loan_program` (string)
- `max_apr` (number)
- `min_apr` (number)
- `offset` (number): Pagination offset, default 0
- `product_type` (string)
- `sort` (string): Default apr_asc
- `state` (string): 2-letter US state code; omit for all states
- `term_months` (number)

Output parameters:

- `as_of` (string|null): UTC timestamp of the newest rate in this result set; the whole page is at least this stale.
- `filters` (object): The filters that were applied to produce these rows; null members were not constrained.
- `pagination` (object): Where this page sits within the full result set.
- `rates` (array): The matching rate rows for this page, in the order given by filters.sort.

### `get_rate_history` (~206 tokens)

Historical rate time-series: a date-ranged array of {date, min/median/max APR, count} points per product/state for dashboards, charts, backtests, and timing confidence — bounded by data retention. Differs from get_rate_delta (a single now-vs-then comparison): this returns the full series. Boats, RVs, motorcycles, and powersports are first-class product types; auto_loan means cars. Calls the /v1/rate-history public API (single source of truth).

Input parameters:

- `interval` (string): Bucket granularity per point. Default "week".
- `product_type` (string, required): Type of financing product. Required.
- `state` (string, required): US state code (2-letter, e.g., CA, TX). Required.
- `vehicle_condition` (string): auto_loan only; selects the benchmark bucket. Default "new".
- `window` (string): Lookback window. Default "90d". Bounded by data retention.

Output parameters:

- `data_source` (string|null): Internal backing store that served this query ('clickhouse'); operational detail, not something to report to the user.
- `interval` (string|null): Bucket size the series is aggregated into, e.g. 'week', 'day', or 'month'. Each entry in `series` covers one of these.
- `note` (string|null): Coverage caveat for this series, notably how many buckets are empty because history is retention-bounded. Do not describe empty buckets as rates falling to zero.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `series` (array): One bucket per interval across the window, oldest first. Buckets with no scrapes are present with null statistics.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `summary` (object): Start-to-end comparison across the populated portion of the series.
- `window` (string|null): Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.

### `assess_buy_timing` (~256 tokens)

Frame a buy/refi-now vs wait recommendation. Combines recent rate movement (direction + magnitude over 1w/2w/4w) with break-even sensitivity on the borrower's loan to return a forward 'lock now' vs 'wait' lean, the bps swing that would change the call, and the cost of waiting. Use for 'should I lock now or wait for rates to drop?' questions. Distinct from get_rate_delta (raw historical deltas only) — this adds a forward recommendation. Not a rate forecast.

Input parameters:

- `closing_costs` (number): Closing/refi costs in dollars (default 0)
- `current_rate` (number): Borrower's existing or quoted rate %, enables refi-now framing
- `loan_amount` (number, required): Loan amount in dollars — drives break-even sensitivity
- `product_type` (string, required): Loan product
- `rate_shift_bps` (number): Hypothetical bps move if waiting; default derived from observed movement
- `since` (string): Movement window (default 4w)
- `state` (string, required): 2-letter US state code
- `term_months` (number): Loan term in months (default 360 for mortgage)

Output parameters:

- `assumed_defaults` (object): Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.
- `break_even` (object): How the cost of waiting nets out against the hoped-for saving.
- `confidence` (string|null): Qualitative confidence in the recommendation — 'high', 'medium', or 'low' — driven by how much data and how large the margin is.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `movement` (object): How the market has moved over the comparison window, from the earlier snapshot to now.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `note` (string|null): A caveat about the DATA behind this call, not an error — e.g. limited rate history for that product and state, so the answer is a snapshot rather than a timing judgement. Present only when such a cav…
- `now` (object): The best deal available today, for comparison against waiting.
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `rationale` (string|null): Plain-English explanation of why this recommendation was reached; safe to quote to the user as the reasoning.
- `recommendation` (string|null): The suggested move, e.g. 'buy_now' or 'wait'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `wait_scenario` (object): A what-if for waiting, built from the caller's assumed rate shift. It is a sensitivity test, not a forecast.
- `window` (string|null): Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.

### `assess_rate_lock` (~246 tokens)

Lock-window-aware lock-vs-float-down recommendation for a deal already in the pipeline. Given a known lock-expiration date, the currently locked rate, and the float-down cost, returns a defensible hold-lock vs exercise-float-down call a loan officer can document — combining recent market movement (1w/2w/4w) with payment and break-even math on this loan. Builds on the same recent-movement signal as assess_buy_timing but framed around the lock window/expiration. Not a rate forecast.

Input parameters:

- `float_down_bps` (number): optional improvement in bps if float_down_rate omitted
- `float_down_cost` (number): $ to exercise float-down; default 0
- `float_down_rate` (number): optional explicit floated rate %
- `loan_amount` (number, required)
- `lock_expiration_date` (string, required): ISO date YYYY-MM-DD
- `locked_rate` (number, required): % already locked
- `product_type` (string, required)
- `since` (string): movement window; default 4w
- `state` (string, required): 2-letter state code
- `term_months` (number): default 360

Output parameters:

- `assumed_defaults` (object): Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.
- `confidence` (string|null): Qualitative confidence in the recommendation — 'high', 'medium', or 'low' — driven by how much data and how large the margin is.
- `disclosures` (array): Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.
- `float_down` (object): Economics of exercising a float-down to today's market rate.
- `lock` (object): The borrower's existing rate lock and how much time is left on it.
- `market_now` (object): Best deal currently available in the market, for comparison against the locked rate.
- `movement` (object): How the market has moved over the comparison window, from the earlier snapshot to now.
- `next_actions` (array): Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.
- `note` (string|null): A caveat about the inputs or data behind this call, not an error — e.g. the supplied lock-expiration date is already in the past, so the economics assume a fresh re-lock at current market. Present on…
- `product_type` (string|null): Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.
- `rationale` (string|null): Plain-English explanation of why this recommendation was reached; safe to quote to the user as the reasoning.
- `recommendation` (string|null): The suggested move, e.g. 'exercise_float_down', 'hold_lock', or 'relock'.
- `state` (string|null): Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.
- `window` (string|null): Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.

### `check_advice_guardrails` (~111 tokens)

Run compliance/suitability guardrails over a financing scenario and an optional recommendation. Returns flags (red/yellow with code + message) for things like DTI strain, long auto terms with negative-equity risk, possible balloon payments, and stale market data, plus generic disclaimers and an overall verdict (ok/caution/stop). Use this before presenting a rate recommendation to a borrower.

Input parameters:

- `recommendation` (object): Optional recommended offer to evaluate.
- `scenario` (object, required): The borrower scenario.

Output parameters:

- `disclaimers` (array): Statements that must be attached to any advice built on this scenario, such as that this is not financial advice and not an offer of credit.
- `flags` (array): Guardrail violations found in the proposed recommendation. An empty array means nothing was tripped.
- `overall` (string|null): Aggregate verdict on the proposed recommendation: 'stop' when a red flag blocks it, otherwise a pass or caution outcome.

### `save_cohort` (~121 tokens)

Save a named cohort ("book of business") — a list of borrower scenarios you want to track and re-scan over time. Each member has a label and a scenario (product_type, state, intent, amount, term_months, optional credit_score and current_offer). Returns the created cohort. Use scan_portfolio later to re-price every member against the live market.

Input parameters:

- `members` (array, required): List of cohort members (max ~50).
- `name` (string, required): Cohort name, e.g. "Q2 refi prospects". Required.

Output parameters:

- `createdAt` (string|null): ISO-8601 creation timestamp.
- `id` (string): Cohort id — pass to scan_portfolio, get_cohort, schedule_digest.
- `lastScan` (object|null): Previous scan snapshot. Null on a newly created cohort.
- `members` (array): The cohort members as supplied.
- `name` (string): Cohort label.
- `updatedAt` (string|null): ISO-8601 last-modified timestamp.

### `list_cohorts` (~48 tokens)

List saved cohorts for the account (newest first). Returns id, name, member count, and last scan time. Keeps the payload small — use get_cohort for full member detail.

Output parameters:

- `cohorts` (array): The cohorts visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.
- `count` (number|null): Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.

### `get_cohort` (~42 tokens)

Get a single saved cohort by id, including all members and the last scan snapshot (triage list).

Input parameters:

- `id` (string, required): Cohort id. Required.

Output parameters:

- `changed` (array): Members whose best offer moved since the previous snapshot.
- `scanned` (number): Members evaluated in this scan.
- `triage` (array): Every member's current best offer, the work list.

### `delete_cohort` (~36 tokens)

Permanently delete a saved cohort by id. This action cannot be undone.

Input parameters:

- `id` (string, required): Cohort id. Required.

Output parameters:

- `success` (boolean): True when the cohort was deleted.

### `scan_portfolio` (~108 tokens)

Re-scan every member of a saved cohort against the live decision engine to find each member's current best offer. Returns a triage list (label, best lender, best APR, monthly payment, optional savings vs current) and a diff vs the previous scan (who's new, whose best lender changed, APR deltas). Persists the new snapshot. Use this to refresh a book of business and surface what changed.

Input parameters:

- `id` (string, required): Cohort id to scan. Required.

Output parameters:

- `changed` (array): Members whose best offer moved since the previous scan.
- `scanned` (number): Members evaluated (capped at 50).
- `triage` (array): Every member's current best offer.

### `generate_share_link` (~101 tokens)

Turn a saved client scenario into a public, branded, shareable URL (https://app.rateapi.dev/r/TOKEN) that anyone can view without logging in. Returns a token and url. The link shows the client name, scenario inputs, and the ranked comparison with a "Powered by RateAPI" footer. Use revoke_share to disable a link later.

Input parameters:

- `scenario_id` (string, required): The saved scenario id to mint a share link for. Required.

Output parameters:

- `created_at` (string|null): ISO-8601 creation timestamp.
- `scenario_id` (string): Scenario the link renders.
- `token` (string): Share token — pass to revoke_share to disable the link.
- `url` (string): Public URL of the hosted report (app.rateapi.dev/r/<token>).

### `list_shares` (~64 tokens)

List all hosted shareable report links for the account, newest first. Returns token, scenario_id, client_name, views, last_viewed_at, revoked, created_at, and url for each share. Use this to see view analytics and manage which links are still live.

Output parameters:

- `count` (number|null): Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.
- `shares` (array): The shares visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.

### `revoke_share` (~57 tokens)

Revoke a hosted shareable report link by its token. Once revoked, the public URL returns a 404 and no longer exposes the report. This action cannot be undone.

Input parameters:

- `token` (string, required): The share token to revoke. Required.

Output parameters:

- `success` (boolean): True when the share was revoked.

### `schedule_digest` (~128 tokens)

Set up a recurring digest: on a cadence (default weekly), automatically re-scan a saved cohort and EMAIL the loan officer a triage of which clients have a new opportunity (best lender changed, crossed a threshold). Turns a one-time portfolio scan into a standing operation. Requires a cohort_id (from save_cohort/list_cohorts) and a delivery email.

Input parameters:

- `cadence` (string): weekly (default) or daily.
- `cohort_id` (string, required): The cohort to scan on a schedule (from list_cohorts).
- `email` (string, required): Where to send the digest.

Output parameters:

- `cadence` (string): 'daily' or 'weekly'. Anything other than 'daily' is stored as 'weekly'.
- `cohort_id` (string): Cohort the digest scans.
- `created_at` (string|null): ISO-8601 creation timestamp.
- `email` (string): Recipient address.
- `enabled` (boolean): True on creation.
- `id` (string): Digest id — pass to delete_digest.

### `list_digests` (~30 tokens)

List the account's scheduled digests (cohort, email, cadence, enabled, last run).

Output parameters:

- `count` (number|null): Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.
- `digests` (array): The digests visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.

### `delete_digest` (~32 tokens)

Delete a scheduled digest by id. Stops the recurring email.

Input parameters:

- `id` (string, required): The digest id to delete.

Output parameters:

- `success` (boolean): True when the digest was deleted.

### `set_email_branding` (~225 tokens)

Set the organization's white-label email branding: display name (used as the From name and CAN-SPAM advertiser identity), brand color (#hex), default intro text, business_address (CAN-SPAM physical address — required before a campaign can be activated), and reply_to_email. Requires a Pro plan. (Logo upload is app-only — not available over MCP.)

Input parameters:

- `brand_color` (string): Accent color as a #hex string (e.g. #00b368).
- `business_address` (string): Physical mailing address of the advertiser (CAN-SPAM).
- `display_name` (string): The lender/brand name shown as the email sender and advertiser.
- `intro_text` (string): Default intro paragraph for campaign emails.
- `logo_background_color` (string): Solid backdrop behind the logo in the email header, as a 6-digit #hex (e.g. #0d1b2a). Useful when the logo is white. Omit or null for the white default.
- `reply_to_email` (string): Optional Reply-To address for campaign emails.

Output parameters:

- `branding` (object|null): The stored branding row.

### `get_email_branding` (~34 tokens)

Get the organization's current email branding (display name, logo URL, brand color, intro, business address, reply-to).

Output parameters:

- `branding` (object|null): The stored branding row, or null when the organization has never set branding.

### `create_email_campaign` (~419 tokens)

Create a branded rate-email campaign: on a cadence, email the campaign's recipient list the latest rates for one or more states (or a named region preset) under the org's branding, with ONE OR MORE products (1-5, no duplicates). Each product is one of: {category:'mortgage', subtype:'30-year-fixed'|'15-year-fixed'}, {category:'auto', condition:'new'|'used'|'any', term_months?:36|48|60|72|84} (auto = cars only), or {category:'rv'|'boat'|'motorcycle', condition:'new'|'used'|'any'}. Defaults to a single 30-year-fixed mortgage if products is omitted. Created 'paused'; add recipients, then activate via update_email_campaign (activation requires branding display_name + business_address). Requires a Pro plan. Provide exactly one of state_code, state_codes, or region.

Input parameters:

- `cadence` (string): Send cadence (default weekly).
- `intro_text_override` (string): Per-campaign intro; falls back to branding intro_text.
- `name` (string, required): Campaign label. Required.
- `products` (array): 1-5 products to feature (no duplicates). Each is {category:'mortgage', subtype:'30-year-fixed'|'15-year-fixed'}, {category:'auto', condition:'new'|'used'|'any', term_months?:36|48|60|72|84}, or {cate…
- `region` (string): Named region preset (e.g. east_coast); expands server-side to its member states.
- `state_code` (string): Legacy single 2-letter US state code (e.g. CA). Prefer state_codes or region for multi-state coverage.
- `state_codes` (array): 2-letter US state codes (up to 25) — best rates are ranked ACROSS all of them, not per state.

Output parameters:

- `amount` (number|null): Loan amount used when pricing the featured rates.
- `cadence` (string|null): 'daily', 'weekly', or 'monthly'.
- `created_at` (number|null): Epoch-ms creation time.
- `credit_score` (number|null): Assumed borrower credit score.
- `id` (string): Campaign id (camp_...) — pass to the other campaign tools.
- `intro_text_override` (string|null): Per-campaign intro, overriding the org default.
- `last_run_at` (number|null): Epoch-ms of the last send, null if never.
- `name` (string): Campaign label.
- `organization_id` (string): Owning organization.
- `product_category` (string|null): 'mortgage', 'auto', 'heloc', or 'personal'.
- `product_subtype` (string|null): Product subtype, when set.
- `product_type` (string|null): Primary product type, e.g. '30-year-fixed'.
- `products` (array|null): Parsed list of products the email covers.
- `region_preset` (string|null): Region preset key when the campaign was scoped by region, else null.
- `state_code` (string|null): Legacy scalar state — always the first entry of state_codes.
- `state_codes` (array|null): Full list of two-letter state codes the campaign covers.
- `status` (string|null): 'draft', 'active', or 'paused'. New campaigns start as 'draft'.
- `term_months` (number|null): Term in months.
- `updated_at` (number|null): Epoch-ms last-modified time.

### `list_email_campaigns` (~29 tokens)

List the organization's branded rate-email campaigns (name, criteria, cadence, status, last run).

Output parameters:

- `campaigns` (array): The campaigns visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.
- `count` (number|null): Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.

### `update_email_campaign` (~244 tokens)

Update a campaign's name, geography, cadence, intro override, products, or status. products (if given) is the full replacement set (1-5, same union as create_email_campaign). Any geography field replaces the campaign's whole state selection. Set status 'active' to start sending (requires branding display_name + business_address) or 'paused' to stop. Provide exactly one of state_code, state_codes, or region.

Input parameters:

- `cadence` (string)
- `id` (string, required): Campaign id. Required.
- `intro_text_override` (string)
- `name` (string)
- `products` (array): Full replacement product set (1-5, no duplicates); same shapes as create_email_campaign.
- `region` (string): Named region preset (e.g. east_coast); expands server-side to its member states.
- `state_code` (string): Legacy single 2-letter US state code. Prefer state_codes or region.
- `state_codes` (array): 2-letter US state codes (up to 25) — best rates are ranked ACROSS all of them, not per state.
- `status` (string)

Output parameters:

- `cadence` (string|null): 'daily', 'weekly', or 'monthly'.
- `created_at` (number|null): Epoch-ms creation time.
- `id` (string): Campaign id.
- `intro_text_override` (string|null): Per-campaign intro override.
- `last_run_at` (number|null): Epoch-ms of the last send.
- `name` (string): Campaign label.
- `organization_id` (string): Owning organization.
- `product_category` (string|null): Product family.
- `product_type` (string|null): Primary product type.
- `products` (array|null): Parsed list of products the email covers.
- `region_preset` (string|null): Region preset key, or null.
- `state_code` (string|null): Legacy scalar state — first entry of state_codes.
- `state_codes` (array|null): Full list of covered state codes.
- `status` (string|null): 'draft', 'active', or 'paused'.
- `updated_at` (number|null): Epoch-ms last-modified time.

### `delete_email_campaign` (~35 tokens)

Delete a branded rate-email campaign and its recipients. This cannot be undone.

Input parameters:

- `id` (string, required): Campaign id. Required.

Output parameters:

- `success` (boolean): True when the campaign was deleted.

### `add_campaign_recipients` (~62 tokens)

Add recipients (email + optional name) to a campaign. Up to 50 per request, 200 per campaign. Duplicate addresses are ignored.

Input parameters:

- `id` (string, required): Campaign id. Required.
- `recipients` (array, required): Recipients to add.

Output parameters:

- `added` (number): Recipients newly inserted by this call.
- `total` (number): Total recipients on the campaign afterwards (capped at 200).

### `remove_campaign_recipient` (~43 tokens)

Remove one recipient from a campaign by recipient id.

Input parameters:

- `id` (string, required): Campaign id. Required.
- `recipient_id` (string, required): Recipient id. Required.

Output parameters:

- `success` (boolean): True when the request completed.

### `send_test_campaign` (~52 tokens)

Send a one-off test render of a campaign (with live rates and the org's branding) to the organization owner's email. Does not affect the campaign schedule.

Input parameters:

- `id` (string, required): Campaign id. Required.

Output parameters:

- `message` (string): Confirmation naming the address the test was sent to.
- `ok` (boolean): True when the test email was accepted by the email provider.

### `send_campaign_now` (~91 tokens)

Send a campaign to ALL of its recipients immediately (one full send, the same path the daily cron uses). The campaign must be active. Honors suppressions and the per-org daily cap, resets the cadence clock (the next scheduled send counts from now), and is guarded against double-fires. Returns { run_id, sent, suppressed, failed }.

Input parameters:

- `id` (string, required): Campaign id. Required.

Output parameters:

- `failed` (number): Recipients the provider rejected.
- `run_id` (string|number|null): Id of the campaign run, for correlating with send history.
- `sent` (number): Emails handed to the provider.
- `suppressed` (number): Recipients skipped because they had unsubscribed or were otherwise suppressed.

### `subscribe_rate_alert` (~284 tokens)

Subscribe a consumer to an EMAIL rate alert: notify them when the live market meets their target (rate/apr/monthly_payment crossing a threshold). Consent-first — sends a double-opt-in confirmation email; the alert only activates after the recipient confirms. One-click unsubscribe in every email (CAN-SPAM). Stores only email + alert criteria. Provide exactly one of state, states, or region.

Input parameters:

- `amount` (number): Loan amount in dollars. Optional.
- `credit_score` (number): Credit score (300-850). Optional.
- `email` (string, required): Consumer email address to send the alert to. Required.
- `intent` (string, required): The loan intent. Required.
- `product_type` (string, required): Type of loan product. Required.
- `region` (string): Named region preset (e.g. east_coast); expands server-side to its member states.
- `state` (string): Legacy single US state code (2-letter, e.g., CA, TX, NY). Prefer states or region for multi-state alerts.
- `states` (array): 2-letter US state codes (up to 25) — best rates are ranked ACROSS all of them, not per state.
- `target` (object, required): The condition that triggers the alert. Required.
- `term_months` (number): Loan term in months (12-480). Optional.

Output parameters:

- `alert_id` (string): Id of the created alert.
- `assumed_defaults` (object): Loan assumptions recorded with the alert; null where the caller supplied none.
- `disclosures` (array): Consent and CAN-SPAM disclosures for the subscription.
- `email` (string): Subscriber address.
- `message` (string): Human-readable next step ('Check your inbox to confirm').
- `next_actions` (array): Suggested follow-up tool names.
- `region_preset` (string|null): Region preset key when one was used, else null.
- `state` (string|null): Legacy scalar state — the first entry of `states`.
- `states` (array|null): Full list of watched state codes. Regions are expanded to a fixed snapshot at subscribe time.
- `status` (string): Typically 'pending_confirmation'.
- `target` (object): The threshold that fires the alert.

### `list_rate_alerts` (~48 tokens)

List the rate alerts subscribed for a given email (status, product, state, intent, target, last notified).

Input parameters:

- `email` (string, required): The email whose alerts to list. Required.

Output parameters:

- `alerts` (array): The borrower's alerts, newest first.
- `count` (number): Number of alerts returned.

### `unsubscribe_rate_alert` (~37 tokens)

One-click unsubscribe via the per-alert token embedded in every email.

Input parameters:

- `token` (string, required): The unsubscribe token from the email. Required.

Output parameters:

- `alert_id` (string): The alert that was unsubscribed.
- `status` (string): 'unsubscribed' on success.

### `search_docs` (~188 tokens)

DOCS: search the RateAPI documentation (authentication, rate limits and pricing, coverage, freshness, methodology, eligibility, endpoint map, product parameters, errors, the MCP server itself, and the rules for quoting the data). Use this whenever the question is about the API rather than about a rate — "how do I authenticate?", "what does rate_phase mean?", "which endpoint gives deposit APYs?", "how fresh is this?", "what does it cost?" — instead of guessing at parameters or inventing endpoints. Returns ranked pages with an excerpt; call get_doc for the full text. This tool NEVER returns rates.

Input parameters:

- `limit` (number): Maximum pages to return (1-12). Defaults to 5.
- `query` (string, required): What you want to know about the API, in plain words (e.g. "oauth", "how fresh are rates", "429 error").

Output parameters:

- `count` (number|null): Number of pages returned.
- `note` (string|null): Guidance on what to do with these results.
- `query` (string|null): The query as received.
- `results` (array|null): Matching documentation pages, best match first.

### `get_doc` (~128 tokens)

DOCS: return the full text of one RateAPI documentation page by slug (from search_docs) or by its published URL. Documentation only — it describes the contract, not live rates. Available slugs: quickstart, authentication, rate-limits-and-pricing, coverage, freshness, evidence-and-methodology, quoting-rules, eligibility, endpoints, mcp-server, products-and-parameters, errors-and-troubleshooting, deprecation-policy.

Input parameters:

- `slug` (string): The page identifier returned by search_docs.
- `url` (string): Alternatively, the canonical published URL of the page.

Output parameters:

- `available` (array|null): Valid slugs, returned alongside an error.
- `content` (string|null): Full page text in markdown, ending with its source URL.
- `error` (string|null): Present when no page matched the reference given.
- `slug` (string|null): The page identifier.
- `summary` (string|null): One-line description of the page.
- `title` (string|null): Page title.
- `url` (string|null): Canonical published URL to cite.

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/dev-rateapi-mcp/mcp#diagnostics

## Score history

- 2026-09-21: 83
- 2026-09-20: 82
- 2026-09-19: 82
- 2026-09-18: 81
- 2026-09-17: 81
- 2026-09-16: 80
- 2026-09-15: 80
- 2026-09-14: 80
- 2026-09-13: 79
- 2026-09-12: 79
- 2026-09-11: 78
- 2026-09-10: 78
- 2026-09-09: 77
- 2026-09-08: 77
- 2026-09-07: 76
- 2026-09-06: 76
- 2026-09-05: 76
- 2026-09-04: 75
- 2026-09-03: 75
- 2026-09-02: 74
- 2026-09-01: 74
- 2026-08-31: 73
- 2026-08-30: 73
- 2026-08-29: 72
- 2026-08-28: 72

## Common questions

### What is the RateAPI — live US mortgage, auto, HELOC, personal… MCP server?

RateAPI — live US mortgage, auto, HELOC, personal… is an MCP server listed in the public MCP registry as dev.rateapi/mcp. Live US mortgage, auto, HELOC, personal & deposit rates with evidence, plus who can join each lender. This page covers its hosted endpoint (https://mcp.rateapi.dev/mcp).

### Is the RateAPI — live US mortgage, auto, HELOC, personal… MCP server safe to use?

RateAPI — live US mortgage, auto, HELOC, personal… scores 83 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the RateAPI — live US mortgage, auto, HELOC, personal… MCP server expose?

RateAPI — live US mortgage, auto, HELOC, personal… exposes 89 tools: get_financing_decision, list_credit_unions, find_credit_unions_near_zip, find_product_rates_near_zip, get_credit_union, and 84 more. Their descriptions and schemas cost roughly 19,967 tokens of context every time the server is loaded.

### Does the RateAPI — live US mortgage, auto, HELOC, personal… MCP server require authentication?

Yes. RateAPI — live US mortgage, auto, HELOC, personal… asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.

### Is the RateAPI — live US mortgage, auto, HELOC, personal… MCP server still maintained?

RateAPI — live US mortgage, auto, HELOC, personal… is still listed as active in the MCP registry. We last reached this channel on 21 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- Remote endpoint: https://mcp.rateapi.dev/mcp
- Website: https://rateapi.dev/mcp
- Changelog RSS feed: https://verifymcp.io/servers/dev-rateapi-mcp/mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/dev-rateapi-mcp/mcp.json
- HTML version of this page: https://verifymcp.io/servers/dev-rateapi-mcp/mcp
