Skip to main content
Glama
hail

hail

Official

Hail

Give your agent a real phone number and an email inbox — in minutes, not days.

License: AGPL v3 PyPI — hail-sdk CLI release Docs Brand assets Run in Postman

Your agent needs to call a person to move an appointment. Hail connects to the telephone carrier and runs the voice pipeline — STT, TTS, turn detection. Your agent is the brain: point Hail at any OpenAI-compatible endpoint (bring your own LLM), or let Hail's fallback chain (Anthropic → OpenAI → Gemini) do the talking. SMS and email work the same way — one MCP endpoint, one API key, one invoice.

Self-hostable with Docker Compose; LiveKit Cloud and the communication providers remain external. Open source under AGPLv3.

Animated terminal demo of hail tail streaming live call events

Self-host quick start

Prerequisites: Git, Docker Engine, and Docker Compose v2. For a public production deployment you also need a domain, HTTPS, and a managed Postgres; start with the VM deployment guide.

The commands below run a local evaluation stack with bundled Postgres. Voice calls additionally require LiveKit Cloud, a carrier (Twilio, Telnyx or DIDWW), Deepgram, Cartesia, and at least one LLM provider. Email is optional and requires AWS SES.

git clone https://github.com/hail-hq/hail
cd hail
cp .env.example .env

# Generate a shared self-host key, then put it in .env as HAIL_API_KEY.
printf 'hk_%s\n' "$(openssl rand -base64 32 | tr -d '/+=' | head -c 40)"

# Edit .env and add the providers required for the channels you will use.
docker compose -f docker-compose.yml -f docker-compose.local.yml \
  run --rm api alembic upgrade head
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d
docker compose -f docker-compose.yml -f docker-compose.local.yml ps
curl --fail http://localhost:8080/healthz

Self-host authentication uses the HAIL_API_KEY value from .env; it does not need an API-key row in Postgres. Export the same key and API URL in the shell where you use the CLI or SDK (Compose does not export .env into your shell):

export HAIL_API_URL=http://localhost:8080
export HAIL_API_KEY='<same value as .env>'

Next, follow LiveKit Cloud and Twilio (optionally Telnyx and DIDWW), then bind a phone number to the self-host organization using the first-run setup. To enable email, follow AWS SES.

Authentication differs by deployment:

  • Hail Cloud (managed, at hail.so): run hail login. The device flow writes a key to ~/.hail/credentials.json.

  • Self-host: do not run hail login; set HAIL_API_URL and HAIL_API_KEY as shown above, or pass --api-url and --api-key.

Full setup guides: self-hosting · Webhooks · MCP · operations

Related MCP server: agentline-mcp

Cursor plugin

Give your AI assistant a phone number and an email inbox.

Let your assistant handle calls, texts, and email. Building an app? Add AI calls, email and SMS with one API.

Make and take calls, send and receive messages, and check conversation history from Cursor. Get phone numbers in 120+ countries, with help for local rules and required documents, including US A2P 10DLC registration. Choose a built-in voice or bring your own. Build with the API, CLI, or Python SDK. Open-source or cloud priced on usage.

From a checkout that includes the plugin, copy its files into Cursor's local plugin directory:

mkdir -p ~/.cursor/plugins/local/hail
git archive HEAD .cursor-plugin mcp.json README.md LICENSE \
  docs/assets/hail-messenger.svg | tar -x -C ~/.cursor/plugins/local/hail

Reload Cursor and open Customize to find the Hail MCP server. Enterprise administrators must allow local plugin imports first. The plugin connects to https://mcp.hail.so using OAuth. Sign in to Hail when Cursor asks. No API key or local MCP runtime is needed. Start with a read-only request:

Find call-capable Hail numbers in the UK, France, and Canada. Compare
monthly fees, setup fees, and registration requirements.

Install the CLI

On macOS or Linux with Homebrew:

brew install hail-hq/tap/hail
hail version

Homebrew adds the hail-hq/tap tap automatically. To update later:

brew upgrade hail-hq/tap/hail

Alternatively, download the archive for your operating system and architecture from GitHub Releases. Release binaries are available for macOS and Linux on Intel and ARM64. See the CLI reference for authentication and commands.

Make your first call

CLI:

hail login                        # Hail Cloud only (device flow)
hail auth logout                  # remove local credentials
hail auth token                   # print bare API key for scripting

hail call +14155550100 --prompt "be brief" --recipient-consent
hail call list
hail call status <id>             # one call's state
hail call tail <id>               # follow events for one call

hail sms +15551234567 --body "Hello!" --recipient-consent
hail sms list
hail sms status <id>
hail sms suppressions list        # opt-out list
hail sms sender-id get            # custom sender ID

hail numbers acquire              # dedicated phone number (voice + SMS), cheapest live offer
hail numbers list
hail contacts list                # org contact directory

hail email send --to a@b.com --subject hi --body "hello" --recipient-consent
hail email list
hail email get <id>
hail email tail <id>              # follow events for one email
hail email raw <id>               # RFC 5322 source
hail email suppressions list      # addresses Hail will not send to
hail email attachment <id> <att-id> --output file.pdf
hail email domain register --kind hail_mail
hail email domain register --kind custom --domain acme.com  # send + receive on your own domain
hail email domain list

printf '%s' "$YOUR_API_KEY" | hail providers set llm \
  --provider openai-compatible \
  --base-url https://api.your-agent.dev/v1 \
  --model your-model \
  --key -                         # standing BYO brain (also: tts, stt)

hail tail                         # cross-channel event stream
hail tail call:<id>               # narrow by resource type

hail mcp endpoint                 # Streamable HTTP URL for the MCP server
hail completion zsh               # source <(hail completion zsh)
hail version

Python (pip install hail-sdk):

import asyncio
from hail import Client

async def main():
    async with Client() as client:  # reads $HAIL_API_KEY
        call = await client.calls.create(
            to="+15551234567",
            recipient_consent=True,
            system_prompt="You are calling to confirm a reschedule.",
        )
        async for event in client.events.tail(id=f"call:{call.id}"):
            print(event.kind, event.payload)

asyncio.run(main())

HTTP (OpenAPI spec, API reference):

curl -X POST http://localhost:8080/v1/calls \
  -H "Authorization: Bearer $HAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"+15551234567","recipient_consent":true,"system_prompt":"..."}'

MCP (Claude.ai, Claude Code, ChatGPT, Cursor, …): local clients can use http://localhost:8081. Web-based clients require a publicly reachable HTTPS endpoint. See the MCP setup guide.

Bring your own LLM

Hail always runs the telephony and the voice pipeline. The brain is pluggable, at two levels:

  • Per call — pass an llm block to POST /calls; different brains for different calls.

  • Standing — save an endpoint once (hail providers set llm …); every call your org places uses it.

Any OpenAI chat-completions-compatible endpoint works. A complete runnable example lives in docs/public/byo-llm.md. TTS and STT are pluggable the same way (hail providers set tts|stt …).

Tenets

  1. Clear comms. Explicit OpenAPI contracts. No hidden behavior.

  2. Simple code. Boring is best. No abstraction before it has two uses.

  3. Brief docs. Each page fits on one screen. Setup takes 10 minutes from a fresh clone.

  4. Self-hostable. Docker Compose runs Hail's API, voicebot, MCP server, and Postgres; LiveKit Cloud and channel providers remain external.

  5. Pluggable brain. BYO LLM endpoint, or Hail's bundled fallback. The voice pipeline and transport are always Hail's.

  6. Agent-first docs. AI agents are first-class readers. Runnable examples first; links to canonical sources, not paraphrase.

Milestones

A checked box is a released feature. Per-artifact changelogs (GitHub Releases for the CLI, PyPI notes for the SDK) record which version shipped it.

Phone calls

  • Outbound

    • Twilio

    • Telnyx

    • DIDWW

  • Inbound (answered by an agent)

    • Twilio

    • Telnyx

    • DIDWW

SMS

  • Outbound

    • Twilio

    • Telnyx

  • Inbound

    • Twilio

    • Telnyx

    • Answered by an agent

Numbers

  • Live quotes across carriers (inventory, price, verification effort)

  • Carrier verification for regulated countries (Twilio, Telnyx)

Email

  • Outbound

    • AWS SES

    • Custom sender domains (own DNS, automatic DKIM + MAIL FROM)

  • Inbound

    • AWS SES

    • Custom domains (receive on verified domains)

Voice pipeline

  • Languages

    • 39 call languages with automatic STT routing and per-language turn detection — see docs/languages.md

  • STT

    • Deepgram

    • Speechmatics

    • Whisper

    • AssemblyAI

  • TTS

    • Cartesia

    • ElevenLabs

    • Deepgram Aura

  • VAD

    • Silero

  • Turn detection

    • LiveKit turn-detector

  • LLM — system-prompt mode

    • Fallback: Anthropic → OpenAI → Gemini, fast models

  • LLM — BYO-endpoint mode

    • OpenAI chat-completions-compatible (docs)

  • Recording

    • Optional call recording

    • Diarization

Distribution

  • API

  • CLI

    • hail binary via GitHub Releases

  • MCP server

    • Remote Streamable HTTP endpoint included with each Hail deployment

    • Stdio entry point included in the MCP container; see MCP setup

  • Python SDK

    • hail-sdk on PyPI, imports as hail

Infrastructure

  • Docker Compose scaffold

  • Self-hosted LiveKit SFU

    • docker compose integration

Architecture

The path of an outbound call:

AI agent ──► Hail API ──dispatch──► Voicebot ──► LiveKit Cloud ──SIP──► carrier (Twilio · Telnyx · DIDWW) ──► 📞

Full diagram and service breakdown: docs/public/architecture.md. All docs are published at hail.so/docs and live as plain markdown in docs/public/.

Contributing

See docs/public/contributing.md. Short version: fork, branch, conventional commits, pull request. Provider adapters go in core/hailhq/core/providers/; new env vars update .env.example in the same commit.

License

Code: AGPL-3.0-or-later — run a modified Hail as a service, release your source. Pricing dataset (costs/): CC-BY-4.0 — use the JSON with attribution.

Available Tools

38 tools
acquire_numberBuy a phone numberA
DestructiveIdempotent
Inspect

Buys a real phone number. It charges the setup fee and the first month now and renews monthly. Call quote_numbers first. Pass the offer's quote_id, country_code, number_type, and confirm_total_cents = monthly_cents + setup_cents from that offer. If the quote expired or the price changed (409) you get an error: quote again. Only buy when your user asked for this number. After buying, call route_number to point it at an agent.

    A quote buys at most one number. After a timeout, retry with the same
    quote_id and idempotency_key, or check list_numbers. Never request a
    new quote after a timeout.

    ``idempotency_key`` is optional; to retry after a timeout or a
    5xx, pass the ``idempotency_key`` that result returned, so the number
    is bought once. A 4xx error returns no key: the API remembers that
    failure under it, so drop it and quote again.

    ``verification_id`` picks which approved verification buys a number
    that needs one: the ``id`` of an approved entry in the offer's
    ``verifications``. Pass it when more than one is approved: show the
    user each ``subject_name`` (the person's or company's name) and ask
    which. With one approved, it is used. ``subject_type`` (``person`` or
    ``business``) is optional: it keeps only that kind. A 422 on
    ``verification_id`` means several are approved and none was picked,
    or the id is not an approved verification for this number.

    Returns the number (``id``, ``e164``, ``provisioning_state``,
    ``verification_id``, ``subject_name``, ...)
    plus ``idempotency_key``, or ``{"error": "<message>",
    "idempotency_key": ...}``.
NameRequiredDescriptionDefault
quote_idYes
number_typeYes
country_codeYes
subject_typeNo
idempotency_keyNo
verification_idNo
confirm_total_centsYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing the financial effect (setup fee + first month charged now, renews monthly), the 409 price-changed/expired-quote path, the 422 verification path, and the timeout/5xx retry contract. Annotations already flag destructive/idempotent, and the description explains the mechanics those hints imply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and cost, then organized into short paragraphs by concern (retry, idempotency, verification, return). It is long, and the idempotency/timeout material is restated across two paragraphs, but nearly every sentence carries operational information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, money-charging, idempotency-sensitive purchase tool, the description covers prerequisites, cost, retry semantics, verification selection, error codes, and the return shape (including the error envelope). Even with an output schema present, the explicit return contract removes ambiguity about the idempotency_key field.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema coverage the description carries the load and does well: it defines confirm_total_cents as monthly_cents + setup_cents, explains quote_id provenance, the idempotency_key retry contract, and verification_id/subject_type semantics with the 422 trigger. country_code and number_type are only implied by 'from that offer', so their expected values are not spelled out.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Buys a real phone number') and immediately situates it in the workflow between quote_numbers and route_number. An agent can distinguish it from quoting, routing, and releasing without inspecting any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('only buy when your user asked for this number'), mandatory prerequisite ('call quote_numbers first'), and required follow-up ('after buying, call route_number'). It also states when NOT to re-quote after a timeout, naming the alternative (retry with same key, or check list_numbers).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_verificationCancel a verificationA
Destructive
Inspect

Cancel a verification that has not been sent for review, or dismiss a rejected one (needed before submitting a new one for the same country and number type). The draft is discarded.

    Works in state ``awaiting_review`` or ``rejected``, and for an
    ``approved`` US SMS registration (``purpose: "sms"``): its numbers
    leave the campaign, US-to-US texts from them fail again, and its
    monthly fee stops after the current month. Some registrations bill at
    least 3 monthly fees from approval, so cancelling sooner can still
    charge 3 months. Ask the user first. A
    ``submitting`` or ``submitted`` verification is under review and
    cannot be cancelled (409): wait for the result with get_verification.

    Returns the verification with ``state: "cancelled"``, or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
verification_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructive and open-world annotations, the description discloses concrete consequences: the draft is discarded, numbers leave the campaign, US-to-US texts fail again, monthly fees stop after the current month, and at least three monthly fees may still be charged. It also surfaces the user-consent requirement and the 409 behavior for in-flight verifications.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is front-loaded with the core action and invocation states, then adds only decision-relevant consequences such as billing risk and the user-confirmation requirement. Despite its detail, every section helps an agent decide whether and how to call the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is rich for a destructive state-changing tool: it states lifecycle applicability, side effects, billing caveats, error behavior, and return shape. The only material omission is how the agent should obtain the required verification_id, which is left implicit despite no schema description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The sole parameter, verification_id, has 0% schema description coverage, and the description does not explain where the ID comes from, its format, or which sibling tool supplies it. The parameter name is self-evident, but the description does not compensate for the missing schema semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Cancel a verification' / 'dismiss a rejected one') and scopes it to verification states and one approved US SMS registration case. It clearly distinguishes cancellation from verification workflows handled by get_verification and submit_verification.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use conditions: awaiting_review, rejected, or approved US SMS registrations, plus the need to dismiss a rejected verification before submitting a new one for the same country and number type. It also states when not to use it (submitting/submitted, 409) and directs the agent to get_verification instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

confirm_verificationConfirm a verification with a codeAInspect

When a registration shows confirmation 'code', ask the person for the code the carrier texted and submit it here.

    ``verification_id`` comes from submit_verification or
    list_verifications. ``code`` is 4 to 10 characters. A wrong or expired
    code is an error naming ``code``; the carrier sends a new one after a
    day. On success the registration moves on; poll get_verification
    until ``approved``. A ``confirmation`` of ``reply`` means the person
    answers the carrier's text instead; nothing is entered here.

    Returns the verification or ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
codeYes
verification_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare the generic profile (not read-only, open-world, not idempotent, not destructive). The description adds real operational context: wrong or expired codes surface as an error naming 'code', the carrier re-sends after a day, success advances the registration and requires polling get_verification until 'approved', and failures return an error object.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and condition, then parameters, then failure modes, then return value – a sensible ordering. The final return-value sentence partially duplicates the output schema and the earlier error statement, so there is minor slack.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers trigger, parameter sourcing, valid input shape, failure behavior with recovery timing, the post-success next step (poll get_verification), and the alternate 'reply' path. Despite an output schema existing, the error-object shape is still worth stating and nothing needed to call this correctly is absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry the burden and it does: verification_id's provenance is stated and code is bounded to 4-10 characters. That is exactly the information missing from the bare string properties.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (confirm) and resource (a verification) plus the mechanism (with a code), and the surrounding text makes clear this is the code-entry path rather than submit_verification or get_verification. An agent can distinguish it from its siblings 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ('when a registration shows confirmation code, ask the person for the code the carrier texted and submit it here') and an explicit exclusion ('a confirmation of reply means the person answers the carrier's text instead; nothing is entered here'). It also names where verification_id must come from (submit_verification or list_verifications).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_agentCreate an agentAInspect

Save an agent. Then call route_number so a number answers with it, or pass its id as agent_id to place_call.

    ``system_prompt`` is what the agent follows. ``first_message`` is
    spoken after the AI line; omit it to let the caller speak first.
    ``ai_disclosure_line`` replaces the workspace AI line for this
    agent; ``{org}`` becomes the organization name. ``language`` is a
    lowercase ISO 639-1 code. ``max_duration_seconds`` is 60..3600.
    ``handover_max_duration_seconds`` (60..3600, default 1800) is the
    call limit once a handover contact answers.
    ``handover_contacts``: People the agent may hand a live call to:
    ``[{contact_id, note}]`` (max 10; ``note`` 1-200 chars says when to
    hand over). ``contact_id`` is an id from ``list_contacts``: a
    contact's uuid, or ``member:<user id>`` for a team member. The
    person needs a phone number. The agent never sees it.

    Returns the API's ``AgentResponse`` as a dict, or
    ``{"error": "<message>"}``.
    
NameRequiredDescriptionDefault
nameYes
toolsNo
languageNo
voice_idNo
sms_enabledNo
ai_disclosureNo
first_messageNo
system_promptYes
voice_enabledNo
handover_contactsNo
recording_enabledNo
ai_disclosure_lineNo
max_duration_secondsNo
handover_max_duration_secondsNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations by disclosing defaults and bounds (max_duration 60..3600, handover default 1800, max 10 contacts, note 1-200 chars), the {org} substitution in ai_disclosure_line, and the privacy behavior that the agent never sees the handover phone number. It omits permission requirements and what the boolean flags (sms_enabled, voice_enabled, recording_enabled) actually toggle.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the creation purpose and the follow-up routing before the parameter detail, so the most important information is first. The dense parameter block is long but each line carries distinct semantics; minor structural noise from the reStructuredText formatting.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so the return-value sentence is bonus rather than necessity, and the annotations already cover the safety profile. The main remaining gap is that seven of fourteen parameters, including the meaningful sms_enabled/voice_enabled/recording_enabled flags, have no semantics anywhere.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 14 parameters, so the description carries the full burden and does explain roughly half: system_prompt, first_message (including what omitting it means), ai_disclosure_line, language, both duration fields, and handover_contacts structure. Name, tools, voice_id, sms_enabled, ai_disclosure, voice_enabled, and recording_enabled are left completely undefined.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Save an agent" plus the follow-up instructions ("so a number answers with it", "pass its id as agent_id to place_call") make clear this persists a new voice/SMS agent. The verb "Save" is slightly ambiguous versus the sibling update_agent, but the surrounding workflow removes most doubt.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states the next step after creation: call route_number or use the returned id with place_call, which gives an agent a concrete context for when this tool belongs in a sequence. It does not explicitly say when to prefer update_agent or delete_agent instead, so no true exclusion guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_contactCreate a contactAInspect

Save a new contact for the workspace. Provide at least one of phone_e164 (E.164, e.g. +14155551234) or email — the API rejects (422) a contact with neither. A duplicate phone or email on an existing contact returns 409.

    Example:
        create_contact(name="Maya Chen", phone_e164="+14155551234")

    Returns the created contact entry as a dict. On failure returns
    ``{"error": "<message>"}`` instead.
    
NameRequiredDescriptionDefault
nameYes
emailNo
phone_e164No

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations (which only say non-readonly, non-destructive, non-idempotent) by disclosing the 422 validation rule, the 409 duplicate behavior, and the return shape including the error-dict failure mode. That is exactly the mutation-side context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then constraints, then example, then return behavior — a sensible order with no filler. The indented multi-line formatting and backticks are slightly clunky for tool text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter create tool this covers the validation rule, duplicate behavior, and return convention; the output schema makes the return description redundant but harmless. Only missing piece is any hint about checking lookup_contact first.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (only bare titles), so the description carries the load: it defines phone_e164 as E.164 with a literal example and clarifies email is an alternative constraint, not optional fluff. It says nothing about 'name' semantics beyond the example, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Save a new contact for the workspace'), which clearly separates it from read siblings like list_contacts and lookup_contact. It never spells out the sibling contrast explicitly, so it stops short of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete preconditions: at least one of phone_e164 or email, otherwise 422; duplicates yield 409. It doesn't explicitly route the agent to lookup_contact/check-before-create, but the duplicate rule implies that workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_agentDelete an agentA
DestructiveIdempotent
Inspect

Delete a saved agent. DESTRUCTIVE. Ask the user before calling this.

    Numbers that used the agent stop answering with it: calls ring out
    and texts reach webhooks only. Reroute them first with
    ``route_number`` if that matters.

    ``confirm_name`` must equal the agent's ``name``. The tool reads the
    agent first and refuses with ``{"error": ...}`` on a mismatch,
    without deleting anything. To stop an agent without deleting it, use
    ``update_agent`` with ``status="paused"``.

    Returns ``{"deleted": true, "agent_id", "name"}``, or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
agent_idYes
confirm_nameYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by spelling out the downstream consequence (numbers stop answering, calls ring out, texts reach webhooks only), the confirm_name guard that makes the tool refuse instead of deleting, and the exact return shapes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the destructive warning, then consequences, then the parameter contract, then the return value. Dense but every sentence carries an operational fact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers safety, side effects, guard behavior, alternative tools, and return values; even though an output schema exists, restating the two result shapes costs little and removes ambiguity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate: it fully explains confirm_name's contract (must equal the agent's name, mismatch returns an error without deleting). agent_id is left implicit as the target agent identifier.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Delete a saved agent') and immediately marks it destructive, which distinguishes it from the nearby 'update_agent' and 'list_agents'/'get_agent' siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to ask the user before calling, names 'route_number' as the prerequisite when number routing matters, and names 'update_agent' with status="paused" as the non-destructive alternative. When-to-use and when-not-to-use are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_agentGet an agentA
Read-onlyIdempotent
Inspect

Fetch one saved agent by id. agent_id comes from list_agents or create_agent.

    Returns the ``AgentResponse`` as a dict (``name``, ``system_prompt``,
    ``first_message``, ``ai_disclosure``, ``voice_config``, ``tools``,
    ``voice_enabled``, ``sms_enabled``, ``status``, ...), or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
agent_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety burden is covered. The description adds value beyond them by describing the returned shape and the ``{"error": ...}`` failure case, which the annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, front-loaded paragraphs: purpose and id provenance first, return shape second. No filler; the return-shape enumeration is the only part that partly overlaps the existing output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so enumerating fields is arguably redundant, but the description rounds it out with the error-case shape and id sourcing. For a one-parameter read tool this is sufficient to call correctly; only id format/edge-case behavior is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% (the single ``agent_id`` string is undocumented in the schema), so the description must compensate. It adds provenance for the id (from list_agents or create_agent) but never specifies format, or behavior on an unknown/missing id beyond a generic error dict.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Fetch one saved agent by id") and contrasts implicitly with list_agents/create_agent by naming them as the source of the id. An agent can distinguish this single-record read from the sibling list/create/update/delete agent tools immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Tells the caller where the required id comes from ("``agent_id`` comes from ``list_agents`` or ``create_agent``"), which routes the agent to the correct prerequisite tools. It does not state any when-not conditions, but for a simple read-by-id there is little ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_callGet a callA
Read-onlyIdempotent
Inspect

Fetch the current state of one call by id.

    Use this after ``place_call`` (or to check on any prior call)
    to read the call's latest ``status`` and timing fields.

    Returns the API's ``CallResponse`` as a dict, or
    ``{"error": "call not found"}`` for an unknown id.
    
NameRequiredDescriptionDefault
call_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and closed-world behavior, so the bar is lower. The description adds genuinely new behavioral detail: it returns the API's CallResponse as a dict, and returns {"error": "call not found"} for an unknown id — the error contract is valuable and not 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the verb and resource, no filler. The retained RST double-backtick markup adds slight visual noise but costs almost nothing in length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read tool with full annotations and an output schema, the description covers purpose, trigger context, and the error case. Only the call_id format/origin is left unstated, which is a small residual gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter call_id has no description in the schema. The description only implies semantics via 'by id' and 'for an unknown id'; it doesn't specify the id's origin or format (e.g., the id returned by place_call). Minor value added over an obvious string-id parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'Fetch the current state of one call by id.' The 'one call' phrasing implicitly separates it from the sibling list_calls, though no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear usage context: 'Use this after place_call (or to check on any prior call) to read the call's latest status and timing fields.' It names the sibling place_call and the follow-up pattern, but offers no explicit exclusion (e.g., 'use list_calls to enumerate calls').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_emailGet an emailA
Read-onlyIdempotent
Inspect

Fetch the full record of one email by id.

    Returns the complete row — including ``body_text`` / ``body_html``
    and (for inbound mail) the ``in_reply_to`` / ``message_id`` headers
    and ``spam``/``virus``/``spf``/``dkim``/``dmarc`` verdicts. Use this
    after ``list_emails`` to read a received reply's body.

    Returns the API's ``EmailResponse`` as a dict, or
    ``{"error": "resource not found"}`` for an unknown id.
    
NameRequiredDescriptionDefault
email_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so safety is fully covered. The description adds a real behavioral detail: the shape of the failure result ({"error": "resource not found"}) for an unknown id. Beyond that, most of the text enumerates returned fields, which duplicates what the declared output schema already provides — little marginal behavioral context for a single-row read.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb and resource in the first line, then workflow, then return contract — a sensible order with no filler sentences. The verdict enumeration (spam/virus/spf/dkim/dmarc) is slightly listy but is concrete enough to earn its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With rich annotations and an output schema present, the description only needs to cover usage and edge cases, and it does: workflow anchor, error result for bad ids, and what makes this endpoint richer than a list row. The remaining gap is sibling disambiguation against get_email_raw and the id format, both minor given the structured fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is one required parameter at 0% schema description coverage, so the description must carry the load. It says the record is fetched "by id" and that an unknown id produces a not-found error, which is useful. But it never specifies the id's form or origin (e.g., whether it is the email id from list_emails rather than a message_id header, which the description itself mentions), leaving ambiguity an agent could hit at call time.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — fetch the full record of one email by id — and names the fields that distinguish it from a list view (body_text/body_html, inbound headers, spam/virus/SPF verdicts). It routes away from list_emails, but never distinguishes itself from the close sibling get_email_raw, which an agent could easily confuse with it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use this after list_emails to read a received reply's body" gives an explicit trigger and workflow position. It stops short of naming when-not-to-use or pointing at get_email_raw as the alternative for raw source, so the sibling boundary is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_email_attachmentGet an email attachmentA
Read-onlyIdempotent
Inspect

Get a fetchable URL for one inbound email attachment.

    ``attachment_id`` comes from an item in ``get_email``'s
    ``attachments`` list. Returns ``{"url": "<presigned-s3-url>"}`` —
    a short-lived (~5 minute) link to the attachment bytes, fetchable
    directly with no auth header. Unknown ids return
    ``{"error": "resource not found"}``.
    
NameRequiredDescriptionDefault
email_idYes
attachment_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/idempotent annotations by disclosing the ~5 minute link expiry, the lack of an auth header requirement on the returned URL, and the exact error shape for unknown ids. These are the operational traits an agent must plan around and none are derivable from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then layers provenance, return shape, expiry, and error behavior in a compact block with no filler. Slightly redundant to spell out the return shape when an output schema exists, but it is short enough to earn its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a rich annotation set and an output schema present, the description still adds the pieces that matter: expiry window, auth-free fetching, and not-found behavior. The only missing element is the meaning of the required email_id parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden. It fully documents attachment_id's provenance but never explains email_id's role or why both are required — an agent may wonder whether attachment_id alone would suffice. Partial compensation for a real coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — returns a fetchable URL for one inbound email attachment — and explicitly links the input to ``get_email``'s attachments list, distinguishing it from sibling tools like get_email and get_email_raw. An agent knows exactly what it gets back without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly establishes the trigger path: the attachment_id must come from an item in get_email's attachments list, which effectively tells the agent to call get_email first. It also explains what to do with the result (fetch bytes directly with no auth header). It stops short of naming an alternative to use instead or stating when the tool should not be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_email_eventsGet email eventsA
Read-onlyIdempotent
Inspect

Delivery/engagement timeline (sent→delivered→opened…) for one email.

    Chronological lifecycle events for a single email — use this to see
    exactly what happened to one message (bounced? opened? clicked?)
    rather than the account-wide aggregates ``get_email_stats`` returns.

    Returns ``{"items": [...], "next_cursor": ...}`` where each item has
    ``kind`` (one of sent, delivered, delivery_delayed, bounced,
    complained, rejected, opened, clicked), ``payload``, and
    ``occurred_at``. ``opened`` and ``clicked`` only occur for emails
    sent with an HTML body. A plain-text-only email still gets sent,
    delivered, and bounce events, but opens and clicks are never
    tracked. Pass ``cursor`` from a previous ``next_cursor`` to
    page (``limit`` 1..1000, default 100). On failure returns
    ``{"error": "resource not found"}`` for an unknown id.
    
NameRequiredDescriptionDefault
limitNo
cursorNo
email_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, and the description still adds substantial context beyond them: the exact event kinds, the HTML-body precondition for opens and clicks, pagination mechanics, and the `{"error": "resource not found"}` failure on unknown ids. These are behavioral traits the annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and the sibling contrast are front-loaded, then the return shape, event kinds, HTML caveat, and pagination follow in descending importance. Every sentence adds distinct information; none is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, 3-parameter tool this covers everything an agent needs: what it returns, the enumerable event kinds, the HTML-body precondition that governs whether opens/clicks ever appear, paging, and error behavior. The output-schema duplication is minor and does not detract.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description fully carries the burden: it explains `cursor` (pass a prior `next_cursor`), `limit` (range 1..1000, default 100), and implies `email_id` semantics via the not-found behavior. Nothing about the three parameters is left undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — a chronological delivery/engagement timeline for one email — and immediately distinguishes it from the account-wide aggregate tool `get_email_stats`. An agent can pick it apart from `get_email`, `get_events`, and `get_email_stats` 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the use case ('see exactly what happened to one message — bounced? opened? clicked?') and names the alternative (`get_email_stats`) plus the condition that selects it (account-wide aggregates). The when-to-use decision is fully resolved.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_email_rawGet raw emailA
Read-onlyIdempotent
Inspect

Get a fetchable URL for an email's original MIME source.

    Returns ``{"url": "<presigned-s3-url>"}`` — a short-lived
    (~5 minute) link to the full raw RFC822 message. Fetch the URL
    directly to read the complete original; it needs no auth header.
    Raw source exists for **inbound** mail only — outbound ids return
    ``{"error": "resource not found"}``.
    
NameRequiredDescriptionDefault
email_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/idempotent annotations: presigned S3 URL, ~5 minute lifetime, no auth header needed to fetch, inbound-only availability, and the exact error payload for outbound ids. These are exactly the operational facts an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action in one sentence, then layers expiration, auth-free fetching, and the inbound-only caveat. No filler; every line carries an actionable fact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, yet the description still spells out the return shape and the failure case, closing the loop on the single-parameter, single-purpose surface. Nothing 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.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and email_id is undocumented in the schema, so the description must compensate. It adds the key semantic constraint — the id must refer to inbound mail or an error is returned — though it doesn't say where to obtain a valid email_id (e.g., from list_emails).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: returning a fetchable URL for an email's original MIME source. This clearly separates it from siblings like get_email (metadata) and get_email_attachment, so an agent knows exactly what this returns without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly scopes usage to **inbound** mail and warns that outbound ids fail with "resource not found", which is a genuine when-not condition. It never names an alternative sibling (e.g., get_email for parsed content), so routing guidance is strong but not complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_email_statsGet email statsA
Read-onlyIdempotent
Inspect

Account-level email deliverability stats (counts, rates, time series).

    Aggregates across your whole organization's outbound mail over a
    window — use this for "how's deliverability doing" rather than
    one message's history (``get_email_events`` covers that).

    ``from_`` / ``to`` are ISO 8601 timestamps (defaults: last 7 days
    ending now). ``bucket`` is ``"day"`` (default) or ``"hour"`` —
    ``"hour"`` is limited to an 8-day span; any range is capped at 92
    days.

    Returns ``{"from": ..., "to": ..., "bucket": ..., "totals": {...},
    "rates": {...}, "series": [...]}`` — ``totals``/each ``series``
    bucket carry counts (sent, delivered, bounced, opened, ...) and
    ``rates`` carries derived ratios (delivery, bounce, open, click),
    each ``None`` when ``totals.sent`` is 0. Open and click numbers
    only count HTML emails. Plain-text-only emails are never tracked
    for opens or clicks, so they lower those rates. On failure returns
    ``{"error": "<message>"}`` instead.
    
NameRequiredDescriptionDefault
toNo
from_No
bucketNoday

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial context beyond them: default time window (last 7 days ending now), bucket span limits, the exact return shape, None-valued rates when totals.sent is 0, the caveat that plain-text-only emails are never tracked for opens/clicks, and the error envelope. That is exactly the behavioral detail an agent needs to interpret results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and the sibling comparison, then parameters, then return shape — a logical order with little waste. The return-shape paragraph is dense and somewhat long, though each clause (None rates, HTML-only tracking) carries real behavioral information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema being present, the description rounds out the picture with rate-nulling semantics, tracking limitations for plain-text mail, and the error format. Combined with the safety annotations, an agent has everything needed to call this and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden and does: from_/to are ISO 8601 timestamps with documented defaults, and bucket is named with its allowed values ("day" default, "hour") plus the 8-day restriction on hourly bucketing. No parameter is left ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (account-level email deliverability stats) and immediately scopes it as an aggregate over the whole organization's outbound mail, naming the sibling get_email_events as the per-message counterpart. An agent can distinguish it from list_emails, get_email, and get_email_events 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use this for "how's deliverability doing" rather than one message's history, with get_email_events named as the alternative. It also gives concrete constraints that decide between parameter choices (hour bucket limited to 8 days, any range capped at 92 days).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_eventsGet eventsA
Read-onlyIdempotent
Inspect

Page through events from across the org or one resource.

    Pass ``id="<type>:<uuid>"`` to narrow to a single resource —
    supported types are ``call``, ``email``, and ``sms`` (e.g.
    ``id="sms:<uuid>"`` after ``send_sms``). When narrowed to a
    call, the response includes a ``call_status`` field reflecting
    the call's current state. Without ``id``, returns events from
    across the whole org. ``kind`` filters server-side by event kind
    (``state_change``, ``agent_turn``, ``user_turn``, ``tool_call``,
    ``error``, ...).

    This is **not** a streaming subscription — the call returns
    whatever events exist now plus a ``next_cursor`` if more pages
    remain. To follow a call to completion, loop: pass the previous
    response's ``next_cursor`` until ``next_cursor`` is null and,
    when narrowed to a call, ``call_status`` is one of
    ``completed``, ``failed``, ``busy``, ``no_answer``, ``canceled``
    (the terminal set).

    Example:
        get_events(id="call:0c2f...-...", limit=200)

    Returns ``{"items": [...], "next_cursor": <str|None>,
    "call_status": <str|None>}`` on success, or
    ``{"error": ...}`` on a malformed ``id`` or upstream failure.
    
NameRequiredDescriptionDefault
idNo
kindNo
limitNo
cursorNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, and the description goes well beyond them: it discloses snapshot-plus-cursor semantics, the terminal `call_status` set that governs when polling may stop, and the `{"error": ...}` shape for malformed ids or upstream failures. This is exactly the extra context the annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and the two modes, then the polling contract, then an example. Slightly long, and the final paragraph restating the return shape partially duplicates the output schema, but the prose is dense and each block serves navigation rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-param, 0-required paginated read tool with an output schema, nothing an agent needs is missing: resource scoping, filter values, cursor loop termination condition, and error behavior are all covered. Return field documentation is appropriately left to the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden and largely does: `id` gets a format spec and enumerated type prefixes, `kind` gets a server-side filtering note plus sample values, and `cursor` is explained through the loop pattern. `limit` is only shown in an example (`limit=200`) with no default, maximum, or range stated, leaving one real gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (page through) and resource (events) plus explicit scope: org-wide by default, or narrowed to one resource via an `id` of the form `<type>:<uuid>`. It does not name the potentially confusable sibling `get_email_events`, so an agent must infer the distinction from scope alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly separates the two modes (with `id` = single resource, without `id` = whole org), names the supported narrowing types, and gives the alternative workflow for following a call: loop on `next_cursor` rather than expecting a stream. It explicitly rules out the streaming interpretation with 'This is **not** a streaming subscription'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_numberGet a numberA
Read-onlyIdempotent
Inspect

Fetch one dedicated number by id: its state, capabilities and which agents answer its calls and texts. number_id comes from list_numbers.

    Returns the ``PhoneNumberResponse`` as a dict, or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
number_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent and non-destructive, so safety is covered. The description adds behavior beyond that: the return is a PhoneNumberResponse dict or an {"error": "<message>"} envelope, which tells the agent to expect in-band errors rather than exceptions. It could still say more about lookup-miss behavior, but this is solid for a read tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, no filler, with the identity and scope stated before the return-shape detail. Every clause carries information the agent cannot get from structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be spelled out, yet the description still flags the error variant, which is the part an agent most needs. For a single-parameter read tool with full annotation coverage, nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% for the single number_id parameter, but the baseline for a 1-param tool is high. The description compensates by stating provenance ("number_id comes from list_numbers"), which the bare string schema does not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb and resource ("Fetch one dedicated number by id") plus a scoping qualifier ("one") that separates it from list_numbers. It also enumerates what the payload contains (state, capabilities, answering agents), so the agent knows exactly what it gets back.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description ties itself to list_numbers as the source of number_id, which implicitly defines the workflow: list first, then get. It does not explicitly state exclusions or when to prefer it over list_numbers, but the "one by id" framing makes the distinction inferable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_smsGet a text messageA
Read-onlyIdempotent
Inspect

Fetch the current state of one SMS by id.

    Use this after ``send_sms`` to check delivery status.

    Example:
        get_sms(sms_id="...")
    
NameRequiredDescriptionDefault
sms_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds a little context — the value is a "current state" snapshot rather than history — but says nothing about behavior for an unknown id or staleness guarantees.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose in one sentence, then the usage note. The example adds little over the schema's required field and is mild waste, but overall the description is tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and annotations cover the safety profile. For a one-parameter read tool the only real remaining gap is how to obtain a valid sms_id.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter has no type detail beyond "string". The description only implies the id is an SMS identifier and shows a placeholder example, without format, prefix, or source of the id.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: "Fetch the current state of one SMS by id." That clearly separates it from list_sms (many) and send_sms (write), though it never names a sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use this after ``send_sms`` to check delivery status" gives a concrete trigger and names the related tool. It lacks an explicit when-not clause (e.g., use list_sms to enumerate messages), so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_verificationGet a verificationA
Read-onlyIdempotent
Inspect

Fetch one verification and its state. Use it to poll.

    There is no notification, and review takes business days. Poll every
    few minutes to hours, not every few seconds; the state refreshes from
    the carrier at most once a minute.

    On ``approved``: call quote_numbers again. The offer is now
    ``ready``; then acquire_number. On ``rejected``: read
    ``rejection_reason``, ask the user, dismiss it with
    cancel_verification, then submit a new one. ``verification_id`` comes
    from submit_verification or list_verifications.

    Returns ``{"id", "state", "rejection_reason", ...}`` or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
verification_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only/idempotent/non-destructive, but the description adds behavior the annotations cannot convey: no push notification, business-day review latency, and an upstream carrier refresh cap of once per minute. It also discloses the return shape including an error form, which is important for polling loops.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then cadence, then state-driven workflow, then return shape — a sensible ordering. Somewhat long for a single-parameter read, but each block (polling policy, next-step routing) carries actionable information rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A read-only polling tool with one required param and an output schema; the description covers purpose, polling behavior, latency expectations, state transitions, and next-step routing. Nothing an agent needs in order to call it correctly or act on the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% for the single parameter, but the description compensates by stating provenance: 'verification_id comes from submit_verification or list_verifications.' That is the only real semantic question for this ID, though it does not describe format/validation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource: 'Fetch one verification and its state.' It immediately separates itself from siblings by naming the surrounding tools (submit_verification, list_verifications, cancel_verification, quote_numbers, acquire_number) and its role in that lifecycle.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use it ('Use it to poll'), why polling is required ('There is no notification, and review takes business days'), and gives concrete cadence guidance ('every few minutes to hours, not every few seconds'). It also prescribes next actions per state (approved → quote_numbers; rejected → cancel_verification then resubmit), which is richer than a simple use/don't-use rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_verification_requirementsGet verification requirementsA
Read-onlyIdempotent
Inspect

Read what the carrier needs to verify the organization before it can buy a number. Call this when quote_numbers shows an offer with readiness == "verification_required". Read-only.

    ``country_code`` is ISO alpha-2 (for example ``"GB"``). ``number_type``
    is ``local``, ``mobile``, ``national`` or ``toll_free``.
    ``subject_type`` is required: ``person`` (the user) or ``business``
    (the user's company). Never guess it: ask the user "you or your
    company?". The result's ``subject_types`` lists what the carrier
    accepts. The organization may hold one verification of each. ``quote_id`` is the
    offer's ``quote_id`` from quote_numbers. It is required for
    ``purpose='number'``: the form is the one for that offer.

    ``purpose`` is ``number`` (default, to buy a number) or ``sms``.
    ``purpose='sms'`` registers the organization to text US numbers from a
    US number (country_code US, number_type local). Fees are charged from
    credit per step: when the details are submitted, when the carriers
    start their review, then monthly after approval. If the error says to pass
    ``number_id``, pass the ``id`` of one of the organization's US numbers
    from list_numbers.

    Returns ``required`` (false means no verification is needed and
    submit_verification would fail), ``fields`` (values to collect),
    ``documents`` (slots, each with ``options``), ``address_required``.
    A field of kind ``choices`` takes several of its ``options``: send
    their keys joined by commas (for example
    ``"CUSTOMER_CARE,DELIVERY_NOTIFICATION"``), between ``min_choices``
    and ``max_choices`` of them.
    A field with ``max_length`` takes at most that many characters,
    counted in UTF-16 code units (an emoji counts as 2); a longer value
    is refused (422).
    Skip any document slot whose ``needs_input`` is false: do not send it.

    Ask the USER for every value and every file. Never invent, guess or
    infer personal or company data. Never reuse data from another task.

    Errors come back as ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
purposeNonumber
quote_idNo
number_idNo
number_typeYes
country_codeYes
subject_typeYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, but the description adds substantial workflow context: fees are charged per step for SMS, required=false means submit_verification would fail, and invalid field lengths are rejected with 422. It also warns never to invent or reuse personal data, which is important behavioral guidance 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.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Despite its length, the description is front-loaded with purpose and trigger condition, then proceeds through parameter meaning, return structure, validation rules, and data-handling constraints. Every section earns its place given six parameters with zero schema documentation and a multi-step verification workflow.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, but the description still summarizes the key return fields an agent must act on: required, fields, documents, address_required, subject_types, and choices/min_choices/max_choices semantics. Combined with the detailed parameter and error guidance, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the full burden and does so completely: country_code is ISO alpha-2, number_type lists the four accepted values, subject_type explains person vs business and requires asking the user, quote_id is required for purpose='number', number_id is the fallback for certain SMS errors, and purpose defaults to number.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: read what the carrier needs to verify the organization before buying a number. It also names the sibling workflow condition from quote_numbers, so an agent can distinguish it from submit_verification, get_verification, and quote_numbers without opening another schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to call this when quote_numbers returns readiness == "verification_required", and distinguishes purpose='number' from purpose='sms'. It also gives the exact fallback for number_id and says to skip document slots with needs_input=false.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_agentsList agentsA
Read-onlyIdempotent
Inspect

List the workspace's saved agents: the brains that answer calls and texts on its numbers, and that place_call can use via agent_id.

    Returns ``{"items": [{"id", "name", "system_prompt", "first_message",
    "ai_disclosure", "ai_disclosure_line", "voice_config", "tools",
    "max_duration_seconds", "handover_max_duration_seconds", "voice_enabled",
    "sms_enabled", "status", "handover_contacts"}, ...]}``.
    
NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive behavior; the description adds workspace scope, the semantic role of agents, and the returned fields. It does not mention pagination, rate limits, or empty-list behavior, but the annotation coverage lowers the burden.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence front-loads purpose effectively, but the second sentence reproduces a long return field list even though an output schema exists. That makes the description more verbose and redundant than necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only list tool with rich annotations and an output schema, the description covers purpose, workspace scope, the semantic role of agents, and return shape. Nothing critical for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero input parameters and schema coverage is 100%, so there are no parameter semantics to explain. Baseline for a zero-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List ... saved agents'), scopes it to the workspace, and explains what an agent is (answers calls/texts, usable by place_call via agent_id). This clearly distinguishes it from get_agent, create_agent, and other siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context for discovering saved agents and notes their relationship to place_call via agent_id. It does not explicitly say when to prefer get_agent for a single agent or mention ordering/exclusions, so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_callsList callsA
Read-onlyIdempotent
Inspect

List recent calls in your organization, newest first.

    Cursor-paginated: pass the previous response's ``next_cursor``
    to fetch the next page. ``status`` (one of queued, dialing,
    ringing, in_progress, completed, failed, busy, no_answer,
    canceled) and ``to`` (E.164) are optional server-side filters.

    Returns a dict ``{"items": [...], "next_cursor": <str|None>}``.
    
NameRequiredDescriptionDefault
toNo
limitNo
cursorNo
statusNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the safety profile is covered. The description adds real context beyond them: newest-first ordering, org-wide visibility, server-side filtering, and cursor-pagination behavior. It omits rate limits and the effect of the default limit, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight paragraphs, front-loaded with purpose then pagination then return shape. Every sentence carries information the schema does not; only minor RST double-backtick artifacts add noise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so restating the return shape is redundant but harmless. For a 4-param read tool with strong annotations, the definition is nearly sufficient; the missing piece is any guidance on `limit` (default 50, max value) and on how pagination terminates when next_cursor is null.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry parameter meaning, and it largely does: it enumerates all valid status values (the schema has no enum), specifies E.164 for `to`, and explains that `cursor` comes from the previous response's next_cursor, none of which is in the schema. The `limit` parameter is never mentioned, leaving one of four parameters undocumented anywhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'List recent calls in your organization, newest first.' The ordering guarantee and org-wide scope make the operation unambiguous. It does not explicitly route the agent away from get_call/list_sms siblings, but the list-vs-get distinction is clear from the content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage mechanics are given (pass next_cursor to page, filters are optional and server-side), which implies the pagination workflow, but there is no explicit statement of when to prefer this over get_call or when-not to use it. The agent must infer routing from the tool names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_contactsList contactsA
Read-onlyIdempotent
Inspect

List the workspace's contacts: org members (with their phone/email) plus manually saved contacts. Use lookup_contact for name searches.

    ``q`` optionally filters server-side (matches name/email/phone).
    ``limit`` caps the page (server default 100, max 500).

    Returns ``{"items": [{"id", "kind", "name", "phone_e164", "email",
    "role"}, ...]}`` — ``kind`` is ``"member"`` (id ``member:<user_id>``,
    ``role`` set) or ``"manual"`` (id is the contact's UUID, ``role``
    null).
    
NameRequiredDescriptionDefault
qNo
limitNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent and non-destructive, so the bar is low, yet the description adds substantial context: server-side pagination behavior with a default of 100 and a hard max of 500, plus the two record kinds and their id formats (`member:<user_id>` vs UUID). That is exactly the kind of operational detail annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The scoping line is front-loaded, alternatives come second, and parameter detail follows in a natural order. The only waste is the return-shape block, which restates information an output schema already supplies, though it does add the `kind`/`id` semantics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter read tool with full annotation coverage, nothing needed to call it correctly is missing: scope, alternative, filter semantics, pagination caps and record-kind meaning are all present. The return-shape paragraph is redundant against the output schema but harmless.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden and does: `q` is documented as a server-side filter matching name/email/phone, and `limit` is documented with both the server default and the maximum. These are semantics the schema (bare `string`/`integer`) provides nowhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb and resource and defines the scope precisely: 'org members (with their phone/email) plus manually saved contacts.' It also points at the sibling tool that handles the search case, so the agent can distinguish list_contacts from lookup_contact without reading either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly routes name searches to lookup_contact, which is the key decision an agent faces among ~35 siblings. It stops short of a full when/when-not statement, and there is mild tension because `q` is also said to match name, so the agent must infer the boundary (filter vs. search).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_email_domainsList email domainsA
Read-onlyIdempotent
Inspect

List the addresses this workspace can send email from. Call this BEFORE send_email when you do not already know the from_ address — do not guess a domain.

    Returns ``{"items": [...], "next_cursor": ..., "default_from": ...}``.
    Each item carries ``domain``, ``kind`` (``"custom"`` or
    ``"hail_mail"``) and ``verification_status``; only ``"verified"``
    rows can send. A ``custom`` item's ``domain`` is a bare DNS name
    that accepts any local-part (``sales@acme.com``); a ``hail_mail``
    item's ``domain`` is already a full address.

    ``default_from`` is the address a ``send_email`` with no ``from_``
    goes out as. It is null when the workspace has several verified
    identities — then ``send_email`` rejects a missing ``from_`` and you
    must pass one from ``items``.

    Example:
        list_email_domains()
    
NameRequiredDescriptionDefault
limitNo
cursorNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it read-only, and the description adds the non-obvious rules: only 'verified' rows can send, custom domains are bare DNS names accepting any local-part while hail_mail domains are full addresses, and send_email rejects a missing from_ when there are multiple verified identities. These are real behavioral constraints beyond structured data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then the when-to-use rule, then return shape, then the domain-kind semantics and the default_from edge case. Dense but every block earns its place; the shape could be slightly tighter, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, usage gating, return shape (even though an output schema exists), field semantics, and the default_from null edge case — more than enough for a read-only list tool. The only gap is pagination parameter behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description should compensate for limit and cursor. It only touches pagination indirectly by showing next_cursor in the return shape; neither limit nor cursor semantics (page size, default, how to resume) are explained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the addresses this workspace can send email from') and scopes it to the workspace, which clearly separates it from send_email and the other listing siblings. An agent knows exactly what it will get without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to call this BEFORE send_email when the from_ address is unknown and warns 'do not guess a domain', naming both the trigger and the alternative misuse. It also states the follow-up condition (pass a from_ from items when default_from is null).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_emailsList emailsA
Read-onlyIdempotent
Inspect

List emails in your organization, newest first.

    Cursor-paginated: pass the previous response's ``next_cursor`` to
    fetch the next page. Two optional server-side filters:

    * ``direction`` — ``outbound`` or ``inbound``. Pass
      ``direction="inbound"`` to read replies and other received mail.
    * ``status`` — one of ``queued``, ``sent``, ``failed``,
      ``bounced``, ``complained``, ``received``.

    Items are trimmed summaries (no message body). Call ``get_email``
    with an item's ``id`` to read the full body.

    Example:
        list_emails(direction="inbound")

    Returns ``{"items": [...], "next_cursor": <str|None>}`` on success,
    or ``{"error": "<message>"}`` instead.
    
NameRequiredDescriptionDefault
limitNo
cursorNo
statusNo
directionNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint/idempotentHint already covering the safety profile, the description adds what the annotations cannot: items are trimmed summaries without message bodies, responses are cursor-paginated via next_cursor, and errors come back as {"error": ...} rather than throwing. That is meaningful behavioral context beyond structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core statement, then pagination, then filters as scannable bullets, then the escalation path, then return shape. Every sentence carries distinct information; nothing is restated from the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Pagination, filter semantics, item granularity, return shape, and the follow-up call are all covered, and an output schema exists for deeper shape detail. The one omission is the `limit` parameter's meaning and maximum, which matters for a list tool with server-side pagination.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden and does so for the two ambiguous filters, enumerating accepted values for both direction (outbound/inbound) and status (queued, sent, failed, bounced, complained, received) plus how cursor works. It leaves `limit` (default 50) completely undocumented, so one of four parameters is still unexplained anywhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("List emails in your organization") plus ordering ("newest first"), which is scope detail an agent cannot infer from the name. It is clearly distinguishable from get_email (body retrieval) and list_email_domains among the siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use this list tool for summaries and "Call ``get_email`` with an item's ``id`` to read the full body." It also names the concrete scenario for the inbound filter ("read replies and other received mail") and provides an example call.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_number_regionsList number search regionsA
Read-onlyIdempotent
Inspect

List the US state and Canadian province codes that quote_numbers accepts as region (optional, with city).

    Returns ``{"regions": [{"country_code", "code", "name"}]}``, such as
    ``{"country_code": "US", "code": "AZ", "name": "Arizona"}``, or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds value beyond that by disclosing the exact response envelope ({"regions": [...]}) and the {"error": "<message>"} failure shape, which is real behavioral context an agent cannot get from annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, front-loaded with what is listed and immediately followed by the return shape and a concrete example. Nothing is redundant and no sentence could be dropped without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read-only lookup, the description covers purpose, linkage to quote_numbers, return structure, and the error case. With an output schema present it need not do more, and nothing required for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description still adds meaning by explaining how the returned `code` values are consumed as the `region` argument of quote_numbers, which helps the agent use the output correctly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (list the region codes that quote_numbers accepts as `region`) and ties the resource to a named sibling, so it is clearly not one of the other list_* tools. The example entry makes the granularity unambiguous: state/province codes, not phone numbers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The reference to quote_numbers accepting these codes as `region` (optionally with `city`) gives a clear implicit context: call this before filtering a quote by region. It does not spell out an explicit 'use this instead of X' rule or state that no parameters are needed, but the surrounding workflow is easy to infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_numbersList numbersA
Read-onlyIdempotent
Inspect

List the workspace's dedicated phone numbers, newest first.

    ``limit`` is 1..200 (default 50). Pass the returned ``next_cursor``
    as ``cursor`` for the next page.

    Returns ``{"items": [{"id", "e164", "country_code",
    "number_type", "capabilities", "provisioning_state", "voice_agent_id",
    "sms_agent_id", ...}], "next_cursor"}``, or ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
limitNo
cursorNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive, closed-world behavior, so the description needn't restate safety. It adds real context beyond that: default ordering (newest first), the 1..200 limit bound with default 50, cursor-based pagination, and the error return shape.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose, then pagination rules, then return shape — easy to scan and free of filler. The detailed return-value block is somewhat redundant given an output schema exists, costing a little tightness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter read listing, everything needed to invoke it correctly is present: scope, ordering, pagination loop, and error behavior. The only excess is restating the response object that the output schema already defines.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden and does: it gives the limit range (1..200, default 50) and explains that cursor takes the previously returned next_cursor. Both parameters are fully operable from the prose alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('List the workspace's dedicated phone numbers') and adds a meaningful scope/ordering detail ('newest first'). It implicitly distinguishes from siblings like list_number_regions or quote_numbers by saying 'dedicated' numbers, but never names an alternative explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent infers this lists provisioned numbers in the workspace. There is no explicit 'use this when…' or exclusion such as 'for a single number use get_number, for purchasable numbers use quote_numbers', even though the sibling list is crowded with number-related tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_smsList text messagesA
Read-onlyIdempotent
Inspect

Page through recent SMS messages for your organization.

    ``status`` filters to one of: queued, sent, delivered, failed,
    undelivered, received. ``to`` filters to messages sent to a
    specific E.164 number. Paginate with the returned
    ``next_cursor``.
    
NameRequiredDescriptionDefault
toNo
limitNo
cursorNo
statusNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, and closed-world, so the safety profile is covered. The description adds real behavioral detail beyond that: the valid status values, E.164 formatting for `to`, and cursor-based pagination via `next_cursor`. It stops short of defining what "recent" means or any result window.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, each carrying distinct information (scope, status values, to-format, pagination), with the core purpose front-loaded. No filler or repetition of schema fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't explain return shapes, and it correctly focuses on filtering and pagination. The remaining gaps — undefined "recent" window and unstated `limit` behavior — are small but real for a paginated listing tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry the load, and it does for three of four parameters: `status` gets an explicit value list, `to` gets E.164 format semantics, and `cursor` is tied to the returned `next_cursor`. Only `limit` is left undocumented, which is a minor gap against the schema default of 50.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: paging through recent SMS messages for the organization. The verb distinguishes it from get_sms (single retrieval) and send_sms (write), even though those siblings aren't named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the description of filters and pagination, giving the agent a clear picture of the listing use case. However, it never states when to prefer this over get_sms for a known message or how to narrow results beyond the three filters.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_verificationsList verificationsA
Read-onlyIdempotent
Inspect

List the organization's carrier verifications, newest first.

    ``purpose`` is ``number`` or ``sms``; only that kind is listed.
    Omit to see every registration. ``purpose='sms'`` lists the
    registrations to text US numbers from a US number.

    Returns ``{"items": [{"id", "country_code", "number_type",
    "subject_type", "subject_name", "purpose", "state",
    "rejection_reason", "created_at",
    "updated_at", "submitted_at", "approved_at", "confirmation",
    "step", "identity_confirmed"}]}``. ``step`` says where a US texting
    filing in progress is: ``confirm_identity``, ``filing`` or
    ``carrier_review``. ``identity_confirmed`` on a person's newest
    filing, when cancelled or rejected: the next one with the same person
    needs no code. Dismiss a rejected filing first.
    ``state`` is ``awaiting_review``, ``submitting``, ``submitted``,
    ``approved``, ``rejected`` or ``cancelled``. Use it to check whether a
    submission already exists before submitting again. ``confirmation``
    ``code``: call confirm_verification with the code the carrier texted
    the person.

    Errors come back as ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
purposeNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only annotations, the description discloses the return shape, state values, step semantics for in-progress US texting filings, identity_confirmed behavior, and error format. This provides substantial behavioral context for interpreting results and deciding next actions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core listing behavior and remains focused, but it includes a full return-shape listing that partly duplicates the output schema. The remaining detail is dense and mostly earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has one optional parameter, an output schema, and rich annotations, the description supplies the remaining operational context: filtering semantics, result interpretation, state meanings, workflow guidance, and error behavior. Nothing essential for correct invocation appears missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the purpose parameter has no enum, but the description fully compensates by explaining the accepted values number and sms, what omission means, and the specific meaning of sms. This adds important meaning beyond the input schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: list the organization's carrier verifications, newest first. It is clearly distinguishable from get_verification and submit_verification by the list semantics, though it does not explicitly name those siblings as alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context: use state to check whether a submission already exists before submitting again, and dismiss a rejected filing first. It also points to confirm_verification when a confirmation code is present, but it does not explicitly state when not to use this tool or name every related alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lookup_contactLook up a contactA
Read-onlyIdempotent
Inspect

Find a contact by name, email, or phone fragment. Resolve a person to their phone_e164/email BEFORE calling place_call, send_sms, or send_email — do not guess a contact's number.

    Returns up to 10 matches, same item shape as ``list_contacts``.

    Example:
        lookup_contact(query="maya")
    
NameRequiredDescriptionDefault
queryYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description adds genuinely new behavior: a hard cap of up to 10 matches and a reference point for item shape (same as list_contacts). It does not say what happens on zero matches or whether matching is exact vs substring beyond 'fragment,' which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short, front-loaded sentences plus a one-line example; the resolution precondition precedes the return-value note, and nothing is redundant with the title or schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter lookup with an output schema, the description supplies the only things the schema can't: accepted query forms, result cap, cross-tool sequencing, and return shape. Nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% for the single `query` param, so the description must compensate; it does by enumerating the three accepted key types (name, email, phone fragment) and showing a usage example. It still doesn't specify matching semantics (case sensitivity, substring vs prefix) or format expectations for each key type.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Find a contact'), names the accepted lookup keys (name, email, phone fragment), and distinguishes it from list_contacts and create_contact by describing resolution rather than enumeration or creation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit precondition: resolve to phone_e164/email BEFORE calling place_call, send_sms, or send_email, plus the negative instruction 'do not guess a contact's number.' It names the concrete alternative risk (guessing) and the sibling tools it feeds into.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

place_callPlace a phone callAInspect

Originate an outbound phone call.

    Provide ``system_prompt`` (mode A — Hail's bundled fallback LLM
    uses this prompt) or ``llm`` (mode B — bring your own
    OpenAI-compatible endpoint as
    ``{"base_url": ..., "api_key": ..., "model": ...}``), or both, or
    ``agent_id`` (a saved agent from ``list_agents`` supplies the
    prompt, first message, AI line, voice and tools; fields you pass
    here win). At least one is required. Passing both runs your prompt on your
    own endpoint: it receives Hail's voice preamble plus your prompt
    as the leading system message.

    ``to`` must be E.164 (e.g. ``+14155551234``). ``from_`` is
    optional and defaults to the first active number on your org.
    ``first_message`` is spoken verbatim on pickup; omit it to let
    the agent open the conversation itself — it reacts to how the
    call was answered, or introduces itself after silence.
    ``language`` sets the call's spoken language for speech-to-text,
    text-to-speech, and turn detection, as a lowercase ISO 639-1 code
    (e.g. ``"da"``); 39 languages are supported (server rejects others
    with 422); omit for English. STT provider selection is
    console-BYO-only (no per-call override); configure it on the
    organization to pin a provider.
    ``ai_disclosure=False`` skips the spoken "this is an AI
    assistant" line at the start of the call. Leave enabled unless
    the user has verified it is not required for this call — US
    artificial-voice calls (47 CFR 64.1200(b)(1)) and several AI
    bot-disclosure laws require it, and Hail does not verify this.
    The agent still identifies itself as an AI if asked.
    ``recording_enabled``: omit it to follow the agent, then the
    workspace recording setting. ``true`` records this call and
    ``false`` does not, whatever the workspace setting. Pass it only
    when the user asked for or against a recording.
    ``metadata`` is free-form JSON attached to the call record.
    ``tools`` are the agent tools to allow on this call. Omit for all
    available; pass ``[]`` to disable.

    ``recipient_consent`` is required and must be the JSON boolean
    ``true`` (strings and numbers are refused): attest that you (the caller
    triggering this request) have obtained the lawful consent needed
    to contact this recipient. The API rejects the request (422) if
    this is not ``true`` — Hail does not verify consent for you, you
    are responsible for having a lawful basis (TCPA / ePrivacy / GDPR
    as applicable). Set ``message_type="marketing"`` for promotional
    calls (this additionally requires a non-empty ``consent_source``
    describing how/where consent was obtained) — leave as the default
    ``"informational"`` for transactional/service calls.

    ``idempotency_key`` defaults to a fresh UUID per invocation
    and is returned in the response under ``idempotency_key`` — to
    retry *this* exact request (rather than dispatch a second call),
    pass the value back on the retry. A new key is a new call.

    Example:
        place_call(to="+14155551234",
                   recipient_consent=True,
                   system_prompt="You are scheduling a haircut.",
                   first_message="Hi, I'm calling on behalf of Alex.")

    Returns the API's ``CallResponse`` as a dict (id, status,
    from_e164, to_e164, ...). On failure returns
    ``{"error": "<message>"}`` instead.
    
NameRequiredDescriptionDefault
toYes
llmNo
from_No
toolsNo
agent_idNo
languageNo
metadataNo
message_typeNoinformational
ai_disclosureNo
first_messageNo
system_promptNo
consent_sourceNo
idempotency_keyNo
recipient_consentYes
recording_enabledNo
consent_obtained_atNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare it is a non-readonly, open-world, non-idempotent call, and the description adds substantial context beyond that: 422 rejection for bad language or missing consent, legal disclosure obligations from 47 CFR 64.1200(b)(1), recording setting precedence, idempotency-key retry semantics, and the error-dict failure shape. This is exactly the behavioral detail an agent needs before mutating anything.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is long but organized: purpose and mode selection first, then parameters in rough order of importance, then an example, then return shape. A few passages — the STT console-BYO note and repeated consent warnings — could be tightened, but almost every sentence carries operational or legal significance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter, legally regulated outbound-call tool, the description covers mode selection, hard validation rules, compliance requirements, recording precedence, retry semantics, and an example. An output schema exists, so the added CallResponse/error explanation is a bonus rather than a necessity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% across 16 parameters, so the description must carry the full burden and it does — it explains the system_prompt/llm/agent_id interplay and precedence, E.164 format for to, from_ default behavior, language ISO code constraints, ai_disclosure and recording_enabled precedence, tools defaults, metadata, consent_source, and idempotency_key semantics. Only consent_obtained_at goes undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first line states a specific verb and resource — 'Originate an outbound phone call' — which is unmistakable and inherently distinct from get_call, list_calls, send_sms, and the other siblings. No ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives rich conditional guidance: mode A vs mode B vs agent_id, when to pass recording_enabled ('only when the user asked for or against'), when to use ai_disclosure=False, and when message_type should be marketing. It does not explicitly compare against channel alternatives like send_sms, so it stops short of full when/when-not/alternatives coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

quote_numbersQuote phone numbersA
Read-onlyIdempotent
Inspect

Compare live phone-number offers from the carriers. Read-only: it buys nothing and charges nothing.

    ``country_code`` is an ISO alpha-2 code such as ``"US"``.
    ``capabilities`` is ``["voice"]``, ``["sms"]`` or both (default).
    ``number_type`` is ``local``, ``mobile``, ``national`` or
    ``toll_free``; omit it to compare all types.
    ``area_code`` is an area code or the first digits of the number, as
    dialed in the country: ``"020"`` (London), ``"480"`` (Arizona).
    ``city`` is a city name such as ``"London"``. Each offer has
    ``locality`` and ``region`` (such as ``"Phoenix"``, ``"AZ"``): check
    them, since city names repeat across states. ``region`` (optional,
    with ``city``) is a US/CA state code; list_number_regions lists them.
    Omit all three to search the whole country.

    Returns ``{"offers": [...], "recommended_quote_id", "expires_at"}``.
    Each offer has ``e164``, ``number_type``,
    ``capabilities``, ``monthly_cents``, ``setup_cents``, ``readiness``,
    ``requirements``, ``subject_types``, ``verifications`` and
    ``quote_id``. Money fields are cents (USD).
    Quotes expire in 10 minutes (``expires_at``); quote again after that.

    ``subject_types`` says who may verify for the number: ``person``
    (the user), ``business`` (the user's company), or both; empty when no
    verification is needed. ``verifications`` lists the verifications
    the offer can be bought with (``id``, ``state``, ``subject_type``,
    ``subject_name``), approved first: those of an accepted subject type
    still under review, and the approved ones the carrier still accepts
    for the offer. ``subject_name`` is the person's or company's name from the
    verification form. When several are approved, show the user the
    names and ask which one buys the number; pass its ``id`` as
    ``verification_id`` to acquire_number.

    An offer with ``readiness == "verification_required"`` cannot be
    bought until the organization is verified. Ask the user "you or your
    company?" to pick the ``subject_type`` (one of ``subject_types``).
    Call get_verification_requirements, ask the user for the details,
    then submit_verification, both with the offer's ``quote_id`` and that
    ``subject_type``, and poll get_verification (review takes business
    days). ``requirements``
    lists what the carrier needs. Prefer an offer whose
    ``readiness`` is ``"ready"``; ``recommended_quote_id`` points at the
    best one, or is null if none is ready.

    An offer with ``by_request: true`` has no ``e164``: support orders
    that number by hand. acquire_number refuses it; tell the user to ask
    support. Its ``quote_id`` still works for verification.

    Errors come back as ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
cityNo
regionNo
area_codeNo
number_typeNo
capabilitiesNo
country_codeYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the annotations: quotes expire in 10 minutes, money is in cents, by_request offers cannot be acquired directly, verification-required offers need a workflow, and errors are returned as an error object. These details are critical for correct invocation and do not contradict the read-only annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but appropriately structured and front-loaded with the core purpose and read-only guarantee. Some return-field detail is redundant with the output schema, but the information is organized and largely earns its place given the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete for a complex quoting tool: it covers all parameters, return semantics, expiration, verification workflows, error format, and edge cases like by_request offers. Together with the existing output schema and annotations, an agent has everything needed to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description fully compensates by explaining every parameter: country_code format, capabilities options and default, number_type values, area_code examples, city usage, and region semantics. It also explains interactions such as omitting all location filters to search the whole country.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: compare live phone-number offers from carriers. It also clarifies the read-only nature and distinguishes quoting from buying, so an agent can identify the tool's role without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context, including how to handle verification-required offers, by-request offers, quote expiration, and passing verification_id to acquire_number. It does not explicitly state when not to use this tool versus siblings like list_numbers, so it falls short of a full when/when-not/alternatives guide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

release_numberRelease a numberA
DestructiveIdempotent
Inspect

Release a phone number. DESTRUCTIVE and permanent.

    Calls and texts to the number stop. This month's fee and any earlier
    months are still billed. There is no refund. The number may not be
    recoverable.
    Ask the user before calling this.

    ``confirm_e164`` must equal the number's ``e164`` (for example
    ``"+14155550100"``). The tool reads the number first and refuses with
    ``{"error": ...}`` on a mismatch, without releasing anything. A number
    whose order is still pending cannot be released (409). A number whose
    order failed was never bought: the call only hides it from the list
    and returns ``{"dismissed": true, "number_id", "e164"}``.

    Returns ``{"released": true, "number_id", "e164"}``, or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
number_idYes
confirm_e164Yes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the destructiveHint annotation: it explains that calls/texts stop, that current and prior months are still billed with no refund, that the number may be unrecoverable, and that a mismatch aborts before any release happens. The 409 pending-order case and the dismissed-failed-order outcome are precisely the side effects an agent cannot infer from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the destructive warning, then progressively less critical detail. Some return-shape text duplicates the output schema, but the error and dismissal paths add real value, so almost every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive two-parameter mutation with full annotation coverage and an output schema, this covers everything an agent needs: consequences, billing, confirmation semantics, refusal conditions, and failure outcomes. No material gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry the burden, and it does for the risky parameter: confirm_e164 must equal the number's e164, with a concrete format example and the mismatch-abort behavior spelled out. number_id is left undefined, but its meaning is self-evident from the resource context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Release a phone number") and immediately flags the consequence ("DESTRUCTIVE and permanent"). This is clearly distinguishable from siblings like acquire_number, get_number, or cancel_verification 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit guardrail ("Ask the user before calling this") and describes when the tool refuses (pending order → 409) and the special failed-order path that only dismisses rather than releases. It doesn't name a sibling alternative, but the when/when-not conditions are clear enough that an agent knows exactly when the call will and won't do what it expects.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

route_numberRoute a number to an agentA
Idempotent
Inspect

Choose which agent answers a number's calls and texts.

    ``voice_agent_id`` makes the number answer calls with that agent
    (Hail registers it for inbound at the carrier and LiveKit);
    ``clear_voice=True`` stops answering calls. ``sms_agent_id`` makes
    the agent reply to texts; ``clear_sms=True`` stops that. A field
    left out keeps its value. ``number_id`` comes from GET /numbers.

    Returns the updated ``PhoneNumberResponse`` as a dict, or
    ``{"error": "<message>"}``.
    
NameRequiredDescriptionDefault
clear_smsNo
number_idYes
clear_voiceNo
sms_agent_idNo
voice_agent_idNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotent=true and destructiveHint=false, but the description adds real context beyond them: Hail registers the agent at the carrier and LiveKit, and clear_voice/clear_sms stop answering/reply behavior. This exposes the external side effects of the mutation. It omits permission or failure-mode details, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose sentence is front-loaded, and the parameter walkthrough is compact and ordered. The parenthetical about carrier/LiveKit registration is slightly verbose but carries real information, so there is little waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With idempotency and non-destructiveness in annotations and an output schema present, the description supplies the mutation semantics and the error shape ({'error': ...}) an agent needs. The remaining gap is the conflict behavior when both set and clear flags are provided on the same channel.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden, and it covers all five parameters with concrete meaning: voice_agent_id assigns answering, clear_voice stops answering, sms_agent_id assigns texting, clear_sms stops it, and number_id is sourced from GET /numbers. It doesn't address what happens if voice_agent_id and clear_voice are set together, which is the main remaining gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb and resource: choosing which agent answers a number's calls and texts. It clearly separates this from read-only siblings like get_number or list_numbers, so an agent can identify it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains the operational semantics for each mode (assign vs. clear) and the crucial partial-update rule: 'A field left out keeps its value.' It also gives provenance for number_id ('comes from GET /numbers'). It stops short of naming explicit when-not conditions or alternatives, but the context for use is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

send_emailSend an emailAInspect

Send an outbound email through your configured SES sender.

    ``to`` is a non-empty list of RFC-style email addresses. At
    least one of ``body_text`` / ``body_html`` is required (both
    is fine — multipart-alternative). Prefer including
    ``body_html``: open and click tracking only works for emails
    with an HTML body. A plain-text-only email still gets sent,
    delivered, and bounce events, but opens and clicks are never
    tracked. ``cc``, ``bcc``, and
    ``reply_to`` are optional and follow the usual mail
    conventions. Hail sets no ``reply_to`` of its own — to have
    replies reach the human running this session, call ``whoami``
    and pass their ``email``.

    ``recipient_consent`` is required and must be the JSON boolean
    ``true`` (strings and numbers are refused): attest that you (the caller
    triggering this request) have obtained the lawful consent needed
    to email this recipient. The API rejects the request (422) if
    this is not ``true`` — Hail does not verify consent for you. Set
    ``message_type="marketing"`` for promotional email (this
    additionally requires a non-empty ``consent_source`` describing
    how/where consent was obtained) — leave as the default
    ``"informational"`` for transactional/service email.

    ``from_`` is optional only while the workspace has one verified
    sender identity. With several, omitting it returns 422 listing
    them — call ``list_email_domains`` and pass one. With none, the
    server auto-mints a per-org hail-mail address of the form
    ``<user>+<org>@<base>`` if the operator configured
    ``HAIL_MAIL_BASE_DOMAIN`` (the ``<org>`` part is derived from your
    organization id; the ``<user>`` part comes from ``HAIL_MAIL_FROM``
    / ``HAIL_MAIL_DEFAULT_USER_PREFIX``, or an explicit row created
    via ``POST /email-domains``). When supplied, ``from_`` must match
    a verified row already in ``email_domains`` (register one with
    the website console or ``POST /email-domains``).

    ``from_name`` is an optional display name rendered on the
    From: header ("Acme Billing <billing@acme.com>"). Control
    characters are rejected.

    ``metadata`` is free-form JSON attached to the email record.

    ``idempotency_key`` defaults to a fresh UUID and is returned
    in the response under ``idempotency_key`` — pass the same
    value on a retry to replay rather than re-send. A new key
    is a new message.

    ``attachment_ids`` are ids returned by ``upload_email_attachment``
    — upload a file first, then pass its id(s) here to attach it.

    Example:
        send_email(to=["alice@example.com"],
                   subject="Welcome",
                   recipient_consent=True,
                   body_text="Thanks for signing up.")

    Returns the ``EmailResponse`` dict (id, status, from_address,
    to_addresses, sent_at, provider_message_id, ...). On failure
    returns ``{"error": "<message>"}`` instead.
    
NameRequiredDescriptionDefault
ccNo
toYes
bccNo
from_No
subjectYes
metadataNo
reply_toNo
body_htmlNo
body_textNo
from_nameNo
message_typeNoinformational
attachment_idsNo
consent_sourceNo
idempotency_keyNo
recipient_consentYes
consent_obtained_atNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare the safety profile (non-read-only, open-world, non-destructive, non-idempotent); the description adds substantial behavioral context beyond that — the 422 consent rejection, that Hail does not verify consent, tracking limitations for text-only mail, the auto-minted per-org sender address, and the from_ resolution failure mode. The 'new key is a new message' note is consistent with idempotentHint=false rather than contradicting it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then organized one paragraph per parameter group, with a compact example. It is long but nearly every sentence corresponds to a real decision the caller must make; the operator-configuration detail about HAIL_MAIL_BASE_DOMAIN is the one stretch that could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter, non-idempotent, consent-gated outbound mutation, the description covers preconditions, failure modes, collaboration steps, and even restates the success/error return shape despite an output schema existing. An agent has everything needed to invoke it correctly on the first attempt.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage across 16 params, the description carries nearly the full burden and does so well: it explains the to/body_text/body_html constraint, cc/bcc/reply_to conventions, the strict boolean type of recipient_consent, consent_source's conditional requirement, from_ resolution rules, and attachment_ids sourcing. The notable gap is consent_obtained_at, which is never mentioned, and subject is left implicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+transport: 'Send an outbound email through your configured SES sender.' It also names the collaborating siblings (upload_email_attachment, list_email_domains, whoami), making it easy to distinguish from get_email/list_emails in the sibling set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit conditional guidance throughout: prefer body_html because tracking requires it, use message_type="marketing" only for promotional mail, call whoami to obtain a reply_to, upload attachments first, and retry with the same idempotency_key. It names alternatives and the conditions that select them rather than leaving routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

send_smsSend a text messageAInspect

Send an outbound SMS.

    ``to`` must be E.164 (e.g. ``+14155551234``). ``body`` is the
    message text. With no ``from_``: destinations where the sender-ID
    carrier delivers a dynamic alphanumeric sender ID unchanged (about
    110 countries, see core/hailhq/core/sender_id_corridors.py) use
    your organization's sender ID
    (or ``HAIL``, the platform default); Australia (+61) may use
    ``HAIL`` instead; every other destination,
    including the US and Canada,
    uses your organization's oldest active SMS-capable number and the
    API returns 422 when there is none.
    SMS never uses the shared voice-call pool.

    ``recipient_consent`` is required and must be the JSON boolean
    ``true`` (strings and numbers are refused): attest that you (the caller
    triggering this request) have obtained the lawful consent needed
    to text this recipient. The API rejects the request (422) if
    this is not ``true`` — Hail does not verify consent for you. Set
    ``message_type="marketing"`` for promotional texts (this
    additionally requires a non-empty ``consent_source``) — leave as
    the default ``"informational"`` for transactional/service texts.

    ``idempotency_key`` defaults to a fresh UUID and is returned in
    the response under ``idempotency_key`` — pass the same value on
    a retry to replay rather than re-send.

    Example:
        send_sms(to="+14155551234", body="Your order shipped!",
                 recipient_consent=True)

    Returns the ``SmsResponse`` dict (id, status, from_e164,
    to_e164, segment_count, ...). On failure returns
    ``{"error": "<message>"}`` instead.
    
NameRequiredDescriptionDefault
toYes
bodyYes
from_No
metadataNo
message_typeNoinformational
consent_sourceNo
idempotency_keyNo
recipient_consentYes
consent_obtained_atNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond annotations by detailing consent requirements, error cases (422), sender-ID routing, idempotency replay behavior, and return format. Annotations already cover safety hints (readOnlyHint, destructiveHint, openWorldHint), and the description adds critical operational context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is fairly long but dense with necessary information. It is front-loaded with the core action and includes an example and return details, though some sections (e.g., the sender-ID logic) could be tightened. Overall, every sentence earns its place given the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with 9 parameters and an output schema, the description covers the most critical aspects: consent, sender-ID behavior, idempotency, and error handling. It omits metadata and consent_obtained_at, but given the output schema exists and annotations carry safety hints, the description is nearly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must compensate and does so for most parameters: it explains to (E.164), body, from_ (dynamic routing), recipient_consent (must be boolean true), message_type (marketing vs informational), consent_source, and idempotency_key. However, it omits metadata and consent_obtained_at entirely, leaving two parameters undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (send) and resource (outbound SMS), making the tool's function immediately clear. It does not explicitly differentiate from siblings like send_email or place_call, but the resource distinction is obvious from the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides some usage context, such as setting message_type for marketing and the behavior when from_ is omitted, but it never states when to use this tool versus alternatives (e.g., send_email or place_call). The guidance is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

submit_verificationSubmit a verificationA
Destructive
Inspect

Send the user's personal or company details and identity documents to the carrier for verification. IRREVERSIBLE: once submitted it cannot be cancelled, and the carrier keeps the documents.

    ``attest_authorized``: pass true only if the person or company named
    in these details and documents asked for this submission and gave you
    the details and files in this conversation. Never invent, guess, infer
    or reuse personal data or documents. Anything else: pass false (the
    call then sends nothing).

    ``purpose`` is ``number`` (default) or ``sms``. ``purpose='sms'``
    registers the organization to text US numbers from a US number
    (country_code US, number_type local). The carrier fee is debited from
    credit at filing. Pass the same ``purpose`` to
    get_verification_requirements. For ``purpose='number'``, pass the
    same ``quote_id`` you passed to get_verification_requirements. For
    ``purpose='sms'``, pass the same ``number_id`` if you passed one.

    ``subject_type`` is required: ``person`` (the user) or ``business``
    (the user's company), the same one passed to
    get_verification_requirements. Never guess it: ask the user "you or
    your company?".

    The verification is named after the person or company in the form
    (for example the business name, or the first and last name); it
    comes back as ``subject_name``. The organization may hold several
    verifications of one subject type (several people or companies).

    Steps: 1) call get_verification_requirements. 2) Ask the user for each
    field and file. 3) Call this once. Do not submit twice: a 409 means
    one with the same subject type and name already exists (see
    list_verifications).

    Arguments, as listed by get_verification_requirements:
    ``fields`` is ``{field name: value}``. ``address`` is
    ``{"customer_name", "street", "city", "region", "postal_code",
    "country_code"}`` (all required when ``address_required``).
    ``documents`` is ``{slot: {"option": <option key>, "fields": {...}}}``
    for each slot with ``needs_input``. ``files`` is a list of
    ``{"slot", "content_type", "content_base64"}``, one per slot that
    needs a file; ``slot`` must be a key in ``documents``
    and match letters, digits, - and _ (at most 64).
    ``content_type`` is ``image/jpeg``, ``image/png`` or
    ``application/pdf``. Limits: 10 MiB per file, 29 MiB in total, at
    most 20 files and 20 fields. Compress images to JPG or PNG under about
    7 MiB so the call stays small.

    Returns the verification: ``id``, ``state`` and ``subject_name``.
    Review takes business days and nothing notifies you: poll
    get_verification. If the carrier finds a problem you get
    ``{"error", "problems": [{"loc", "msg"}]}`` and nothing is stored:
    ask the user to fix it, then submit again. After a timeout call
    list_verifications before trying again.
NameRequiredDescriptionDefault
filesYes
fieldsYes
addressNo
purposeNonumber
quote_idNo
documentsYes
number_idNo
number_typeYes
country_codeYes
subject_typeNo
attest_authorizedYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses irreversibility, that the carrier keeps the documents, what attest_authorized=false does, carrier-fee timing, review timing with no notification, 409 duplicate behavior, and the error format when nothing is stored. These specifics are consistent with the destructive, non-idempotent, open-world annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but appropriately sized for an irreversible 11-parameter submission workflow. Purpose and irreversibility are front-loaded, followed by attestation rules, purpose variants, steps, argument shapes, and error handling, with no obvious filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity, nested objects, and zero schema description coverage, it covers the prerequisite call, user interaction, authorization attestation, payload limits, returned fields, errors, retries, and duplicate handling. The minor gap around country_code and number_type is mitigated by the required get_verification_requirements workflow.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates well for most of the 11 parameters: attest_authorized, purpose variants, subject_type, fields, address keys, documents slots, files structure/content types/limits, and quote_id/number_id linkage. It does not fully explain the general semantics or accepted values for country_code and number_type beyond the SMS example.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names the exact verb and resource: sending the user's personal or company details and identity documents to the carrier for verification. Later references to get_verification_requirements, get_verification, and list_verifications make clear how this action differs from its siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit ordered workflow: call get_verification_requirements, ask the user for each field and file, then call this tool once. It also states when not to resubmit and routes a 409 to list_verifications, while naming get_verification for polling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_agentUpdate an agentA
Idempotent
Inspect

Change a saved agent. Safe to repeat: the same call gives the same result.

    Only the fields you pass change; a field left out keeps its value.
    ``status`` is ``"live"`` or ``"paused"``; a paused agent does not
    answer. ``language`` is a lowercase ISO 639-1 code. Pass ``language``
    or ``voice_id`` alone: the other value is kept. ``max_duration_seconds``
    and ``handover_max_duration_seconds`` are 60..3600.
    ``handover_contacts`` replaces the whole list: ``[{contact_id, note}]``
    (max 10) as in ``create_agent``; ``[]`` removes every contact.

    To remove a value, list its name in ``clear_fields``. Allowed:
    ``first_message`` (the agent waits for the caller),
    ``ai_disclosure_line`` (back to the workspace line), ``tools``
    (back to all tools), ``max_duration_seconds`` (back to the workspace
    limit), ``handover_max_duration_seconds`` (back to 1800). Any other
    name is refused. Do not set and clear one field.

    Live calls keep the settings they started with. The change applies
    to the next call or text.

    Returns the updated ``AgentResponse`` as a dict, or
    ``{"error": "<message>"}``.
NameRequiredDescriptionDefault
nameNo
toolsNo
statusNo
agent_idYes
languageNo
voice_idNo
sms_enabledNo
clear_fieldsNo
ai_disclosureNo
first_messageNo
system_promptNo
voice_enabledNo
handover_contactsNo
recording_enabledNo
ai_disclosure_lineNo
max_duration_secondsNo
handover_max_duration_secondsNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations it discloses what actually matters operationally: live calls keep the settings they started with and the change applies to the next call or text, handover_contacts replaces the entire list, and clear_fields reverts specific values to workspace defaults rather than blanking them. It also states the return shape (AgentResponse dict or an error dict), which the annotations do not cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and idempotency are front-loaded, then field-level constraints, then clear_fields, then the live-call caveat and return value — a sensible progression with no filler sentences. It is dense for a 17-parameter tool, but the density is justified by real constraints rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a non-destructive mutation tool with 0% schema coverage and 17 parameters, the description covers the failure-prone paths (clear/set conflicts, list replacement, duration bounds, live-call timing) and even the error return shape despite an output schema existing. The gap is the mundane field semantics it skips, which are largely inferable from names but not stated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 17 parameters, so the description carries the burden and does so for the tricky ones: status enum values, lowercase ISO 639-1 for language, the language/voice_id mutual exclusion, the 60..3600 range on both duration fields, and the [{contact_id, note}] shape with a max of 10 for handover_contacts. Several booleans (sms_enabled, voice_enabled, recording_enabled, ai_disclosure), plus name and system_prompt, are left entirely to the schema titles, which keeps it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb and resource — "Change a saved agent" — which separates it cleanly from create_agent, get_agent, delete_agent and list_agents without ambiguity. The immediately following clause also establishes the partial-update semantics, so an agent knows the operation mode as well as the target.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete operating rules: only passed fields change, do not set and clear the same field, pass language or voice_id alone, and clear_fields accepts only the listed names with everything else refused. It never explicitly routes the agent to create_agent or delete_agent for adjacent tasks, so it stops short of the explicit when-not/alternative guidance a 5 requires.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

upload_email_attachmentUpload an email attachmentAInspect

Upload a file to attach to a future outbound email.

    ``content_base64`` is the file's raw bytes, base64-encoded.
    Returns ``{"id": ..., "filename": ..., "content_type": ...,
    "size_bytes": ...}`` — pass ``id`` in ``send_email``'s
    ``attachment_ids`` list. The id is reusable across many sends
    and expires in 24h if never used. Files over 25MB (combined
    with the message body and any other attachments, per send) are
    rejected — host large files externally and link to them in the
    body instead.
    
NameRequiredDescriptionDefault
filenameYes
content_typeYes
content_base64Yes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (which only say non-readonly, non-destructive, non-idempotent): it discloses the 24h expiry if never used, id reusability across many sends, the 25MB limit counted against body + other attachments per send, and the rejection behavior. Those are exactly the operational constraints an agent would otherwise discover by failing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded in the first sentence, then the parameter note, return shape, id lifecycle, and size limit each get a compact clause. Slightly verbose with reStructuredText markup and a return-shape restatement, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description adds the details that matter for correct invocation — id reuse, expiry window, and combined size budget across body and attachments per send. Nothing an agent needs before calling, or before handling the response, is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry the load; it does for the non-obvious parameter by defining ``content_base64`` as 'the file's raw bytes, base64-encoded'. ``filename`` and ``content_type`` are left to their self-evident names with no format guidance (e.g. MIME type expectations), which keeps it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Upload a file to attach to a future outbound email') and scopes it to future sends, which distinguishes it from send_email and get_email_attachment in the sibling list. An agent can route correctly without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to pass the returned ``id`` into ``send_email``'s ``attachment_ids`` list, which chains this tool to its consumer, and names the alternative path for oversized files ('host large files externally and link to them in the body instead'). It stops short of stating when *not* to call it (e.g. attaching to an already-sent email), so not a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whoamiWho am IA
Read-onlyIdempotent
Inspect

Identify the human whose credentials this session runs under.

    Use it to sign or route mail as that person: pass their address as
    ``send_email(reply_to=...)`` so replies reach them rather than the
    sending domain, which is often an unattended ``noreply@``.

    Returns ``{"auth_kind", "organization_id", "user_id", "email",
    "name"}``. ``user_id``/``email``/``name`` are null when the server
    runs on a shared operator key (``auth_kind="shared"``) — there is no
    human behind it, so send without a ``reply_to``.

    Example:
        whoami()
    
NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/idempotent annotations by disclosing that user_id/email/name can be null when auth_kind="shared", which changes what the caller should do next. The nuance is genuinely useful; only minor gaps remain (no note on failure modes if credentials are invalid).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the one-line purpose, then use case, then return contract. The trailing 'Example: whoami()' adds nothing for a zero-argument tool and could be cut.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even though an output schema exists, the description adds interpretation the schema cannot carry: what auth_kind="shared" means and how to adapt behavior. For a no-param identity tool this is everything an agent needs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4 and there is nothing for the description to disambiguate. It spends its words on return semantics instead, which is the correct allocation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (identify) and precise resource (the human behind the session credentials), which no sibling tool duplicates. An agent can tell immediately this is an identity/introspection call, not a data fetch.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit downstream use (pass the address as send_email(reply_to=...) so replies reach a human) and an explicit when-not path: under auth_kind="shared" there is no human, so send without reply_to. Both the use case and the exclusion are spelled out.

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.

  1. 4 tool updatesv0.30.0
    • Changedacquire_number3 fields changed
      • removedInput schema / properties / provider
        Removed value: -{
        -  "default": "auto",
        -  "title": "Provider",
        -  "type": "string"
        -}
      • addedInput schema / properties / subject_type
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Subject Type"
        +}
      • addedInput schema / properties / verification_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Verification Id"
        +}
    • Changedget_verification_requirements5 fields changed
      • addedInput schema / properties / number_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Number Id"
        +}
      • removedInput schema / properties / provider
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "title": "Provider"
        -}
      • addedInput schema / properties / quote_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Quote Id"
        +}
      • removedInput schema / properties / subject_type / default
        Removed value: -"person"
      • changedInput schema / required
        Previous value: -[
        -  "country_code",
        -  "number_type"
        -]New value: +[
        +  "country_code",
        +  "number_type",
        +  "subject_type"
        +]
    • Changedquote_numbers1 field changed
      • removedInput schema / properties / provider
        Removed value: -{
        -  "default": "auto",
        -  "title": "Provider",
        -  "type": "string"
        -}
    • Changedsubmit_verification6 fields changed
      • addedInput schema / properties / number_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Number Id"
        +}
      • removedInput schema / properties / provider
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "title": "Provider"
        -}
      • addedInput schema / properties / quote_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Quote Id"
        +}
      • addedInput schema / properties / subject_type / anyOf
        Added value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / subject_type / default
        Previous value: -"person"New value: +null
      • removedInput schema / properties / subject_type / type
        Removed value: -"string"
  2. 38 tool updatesv0.29.0
    • First observedacquire_number
    • First observedcancel_verification
    • First observedconfirm_verification
    • First observedcreate_agent
    • First observedcreate_contact
    • First observeddelete_agent
    • First observedget_agent
    • First observedget_call
    • First observedget_email
    • First observedget_email_attachment
    • First observedget_email_events
    • First observedget_email_raw
    • First observedget_email_stats
    • First observedget_events
    • First observedget_number
    • First observedget_sms
    • First observedget_verification
    • First observedget_verification_requirements
    • First observedlist_agents
    • First observedlist_calls
    • First observedlist_contacts
    • First observedlist_email_domains
    • First observedlist_emails
    • First observedlist_number_regions
    • First observedlist_numbers
    • First observedlist_sms
    • First observedlist_verifications
    • First observedlookup_contact
    • First observedplace_call
    • First observedquote_numbers
    • First observedrelease_number
    • First observedroute_number
    • First observedsend_email
    • First observedsend_sms
    • First observedsubmit_verification
    • First observedupdate_agent
    • First observedupload_email_attachment
    • First observedwhoami

TDQS

A3.9/5.0

Scored across 38 tools

Disambiguation4/5

Most tools target a clearly distinct resource and action, and the detailed descriptions help separate calls, SMS, email, numbers, agents, and verification. A few overlaps remain, especially get_email_events versus get_events narrowed to an email, and lookup_contact versus list_contacts with a query filter.

Naming Consistency4/5

The set is overwhelmingly snake_case with predictable verb_noun naming such as list_calls, send_email, get_agent, and route_number. The main deviations are whoami, which does not follow the pattern, and some domain-specific verbs like quote_numbers and lookup_contact.

Tool Count2/5

The surface is broad, covering telephony, SMS, email, agents, numbers, contacts, and verifications, but 38 tools is heavy for a single MCP server. A set this large increases selection burden and could reasonably be split by domain.

Completeness4/5

Core lifecycle coverage is strong: calls, SMS, email, numbers, agents, and carrier verifications all have create/read/list/update or state-management operations where appropriate. Minor gaps exist, such as no update/delete contact tools and only listing email domains rather than managing them through the MCP surface.

Maintenance

ActivityActive
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Gives AI agents phone numbers, email, SMS, and voice calls as MCP tools, enabling them to provision numbers, capture 2FA codes, send messages, and make calls.
    15
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Let your AI agent call your phone and talk to you — MCP servers for live, interruptible voice calls + tiered alerts, using free self-hosted pieces (pjsua2 + whisper.cpp + Linphone). No paid telephony, no extra API key.
    3
    28
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Self-hosted email for AI agents: unlimited mailboxes on your own domain with docker compose, OTP/link extraction, mail_wait_for, web dashboard. v0.7.3: webhook wake example, reliable long waits (mail_wait_for), optional pending journal for task claims. Release: https://github.com/openagentemail/openagentemail/releases/tag/v0.7.3
    25
    55
    Apache 2.0