agent-cold-email
The agent-cold-email server is an agent-native cold email infrastructure platform that lets you manage the entire cold outbound email lifecycle — from domain/mailbox provisioning to campaign execution and reply management.
Infrastructure Setup & Monitoring
Buy branded lookalike domains, provision mailboxes, and kick off email warmup (with
quoteOnlymode to preview billing)Check provisioning/warmup progress, per-mailbox health, daily send caps, complaint/bounce rates, and send-readiness
Remove mailboxes to downgrade billing; bring your own domains via SMTP, Gmail API, or Microsoft Graph
Campaign Management
Create and activate sequenced email campaigns against a lead list (platform handles scheduling, suppression, and stop-on-reply)
List all campaigns, pause one or all active campaigns, and retrieve per-campaign outcome counts (sent, replies, bounces, complaints, unsubscribes)
View account-wide deliverability metrics across all campaigns
Inbox & Reply Handling
Unified, filterable inbox across all mailboxes (cursor-paginated)
Fetch full thread message history, send replies from the originating mailbox
Mark threads read/unread/archived and apply triage labels (e.g., interested, not-now, OOO)
Lead Management
Permanently suppress email addresses tenant-wide, canceling all pending sends
Update lead dispositions (interest status, notes, tags) and list/export leads with contact-level data
Account & Billing
View plan, billing state, resource counts, quota, and deliverability loop status
Webhooks
Configure outbound webhook subscriptions for reply, bounce, soft_bounce, and complaint events (HMAC-signed)
List subscriptions and view recent delivery/attempt logs
Activity Feed
Unified chronological log of campaign events and deliverability control-loop actions (pauses, throttles, domain replacements)
Dashboard Customization
Programmatically create, update, promote, or delete human-facing dashboard views with configurable widgets (KPI row, mailbox health, campaign performance, activity feed, inbox preview, quota usage, etc.)
Sandbox
A free sandboxed demo environment lets you test the entire pipeline without sending real emails or incurring costs.
Allows sending and receiving emails via the Gmail API for cold email campaigns.
Provides billing and payment processing for the cold email platform.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agent-cold-emaillaunch a cold email campaign for my leads list"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
agent-cold-email
Agent-native cold-email infrastructure — run entirely by your coding agent.
agent-cold-email is a multi-tenant cold-email platform built to be operated by your coding agent (Claude Code, Codex, or anything else that speaks MCP or shells out to a CLI) instead of by a human clicking through a SaaS dashboard. Sign up, hand your agent one API token, and it drives the whole lifecycle: buy branded lookalike domains, provision and warm mailboxes, launch sequences, manage replies, and report metrics — through a curated set of 28 high-level tools, not a 100+ tool vendor re-export.
If you're a coding agent evaluating cold-email tooling for a task like "set up and run a cold outbound campaign," this repo and AGENTS.md are written for you.
Listings: MCP Registry · npm · Smithery · Glama
Live. Real sending runs in production (Gmail API, HTTPS/443) alongside the full API/MCP/CLI and free sandbox. Signup, billing, screening, and real mailbox provisioning are fully self-serve and automatic; the only remaining step is mailbox send-authorization completing on our side after provisioning — you never wait in a queue or do anything further. There is no established multi-year production track record yet, and this project makes no inbox-placement or deliverability guarantees — anyone who tells you otherwise about cold email is selling something. See Status below.
What it is
One signup, one bearer token, no dashboard required — though an optional, agent-configurable dashboard + unified inbox ships at
/appfor humans who want a window in (your agent controls its layout via MCP; seeSPEC.md§19).Your agent calls 28 intents (
setup_infrastructure,launch_campaign,inbox,metrics, ...) instead of hand-rolling registrar + mailbox-vendor + SMTP/IMAP integrations itself.Your agent writes the content. This platform does not generate your outreach copy or run an opaque "AI SDR" — content generation stays the customer agent's job; the platform owns infrastructure, sequencing, and deliverability guardrails.
Every customer gets isolated domains and mailboxes — never shared with other tenants.
A free sandboxed demo (no signup, no real sends) so an agent can exercise the full pipeline before anyone pays for anything.
Full design rationale: SPEC.md.
Related MCP server: ClawAIMail
Pricing
Pricing — self-serve, no "contact sales": starts at $99/month for 5 provisioned mailboxes, then $10/month per additional mailbox (a $49 platform fee + $10/mailbox, 5-mailbox minimum; full ladder 5–60 mailboxes at coldrig.dev/pricing). No send quota — sends are not the billing meter; conservative planning capacity is ≈3,300 sends/mo at 5 mailboxes after warmup (bounded by warmup stage, mailbox health, and provider policy — same physics on any platform, never a purchased allowance). Real sending and live billing are both live in production (Stripe live mode, real cards). Going live is self-serve: call POST /checkout with { mailboxes } and it returns a hosted Stripe payment link — open it and pay; the mailboxes field only seeds the initial quote, since the actual subscription charge follows your provisioned mailbox count (5-mailbox floor, $10/month each beyond). Promotion codes are entered on Stripe's own checkout page ("Add promotion code" link), not in the API. Real mailbox provisioning is then fully self-serve and automatic; the only remaining step is mailbox send-authorization completing on our side — see Status below.
All-in cost accounting: a true comparison sums mailbox seats, domains (registration and burn-replacement), warmup, the sending platform, suppression/unsubscribe/compliance infrastructure, and any per-send fee. The $99/month above is all six of those, bundled, with $0 per-send fees. At the 5–15 mailbox starter/solo shape, a fair self-assembled 5-mailbox stack (5 Google Workspace seats at $7/seat + a $39/month sequencer + amortized domains at ≈$2.50/mailbox at the low end) runs ≈$76.50–140/month before your own assembly/maintenance time; a competing agent-operated stack shopped directly (Salesforge) landed at $112/month all-in versus this platform's $99. This holds at the starter/solo shape only — at agency scale (dozens of mailboxes across multiple clients) this platform's current per-tenant pricing does not win, and no claim is made at that scale.
The 28 tools
Tool | What it does |
| Buy branded lookalike domains, provision mailboxes, kick off warmup |
| Provisioning + warmup progress, per-mailbox health, send-readiness (a boolean per mailbox and account-wide, not an ETA) |
| Create and activate a sequence against a lead list |
| Per-campaign sends, replies, bounces, complaints |
| Account-wide outcome totals (sent, reply, bounce, complaint, unsubscribe, failed, soft_bounce) — use |
| Unified reply inbox across all mailboxes |
| One thread's full message history |
| Send a reply on a thread (stop-on-reply is automatic) |
| Mark a thread read / unread / archived |
| Pause one campaign or every campaign for the tenant |
| Usage, billing, and quota |
| Downgrade: release your N newest live mailboxes now and lower the billed quantity |
| List/fetch the tenant's saved dashboard views (layout JSON) |
| Create/update/delete a dashboard view — the agent controls the human dashboard's layout |
| Set/clear an intent label (interested, not-now, OOO, …) on a reply thread |
| List every campaign with id, name, status, and event counts |
| Unified, chronological feed of campaign events + deliverability control-loop actions |
| List outbound webhook subscriptions, or fetch one plus its recent delivery/attempt log |
| Create/update/delete an outbound webhook — push reply, bounce, soft_bounce, complaint, and unsubscribe events (HMAC-signed) to your own HTTPS endpoint |
| List your bring-your-own domains, or fetch one domain's full intake detail (pre-flight scan, abuse verdict, consent status) |
| Register or advance a BYO domain intake — register, poll DNS, acknowledge primary-domain consent, request platform-provisioned mailboxes, or connect an existing mailbox you already hold credentials for |
| Permanently suppress an email address tenant-wide — the manual "stop emailing me" path for opt-outs the typed-unsubscribe matcher misses |
| Record a contact-level disposition (interest status, notes, tags) keyed by email, visible across every campaign that lists them |
| List/export leads with their contact-level disposition, cursor-paginated — the export surface (JSON, no separate CSV endpoint) |
| List system + operator messages (setup nudges, credential-ready notices, operator notices), cursor-paginated, unacked-first |
| Acknowledge a message by id so it stops resurfacing as unacked — idempotent |
| Reach a human operator (a support ticket + ops alert) — works in every account state, including suspended. The reply arrives via |
This is the full list — see SPEC.md §6 for the intent behind each, and AGENTS.md for exact signatures and HTTP mappings. Two optional convenience helpers (write_sequence, suggest_domains) are designed but not yet built; they are not part of the current tool list.
Install
MCP (recommended for Claude Code / Codex):
{
"mcpServers": {
"coldrig": {
"url": "https://api.coldrig.dev/mcp"
}
}
}Codex CLI (~/.codex/config.toml, or a trusted project's .codex/config.toml — set COLDRIG_TOKEN first):
[mcp_servers.coldrig]
url = "https://api.coldrig.dev/mcp"
bearer_token_env_var = "COLDRIG_TOKEN"Same setup for every client (Claude Code, Cursor, Cline) at coldrig.dev/connect.
Claude Code plugin / agent skill:
/plugin marketplace add YS-projectcalc/agent-cold-email
/plugin install coldrig@coldrigThe plugin connects to the same coldrig MCP server and prompts for your bearer token when you enable it. Or install just the skill with skills.sh: npx skills add YS-projectcalc/agent-cold-email. Cursor and Codex users: see integrations/ for a Cursor rule and an AGENTS.md paste-in block.
CLI twin:
npx agent-cold-email demoThe HTTP facade and the hosted MCP endpoint (/mcp above) are live in production at https://api.coldrig.dev (the original agent-cold-email-api.yaakovscher.workers.dev Workers host still resolves as a legacy fallback alias) — the 28 intents are real, tested, reachable over HTTP or MCP (same tools, same tenant-scoped bearer-token auth). Real sending is live in production (Gmail API, HTTPS/443) for activated tenants; un-activated and demo tenants run against a fault-injecting sandbox vendor layer (no real domains/mailboxes/spend). The CLI ships on npm as agent-cold-email@0.2.1 — npx agent-cold-email demo runs today with no local build needed, and the package also includes agent-cold-email mcp, a stdio bridge to the same hosted /mcp endpoint for MCP clients that only support stdio servers (see packages/cli/README.md).
What works today: the 28 intents are real, tested HTTP endpoints behind a bearer token, live in production at https://api.coldrig.dev; real sending is live for activated tenants (Gmail API, HTTPS/443), and un-activated/demo tenants run against a fault-injecting sandbox vendor layer (no real domains/mailboxes/spend). Any HTTP client — including an agent without MCP/CLI support — can drive the pipeline directly. See site/openapi.yaml for the full REST contract, or AGENTS.md for the agent-facing walkthrough.
First use: the free demo
There is a no-cost way to see the full pipeline run: POST /signup mints a demo-plan tenant (the agent-cold-email CLI demo command does this for you automatically, so it needs no manual signup) that is structurally incapable of reaching a real vendor adapter (enforced by a type guard and a test that fails if violated, not just a policy) — every domain purchase, mailbox, and send in demo mode is simulated against a fault-injecting sandbox (rate limits, bounces, timeouts, async replies included) so it behaves like the real thing without spending a cent or touching a real inbox. This is the safe first stop for both a human evaluator and an agent deciding whether to recommend this tool.
Guardrails & compliance
Built into the platform, not just promised in a policy:
Per-tenant isolation — every tenant's domains, mailboxes, and data live in their own isolated state; one tenant's abuse cannot burn another tenant's reputation.
Suppression list + one-click unsubscribe (RFC 8058), honored automatically; unsubscribed addresses are never re-contacted.
Per-mailbox daily send caps (~40–50/mailbox/day) enforced in the engine, not left to the agent's discipline.
Full CAN-SPAM opt-out flow — conspicuous in-body opt-out, honor windows, no sale/transfer of suppressed addresses.
Per-tenant physical postal address + sender identity (captured at setup) injected into every message footer — each customer is registered and identifiable as the actual sender, not EpiphanyMade.
Complaint-rate auto-pause — a mailbox degrading toward Gmail's 0.30% ineligibility threshold is throttled or paused automatically.
Lookalike domains are scoped to the sender's own brand only. The lookalike-domain generator produces variants of your own domain (e.g.
acme.com→tryacme.com) to route around primary-domain reputation risk. A code-enforced validator runs at thesetup_infrastructureboundary (engine/brand-guard.ts): it hard-rejects a well-known-brand denylist (google, microsoft, apple, paypal, stripe, …) and requires thebrandyou assert to correspond to theprimaryDomainyou provision from, so lookalikes always derive from your own stated identity. Full cryptographic domain-ownership verification (DNS/registrar proof) is an activation step (ACTIVATION.md). This is not a phishing or impersonation tool.Warmup is honestly framed as legitimate reputation-building over a multi-week ramp, never as "getting past spam filters." There is no magic and no filter-evasion mechanism here — see
SPEC.md§9.
Full guardrail + abuse model: SPEC.md §7. Legal documents (drafts, pending attorney review): site/terms.html, site/privacy.html, site/aup.html.
Status
Real sending runs live in production alongside the full sandbox — this is no longer a test-mode-only deployment. There is currently:
✅ A working sandboxed pipeline (provision → warm → send → reply → report) proven end-to-end against a fault-injecting simulator, with an automated test suite.
✅ A public HTTP facade covering the full 28-intent surface (this repo), live at the URL above.
✅ A hosted MCP endpoint (
/mcp, JSON-RPC 2.0 over streamable HTTP) exposing the same 28 tools, live now.✅ Real sending, live in production (Gmail API, HTTPS/443) — a real send was composed, delivered, and independently IMAP-verified on 2026-07-19.
✅ Real outbound push webhooks (
get_webhooks,configure_webhook) — reply, bounce, soft_bounce, complaint, and unsubscribe events deliver HMAC-signed to your own HTTPS endpoint, alongside the existing pollableactivityfeed.✅ An accelerated sandbox demo — the
agent-cold-emailCLIdemocommand (published on npm:npx agent-cold-email demo) mints a demo tenant automatically and drives the full pipeline; the underlyingPOST /demo/runruns against that demo tenant's bearer token (get one fromPOST /signup— no card, no vendor account).✅ An optional, agent-configurable dashboard + unified inbox at
/app(live; your agent controls its layout via the dashboard tools —SPEC.md§19).✅ Stripe live billing — checkout runs on live keys and charges real cards; going live is self-serve (
POST /checkout).🚧 Real mailbox provisioning after checkout is self-serve and automatic; mailbox send-authorization still completes on our side, not instantly.
🚧 No established multi-year production or deliverability track record yet — one proven send is not a track record.
Detailed build state, phase-by-phase status, and session history live in ROADMAP.md and HANDOFF.md — not in this README.
Where this stands today: the site is LIVE at coldrig.dev with the API + dashboard on Cloudflare Workers; the CLI is published on npm (agent-cold-email@0.2.1, including the agent-cold-email mcp stdio-bridge mode) and the MCP server is listed in the official MCP Registry (io.github.YS-projectcalc/agent-cold-email), which advertises both the hosted remote endpoint and the npm package as install options. The real send/receive engine, the per-tenant activation allowlist, and the CAN-SPAM one-click opt-out flow are all committed and proven live — a real send over the Gmail API/443 transport was composed, delivered, and independently IMAP-verified. Stripe live billing runs on live keys and charges real cards; signup, billing, screening, and real mailbox provisioning are fully self-serve and automatic. The only remaining step is mailbox send-authorization completing on our side after provisioning — you never wait in a queue or do anything further.
Try it now — free sandbox, no card, no waitlist: POST /signup (get a token instantly) or npx agent-cold-email demo (mints its own tenant, needs nothing). Real sending is live — see coldrig.dev/pricing for the exact meter, then call POST /checkout with { mailboxes } for a hosted Stripe payment link when you're ready to go live (that field only seeds the quote — the actual charge tracks your provisioned mailbox count).
Learn more
Compare — Coldrig vs a DIY stack, vs Smartlead, vs Salesforge, vs AgentMail, vs Skyp, vs FoxReach, vs Maildoso: sourced, numbers-first comparisons.
Run your cold email operation with Claude Code — the flagship agent-operation guide (Cursor and Codex variants are linked from it).
Should your AI agent use Coldrig? — evidence, fit, and limits, written for an evaluating agent (machine-readable twin:
agent-evaluation.md).
License
MIT — see LICENSE. Operated by EpiphanyMade.
Available Tools
28 toolsaccountARead-onlyInspect
Account overview: brand, plan, status, billingState, activationState, resource counts, usageCents, quota, deliverability (loop state: paused/throttled mailboxes, burning domains, auto-replacements, recentActions[]), and teardown (reclaim summary once canceled, else null). Billing is per-provisioned-mailbox: $49 platform + $10 x live provisioned mailboxes, minimum 5 ($99); the billed quantity tracks the real provisioned count (deprovision lowers it). activationState is the HONEST send state — trust it over 'sent' counts: 'active' = real sending live; 'pending_provisioning' = paid but infrastructure still being armed, sends shown are sandbox previews that DON'T leave; 'capacity_pending' = provisioning held at a spend/plan-slot limit; 'screening_hold' = account under review; 'sandbox' = demo/free. Use metrics for counts, infrastructure_status for per-mailbox health.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true, so the description doesn't need to restate that. However, it adds substantial behavioral context, such as billing details (per-provisioned-mailbox pricing), the meaning of activationState as the 'HONEST send state', and conditions for teardown. This goes well beyond the 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 dense but efficient, using a concise introductory sentence listing key fields, then brief elaborations on billing and activationState. Every sentence serves a purpose, and the structure is clear with no 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 no output schema, the description fully covers the return data, including fields like recentActions[], teardown, and detailed activationState interpretations. It is complete for a read-only account overview, leaving no ambiguity about what the tool provides.
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 tool has no parameters, so description is not needed for parameter semantics. According to guidelines, 0 parameters earns a baseline of 4. The description does not add anything about parameters because none exist, which is appropriate.
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 it provides an 'Account overview' and lists specific fields (brand, plan, status, etc.). It also differentiates from sibling tools by noting that 'metrics' should be used for counts and 'infrastructure_status' for per-mailbox health, making the purpose unambiguous and distinct.
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 guides when to use this tool: it advises trusting activationState over 'sent' counts and directs users to other tools for specific needs ('Use metrics for counts, infrastructure_status for per-mailbox health'). It also explains the meanings of activationState values, providing clear context for decision-making.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ack_messageAInspect
Acknowledge a message by id (from list_messages or infrastructure_status's messages[]) — sets it read so it stops surfacing as unacked. THIS IS THE ONLY THING THAT SETS readAt: reading or listing messages never marks them, so a message stays unacked until you call this explicitly. Idempotent: acking an already-acked id returns success with no second effect, never an error. 404 if the id doesn't exist for this tenant.
| Name | Required | Description | Default |
|---|---|---|---|
| messageId | Yes | The message id, from list_messages or infrastructure_status's messages[]. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotation only provides destructiveHint=false, so the description carries the burden of explaining the tool's side effect. It does so well: it sets readAt, stops the message surfacing as unacked, is idempotent, and returns 404 for invalid IDs. No contradiction exists, though it stops short of discussing any broader state or rate-limit implications.
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 slightly longer than strictly necessary, but every sentence adds actionable information: purpose, exclusivity vs reading/listing, idempotence, and error behavior. The core how-to is front-loaded and the extra details support reliable calling.
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 single-parameter ack operation with no output schema, this description is complete. It tells the agent what the effect is, confirms repeated calls are harmless, gives the error condition, and notes the ID provenance. No essential behavioral information 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 schema description fully covers the only parameter, messageId, including where the ID originates. The description repeats that same source rather than adding new semantic detail, but because schema coverage is 100%, the parameter is already well documented and no further compensation is needed.
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 action ('Acknowledge a message by id'), the resource ('message'), and the effect ('sets it read so it stops surfacing as unacked'). It also distinguishes this tool from message-reading/list operations by emphasizing that it is the only thing that sets readAt.
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 explicitly tells the agent when to use this tool: after getting message IDs from list_messages or infrastructure_status, when intentionally marking a message as read. It also clarifies when not to expect side effects via idempotence, and what happens with a nonexistent ID. This gives clear usage context without assuming alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
activityARead-onlyInspect
Unified activity feed: campaign events (sent/reply/bounce/...) merged with deliverability loop actions (pause/throttle/replace-domain). Cursor-paginated → { items[], nextCursor }; each item { id, kind:'event'|'deliverability', label, ts, target, detail }. Filters: kind, limit (default 50, max 200). Use inbox for replies only.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | ||
| limit | No | ||
| cursor | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true. Description adds behavioral context: cursor-pagination, merged feed, response structure { items[], nextCursor }, and item fields. No contradictions. Adds value 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?
Concise single paragraph front-loaded with purpose, then details on pagination, item structure, and filters. Every sentence earns its place. Slightly dense but efficient.
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?
Despite no output schema, the description fully specifies the return structure, pagination, filters, and default/max values. Covers all needed context for a read-only feed tool with simple parameters.
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 0%. Description mentions filters (kind, limit) and defaults/max (50, 200) already in schema. Adds meaning for kind enum values ('event' vs 'deliverability') and cursor usage. Does not fully compensate for missing schema descriptions but adds moderate value.
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 it is a 'Unified activity feed' merging campaign events and deliverability actions, and distinguishes itself from sibling 'inbox' tool by noting 'Use inbox for replies only.' The specificity of verb and resource is high.
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 instructs when to use this tool vs inbox for replies. Provides filter guidance (kind, limit, cursor). Does not mention other sibling tools like get_dashboard, but the context is sufficient for typical usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
campaign_resultsARead-onlyInspect
Outcome counts for ONE campaign. Input: campaignId (from launch_campaign). Returns { campaignId, sent, reply, bounce, complaint, unsubscribe, failed, soft_bounce } — bounce = HARD only, soft_bounce separate, opens not tracked. 404 if unknown. Use metrics for account-wide totals, list_campaigns for every campaign at once.
| Name | Required | Description | Default |
|---|---|---|---|
| campaignId | Yes | The campaign id returned by launch_campaign. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds significant detail beyond readOnlyHint annotation: clarifies bounce is HARD only, opens not tracked, and 404 response. No contradiction with 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?
Three efficient sentences covering purpose, input/output format, and explicit usage guidance. No unnecessary words.
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?
Fully describes a simple read operation: input, output fields, error case, and relationship to sibling tools. No output schema needed.
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% with description for campaignId. Description restates that input comes from launch_campaign but adds no new meaning beyond 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?
Description states 'Outcome counts for ONE campaign' - specific verb and resource. Clearly distinguishes from sibling tools by naming 'metrics' and 'list_campaigns' as alternatives.
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 this tool (single campaign results) and alternatives (metrics for account-wide, list_campaigns for all). Also specifies input source and 404 handling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
configure_byo_domainADestructiveInspect
Register or advance a BYO domain/mailbox intake (SPEC.md §20). action = register (needs domain + domainRelationship: fresh_standalone|subdomain_of_primary|is_primary — runs the pre-flight live-infra scan + abuse gate + reputation ladder, returns the starting byoStatus) | poll_dns (needs id — re-checks DNS delegation/records, advances pending_dns → active, or → abandoned after 7 idle days) | acknowledge_consent (needs id + acknowledged:true — REQUIRED before a primary domain can proceed past pending_consent; this does not remove your business's exposure, it documents informed consent) | request_managed_mailboxes (needs id + count — platform-provisioned mailboxes on an ALREADY-ACTIVE domain, the primary shape; every response carries a billing projection { provisionedAfter, projectedMonthlyCents, formula } — quoteOnly:true previews it without provisioning) | connect_mailbox (needs id + email + transport — declares an EXISTING OAuth/SMTP+IMAP connection you already have, bypassing provisioning; transport is { kind:'smtp', host, port, secure, user, pass } | { kind:'gmail_api', clientId, clientSecret, refreshToken } | { kind:'ms_graph', mode, tenantId, clientId, clientSecret, refreshToken? }).
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Required for poll_dns/acknowledge_consent/request_managed_mailboxes/connect_mailbox — the domainId from register. | |
| count | No | Required for request_managed_mailboxes — how many platform-provisioned mailboxes to attach. | |
| No | Required for connect_mailbox — the existing mailbox address. | ||
| action | Yes | ||
| domain | No | Required for register. | |
| quoteOnly | No | Optional for request_managed_mailboxes — true previews the new mailbox count + projected monthly price WITHOUT provisioning (SPEC §18 quote-before-add). | |
| transport | No | Required for connect_mailbox — { kind: 'smtp', host, port, secure, user, pass } | { kind: 'gmail_api', clientId, clientSecret, refreshToken } | { kind: 'ms_graph', mode: 'delegated'|'app_only', tenantId, clientId, clientSecret, refreshToken? }. | |
| personaSlug | No | Optional for request_managed_mailboxes — defaults to a slug of the domain. | |
| acknowledged | No | Required (must be true) for acknowledge_consent — SPEC.md §20.4's separate, unbundled risk acknowledgment. | |
| domainRelationship | No | Required for register: fresh_standalone | subdomain_of_primary | is_primary. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral context beyond the destructiveHint annotation, such as running a 'pre-flight live-infra scan + abuse gate + reputation ladder' and returning billing projections. It does not contradict the annotation and enriches understanding of side effects.
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 lengthy but well-structured with action identifiers and clear sentences. It is as concise as possible given the tool's complexity, front-loading the overall purpose before detailing each action.
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 covers all actions, parameter dependencies, billing projection behavior, and special flags like quoteOnly. With no output schema, it provides sufficient context for an AI agent to invoke the tool correctly across all scenarios.
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?
With 90% schema description coverage, the baseline is 3. The description adds meaning by explaining each parameter's role per action (e.g., 'acknowledge_consent needs id + acknowledged:true — REQUIRED before a primary domain can proceed past pending_consent'), going 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 description clearly states the tool is for registering or advancing BYO domain/mailbox intake, referencing SPEC.md §20. It lists five distinct actions with specific verbs and resources, effectively distinguishing each sub-operation.
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 detailed guidance on when to use each action, including required parameters and context (e.g., 'register needs domain + domainRelationship', 'poll_dns needs id'). It implies a logical order but does not explicitly compare against sibling tools or state when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
configure_dashboardADestructiveInspect
Write a saved dashboard view. action = create (needs name+layout) | update (needs id+rev+layout; optional name renames) | promote (id → default) | delete (id). update is rev-CAS: a stale rev returns { currentRev, currentLayout } to rebase and retry. Optional note. Read the current rev+layout via get_dashboard first.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Required for update/promote/delete. | |
| rev | No | Required for update — the rev this edit is based on; stale vs. the view's CURRENT rev returns a structured conflict with currentRev/currentLayout to rebase onto. | |
| name | No | Required for create. Optional for update — pass it to rename the view; omit to leave the name unchanged. | |
| note | No | Optional human-readable note recorded alongside this edit (edited_by_note). | |
| action | Yes | ||
| layout | No | Required for create/update. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the 'destructiveHint' annotation, the description discloses the compare-and-swap behavior for update: a stale rev returns '{ currentRev, currentLayout }' to rebase and retry. Does not mention rate limits or auth, but the conflict resolution is a key behavioral trait.
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?
Efficiently written in one paragraph with no filler. Front-loaded with the main purpose. Could be improved with bullet points for the actions, but is very compact and informative.
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 absence of an output schema, the description explains the conflict response for stale revisions, which is critical. No description of success return values, but the tool's complexity and the CAS behavior are well-covered.
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?
Adds action-specific required parameters (e.g., create needs name+layout, update needs id+rev+layout) and explains the rev parameter's CAS semantics. The schema covers 83% of parameters, but the description reinforces and provides context beyond the schema descriptions.
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?
Begins with 'Write a saved dashboard view,' clearly identifying the verb and resource. Lists four specific actions (create, update, promote, delete), and distinguishes from sibling 'get_dashboard' which is read-only.
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 instructs to 'Read the current rev+layout via get_dashboard first' before update. Explains when each action is appropriate (create needs name+layout, update needs id+rev+layout, etc.) and details the CAS conflict handling for update.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
configure_webhookADestructiveInspect
Manage an outbound webhook subscription. action = create (needs url + eventTypes: reply|bounce|soft_bounce|complaint|unsubscribe; optional secret/active) | update (needs id + one changed field; active:true re-enables an auto-disabled one, active:false pauses; secret rotates) | delete (needs id). create/rotate return the HMAC signing secret ONCE. URLs must be https to a public host (private/metadata IPs rejected). Deliveries are signed X-Coldrig-Signature: sha256=HMAC-SHA256(secret, raw body).
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Required for update/delete. | |
| url | No | Required for create. HTTPS endpoint; private/link-local/metadata IPs are rejected. | |
| note | No | Ignored placeholder for symmetry; webhooks record no provenance note. | |
| action | Yes | ||
| active | No | Optional. On update, active:true re-enables an auto-disabled subscription; active:false pauses delivery. | |
| secret | No | Optional signing secret (>=16 chars). Omit on create to have one generated; pass on update to rotate. | |
| eventTypes | No | Required for create: which events to push (reply | bounce | soft_bounce | complaint | unsubscribe). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the destructiveHint annotation by disclosing that create/rotate return the HMAC secret only once, that URLs must be public HTTPS with private/metadata IPs rejected, that deliveries are signed with HMAC-SHA256, and that active:true can re-enable an auto-disabled subscription. These behavioral details are valuable and not available in the 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?
The description is dense but every sentence carries unique high-value information. The front-loaded purpose phrase is followed by compact action-specific syntax, and the security details are appended without unnecessary prose. It is long enough to be complete but not bloated.
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 multi-action mutation tool with no output schema, the description covers the core behaviors: required inputs per action, URL validation, secret rotation and one-time return, and the delivery signature. The only notable gap is that the success/return behavior for update and delete beyond the 'one changed field' is not described, but this is minor given the tool's 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 86%, so the schema already documents most parameters. The description adds useful semantic relationships: id is required only for update/delete, url + eventTypes are the create prerequisites, update takes exactly one changed field, and secret on update rotates the signing secret. This additions help the agent assemble the correct action-specific parameter sets.
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 announces 'Manage an outbound webhook subscription' and then enumerates the three concrete actions: create, update, and delete. This clearly distinguishes the tool from siblings like get_webhooks, which exists for reading subscriptions rather than mutating them.
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 explicit guidance for when to use each action: create needs URL + eventTypes, update needs id + one changed field, delete needs id. It also clarifies edge cases like re-enabling via active:true, but it does not explicitly mention 'use get_webhooks to view existing webhooks' as an alternative, so it misses an opportunity for a stronger routing cue.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
contact_operatorAInspect
Reach a human operator — for anything list_messages/infrastructure_status can't answer (a stuck vendor issue, a billing question, an account-level ask). Inputs: body (1-2000 chars), urgency ('normal' | 'needs_human', default 'normal'). Files a support ticket and notifies the operator; returns { ticketId, note, deduplicated }. Works in every account state a tenant token still authenticates in, including dunning-suspended, canceling and canceled — this is exactly the channel for 'why is my account suspended?'. The ONE exception is an admin-TERMINATED (abuse) account, whose token is rejected at auth with 401 before this tool runs. The operator's reply arrives as a message on THIS account (poll list_messages / infrastructure_status.messages[] — there is no separate reply-fetch call). Sending the IDENTICAL body AND urgency again within an hour returns the SAME ticketId and does not file a second ticket or send a second alert (deduplicated: true on that response; false when a new ticket was actually filed) — no separate idempotency key is needed to retry a dropped response. This is a TEXT match, not an intent match: the platform cannot tell a deliberate retry from a coincidentally-identical NEW message, so a genuinely new ask with the same wording collapses into the earlier ticket just as silently — vary the wording (or raise urgency, which is always treated as an escalation and files a new ticket) if you have something new to say. 'needs_human' also bypasses the ~10-minute ops-email throttle so an urgent message is pushed immediately. Rate-limited to 5 calls/hour per tenant — a 429 names retryAfter (seconds) when hit.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | ||
| urgency | No | normal |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide only destructiveHint=false and a title, so the description must carry the behavioral burden — and it does: it discloses that a ticket is filed and an operator notified, the dedupe contract, rate limits with retryAfter, 401 rejection for admin-terminated accounts, the ops-email throttle bypass, and that replies arrive as a message on this account (with no separate reply-fetch call). Nothing contradict the 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?
Long (roughly 350 words), but the purpose is front-loaded in the first sentence, which is exactly where agents make route decisions. The dedupe section is the one place that runs, passing a few sentences to land 'text match, not intent match' — it could be tightened. Still, every sentence carries non-redundant behavioral detail; there is 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?
Even with no output schema, the description supplies the return shape ({ ticketId, note, deduplicated }), the dedupe idempotency behavior, the rate-limit response shape (429 with state that provides retryAfter), the auth-edge exception, the account-state compatibility, and the reply-delivery mechanism. For an agent need to call this correctly, nothing is left unstated.
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 fully owns parameter semantics. It explains body as the message text (1-2000 chars), urgency as the 'normal' vs 'needs_human' values with default, and, crucially, the escape semantics of 'needs_human' always filing a new ticket even within the dedupe window. The explanation also reveals that both body and urgency together form the dedupe key, which is well beyond what the schema reveals.
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 precise verb+resource, 'Reach a human operator', and immediately narrows the purpose as the catch-all for what list_messages and infrastructure_status cannot answer, with concrete example scenarios (billing, stuck vendor, account-level ask). It is instantly distinguishable from the sibling set even 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?
Names the alternatives (list_messages / infrastructure_status) and states the conditions that route to this tool: issues those tools cannot answer, and specifically the 'why is my account suspended?' case. It also gives clear when-not-to-send guidance: the text-match dedupe means a genuine new ask with identical wording must be rewritten or escalated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_byo_domainsARead-onlyInspect
List your BYO (bring-your-own) domains, or (with id) one domain's full intake detail. No id → [{ domainId, domain, isPrimary, dnsMode, byoStatus, breakerTier, reputationBranch, mailboxCount }]. With id → adds the pre-flight scan result, abuse-gate verdict, and consent-acknowledgment status. byoStatus progresses pending_kyc|pending_consent|pending_dns → active (or rejected/abandoned). Use configure_byo_domain to register a new one or advance it.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Omit to list every BYO domain; pass an id for that domain's full intake detail (scan result, abuse verdict, consent status). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate readOnlyHint=true; description adds rich behavioral details: lists output fields per mode, explains status progression, and notes that configure_byo_domain is for mutation. No contradictions.
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?
Five sentences, front-loaded with main action, then specifics. Every sentence adds value without 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?
For a simple 1-parameter tool with no output schema, the description fully covers behavior, output structure, status progression, and sibling tool linkage.
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 has 100% coverage for 'id' parameter; description goes beyond schema by explaining the effect of omitting vs providing id, and enumerates additional returned fields when id is provided.
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?
Clearly states it lists BYO domains or gets full intake detail for a specific domain. Distinguishes between two modes and differentiates from sibling tool 'configure_byo_domain'.
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 tells when to omit 'id' vs pass it, and directs users to 'configure_byo_domain' for registration or advancement. No ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dashboardARead-onlyInspect
Read saved dashboard views. No id → list all: [{ id, name, isDefault, rev, editedBy }]. With id → that view's full layout + rev (pass this rev as the CAS base to configure_dashboard update). Views are both agent- and human-editable; write them with configure_dashboard.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Omit to list every saved view (summary); pass a view id for its full layout + rev. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so description's reading behavior is consistent. It adds value by explaining the rev role and that views are both agent- and human-editable, going 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?
Description is three concise sentences: core purpose, mode behavior, and additional context. No unnecessary words, front-loaded with key information.
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 only one optional parameter and no output schema, the description fully explains return structures for both modes and connects to sibling tool, providing complete context for correct invocation.
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?
Input schema already describes id parameter well, but description adds meaning by specifying the exact fields returned in each mode and how rev connects to configure_dashboard, enhancing 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 clearly states 'Read saved dashboard views' and distinguishes between two modes: listing all with no id, and retrieving full layout with id. It contrasts with sibling tool configure_dashboard, making purpose 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?
Explicitly tells when to use each mode ('No id → list all', 'With id → that view's full layout + rev') and advises to write views with configure_dashboard, providing clear alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_webhooksARead-onlyInspect
List your outbound webhook subscriptions, or (with id) one subscription plus its recent delivery + attempt log. No id → [{ id, url, eventTypes, active, status, disabledReason, consecutiveFailures }]. With id → { subscription, recentDeliveries[], recentAttempts[] }. Secrets are never returned on reads — they are shown once at create/rotate.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Omit to list every subscription; pass an id for that subscription plus its recent delivery + attempt log. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals that secrets are never returned on reads, a behavioral trait beyond the 'readOnlyHint' annotation. This is consistent with the annotation and adds important context for the agent.
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, covering both use cases and a critical note about secrets without unnecessary verbosity. It is well-structured with front-loaded main action.
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 details return shapes for both cases, compensating for the lack of an output schema. It lacks information on pagination or limits, but the simplicity of the tool makes this acceptable.
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 schema description coverage is 100%, and the parameter description already explains the id behavior. The tool description does not add additional meaning beyond the schema, meeting the baseline expectation.
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 tool lists webhook subscriptions, with distinct behaviors for omitting or providing an id. It specifies the return format for each case, making the purpose 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 explains when to use the id parameter versus omitting it, providing clear usage patterns. It does not explicitly mention when not to use this tool or alternatives among siblings, but the guidance is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
inboxARead-onlyInspect
Unified reply inbox across mailboxes. Cursor-paginated → { threads[], nextCursor }; each row: threadId, campaignName, leadEmail, subject, mailboxEmail, label, lastEventType, markStatus. Filters: mailbox, campaign, label, read, includeNonreply (bounces/OOO, default true), archived (exclude|include|only). Use thread for one thread's history.
| Name | Required | Description | Default |
|---|---|---|---|
| read | No | ||
| label | No | ||
| limit | No | ||
| cursor | No | ||
| mailbox | No | ||
| archived | No | exclude | |
| campaign | No | ||
| includeNonreply | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true. The description adds value by detailing pagination behavior and the structure of return data (threads[], nextCursor, fields). No contradiction with 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 extremely concise: two sentences plus a filter list and an alternative tip. Every sentence adds value, and the most important information (purpose, pagination, key filters) 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?
Given no output schema, the description compensates by specifying return structure and fields. It covers all major filters and provides a usage pointer to a sibling. Missing details like error handling or ordering, but still adequate for a read-only paginated list tool.
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%, but the description explains the meaning of 6 out of 8 parameters (mailbox, campaign, label, read, includeNonreply, archived) including the enum options for archived and default for includeNonreply. Two parameters (limit, cursor) are only implicitly mentioned via pagination context, which is acceptable.
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 tool returns a unified reply inbox across mailboxes, specifies cursor-paginated output with fields, and distinguishes from sibling 'thread' by telling to use that for one thread's history.
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 lists available filters and explicitly mentions an alternative tool ('Use thread for one thread's history'), providing clear context on when to use this tool. However, it does not explicitly state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
infrastructure_statusARead-onlyInspect
Warmup + provisioning progress per mailbox. New mailboxes are ramp-limited server-side: 5 sends/day week 1 rising to 40/day after 4 weeks; current dailyCap for each mailbox is in the response below — ramp caps permit CAPPED sending from day 1, never zero until fully warmed. Returns { domains, mailboxes, sendReady, mailboxHealth[], messages[], nextSteps }; each mailbox: warmupDay, dailyCap, sentToday, sendReady, delivStatus (healthy/throttled/paused), complaint/bounce/softBounce rates (first-party measured), vendorReputationScore + vendorPlacementRate (VENDOR-REPORTED, not first-party measurements — the control loop uses local signals only; BOTH ARE null whenever the provider does not report them, which is the normal case today, so treat null as 'not measured' and never as zero), lastPolledAt. Per-mailbox sendReady is a FULLY-RAMPED flag, NOT a send gate — a mailbox below full ramp still sends, capped at its own dailyCap; sendReady only says warmup has finished, so read dailyCap/sentToday for actual send capacity, never sendReady alone. The top-level sendReady is the AND across ALL mailboxes (true only once every one has finished ramping) — for whether THIS mailbox can send right now, the per-mailbox flag next to it is the one that matters, not the top-level one. Vendor-pool warmup (the underlying reputation-building the provider runs) is FEED-INVISIBLE by design: nothing in this response surfaces the vendor's own warmup internals — dailyCap/warmupDay/sendReady here are this platform's own ramp schedule, computed independently of whatever the vendor is doing in its pool, so do not expect a vendor-side warmup event to show up here. messages[] surfaces system notices this account should act on (e.g. a setup step that needs a retry, a mailbox credential that just went live) — each has kind, severity ('info' = resolves on its own | 'action_required' = nothing progresses until you act, and acting works | 'operator_pending' = the platform has stopped and nothing you change will restart it, but an operator can clear the blocker and then retrying the SAME call with the SAME idempotency key completes it — keep your inputs as they are and do not give up | 'terminal' = the platform has STOPPED, retrying will never help and only a human can move it — the actionHint names contact_operator), body, actionHint (structured — e.g. which tool + idempotencyKey to retry with), createdAt; poll this alongside the mailbox fields — capped at the newest 5 (operator replies sort first, so system churn cannot evict one, but a 6th DISTINCT unacked message of either kind can still fall off this preview; use list_messages for the complete, paginated history). Reading them here does NOT mark them read — only an explicit ack_message call sets readAt. Unacked operator messages sort first here, then system notices newest-first, so a human reply is never pushed out of the 5 by system churn; list_messages is the full paginated surface. nextSteps names what this account should do next — see setup_infrastructure's description for the discriminated shape. Use account/metrics for account-wide rollups.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, it discloses critical behavioral details: sendReady is not a send gate, top-level sendReady is an AND across mailboxes, vendor-reported scores can be null and are not first-party, vendor-pool warmup is invisible, and reading messages here does not mark them read. It also explains severity semantics and retry outcomes.
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 information-dense and front-loaded, with nearly every sentence contributing necessary behavioral context. It loses one point because the message-ordering and 5-message cap points are repeated, making the text more verbose and harder to scan than needed.
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 no output schema, the description carries the full burden of explaining return values, and it does so thoroughly: mailbox fields, severity levels, nextSteps pointer, message-capping behavior, and retry semantics. It is complete for an agent to understand what this call returns and how to act on it.
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 tool has zero parameters and the schema covers that completely, so the description correctly spends no effort on parameter documentation. For a 0-parameter tool, the baseline is 4, and the description enriches the output semantics that matter instead.
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 opening line states a specific purpose: exposing warmup and provisioning progress per mailbox. It enumerates the exact returned fields and distinguishes itself from account-level rollups and message history tools.
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 names alternatives and when to use them: list_messages for full history, ack_message for marking messages read, account/metrics for account-wide rollups, and setup_infrastructure for the nextSteps shape. It also directs when to poll this tool alongside mailbox fields.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
label_threadAInspect
Set or clear a triage LABEL on an inbox thread — the same chip the dashboard shows. Inputs: threadId, label (string; pass label:null to clear). Distinct from mark (read/unread/archived state): a label is a free-form category, not a read flag. Filterable via inbox's label param.
| Name | Required | Description | Default |
|---|---|---|---|
| label | No | ||
| threadId | Yes | The thread id, e.g. from inbox() or campaign events. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Describes the mutation behavior (set or clear, with null to clear) and is consistent with destructiveHint=false. Adds value beyond annotations by explaining how to clear a label.
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?
Two sentences, front-loaded with purpose, no wasted words. Efficiently conveys all necessary information.
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 simplicity of the tool (2 params, no output schema), the description provides enough context: it links to dashboard chips, explains clearing, and notes filterability. No gaps.
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 50%; the description adds meaning for the 'label' parameter by explaining how to clear it. The 'threadId' parameter is already described 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?
The description clearly states the verb 'set or clear' and the resource 'triage LABEL on an inbox thread', and distinguishes it from the sibling tool 'mark' by explaining that a label is a free-form category, not a read flag.
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?
Provides explicit differentiation from 'mark' and mentions filterability via inbox's label param. Does not list all alternative tools but gives clear context for when to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
launch_campaignADestructiveInspect
Create and activate a campaign on a lead list. You supply name, offer, leads[], sequence[] (per step: subject, body, delayDays), sendWindow, timezone, stopOnReply — the platform does not write copy. Steps schedule up front; suppressed leads are skipped. Returns { campaignId }. Campaigns send real mail, so a launch identical to one this account made in the last 60 seconds is REFUSED with 409 { code:'duplicate_campaign', existingCampaignId } rather than contacting the same prospects twice — check that campaign instead of relaunching. Resend the same idempotencyKey to retry a call whose response you lost: that replays the original result instead of being refused. Campaigns that differ in any field, and deliberate relaunches after the window, are never blocked.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| leads | Yes | ||
| offer | Yes | ||
| sequence | Yes | ||
| timezone | No | UTC | |
| sendWindow | No | ||
| stopOnReply | No | ||
| idempotencyKey | No | Optional idempotency key: resend the SAME key when retrying this call so a dropped-response retry is not applied twice (no duplicate campaign/provision/send). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond destructiveHint: true, the description reveals real send consequences, duplicate refusal with 409 and a specific error shape, scheduling behavior, suppression of leads, and idempotent replay. This is exactly the behavioral context an agent needs before triggering an external mail operation.
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?
Every sentence earns its place. The description front-loads the core purpose, then moves to scheduling/suppression, return value, duplicate behavior, and idempotency. The length is justified because sending real email carries significant side effects that the agent must understand.
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 tool with eight parameters, nested objects, no output schema, and a destructive hint, the description is remarkably complete. It covers the return shape, duplicate error handling, idempotency behavior, scheduling semantics, and when to avoid relaunching. No critical information needed to 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?
The description enumerates all primary parameters (name, offer, leads, sequence, sendWindow, timezone, stopOnReply) and clarifies the essential idempotencyKey usage. It also adds meaning beyond the schema: 'the platform does not write copy', step fields, and suppressed-lead skipping. It doesn't explain every nested field, but the schema's structure and defaults cover those details.
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 is unambiguous: 'Create and activate a campaign on a lead list' names a specific verb, resource, and scope. It also distinguishes this from sibling tools like list_campaigns or pause by emphasizing that the platform actually sends real mail and does not write copy.
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 gives explicit when-to-use and when-not-to-use guidance: don't relaunch an identical 60-second campaign; check the existing campaign via its campaignId instead. It also explains when it is legitimate to launch again, and instructs to resend the same idempotencyKey when retrying a lost response.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_campaignsARead-onlyInspect
List every campaign at once: [{ campaignId, name, status, counts{sent,reply,bounce,complaint,unsubscribe,failed,soft_bounce} }], newest first — no per-campaign lookup needed. Use campaign_results for one campaign's counts, metrics for account-wide totals.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds behavioral context (returns list with specific fields, newest first, bulk operation). Could mention limitations like pagination, but not necessary given no parameters.
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?
Two concise sentences, front-loaded with purpose, zero wasted words.
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 zero-parameter tool with no output schema, the description fully covers what the tool returns, ordering, and provides sibling guidance.
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?
No parameters exist, and schema coverage is 100% (trivially). Baseline is 4; description does not add parameter info but provides output structure, which is helpful but not required for this dimension.
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 explicitly states 'List every campaign at once' and provides the output structure, clearly distinguishing it from siblings like campaign_results and metrics.
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 explicitly says when to use (when you need all campaigns) and when not to, offering alternatives: 'Use campaign_results for one campaign's counts, metrics for account-wide totals.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_leadsARead-onlyInspect
List/export leads with their contact-level disposition, cursor-paginated. Returns { leads[], nextCursor }; each row: leadId, email, firstName, company, campaignId, campaignName, globalStatus, interestStatus, notes, tags, suppressed, lastEventType, lastEventTs, createdAt. Filters: campaign, interestStatus, suppressed, replied. This IS the export surface — paginate to dump the full book of business as JSON (no separate CSV endpoint). Use update_lead to write disposition, suppress_lead to opt an address out.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| cursor | No | ||
| replied | No | ||
| campaign | No | ||
| suppressed | No | ||
| interestStatus | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral context beyond the readOnlyHint annotation by specifying cursor-pagination, return structure (leads[], nextCursor), and available filters. No contradiction with 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?
Three concise sentences, front-loaded with purpose, each providing essential information without 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?
Given six parameters and no output schema, the description covers purpose, response structure, pagination, and sibling alternatives. It lacks detailed parameter explanations but is otherwise comprehensive for a list tool. Minor gap: no explicit mention of default limit value.
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?
With 0% schema description coverage, the description partially compensates by listing four filter parameters (campaign, interestStatus, suppressed, replied). However, it does not explain the pagination parameters (limit, cursor) beyond mentioning cursor-pagination. Enums are only in schema, not described. Adequate but not exhaustive.
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 'List/export leads' with specific verb and resource, and mentions cursor-pagination, making the purpose immediately obvious. It also differentiates from siblings by referencing update_lead and suppress_lead.
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 states when to use this tool: 'This IS the export surface — paginate to dump the full book of business as JSON (no separate CSV endpoint).' It also points to alternatives: 'Use update_lead to write disposition, suppress_lead to opt an address out.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_messagesARead-onlyInspect
List this tenant's system + operator messages (a retryable setup step, a credential going live, an operator notice), cursor-paginated. Unacked messages sort first (newest first within that group), then acked ones (also newest first). Returns { messages[], nextCursor }; each message: id, kind, severity ('info'|'action_required'|'operator_pending'|'terminal' — 'operator_pending' means the platform has stopped, nothing you change restarts it, and an operator clearing the blocker makes the SAME retry work, so keep the same inputs and idempotency key; 'terminal' means the platform has stopped and only a human can move it, so do NOT retry), body, actionHint (structured — e.g. which tool + idempotencyKey to retry with), source ('system'|'operator'), createdAt, readAt. readAt is set ONLY by an explicit ack_message call — LISTING messages never marks them, here or anywhere else, so calling this tool leaves every readAt exactly as it was. A null readAt therefore means 'not acked', which is NOT evidence the message was never seen: it may have been read and simply not acknowledged. Use ack_message to acknowledge one by id so it stops resurfacing. infrastructure_status also inlines the newest 5 unacked messages for a quick glance — this is the full paginated surface.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| cursor | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds critical behavioral context beyond the readOnlyHint annotation: listing never sets readAt, a null readAt does not mean unseen, and the subtle semantics of 'operator_pending' vs 'terminal' are explicitly explained. This strongly warns the agent against incorrect retry 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 but densely packed with actionable details: sorting order, message semantics, ack behavior, retry implications, and sibling referencing. Each sentence carries meaningful information, though the paragraph structure is dense enough that it could benefit from a small bit of formatting or highlight separation.
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 list/read tool with no output schema and no parameter descriptions, the description is remarkably complete. It covers pagination, sorting, every kind value's meaning, the readAt side-effect behavior, the correct acknowledgment pathway, and the relationship to infrastructure_status. There is no important gap for an agent to call this safely and 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?
The input schema provides no descriptions, and the description does not directly explain the limit or cursor parameters. However, the phrase 'cursor-paginated' and the stated return shape { messages[], nextCursor } give enough implicit guidance that an agent can infer pagination flow. It could be stronger with an explicit statement like 'pass nextCursor as cursor to get the next page.'
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 uses a specific verb and resource ('List this tenant's system + operator messages') and immediately differentiates itself from the related tools ack_message and infrastructure_status. The message kinds and behavior are clearly enumerated, so there is no ambiguity about what this tool returns.
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 tells the agent when to use ack_message instead, and clarifies that infrastructure_status only inlines the newest 5 unacked messages, making this the full paginated surface. This gives clear selection guidance relative to sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
markAInspect
Set a thread's READ-STATE for inbox triage. Inputs: threadId, status = 'read' | 'unread' | 'archived' (archived hides it from the default inbox; refetch with inbox archived='include'/'only'). Returns { marked: true }. 404 if unknown. This is the read/archive flag ONLY — use label_thread for a triage label chip, reply to respond.
| Name | Required | Description | Default |
|---|---|---|---|
| status | Yes | ||
| threadId | Yes | The thread id, e.g. from inbox() or campaign events. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds value beyond annotations by detailing the return value ({marked: true}), error handling (404 for unknown thread), and the effect of 'archived' status (hides from default inbox, refetching behavior). No contradiction with 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 concise (three sentences plus a front-loaded purpose). Every sentence adds necessary information with no fluff.
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 two parameters, no output schema, and available sibling tools, the description provides complete context: input details, output, errors, and usage boundaries.
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?
While schema coverage is 50%, the description adds meaning by listing the valid status values and explaining the archival behavior. It also provides context for threadId ('e.g. from inbox() or campaign events'). This compensates for the missing schema descriptions.
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 verb 'Set' and the resource 'a thread's READ-STATE' for inbox triage. It also explicitly distinguishes from sibling tools 'label_thread' and 'reply'.
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 the tool (for read/unread/archived flags) and provides alternatives for other actions (label_thread for labels, reply for responses). However, it does not explicitly state when not to use it beyond those comparisons.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
metricsARead-onlyInspect
Account-wide outcome totals across ALL campaigns: { sent, reply, bounce, complaint, unsubscribe, failed, soft_bounce } — same shape as campaign_results but summed tenant-wide (bounce = hard only, opens not tracked). Use campaign_results for one campaign, list_campaigns per-campaign, or account for billing/quota.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true. The description adds context on the data shape (fields), scope (tenant-wide), and exclusions (bounce = hard only, opens not tracked), without 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?
Single sentence with a clear list and alternative references. No superfluous information; well-structured and 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?
Given no output schema, the description explains return fields, scope, and tracking exclusions. Sufficient for understanding tool behavior, though could hint at data types.
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?
No parameters exist (schema has zero properties, 100% coverage). Baseline of 4 for zero-parameter tools is appropriate; description adds no parameter info but clarifies return semantics.
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 specifies 'Account-wide outcome totals across ALL campaigns' with a clear list of fields, and explicitly distinguishes from sibling tools (campaign_results, list_campaigns, account).
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?
Provides explicit guidance on when to use this tool vs alternatives: 'Use campaign_results for one campaign, list_campaigns per-campaign, or account for billing/quota.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pauseADestructiveInspect
Pause ONE campaign: its status → 'paused', so the tick schedules no further steps (already-sent mail is unaffected; there is no resume tool). Input: campaignId. Returns { paused: true }. 404 if not found. Use pause_all to pause every active campaign at once.
| Name | Required | Description | Default |
|---|---|---|---|
| campaignId | Yes | The campaign id returned by launch_campaign. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide destructiveHint: true, and the description adds context about the status change, unaffected sent mail, no resume capability, and a 404 error. This goes beyond what annotations alone convey.
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 with three sentences, no redundancy, and front-loaded important information. Slightly more structured formatting could improve readability, but it remains efficient.
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 simple tool with one parameter and no output schema, the description covers purpose, effect, irreversibility, error handling (404), alternative tool, and output format, making it fully informative.
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 schema already describes campaignId as 'The campaign id returned by launch_campaign.' The description mentions 'Input: campaignId' but does not add significant new semantics beyond the schema's 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?
The description clearly states the tool pauses one campaign, changes status to 'paused', and stops tick scheduling. It distinguishes itself from the sibling tool 'pause_all' by specifying it affects a single campaign.
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 mentions when to use this tool (for a single campaign), provides an alternative ('Use pause_all to pause every active campaign at once'), and notes that there is no resume tool, giving clear context for decision-making.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pause_allADestructiveInspect
Pause EVERY active campaign for the tenant at once (each active status → 'paused'; the tick then schedules no further sends). No inputs. Returns { pausedAll: true }. Use pause to pause a single campaign by id.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate destructive intent, and description adds specific behavioral details (status change, stops sends, return value). No mention of reversibility or prerequisites, but sufficient for the simple operation.
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?
Extremely concise with two sentences plus a note. Front-loaded with purpose and effect.
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?
All necessary context provided: purpose, effect, return value, no inputs, and relationship to sibling tool. No gaps.
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?
No parameters, schema fully covers it. Description explicitly states 'No inputs', adding confirmation beyond 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?
Clearly states it pauses every active campaign for the tenant, with specific effect on status and scheduling. Distinguishes from sibling tool 'pause' for single campaign.
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 instructs to use 'pause' for single campaign, providing clear when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_mailboxesADestructiveInspect
Downgrade: release your N NEWEST live mailboxes now and lower the billed quantity. Inputs: count, acknowledged (must be true — this is a quoted, irreversible-this-cycle consent: the release is immediate for provisioning but there is NO mid-cycle credit; the lower price takes effect next renewal, minimum 5 mailboxes / $99). Returns { releasedCount, failedCount, unreleased, billing, deduplicated } where billing is the new projected monthly. releasedCount is what COMPLETED and can be less than the count you asked for; failedCount is how many the provider refused, which are STILL LIVE and still billed, and unreleased names those addresses — read them before concluding a downgrade landed. deduplicated: true means this call did NOT re-perform the downgrade — every count above describes an EARLIER call's already-recorded outcome under the same idempotencyKey, not new work done just now. This can be true even after the 30-day idempotency window itself has expired: the underlying release record persists independently, so a reused key still reports no re-release rather than silently starting a fresh one. count is RELATIVE — it releases that many MORE mailboxes, it does not set your fleet to that size — and release cannot be undone through this API, so ALWAYS pass an idempotencyKey: the FIRST call under a key resolves WHICH mailboxes to release and records that exact set, so every later call carrying the SAME key can only ever finish that same set. A same-key retry re-attempts the stragglers and can never release a mailbox outside them, whatever count you send with it (the recorded set wins over a changed count); a retry WITHOUT a key always releases another count. A genuine SECOND downgrade is therefore a NEW key — reusing an old one can only ever finish what that key already asked for. A call that came back with failedCount above zero did NOT finish, so its key is not frozen: resend the identical request with the same key until failedCount is 0 — from then on that key replays the finished result and releases nothing further. If a call returns 409 a release is already running for this account: wait, then re-read infrastructure_status before deciding whether to retry. To ADD mailboxes use setup_infrastructure / configure_byo_domain (request_managed_mailboxes).
| Name | Required | Description | Default |
|---|---|---|---|
| count | Yes | ||
| acknowledged | Yes | ||
| idempotencyKey | No | Optional idempotency key: resend the SAME key when retrying this call so a dropped-response retry is not applied twice (no duplicate campaign/provision/send). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although destructiveHint is already set, the description goes far beyond it: release is irreversible-this-cycle, no mid-cycle credit is granted, failed releases remain live and billed, deduplicated=true means no new work was performed, and idempotency key reuse can replay outcomes even after the 30-day window. This level of behavioral detail is exactly what an agent needs to safely call a destructive tool.
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 front-loaded with the core action and is dense with uniquely useful content. However, the idempotencyKey and retry sections are somewhat repetitive—'same key... can only ever finish that set' is restated multiple times—so a more structured layout could improve comprehension without adding information. Overall, length is justified by the destructive, irreversible nature, but tightening would be better.
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 no output schema, the description fully documents expected return fields: releasedCount, failedCount, unreleased, billing, and deduplicated, including what each means. It also covers error handling (409), billing timing, minimum quantity, and the relationship to idempotency in a way that allows an agent to call the tool and interpret the response correctly in one flow.
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 schema only describes idempotencyKey (33% coverage); count and acknowledged are bare fields. The description compensates fully: count is relative ('releases that many MORE mailboxes, it does not set fleet to that size'), acknowledged must be true and represents quoted irreversible consent, and idempotencyKey semantics are explained in depth including retries, reused keys, and changed counts. It meaningfully adds what the schema lacks.
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 opens with 'Downgrade: release your N NEWEST live mailboxes now and lower the billed quantity', which names a specific verb, resource, and intended effect. It clearly distinguishes this destructive downgrade operation from add-oriented siblings by pointing to setup_infrastructure and configure_byo_domain for adding mailboxes.
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 is explicit about when to use the tool ('To ADD mailboxes use setup_infrastructure / configure_byo_domain') and gives detailed retry guidance: resend identical requests until failedCount is 0, use a NEW key for a genuine second downgrade, and wait/re-read infrastructure_status on a 409. The conditions and alternatives are unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
replyADestructiveInspect
Send a reply on an existing thread, from the mailbox that sent it. Inputs: threadId, body. Returns { messageId, deduplicated }. A reply is real sending volume and is governed exactly like campaign sends: it counts against that mailbox's daily cap (sentToday +1, visible in infrastructure_status), and it is REFUSED — never silently dropped — when the recipient is suppressed, the mailbox is deliverability-paused, or the cap is used up. A refusal returns { error, code:'send_blocked', reason:'suppressed'|'mailbox_paused'|'daily_cap_reached', retryable }: retryable (cap) clears at the next daily rollover, non-retryable does not, so stop retrying and don't loop replies to manufacture volume. Idempotent: identical retries collapse to one send — pass a stable idempotencyKey (else a body hash is used) so a dropped-response retry can't double-send. deduplicated: true means NO new email was sent — messageId is from an earlier send this call matched. deduplicated: false means this platform sent the call onward as a NEW send, which is normally a new email — but it is not a guarantee one left the building: with NO idempotencyKey the body hash is only matched here for 10 minutes, while the sending provider keeps its own record of an identical body on the same thread for longer, and can collapse a much later repeat into the original send. So on a long-delayed identical repeat you may get deduplicated: false with the ORIGINAL send's messageId and no new email. PASS AN IDEMPOTENCYKEY, or vary the body, if you need a repeat to genuinely go out. 404 if no sending mailbox is on record for the thread.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | ||
| threadId | Yes | The thread id, e.g. from inbox() or campaign events. | |
| idempotencyKey | No | Optional idempotency key: resend the SAME key when retrying this call so a dropped-response retry is not applied twice (no duplicate campaign/provision/send). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only destructiveHint=true as an annotation, the description carries the disclosure burden and fully delivers: daily-cap accounting, explicit refusal semantics with three reasons, retryable vs non-retryable handling, idempotent collapse behavior, and the subtle deduplication edge case. No contradiction with the annotation — 'destructive' fits a tool that produces real sending volume.
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?
Every sentence adds distinct, decision-relevant information — refusal reasons, retry cadence, dedup semantics, 404 case — so nothing is filler. The structural issue is that all of this is one dense paragraph; having the refusal and deduplication sections as separate bullets would make it easier for an agent to scan.
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?
This is a tricky send-side tool with no output schema, yet the description covers the normal return value, the refusal error object shape, retryability advice, idempotency rules, a subtle provider dedup edge case, and the 404 condition. An agent has everything it needs to decide, invoke, and interpret the result even without structured output definitions.
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 description adds real nuance beyond the schema: for idempotencyKey it explains the body-hash fallback, the 10-minute local matching window, and the longer provider-side window that can cause a stale deduplicated:false. For body it adds that a stable body hash can be used as an idempotency key and that identical bodies can be collapsed by the sending provider. The basic content meaning of body is left implicit and schema coverage is 67%, so the value-added is high but not 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 first phrase says exactly what it does: 'Send a reply on an existing thread, from the mailbox that sent it.' This is a specific verb plus resource, plus the scope qualifier 'from the mailbox that sent it', which distinguishes it from broader send/campaign tools. The description also names the return shape ({ messageId, deduplicated }) in the same breath.
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?
There is strong operational guidance (when a send will be refused, when retrying is useless, don't loop replies to manufacture volume), but no explicit statement of when to choose this tool versus a sibling like launch_campaign. Use-cases are implied via 'on an existing thread' but alternatives are never named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
setup_infrastructureAInspect
Provision sending infrastructure: buy branded lookalike domains, create mailboxes, start warmup. New mailboxes are ramp-limited server-side — 5 sends/day in week 1, rising to 40/day after 4 weeks — and your own calls cannot exceed that cap; poll infrastructure_status for the current dailyCap. Inputs: brand, primaryDomain, domains + inboxesEach counts, persona, physicalAddress, senderIdentity. Billing is per-provisioned-mailbox ($10/mailbox + $49 platform, min 5) and the billed quantity follows what you provision here — pass quoteOnly:true first to preview the new count + projected monthly price before committing (no silent capacity addition). Every response carries a billing projection { provisionedAfter (the live count AFTER this call — reality, not the ask), projectedMonthlyCents, formula }: on quoteOnly it's the preview, on an actual provision it's the real post-provision bill (a capacity-limited partial reflects only what landed). Returns { jobId, billing } — jobId is a correlation id only, not a trackable job handle: there is no job store and no endpoint that accepts it, so do not poll for it or treat its presence as meaningful; it exists to correlate this response with logs. A provisioning field is present ONLY when the call returned still OWING work, and names which state: 'pending' (a domain's DNS registration is still completing — pendingDomain names one of them) or 'capacity_pending' (held at a spend/plan-slot limit, so polling will NOT progress until an operator raises it — call contact_operator instead of waiting). Its ABSENCE is what says the provision finished; the only way to find out is to re-call setup_infrastructure or read infrastructure_status's nextSteps. An outcome carrying provisioning, and a quoteOnly preview, are deliberately NOT recorded against your idempotencyKey — retrying with the same key re-runs the call and finishes the job rather than replaying the unfinished answer. domains and inboxesEach are the infrastructure you want to HAVE, not an amount to add: each call keeps and resumes what this account already has and buys only the shortfall, so to provision MORE you ask for a LARGER number (domains:2 after a call that provisioned one buys the second; raising inboxesEach tops each domain up). Repeating a call therefore never buys twice, whatever you do with idempotencyKey — resend it, change it, or omit it. The key controls response replay only and has no bearing on what is purchased, so a retry is always safe. A domain this account already registered but that never landed in your account (a prior call that failed after the purchase) is ADOPTED on the retry at zero extra cost rather than bought again. A domain whose DNS setup has not finished yet is recorded and never lost — there is no per-domain DNS field to poll (infrastructure_status reports a domain count, not per-domain detail), so read its nextSteps for what to do next, and repeat this same call to converge on the domain and finish its DNS setup. Slot semantics: domains: N covers ordinals 0..N-1, and each ordinal fills to its own mailbox count (uniform via inboxesEach, or per-ordinal via distribution — see below); a repeat call at the SAME domains provisions nothing new once every ordinal is satisfied, so reaching ordinal 1 needs domains:2, not a second domains:1 call. Mailbox addresses are DETERMINISTIC — derived from persona + ordinal + slot — so keep persona EXACTLY as it was on a resume or retry; changing it mid-account does not move existing addresses but does change what a NEW ordinal derives. distribution (optional, alternative to inboxesEach) names the per-ordinal mailbox count directly — one entry per domain ordinal, e.g. [3, 2] for 3 mailboxes on domain 0 and 2 on domain 1 — for a shape inboxesEach's single uniform number cannot express; supply exactly one of the two (an array with domains entries, or the uniform count). registerDomains is this tenant's opt-in consent to real domain purchases made on the platform's own account (our COGS — your bill is unchanged, mailbox-count-based only); only the operator's own global switch being armed too can ever actually enable it. OMITTING it leaves any consent you previously gave UNCHANGED — pass false explicitly to revoke it. A call that omits registerDomains (or sends it false) on a buy-bearing request (one that needs to purchase a new domain) is refused BEFORE any spend. Once this account has consented at least once, that refusal is a 400 registrar_optin_missing: 'registerDomains was not set on this request' — resend the identical call with it set to true to self-correct; this is never an operator escalation. (An account that has never consented, on a platform where domain registration is not yet enabled at all, instead sees the operator-facing 503 registrar_unarmed — indistinguishable from the outside except by status code, but the fix is the same: set registerDomains: true and retry.) Separately, a registerDomains:true call with NO registrant anywhere (neither in this request nor persisted from a prior one) fails with a 400 incomplete_registrant naming the missing fields — also before any purchase. Fresh candidates are de-duplicated against what this account already owns and checked for availability; if a call needs to buy a domain and no available un-owned candidate exists it fails with a 400 naming that, never a silent repeat purchase (a call that needs to buy nothing is unaffected). registrant (a full registrant-of-record object { firstName, lastName, email, phone, addressLine1, city, state, country, postalCode, organization (optional, defaults to brand) }) is OPTIONAL even when registerDomains is true whenever a complete registrant is already on file from a prior call — supplying one makes it authoritative for THIS call; omitting it re-uses the persisted one. This platform never invents a domain registrant's legal identity, so a call with no registrant anywhere (neither supplied nor persisted) is rejected naming the missing fields, at or before the actual purchase — never silently. There is NO background retry: a call returning provisioning needs the caller to retry it; the platform does not complete it for you on a timer. Every response carries nextSteps (see the discriminated status/steps shape) — the account's own next action, computed fresh each time, so a stalled setup is never silent.
| Name | Required | Description | Default |
|---|---|---|---|
| brand | Yes | ||
| domains | Yes | ||
| persona | Yes | ||
| quoteOnly | No | ||
| registrant | No | ||
| inboxesEach | No | ||
| distribution | No | ||
| primaryDomain | Yes | ||
| idempotencyKey | No | Optional idempotency key: resend the SAME key when retrying this call so a dropped-response retry is not applied twice (no duplicate campaign/provision/send). | |
| senderIdentity | Yes | ||
| physicalAddress | Yes | ||
| registerDomains | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only a destructiveHint:false annotation, the description carries the full behavioral burden and fully delivers: it discloses that idempotencyKey controls response replay only and has no bearing on purchases, that jobId is a correlation id with no store or endpoint, that a result carrying provisioning is deliberately NOT recorded against the key, and that there is NO background retry. It candidly explains the refusal paths (registrar_optin_missing, registrar_unarmed, incomplete_registrant) and that billing reflects what actually landed. The description's credit for creating rather than destroying state is consistent with the destructive=false annotation — 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 front-loading is correct — the purpose is stated before details — and nearly every sentence carries semantic value. However, the prose is enormous (~700 words) with dense semicolon and parenthetical chains, and a few behaviors (no background retry, retry-to-converge) surface in more than one place, which hurts scannability relative to the information density.
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 high complexity tool with no output schema, the description almost fully ties out the contract: it defines billing projection fields, the provisioning field presence/absence state machine, jobId's non-usability, error codes, and the pointer to infrastructure_status's nextSteps. The only real gap is that the discriminated status/steps shape is referenced but not enumerated, and primaryDomain's role in the domain acquisition stays ambiguous.
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 only 8% (one param has a description), so the description must compensate — and it largely does: the slot semantics for domains with ordinals 0..N-1, the inboxesEach vs distribution alternative with an example array, determinism of mailbox addresses with persona, and registerDomains/registrant/quoteOnly consent flows. The remaining gap is primaryDomain, which is name-dropped in the inputs list but never distinguished from the lookalike domains being purchased; the schema entry is just a string field, so the agent gains no clarity there.
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 opens with a precise verb and resource — 'Provision sending infrastructure: buy branded lookalike domains, create mailboxes, start warmup' — which immediately distinguishes it from read-only siblings like infrastructure_status and from teardown tools like remove_mailboxes. An agent can tell what this tool does and what it is not without reading any other 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 routes the agent to the right action for each state: poll infrastructure_status for dailyCap, call contact_operator instead of waiting when capacity is held, re-call setup_infrastructure to converge DNS after 'pending', and pass quoteOnly:true first to preview billing before committing. Sibling tools and alternative behaviors are named explicitly with the exact conditions that select them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
suppress_leadADestructiveInspect
Permanently suppress an email address tenant-wide (every current and future campaign) — the manual/free-text 'stop emailing me' path for opt-outs the strict typed-unsubscribe matcher misses. Inputs: email, reason (fixed 'manual' — the only value this tool honestly claims; bounce/complaint/unsubscribe are recorded automatically elsewhere), note (accepted, not persisted). Cancels every pending send + marks every campaign-lead row 'suppressed'. Last-write-wins: re-suppressing a bounce/complaint/unsubscribe row relabels its reason to 'manual'. There is no un-suppress tool.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | ||
| Yes | |||
| reason | No | manual |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the `destructiveHint` annotation by detailing side effects: cancels pending sends, marks rows suppressed, last-write-wins relabeling, and the fact that notes are accepted but not persisted. This provides complete transparency beyond what annotations offer.
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 but packs in all critical details. The structure is front-loaded with the core purpose, then details. Minor improvement: could break into bullet-style for even quicker scanning, but overall every sentence earns its place.
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?
Despite no output schema, the description fully covers input semantics, side effects, behavioral traits (last-write-wins), and caveats (no un-suppress). It leaves no ambiguity about what the tool does or its consequences for a 3-parameter tool.
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 0%, but the description fully compensates: it explains that `reason` is fixed to 'manual' (const), `note` is accepted but not persisted, and `email` is required. This adds significant meaning beyond the bare 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 description specifies a clear verb ('suppress') and resource ('email address tenant-wide'), and distinguishes its purpose as the manual opt-out path for cases the typed-unsubscribe matcher misses. It names the exact inputs and effects, making the tool's role 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 explicitly states when to use ('manual opt-out path') and implicitly when not to use (bounce/complaint/unsubscribe are handled automatically elsewhere). It also warns there is no un-suppress tool and explains the last-write-wins behavior, guiding appropriate use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
threadARead-onlyInspect
Full message history for ONE thread. Input: threadId (from inbox). Returns { threadId, campaignId, leadId, leadEmail, mailboxEmail (null before first send), messages[] }, each message { type (sent/reply/bounce/...), ts, messageId, metadata }, oldest first. 404 if unknown. Use inbox to LIST threads; reply to respond; mark/label_thread to triage.
| Name | Required | Description | Default |
|---|---|---|---|
| threadId | Yes | The thread id, e.g. from inbox() or campaign events. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already set readOnlyHint=true. Description adds specifics: return shape with nullable mailboxEmail, oldest-first order, and error behavior. No contradictions.
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?
Single paragraph covering purpose, input, output, error, and sibling hints. No redundancy; efficient but could be slightly more structured.
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 one parameter, no output schema, and high schema coverage, the description provides complete context: purpose, input, output shape, error, and usage alternatives.
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 has 100% coverage with clear description for threadId. Description mentions it but adds no new semantic detail 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?
Explicitly states 'Full message history for ONE thread' with specific verb and resource. Distinguishes from siblings by naming inbox, reply, and label_thread.
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?
Provides clear when-to-use: 'Use inbox to LIST threads; reply to respond; mark/label_thread to triage.' Also notes 404 error for unknown threads.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_leadAInspect
Record what you learned about a contact (their reply, your triage) as a durable, contact-level disposition — keyed by email, visible across every campaign that lists them. Inputs: email, interestStatus (none|interested|meeting_booked|not_now|not_interested|bad_fit|out_of_office|wrong_person — a server-enforced enum; 'do not contact' is NOT a member, use suppress_lead instead), notes, tags (free-form). A PARTIAL patch — only the fields you pass are changed; at least one of interestStatus/notes/tags is required. Filterable via list_leads.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| Yes | |||
| notes | No | ||
| interestStatus | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses key behavioral traits beyond annotations: it states it's a partial patch (only passed fields changed), requires at least one of interestStatus/notes/tags, and mentions server-enforced enum validation. Annotations only provide destructiveHint=false, so the description adds useful context. However, it does not mention authorization needs or rate limits, which are minor gaps.
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 well-structured with a clear lead sentence followed by a parameter list. It is relatively long but each sentence adds value. Minor redundancy: 'Inputs: ' could be integrated. Overall, it's concise for the amount of detail provided.
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 4 parameters, no output schema, and low schema coverage, the description thoroughly covers inputs, behavior (partial patch), and relationships to sibling tools (suppress_lead, list_leads). It also notes the contact-level scope and cross-campaign visibility. No missing aspects for the tool's 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 description coverage is 0%, so the description fully carries the burden. It explains each parameter's role: email as key, interestStatus with explicit enum values and the note that it's server-enforced, notes and tags with constraints (maxLength, maxItems). It also clarifies that at least one optional param is required, adding meaning 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 description clearly states the tool's purpose: recording contact-level disposition keyed by email. It uses specific verbs ('record what you learned') and resource ('contact-level disposition'), and distinguishes itself from sibling tool 'suppress_lead' by explicitly noting that 'do not contact' is not a valid interestStatus.
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 explicit guidance on when to use this tool versus alternatives: it notes that 'do not contact' should be handled via suppress_lead. It also mentions that the tool is filterable via list_leads, offering context for integration. No when-not-to-use scenarios are omitted.
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. Dates show when Glama detected each change.
6 tool updates
v0.2.3- Added
ack_message - Changed
configure_webhook1 field changed- changed
Input schema / properties / eventTypes / descriptionPrevious value: -"Required for create: which events to push (reply | bounce | soft_bounce | complaint)."New value: +"Required for create: which events to push (reply | bounce | soft_bounce | complaint | unsubscribe)."
- Added
contact_operator - Added
list_messages - Changed
remove_mailboxes1 field changed- added
Input schema / properties / idempotencyKeyAdded value: +{ + "description": "Optional idempotency key: resend the SAME key when retrying this call so a dropped-response retry is not applied twice (no duplicate campaign/provision/send).", + "maxLength": 200, + "minLength": 1, + "type": "string" +}
- Changed
setup_infrastructure4 fields changed- added
Input schema / properties / distributionAdded value: +{ + "items": { + "maximum": 10, + "minimum": 1, + "type": "integer" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" +} - added
Input schema / properties / registerDomainsAdded value: +{ + "type": "boolean" +} - added
Input schema / properties / registrantAdded value: +{ + "properties": { + "addressLine1": { + "maxLength": 500, + "minLength": 1, + "type": "string" + }, + "city": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "country": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "email": { + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + "type": "string" + }, + "firstName": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "lastName": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "organization": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "phone": { + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "postalCode": { + "maxLength": 20, + "minLength": 1, + "type": "string" + }, + "state": { + "maxLength": 200, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "firstName", + "lastName", + "email", + "phone", + "addressLine1", + "city", + "state", + "country", + "postalCode" + ], + "type": "object" +} - changed
Input schema / requiredPrevious value: -[ - "brand", - "primaryDomain", - "domains", - "inboxesEach", - "persona", - "physicalAddress", - "senderIdentity" -]New value: +[ + "brand", + "primaryDomain", + "domains", + "persona", + "physicalAddress", + "senderIdentity" +]
25 tool updates
v0.1.0- First observed
account - First observed
activity - First observed
campaign_results - First observed
configure_byo_domain - First observed
configure_dashboard - First observed
configure_webhook - First observed
get_byo_domains - First observed
get_dashboard - First observed
get_webhooks - First observed
inbox - First observed
infrastructure_status - First observed
label_thread - First observed
launch_campaign - First observed
list_campaigns - First observed
list_leads - First observed
mark - First observed
metrics - First observed
pause - First observed
pause_all - First observed
remove_mailboxes - First observed
reply - First observed
setup_infrastructure - First observed
suppress_lead - First observed
thread - First observed
update_lead
TDQS
Each tool targets a distinct resource or action. For example, activity vs inbox differentiate broad events vs replies, and campaign_results vs metrics vs list_campaigns each serve unique query scopes. No two tools overlap in purpose.
Most tools follow a verb_noun pattern (e.g., list_campaigns, configure_webhook), but a few are noun-only (activity, inbox, thread, metrics). The overall pattern is clear and readable, with only minor deviations.
25 tools is slightly above the typical 3-15 range, but the complexity of cold email infrastructure (campaigns, inbox, leads, infrastructure, webhooks) warrants a larger set. Each tool feels justified.
Core workflows (campaign creation, inbox triage, lead management, infrastructure) are covered, but notable gaps exist: no update or delete campaign, and no resume after pause. These missing operations could hinder agent workflows.
Maintenance
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Hosted email MCP for AI agents with inboxes, send/receive, memory, recovery, and credits.
Cold email infrastructure — campaigns, prospects, mailbox health and replies via Claude.
Email inboxes for AI agents: send, receive, reply, search, and manage threaded email over MCP.
Related MCP Servers
- AlicenseBqualityCmaintenanceDisposable email MCP server for autonomous AI agents. Create labeled temporary inboxes, wait for verification emails, extract OTP codes and confirmation links — zero human intervention required.6MIT
- AlicenseAqualityDmaintenanceEmail infrastructure for AI agents — create inboxes, send/receive email, search messages, and manage threads via MCP tools.10292MIT
- AlicenseAqualityDmaintenanceMCP server for SentVia that provides email infrastructure for AI agents, enabling them to create inboxes, send, reply, forward, search messages, manage drafts, domains, webhooks, and allow/block rules through 21 tools.2185MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for managing cold-email infrastructure: buy domains via Porkbun, import them into CheapInboxes, provision Google/Microsoft mailboxes, and sync credentials to platforms like Instantly and Smartlead.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/YS-projectcalc/agent-cold-email'
If you have feedback or need assistance with the MCP directory API, please join our Discord server