MCP tool reference
All 20 Ody MCP tools: what each does, its arguments, required scope, annotations and test-mode behaviour.
Every tool requires one scope. tools/list only returns the tools the key can call. Results come back as JSON text in content[0].text, and the same data is also in structuredContent.result.
Annotation key: R read-only · W writes to the workspace · $ spends money or reaches the outside world (openWorldHint) · D destructive · I idempotent (safe to repeat).
#At a glance
| Tool | Scope | Hints | Test key |
|---|---|---|---|
workspace_summary | conversations:read | R | Same |
list_contacts | contacts:read | R | Same |
create_contact | contacts:write | W | Same (real write) |
update_contact | contacts:write | W · I | Same (real write) |
delete_contact | contacts:write | W · D · I | Same (real delete) |
list_conversations | conversations:read | R | Same |
get_conversation | conversations:read | R | Same |
set_conversation_status | conversations:write | W · I | Same (real write) |
search_messages | conversations:read | R | Same |
wait_for_message | conversations:read | R | Same |
send_message | messages:send | W · $ | Simulated |
list_numbers | numbers:read | R | Same |
search_numbers | numbers:manage | R · $ | Same (live inventory) |
buy_number | numbers:manage | W · $ | Simulated |
get_messaging_status | numbers:manage | R | Same |
submit_10dlc_registration | numbers:manage | W · $ · I | Mock filing |
place_call | calls:place | W · $ | Simulated |
get_agent | agent:manage | R | Same |
configure_agent | agent:manage | W · $ · I | Saves; publish simulated |
connect_agent_to_number | agent:manage | W · $ · I | Real routing change |
A test key simulates anything that sends, spends or dials. Contact, conversation-status and routing changes are real writes to the workspace. Use a dedicated test workspace if you don't want them in your live data.
#Orientation
#workspace_summary
A snapshot of the workspace: contact count, open and done conversation counts, unread total, active numbers, and message and call volume over the last 7 days. Good as an assistant's first call.
Arguments: none.
#Contacts
#list_contacts
Lists or searches contacts.
qstring — Full-text search over names, company, phones and emails.
#create_contact
Creates a contact. Provide at least one of firstName, lastName, company, phone, email.
firstName,lastName,companystringphonestring — E.164.emailstring
#update_contact
Updates a contact. Only the fields you provide change. phone and email replace the contact's phone and email lists.
contactIduuid requiredfirstName,lastName,company,phone,emailstring
#delete_contact
Permanently deletes a contact. Its conversations remain. This can't be undone.
contactIduuid required
#Conversations
#list_conversations
Lists recent conversations, most recent activity first.
status"open" | "done"
#get_conversation
The full thread: messages, calls, voicemails, transcripts and AI summaries.
conversationIduuid required
#set_conversation_status
Marks a conversation open or done.
conversationIduuid requiredstatus"open" | "done" required
#search_messages
Case-insensitive search over message bodies, voicemail transcripts and call notes, newest first. Each match includes its conversationId.
qstring requiredlimitinteger
#wait_for_message
Long-polls for a new inbound message in a conversation, for up to 25 seconds. It returns { activities, lastActivityId } as soon as something arrives, or { activities: [], timedOut: true, lastActivityId }. Call it again with afterActivityId: lastActivityId to keep waiting without missing anything.
conversationIduuid requiredafterActivityIduuid — Only return activities newer than this. Defaults to the newest activity at call time.timeoutSecondsinteger — 1–25, default 20.
#Texting
#send_message
Sends an SMS. Provide body, plus either conversationId or to (E.164). With to, the conversation is created from the workspace's number. Live texting needs 10DLC.
bodystring requiredconversationIduuidtostring — E.164.
#Numbers and 10DLC
#list_numbers
The workspace's phone numbers, with routing (voiceMode).
#search_numbers
Searches carrier inventory, with Ody's monthly price per result: local numbers are $5/mo (the first is included in the plan), toll-free $10/mo (calling only).
type"local" | "toll_free" — Defaultlocal.countrystring — ISO 3166 alpha-2, defaultUS.startsWithstring — Area-code prefix (local only).containsstring,localitystring,statestringlimitinteger
#buy_number
Buys a number. Spends real money: it's billed to the workspace's plan like an in-app purchase. The same plan, identity and App Store gates as the REST endpoint apply.
phoneNumberstring required — E.164, fromsearch_numbers.type"local" | "toll_free" — A hint; Ody works out the real type from the number.
#get_messaging_status
10DLC status: step, canText and any failure reasons. See Messaging (10DLC).
#submit_10dlc_registration
Files the brand and campaign. Submitting is a purchase. On a free trial it ends the trial and charges the plan plus the $20 per-number setup fee right away, so the assistant must tell the user and pass acknowledge_trial_end: true. Fields match POST /messaging/registration.
businessobject requiredcampaignobjectacknowledge_trial_endboolean — Required on a trial, after the user has been told.
#Calls and agent
#place_call
The published AI agent calls to and holds the conversation. Billed in AI credits like an inbound AI call. See Place an AI call.
tostring required — E.164.fromstring — One of the workspace's numbers.
#get_agent
The agent's configuration (name, greeting, tone, voice, jobs, hours, publish status) plus this cycle's credit usage.
#configure_agent
Creates or updates the agent. Only the fields you provide change. Pass publish: true to push the configuration live in the same call.
name,greeting,tone,voice,languagestringtimezonestring — IANA, for exampleAmerica/Chicago.inHoursAction,offHoursAction"agent" | "voicemail" | "app" | "forward"enabledbooleanjobsarray of {name, instructions}publishboolean
#connect_agent_to_number
Routes a number's inbound calls to the agent. The agent must exist; publish it for live answering.
phoneNumberstring required — One of the workspace's numbers.
#Errors
A tool that fails returns a normal result with isError: true and a readable message, so the model can explain or recover:
{
"content": [{ "type": "text", "text": "Unauthorized: this API key does not have the 'messages:send' scope required by send_message. Ask the workspace admin for a key with that scope." }],
"isError": true
}Protocol-level problems (unknown tool, missing name) come back as JSON-RPC errors instead. See Protocol details.