https://mcp.chatsailer.com/mcp/crm
Read and manage a Sailer workspace. Record tools take a resource argument so
they can grow without eating the client’s tool budget. Today the only value is
"contact". Campaigns have their own tools. Organizations, deals, and
messages are not tools yet.
Every workspace defines its own custom fields. The JSON Schema a client caches
does not include them — clients cache by server, not by tenant. That is
why describe_schema exists, and why you call it first.
First connection is read-only. Write tools will not even appear
until you reconnect with
contacts:write.Orient
whoami
No arguments, no scope. Which workspace this connection is bound to, who
authorized it, oauth vs api_token, whether it reads company-wide, and the
scopes you actually have.
Which Sailer workspace am I connected to?A Sailer account can belong to several workspaces. The connection is bound to exactly one, chosen at consent. No tool argument can change it.
describe_schema
Scope: contacts:read. Optional resource ("contact"); omit it to describe
everything this server can touch.
Returns built-in and custom fields, which are required or read-only, select
options, and which keys are filterable, sortable, or expandable.
What custom fields does this workspace have?Use the
key it returns inside custom_fields on create and update. Guessing
from another workspace — or from these docs — is how you get an unknown-field
error.
Read contacts
Ids look likecon_8f3a…. That prefix is the resource; a deal id sent here is
a 400, not a mysterious 404.
search_records
Scope: contacts:read. resource defaults to "contact".
If
has_more is true, keep paging. Do not count a page and call it the
population — that is what count_records is for. Cursors are opaque, same
contract as REST pagination.
Find contacts created in the last 7 days.
get_record
Scope: contacts:read. resource, id, optional expand.
Show me contact con_…
Missing, deleted, or outside what you can see: not found. Same next step in
all three cases — search again.
count_records
Scope: contacts:read. Same filter / q as search, no paging.
How many contacts are in this workspace?
Write contacts
Scope on every tool here:contacts:write. Call describe_schema first.
Unknown or read-only custom-field keys are rejected, not ignored.
first_name and phone are required on create. Phone is unique per workspace
and stored as E.164.
create_record
New row. Prefer upsert_contact if the person may already exist — a duplicate
is not automatically reversible.
Create a contact named Ana with phone +5511999999999.
update_record
Destructive: it overwrites what you send. Omit a field to leave it; send
null to clear it. Read first if you meant to append.
Set Ana’s email to ana@example.com.
upsert_contact
Match on phone, after canonicalization — (11) 98765-4321 and
+55 11 98765-4321 are the same person. Default on_match is update;
ignore returns the existing row untouched.
The result tells you which branch ran (created vs matched_existing). The
record alone does not.
Add or update the contact with this phone number.
Campaigns
list_campaigns
Scope: campaigns:read. Newest first. Optional status, limit 1–100
(default 25). Use this to get a campaign_id.
List this workspace’s campaigns.
get_campaign_analytics
Scope: campaigns:read. One campaign, one metric family.
Optional
window_start / window_end (UTC). Defaults to the last 30 days.
These families are not interchangeable. big_numbers and daily_metrics
use a strict “answered” (a qualifying inbound, classified as a reply).
status_funnel uses the lifecycle status, which is usually a larger number.
Rates on big_numbers are 0–100, not fractions.
Every response carries _meta.caveats. Read them before comparing two
numbers. A difference between two families is not a change over time.
Show me campaign performance. Read the caveats before you summarize.