Sondo

MCP server and clients

Connect Claude Code, Claude Desktop, Cursor, VS Code, Codex or any MCP client to your workspace, and the full tool reference.

Markdown

Sondo speaks the Model Context Protocol, so an AI client can work with your workspace from wherever you already are: read the conversations your widget had overnight, reply to one as yourself, add a page to the Knowledge Base, or change what the assistant is allowed to say.

The one endpoint every client connects to is https://usesondo.com/api/mcp.

The tools cover the work the dashboard does day to day: conversations, the Knowledge Base, connected sites, the workspace and widget settings, the API keys and the model spend. Billing, creating a workspace, issuing a key and the outbound webhook stay in the dashboard.

Nothing here takes a workspace argument. The key you connect with decides which workspace you are in, and it cannot reach another one.

Get a key first

Every client authenticates with its own API key from the Integrations page in your dashboard. It starts with sondo_sk_, it is shown once, and you can revoke it without touching your other clients. See API keys and plans for how to issue one.

There is no OAuth. The key travels as a bearer token on the Authorization header, which is why every command below carries one.

Connect your client

Replace the placeholder key in each command with your own.

Claude Code

Run this once:

claude mcp add --scope user --transport http sondo https://usesondo.com/api/mcp --header "Authorization: Bearer sondo_sk_…"

Issue the key under Settings > Integrations first. It is shown once.

Claude Desktop

Settings → Developer → Edit Config (claude_desktop_config.json), then restart the app.

{
  "mcpServers": {
    "sondo": {
      "type": "http",
      "url": "https://usesondo.com/api/mcp",
      "headers": { "Authorization": "Bearer sondo_sk_…" }
    }
  }
}

Cursor

Add this to your Cursor MCP settings file:

{
  "mcpServers": {
    "sondo": {
      "type": "http",
      "url": "https://usesondo.com/api/mcp",
      "headers": { "Authorization": "Bearer sondo_sk_…" }
    }
  }
}

Paste your key from Settings > Integrations, then enable Sondo in Cursor.

VS Code

Add this to .vscode/mcp.json:

{
  "mcpServers": {
    "sondo": {
      "type": "http",
      "url": "https://usesondo.com/api/mcp",
      "headers": { "Authorization": "Bearer sondo_sk_…" }
    }
  }
}

Paste your key from Settings > Integrations, then start the server.

Codex CLI

Run this once:

codex mcp add sondo --url https://usesondo.com/api/mcp --bearer-token-env-var SONDO_API_KEY

Export SONDO_API_KEY with your key from Settings > Integrations, then start codex.

Codex reads that environment variable when it starts, not when you export it, so export it and then start Codex, in that order.

Gemini CLI

Run this once:

gemini mcp add --transport http --header "Authorization: Bearer sondo_sk_…" sondo https://usesondo.com/api/mcp

Issue the key under Settings > Integrations first. It is shown once.

Anything else

Point it at the endpoint and send the key on this header:

https://usesondo.com/api/mcp
Authorization: Bearer sondo_sk_…

Issue the key under Settings > Integrations. It is shown once.

Chat products that connect through their own interface, including Claude, ChatGPT, Grok and Meta Muse, need the same two things: the endpoint, and the key on that header. Where their interface puts those fields is their business, and it changes often enough that this page will not guess.

Check that it worked

Ask your client to use Sondo's ping tool by name. It answers with the workspace it is connected to, which is the fastest way to tell a working key from a working connection to the wrong workspace.

Naming the tool matters. Asked loosely, a coding agent will often reach for curl instead, which proves only that the endpoint is reachable.

Tool reference

Generated from the server, so it cannot drift from what your client will actually find.

An unknown id, or one from another workspace, comes back as "not found" rather than an error about permission, because a permission error would confirm that the thing exists.

Sondo exposes 27 tools.

Conversations

Read what visitors asked, reply as the operator, and keep the list tidy.

conversation_reply

Write your own reply into a conversation, as the operator. The visitor sees it within a few seconds. This is not a takeover: the assistant still answers their next message, having read your reply. Pause it first with conversation_set if you want the thread.

ArgumentTypeNotes
iduuid
contentstring1 to 4,000 characters

conversation_set

Set a conversation's star, block its visitor, or pause the assistant in it. Pass at least one of starred, visitorBlocked or aiPaused. Read and archived belong to set_read and set_archived.

ArgumentTypeNotes
iduuid
starred (optional)boolean
visitorBlocked (optional)boolean
blockMessage (optional)stringWhat a blocked visitor is told. Only meaningful when blocking; unblocking clears it. up to 300 characters
aiPaused (optional)booleanPaused, the assistant stops answering until you resume it. Manual only

get_conversation

The full transcript of one conversation, plus visitor context, signals and model cost. Ids come from list_conversations.

ArgumentTypeNotes
iduuid

list_conversations

Overview of this workspace's conversations: the total, then the 10 most recent by activity (id, title, unread). Start here and stay zoomed out. Pass detail:'summaries' for a gist and triage signals per conversation, or get_conversation for one full transcript.

ArgumentTypeNotes
view (optional)one of all, unread, archivedall (default, excludes archived) | unread | archived
q (optional)stringSearch titles, messages and visitor emails
detail (optional)one of titles, summariesDefault titles
page (optional)integerat least 1

set_archived

Archive one conversation (out of the inbox) or restore it. Archiving is reversible and deletes nothing.

ArgumentTypeNotes
iduuid
archived (optional)booleanDefault true

set_read

Mark one conversation read/unread by id, or pass id:'all' to clear the whole inbox. 'all' only marks READ; there is no bulk unread.

ArgumentTypeNotes
iduuid or all
read (optional)booleanDefault true

unread_count

How many conversations are unread (excludes archived). Takes no arguments.

Takes no arguments.

Knowledge Base

Everything the Add source form does, plus editing and removing what is already there.

kb_add

Add a document by pasting its text. Chunked and embedded at once, so the assistant can use it on the next message. Costs pages from the plan's allowance.

ArgumentTypeNotes
titlestring1 to 200 characters
textstring1 to 200,000 characters

kb_add_file

Add a text-based PDF, Markdown or plain-text file, base64-encoded. Up to 2 MB decoded. A scanned, image-only PDF has no text to extract and is refused.

ArgumentTypeNotes
filenamestringUsed to pick the extractor and the title. 1 to 255 characters
contentBase64stringat least 1 characters
title (optional)string1 to 200 characters

kb_add_url

Fetch a public page and add its main content as a document. The address is checked against private networks before anything is fetched. Title defaults to the page's own.

ArgumentTypeNotes
urlURLup to 2,048 characters
title (optional)string1 to 200 characters

kb_get

One document's stored text, with its title, source and size in pages. Ids come from kb_list. This is the text the assistant retrieves from.

ArgumentTypeNotes
iduuid

kb_list

This workspace's Knowledge Base: how many pages of the plan's allowance are used, then one line per document (id, title, where it came from, status, chunks). No text. Use kb_get for one document's content.

ArgumentTypeNotes
page (optional)integerat least 1

kb_refresh

Bring one document up to date. A document added from a URL is fetched again from that address, overwriting any hand edits. Every other document is re-chunked and re-embedded from its stored text. Not for a site's posts, which their site syncs.

ArgumentTypeNotes
iduuid

kb_remove

Delete a document and its chunks. The assistant stops retrieving from it immediately, and past answers that cited it read as 'source removed'. A site's posts are removed by removing the site.

ArgumentTypeNotes
iduuid

kb_update

Replace a document's title, its text, or both. Re-chunks and re-embeds. Omitted fields keep what is stored. A document synced from a connected site cannot be edited here.

ArgumentTypeNotes
iduuid
title (optional)string1 to 200 characters
text (optional)string1 to 200,000 characters

Connected sites

Connect a blog, sync it, and disconnect it.

site_connect

Connect a blog so its posts sync into the Knowledge Base. Posts are found from the site's sitemap, feed or llms.txt; pass manualIndexUrl (same host) if it has none. The first sync starts in the background. Read site_list for its progress.

ArgumentTypeNotes
rootUrlURLup to 2,048 characters
pathPrefix (optional)string matching ^\/.*up to 200 characters
manualIndexUrl (optional)URLup to 2,048 characters

site_list

Every site connected to this workspace: where it is, how its posts were found, how many it holds, and what its last sync did. Read this after site_connect or site_sync to see how the run ended.

Takes no arguments.

site_remove

Disconnect a site and delete every post it synced. The assistant stops retrieving from them at once. Nothing else in the Knowledge Base is touched.

ArgumentTypeNotes
iduuid

site_sync

Re-run one site's sync: fetch its index, then re-embed the posts that changed. Runs in the background and returns at once. Read site_list for progress and the result.

ArgumentTypeNotes
iduuid

Settings and the widget

The workspace's own configuration, and how the chat looks and behaves.

settings_get

Everything settings_update can change, as it is now, plus the plan and how much of its Knowledge Base allowance is used. The OpenRouter key is reported as configured or not, never as its value.

Takes no arguments.

settings_update

Change any of the workspace's settings. Pass only the keys you want changed; the rest are left alone. Validation is all or nothing: if any key is rejected, nothing at all is written. guardrails and responseStyle are whole objects, and postSuggestions and postCards must be sent together.

ArgumentTypeNotes
name (optional)stringThe workspace's display name. 1 to 64 characters
websiteUrl (optional)stringThe workspace's own website as a full http(s) URL, or "" to clear it. Its icon is fetched too. up to 2,048 characters
timezone (optional)string, or "" to clear itAn IANA name such as "Europe/Amsterdam", or "" for Auto. 1 to 64 characters
persona (optional)stringHow the assistant should behave. up to 8,000 characters
guardrails (optional)object with allowCode (required), allowCreative (required), allowGeneralQA (required)All three flags, always. Which deliverables the assistant may produce
guardrails.allowCodeboolean
guardrails.allowCreativeboolean
guardrails.allowGeneralQAboolean
responseStyle (optional)object with enabled (required), level (required)Both fields, always. level 1 is briefest, 5 is fullest
responseStyle.enabledboolean
responseStyle.levelone of 1, 2, 3, 4, 5
resumeWindowHours (optional)numberHow long a returning visitor picks up where they left off. One of: 1, 6, 24, 48, 168, 336 (hours)
postSuggestions (optional)one of never, when_relevant, only_when_askedSend with postCards
postCards (optional)booleanSend with postSuggestions
models (optional)object with chat, summary, extractA provider/model slug pins a task; null clears it back to the default
models.chat (optional)string matching ^[\w.-]+\/[\w.:-]+$, or null1 to 120 characters
models.summary (optional)string matching ^[\w.-]+\/[\w.:-]+$, or null1 to 120 characters
models.extract (optional)string matching ^[\w.-]+\/[\w.:-]+$, or null1 to 120 characters
openrouterKey (optional)string, or "" to clear itWrite-only; it is never read back. "" REMOVES the key, which pauses the assistant for every visitor until a new one is saved. There is no server key to fall back to. 20 to 300 characters

widget_get

What visitors see and where the widget may load: its name, header, welcome message, suggested questions, booking link, showcase cards, colors, allowed origins, and the embed snippet to paste into a site.

Takes no arguments.

widget_update

Change any of the widget's settings. Pass only what you want changed; everything else keeps its current value. An array (starters, showcase, allowedOrigins) is replaced whole, so pass the full list, and [] really does clear it.

ArgumentTypeNotes
name (optional)string1 to 80 characters
welcomeMessage (optional)stringup to 500 characters
bookingUrl (optional)URL, or "" to clear itup to 2,048 characters
starters (optional)array (up to 8) of string
headerTitle (optional)stringup to 80 characters
showHeader (optional)boolean
chatOrb (optional)boolean
colors (optional)object with light (required), dark (required)Both modes, each #rrggbb or ""
colors.lightobject with primary (required), userBubble (required), userBubbleForeground (required), assistantBubble (required), assistantBubbleForeground (required)
colors.darkobject with primary (required), userBubble (required), userBubbleForeground (required), assistantBubble (required), assistantBubbleForeground (required)
shader (optional)stringThe launcher orb's shader key. 1 to 64 characters
emailCapture (optional)object with contactReason (required), gapReason (required)
emailCapture.contactReasonstringup to 300 characters
emailCapture.gapReasonstringup to 300 characters
contactEmail (optional)email, or "" to clear itup to 200 characters
showcase (optional)array (up to 6) of object with title (required), description (required), imageUrl (required), url (required)
showcase[].titlestring1 to 80 characters
showcase[].descriptionstringup to 140 characters
showcase[].imageUrlURL or string matching ^\/(?!\/)\S*$, or "" to clear itup to 2,048 characters
showcase[].urlURL, or "" to clear itup to 2,048 characters
allowedOrigins (optional)array (up to 20) of stringSites the widget may be embedded on. Replaces the whole list; [] blocks every external embed
resumeWindowHours (optional)number

API keys

List and revoke the keys other clients connect with.

key_list

Every API key for this workspace, oldest first: label, when it was made, when it was last used, and whether it is revoked. Key values are never stored and never shown. Issue a new key from the dashboard's Integrations page.

Takes no arguments.

key_revoke

Revoke one API key by id, from key_list. The row survives as a record, with its revoke date. Revoking the key you are calling with is allowed, and ends this session's access immediately.

ArgumentTypeNotes
iduuid

Everything else

A connectivity check, and what this workspace has spent.

ping

Check the Sondo connection and report which workspace this API key opens. Takes no arguments.

Takes no arguments.

usage_summary

Model spend in USD, bucketed by day (last 30), week (12) or month (12). UTC calendar days.

ArgumentTypeNotes
unit (optional)one of day, week, month

On this page