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: readFree

List 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

ParameterTypeDescription
include_disabledbooleanInclude 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: readFree

Get 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

ParameterTypeDescription
product_idrequirednumberThe product ID.
include_disabledbooleanInclude 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: readFree

List 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

ParameterTypeDescription
product_idrequirednumberProduct to get prospects for.
min_deal_scorenumberMinimum deal score (1-5). Implies assessed-only: unscored rows (including unavailable) can't match a score floor.
12345
min_buying_signalnumberMinimum buying signal (0.0-1.0). Same assessed-only implication.
assessment_statusstring[]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_typestring[]Match families whose companies include any of these insurance entity types. "unknown" matches unclassified rows.
carrierreinsureragencymgabrokerageunclassified_intermediaryunknown
ownershipstring= anyFilter on family ownership. Distinct from include_private, which is an entitlement gate.
publicprivateany
include_privatebooleanDefaults 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_premiumnumberMinimum annual premium in USD. Applies per line when lines_of_business is supplied, otherwise to total all-lines premium.
max_premiumnumberMaximum annual premium in USD. Same rule as min_premium.
lines_of_businessstring[]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_statesnumberMinimum family-union licensed-state footprint (0-50).
states_licensed_instring[]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.
qstringName search. Matches family names, tickers, aliases, and subsidiary names — use it when you were given a company name rather than a ticker.
include_childrenbooleanInline each family's subsidiaries with the results. Forces limit to 50 or fewer.
sort_bystring= relevanceServer-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_linestringOne 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_indexnumberMinimum 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_complaintsnumberMinimum complaint count in the selected line (default 0). Use 10 to drop indexes built on one or two complaints.
sort_dirstringSort direction; defaults to the sensible one per key.
ascdesc
limitnumber= 100Max results (1-500).
offsetnumber= 0Pagination offset.
generation_idstringPaging 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: readFree

Full analysis for one company: findings, recommendations, evidence excerpts, firmographics, premium by line of business, complaint history, and its corporate family.

Inputs

ParameterTypeDescription
tickerrequiredstringCompany serving alias: letters, numbers, dots or hyphens, up to 12 characters. Also accepts any hierarchy.children[].ticker from a previous call.
product_idrequirednumberProduct to get the analysis for.
include_privatebooleanDefaults 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_yearnumberNarrow 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: readFree

Search and filter evidence excerpts for one prospect and product. Use this for granular evidence analysis beyond the capped excerpts get_prospect returns.

Inputs

ParameterTypeDescription
product_idrequirednumberThe product the excerpts were assessed against.
tickerrequiredstringCompany serving alias.
min_impact_scorenumberMinimum impact score (1-5).
keywordstringFilter by keyword against the excerpt's pain points (case-insensitive).
limitnumber= 50Max results (1-200).
offsetnumber= 0Pagination 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: readFree

Get 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

ParameterTypeDescription
product_idrequirednumberProduct context.
tickerrequiredstringCompany 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 credits

Generate 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

ParameterTypeDescription
product_idrequirednumberProduct context.
tickerrequiredstringCompany serving alias. A subsidiary ticker resolves to the family; a generate that lands on an already-cached family map is not charged.
force_refreshboolean= falseRequest 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: readFree

Override 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

ParameterTypeDescription
product_idrequirednumberProduct context.
tickerrequiredstringCompany serving alias.
node_idrequiredstringThe node_id from get_dealmap stakeholders.
stakeholder_rolerequiredstringThe 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: readFree

Mark 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

ParameterTypeDescription
product_idrequirednumberProduct context.
tickerrequiredstringCompany serving alias.
node_idrequiredstringThe node_id from get_dealmap stakeholders.
is_top_pickrequiredbooleantrue 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, outreachFree

List 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

ParameterTypeDescription
product_idrequirednumberProduct context.
limitnumber= 50Maximum team templates (1-100).
offsetnumber= 0Team-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 credit

Create 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

ParameterTypeDescription
product_idrequirednumberProduct context.
tickerrequiredstringCompany serving alias. A subsidiary ticker resolves to the family's DealMap for lead selection.
platformrequiredstringTarget platform.
emaillinkedin
selected_leadSelectedLeadFull lead object to personalize for.
lead_selectorobjectSelector to resolve a stakeholder: { node_id }, { level }, { full_name, level }, or { stakeholder_role } (picks the top-pick for that role).
template_keystringKey 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.

MCP Tool Catalog | DealSurface Docs