Safety & compliance
Safety & Compliance
CallMCP places real phone calls and spends real money on real carrier infrastructure. This page describes, precisely, what is actually enforced before that happens — server-side, client-side, and not yet at all — so you can decide how much autonomy to give an agent holding a CallMCP key.
What's enforced server-side
Config-changing calls — editing an agent's prompt, voice, model, greeting, or transfer number via update_agent_config — don't hit the provider directly. They route through a governed update broker (intent agent.patch) that enforces:
- Idempotency. Every mutating request needs an
idempotency_key. Retry the same key and you get the original outcome back — repeating a key against a different payload is rejected outright as a conflict. - An authority envelope for high-impact fields. Changing the prompt, voice, model, greeting, transfer number, or raw config requires
authority: { mode: human_confirmed | dashboard_session | system_policy }. An agent simply asserting "I'm allowed to do this" (agent_asserted) is not sufficient authority for these fields — the broker checks the mode plus, forhuman_confirmed, thatconfirmed_by/confirmed_at/confirmation_refare all present. - A working approval queue. Call without sufficient authority and the broker returns
needs_approvalwith exact confirmation text to relay to a human. Passqueue_for_approval: trueinstead and it persists apending_approvalrow (24-hour window) for dashboard review rather than executing blind. Only once authority is satisfied does the request move toexecutingand then a terminal status (executed,failed,rejected,denied, orexpired). - Versioned, hashed config snapshots. Once a config change actually lands, the full post-sync assistant config is hashed (sha256, canonical JSON) and stored as an immutable, monotonically-versioned snapshot — before-and-after state is fully recoverable. No-op changes don't create version churn. This happens whether the change was auto-executed or came through the approval queue.
configure_agent_business_rules (prompt section edits) and request_kaicalls_update (the same broker, for E911 address changes and transcript-webhook configuration) go through the identical idempotency + authority + approval machinery — one broker behind three entry points, so all three get identical guarantees.
What's client-enforced via MCP annotations
make_call does not go through that broker. It executes immediately against a valid, correctly-scoped API key, dispatching the outbound call as soon as the agent is verified as belonging to your business. There is no authority envelope or approval queue in front of it — an optional idempotency_key makes retries safe (repeating the same key returns the original call instead of dialing again), but nothing blocks the first call from an unattended agent.
What it does have is an annotation: make_call is marked destructiveHint: true and readOnlyHint: false in its tool definition. Concretely, that means an MCP client that implements human-in-the-loop confirmation for destructive tools — Claude is one — will prompt you before calling it, the same way it would before deleting a file. It does not mean CallMCP itself stops the call. A client that ignores the annotation (or an agent running without a human in the loop at all) will place the call without anyone confirming first. The annotation is a signal to well-behaved clients, enforced entirely client-side.
buy_number is different, and stricter than an annotation: because a purchase is carrier-billed the moment it executes, it now runs through the same authority-gated broker as update_agent_config. Call it without a satisfied authority envelope (human_confirmed, or a dashboard approval) and it executes nothing — it returns a pending_approval record for the business owner to approve or deny from the dashboard instead of buying the number. Agent-initiated purchases don't run unattended.
TCPA compliance, outlined
If you've never touched telephony compliance: the U.S. Telephone Consumer Protection Act (TCPA), plus a patchwork of state wiretap/eavesdropping statutes, is the reason a phone-calling AI agent can't just dial and talk like a chat completion. Four things matter for an AI voice agent specifically — (1) telling the person they're talking to an AI and that the call may be recorded, (2) getting the right kind of consent to record (some states require consent from everyone on the call, business included), (3) honoring a "stop calling me" request permanently, and (4) not calling or texting outside allowed hours. Below is what CallMCP's backend actually does for each — and where it falls short — grounded in the real modules.
1. AI-voice & recording disclosure
What TCPA-adjacent law requires: a growing set of states require telling a caller they're speaking with an AI, and separately, wiretap law requires disclosing (or in some states, getting consent for) call recording.
What CallMCP does: before the assistant's first word, the call router resolves the caller's state from their number and looks it up against a maintained per-state table, where each state is tagged aiDisclosure: 'none' | 'required' | 'future' | 'limited' (falling back to 'unknown' at runtime when the state itself can't be resolved). If required — by state law, by a business setting forcing it on every call, or because the caller's state can't be determined and the business is in a high-risk category (law, medical, finance, insurance, debt/credit) — the disclosure text is prepended to the agent's greeting before the call ever answers:
getRequiredDisclosure({ settings, callerState, businessCategory, businessName })
→ disclosure.text // e.g. the two lines below, concatenated
→ assistant.firstMessage = prependDisclosureToFirstMessage(disclosure.text, firstMessage)The real default strings, verbatim from the source: "You are speaking with an AI assistant for this business." and "This call may be recorded for quality and training purposes." — a business can override either message, but can't remove the AI one for a state where it's legally required. This is wired into the live call path: the call router calls getRequiredDisclosure() and prependDisclosureToFirstMessage() and sets assistant.firstMessage directly on the Vapi assistant config before the call connects. create_agent and buy_number both carry this automatically for anything they provision.
2. Recording consent — one-party vs. two-party states
What the law requires: most U.S. states are "one-party consent" — only one participant (the business) needs to know a call is recorded. A minority are "two-party" (really all-party) consent states, where every participant must consent. Get this wrong in a two-party state and the recording itself can be the violation, independent of TCPA.
What CallMCP does: every state in the rules table is tagged recordingConsent: 'one_party' | 'two_party' | 'notification'. Real examples from the table: California, Florida, Illinois, and Pennsylvania are tagged two_party; most other states are one_party. In a two-party (or notification) state, the recording-disclosure message above is forced on regardless of business settings, and it's treated as the consent mechanism — the caller hears "this call may be recorded" and their continuing the call is the implied consent.
Be precise about what this is NOT: the recording-consent logic decides only whether to play a disclosure — a separate question from whether to allow the recording to happen. There is no code path that disables the recorder if a two-party-state caller doesn't affirmatively consent — it's notice-based implied consent only, nothing captured or independently checkable. If your use case needs provable explicit consent before recording starts, that's a gap today.
3. Do-not-call / opt-out honoring
What the law requires: once someone tells you to stop calling, you have to stop — permanently, across every channel you'd otherwise use to reach them again.
What CallMCP does: every inbound call transcript is scanned for opt-out phrasing — only what the caller said, never the assistant's own turns (so the agent saying "I won't call you again" can't trip its own detector). The phrase list is real and specific — a sample of the exact substrings matched (lowercased, apostrophes stripped): "do not call", "stop calling", "take me off your", "remove me from your", "unsubscribe", "opt out", "leave me alone" — 28 phrases total, plus a structured call_outcome of do_not_call/opted_out/opt_out, plus an explicit extracted do_not_call flag as a third detection path. Detecting one triggers a single suppression routine that:
- upserts the number into a DNC list with both
block_voiceandblock_smsset true — the opt-out blocks both channels, even if the caller only used one; - flips consent records to
opted_outfor voice and SMS with a revocation timestamp; - pauses the lead (
sdr_paused, status →do_not_contact) so automated follow-up sequences stop touching it; - and cancels every already-queued callback target, attempt, and job tied to that lead — so "please don't call here anymore" can't still result in a scheduled robo-callback that was queued before the opt-out landed.
A second, cheap pre-dispatch check runs before any callback actually fires, independent of whether the suppression routine above ran cleanly — so a suppressed number can't slip through even if an earlier step missed it. That check fails open on a database error (a transient DB blip doesn't halt the whole callback pipeline) — the durable suppression write is the authoritative stop, and the pre-dispatch check is a belt-and-suspenders layer on top of it.
4. Quiet hours
What the law requires: in the U.S., TCPA-adjacent guidance restricts telemarketing-style calls/texts to 8am–9pm in the recipient's local time, regardless of the business's own timezone.
What CallMCP does: a country-aware calling-hours gate resolves the recipient's timezone through a priority chain — explicit lead timezone, then area-code inference (US/Canada), then U.S. state inference, then the country's default timezone, then the business's timezone as a last resort — and checks the current hour in that timezone against a per-country window. The real U.S. window is 8:00–21:00, every day, no holiday block. This isn't U.S.-only: Canada (8–21), Australia (weekday 9–20, Saturday 9–17, blocked on public holidays), the UK (8–21 weekday, bank holidays blocked), New Zealand, Ireland, and Germany each have their own real per-country window, and any other country falls back to a conservative default (9–20 weekday, holiday-blocked) rather than silently allowing anytime contact.
Outbound SMS is gated through this same check before send — a message outside the window is deferred (not dropped), with the next allowed time computed and returned rather than the message just disappearing. One deliberate exception: an SMS sent as a live reply while the recipient is actively on a call with the agent skips the quiet-hours gate — the reasoning treats being mid-call as the engagement itself, so no separate solicitation is occurring. The equivalent voice-side tools (scheduled callback, payment-link calls) return a structured "try again later" outcome rather than a silent failure when a call would land outside the window, so a caller (or the calling agent) gets an explicit reason instead of nothing happening.
What's not gated yet
Being direct about the gaps, so you can plan around them rather than discover them:
make_callhas no server-side approval step. It executes on a valid scoped key today; the destructive-hint annotation is the only gate, and it only works if the client honors it. Bringing it under the same broker-and-authority model already used byupdate_agent_configandbuy_numberis a real, disclosed gap — plan on it as a roadmap item if you're handing a key to an unsupervised autonomous agent.- Recording consent in two-party states is notice-based only. As above: the recorder doesn't get disabled if a two-party-state caller doesn't affirmatively consent after hearing the disclosure. If your use case needs a captured, checkable opt-in rather than implied consent from a continued call, build that check on top — it isn't there today.
- No integration with the National Do-Not-Call Registry. The DNC list CallMCP enforces is built from explicit in-call opt-outs (and whatever a business adds manually); there is no live lookup against the FTC's national registry before a number gets dialed. If a lead is on the national registry but has never told CallMCP to stop, nothing here catches that today.
- No public sandbox or demo number. There is no number you can call to test CallMCP without a live account. Don't assume one exists.