Onsa
Server Details
Find scored B2B leads, read campaign replies and send approved LinkedIn outreach.
- Status
- Healthy
- Uptime
- 100.0% over 42 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
TDQS
Scored across 16 tools
Most tools target a distinct resource+action (search, poll, campaign reads, stats, replies, drafts, shortlist, guidance). A few pairs require careful reading to separate: find_leads vs continue_campaign (both add leads) and fetch_leads vs get_campaign_leads (both return leads), but the descriptions explicitly cross-reference and delineate them.
All names are snake_case verb_noun (find_leads, get_campaign_stats, list_replies, send_outreach, etc.), which is predictable and readable. The only minor deviation is the mix of retrieval verbs fetch/get/find (fetch_leads vs get_campaign_leads), which are near-synonyms for related operations.
16 tools sits at the borderline-heavy end, but each one maps to a real step in the lead-search-to-outreach lifecycle (search, poll, campaign/lead reads, stats, replies, draft review/edit/send, shortlist preview/create/revoke, guidance). Nothing looks redundant or padded, though the surface is on the larger side for the domain.
The lifecycle is well covered: launch/continue searches, poll results, inspect campaigns/leads/stats/replies, research memos, manage outreach drafts, and shortlist sharing. Gaps are minor (no campaign/lead deletion, no direct ICP editing, no way to send a reply back to a prospect), all workaroundable via the Onsa app.
Available Tools
16 toolscontinue_campaignSteer a campaignADestructiveInspect
Sends an instruction to the agent inside an existing campaign and returns a jobId to read with fetch_leads. This is the tool that grows or steers a cohort in place - 'find 5 more like these', 'look at Singapore and the Gulf instead of US institutions', 'focus on funds over $5bn AuM'. find_leads always creates a separate campaign with its own ICP, which splits the funnel and leaves the two cohorts incomparable. The agent sees the campaign's existing leads and ICP, so they can be referred to. It cannot answer back through this API, so a question sent here gets no response. New leads count against the prospect allowance, and de-duplication is per workspace, so a request for 5 more can yield fewer when the agent rediscovers people already in the workspace. It does not remove or skip leads: 'drop the bad ones' takes nothing out of the cohort or out of the outreach queue.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | What to tell the agent, in plain language, as the user would say it | |
| campaignId | Yes | Campaign to continue, from list_campaigns or fetch_leads | |
| taskContext | No | Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request, beyond what the query/message already states. Maximum 1000 characters; this field carries the task context of the current request only - not a transcript, a broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history. |
Output Schema
| Name | Required | Description |
|---|---|---|
| jobId | Yes | |
| campaignId | Yes | |
| campaignUrl | Yes | |
| billingWarning | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations (destructiveHint/idempotentHint/openWorld) by disclosing that leads count against the prospect allowance, that de-duplication is per workspace so a request for 5 can yield fewer, that the agent cannot reply through this API, and that it does not remove or skip leads even on 'drop the bad ones'. These are non-obvious consequences an agent cannot infer from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and return value, then layers limits and the sibling contrast without redundancy. It runs long as a single paragraph, but nearly every sentence carries distinct, decision-relevant information; only the example list is slightly expendable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutating, non-idempotent tool with an output schema already covering the return, the description supplies the missing pieces: side effects (allowance consumption, de-dup), non-effects (no lead removal), the question/no-answer limitation, and the alternative tool. Nothing needed to call it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so message, campaignId, and taskContext are already documented, including the taskContext scoping/authorization caveats. The description adds usage framing for the instruction but no additional field-level meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('sends an instruction to the agent inside an existing campaign') plus the output contract ('returns a jobId to read with fetch_leads'), and distinguishes itself from find_leads by naming that sibling and its differing behavior. An agent can route between the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit: use this to 'grow or steer a cohort in place', use find_leads when a separate ICP/split funnel is acceptable, and do not use it to ask questions since 'a question sent here gets no response'. Includes concrete example instructions, which pins the expected input shape.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_shortlistCreate a public list linkADestructiveInspect
Publishes a preview_shortlist snapshot as a link. It requires the previewKey that preview_shortlist returned, and confirmPublic: true. The server itself requests no confirmation from the user: confirmPublic: true records the caller's statement that the user reviewed this snapshot and confirmed publishing it. The server rebuilds the snapshot and creates nothing when the selection or the snapshot no longer matches that previewKey: a different campaign, selection or order of leadIds, a different note, an includeRationale value that changes the snapshot, a prospect changed or removed, or the campaign renamed since the preview. The link makes the snapshot viewable by anyone who has it for 30 days unless it is revoked with revoke_shortlist. This does not share the conversation or invite anyone into the workspace. Returns the URL, list id and expiry to the requester; sending it to another person is a separate user action.
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | ||
| title | Yes | ||
| leadIds | Yes | ||
| campaignId | Yes | ||
| previewKey | Yes | ||
| confirmPublic | Yes | ||
| includeRationale | Yes | When true, each person in the snapshot carries a fit rating (1–5, or null when none is stored) and a why-matched explanation; when false, the rating is null and the explanation empty. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| url | Yes | |
| snapshot | Yes | |
| expiresAt | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructiveHint=true, openWorldHint=true): it discloses that the server performs no user confirmation, that the snapshot is rebuilt and nothing is created on any mismatch (campaign, selection/order, note, includeRationale, prospect change, rename), the 30-day public visibility window, and that it does not share the conversation or invite anyone. This is exactly the kind of context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then prerequisites, then failure modes, then visibility. Sentences are dense and some are long, but virtually every clause carries distinct information, so the size is justified for the amount of behavior disclosed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't detail return fields, yet it still names URL, list id and expiry and notes that sending the link onward is a separate user action. Combined with the failure-mode list and revocation pointer, an agent has everything needed to call this mutating, open-world tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 14%, so the description must compensate, and it does: it explains that previewKey comes from preview_shortlist, that confirmPublic records the caller's confirmation rather than prompting the user, and that note/leadIds order/campaignId participate in the snapshot-match check. includeRationale's meaning is left to the schema, keeping this short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Publishes') and resource ('a preview_shortlist snapshot as a link') and names the sibling previews (preview_shortlist, revoke_shortlist) it relates to. An agent can distinguish it from the read-only preview and the revoke tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Makes the prerequisite explicit (requires the previewKey that preview_shortlist returned plus confirmPublic: true) and points to revoke_shortlist for undoing the link. It doesn't give an explicit 'when not to use this' statement, but the gating condition is clear enough to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_leadsFetch search resultsARead-onlyIdempotentInspect
Returns the status and any results of a find_leads or continue_campaign job, by jobId. Status values are "pending", "completed" and "stalled", and leads can hold a partial list while "pending". For a find_leads job: "pending" while it has no leads, the agent has not answered and it is under about 15 minutes old, and also while it has leads, until a reply carrying leads completes it; "completed" once the agent posts a reply carrying leads while this is the oldest open job on its campaign, usually its final report (total can still change afterwards); "stalled" as soon as the agent answers without any leads (a question, or none found), or when no lead has arrived after about 15 minutes - derived on each read, so a lead that lands later turns it back to "pending". For a continue_campaign job: "pending" while newLeads is 0 and it is under about 15 minutes old, even after the agent has replied (if that reply confirms a settings-only change, the request is done), and while newLeads is above 0, until a reply carrying leads completes it; "completed" once a reply carrying leads arrives on the campaign while this is the oldest open job there (possibly a late reply from an earlier search), or after about 15 minutes with newLeads 0 when an agent reply was confirmed; "stalled" after about 15 minutes with newLeads 0 when no agent reply was confirmed (agentMessage can still hold one). A reply carrying leads completes only the oldest open job on a campaign, so a newer job stays "pending" meanwhile, even with newLeads above 0. A pending search keeps running when the conversation ends, and a later call with the same jobId returns what it found. First leads arrive within 5 minutes in half of searches and within 9 minutes in 9 of 10. More can arrive until the final report, typically about 10 minutes after the start (9 of 10 within 15). Also returns total (for a find_leads job, the leads the campaign holds now, skipped and deleted ones excluded; for a continuation, equal to newLeads), newLeads (continuations only: leads added to the campaign since the continuation started - a count by time, which can include a late batch from an earlier search), returned (how many this response carries), campaignId (accepted by get_campaign, get_campaign_leads and get_campaign_stats) and campaignUrl, a deep link to the prospects tab for this search in Onsa. agentMessage is the latest agent text in this campaign's chat. For a continuation it is filtered to what was said after the continuation started, though it can be a late message from an earlier search; for a find_leads job it is not filtered, so after a later continue_campaign on the same campaign it can be that request’s reply. A null agentMessage does not mean the agent is silent: artifact-only messages carry no text, and an agent that errored writes nothing there at all. The agent cannot be replied to through this API. While a search is running, one call can wait up to 35 seconds for its first leads or its next batch before answering, so a call can take that long; other calls answer at once. progress carries startedAt, elapsedSeconds and a note on where the search stands, whether the next call will wait, and when results are likely. Each lead carries name, companyName, linkedInUrl, position, headline, location, industry, companyUrl, email (often null), and score (1-5) with scoreExplanation, the reasoning for why this person matches the ICP. A lead has signal (status verified, inferred or none, plus a one-sentence summary) only when the search asked for a need signal. refinements appears when leads are returned and the campaign does not filter by company size; each entry is a suggestion the user can accept, not something already done.
| Name | Required | Description | Default |
|---|---|---|---|
| jobId | Yes | The jobId returned by find_leads | |
| limit | No | How many leads to return (default 100) |
Output Schema
| Name | Required | Description |
|---|---|---|
| jobId | Yes | |
| leads | Yes | |
| total | Yes | |
| status | Yes | One of "pending", "completed", "stalled"; more values may be added later. `leads` can hold a partial list while "pending". For a find_leads job: "pending" while it has no leads, the agent has not answered and it is under about 15 minutes old, and also while it has leads, until a reply carrying leads completes it; "completed" once the agent posts a reply carrying leads while this is the oldest open job on its campaign, usually its final report (`total` can still change afterwards); "stalled" as soon as the agent answers without any leads (a question, or none found), or when no lead has arrived after about 15 minutes - derived on each read, so a lead that lands later turns it back to "pending". For a continue_campaign job: "pending" while `newLeads` is 0 and it is under about 15 minutes old, even after the agent has replied (if that reply confirms a settings-only change, the request is done), and while `newLeads` is above 0, until a reply carrying leads completes it; "completed" once a reply carrying leads arrives on the campaign while this is the oldest open job there (possibly a late reply from an earlier search), or after about 15 minutes with `newLeads` 0 when an agent reply was confirmed; "stalled" after about 15 minutes with `newLeads` 0 when no agent reply was confirmed (agentMessage can still hold one). A reply carrying leads completes only the oldest open job on a campaign, so a newer job stays "pending" meanwhile, even with `newLeads` above 0. |
| newLeads | Yes | |
| progress | Yes | |
| returned | Yes | |
| campaignId | Yes | |
| campaignUrl | Yes | |
| refinements | No | |
| agentMessage | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnly, idempotent, non-destructive), and the description adds far more: status state machine for both job types, the 35-second long-poll wait, partial results while pending, timing distributions, null agentMessage semantics, and derived-on-read status behavior. This is exceptional disclosure beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose then status semantics, and nearly every sentence carries load-bearing behavioral detail given the complexity. It is a single dense wall of text with no structure or bullets, which hurts scannability, but little of the content is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a polling tool with an output schema and safety annotations, the description covers everything an agent needs: status meanings, wait behavior, return field semantics, and edge cases like artifact-only messages and late replies. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents jobId and limit, so the baseline is 3. The description does add jobId lifecycle meaning (same jobId returns later-found results) but says nothing about `limit`, so it does not meaningfully exceed the schema for parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Returns the status and any results of a find_leads or continue_campaign job, by jobId.' It names the two job-producing siblings it serves, so an agent can distinguish it from find_leads/continue_campaign without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly implies polling usage ('a later call with the same jobId returns what it found') and explains the full status lifecycle for both job types. It does not explicitly frame a when-to-use/when-not comparison against siblings beyond naming them, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_leadsFind leadsADestructiveInspect
Starts a live B2B lead search with Onsa's agent, matching real people (with LinkedIn profiles) against the workspace's ICP. Takes a natural-language brief - titles, company type, geography, e.g. 'find 5 fintech founders in NYC'. Returns a jobId immediately, with campaignUrl and a progress note. The search itself runs in the background and keeps running after the conversation moves on. First leads arrive within 5 minutes in half of searches and within 9 minutes in 9 of 10. More can arrive until the final report, typically about 10 minutes after the start (9 of 10 within 15). Its status and results are read with fetch_leads, with the same jobId at any later time. Hosts that render MCP Apps show a live card that follows the search and lists leads as they arrive. limit is a target the agent aims at rather than a cap, so it often returns more than asked. Every lead it finds counts against the workspace's prospect allowance.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many leads to find (default 5) | |
| query | Yes | Natural-language lead brief, e.g. 'find 5 fintech founders in NYC' | |
| taskContext | No | Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request, beyond what the query/message already states. Maximum 1000 characters; this field carries the task context of the current request only - not a transcript, a broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history. |
Output Schema
| Name | Required | Description |
|---|---|---|
| jobId | Yes | |
| progress | Yes | |
| campaignId | Yes | |
| campaignUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructive/openWorld/non-idempotent, and the description goes well beyond them: async background execution that continues after the conversation moves on, concrete latency expectations (first leads within 5 min in half of searches, final report ~10 min after start), and the critical cost disclosure that every lead found counts against the workspace's prospect allowance. This is exactly the behavioral context an agent needs before triggering a costly, destructive search.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads what the tool does and its return value, then layers timing, cost, and the limit caveat. It is long but nearly every sentence adds decision-relevant detail; a slight trim of the latency statistics would tighten it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the async lifecycle, the sibling used to read results, the immediate return (jobId, campaignUrl, progress), latency expectations, quota impact, and UI behavior on MCP Apps hosts. With an output schema present, no further return-value explanation is required, so the definition is complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds genuine meaning about `limit`: it is a target the agent aims at rather than a hard cap, so results may exceed it. The query and taskContext semantics are left to the schema, which documents them thoroughly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('starts a live B2B lead search'), the population it targets (real people with LinkedIn profiles matched to the workspace ICP), and how it differs from siblings by noting status/results are read via fetch_leads. An agent can distinguish it from get_campaign_leads or list_campaigns without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to fetch_leads with the same jobId for reading status and results, and frames the tool as the initiation step. It lacks an explicit when-not-to-use clause (e.g. don't re-run for an existing job), so it falls just short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_campaignGet campaignARead-onlyIdempotentInspect
Returns one campaign's ICP - the ideal-customer profile the agent derived and scores leads against - plus its outreach template and settings. The ICP comes back exactly as stored, in snake_case: perfect_lead and reachable_market are one-line summaries, while company and person hold the rules that actually drive scoring, each an object with critical and preferential rule lists. product and owner describe the seller. The two summary strings are not the scoring criteria; company.critical and person.critical are. No key is guaranteed present. outreachTemplate shows how much personalization the messages allow: a template whose only placeholders are [FIRST_NAME] and [COMPANY_NAME] produces near-identical mail-merge copy for every lead.
| Name | Required | Description | Default |
|---|---|---|---|
| campaignId | Yes | Campaign id, as returned by list_campaigns or fetch_leads |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| icp | Yes | |
| tags | Yes | |
| title | Yes | |
| createdAt | Yes | |
| updatedAt | Yes | |
| leadsTotal | Yes | |
| campaignUrl | Yes | |
| leadsApprove | Yes | |
| outreachTemplate | Yes | |
| outreachAutoApprove | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false. The description adds substantial behavioral context: data returns exactly as stored in snake_case, the summary strings are not scoring criteria, no key is guaranteed present, and it explains how to interpret outreachTemplate personalization. This goes well beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is detailed but every sentence contributes meaning: it explains the main purpose, the structure of the ICP, clarifies which fields drive scoring, warns about missing keys, and interprets the outreach template. It is front-loaded with the primary purpose and well-organized.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (nested ICP structure with critical/preferential rules), the description thoroughly explains the semantics and caveats. Since an output schema exists, it doesn't need to describe return values, but it explains how to interpret the data. Nothing an agent needs to decide when to call it or understand its output is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the schema already fully documents campaignId with format and description. The description does not add any additional parameter-specific meaning, so the baseline of 3 applies. No extra compensation needed since coverage is complete.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Returns one campaign's ICP - the ideal-customer profile... plus its outreach template and settings.' It clearly distinguishes the tool's scope from siblings that return leads or stats. The purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context—when you need the ICP and outreach settings, use this tool. However, it does not explicitly mention alternatives or conditions where another sibling (e.g., get_campaign_leads) would be more appropriate. It provides clear context but lacks explicit exclusions or alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_campaign_leadsGet campaign leadsARead-onlyIdempotentInspect
Returns the leads of any campaign by campaignId, with the same fields as fetch_leads, including score and scoreExplanation. It covers campaigns not started in this session, which fetch_leads cannot reach because fetch_leads requires a jobId from a find_leads call in the same session. Passing leadIds resolves the reply buckets from get_campaign_stats back into named people. A lead carries signal only when the search asked for a need signal.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many leads to return (default 50) | |
| leadIds | No | Optional; when set, only these leads are returned, e.g. positiveLeadIds from get_campaign_stats | |
| campaignId | Yes | Campaign id, as returned by list_campaigns or fetch_leads |
Output Schema
| Name | Required | Description |
|---|---|---|
| leads | Yes | |
| total | Yes | |
| returned | Yes | |
| campaignId | Yes | |
| campaignUrl | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, so safety is covered. The description adds real context beyond that: it mirrors fetch_leads' field set (score, scoreExplanation) and notes that `signal` is only present when the search asked for a need signal — a conditional output behavior the agent cannot learn from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the core purpose and differentiation before parameter and output caveats. Every sentence carries information; it is slightly dense but has no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists as do comprehensive annotations, so return-value and safety disclosure are not needed here. The description supplies the sibling routing, field parity, and conditional-signal context, leaving only minor operational details (like the limit default) to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: it explains that leadIds resolves get_campaign_stats reply buckets (e.g. positiveLeadIds) back into named people, which the schema only describes as 'only these leads are returned'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Returns) and resource (leads of any campaign) keyed by campaignId, then immediately names the sibling it competes with (fetch_leads) and what differentiates them. An agent can distinguish it without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use it vs fetch_leads: this tool reaches campaigns not started in the current session, whereas fetch_leads requires a jobId from a find_leads call in the same session. It also routes the leadIds parameter to its source (reply buckets from get_campaign_stats).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_campaign_statsGet campaign funnelARead-onlyIdempotentInspect
Returns the outreach funnel for one campaign: invites sent, invites accepted, messages sent, and replies split into positive / negative / other by sentiment. LinkedIn and email are merged, as on Onsa's Overview page. These count leads rather than actions - a lead invited twice counts once - so where a lead was re-invited they read slightly lower than the Overview widget, which counts actions. invitesSent can exceed leadsTotal without anyone having been invited twice: the counters are already de-duplicated by lead, and the gap means a lead who was contacted has since been skipped or deleted, which action rows survive and leadsTotal does not count. Onsa stores no post likes or emoji reactions at all, so 'LinkedIn reactions' in this data means the replies people sent; list_replies returns their text, and this tool only counts them.
rates carries acceptancePct, replyPct, positivePct and negativePct, each already computed over its own correct denominator; leadsTotal is not one of those denominators, since it counts every prospect in the cohort including those never contacted. A rate is null when its denominator is 0, meaning nothing was sent so no rate exists - which is different from the counts above being genuinely 0. All four rates count only replies Onsa has scored, so an unscored or still-in-window reply appears in none of them, and list_replies can legitimately show more replies than the rates imply. Two further properties of the data: the *Scheduled counts are everything queued regardless of date, and sentiment is evaluated once per lead ever rather than once per reply. A campaign whose invites were never sent reads as all zeros, which is 'not tried yet' rather than 'failed'.
| Name | Required | Description | Default |
|---|---|---|---|
| campaignId | Yes | Campaign id, as returned by list_campaigns or fetch_leads |
Output Schema
| Name | Required | Description |
|---|---|---|
| rates | Yes | |
| responses | Yes | |
| campaignId | Yes | |
| leadsTotal | Yes | |
| campaignUrl | Yes | |
| invitesSent | Yes | |
| messagesSent | Yes | |
| invitesAccepted | Yes | |
| invitesScheduled | Yes | |
| messagesScheduled | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint false, so the safety profile is clear. The description adds extensive behavioral nuance: de-duplication by lead, rates computed over their own denominators, nulls when denominator is zero, sentiment evaluated once per lead ever, and the meaning of all-zero results. It also clarifies that 'LinkedIn reactions' actually refers to replies because Onsa stores no likes. This goes far beyond annotations, fully disclosing the tool's behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long and dense, but every sentence contributes unique behavioral insight. It opens with a crisp one-sentence summary, then systematically addresses edge cases and clarifications. It is well-structured and front-loaded with the core purpose. While it could be trimmed slightly, the complexity of the data justifies the length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is exhaustive for a read-only stats tool. It covers return structure, de-duplication logic, rate denominators, null semantics, the difference between counts and actions, scheduled counts, sentiment evaluation, and the all-zero case. The output schema exists but the description enriches it with practical interpretation. Nothing an agent needs to correctly interpret the returned data is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, campaignId, is already well described in the schema: 'Campaign id, as returned by list_campaigns or fetch_leads.' The description adds no additional parameter-specific meaning. Since schema description coverage is 100%, the baseline of 3 applies; the description is not required to compensate, and it doesn't.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the exact output: 'Returns the outreach funnel for one campaign: invites sent, invites accepted, messages sent, and replies split into positive / negative / other by sentiment.' It uses a specific verb ('returns') and a precise resource ('one campaign'). It also distinguishes itself from list_replies by noting that tool returns text while this one counts, which differentiates it from a sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives strong contextual guidance by contrasting with list_replies: 'list_replies returns their text, and this tool only counts them.' It also explains why counts may differ from the Overview widget, helping agents choose the right tool. However, it does not explicitly state 'use this instead of X when you need aggregate counts,' but the guidance is clear enough for a competent agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_lead_memoGet lead research memoARead-onlyIdempotentInspect
Returns the research memo Onsa's agent wrote about one lead: role history, company size and stage, what they have said publicly, and the angle on them. It is usually far richer than scoreExplanation, and it is the source material for outreach built on a specific, checkable fact rather than a generic opener. Most leads have no memo - Onsa writes one only for prospects it has researched - so memo: null is the common case and not an error, and scoreExplanation is the remaining source in that case.
| Name | Required | Description | Default |
|---|---|---|---|
| leadId | Yes | Lead to read, from any tool that returns leads |
Output Schema
| Name | Required | Description |
|---|---|---|
| memo | Yes | |
| name | Yes | |
| leadId | Yes | |
| companyName | Yes | |
| memoWrittenAt | Yes | |
| scoreExplanation | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety. The description adds critical behavioral context beyond annotations: most leads have no memo, so a null return is common and not an error, and it clarifies the source of the memo (Onsa's agent). This is valuable and does not contradict any annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise yet comprehensive, using three sentences that each add distinct value: content of the memo, comparison to scoreExplanation, and the null-return behavior. No fluff or redundant phrasing; the most critical information (memo content and null case) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return format is not needed. The description covers the tool's purpose, contents, typical null behavior, and relationship to the alternative source. Nothing an agent needs to invoke it correctly or interpret results is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single parameter leadId, which already explains it is the lead to read. The description adds the hint 'from any tool that returns leads', which is mildly helpful but does not substantially alter parameter meaning. Baseline 3 is appropriate given full schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb and resource: 'Returns the research memo' about one lead, and enumerates its contents (role history, company size/stage, public statements, angle). It clearly distinguishes itself from scoreExplanation by noting it is 'usually far richer' and serves as the basis for fact-based outreach. This differentiates it from sibling tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use it: for building outreach on a specific, checkable fact, and notes it is richer than scoreExplanation. It also states that when no memo exists (common case), scoreExplanation is the fallback. This gives clear context and implies alternatives, though it does not explicitly name a sibling tool or a hard 'when not to use' condition, so it loses one point.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_campaignsList campaignsARead-onlyIdempotentInspect
Lists the campaigns (past lead searches) in this workspace that the user takes part in, newest first. Returns the newest limit of them, default 50; returned against total shows whether older campaigns were omitted. Each entry has id, title, leadsTotal, hasIcp, tags, createdAt and updatedAt. An id is accepted by get_campaign for its ICP, get_campaign_leads for its people, get_campaign_stats for its outreach funnel, list_replies for what prospects wrote back, and list_next_steps for what the campaign still needs a human to do. Searches started over MCP often share a generic title, so the ICP and the dates distinguish cohorts more reliably than the title alone. A campaign row exists from the moment a search starts, so the newest entry is frequently still empty, with leadsTotal 0.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many campaigns to return, newest first (default 50) |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| returned | Yes | |
| campaigns | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark readOnly/idempotent/non-destructive, and the description adds substantial behavior beyond that: newest-first ordering, default limit and returned/total omission signal, field list, and the caveat that a campaign row exists as soon as a search starts and is often empty with leadsTotal 0. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The main action is front-loaded in the first sentence, and each subsequent sentence adds useful operational detail (limit behavior, fields, follow-up routing, cohort identification, empty newest rows) without fluff. Length is justified for a central list tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter list tool with an output schema and strong annotations, the description covers scope, ordering, limit semantics, return fields, caveats, and downstream tool usage. Nothing an agent needs to select or invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already explains limit and its default. The description adds the returned/total consequence of limiting, but this is primarily output behavior, so it only marginally enriches the parameter semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb ('Lists'), resource ('campaigns (past lead searches)'), and scope ('in this workspace that the user takes part in'), plus ordering ('newest first'). It clearly separates this from sibling detail tools by naming what an id can be used for next.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly maps follow-up tools to their purposes ('get_campaign for its ICP, get_campaign_leads for its people...') and warns that generic MCP titles make title unreliable, telling the agent how to interpret results. This is more than clear context; it routes to alternatives by need.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_next_stepsWhat to do nextARead-onlyIdempotentInspect
Returns read-only guidance for what to do next. Without campaignId, it returns the first-search question, active search progress, or campaign names and statuses to choose from. A single accessible campaign is resolved automatically. With campaignId, it returns a ranked to-do list: people who replied, people who accepted an invite but were never messaged, drafts and LinkedIn follow-ups waiting for approval, people with no reply for 7+ days while follow-ups are off, leads found but never contacted, and setup that is missing. It answers 'what should I do about this campaign today', where get_campaign_stats answers 'how is it doing'. For replies specifically, list_replies is the better source: its awaitingOurReply compares timestamps, while the replied bucket here covers only leads whose sentiment was scored and does not know whether we have since answered. leadIds passed to get_campaign_leads resolves the buckets into named people. Limits of the data: Onsa does not record whether we have already replied, or whether someone was contacted outside Onsa; 'replied' includes only replies whose sentiment was scored, so it is a floor; a withdrawn or unreachable invite leaves no trace, so some 'never contacted' leads may already have been tried. Sentiment is judged once per lead, not per message. Counts are complete; leadIds are capped at 200.
| Name | Required | Description | Default |
|---|---|---|---|
| campaignId | No | Optional campaign to inspect; omitted for workspace guidance |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| items | Yes | |
| scope | No | |
| total | No | |
| returned | No | |
| campaigns | No | |
| campaignId | No | |
| leadsTotal | No | |
| nextAction | No | |
| campaignUrl | No | |
| workspaceUrl | No | |
| campaignTitle | No | |
| workspaceState | No | |
| searchAvailability | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the bar is lower, yet the description adds substantial context: data limitations (Onsa doesn't record prior replies or off-platform contact), the 'replied' bucket as a floor, sentiment judged once per lead, no trace for withdrawn/unreachable invites, and leadIds capped at 200 while counts are complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core behavior, then alternatives, then limitations, with no filler sentences. It is dense and fairly long, but every clause carries actionable information; only minor tightening is possible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return-value documentation is unnecessary, and the description instead covers the two invocation modes, bucket composition, sibling alternatives, and a thorough account of data limitations — complete for a read-only guidance tool of this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and only one optional param exists, so the schema already documents campaignId. The description goes beyond it by explaining the omission path (workspace guidance, auto-resolution of a single accessible campaign) and the campaignId path (ranked to-do buckets), adding meaning the schema's one-line note doesn't.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (returns guidance for what to do next) and precisely delineates two modes: without campaignId it surfaces the first-search question, search progress, or campaign choices; with campaignId it returns a ranked to-do list. It names the buckets and explicitly distinguishes itself from get_campaign_stats ('how is it doing') and list_replies, so an agent can select it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing: get_campaign_stats for campaign health, list_replies as the better source for replies (with the awaitingOurReply vs scored-sentiment rationale), and get_campaign_leads with leadIds to resolve buckets into people. When/when-not/alternative conditions are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_pending_outreachList pending outreachARead-onlyIdempotentInspect
Lists outreach messages the agent has drafted that are waiting for a human to approve - the 'a message for X is ready' queue. Each entry carries the draft text, the lead it is for, and why that lead scored as it did. Without campaignId, the list covers every campaign in this workspace that the user takes part in. Each entry has kind: first_message, or follow_up (a LinkedIn follow-up for someone who did not reply, carrying the message it follows up in followsUp). This tool sends nothing: rewrite_outreach replaces a draft's text, and send_outreach queues one for delivery.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many drafts to return (default 50) | |
| campaignId | No | One campaign to limit the list to; when omitted, the list covers every campaign the user takes part in |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| pending | Yes | |
| returned | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and destructiveHint=false; the description adds real value by stating 'This tool sends nothing' and delineating what each entry contains (draft text, lead, scoring rationale, kind, followsUp). It does not discuss ordering, pagination, or approval workflow mechanics, but the safety profile is well reinforced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose, then layers in scope, entry shape, and sibling routing in a compact four-sentence block. Dense but every sentence contributes; slight redundancy in re-explaining campaignId scope.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not document return values, yet it still characterizes entry contents and the kind/followsUp semantics. Together with the annotations and full schema coverage, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both limit and campaignId are already documented, and the description's campaignId scoping note largely restates the schema. Baseline 3 applies since the schema carries the parameter burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Lists outreach messages the agent has drafted waiting for a human to approve') and crystallizes it with a concrete mental model ('the a message for X is ready queue'). It also distinguishes itself from write siblings by naming rewrite_outreach and send_outreach.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the default scope when campaignId is omitted and routes the agent to rewrite_outreach and send_outreach with their distinct effects. It does not, however, contrast with other read siblings like list_next_steps or list_replies, so the when-to-use framing is clear but not fully exclusive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_repliesRead prospect repliesARead-onlyIdempotentInspect
Returns the text of what prospects replied, for every lead in the campaign that answered, paired with the outbound message it answers. get_campaign_stats counts replies and labels them; this returns the words. sentiment is Onsa's own label, written once per lead on their first reply - later replies never change it, and a reply Onsa has not scored yet comes back as sentiment: null, which means unscored rather than neutral. Those unscored replies are absent from get_campaign_stats entirely, so this tool can return more replies than the funnel counts.
Three derived fields come with the reply. awaitingOurReply: the prospect spoke last and no sent message followed. It is structural only - a flat 'no thanks' satisfies it too - and Onsa sees only what Onsa sent, so a reply made by hand inside LinkedIn is invisible to it; what the data supports is 'no reply recorded here'. daysSinceLastReply is elapsed whole days rather than time-unanswered: it is populated even where we did answer, so it describes time-unanswered only when awaitingOurReply is also true. looksLikeBroadcast: the prospect's most recent message reached another profile in this campaign word for word, which indicates a mass DM rather than an answer. All three are floors rather than verdicts - a blast only one lead received is indistinguishable from a real reply, and two people who send the same long template are both flagged. Top-level awaitingOurReplyCount spans the whole campaign rather than this page, and leaves out broadcasts and replies scored negative; it can exceed returned when limit is small.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum replies to return, newest first (default 50) | |
| campaignId | Yes | Campaign to read replies from |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| returned | Yes | |
| campaignId | Yes | |
| campaignUrl | Yes | |
| campaignTitle | Yes | |
| conversations | Yes | |
| awaitingOurReplyCount | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, but the description adds substantial behavioral context: the semantics of sentiment null (unscored vs neutral), the structural nature of awaitingOurReply (only sees Onsa-sent messages, hand-made replies invisible), daysSinceLastReply as elapsed days even if answered, looksLikeBroadcast as a floor not verdict, and top-level count spanning the whole campaign with exclusions. This far exceeds the minimal annotation coverage and clarifies subtle data interpretation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence earns its place, explaining nuanced semantics that an agent must understand to interpret results correctly. It is front-loaded with the core purpose, then systematically explains the three derived fields and the top-level count, using clear structure. No fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't restate return structure. It covers edge cases (unscored replies, hand-made replies, broadcast detection limits, daysSinceLastReply semantics) and clarifies the meaning of derived fields and the top-level counter. For a read-only tool with rich output semantics, this is complete for correct invocation and interpretation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with both parameters fully documented (limit with default and ordering, campaignId with format). The description adds no new parameter-level semantics beyond what the schema already provides, so the baseline of 3 is appropriate. It does mention the interaction between limit and the top-level count, but that pertains to output behavior rather than parameter usage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states what the tool does: returns reply text paired with the outbound message, and explicitly contrasts with get_campaign_stats which counts replies. The verb 'returns' and resource 'reply text' are specific, and the sibling differentiation is explicit, leaving no ambiguity about purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides direct guidance on when to use this tool versus get_campaign_stats, noting that this returns the words while the sibling counts and labels. It also explains when this tool may return more replies than the funnel counts, clarifying its scope and limitations relative to the alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
preview_shortlistPreview a shareable listARead-onlyIdempotentInspect
Prepares a preview of 1–50 selected prospects from a campaign the user takes part in, and publishes nothing. The snapshot holds a list title, which is the campaign's name, the note, and for each person only a name, role, company, LinkedIn profile and, when includeRationale is true, a fit rating and why-matched explanation. The preview returns the complete snapshot a link would expose, with the previewKey that create_shortlist requires; a created link stays viewable for 30 days by anyone who has it, and can be revoked with revoke_shortlist.
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | ||
| title | Yes | ||
| leadIds | Yes | ||
| campaignId | Yes | ||
| includeRationale | Yes | When true, each person in the snapshot carries a fit rating (1–5, or null when none is stored) and a why-matched explanation; when false, the rating is null and the explanation empty. |
Output Schema
| Name | Required | Description |
|---|---|---|
| snapshot | Yes | |
| previewKey | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint, so the bar is lower, yet the description adds real behavior: no publication occurs, the snapshot's exact field set, the conditional rationale fields, and the 30-day public viewability of a resulting link. It stops short of stating auth or rate-limit expectations, but the added context is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and the 'publishes nothing' constraint, then details the payload and the downstream key. Dense but every clause carries information; only the snapshot field enumeration could be trimmed since the output schema exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values needn't be described, yet the description still outlines the snapshot contents and ties the output to create_shortlist, giving the agent enough to chain calls. Missing only edge details such as length limits and campaignId ownership semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 20% (includeRationale alone is documented), so the description carries most of the burden and does so reasonably: it pins leadIds to the 1–50 range, explains title as the campaign's name and note as the snapshot note, and restates includeRationale's effect. It omits the title/note length limits that the schema enforces, which keeps it below 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Prepares a preview') and resource ('1–50 selected prospects from a campaign'), and immediately distinguishes itself from the write path by noting it 'publishes nothing'. An agent can tell this apart from create_shortlist and revoke_shortlist without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Makes the preview→create workflow explicit by saying the result contains 'the previewKey that create_shortlist requires', and names revoke_shortlist as the undo path for the link that a later create produces. It doesn't spell out a when-not-to-use condition, but the create/preview split is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_shortlistRevoke a list linkADestructiveIdempotentInspect
Revokes a list link by the id create_shortlist returned; only the user who created the link can revoke it. Future views stop immediately; previously copied or downloaded information cannot be recalled.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| revoked | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With destructiveHint=true already declared, the description adds real operational context: effect is immediate ('Future views stop immediately') and irreversible for already-copied content ('previously copied or downloaded information cannot be recalled'), plus an authorization constraint (creator-only). It doesn't address idempotent re-calls despite idempotentHint=true, so it stops short of 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with the core action first, then preconditions, then consequences. No padding, no repetition of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation; the description covers the id's provenance, the authorization requirement, and the destructive/irreversible effects, which is everything an agent needs to invoke this single-parameter mutation correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate; it does by telling the agent the id originates from create_shortlist rather than being an arbitrary UUID, which is the one non-obvious fact about a single required uuid parameter. It adds no validation or format detail beyond the schema pattern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Revokes a list link') and anchors it to a sibling ('the id create_shortlist returned'), so an agent can distinguish it from create_shortlist and preview_shortlist without reading either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It supplies a precondition ('only the user who created the link can revoke it') which implies who may call it, but never states when to reach for this tool versus siblings such as create_shortlist or preview_shortlist, nor any when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rewrite_outreachRewrite outreach draftADestructiveIdempotentInspect
Replaces the text of an outreach draft that is waiting for approval. The current draft and the lead's scoreExplanation come from list_pending_outreach; get_lead_memo carries the richer research on that person. The rewritten draft stays in the approval queue, and this tool sends nothing. LinkedIn follow-up drafts (kind: follow_up) cannot be rewritten here: they are edited in Onsa, or approved as written with send_outreach.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The full replacement message. This same string is called `draftText` when list_pending_outreach returns it, and `confirmText` when you pass it to send_outreach — three names, one set of bytes. | |
| leadId | Yes | Lead whose draft to rewrite, from list_pending_outreach | |
| subject | No | Email subject; only email delivery reads it, and send_outreach, a LinkedIn send, does not. When omitted, the stored subject stays unchanged, so a body-only edit keeps it; a string replaces it, and null clears it. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | |
| leadId | Yes | |
| subject | Yes | |
| updated | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and readOnlyHint=false, which alone would alarm an agent about a write. The description adds the crucial bound: the draft 'stays in the approval queue, and this tool sends nothing', so the agent understands the mutation is a text replacement, not an outbound message. It does not cover auth/permission requirements or whether the prior text is recoverable, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, all front-loaded with the core mutation first, then sourcing, then side effects, then the exclusion. No filler, though the middle two sentences pack several cross-references that could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation. The description covers the operation, data sourcing from two siblings, the side-effect boundary (nothing sent, stays queued), and the unsupported draft kind with its alternative — everything needed to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema itself already documents the text/draftText/confirmText aliasing, the leadId source, and the subject null-vs-omitted behavior in detail. The description's parameter-relevant content (leadId from list_pending_outreach, scoreExplanation source) largely repeats what the schema states, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('Replaces the text') plus resource ('an outreach draft') plus a state qualifier ('waiting for approval') that an agent can verify. It clearly distinguishes itself from list_pending_outreach (source of the draft), get_lead_memo (research), and send_outreach (the actual send).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: current draft and scoreExplanation come from list_pending_outreach, richer research from get_lead_memo, and LinkedIn follow_up drafts are excluded with the correct alternative path (edit in Onsa or approve as written with send_outreach). Both when-to-use and when-not-to-use are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_outreachSend outreach messageADestructiveInspect
Queues one already-approved outreach draft for delivery to a real person on LinkedIn. It requires confirmText, the draft body character-for-character as stored, and confirmName, the recipient's name: drafts are often near-identical between people, so matching the body alone does not identify which one was meant. A mismatch is refused without returning the stored text, which list_pending_outreach supplies. The server additionally requires a confirmation from the person at the keyboard, rendered by the MCP client and quoting the draft as stored; that approval is single-use and bound to one recipient and one draft. A client that cannot render such a confirmation receives a refusal carrying a link to approve inside the Onsa app, and nothing is queued. On success the message is queued rather than delivered: Onsa sends it on its own schedule, subject to daily pacing limits. A follow-up draft (kind: follow_up) goes into the same LinkedIn thread as the first message and is cancelled if the person replies before it is sent.
| Name | Required | Description | Default |
|---|---|---|---|
| leadId | Yes | Lead to message, from list_pending_outreach | |
| confirmName | Yes | The recipient's name as shown to the user, to prove you meant this person | |
| confirmText | Yes | The exact draft text you showed the user and they approved, verbatim |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | No | |
| name | Yes | |
| leadId | Yes | |
| queued | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructive/non-idempotent/open-world, and the description adds substantial context beyond them: a single-use, recipient-bound confirmation from the person at the keyboard, refusal-without-echoing-text on mismatch, a fallback refusal link for clients that cannot render the confirmation, and the fact that success means queued (paced) rather than delivered. It even discloses follow-up thread and reply-cancellation behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the two confirmation arguments are front-loaded, and each subsequent sentence carries a distinct operational fact (refusal behavior, app-approval fallback, queuing semantics, follow-up threading). It is long but nearly every sentence earns its place; minor density could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, open-world mutation with an output schema, the description covers what an agent needs: prerequisites, required confirmation semantics, failure modes, and post-call queuing/pacing behavior. Return values are covered by the output schema, so nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: confirmText must be the body 'character-for-character as stored', confirmName is the recipient's name, and it explains why both are needed (near-identical drafts make body matching insufficient). That rationale is not in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Queues one already-approved outreach draft for delivery to a real person on LinkedIn') and immediately distinguishes itself from siblings by referencing list_pending_outreach as the source of drafts and stored text. An agent can tell this apart from rewrite_outreach or list_pending_outreach without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The precondition is explicit: the draft must already be approved, and the tool routes the agent to list_pending_outreach when a mismatch occurs. It does not name rewrite_outreach as the path for editing an unapproved draft, so the sibling routing is incomplete, but the when-to-use condition is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
- Changed
list_pending_outreach2 fields changed- added
Output schema / properties / pending / items / properties / followsUpAdded value: +{ + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "sentAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "sentAtIsExact": { + "type": "boolean" + }, + "text": { + "type": "string" + } + }, + "required": [ + "text", + "sentAt" + ], + "type": "object" + }, + { + "type": "null" + } + ] +} - added
Output schema / properties / pending / items / properties / kindAdded value: +{ + "type": "string" +}
- Changed
send_outreach1 field changed- added
Output schema / properties / kindAdded value: +{ + "type": "string" +}
2 tool updates
- Changed
fetch_leads2 fields changed- added
Output schema / properties / leads / items / properties / signalAdded value: +{ + "additionalProperties": {}, + "properties": { + "sourceUrl": { + "type": "string" + }, + "status": { + "enum": [ + "verified", + "inferred", + "none" + ], + "type": "string" + }, + "summary": { + "type": "string" + } + }, + "required": [ + "status", + "summary" + ], + "type": "object" +} - added
Output schema / properties / refinementsAdded value: +{ + "items": { + "additionalProperties": {}, + "properties": { + "arguments": { + "additionalProperties": {}, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "kind": { + "type": "string" + }, + "offer": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "tool": { + "type": "string" + } + }, + "required": [ + "kind", + "reason", + "offer", + "tool", + "arguments" + ], + "type": "object" + }, + "type": "array" +}
- Changed
get_campaign_leads1 field changed- added
Output schema / properties / leads / items / properties / signalAdded value: +{ + "additionalProperties": {}, + "properties": { + "sourceUrl": { + "type": "string" + }, + "status": { + "enum": [ + "verified", + "inferred", + "none" + ], + "type": "string" + }, + "summary": { + "type": "string" + } + }, + "required": [ + "status", + "summary" + ], + "type": "object" +}
7 tool updates
- Changed
continue_campaign1 field changed- changed
Input schema / properties / taskContext / descriptionPrevious value: -"Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request. Omit when the query/message is sufficient. Maximum 1000 characters. Do not send a transcript, broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history."New value: +"Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request, beyond what the query/message already states. Maximum 1000 characters; this field carries the task context of the current request only - not a transcript, a broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history."
- Changed
create_shortlist1 field changed- changed
Input schema / properties / includeRationale / descriptionPrevious value: -"Include fit rating and why-matched explanation; normally true unless the sender asks to omit them."New value: +"When true, each person in the snapshot carries a fit rating (1–5, or null when none is stored) and a why-matched explanation; when false, the rating is null and the explanation empty."
- Changed
find_leads1 field changed- changed
Input schema / properties / taskContext / descriptionPrevious value: -"Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request. Omit when the query/message is sufficient. Maximum 1000 characters. Do not send a transcript, broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history."New value: +"Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request, beyond what the query/message already states. Maximum 1000 characters; this field carries the task context of the current request only - not a transcript, a broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history."
- Changed
get_campaign_leads1 field changed- changed
Input schema / properties / leadIds / descriptionPrevious value: -"Optional: return only these leads, e.g. positiveLeadIds from get_campaign_stats"New value: +"Optional; when set, only these leads are returned, e.g. positiveLeadIds from get_campaign_stats"
- Changed
list_pending_outreach1 field changed- changed
Input schema / properties / campaignId / descriptionPrevious value: -"Limit to one campaign; omit for every campaign you take part in"New value: +"One campaign to limit the list to; when omitted, the list covers every campaign the user takes part in"
- Changed
preview_shortlist1 field changed- changed
Input schema / properties / includeRationale / descriptionPrevious value: -"Include fit rating and why-matched explanation; normally true unless the sender asks to omit them."New value: +"When true, each person in the snapshot carries a fit rating (1–5, or null when none is stored) and a why-matched explanation; when false, the rating is null and the explanation empty."
- Changed
rewrite_outreach1 field changed- changed
Input schema / properties / subject / descriptionPrevious value: -"Email subject. OMIT it to leave the stored subject untouched (do this for LinkedIn, and whenever you are only changing the body); pass null only if you genuinely mean to clear it."New value: +"Email subject; only email delivery reads it, and send_outreach, a LinkedIn send, does not. When omitted, the stored subject stays unchanged, so a body-only edit keeps it; a string replaces it, and null clears it."
4 tool updates
- Changed
fetch_leads2 fields changed- changed
Input schema / properties / jobId / descriptionPrevious value: -"The jobId returned by find_leads — never invent one"New value: +"The jobId returned by find_leads" - changed
Output schema / properties / status / descriptionPrevious value: -"One of: \"pending\" (search still running), \"completed\" (a batch of leads arrived — not a promise that no more will), \"stalled\" (no leads after ~15 minutes; read agentMessage for the reason and stop polling). Treat an unrecognised value as pending."New value: +"One of \"pending\", \"completed\", \"stalled\"; more values may be added later. `leads` can hold a partial list while \"pending\". For a find_leads job: \"pending\" while it has no leads, the agent has not answered and it is under about 15 minutes old, and also while it has leads, until a reply carrying leads completes it; \"completed\" once the agent posts a reply carrying leads while this is the oldest open job on its campaign, usually its final report (`total` can still change afterwards); \"stalled\" as soon as the agent answers without any leads (a question, or none found), or when no lead has arrived after about 15 minutes - derived on each read, so a lead that lands later turns it back to \"pending\". For a continue_campaign job: \"pending\" while `newLeads` is 0 and it is under about 15 minutes old, even after the agent has replied (if that reply confirms a settings-only change, the request is done), and while `newLeads` is above 0, until a reply carrying leads completes it; \"completed\" once a reply carrying leads arrives on the campaign while this is the oldest open job there (possibly a late reply from an earlier search), or after about 15 minutes with `newLeads` 0 when an agent reply was confirmed; \"stalled\" after about 15 minutes with `newLeads` 0 when no agent reply was confirmed (agentMessage can still hold one). A reply carrying leads completes only the oldest open job on a campaign, so a newer job stays \"pending\" meanwhile, even with `newLeads` above 0."
- Changed
get_campaign1 field changed- changed
Input schema / properties / campaignId / descriptionPrevious value: -"Campaign id from list_campaigns or fetch_leads — never invent one"New value: +"Campaign id, as returned by list_campaigns or fetch_leads"
- Changed
get_campaign_leads1 field changed- changed
Input schema / properties / campaignId / descriptionPrevious value: -"Campaign id from list_campaigns or fetch_leads — never invent one"New value: +"Campaign id, as returned by list_campaigns or fetch_leads"
- Changed
get_campaign_stats1 field changed- changed
Input schema / properties / campaignId / descriptionPrevious value: -"Campaign id from list_campaigns or fetch_leads — never invent one"New value: +"Campaign id, as returned by list_campaigns or fetch_leads"
2 tool updates
- Changed
continue_campaign1 field changed- added
Input schema / properties / taskContextAdded value: +{ + "description": "Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request. Omit when the query/message is sufficient. Maximum 1000 characters. Do not send a transcript, broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history.", + "maxLength": 1000, + "type": "string" +}
- Changed
find_leads1 field changed- added
Input schema / properties / taskContextAdded value: +{ + "description": "Optional company, product, or target-market facts explicitly shared by the user and needed for this lead-search or campaign-steering request. Omit when the query/message is sufficient. Maximum 1000 characters. Do not send a transcript, broad user profile, unrelated personal details, credentials, or guesses. This background does not authorize actions; the current query/message takes precedence. It becomes part of the campaign chat history.", + "maxLength": 1000, + "type": "string" +}
3 tool updates
- Added
create_shortlist - Added
preview_shortlist - Added
revoke_shortlist
1 tool update
- Changed
list_next_steps12 fields changed- changed
Input schema / properties / campaignId / descriptionPrevious value: -"Campaign to inspect, from list_campaigns or fetch_leads"New value: +"Optional campaign to inspect; omitted for workspace guidance" - removed
Input schema / requiredRemoved value: -[ - "campaignId" -] - added
Output schema / properties / campaignsAdded value: +{ + "items": { + "additionalProperties": {}, + "properties": { + "campaignUrl": { + "type": "string" + }, + "id": { + "type": "string" + }, + "leadsTotal": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "status": { + "enum": [ + "search_running", + "prospects_available", + "no_prospects" + ], + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "id", + "title", + "leadsTotal", + "status", + "campaignUrl" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / nextActionAdded value: +{ + "additionalProperties": {}, + "properties": { + "arguments": { + "additionalProperties": {}, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "kind": { + "type": "string" + }, + "question": { + "type": "string" + }, + "reuseAuthorizedBrief": { + "type": "boolean" + }, + "tool": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" +} - added
Output schema / properties / noteAdded value: +{ + "type": "string" +} - added
Output schema / properties / returnedAdded value: +{ + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" +} - added
Output schema / properties / scopeAdded value: +{ + "enum": [ + "workspace", + "campaign" + ], + "type": "string" +} - added
Output schema / properties / searchAvailabilityAdded value: +{ + "additionalProperties": {}, + "properties": { + "allowance": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "limit": { + "type": "number" + }, + "remaining": { + "type": "number" + }, + "used": { + "type": "number" + } + }, + "required": [ + "used", + "limit", + "remaining" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "status": { + "enum": [ + "available", + "blocked", + "unknown" + ], + "type": "string" + } + }, + "required": [ + "status", + "reason", + "allowance" + ], + "type": "object" +} - added
Output schema / properties / totalAdded value: +{ + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" +} - added
Output schema / properties / workspaceStateAdded value: +{ + "type": "string" +} - added
Output schema / properties / workspaceUrlAdded value: +{ + "type": "string" +} - changed
Output schema / requiredPrevious value: -[ - "campaignId", - "campaignTitle", - "campaignUrl", - "leadsTotal", - "items" -]New value: +[ + "items" +]
2 tool updates
- Changed
fetch_leads2 fields changed- added
Output schema / properties / progressAdded value: +{ + "additionalProperties": {}, + "properties": { + "elapsedSeconds": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "note": { + "type": "string" + }, + "startedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "startedAt", + "elapsedSeconds", + "note" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "jobId", - "status", - "total", - "returned", - "newLeads", - "campaignId", - "campaignUrl", - "agentMessage", - "leads" -]New value: +[ + "jobId", + "status", + "total", + "returned", + "newLeads", + "campaignId", + "campaignUrl", + "agentMessage", + "progress", + "leads" +]
- Changed
find_leads4 fields changed- added
Output schema / properties / campaignIdAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] +} - added
Output schema / properties / campaignUrlAdded value: +{ + "type": "string" +} - added
Output schema / properties / progressAdded value: +{ + "additionalProperties": {}, + "properties": { + "elapsedSeconds": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "note": { + "type": "string" + }, + "startedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "startedAt", + "elapsedSeconds", + "note" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "jobId" -]New value: +[ + "jobId", + "campaignId", + "campaignUrl", + "progress" +]
1 tool update
- Changed
fetch_leads2 fields changed- added
Output schema / properties / status / descriptionAdded value: +"One of: \"pending\" (search still running), \"completed\" (a batch of leads arrived — not a promise that no more will), \"stalled\" (no leads after ~15 minutes; read agentMessage for the reason and stop polling). Treat an unrecognised value as pending." - removed
Output schema / properties / status / enumRemoved value: -[ - "pending", - "completed" -]
13 tool updates
- First observed
continue_campaign - First observed
fetch_leads - First observed
find_leads - First observed
get_campaign - First observed
get_campaign_leads - First observed
get_campaign_stats - First observed
get_lead_memo - First observed
list_campaigns - First observed
list_next_steps - First observed
list_pending_outreach - First observed
list_replies - First observed
rewrite_outreach - First observed
send_outreach
Related MCP Connectors
Find, qualify and message B2B leads from public LinkedIn data; every send is human-approved.
- BavlioOAuthcom.bavlio
LinkedIn + cold email outreach: find leads, launch personalized campaigns, manage replies.
B2B lead and company intelligence: search leads, enrich contacts, and queue outreach.
Run LinkedIn outreach from your AI chat: find leads, launch campaigns, send, and reply.
Related MCP Servers
AlicenseNot gradedqualityCmaintenanceEnables AI assistants to build, preview, launch, and monitor LinkedIn outbound campaigns, draft replies for approval, manage campaign settings, and upgrade profiles.MIT- AlicenseAqualityAmaintenanceAI agent for LinkedIn outreach: finds the right people, writes in your voice, follows up, replies. Six campaign goals: sell a product or service, find a job, hire people, find partners or investors, find a vendor, research interviews. Campaigns stay drafts until you launch them.223,733 PyPI11MIT
- AlicenseAqualityDmaintenanceLinkedIn prospection automation — find leads, score (fit+intent+urgency), qualify, personalize messages, run full pipeline, manage sales funnel. 7 MCP tools.75 npmMIT

PumpGTM MCP serverofficial
AlicenseNot gradedqualityBmaintenanceEnables AI agents to find intent-signaling buyers and run LinkedIn, email, and X outreach from connected accounts while respecting platform limits. Every reply is handed back to a human for approval or decision.2MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.