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 (assessed, pending_score, unassessed, unavailable; unavailable rows rank after scored rows, before unassessed rows). 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 (including unavailable) 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. unavailable: analysis is not available for this company in the current results. Not a low score.assessedpending_scoreunassessedunavailable |
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 | Defaults to the team-entitled population. Set false for public-only results. The response population field explains the policy and rank scope; live team entitlement always controls access. |
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. complaint_index sorts by the all-lines index unless complaint_line (or a single supported CIS lines_of_business value) selects a line. Rows with no value for the key sort last, never as zero.relevancedeal_scorebuying_signalpremium_totalpremium_linecomplaint_indexlicensed_state_count |
complaint_line | string | One supported CIS policy line. Selects the line used by sort_by=complaint_index, min_complaint_index and min_complaints. Defaults to a single supported lines_of_business value; sector roll-ups and statement-only lines retain the all-lines index. Per-line requests return 503 until a full projection refresh publishes the data. |
min_complaint_index | number | Minimum Complaint Index (at least this value) on the selected line. Strict: families with no index for that line are excluded and counted in excluded_no_data_groups. |
min_complaints | number | Minimum complaint count in the selected line (default 0). Use 10 to drop indexes built on one or two complaints. |
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. |
generation_id | string | Paging token for later pages of the same list: echo publication.generation_id from the first page back here unchanged. A 409 generation_unavailable means restart from offset 0 without it. |
Output
{
prospects: Array<{
ticker, company_name,
assessment_status: "assessed" | "pending_score" | "unassessed"
| "unavailable", // analysis not available in the current results
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, // all lines
complaint_index_status,
by_line_of_business: { [line]: { report_year, total_complaints,
complaint_index, complaint_index_status,
contributing_entity_count, low_sample } } } | 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
publication?: { // only for products on published generations; whole-result-set signals
generation_id, // paging token: echo back on later pages
state, update_in_progress, latest_update_failed, previous_settings,
warnings: Array<{ code, message }>
}
}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".
- •409 — generation_unavailable: the paging token is stale. Restart from offset 0 without generation_id.
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 | Defaults to ranking within the team-entitled population. False requests public-only ranking for public prospects; private prospects retain private-inclusive ranking. Detail ranks cover unfiltered families. |
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, // null with scope "family"
scope?: "family", // parents with no cocode of their own
available_years,
observations: Array<{ report_year, line_of_business,
total_complaints, complaint_index,
complaint_index_status, low_sample }>,
by_entity?: Array<{ cocode, legal_name, observations }> } | 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 }>,
publication?: { generation_id } // only for products on published generations
}Common failures
- •404 — Unknown ticker for this product, or the alias is ambiguous. Companies without analysis (unassessed or unavailable) 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
publication?: { generation_id } // only for products on published generations
}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.
- •409 — analysis_unavailable: analysis is not available for this company in the current results. Tell the user briefly and do not retry.
- •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. Successful org_fresh and org_fresh_empty results cost 10 credits, including fresh empty org results supplemented with people. org_cache and annotated_cache_hit are free. Hard-capped at 20 requests per minute per API key; for many companies, run up to 10 generations in parallel.
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 | Request fresh org chart data. Successful fresh results cost 10 credits; failed generation is not charged. |
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_fresh_empty" | "org_cache" | "annotated_cache_hit"
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 20 requests per minute exceeded. Wait Retry-After seconds, then retry only the rejected calls.
- •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.
list_outreach_templates
scope: read, outreachFreeList active static messages and generation prompts for a product, plus the built-in DealSurface default. Use when the user asks to explore alternatives; normal crafting uses the product default automatically.
Inputs
| Parameter | Type | Description |
|---|---|---|
product_idrequired | number | Product context. |
limit | number= 50 | Maximum team templates (1-100). |
offset | number= 0 | Team-template pagination offset. |
Output
{
system_template: { template_key, name, kind, credit_cost, version, is_default }
effective_default_key: string
templates: Array<{ template_key, name, kind, credit_cost, description, version, is_default, requires_lead }>
pagination: { offset, limit, total, has_more }
}Common failures
- •403 — API key lacks read or outreach scope.
- •404 — Product not found or not owned by the key's team.
Sequencing
Optional discovery step before craft_outreach. Skip it when the user is happy to use the configured product default.
craft_outreach
scope: read, outreach0–1 creditCreate outreach from a static message or generation prompt for an authorized prospect. Pure static messages are free; a generated prompt or static AI hook costs one credit on success. Hard-capped at 60 requests per minute per API key; for many leads, run up to 10 drafts in parallel.
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 |
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). |
template_key | string | Key returned by list_outreach_templates. Omit for the product default; system_default explicitly selects the built-in template. |
Output
{
subject?: string
body: string
platform: string
used_excerpt_ids: number[]
selected_lead?: { full_name, title, level }
selected_lead_note?: string
template_used: { template_key, name, kind, version, source, resolution }
publication?: { generation_id } // only for products on published generations
}Common failures
- •402 — Insufficient credits.
- •404 — No prospect data.
- •409 — analysis_unavailable: analysis is not available for this company in the current results. Tell the user briefly and do not retry. No credit is charged.
- •400 — Invalid platform value.
- •429 — Hard cap of 60 requests per minute exceeded. Wait Retry-After seconds, then retry only the rejected calls.
Sequencing
Final step in a workflow. Omit template_key to use the product default. List templates only when the user asks for another style.
Lead targeting
If both selected_lead and lead_selector are provided, selected_lead takes precedence. Omit both for generic company outreach.