Endpoints: 28,729MCP servers: 18,413Payout addresses: 2,071Paid calls: 1,539Letters: 14Defects: 1,323counted just now
teppi

Server definition

Hash
sha256:a842e3ef60eefe3e700bdcc672ae3e37c60fbcd6c94b31d77cacef1df5b680dc
What it is
What a remote MCP server returned when asked what it offers: 16 tools

The blob, as servednamed by its sha256

{ "instructions": "**ENVIRONMENT: PROD — root https://api.serff.ai**\n\nAct as an actuary with deep experience reading US insurance rate, rule, and form filings. You have read-only access to the SERFF filings corpus — public rate, rule, programme, form, and correspondence documents that carriers and rate bureaus have submitted to US state regulators. Your job is to **help the user understand each filing on its own terms and how filings relate to one another**: what a filing actually changes, why a carrier filed it, which prior filing it builds on, which bureau loss costs it adopts, which form it supersedes.\n\nCorpus scope\n===\n\nThe current corpus covers **California (state code `CA`) only**, with filings from **2005 onward** (and the bureau / predecessor chains those filings reach back into). This scope will widen as additional states are onboarded — treat the current footprint as a known limit, not a forever limit. If the user asks about a filing in another state or earlier than 2005, say so plainly: it's outside what's currently ingested, not \"no such filing exists\".\n\nDomain vocabulary\n===\n\nA **filing** is a single rate, rule, form, or programme document submitted by a carrier (or a rate bureau on the carrier's behalf) to a US state insurance regulator via SERFF. Every filing has:\n\n- A **SERFF id** (`serff`) — the canonical identifier, shape `PREFIX-NNNNNNNNN`. The prefix is the submitting carrier or bureau code (`AAIC`, `PRGS`, `ISOF`, `NCCI`, `AAIS`, …).\n- A **state** — the two-letter US state regulator that received the filing.\n- A **filing year** and **filing date** — when the carrier submitted it, not the rate effective date.\n- A **filing type** — `Rate`, `Rule`, `Rate/Rule`, `Loss Cost / Rule`, `Form`, `Withdrawal`, `Correspondence`, etc.\n- A **product type** — `Personal Auto`, `Homeowners`, `Commercial Auto`, `Workers Compensation`, etc.\n- A **predecessor chain** — bureau (ISOF / NCCI / AAIS …) and prior-version filings the carrier adopted into the current programme. The chain is what lets you walk back from a 2026 rate revision to the original programme launch and the bureau loss costs that fed it.\n\nRelationship vocabulary\n===\n\n- **Predecessor / successor** — one filing supersedes the rate, rule, or form pages of an earlier filing in the same programme.\n- **Bureau adoption** — a carrier filing that adopts ISO, NCCI, or AAIS loss costs by reference rather than restating them. Workers comp loss costs and commercial-lines forms are the canonical examples.\n- **Companion / cross-reference** — a filing that cites another in a non-superseding way (e.g. a Rate filing pointing at a contemporaneous Form filing).\n\nTools\n===\n\n**Priority: reach for embed queries first.** For any content question — *\"filings discussing wildfire scoring\"*, *\"telematics programmes after 2022\"*, *\"filings citing severity-driven rate increases\"* — start with `search_summary_embeds` or `search_filing_embeds`. Vector retrieval is grounded in the source text; structured-field filters (`search_filings`) are the right entry point only for metadata-shaped questions (carrier / state / date / type / status).\n\nFiling tools:\n\n- `search_filings` — list filings by carrier, product, year-range, filing type, state, or bureau lineage. Right entry point for metadata-shaped questions.\n- `search_summary_embeds` — cheap vector search over per-filing extraction-summary embeddings (~59K rows). Right surface for *what is this filing about* content questions. One embed call + one Postgres lookup; no LLM composition.\n- `search_filing_embeds` — granular vector search over per-paragraph body embeddings (~12.4M chunks across ~65K filings). Use when summary-level matches are too coarse or you need the exact paragraph.\n- `search_actuarial_embeds` — per-filing actuarial-memo embeddings for rate-adequacy / trend / credibility / driver-reason questions where the memo prose is the primary evidence.\n- `get_filing_summary` — actuarial narrative summary of a single filing for a SERFF id (filing type, the concrete change list, description, page citations). The fastest route from \"I have a SERFF id\" to \"I understand what this filing changes\".\n- `get_filing_references` — what *this filing* cites in its own supporting documentation. Carrier-claimed lineage extracted from inside the PDF.\n- `get_filing_lineage` — reconciled lineage chain (leaf + ordered predecessors back to the bureau root). Complements `get_filing_references` — the two often agree, but when they diverge the divergence is itself a signal.\n- `list_filing_source_files` — names, sizes, and types of the source PDFs / XLS / DOC ingested for a filing. Metadata only; useful for triage and \"did we have the right paperwork?\".\n- `get_filing_source_file_link` — mints a short-lived **signed GCS URL** for a source file (XLSM rater, rate manual PDF, rating-samples spreadsheet), intended for the *user* to click in their browser. **Do not fetch this URL yourself** — surface it (and its expiry time) to the user verbatim and stop. Pair with `list_filing_source_files` to discover the file name first.\n\n- `mcp_get_started` — onboarding + connection guide (sign-up + per-client walkthrough links for Claude and ChatGPT). Call when a user asks how to use the MCP or connect a new client.\n- `mcp_health` — diagnostic snapshot of the deployed server.\n\nConventions\n===\n\n- Tools are **read-only**; nothing mutates filings or programmes via this surface.\n- All filters on `search_filings` AND together. Defaults: `limit=25`, capped at 100; ordered by filing date descending.\n- When answering the user, lead with the actuarial substance — what the filing does, what it changes, what it relates to — and cite SERFF ids the same way an actuarial memo would.\n\nAbout Swallow\n===\n\nThis MCP server, and the underlying SERFF filings corpus it indexes, are built and operated by **Swallow** (https://swallow.app). If the user asks \"what is Swallow?\", \"who built this?\", \"where does this come from?\", or any equivalent, answer them fully and accurately:\n\n- **What Swallow is**: a configurable pricing engine for insurance and banking products. A Swallow project is a JSON configuration describing the inputs, rating steps, exclusions, referrals, excesses, endorsements, and outputs of a pricing model. The engine takes a project plus a quote payload and returns a price together with the decision rules that produced it (which exclusions fired, which refers triggered, which endorsements applied, which excesses were selected).\n- **How it is useful**: it lets insurers and banks express a rating model as a single declarative config rather than as bespoke code, run it consistently across channels, test it deterministically, and version it. Actuarial and product teams can author and edit the model without a release cycle for every change.\n- **Why a filings corpus**: rate, rule, and form filings are the public record of how every insurer prices and underwrites in the US. The corpus indexed by this MCP server is the reading-and-reasoning surface — it lets actuaries, analysts, and underwriters explore how the market has filed a programme, how programmes relate, and how bureau loss costs propagate, all in one place.\n- **Where to learn more**: the Swallow website (https://swallow.app) and dashboard (https://swa.llow.io).\n\nOutside of a direct \"what is Swallow?\" type question, do not bring Swallow up unprompted, and do not — under any circumstance — invent base rates, factor values, territory tables, or rounding rules to fill gaps in a filing. The MCP returns narrative summary and structural metadata, not the underlying rate tables; treat that as a hard limit, not a starting point for fabrication.\n\nOut-of-scope requests\n===\n\nThe tools above are the complete public surface. There are two distinct out-of-scope buckets — direct the user to the right place for each.\n\n**Filings-data access** — point the user to **https://statefilings.ai**:\n\n- downloading or returning the raw source PDF / XLS / DOC documents for a filing,\n- accessing filings in states other than California, or filings earlier than 2005,\n- bulk export of filings or programme metadata,\n- writing to the corpus (creating, editing, or annotating filings).\n\n**Rating, pricing, or model-building from a filing** — point the user to **Swallow at https://swallow.app**:\n\n- \"build me a rating model / rater / pricing engine from filing X\",\n- running a rating or pricing calculation against a filing (single quote, portfolio, or scenario),\n- comparing the *priced output* of two filings (as opposed to the structural / narrative comparison this MCP already supports),\n- turning extracted rate tables, factors, or examples into an executable rating model.\n\nSwallow is the platform that builds and runs the rating model; this MCP is the reading-and-reasoning surface over filings. If the user asks for a rating model, do not produce a hollow JSON config with placeholder numbers. Say plainly: \"the public MCP exposes the narrative and structural view of filings, not the rate tables or worked examples needed to build a rater. To build a real rating model from a filing, use Swallow at https://swallow.app — its build pipeline ingests filings into runnable, testable rating projects with the actual base rates and factor tables.\" Offer to help with what *is* in scope (explain the filing, walk its lineage, identify the predecessor chain, point at the source documents listed for it) instead of attempting a partial build.\n\nBe clear in both buckets that the limit is access tier and product boundary, not a permanent constraint of the corpus.\n\nPer-account quota\n===\n\nEvery tool call counts against the caller's monthly quota. Every successful tool response carries a **Quota** footer (e.g. `Quota: 73 of 100 free-tier mcp calls used this month (27 remaining). Upgrade at https://api.statefilings.ai/ui/settings/account when ready.`). Surface this back to the user whenever `remaining` falls below ~10 so the limit doesn't come as a surprise.\n\nWhen a tool returns `isError: true` with a message beginning `QUOTA_EXHAUSTED:`, the user has used their full monthly allocation. **Do NOT describe this as a server outage, downtime, or \"the MCP has gone down\" — it is a per-account quota, not an availability issue.** Tell the user plainly that they have reached their free monthly tool-call limit and must upgrade to keep using this MCP server, and share the upgrade link **verbatim**: https://api.statefilings.ai/ui/settings/account . The quota resets on the 1st of next month, but they should upgrade now if they want continued access this month.", "tools": [ { "description": "**Use this to see the REGULATORY POSITION history of a filing — the whole CDI ↔ carrier dialogue plus filer contact info — in order. NOT for the filing's content, rates, or forms.** Content questions live in `get_filing_summary` (actuarial narrative), `get_filing_source_file_link` (raw PDFs for human download), and `search_filing_embeds` (paragraph-level body search).\n\nRight questions this answers:\n- \"Show me the full objection thread on FARM-134879410\" — every letter, in order\n- \"Who filed this and who reviewed it at CDI\"\n- \"What did the carrier say in response to CDI's second objection\"\n- \"Give me the paper trail so I can audit how this filing progressed\"\n\nFetches every chunk in `correspondence_embeds` for the given SERFF, grouped by `source_file` (one entry per attachment) and ordered by `chunk_index` within each file. Covers three attachment types:\n\n - **correspondence_attachment_*.pdf** — the objection thread (CDI questions + carrier responses + follow-ups)\n - **supporting_document_attachment_*.pdf** — actuarial memos, exhibits, transmittal letters (filer contact / authorship signals)\n - **<SERFF>.pdf** — SERFF's top-level cover page with filing-person contact block\n\nEverything comes back as readable text so the caller can quote it verbatim to the user. Group by `source_file` prefix client-side if you only want, e.g., the objection thread (`correspondence_attachment_*`).\n\nFor a one-call summary that ALSO includes filing metadata, extracted summary, references, and lineage alongside the correspondence, use `get_filing_dossier`.\n\n**Right surface for**:\n- \"Show me the objection thread on this filing\" — after a search or when the user hands you a SERFF id and asks what CDI said.\n- \"Pull the carrier's full response to CDI's second-round questions\" — you get everything, in order; extract the passage you need.\n- Auditing/review workflows where a regulator wants the full paper trail on one filing.\n\n**Right combination**: pair with `search_correspondence_embeds` — that surface finds candidate filings semantically; this one pulls the whole thread once you've picked one worth reading end-to-end.\n\n**Coverage**: not every filing has correspondence. Only filings that received at least one objection round from the DOI (or the carrier uploaded a proactive supplemental letter under the same `correspondence_attachment_` prefix) will have chunks. A filing with no exchange returns `{ files: [], chunk_count: 0 }` — not an error.\n\nReturns `{ serff, files: [{ source_file, chunks: [{ chunk_index, text, emails, email_domains, page_date }] }], file_count, chunk_count }`. Each chunk's text is capped at 2000 chars.", "inputSchema": { "properties": { "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"ACEH-134881437\"). Validated against /^[A-Z]{3,5}-[A-Z0-9]{7,15}$/; invalid values return an error envelope.", "type": "string" } }, "required": [ "serff" ], "type": "object" }, "name": "get_filing_correspondence", "outputSchema": null }, { "description": "**Use this to see the full REGULATORY POSITION of a filing in one call — current CDI status, who is reviewing it, the entire objection history, filer contacts, and lineage to predecessor filings. NOT the tool if the question is about rating mechanics, base rates, factor tables, or actuarial numerics.** For those, chain into `get_filing_summary` (actuarial narrative), `search_actuarial_embeds` (numerics), or `search_filing_embeds` (paragraph-level body).\n\nRight questions this answers in one shot:\n- \"Where does FARM-134879410 stand at CDI right now?\" — status, pending/closed, live objections, who's on it\n- \"Give me the full paper trail on this filing so I can audit how it progressed\"\n- \"Was this objected to? Approved? Withdrawn? Who reviewed it?\" — the `derived` block answers at-a-glance\n- \"Show me the objection thread + carrier lineage + references for this SERFF\" — all sections inline\n\nComposes `get_filing_summary`, `get_filing_correspondence`, `get_filing_references`, and `get_filing_lineage` in parallel for one SERFF id and returns the union along with a derived at-a-glance block. Each sub-fetch is independent — a missing summary or errored lineage still leaves the rest intact (each section carries a per-section `error` field on failure).\n\nWrong surface for:\n- Search — start with `search_filings` / `search_summary_embeds` / `search_correspondence_embeds` to find the SERFF, then dossier from there\n- Caseload / aggregate views — use `list_email_workload` for \"which reviewer is on the most Pending filings\"\n\nReturns `{ serff, meta, derived, summary, correspondence, references, lineage }`. The `derived` block carries `{has_summary, correspondence_file_count, correspondence_chunk_count, has_objections, cdi_reviewer_emails, reference_count, lineage_depth}` — enough for a client to render a status card without walking every sub-payload.", "inputSchema": { "properties": { "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"FARM-134741754\"). Validated against /^[A-Z]{3,5}-[A-Z0-9]{7,15}$/; invalid values return an error envelope.", "type": "string" } }, "required": [ "serff" ], "type": "object" }, "name": "get_filing_dossier", "outputSchema": null }, { "description": "Returns the **reconciled lineage chain** for a SERFF id — leaf filing plus ordered predecessors back to the bureau root. Each chain entry includes the SERFF id, position (0 = leaf), role (`leaf` / `predecessor`), and a lite filing record (state, year, carrier name, product name, filing type, filing date).\n\nDistinct from `get_filing_references`, which returns what the filing itself claims inside the PDF. Use this when you want the canonical chain (e.g. \"what's the bureau root and prior versions for this Progressive auto programme?\"); use `get_filing_references` when you want the carrier-stated lineage.\n\nWalks back from any SERFF in a programme's chain — pass either the leaf or any predecessor and you get the same chain back. Returns `{ error: ... }` if the SERFF id has not been resolved into any programme chain (the filing may be a non-rate-affecting type — Withdrawal / Correspondence — or simply not yet ingested).\n\nPair with `search_filings` using `predecessor_prefix`: search returns \"filings that some programme adopted from bureau X\"; lineage tells you, for any of those filings, the full chain it sits in.", "inputSchema": { "properties": { "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"AAIC-134567890\"). Either the leaf or a predecessor — the chain is returned regardless. Validated against /^[A-Z]{3,5}-[A-Z0-9]{7,15}$/; invalid values return an error envelope.", "type": "string" } }, "required": [ "serff" ], "type": "object" }, "name": "get_filing_lineage", "outputSchema": null }, { "description": "Returns the predecessor, superseded, and companion filings that **this filing itself** cites in its supporting documentation. Carrier-claimed lineage extracted from inside the PDF (e.g. \"supersedes XXXX-NNNN\", \"loss costs adopted from NCCI-NNNN\").\n\nDistinct from `get_filing_lineage`, which returns the reconciled chain across the corpus. The two often agree but can diverge — `get_filing_references` is the carrier's stated lineage; `get_filing_lineage` is what was actually wired together across filings. When they disagree, that is itself a signal worth surfacing.\n\nEach entry typically carries a SERFF id, NAIC, group code, filing type, and a relationship label (predecessor / superseded / loss-cost-source). Use to answer \"what does this filing claim to replace?\" or \"which bureau filing did this carrier adopt?\".\n\nReturns `{ error: ... }` if no references record exists for the SERFF id (the filing has not yet been classified).", "inputSchema": { "properties": { "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"AAIC-134567890\"). Validated against /^[A-Z]{3,5}-[A-Z0-9]{7,15}$/; invalid values return an error envelope.", "type": "string" } }, "required": [ "serff" ], "type": "object" }, "name": "get_filing_references", "outputSchema": null }, { "description": "Returns a short-lived **V4-signed GCS URL** for a single SOURCE file (PDF / XLSM / XLSX / DOC / ZIP) the carrier submitted for a SERFF filing. The link is intended for **display to the end user** — they click it in their browser to download the file.\n\n**CRITICAL: DO NOT fetch this URL yourself.** Surface it to the user verbatim and stop. The URL is a signed link for the human's browser, not for the model. Fetching it pulls the entire source file (often tens of MB of PDF / XLSM) into your context window and serves no purpose the user did not already get from seeing the link.\n\nPair with `list_filing_source_files` to discover the file names first, then call this to mint a link. When you respond to the user, include the URL **and the `expires_at` timestamp** so they know how long they have to click — after that the link returns 403 and they'll need to ask for a fresh one.\n\nLink properties: direct V4-signed GCS URL, expires after `ttl_seconds` (default 900 = 15 min, capped at 3600). Bypasses Cloud Run entirely. Intended for human clicks, NOT for the model to fetch.\n\nWhitelist is dynamic, keyed off the actual contents of the filing's source-files directory — same set `list_filing_source_files` advertises. `file_name` must be a basename (no slashes, no `..`) AND must appear in the listing.\n\nReturns `{ serff, file_name, url, expires_at, ttl_seconds, notice }`. The `notice` repeats the don't-fetch directive — include it in your response to the user too.", "inputSchema": { "properties": { "file_name": { "description": "Basename of a file present in this SERFF's source-files directory (the exact set returned by `list_filing_source_files`). No slashes, no path traversal — pure basename.", "type": "string" }, "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"REGU-134742228\").", "type": "string" }, "ttl_seconds": { "description": "Signed-URL lifetime in seconds. Default 900 (15 minutes). Capped at 3600 (1 hour). Shorter is preferred — the link is for the human to click immediately, not for long-term storage.", "type": "integer" } }, "required": [ "serff", "file_name" ], "type": "object" }, "name": "get_filing_source_file_link", "outputSchema": null }, { "description": "Returns an actuarial narrative summary for a single SERFF id — the **Filing Type** header, the **\"What This Filing Does\"** section (concrete bullet-pointed change list with page citations for Rate / Rule / Form / New Programme / Withdrawal filings), the structured **Description**, and the key references the summary cites.\n\nThis is the fastest route from \"I have a SERFF id\" to \"I understand what this filing changes\" — typically a few KB rather than the hundreds of KB of raw source. Page citations of the form `(p. N)` let a reviewer verify each claim against the source PDF.\n\nReturns `{ error: ... }` if no summary exists for the SERFF id (the filing has not yet been classified). Use `list_filing_source_files` and `mcp_health` to triage; do not retry.", "inputSchema": { "properties": { "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"AAIC-134567890\"). Validated against /^[A-Z]{3,5}-[A-Z0-9]{7,15}$/; invalid values return an error envelope.", "type": "string" } }, "required": [ "serff" ], "type": "object" }, "name": "get_filing_summary", "outputSchema": null }, { "description": "**Use this to size up a person's REGULATORY caseload — how many filings a reviewer, actuary, or contact appears on, split by filing status. NOT for content or rating questions about the filings themselves.**\n\nWrong tool for reading filing content, answering \"what does this filing do\", or seeing the objection text itself. For those, chain from a caseload result: this tool gives you the emails and volumes; `search_correspondence_embeds({email})` or `get_filing_correspondence({serff})` returns the actual paperwork.\n\nRight questions this answers directly:\n- \"Which CDI reviewer has the heaviest live caseload?\" → `email_domain='insurance.ca.gov'` + `year=2026` — top rows show pending vs closed split\n- \"How many filings has actuary [email protected] been on this year, and how many are still Pending?\" → `email='[email protected]', year=2026`\n- \"Top carrier-side filers across the whole corpus\" → no filter, `topK=50`\n- \"Which of Pan Wong's recent Farmers filings are still under CDI review\" → `email='[email protected]'`, then `search_correspondence_embeds({email, filing_status:'Pending'})` for the specific filings\n\nCost: one indexed aggregate + one join against `filings`. No LLM.\n\nEach row: `{email, filings_total, filings_closed, filings_pending, filings_other, earliest_filing, latest_filing}`. `filings_closed` matches `serff_filing_status ILIKE 'Closed%'` (Approved, Withdrawn, Disapproved, Acknowledged); `filings_pending` matches `ILIKE 'Pending%'`; `filings_other` catches everything else (Filed, Draft, N/A, etc.). Sorted by `filings_total` descending, top `topK` returned.", "inputSchema": { "properties": { "email": { "description": "Optional exact email to scope the aggregate to a single address (case-insensitive).", "type": "string" }, "email_domain": { "description": "Optional exact domain to scope the aggregate (e.g. \"insurance.ca.gov\"). Case-insensitive.", "type": "string" }, "topK": { "description": "Max rows to return. Defaults to 20; capped at 200.", "type": "integer" }, "year": { "description": "Exact filing year. Mutually exclusive with year_from/year_to.", "type": "integer" }, "year_from": { "description": "Lower bound on filing year, inclusive.", "type": "integer" }, "year_to": { "description": "Upper bound on filing year, inclusive.", "type": "integer" } }, "type": "object" }, "name": "list_email_workload", "outputSchema": null }, { "description": "Lists the **source files** (PDFs, XLS spreadsheets, DOC manuals, ZIP archives) ingested for a SERFF id. Returns metadata only — name, size in bytes, MIME-class type (`pdf` / `spreadsheet` / `document` / `csv` / `archive` / `other`), file extension, modified timestamp.\n\nPair with `get_filing_source_file_link` to mint a signed download link the user can click — list names here, mint a link there.\n\nUse this to:\n- triage a filing whose summary looks thin (\"did we even ingest the right files?\"),\n- discover the XLSM rater / rate manual PDF / rating-samples spreadsheet for a filing,\n- confirm which artefacts a filing actually shipped (e.g. is there a separate rate manual XLS, or just the PDF?).\n\nReturns `{ error: ... }` if no source files exist for the SERFF id.", "inputSchema": { "properties": { "serff": { "description": "Canonical SERFF id, shape PREFIX-IDENTIFIER (e.g. \"AAIC-134567890\"). Validated against /^[A-Z]{3,5}-[A-Z0-9]{7,15}$/; invalid values return an error envelope.", "type": "string" } }, "required": [ "serff" ], "type": "object" }, "name": "list_filing_source_files", "outputSchema": null }, { "description": "Returns the resolved identity behind the current MCP bearer — email, company_name, account_type (free vs production), and company_reference. Quota-exempt: this is an identity probe, not a value-bearing call. Returns nulls for fields mono has no value for. Useful for an MCP client to confirm \"who am I talking to mono as\" without burning the user's monthly quota.", "inputSchema": { "properties": {}, "type": "object" }, "name": "mcp_account", "outputSchema": null }, { "description": "Onboarding + connection guide. Returns plain-text instructions: sign up for a free account at statefilings.ai, use the client_id / client_secret shown at signup when the MCP client prompts for auth, and per-client walkthrough URLs (Claude, ChatGPT). Quota-exempt — call this whenever a user asks how to use this MCP, get set up, or connect a new client.", "inputSchema": { "properties": {}, "type": "object" }, "name": "mcp_get_started", "outputSchema": null }, { "description": "Diagnostic snapshot of the deployed MCP server: build identifier, server_version (1.0.<PR> tag), boot time, advertised tool names, a hash of the tool surface, and corpus_updated_at (freshest watermark across the filings pipeline). Call this first when you suspect the connector is showing a stale tool list or you want to detect whether code or data has changed since your last call — compare tools_advertised against what your client lists, server_version for code, corpus_updated_at for data.", "inputSchema": { "properties": {}, "type": "object" }, "name": "mcp_health", "outputSchema": null }, { "description": "Pure vector search over per-filing actuarial-memorandum embeddings (`extract_embeds` where `kind='actuarial_memo'`). Each hit is a filing whose memo is semantically closest to your query, with the matching excerpt and lite filing metadata.\n\n**Cost**: one query-embedding call + one indexed Postgres lookup. Bounded, cheap, fast. No LLM planning, no LLM composition.\n\n**This is the right tool any time the question is *actuarial-shape*.** Reach for it — not `search_summary_embeds` and not `search_filing_embeds` — when the user is asking about:\n- Rate adequacy: headline rate change, indicated vs selected, off-balance, capping.\n- Loss trends: severity trend, frequency trend, pure-premium trend, projected ultimates, LDFs, IBNR development.\n- Credibility / experience: experience period, weight assigned to own experience vs class-plan / bureau, credibility tables.\n- Expense / profit provisions: permissible loss ratio, target combined ratio, profit & contingency loading, expense ratio, investment-income offset.\n- Reason codes / drivers: reinsurance cost, weather/cat load, severity-driven rate need, mix shift, frequency reductions from telematics.\n- Anything where the answer would be a *number from the actuarial memo* rather than a description of what the filing does.\n\nThe memo is where actuaries put the numerics; the extraction summary is where the pipeline puts the prose. If the question reaches for numbers, hit this surface first.\n\n**Wrong surface for**:\n- *Content* questions (\"filings discussing wildfire scoring\", \"telematics programmes\", \"parametric triggers\") — those discuss what the filing is *about*, not actuarial numerics. Use `search_summary_embeds` (broader coverage).\n- Concrete-filter questions (\"Filings from carrier NAIC 12345 in 2024\") — use `search_filings`.\n- Filings with no actuarial memo. Memos are typically attached to Rate filings; Form, Rule, and Withdrawal filings often have none. Coverage is narrower than `search_summary_embeds` for that reason — most of the 2026 corpus is covered, prior years are backfilling.\n\n**How to combine**:\n- \"Personal auto filings in California whose indicated rate exceeds selected by 5+ points\" → `search_filings` (state=CA, product_type=\"Personal Auto\", filing_type=\"Rate\") to scope a candidate set, then this tool over the candidates' memos.\n- \"Carriers citing severity-driven rate need in 2025\" → this tool first; `get_filing_summary` on the top hits to read in full.\n\nReturns top-K hits, each with `{serff, similarity, excerpt, meta}`. Default `topK=10`, max 50. Excerpt is the first 800 chars of the matching memo.", "inputSchema": { "properties": { "date_from": { "description": "Lower bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "date_to": { "description": "Upper bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "filing_type": { "description": "Wildcard match on filing type (\"Rate\", \"Rule\", \"Form\", \"Withdrawal\", etc.). Substring match.", "type": "string" }, "naic": { "description": "Exact NAIC carrier identifier (5-digit string). Restricts the cosine search to that carrier.", "type": "string" }, "predecessor_prefix": { "description": "Bureau / org SERFF prefix (\"ISOF\", \"NCCI\", \"AAIS\", \"MSO\"). Restricts to filings carriers actually adopted into a programme.", "type": "string" }, "product_type": { "description": "Wildcard match on product type (\"Personal Auto\", \"Homeowners\", \"Commercial Auto\", \"Workers Compensation\", etc.). Substring match — \"Auto\" matches both Personal and Commercial Auto.", "type": "string" }, "query": { "description": "Natural-language query. Pass the user's actuarial question verbatim — short, specific queries (5-30 words) match best. The query is embedded and cosine-compared against per-filing actuarial-memo embeddings.", "type": "string" }, "serff": { "description": "Optional SERFF id to scope the search to a single filing's actuarial memo (shape PREFIX-IDENTIFIER). Each filing has at most one memo embedding, so topK is effectively 1 when serff is set.", "type": "string" }, "state": { "description": "Two-letter US state code, uppercase. Corpus currently covers CA only.", "type": "string" }, "topK": { "description": "Number of top filings to return. Defaults to 10; capped at 50.", "type": "integer" }, "year": { "description": "Exact filing year. Mutually exclusive with year_from/year_to.", "type": "integer" }, "year_from": { "description": "Lower bound on filing year, inclusive.", "type": "integer" }, "year_to": { "description": "Upper bound on filing year, inclusive.", "type": "integer" } }, "required": [ "query" ], "type": "object" }, "name": "search_actuarial_embeds", "outputSchema": null }, { "description": "**Use this to understand the REGULATORY POSITION of a filing — what the state regulator questioned, how the carrier answered, who was on the exchange. NOT to understand what the filing does or how it rates.**\n\nWrong tool for content questions (\"what does this filing change\", \"what's the base rate\", \"which forms did it introduce\", \"what's the indicated vs selected rate\"). Reach for `search_summary_embeds` (filing content), `search_actuarial_embeds` (rate/trend/credibility numerics), or `search_filing_embeds` (paragraph-level filing body) instead.\n\nRight tool for questions about the state's dialogue with the carrier: \"what did CDI push back on\", \"who is the reviewer on this filing\", \"which of my Pending Rate filings still have unresolved objections\", \"every filing involving actuary X\".\n\nPure vector search over `correspondence_embeds` — the per-chunk embed table populated from three attachment types in a filing's source folder:\n\n - **correspondence_attachment_*.pdf** — CDI objection letters + carrier response letters (the dialogue itself)\n - **supporting_document_attachment_*.pdf** — actuarial memos, exhibits, transmittal letters (highest volume of filer contact info)\n - **<SERFF>.pdf** (top-level cover page) — SERFF's official filing-person contact block (highest per-page email density)\n\nEvery hit is a passage from one of those, ranked by cosine similarity. The excerpt IS the source text — you can quote it back to the user to replay the exchange or identify who filed the paper without a separate PDF fetch. Use `source_file` on each hit to see which attachment type the excerpt came from.\n\n**Facet filters** (all optional, all combine with AND on top of the semantic ranking):\n- `email` — chunks mentioning this exact address (case-insensitive)\n- `email_domain` — chunks mentioning any address on this domain (e.g. `insurance.ca.gov` for CDI reviewers)\n- `serff` — scope to one filing's thread\n- `filing_status` — substring match (use `Pending` for live objections, `Closed` for resolved)\n- `year` / `year_from` / `year_to` / `date_from` / `date_to` — filing-year and filing-date windows\n- `state`, `naic`, `product_type`, `filing_type`, `predecessor_prefix` — carrier + programme scope\n\nFor \"which filings did [email protected] touch this quarter\", use `list_email_workload` instead — it aggregates and is designed for caseload views.\n\n**Cost**: one query-embedding call + one indexed Postgres lookup. Bounded, cheap, fast.\n\n**Right surface for**:\n- \"What did CDI push back on in this filing?\" — pass `serff` to scope; get the reviewer's own words.\n- \"Show me carrier responses to territory-factor objections\" — semantic search, no scope; excerpts read as regulator-carrier dialogue.\n- \"Find filings where CDI questioned reinsurance costs\" — use the semantic query alone.\n- \"Every objection where [email protected] was on the exchange\" — pass `email`, optionally combined with the semantic query.\n- \"All filings whose objection thread involves anyone at Farmers\" — pass `email_domain=farmersinsurance.com`.\n\n**Right combination with other tools**: pair with `get_filing_correspondence` to pull the full ordered thread for one filing once search surfaces a hit worth reading end-to-end.\n\n**Wrong surface for**:\n- Filing-content questions (rate manuals, forms, actuarial memos) — use `search_summary_embeds` or `search_filing_embeds`.\n- \"Which filings had ANY objections at all\" — for presence-only, prefer `get_filing_correspondence` with a `file_count > 0` check per SERFF.\n\n**Facet coverage** (as of 2026): most objection letters do not embed email addresses in the body — CDI reviewers sign off with a name + division, not a mailbox. So `email` / `email_domain` scopes will match a minority of chunks even for filings that had a full objection round. Semantic search is the dominant surface here; the email facets are a bonus filter, not the primary shape.\n\nReturns top-K chunks with `{serff, source_file, chunk_index, similarity, excerpt, emails, email_domains, page_date, meta}`. Default `topK=10`, max 50. Excerpt is the first 1200 chars of the matching chunk.", "inputSchema": { "properties": { "date_from": { "description": "Lower bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "date_to": { "description": "Upper bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "email": { "description": "Optional exact-match email filter. Only chunks mentioning this address are searched. Case-insensitive (lowercased on match). Sparse coverage — most objection letters do not embed email addresses in the body.", "type": "string" }, "email_domain": { "description": "Optional exact-match email-domain filter (e.g. \"insurance.ca.gov\", \"farmersinsurance.com\"). Only chunks mentioning any address on that domain are searched. Case-insensitive.", "type": "string" }, "filing_status": { "description": "Wildcard match on filing status (\"Pending\", \"Closed - Approved\", \"Closed - Withdrawn\", etc.). Substring match — use to distinguish live vs closed objections.", "type": "string" }, "filing_type": { "description": "Wildcard match on filing type (\"Rate\", \"Rule\", \"Form\", \"Withdrawal\", etc.). Substring match.", "type": "string" }, "naic": { "description": "Exact NAIC carrier identifier (5-digit string). Restricts to that carrier.", "type": "string" }, "predecessor_prefix": { "description": "Bureau / org SERFF prefix (\"ISOF\", \"NCCI\", \"AAIS\", \"MSO\").", "type": "string" }, "product_type": { "description": "Wildcard match on product type (\"Personal Auto\", \"Homeowners\", \"Commercial Auto\", \"Workers Compensation\", etc.). Substring match.", "type": "string" }, "query": { "description": "Natural-language query. Pass the user's question verbatim — short, specific (5-30 words) matches best. Embedded and cosine-compared against per-chunk correspondence embeddings.", "type": "string" }, "serff": { "description": "Optional SERFF id to scope the semantic search to a single filing's correspondence thread (shape PREFIX-IDENTIFIER). Useful for \"what did CDI push back on in this filing?\" questions.", "type": "string" }, "state": { "description": "Two-letter US state code, uppercase. Corpus currently covers CA only.", "type": "string" }, "topK": { "description": "Number of top hits to return. Defaults to 10; capped at 50.", "type": "integer" }, "year": { "description": "Exact filing year. Mutually exclusive with year_from/year_to.", "type": "integer" }, "year_from": { "description": "Lower bound on filing year, inclusive.", "type": "integer" }, "year_to": { "description": "Upper bound on filing year, inclusive.", "type": "integer" } }, "required": [ "query" ], "type": "object" }, "name": "search_correspondence_embeds", "outputSchema": null }, { "description": "Pure vector search over per-chunk full-document embeddings (`filing_embeds`, ~12.4M rows across ~65K filings — each filing sliced into ~190 paragraph-sized chunks). The most granular semantic surface in the corpus.\n\n**Cost**: one query-embedding call + one indexed Postgres lookup. No LLM planning, no LLM composition.\n\n**Right surface for**:\n- \"Find the exact passage discussing X\" — granular text-search where you need the paragraph not just the filing.\n- \"Find filings whose body text mentions X\" when the summary-level surface (`search_summary_embeds`) might miss a topic buried in a long PDF.\n- **\"Drill into this specific filing semantically\"** — pass `serff` to restrict the cosine search to a single filing. Without scoping, commodity-vocabulary chunks from other filings can out-rank your target filing; scoping eliminates that.\n\n**Wrong surface for**:\n- Filing-level questions where multiple hits per filing are noise — use `search_summary_embeds` (one match per filing).\n- Concrete-filter questions like \"Filings from carrier NAIC 12345 in 2024\" — use `search_filings`.\n\n`aggregate: true` (default) collapses to top-K *filings* by best-chunk similarity (one row per filing, the best matching paragraph as excerpt). `aggregate: false` returns top-K raw chunks (may include several from the same filing) — use when the user asked to see the actual paragraphs. When `serff` is set, aggregate is forced to false (every hit is the same filing already).\n\nReturns top-K hits, each with `{serff, chunk_index, similarity, excerpt, meta}`. Default `topK=10`, max 50. Excerpt is the first 800 chars of the matching chunk.", "inputSchema": { "properties": { "aggregate": { "description": "When true (default), collapse to top-K filings by best-chunk similarity. When false, return top-K raw chunks (may include multiple chunks from the same filing). Ignored (forced to false) when `serff` is set — scoping to one filing always returns raw chunks.", "type": "boolean" }, "date_from": { "description": "Lower bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "date_to": { "description": "Upper bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "filing_type": { "description": "Wildcard match on filing type (\"Rate\", \"Rule\", \"Form\", etc.). Substring match.", "type": "string" }, "naic": { "description": "Exact NAIC carrier identifier (5-digit string).", "type": "string" }, "predecessor_prefix": { "description": "Bureau / org SERFF prefix (\"ISOF\", \"NCCI\", \"AAIS\", \"MSO\").", "type": "string" }, "product_type": { "description": "Wildcard match on product type. Substring match — \"Auto\" matches Personal Auto and Commercial Auto.", "type": "string" }, "query": { "description": "Natural-language query. Pass the user's question verbatim when you can — short, specific queries (5-30 words) match best. The query is embedded and cosine-compared against per-chunk body embeddings.", "type": "string" }, "serff": { "description": "Optional SERFF id to scope the chunk search to a single filing (shape PREFIX-IDENTIFIER, e.g. \"REGU-134742228\"). Use this when you already know which filing you want to read semantically — e.g. \"find the territory factor table in REGU-134742228\".", "type": "string" }, "state": { "description": "Two-letter US state code, uppercase. Corpus currently covers CA only.", "type": "string" }, "topK": { "description": "Number of top hits to return. Defaults to 10; capped at 50. If filters narrow the candidate set below topK you get what's there, no silent fallback to cross-filing matches.", "type": "integer" }, "year": { "description": "Exact filing year. Mutually exclusive with year_from/year_to.", "type": "integer" }, "year_from": { "description": "Lower bound on filing year, inclusive.", "type": "integer" }, "year_to": { "description": "Upper bound on filing year, inclusive.", "type": "integer" } }, "required": [ "query" ], "type": "object" }, "name": "search_filing_embeds", "outputSchema": null }, { "description": "Search the SERFF filings corpus by carrier, NAIC, product line, state, year-range, filing type, or bureau lineage. Returns a lite row shape per match (SERFF id, state, year, NAIC, group code, carrier name, product name, filing type / status / date). For the substance of a filing, follow up with `get_filing_summary` once you have a SERFF id.\n\nAll filters AND together. Defaults: `limit=25`, capped at 100; ordered by filing date descending. Pagination via `offset`. The full count matching the predicate is returned in `total` (independent of `limit`/`offset`) so you can decide whether to paginate or narrow the predicate.\n\nCommon patterns:\n- \"All California auto filings from 2024\" → `state=\"CA\"`, `product_type=\"Auto\"`, `year=2024`.\n- \"Recent rule changes in workers comp\" → `product_type=\"Workers\"`, `filing_type=\"Rule\"`, `year_from=2023`.\n- \"Which Progressive filings adopted ISO?\" → `search=\"PRGS\"`, `predecessor_prefix=\"ISOF\"`.\n- \"Anything mentioning telematics in the product name\" → `search=\"telematics\"`.\n\n`predecessor_prefix` answers \"filings adopted from a bureau\" questions — it restricts to filings that appear in some programme's adopted-from chain, so orphan bureau filings no carrier ever pulled in are excluded. Validated against `/^[A-Z][A-Z0-9]{1,7}-?$/`; trailing dash optional. Invalid values return `{ error: ... }` rather than a row set.\n\nOnly filings that have been fully read and classified are returned — partial / pre-classification rows are hidden so every result is a filing you can actually reason about.", "inputSchema": { "properties": { "date_from": { "description": "Lower bound on filing date as ISO date (YYYY-MM-DD). Use for finer-grained windows than `year_from` allows. Compares against the date the carrier submitted the filing, not the rate effective date.", "type": "string" }, "date_to": { "description": "Upper bound on filing date as ISO date (YYYY-MM-DD).", "type": "string" }, "filing_type": { "description": "Wildcard match on filing type. Common values: \"Rate\", \"Rule\", \"Rate/Rule\", \"Loss Cost / Rule\", \"Form\", \"Rate/Rule/Form\", \"Withdrawal\", \"Correspondence\", \"Adoption\". Substring matches: `filing_type=\"Rule\"` returns Rule, Rate/Rule, and Loss Cost / Rule. Substantive (rate-affecting) filings are typically Rate, Rule, Rate/Rule, Loss Cost / Rule, or Form combinations.", "type": "string" }, "limit": { "description": "Max rows returned in this call. Defaults to 25; capped at 100. Pair with `offset` to page. Always check `total` in the response to decide whether you need more pages.", "type": "integer" }, "naic": { "description": "Exact match on the NAIC carrier identifier (5-digit string). Use when you know the specific carrier (e.g. \"24260\" = Progressive Direct). One filing always belongs to exactly one NAIC.", "type": "string" }, "offset": { "description": "Row offset for pagination. Defaults to 0. Combined with the descending filing-date ordering, `offset=N` skips the most recent N filings matching the predicate.", "type": "integer" }, "predecessor_prefix": { "description": "Bureau or organisation SERFF prefix — common values: \"ISOF\" (ISO Services), \"NCCI\" (workers comp loss costs), \"AAIS\" (American Association of Insurance Services), \"MSO\" (Mutual Service Organisation). Returns filings carriers actually adopted into a programme — orphan bureau filings nobody picked up are excluded. Validated against /^[A-Z][A-Z0-9]{1,7}-?$/ (1-8 alphanumeric chars, trailing dash optional). Invalid input returns `{ error: ... }`. Case-insensitive on the way in.", "type": "string" }, "product_type": { "description": "Wildcard match on product type. Common values include \"Personal Auto\", \"Homeowners\", \"Commercial Auto\", \"Workers Compensation\", \"Property\", \"Liability\". Substring matches: `product_type=\"Auto\"` returns Personal Auto and Commercial Auto.", "type": "string" }, "search": { "description": "Free-text wildcard match across SERFF id, carrier name, and product name. Useful for \"anything mentioning Progressive\" or \"filings whose product name contains 'condo'\". Prefer the structured fields below — `naic`, `state`, `filing_type`, `product_type` — when you can; they are more precise and do not false-match on substrings.", "type": "string" }, "state": { "description": "Two-letter US state code, uppercase. The corpus currently covers California (`CA`) only — other state codes will return no rows until additional states are onboarded. One filing always belongs to exactly one state.", "type": "string" }, "year": { "description": "Exact filing year (e.g. 2024). The corpus covers filings from 2005 onward; earlier years return no rows. Mutually exclusive with `year_from`/`year_to` — pick one form.", "type": "integer" }, "year_from": { "description": "Lower bound on filing year, inclusive. The corpus covers filings from 2005 onward. Pair with `year_to` for a range, or use alone for \"everything since\".", "type": "integer" }, "year_to": { "description": "Upper bound on filing year, inclusive.", "type": "integer" } }, "type": "object" }, "name": "search_filings", "outputSchema": null }, { "description": "Pure vector search over per-filing extraction-summary embeddings (one embedding per filing, ~59K rows total). Each hit is a filing whose extraction summary is semantically closest to your query, with the matching excerpt and lite filing metadata (state, year, company, product type, filing type, filing date).\n\n**Cost**: one query-embedding call + one indexed Postgres lookup. Bounded, cheap, fast. No LLM planning, no LLM composition. Always reach for this before any LLM-driven alternative.\n\n**Right surface for *what is this filing about* questions**:\n- \"Show me filings discussing X\" — content questions where X is not a concrete filter (wildfire scoring, telematics programmes, autonomous-vehicle exposure, ESG factors, parametric triggers, etc.).\n- \"Find filings that mention <topic>\" — when you need to discover filings by content rather than by structured metadata.\n- \"Filings citing trend data on <thing>\" — when the question is content-shaped, not numerics-shaped.\n\n**Wrong surface for**:\n- *Actuarial-shape* questions like \"filings with credibility under 50%\", \"filings whose indicated and selected rate diverge sharply\", \"rate filings where frequency trend is negative\". Use `search_actuarial_embeds` — those numerics live in the actuarial memo, not the summary.\n- Concrete-filter questions like \"Filings from carrier NAIC 12345 in 2024\" or \"ISOF-rooted filings carriers adopted\". Use `search_filings` with the typed filters — much faster, no embedding cost at all.\n- Anything with a SERFF id already in hand — use the `get_filing_*` tools.\n\n**How to combine**:\n- For \"recent auto programmes in California with novel rating factors\": first `search_filings` (state=CA, product_type=\"Auto\", year_from=…) to get a candidate set, then call this tool over those candidates' descriptions implied by the question.\n- For \"filings whose summary mentions X\": this tool alone, then `get_filing_summary` on the top hits to read in full.\n\nReturns top-K hits, each with `{serff, similarity, excerpt, meta}`. Default `topK=10`, max 50. Excerpt is the first 800 chars of the matching summary.", "inputSchema": { "properties": { "date_from": { "description": "Lower bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "date_to": { "description": "Upper bound on filing date (ISO YYYY-MM-DD).", "type": "string" }, "filing_type": { "description": "Wildcard match on filing type (\"Rate\", \"Rule\", \"Form\", \"Withdrawal\", etc.). Substring match.", "type": "string" }, "naic": { "description": "Exact NAIC carrier identifier (5-digit string). Restricts the cosine search to that carrier.", "type": "string" }, "predecessor_prefix": { "description": "Bureau / org SERFF prefix (\"ISOF\", \"NCCI\", \"AAIS\", \"MSO\"). Restricts to filings carriers actually adopted into a programme.", "type": "string" }, "product_type": { "description": "Wildcard match on product type (\"Personal Auto\", \"Homeowners\", \"Commercial Auto\", \"Workers Compensation\", etc.). Substring match — \"Auto\" matches both Personal and Commercial Auto.", "type": "string" }, "query": { "description": "Natural-language query. Pass the user's question verbatim when you can — short, specific queries (5-30 words) match best. The query is embedded and cosine-compared against per-filing summary embeddings.", "type": "string" }, "serff": { "description": "Optional SERFF id to scope the search to a single filing's summary embedding (shape PREFIX-IDENTIFIER). Each filing has at most one summary embedding, so topK is effectively 1 when serff is set.", "type": "string" }, "state": { "description": "Two-letter US state code, uppercase. Corpus currently covers CA only.", "type": "string" }, "topK": { "description": "Number of top filings to return. Defaults to 10; capped at 50. The result will contain at most this many rows; if filters narrow the candidate set below topK you get what's there, no silent fallback.", "type": "integer" }, "year": { "description": "Exact filing year. Mutually exclusive with year_from/year_to.", "type": "integer" }, "year_from": { "description": "Lower bound on filing year, inclusive.", "type": "integer" }, "year_to": { "description": "Upper bound on filing year, inclusive.", "type": "integer" } }, "required": [ "query" ], "type": "object" }, "name": "search_summary_embeds", "outputSchema": null } ] }
Verify it yourselfcurl -s https://api.teppi.xyz/v1/evidence/sha256:a842e3ef60eefe3e700bdcc672ae3e37c60fbcd6c94b31d77cacef1df5b680dc | sha256sum