Tool Catalog
Complete reference for all 10 DealSurface MCP tools. Each tool maps to a REST API endpoint.
For detailed request/response schemas, full filter vocabularies, and code examples, see the REST API Reference. Line-of-business, state, sort, and entity-type vocabularies are embedded in the tool schemas as enums, so an invalid value is rejected by your client with the accepted set — it never silently matches nothing.
list_products
scope: readFreeList active products configured for your team, including which kinds of insurance company each one sells to. This is typically the first tool called in any workflow. Disabled products are hidden unless include_disabled is true.
Inputs
| Parameter | Type | Description |
|---|---|---|
include_disabled | boolean | Include disabled product metadata. Defaults to false. |
Output
{
products: Array<{
product_id: number
name: string
description: string
is_active: boolean
keywords: Array<{ keyword_id, name, auto_extracted }>
sources: Array<{ source_id, url, title, source_type }>
industries: Array<{ industry_name, industry_description, industry_code }>
segment_targeting: "all" | "selected"
target_segments: Array<{
insurance_entity_type: "carrier" | "reinsurer" | "agency" | "mga"
| "brokerage" | "unclassified_intermediary" | "unknown"
company_ownership: "public" | "private" | "any"
carrier_facts: {
lines_of_business: Array<{ line_of_business, premium_min,
premium_max, unknown_premium }>
licensed_footprint: { min, max } | null
include_unknown: boolean
} | null
}>
}>
}Common failures
- •401 — Invalid API key.
- •403 — Key lacks `read` scope.
Sequencing
Start here. Use the returned product_id with every other tool. Read target_segments to know what a product is meant to sell to before you judge whether a prospect fits.
get_product
scope: readFreeGet detailed information about a specific active product, including its keywords, sources, target industries, and target segments. Disabled products are hidden unless include_disabled is true.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | The product ID. |
include_disabled | boolean | Include disabled product metadata. Defaults to false. |
Output
{
product: { ...same shape as one element of list_products }
}Common failures
- •404 — Product not found, disabled without include_disabled, or belongs to a different team.
Sequencing
Use after list_products if you need full details on a single product.
list_prospects
scope: readFreeList prospects for a product, one row per corporate family, with NAIC premium and complaint data. Covers the full candidate universe — assessed and unassessed families alike, labeled by assessment_status. Filter by book of business, licensed footprint, entity type, ownership, and score.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product to get prospects for. |
min_deal_score | number | Minimum deal score (1-5). Implies assessed-only: unscored rows can't match a score floor.12345 |
min_buying_signal | number | Minimum buying signal (0.0-1.0). Same assessed-only implication. |
assessment_status | string[] | Optional narrowing to one or more assessment buckets.assessedpending_scoreunassessed |
entity_type | string[] | Match families whose companies include any of these insurance entity types. "unknown" matches unclassified rows.carrierreinsureragencymgabrokerageunclassified_intermediaryunknown |
ownership | string= any | Filter on family ownership. Distinct from include_private, which is an entitlement gate.publicprivateany |
include_private | boolean | Include private companies, when your team is entitled to them. Defaults to false. |
min_premium | number | Minimum annual premium in USD. Applies per line when lines_of_business is supplied, otherwise to total all-lines premium. |
max_premium | number | Maximum annual premium in USD. Same rule as min_premium. |
lines_of_business | string[] | Lines of business written. Matches families writing ANY of them. The 30 filterable NAIC line keys are enumerated in this tool's schema, so your client rejects an invalid one. total_all_lines, aggregate_write_ins, and international appear in premium output but are report roll-ups and cannot be filtered on. |
min_licensed_states | number | Minimum family-union licensed-state footprint (0-50). |
states_licensed_in | string[] | Two-letter codes for the 50 US states, enumerated in the schema (DC and territories cannot appear in the data and are rejected). Matches families licensed in ALL of them. |
q | string | Name search. Matches family names, tickers, aliases, and subsidiary names — use it when you were given a company name rather than a ticker. |
include_children | boolean | Inline each family's subsidiaries with the results. Forces limit to 50 or fewer. |
sort_by | string= relevance | Server-side sort. Prefer it over ranking a page yourself: a sorted first page is the top of the whole filtered set, not the top of one page. premium_line requires exactly one lines_of_business value. Rows with no value for the key sort last, never as zero.relevancedeal_scorebuying_signalpremium_totalpremium_linecomplaint_indexlicensed_state_count |
sort_dir | string | Sort direction; defaults to the sensible one per key.ascdesc |
limit | number= 100 | Max results (1-500). |
offset | number= 0 | Pagination offset. |
Output
{
prospects: Array<{
ticker, company_name,
assessment_status: "assessed" | "pending_score" | "unassessed",
deal_score, // null unless assessed
buying_signal_score, // null unless assessed
rank, rank_total,
entity_count, // companies in this corporate family
matched_entity_count, // how many of them matched your filters
insurance_entity_types, // key omitted when unclassified
ownership, lines_of_business,
licensed_states, licensed_state_count,
premium: { currency, report_years, total_all_lines_usd,
by_line_of_business, contributing_entity_count } | null,
complaints: { report_years, total_complaints,
complaint_index, complaint_index_status } | null,
children: [...] // only when include_children=true
}>
total_groups: number // corporate families in the filtered universe
total_entities: number // companies inside them
excluded_no_data_groups: number // dropped for lacking the data a filter required
limit: number
offset: number
}Common failures
- •400 — Invalid product_id, or an unrecognized lines_of_business, states_licensed_in, entity_type, or sort_by value. The error names the accepted set; an unknown value is never ignored.
- •404 — Product not found.
- •503 — Prospect data is rebuilding, or has not been rebuilt since the product's keywords changed. The body carries reason: 'rebuilding' is worth retrying in seconds, 'stale_keywords' waits on a pipeline run. Either way it means "not ready", never "no prospects found".
Sequencing
Call after list_products. Use a returned ticker with get_prospect for a deep dive, or get_dealmap to see who to contact.
Reading the results correctly
A result is a corporate family, not one company. It can appear because a subsidiary matched, so the ticker may not be the company that satisfied your filter. matched_entity_count says how many did; use get_prospect and read hierarchy.children to find which.
Premium figures blend report years across a family and the total does not reconcile with the per-line breakdown — use the total for scale, the breakdown for mix. The family complaint index is a ratio against premium-share expectation; a small carrier can top a complaint_index sort on little evidence, so corroborate with get_prospect's full series.
get_prospect
scope: readFreeFull analysis for one company: findings, recommendations, evidence excerpts, firmographics, premium by line of business, complaint history, and its corporate family.
Inputs
| Parameter | Type | Description |
|---|---|---|
tickerrequired | string | Company serving alias: letters, numbers, dots or hyphens, up to 12 characters. Also accepts any hierarchy.children[].ticker from a previous call. |
product_idrequired | number | Product to get the analysis for. |
include_private | boolean | Rank within the private-inclusive population, when entitled. The prospect's identity never changes. |
report_year | number | Narrow the premium and complaint series to a single year. Omit it to receive every available year, which is the default — the trend is usually the actionable half. |
Output
{
ticker, company_name,
assessment_status, deal_score, rank, rank_total,
company_info: { public_or_private, family_public_or_private,
sic_codes, insurance_entity_types,
primary_naic_cocode, all_naic_cocodes,
licensed_states, insurance_types,
website, primary_domain },
premium: { currency, report_years, total_all_lines_usd, by_line_of_business,
observations: Array<{ report_year, line_of_business,
annual_premium_usd }> } | null,
complaints: { cocode, available_years,
observations: Array<{ report_year, line_of_business,
total_complaints, complaint_index,
complaint_index_status }> } | null,
hierarchy: { prospect_kind, child_count, eligible_child_count,
coverage_ratio,
group: { ticker, company_name, is_self },
children: Array<{ ticker, company_name,
deal_score, has_assessment }> } | null,
narrative_scope: "company" | "group",
findings_summary, recommendation_summary,
key_opportunity, primary_challenge,
impact_score_distribution,
findings: Array<{ finding_id, text, evidence_excerpt_ids }>,
excerpt_count: number,
excerpts: Array<{ excerpt_id, text, impact_score, source,
pain_points, sales_summary, buying_signal_present }>
}Common failures
- •404 — Unknown ticker for this product, or the alias is ambiguous. Unassessed companies return the facts-only shape, not 404.
- •400 — Invalid ticker or product_id.
- •503 — Projection unavailable (same reasons as list_prospects).
Sequencing
Call after list_prospects. To drill into a subsidiary, take a ticker from hierarchy.children and call this tool again. Follow with search_excerpts for finer evidence filtering, or get_dealmap to find who to contact.
Embedded excerpts are capped at 20
The excerpts array carries at most 20, highest impact score first, with excerpt_count reporting how many exist. Call search_excerpts for the rest. Well-covered companies carry hundreds — enough to fill your context window in a single call.
Analysing a subsidiary
Pass any hierarchy.children[].ticker straight back into this tool. A subsidiary reports its family's rank rather than one of its own, and its own premium and complaint record. has_assessment tells you whether we hold an assessment for that company — where it is false, fetching it returns the facts-only shape (null scores, empty findings and excerpts) with the firmographic, premium, and complaint data still populated.
insurance_entity_types is left out entirely when a company has not been classified. A missing key means “we do not know”, which is different from an empty list meaning “we checked and it is none”. And complaint_index_status explains a missing index: no_premium_share means complaints were reported but no index could be computed (total_complaints is still meaningful); not_reported means no complaint data.
search_excerpts
scope: readFreeSearch and filter evidence excerpts for one prospect and product. Use this for granular evidence analysis beyond the capped excerpts get_prospect returns.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | The product the excerpts were assessed against. |
tickerrequired | string | Company serving alias. |
min_impact_score | number | Minimum impact score (1-5). |
keyword | string | Filter by keyword against the excerpt's pain points (case-insensitive). |
limit | number= 50 | Max results (1-200). |
offset | number= 0 | Pagination offset. |
Output
{
excerpts: Array<{ excerpt_id, text, impact_score, source,
pain_points, sales_summary, buying_signal_present }>
total_count: number
limit: number
offset: number
}Common failures
- •404 — Unknown ticker for this product. Unassessed companies return an empty page (total_count 0), not 404.
- •400 — Invalid ticker, product_id, or pagination values.
- •503 — Projection unavailable (same reasons as list_prospects).
Sequencing
Use after get_prospect for deeper evidence analysis. Excerpt IDs can be referenced in craft_outreach results.
framework_category removed in 2.0.0
framework_category is no longer accepted as an input, and the field is gone from every excerpt result (here and in get_prospect). Narrow with min_impact_score and keyword instead.
get_dealmap
scope: readFreeGet the buying committee DealMap for a prospect company. Shows stakeholders with AI-assigned roles (Economic Buyer, Decision Maker, Champion, etc.), org hierarchy edges, and a buying_committee_summary identifying the top pick for each role.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product context. |
tickerrequired | string | Company serving alias. A subsidiary ticker resolves to the corporate family's DealMap, and the result names the family it resolved to. |
Output
{
status: "empty" | "ready" | "stale"
chart: { id, generated_at, expires_at, company_name, node_count, relevant_node_count } | null
stakeholders: Array<{
node_id, full_name, title, level, level_label,
linkedin_url, work_email, manager_name,
stakeholder_role, stakeholder_role_source,
annotation_score, annotation_reason,
is_top_pick, top_pick_source
}>
edges: Array<{ from_node_id, to_node_id, relationship }>
buying_committee_summary: {
economic_buyer, decision_maker, champion,
executive_sponsor, evaluator, blockers: [...]
}
}Common failures
- •400 — Invalid product_id or ticker.
- •404 — Product not found.
Sequencing
Call after get_prospect. Returns status 'empty' if no DealMap exists yet — call generate_dealmap first.
generate_dealmap
scope: read, outreach0-10 creditsGenerate or refresh the buying committee DealMap for a prospect. Maps the org structure and assigns stakeholder roles using AI analysis. Credits charged only when fresh org-chart data is fetched. Hard-capped at 5 requests per minute.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product context. |
tickerrequired | string | Company serving alias. A subsidiary ticker resolves to the family; a generate that lands on an already-cached family map is not charged. |
force_refresh | boolean= false | Force fresh org chart fetch. Always charges credits. |
Output
{
status: "ready"
chart: { id, generated_at, expires_at, company_name, node_count, relevant_node_count }
stakeholders: Array<{ node_id, full_name, title, level, stakeholder_role, is_top_pick, ... }>
edges: Array<{ from_node_id, to_node_id, relationship }>
buying_committee_summary: { economic_buyer, decision_maker, champion, ... }
generation_source: "org_fresh" | "org_cached" | "annotation_only"
credits_charged: boolean
}Common failures
- •402 — Insufficient credits for fresh generation.
- •404 — Product not found.
- •409 — A generation for this prospect is already in flight. Wait, then read the result with get_dealmap.
- •429 — Hard cap of 5 requests per minute exceeded.
- •502 — DealMap generation service temporarily unavailable.
Sequencing
Call after get_prospect. Follow with get_dealmap to read the result, or use stakeholders directly with craft_outreach.
Avoid unnecessary force_refresh
Do not use force_refresh unless the user explicitly requests updated org data. Cached org-chart data is reused for free.
override_stakeholder_role
scope: readFreeOverride the AI-assigned stakeholder role for a specific person on the buying committee DealMap. This is a team-wide override visible to all team members. Use when the AI role assignment is clearly wrong.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product context. |
tickerrequired | string | Company serving alias. |
node_idrequired | string | The node_id from get_dealmap stakeholders. |
stakeholder_rolerequired | string | The corrected stakeholder role.Economic BuyerDecision MakerChampionExecutive SponsorEvaluatorEnd UserProcurement / Legal ReviewerBlockerIrrelevant |
Output
{
success: true
node_id: string
stakeholder_role: string
}Common failures
- •400 — Invalid node_id or stakeholder_role.
- •404 — Product not found or node not in DealMap.
Sequencing
Call after get_dealmap when an AI-assigned role needs correction.
set_top_pick
scope: readFreeMark or unmark a stakeholder as the top pick for their role on the buying committee DealMap. Team-wide, like role overrides. New in 2.0.0 — wraps PATCH /dealmap/node-top-pick, so an agent that can correct a role can also mark who to actually approach.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product context. |
tickerrequired | string | Company serving alias. |
node_idrequired | string | The node_id from get_dealmap stakeholders. |
is_top_pickrequired | boolean | true marks this stakeholder as the top pick for their role; false clears a manual top pick. |
Output
{
success: true
node_id: string
is_top_pick: boolean
}Common failures
- •400 — Invalid node_id.
- •404 — Product not found or node not in DealMap.
Sequencing
Call after get_dealmap. The top pick per role feeds buying_committee_summary and the { stakeholder_role } lead selector in craft_outreach.
craft_outreach
scope: read, outreach1 creditGenerate an evidence-backed outreach message (email or LinkedIn) for a prospect. Grounded in real evidence from public filings and earnings calls. Hard-capped at 10 requests per minute.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product context. |
tickerrequired | string | Company serving alias. A subsidiary ticker resolves to the family's DealMap for lead selection. |
platformrequired | string | Target platform.emaillinkedin |
tonerequired | string | Desired tone.hard_sellhelpfulneutral |
length | string= typical | Desired length.shortertypicallonger |
selected_lead | SelectedLead | Full lead object to personalize for. |
lead_selector | object | Selector to resolve a stakeholder: { node_id }, { level }, { full_name, level }, or { stakeholder_role } (picks the top-pick for that role). |
Output
{
subject?: string // Only for email platform
body: string
platform: string
tone: string
length: string
used_excerpt_ids: number[]
selected_lead?: { full_name, title, level }
selected_lead_note?: string
}Common failures
- •402 — Insufficient credits.
- •404 — No prospect data.
- •400 — Invalid platform, tone, or length value.
- •429 — Hard cap of 10 requests per minute exceeded.
Sequencing
Final step in a workflow. Use stakeholders from get_dealmap and evidence from get_prospect or search_excerpts.
Lead targeting
If both selected_lead and lead_selector are provided, selected_lead takes precedence. Omit both for generic company outreach.