prospectapis-mcp 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,29 @@ All notable changes to `prospectapis-mcp` are documented here. The format follow
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.0] - 2026-10-25
10
+
11
+ ### Added
12
+
13
+ - `email_verify` (`POST /v1/email/verify`): check 1 to 25 email addresses for deliverability. Each result carries `status` (valid, invalid, catch-all or unknown), `reason`, `charged`, `flags`, `smtp_code` and `catch_all_tier`. A valid or invalid result costs $0.004; catch-all and unknown results are free. When the balance covers only some addresses, the rest come back `unknown` with reason `not_checked_insufficient_credits`, free. Fifteen tools.
14
+
15
+ ### Changed
16
+
17
+ - Pricing: every account starts with a free $1 balance (no card, no monthly reset) that each paid call draws from at its own price. The 100 free funding records a month are gone, so tool descriptions, the server instructions, the playbooks and the README no longer promise them. Watchlist deliveries cost $0.02 per delivered record from the balance.
18
+ - `pricing_get` and `account_balance` descriptions name the new fields (the signup balance, the email verification price and which statuses are charged).
19
+ - The 402 hint reads "out of credits for this call".
20
+
21
+ ## [0.2.5] - 2026-10-20
22
+
23
+ ### Added
24
+
25
+ - Four playbooks, served as MCP resources (resources/list, resources/read) and as one prompt each (prompts/list, prompts/get), so a client can offer them as slash commands: newly funded prospects, pre-call brief, funding alerts to a webhook, and an investor's recent rounds. A prompt hands its playbook over as an embedded resource, so the recipe matches what resources/read serves, and a client that omits the optional `arguments` still gets it. Tests hold every name a playbook uses to the tool catalog.
26
+
27
+ ### Changed
28
+
29
+ - The README's first sentence now names the product URL (https://prospectapis.com) and who it is for, because directory cards and search snippets copy that sentence alone and were linking GitHub only. A test pins both.
30
+ - Added CODE_OF_CONDUCT.md (Contributor Covenant 2.1), which open-source programs ask for.
31
+
9
32
  ## [0.2.4] - unreleased
10
33
 
11
34
  ### Fixed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # prospectapis-mcp
2
2
 
3
- prospectapis-mcp is the MCP server for ProspectAPIs, built for sales teams and their AI agents in Claude Code, Claude Desktop, Cursor and other MCP clients. It gives your agent fourteen tools over the ProspectAPIs API: search funding rounds by date, round, amount, company, investor and country, get new matching rounds pushed to your webhook, and order a cited research brief on any company or person. Funding records carry the public announcement URL when there is one. Records cost $0.02 each after 100 free a month, a completed brief costs $0.15, and there are no seats, no subscription and no card to sign up. It needs Node.js 22 or later.
3
+ prospectapis-mcp is the MCP server for ProspectAPIs (https://prospectapis.com), for sales and prospecting teams and the AI agents they run in Claude Code, Claude Desktop, Cursor and other MCP clients. It gives your agent fifteen tools over the ProspectAPIs API: search funding rounds by date, round, amount, company, investor and country, get new matching rounds pushed to your webhook, verify email addresses, and order a cited research brief on any company or person. Funding records carry the public announcement URL when there is one. Every account starts with a free $1 balance and no card: records cost $0.02, an email check $0.004 and a completed brief $0.15, with no seats and no subscription. It needs Node.js 22 or later.
4
4
 
5
5
  Install (Claude Code): `claude mcp add prospectapis -e PROSPECTAPIS_API_KEY=pa_live_... -- npx -y prospectapis-mcp`
6
6
 
@@ -10,10 +10,11 @@ Website: https://prospectapis.com/mcp
10
10
 
11
11
  | Tool | Endpoint | Cost |
12
12
  |---|---|---|
13
- | `funding_search` | `GET /v1/funding` | $0.02 per record returned, after 100 free records a month; no match is free |
13
+ | `funding_search` | `GET /v1/funding` | $0.02 per record returned; no match is free |
14
14
  | `funding_get` | `GET /v1/funding/:id` | $0.02 when found; a missing id is free |
15
15
  | `research_submit` | `POST /v1/research` | one research at `research_price_usd` (see `account_balance`), charged only when the brief completes; refunded on failure |
16
16
  | `research_get` | `GET /v1/research/:id` | free; poll until `status` is `completed` or `failed` |
17
+ | `email_verify` | `POST /v1/email/verify` | $0.004 per `valid` or `invalid` result; `catch-all` and `unknown` are free; 1 to 25 addresses a call |
17
18
  | `watchlist_create`, `watchlist_list`, `watchlist_get`, `watchlist_deliveries`, `watchlist_test`, `watchlist_delete` | `/v1/watchlists` | free to manage; a delivered event costs one record, only when your webhook answers 2xx |
18
19
  | `account_balance` | `GET /v1/account` | free |
19
20
  | `feedback_send` | `POST /v1/feedback` | free; reports a bug, wrong field or missing capability to the team (10 an hour per key) |
@@ -29,6 +30,10 @@ Website: https://prospectapis.com/mcp
29
30
  `context` (your own product, at most 1,000 characters) and `purpose` (`account_research`, `pre_call` or
30
31
  `outreach`). It returns a `research_id` at once; a brief takes 20 to 90 seconds.
31
32
 
33
+ `email_verify` takes `emails`, a list of 1 to 25 addresses. Each result has `status` (`valid`, `invalid`,
34
+ `catch-all` or `unknown`), `reason`, `charged`, `flags`, `smtp_code` and `catch_all_tier`. If the balance covers only
35
+ some addresses, the rest come back `unknown` with reason `not_checked_insufficient_credits` and are not charged.
36
+
32
37
  ## Configure
33
38
 
34
39
  | Variable | Required | Default |
@@ -56,7 +61,7 @@ Claude Code: `claude mcp add prospectapis -e PROSPECTAPIS_API_KEY=pa_live_... --
56
61
 
57
62
  **Where does the funding data come from?** Records carry the public announcement URL when there is one.
58
63
 
59
- **What is free?** 100 funding records a month, any search that matches nothing, watchlist management, and the balance, pricing and version tools.
64
+ **What is free?** A $1 balance when you sign up (about 50 funding records, 250 email checks or 6 research briefs), any search that matches nothing, catch-all and unknown email results, watchlist management, and the balance, pricing and version tools.
60
65
 
61
66
  **Which clients work?** Claude Code, Claude Desktop, Cursor and any client that reads an mcpServers config, through `npx -y prospectapis-mcp`.
62
67
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "prospectapis-mcp",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "mcpName": "io.github.ProspectAPIs/prospectapis-mcp",
5
- "description": "MCP server for ProspectAPIs: search funding rounds, run paid prospect research briefs, manage funding watchlists, read your balance and the live price list.",
5
+ "description": "MCP server for ProspectAPIs: search funding rounds, verify email addresses, run paid prospect research briefs, manage funding watchlists, read your balance and the live price list.",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "prospectapis-mcp": "src/index.js"
@@ -0,0 +1,113 @@
1
+ // Playbooks: short recipes an agent runs with the tools in src/tools.js, served over the MCP RESOURCE primitive
2
+ // (resources/list, resources/read) and offered as one PROMPT each (prompts/list, prompts/get), so a client can show
3
+ // them as slash commands.
4
+ //
5
+ // WHY RESOURCES AND PROMPTS, NOT TOOLS. Every tool in src/tools.js is one REST endpoint (test/api-parity.test.js
6
+ // holds the catalog to the API). A recipe wraps no endpoint; it is read-only context an agent fetches when it needs
7
+ // it, which is what resources are for, and a prompt is how a client offers that recipe to a user.
8
+ //
9
+ // A DESCRIPTION IS LISTED, A BODY IS FETCHED. Clients show the title and description beside every tool, so those
10
+ // state what the recipe does in plain product terms and never instruct the model. The body is returned only for a
11
+ // URI or prompt the caller asked for by name, so it names tools freely.
12
+ //
13
+ // Every figure in a body (prices, page size, alert limit, poll interval) is the one the tool descriptions in
14
+ // src/tools.js state, checked by review, not by a test. test/playbooks.test.js fails if a body names a tool,
15
+ // parameter, value or response field the catalog does not have.
16
+
17
+ export const PLAYBOOK_MIME = "text/markdown";
18
+
19
+ const NEWLY_FUNDED = `# Newly funded prospects
20
+
21
+ Build a short list of companies that just raised, worth reaching out to while the round is fresh.
22
+
23
+ 1. \`account_balance\` first. Each funding record returned costs $0.02, drawn from your balance (a new account starts
24
+ with $1, about 50 records), so know what is left before you pull pages.
25
+ 2. \`funding_search\` with a tight window and the filters that describe the buyer: \`since\` (for example the last 30
26
+ days), \`round\` (such as \`seed,series_a\`), \`country\`, and \`min_amount_usd\` or \`max_amount_usd\`. Start with
27
+ \`limit\` 10 to 25. A search that matches nothing costs nothing, so narrow before you widen.
28
+ 3. Read the results. Each record has the company, its domain, the round, the amount, the investors and, when there is
29
+ one, the URL of the public announcement. Drop companies without a domain or outside the buyer profile.
30
+ 4. Page with \`cursor\` only if the first page is all good fits; pass \`next_cursor\` back exactly as returned. A null
31
+ \`next_cursor\` means there are no more matches.
32
+ 5. For the two or three best fits, run the pre-call brief playbook (\`research_submit\` with \`domain\`).
33
+ 6. Present the list as company, domain, round, amount, date, lead investors and the announcement URL where there is
34
+ one, so every line can be checked.
35
+ `;
36
+
37
+ const PRE_CALL_BRIEF = `# Pre-call brief
38
+
39
+ A cited brief on one company or person before a call or a first email.
40
+
41
+ 1. \`research_submit\` with exactly ONE identifier: \`domain\` is best; otherwise \`website_url\`, \`company_name\`, a work
42
+ \`email\`, or \`person_name\` together with \`company_name\`. Set \`purpose\` to \`pre_call\` for objections and discovery
43
+ questions, or \`outreach\` for sourced hooks with draft first lines. Add \`context\` (your own product, up to 1,000
44
+ characters) to get a \`fit\` section.
45
+ 2. It returns \`research_id\` at once. The brief takes 20 to 90 seconds: call \`research_get\` with that id every 10 to 15
46
+ seconds until \`status\` is \`completed\` or \`failed\`. Polling is free.
47
+ 3. A brief is charged only when it completes, at the \`research_price_usd\` that \`account_balance\` reports, and refunded
48
+ in full if it fails.
49
+ 4. Every field in \`result\` is \`{value, sources, confidence}\`. Quote the sources with the claims you use, and say when
50
+ a field came back empty rather than filling the gap.
51
+ `;
52
+
53
+ const FUNDING_ALERTS = `# Funding alerts to a webhook
54
+
55
+ Get every new funding round that matches a profile pushed to your own endpoint, instead of searching again.
56
+
57
+ 1. Decide the filters with \`funding_search\` first (\`round\`, \`country\`, \`min_amount_usd\`, \`max_amount_usd\`,
58
+ \`investor\`, \`company\` or \`domain\`), and check the results look right. Date windows and paging do not apply to an
59
+ alert.
60
+ 2. \`watchlist_create\` with a \`name\`, those \`filters\` and an https \`webhook_url\` on a public host. Save the \`secret\`
61
+ it returns: it is shown once, and every delivery is signed with it in the Prospect-Signature header
62
+ (t=..,v1=HMAC-SHA256). Creating is free; each delivered event costs one record, charged only when your webhook
63
+ answers 2xx. An account can have 20 active alerts.
64
+ 3. \`watchlist_test\` sends a signed sample event now, so the receiver can be built and checked before a real round
65
+ arrives. Free, 5 a minute.
66
+ 4. Later, \`watchlist_deliveries\` shows the last 50 deliveries and their outcome (delivered, retry, failed,
67
+ no_credit), and \`watchlist_get\` shows whether the alert is active and why it was paused.
68
+ `;
69
+
70
+ const INVESTOR_ROUNDS = `# An investor's recent rounds
71
+
72
+ See which companies an investor has backed lately, to find warm introductions or a portfolio to sell into.
73
+
74
+ 1. \`funding_search\` with \`investor\` set to the investor's exact name (case-insensitive) and a \`since\` date, newest
75
+ first. Add \`round\` to keep to one stage.
76
+ 2. Each record lists every investor named and the lead investors, so you can tell a lead from a participation.
77
+ 3. Group the results by round and by country, and give the announcement URL with each line that has one.
78
+ 4. To follow this investor from now on, run the funding alerts playbook with \`investor\` as the filter.
79
+ `;
80
+
81
+ export const PLAYBOOKS = Object.freeze([
82
+ {
83
+ name: "newly-funded-prospects",
84
+ uri: "prospectapis://playbooks/newly-funded-prospects",
85
+ title: "Newly funded prospects",
86
+ description: "Build a short list of companies that raised recently, filtered by round, country and amount, with the announcement for each.",
87
+ text: NEWLY_FUNDED,
88
+ prompt: { arg: "profile", describe: "Who you sell to, for example 'seed and Series A fintech in the US'.", ask: (v) => `Run this playbook for: ${v}` },
89
+ },
90
+ {
91
+ name: "pre-call-brief",
92
+ uri: "prospectapis://playbooks/pre-call-brief",
93
+ title: "Pre-call brief",
94
+ description: "A cited research brief on one company or person before a call or a first email.",
95
+ text: PRE_CALL_BRIEF,
96
+ prompt: { arg: "prospect", describe: "The company domain, company name, or person and company.", ask: (v) => `Run this playbook for: ${v}` },
97
+ },
98
+ {
99
+ name: "funding-alerts",
100
+ uri: "prospectapis://playbooks/funding-alerts",
101
+ title: "Funding alerts to a webhook",
102
+ description: "Push every new funding round that matches a profile to your own https endpoint, signed, instead of searching again.",
103
+ text: FUNDING_ALERTS,
104
+ },
105
+ {
106
+ name: "investor-rounds",
107
+ uri: "prospectapis://playbooks/investor-rounds",
108
+ title: "An investor's recent rounds",
109
+ description: "The companies one investor has backed lately, split into lead and participation, with sources.",
110
+ text: INVESTOR_ROUNDS,
111
+ prompt: { arg: "investor", describe: "The investor's name, for example 'Example Ventures'.", ask: (v) => `Run this playbook for: ${v}` },
112
+ },
113
+ ]);
package/src/server.js CHANGED
@@ -1,22 +1,27 @@
1
1
  // MCP server wiring: one registered tool per catalog entry, each a single
2
- // authenticated request (a GET, or a POST with a JSON body for research_submit)
2
+ // authenticated request (a GET, or a POST with a JSON body for research_submit and email_verify)
3
3
  // against the ProspectAPIs REST API. Exported as a factory
4
4
  // (createServer) so tests inject a fake fetch and a host could inject auth.
5
5
 
6
6
  import { createRequire } from "node:module";
7
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
8
  import { TOOLS, buildUrl, buildPath, buildBody, annotationsFor } from "./tools.js";
9
+ import { z } from "zod";
10
+ import { GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js";
11
+ import { PLAYBOOKS, PLAYBOOK_MIME } from "./playbooks.js";
9
12
 
10
13
  export const { version: VERSION } = createRequire(import.meta.url)("../package.json");
11
14
 
12
15
  export const DEFAULT_BASE_URL = "https://api.prospectapis.com";
13
16
  export const DEFAULT_TIMEOUT_MS = 30000;
14
17
  export const SIGNUP_URL = "https://prospectapis.com/signup?utm_source=mcp";
15
- export const TOP_UP_URL = "https://prospectapis.com/dashboard/credits?utm_source=mcp";
18
+ export const TOP_UP_URL = "https://prospectapis.com/dashboard/billing?utm_source=mcp";
16
19
 
17
20
  export const INSTRUCTIONS =
18
- "ProspectAPIs MCP server: funding rounds data and prospect research briefs. funding_search and funding_get cost $0.02 per record returned, " +
19
- "after 100 free records per calendar month; a search that matches nothing costs nothing. account_balance, pricing_get and api_version are free. " +
21
+ "ProspectAPIs MCP server: funding rounds data, email verification and prospect research briefs. Every account starts with a free $1 balance " +
22
+ "(no card, no monthly reset), and each paid call draws from it at its own price. funding_search and funding_get cost $0.02 per record returned; " +
23
+ "a search that matches nothing costs nothing. email_verify checks 1 to 25 addresses for $0.004 per valid or invalid result; catch-all and " +
24
+ "unknown results are free. account_balance, pricing_get and api_version are free. " +
20
25
  "Use filters (dates, round, amount, domain, investor, country) to keep result sets small, and call account_balance before a large paged search. " +
21
26
  "research_submit starts a cited brief on one prospect and returns a research_id; poll research_get (free) until it is completed or failed. " +
22
27
  "A research is charged only when it completes, at the research_price_usd account_balance reports. " +
@@ -25,8 +30,7 @@ export const INSTRUCTIONS =
25
30
 
26
31
  export function hintFor(status) {
27
32
  if (status === 401) return " (missing or invalid API key: set PROSPECTAPIS_API_KEY to a key from the dashboard)";
28
- // research never draws on free records, so the hint does not promise any (PR #23 review, L4)
29
- if (status === 402) return ` (not enough credit for this call; the body says what it costs: top up at ${TOP_UP_URL})`;
33
+ if (status === 402) return ` (out of credits for this call; the body says what it costs: top up at ${TOP_UP_URL})`;
30
34
  if (status === 400) return " (an argument was rejected: the body says which one)";
31
35
  if (status === 404) return " (not found: the id may be wrong, or the record is not published)";
32
36
  if (status === 429) return " (rate limited: wait a few seconds and retry)";
@@ -91,6 +95,52 @@ export function createServer({
91
95
  }
92
96
 
93
97
  const server = new McpServer({ name: "prospectapis", version: VERSION }, { instructions: INSTRUCTIONS });
98
+
99
+ // Playbooks (src/playbooks.js): each one a resource (resources/list, resources/read) and a prompt (prompts/list,
100
+ // prompts/get). The prompt hands the playbook over as an embedded resource, so the recipe a user picks is exactly
101
+ // the one resources/read serves. Registering either declares that capability, which a server with none does not
102
+ // advertise.
103
+ for (const p of PLAYBOOKS) {
104
+ server.registerResource(
105
+ p.name,
106
+ p.uri,
107
+ { title: p.title, description: p.description, mimeType: PLAYBOOK_MIME },
108
+ async (uri) => ({ contents: [{ uri: uri.href, mimeType: PLAYBOOK_MIME, text: p.text }] }),
109
+ );
110
+ }
111
+ // `arguments` is optional on prompts/get (MCP spec), but the SDK validates a prompt that declares arguments against
112
+ // a required object, so a client that leaves it out would get -32602 for an argument it was told is optional. The
113
+ // SDK installs its prompts/get handler through the low-level Server the first time a prompt is registered; wrapping
114
+ // setRequestHandler before that defaults a missing `arguments` to {} and leaves every other request untouched.
115
+ {
116
+ const low = server.server;
117
+ const setRequestHandler = low.setRequestHandler.bind(low);
118
+ low.setRequestHandler = (schema, handler) =>
119
+ setRequestHandler(
120
+ schema,
121
+ schema === GetPromptRequestSchema
122
+ ? (request, extra) => handler({ ...request, params: { ...request.params, arguments: request.params?.arguments ?? {} } }, extra)
123
+ : handler,
124
+ );
125
+ }
126
+ for (const p of PLAYBOOKS) {
127
+ const argsSchema = p.prompt ? { [p.prompt.arg]: z.string().max(200).optional().describe(p.prompt.describe) } : undefined;
128
+ server.registerPrompt(
129
+ p.name,
130
+ { title: p.title, description: p.description, ...(argsSchema ? { argsSchema } : {}) },
131
+ async (args = {}) => {
132
+ const v = p.prompt ? String(args[p.prompt.arg] ?? "").trim() : "";
133
+ return {
134
+ description: p.description,
135
+ messages: [
136
+ { role: "user", content: { type: "resource", resource: { uri: p.uri, mimeType: PLAYBOOK_MIME, text: p.text } } },
137
+ { role: "user", content: { type: "text", text: p.prompt && v ? p.prompt.ask(v) : "Run this playbook." } },
138
+ ],
139
+ };
140
+ },
141
+ );
142
+ }
143
+
94
144
  for (const tool of TOOLS) {
95
145
  server.registerTool(
96
146
  tool.name,
package/src/tools.js CHANGED
@@ -6,9 +6,9 @@
6
6
  // except `{name}` placeholders in `path`, which are interpolated into the
7
7
  // URL and removed from the query string;
8
8
  // - `body: true` sends the arguments as a JSON body instead of a query
9
- // string (research_submit, a POST);
9
+ // string (research_submit and email_verify, POSTs);
10
10
  // - `write: true` marks a tool that changes state or spends credits
11
- // (research_submit starts a paid job); the server turns `write` into MCP's
11
+ // (research_submit starts a paid job, email_verify spends credits); the server turns `write` into MCP's
12
12
  // readOnlyHint, so every other tool is read-only;
13
13
  // - `auth: false` marks the tools the API serves without a key (pricing_get, api_version);
14
14
  // - `title` is the human name a client shows instead of the raw tool name;
@@ -48,7 +48,7 @@ export const TOOLS = [
48
48
  write: false,
49
49
  format: { min_amount_usd: formatAmount, max_amount_usd: formatAmount },
50
50
  description:
51
- "Search funding rounds (venture rounds, debt, grants, IPOs), newest announcement first. Costs $0.02 per record returned, after 100 free records a month; a search that matches nothing is free. " +
51
+ "Search funding rounds (venture rounds, debt, grants, IPOs), newest announcement first. Costs $0.02 per record returned, drawn from your balance (every account starts with a free $1); a search that matches nothing is free. " +
52
52
  "Page with `cursor`: pass back `next_cursor` exactly as returned; a null `next_cursor` means there are no more matches. Narrow with filters before raising `limit`.",
53
53
  shape: {
54
54
  since: DATE.describe("Earliest announcement date, inclusive (YYYY-MM-DD)."),
@@ -62,7 +62,7 @@ export const TOOLS = [
62
62
  company: z.string().min(1).max(100).optional().describe("Company name contains this text (case-insensitive)."),
63
63
  domain: z.string().min(3).max(253).optional().describe("Exact company domain, for example `example.com`."),
64
64
  investor: z.string().min(1).max(100).optional().describe("Exact investor name, case-insensitive."),
65
- country: z.string().min(1).max(60).optional().describe("Headquarters country, case-insensitive."),
65
+ country: z.string().min(1).max(60).optional().describe("Headquarters country as a name or ISO code, such as US, United States or DE. Other text, such as a city, matches the stated location."),
66
66
  limit: z.number().int().min(1).max(100).optional().describe("Records per page, 1 to 100 (default 25). Each record returned is billed."),
67
67
  cursor: z.string().max(200).optional().describe("Opaque cursor from the previous page's `next_cursor`."),
68
68
  },
@@ -73,7 +73,7 @@ export const TOOLS = [
73
73
  path: "/v1/funding/{id}",
74
74
  title: "Get Funding Round",
75
75
  write: false,
76
- description: "Read one funding record by id. Costs $0.02 when found (free records are used first); a missing id is free.",
76
+ description: "Read one funding record by id. Costs $0.02 when found; a missing id is free.",
77
77
  shape: {
78
78
  id: z.string().uuid().describe("The funding record id from a `funding_search` result."),
79
79
  },
@@ -92,7 +92,7 @@ export const TOOLS = [
92
92
  "a work email, or linkedin_url), or person_name together with company_name. Returns `research_id` at once; the brief takes 20 to 90 seconds, " +
93
93
  "so poll research_get every 10 to 15 seconds until `status` is `completed` or `failed`. " +
94
94
  "Costs one research at the price account_balance reports as `research_price_usd`, held when you submit, charged only when the brief " +
95
- "completes and refunded in full if it fails. Free records do not apply.",
95
+ "completes and refunded in full if it fails.",
96
96
  shape: {
97
97
  domain: z.string().min(3).max(253).optional().describe("The company's domain, for example `acme.com`."),
98
98
  website_url: URL_ARG.optional().describe("Any http(s) URL on the company's website."),
@@ -125,6 +125,26 @@ export const TOOLS = [
125
125
  id: z.string().uuid().describe("The `research_id` from research_submit."),
126
126
  },
127
127
  },
128
+ {
129
+ name: "email_verify",
130
+ method: "POST",
131
+ path: "/v1/email/verify",
132
+ title: "Verify Email Addresses",
133
+ write: true,
134
+ body: true,
135
+ description:
136
+ "Check whether 1 to 25 email addresses can receive mail. Each result has `status` (valid, invalid, catch-all or unknown), " +
137
+ "`reason`, `charged`, `flags`, `smtp_code` and `catch_all_tier`. Costs $0.004 per valid or invalid result, drawn from your " +
138
+ "balance; catch-all and unknown results are free (pricing_get lists which statuses are charged). When the balance covers only " +
139
+ "some addresses, the rest come back `unknown` with reason `not_checked_insufficient_credits`, free.",
140
+ shape: {
141
+ emails: z
142
+ .array(z.string().min(3).max(254))
143
+ .min(1)
144
+ .max(25)
145
+ .describe("The addresses to check, 1 to 25 per call."),
146
+ },
147
+ },
128
148
  {
129
149
  name: "watchlist_create",
130
150
  method: "POST",
@@ -135,7 +155,7 @@ export const TOOLS = [
135
155
  description:
136
156
  "Save a funding-signal alert: a set of funding_search filters plus an https webhook. Each NEW funding event that " +
137
157
  "matches is POSTed to the webhook, signed with the returned `secret` (header Prospect-Signature: t=..,v1=HMAC-SHA256). " +
138
- "Creating is free; each delivered event costs one record ($0.02, free records first), charged only when the webhook " +
158
+ "Creating is free; each delivered event costs one record ($0.02), charged only when the webhook " +
139
159
  "answers 2xx. The `secret` is shown once. Max 20 active per account.",
140
160
  shape: {
141
161
  name: z.string().min(1).max(100).describe("A label, such as 'Series A robotics'."),
@@ -210,7 +230,7 @@ export const TOOLS = [
210
230
  title: "Get Account Balance",
211
231
  idempotent: true,
212
232
  write: false,
213
- description: "Your credit balance and the free records left this month. Free. Check it before a large paged search.",
233
+ description: "Your credit balance and the prices you pay (record, research, email verification). Free. Check it before a large paged search.",
214
234
  shape: {},
215
235
  },
216
236
  {
@@ -241,8 +261,9 @@ export const TOOLS = [
241
261
  write: false,
242
262
  auth: false,
243
263
  description:
244
- "The live price list: funding records (price per record and free records a month), research (whether it is " +
245
- "available and its price per brief) and watchlist deliveries. Free, needs no key. Use it to quote a cost before a large call.",
264
+ "The live price list: the balance a new account starts with, funding records (price per record), research (whether it is " +
265
+ "available and its price per brief), email verification (price per check, which statuses are charged and which are free) " +
266
+ "and watchlist deliveries. Free, needs no key. Use it to quote a cost before a large call.",
246
267
  shape: {},
247
268
  },
248
269
  {