https://api.zelto.ai/mcp. Any MCP-compatible client can connect
and get read access to your agents, conversations, transcripts,
reviews, and findings, plus a small set of write tools for the
bucket-based review workflow.
Most read and write tools mirror a public REST API
endpoint, so anything you can do over HTTP you can do from inside your
editor. Some tools go beyond the REST surface, though — review queues,
changes, bucket population, voice-provider connect/import, and a raw
read-only SQL tool (query_database) are MCP-only. The Mirrors column in each table
below tells you which is which (— (MCP-only) means there’s no REST
equivalent).
New here? Onboard with an agent drives the whole setup — connect a provider, get calls in, create a monitor, and route findings — over the onboarding tools below.
Get an API key
Mint one athttps://dashboard.zelto.ai/org/<your-slug>/settings/integrations →
API Call Upload. The key is shown once — copy it immediately. The
same key works for the REST API and every MCP client below.
Minting and revoking keys is an owner/admin action; if you hold the member
role, ask an owner or admin for one (and see
Your role decides what you can do).
Export it for the snippets below:
Sign in with OAuth
Clients that support remote MCP OAuth — Claude, Cursor, VS Code, and others — can connect without minting a key. Point the client at the server URL and sign in through your browser:Clients
Claude Code
Add the server to~/.claude.json (create the file if it doesn’t
exist):
/mcp to refresh). The zelto: tools
appear in the picker; zelto:health returns your org id as a smoke
test.
The integrations page also shows this snippet pre-filled with the current host — go to Settings → Integrations → AI agent access and open the Claude card.
OpenAI Codex CLI
Codex CLI supports MCP servers via~/.codex/config.toml. Add a server
entry under [mcp_servers.zelto]:
codex and ask it something that needs your data, e.g.
“list my last 20 conversations and group failures by agent.” Codex
discovers the zelto: tools automatically.
Cursor
~/.cursor/mcp.json accepts the same shape as Claude Code:
zelto server on. The
tools show up in the chat sidebar.
Continue, Zed, and other Streamable-HTTP clients
The server speaks Streamable HTTP, so any client that accepts a URL +Authorization header works. Continue uses config.yaml:
~/.config/zed/settings.json under context_servers.zelto
with the same url + headers shape.
Quick smoke test (curl)
If a client is misbehaving, verify your key and connectivity against the
REST API — the same key authenticates both:
200 with a { "data": [...] } page means the server and your key are
good — the problem is in the client config. From inside a connected client,
the health tool returns { "status": "ok", "orgId": "…" } as the same check.
A 401 means the credential is the problem: the key was deleted, or the person
it belongs to lost access to the organization (removed, or their account
banned). Minting a fresh key only helps if your own account still has access to
that org.
Authentication
Every request carries anAuthorization: Bearer <token> header, where the
token is either an API key or an OAuth access token
obtained by signing in. Requests with no token or an
invalid/expired token return 401 and never reach a tool. Either way the token
resolves to a single organization server-side — an API key from its baked-in
org, an OAuth token from the org you chose at consent — and a tool only ever
sees that organization’s data.
Your role decides what you can do
Authenticating proves which organization you may act on, not what you may do inside it. Tools that administer the organization itself require theowner or
admin role — the same gate the dashboard
applies:
update_org_settings · invite_member · remove_member ·
save_usage_report_config · set_voice_tool_access · delete_agent ·
set_findings_delivery · merge_findings · delete_finding ·
approve_finding_candidate · reject_finding_candidate · update_finding
(only when you pass title — the triage fields stay open to any member)
update_member_role is stricter still: owner only, and it refuses to change
your own role. remove_member likewise refuses to remove your own membership,
whatever your role — ask another owner or admin.
A token belonging to a member reaches every read tool and every
non-administrative write, but the tools above return
Only an organization owner or admin can perform this action. instead of acting
(update_member_role returns Only an organization owner can perform this action.).
This is true for both credential types: a key or token acts as the person behind
it, and this gate reads that person’s role at call time rather than at mint time.
To take a credential out of service entirely, revoke it — see
API keys. Removing that person from the organization
(or banning their account) does the same thing implicitly: every request
re-checks the owner, so their keys and OAuth tokens stop working on the next
call.
Tools
Read tools
read_docs is MCP-only — call it with no arguments to list every
documentation page (slug + title + description), then pass a path (e.g.
findings or integrations/slack) to read that page’s full Markdown.
status enums: reviews accept pending / reviewed / flagged;
findings accept open / acknowledged / resolved / ignored. Finding priority
accepts none / low / medium / high / urgent.
Raw SQL (query_database)
When the dedicated list_* / get_* tools can’t express what you need —
aggregations, group-bys, ad-hoc joins — query_database runs a single
read-only SQL statement against either store and returns
{ rows, rowCount, columns, truncated }. It’s MCP-only (no REST
equivalent) and annotated readOnlyHint: true, destructiveHint: false.
Inputs:
What each store exposes:
clickhouse— call & analytics data:conversations,transcripts,conversation_analyses,analysis_findings,agents,webhooks. Use it for aggregations over call data. TheReplacingMergeTreetables (conversations,transcripts,conversation_analyses) should useFINALfor accurate reads.postgres— app & config data: any table with anorganization_idcolumn —receivers,integrations,reviews,buckets,findings,agents,jobs,webhooks, and more. Tables without anorganization_idcolumn (e.g. rawconversations) aren’t reachable here — query ClickHouse for those, or join through a scoped table.
- Org scoping is injected for you — ClickHouse via
additional_table_filters, Postgres by rewriting the SQL AST to addorganization_id = <your-org>to every table reference. You can’t bypass it by omitting aWHERE. - Row cap of ~1,000 rows. Any
LIMIThigher than that is clamped down, and a missingLIMITgets one injected. The response setstruncated: truewhen the cap is hit. - Timeout of 30s on ClickHouse queries.
Write tools
annotate_finding_conversation (add a system-authored, optionally
audio-ranged annotation to a call within a finding) requires a platform-admin
API key and the X-Organization-Id header — it is not callable with a
standard org key. Regular org keys can write the same annotation over REST at
POST /v1/findings/[id]/conversations/[conversationId]/comments (attributed to
the calling user), or read them via list_finding_conversation_comments and
edit/remove with update_finding_conversation_comment /
delete_finding_conversation_comment.add_conversation_to_bucket and add_conversation_to_finding
return the existing row with alreadyExisted: true on re-add. The
conversation must belong to the same agent as the bucket. create_bucket
accepts only type: "static" today. AI agent creation runs the system
prompt through the audit pipeline before insert.
create_finding submits every finding as a candidate pending platform
review: it does not appear in the organization’s findings list and is not
auto-linked to calls until a platform admin approves it (or rejects it) from
the Candidates queue on the findings page.
update_agent changes only the fields you pass — send description: null to
clear it, omit a field to leave it untouched. systemPrompt is accepted for AI
agents only (human agents have none) and is written as-is: unlike creation, it is
not re-run through the audit pipeline. An agent’s type and provider are
immutable and cannot be changed.
Review queues
A queue is a saved set of filters defining a dynamic collection of conversations to review. These tools are MCP-only.
The
filters object accepts: agentIds, agentType (ai / human),
durationMinSeconds, durationMaxSeconds, endedReasons, dateFrom
(YYYY-MM-DD), dateTo (YYYY-MM-DD), alreadyReviewed, hasAudio,
isInteresting, findingTypes. An empty/omitted filters matches every
conversation in the org. On update_queue, passing filters replaces
the whole object — it is not merged with the existing one.
Changes
A change is one atomic, agent-scoped suggestion that addresses a set of findings. Each new change starts as a draft (no workflow status, hidden from the main list) until a human publishes it. These tools are MCP-only.For API stability the MCP tool names keep the original
solution term
(create_solution, list_solutions, …) even though the product now calls
these changes. The tools and the UI operate on the same records.create_solution inserts exactly one draft per call — never bundle
multiple ideas into one body; call it again for each distinct suggestion.
A published change’s status is one of backlog / todo /
in_progress / done / cancelled. You can’t set status on a draft:
move it out of draft first with publish_solution (→ backlog) or
discard_solution (→ cancelled). Deleting a change removes its
finding links by cascade but never deletes the underlying findings.
Reports
A report is a free-form analyst write-up authored in the same rich-text editor as findings and changes.prompt holds the question or
brief; description holds the body as a TipTap/ProseMirror JSON document.
status tracks the generation lifecycle (pending / generating /
completed / failed) — a report you create sits in pending unless you
pass a finished body and set completed. These tools are MCP-only.
On
update_report, passing description replaces the whole body — it
is not merged with the existing document. Pass prompt: null to clear the
ask.
Bucket population
These tools snapshot conversations into buckets from queues or raw filters. They are MCP-only.
Because queues can span multiple agents but buckets are agent-scoped,
create_bucket_from_queue creates one bucket per matched agent and
returns an array. The populate_* tools are idempotent — re-running adds
zero new rows — and matches belonging to a different agent than the
bucket are skipped and counted in skippedOtherAgentCount.
Bucket & finding mutations
The remaining MCP-only mutations, plus the one finding-conversation unlink that does mirror a REST endpoint.type accepts only "static". Every delete cascades its own link rows
(bucket tasks, finding-conversation links, comments) but never deletes
the underlying conversations.
Provider import
Connect a voice provider and pull its agents and calls directly into Zelto — the same connect → import → backfill flow as Settings → Integrations, driven from your editor. These tools are MCP-only and cover every pull-capable provider: Vapi, Retell, Speechify, Telnyx, and ElevenLabs. Each takes aprovider argument (vapi / retell / speechify / telnyx /
elevenlabs).
connect_provider uses a browser handoff so the API key never passes through
the agent: it returns a one-time url (valid 15 minutes). You hand that URL to
the user; they open it while signed in to Zelto and paste their key there, so the
key goes straight to the server — never into your context or logs. Don’t ask the
user for their API key yourself. After they finish, poll
check_provider_connection with the returned token until status is
completed (it returns agentsFound) — or expired (start over). label
defaults to Default and must be unique per provider; the user can change it on
the connect page.
list_provider_agents returns every agent/assistant in the connected
account(s), each annotated with alreadyImported (and importedAgentId once
imported). agentId is the provider’s external id; for Vapi and Telnyx
that is the assistant id.
get_retell_agent reads one Retell agent directly without importing it. It
returns the current general_prompt for Retell LLM agents and global_prompt
for conversation-flow agents.
import_provider_agent imports one agent and fails if it is already
imported — call list_provider_agents first. import_provider_conversations
imports that agent’s calls from since (an ISO 8601 timestamp, e.g.
2026-03-01T00:00:00Z) until now, in the background — the agent must already be
imported, and re-running with an overlapping window is safe (already-imported
calls are skipped).
Onboarding
Stand a new organization up end to end from your editor: connect a call provider, create a monitor, and route findings. These tools are MCP-only. The Onboard with an agent guide walks an agent through the whole flow using them.
A headless run in order:
get_onboarding_status— readnextIncompleteto resume from the right step.connect_integration—provideris one ofvapi,retell,speechify,telnyx,elevenlabs;apiKeyis that provider’s key. For Vapi / Retell / Speechify the response’swebhook.webhookUrlmust be pasted into the provider’s dashboard (a human step) before calls flow; ElevenLabs and Telnyx sync automatically. Confirm withlist_conversations.create_monitor— pass astarterKeyfromlist_starter_monitors, or aname+ a natural-language booleaninstruction. OmittingagentIdsapplies it to every agent. Confirm withlist_monitors.set_findings_delivery—channelsis any ofemail/slack(Slack also needs the Slack app connected via OAuth in the web UI).
list_* / get_* reads) and return a JSON
object that may carry an error key — inspect it, and because writes settle
asynchronously, confirm each step with the paired read tool before advancing.
Monitors & scorecards
Manage the AI judges that surface findings (create_monitor /
list_monitors / list_starter_monitors are under Onboarding).
Findings workflow
Beyondcreate_finding / update_finding, these drive the candidate → open
lifecycle and dedup.
Everything in this table except
set_finding_version_scope requires the owner
or admin role, as does delete_finding and renaming through update_finding
— see Your role decides what you can
do.
Call review
flag_call_for_review only queues a call; these record the actual review.
Agents (lifecycle)
create_ai_agent / create_human_agent / update_agent plus:
merge_agents / unmerge_agents exist too but require an admin (cross-org) key,
matching the staff-only merge tools in the web UI.
Receivers (phone numbers)
Integrations & connectors
Provider connect/import is under Provider import. These configure an already-connected integration.
Slack (post-connect; OAuth install stays in the web UI):
add_slack_channel,
remove_slack_channel, set_default_slack_channel,
set_slack_channel_chat_enabled, send_slack_channel_test,
set_agent_slack_channel — each takes a Slack channel id (C…), and
set_agent_slack_channel also an agentId.
Linear (post-connect; OAuth install stays in the web UI):
list_linear_teams, set_default_linear_team (teamId, nullable),
create_linear_issue_for_finding (findingId),
create_linear_issue_for_solution (solutionId), unlink_linear_issue
(findingId? / solutionId?).
Organization & members
Every tool in this table except
upload_conversation requires the owner or
admin role, and update_member_role requires owner — see Your role decides
what you can do.
The inputs above are the primary fields; the MCP server advertises the full,
authoritative schema for each tool via tools/list.
Email inputs use regular-language JSON Schema patterns so the advertised tool
schemas remain compatible with strict structured-output providers, including
OpenAI.
Output shapes & pagination
Tool responses match the REST API exactly. See the API reference for the JSON shapes ofAgent,
Conversation, Transcript, Review, Bucket, and Finding, plus
the { data, nextCursor } pagination envelope.
limit clamps to 200 (default 50). cursor is opaque — pass back the
nextCursor value from a previous response to fetch the next page.
Troubleshooting
401from every tool — the bearer token is wrong or revoked. Test the key directly:curl -H "Authorization: Bearer $ZELTO_API_KEY" https://api.zelto.ai/v1/agents. If that also returns401, mint a new key.Only an organization owner or admin can perform this action.— the tool worked, your role didn’t. Your credential resolves to thememberrole and the tool administers the organization. Ask an owner or admin to run it or to raise your role; see Your role decides what you can do.- Tools list is empty in the client — most clients cache the tool
list. Restart the client (Claude Code:
/mcp; Cursor: toggle the server off/on; Codex: restart the CLI). 429rate-limited — back off and retry. Use thecursorpagination instead of fetching large pages.- Cross-org access denied — keys are scoped to the org they were minted in. Switch organizations in the web app and mint a new key from that org’s Settings → Integrations.

