MCP server
Reply.io's full sales platform as 70 MCP tools — sequences, contacts, inbox, tasks, and the Jason AI SDR autopilot. Live at mcp2.reply.io. Verified overview — auth, contract rules, envelopes, error model, recipes — with the full 70-tool reference at /mcp/tools.
Status — available today, verified live
Reply MCP is an official, live, remote Streamable HTTP MCP server exposing Reply.io’s sales-engagement, inbox, AI SDR (Jason), task, account, and help workflows as 70 tools for any MCP-compatible client — Claude, Cursor, Make, n8n, and custom agents.
Everything below was read off the running server. Tool names, signatures, per-argument documentation, enum values, MCP annotations, response envelopes, and error codes come from an authenticated
initialize+tools/listhandshake and safe validation probes on 2026-07-05 — not from published docs. This page is the overview; the full per-tool reference lives at /mcp/tools. This is the current next-generation surface. If any other documentation disagrees, trust this page or re-probe the server yourself (see §10, Reproduce this, at the end of this page).
On this page: 1. Server overview · 2. Contract rules the schemas enforce · 3. Response envelopes and error model · 4. Design principles for agents · 5. Tool index (70 tools) · 6. Workflow recipes · 7. High-stakes tools · 8. Relationship to the REST API (v3) · 9. Agent prompt guidance · 10. Reproduce this — full tool reference: /mcp/tools
1. Server overview
| Endpoint | https://mcp2.reply.io/ |
| Transport | Streamable HTTP (responses are SSE text/event-stream frames carrying JSON-RPC) |
| Wire format | JSON-RPC 2.0 over HTTP |
| MCP protocol | 2025-06-18 |
| Server | Reply.Mcp v1.0.0.0 |
| Capabilities | tools, logging (no prompts or resources advertised) |
| Tools | 70 — 31 annotated readOnlyHint, 39 annotated destructiveHint |
| Sessions | None required — initialize and tools/list work without Mcp-Session-Id |
| Auth | x-api-key: <key> or Authorization: Bearer <key> |
| Rate limit | Hourly window, ~3000/hour (X-Rate-Limit-Limit: 1h, -Remaining, -Reset on every response) |
Unauthenticated behavior. A call with no credentials returns 401 Unauthorized with:
WWW-Authenticate: Bearer resource_metadata="https://mcp2.reply.io/.well-known/oauth-protected-resource/"
X-Rate-Limit-Limit: 1h
X-Rate-Limit-Remaining: 2997
X-Rate-Limit-Reset: 2026-07-05T00:00:00.0000000Z
OAuth protected-resource metadata (GET /.well-known/oauth-protected-resource/):
{
"resource": "https://mcp2.reply.io",
"authorization_servers": ["https://oauth.sandbox.replyapp.io"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["reply-web-api", "mcp:tools"]
}
For most agents the simplest path is an API-key header; the OAuth metadata exists for clients (e.g. Claude custom connectors) that prefer a discovery-based OAuth flow.
Client initialization flow
- Open an HTTP connection to
https://mcp2.reply.io/. - Send JSON-RPC
initializewith your protocol version and client info. - Send the
notifications/initializednotification if your client library requires it. - Call
tools/listto discover tools, their JSON schemas, and their annotations. - Call
tools/callwith a tool name and an argument object.
initialize payload
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "your-client", "version": "1.0.0" }
}
}
MCP client config
Header form (recommended):
{
"mcpServers": {
"reply": {
"type": "http",
"url": "https://mcp2.reply.io/",
"headers": { "x-api-key": "YOUR_REPLY_API_KEY" }
}
}
}
Bearer form (equivalent):
{
"mcpServers": {
"reply": {
"type": "http",
"url": "https://mcp2.reply.io/",
"headers": { "Authorization": "Bearer YOUR_REPLY_API_KEY" }
}
}
}
Claude Code, one line:
claude mcp add --transport http reply https://mcp2.reply.io/ \
--header "x-api-key: YOUR_REPLY_API_KEY"
2. Contract rules the schemas enforce
These apply to every one of the 70 tools — verified against the served JSON schemas and live validation probes:
- Unknown arguments are invalid. Every
inputSchemasetsadditionalProperties: false. Don’t pass extra keys “just in case” — the call fails validation. - Required means non-empty. Required string and array fields reject
null,"", and[]alike. The server’s own words: “null, empty strings, and empty arrays are not accepted for required fields.” - Every tool is annotated.
readOnlyHint: true(31 tools) ordestructiveHint: true(39 tools) arrives intools/list. Agents can — and should — auto-gate on these before adding their own confirmation UX for the ⚠️ subset. - Pagination is uniform. List/search tools take
top(default 20, max 100) andskip; responses returnData.ItemsplusHasMore. Iterate withskip += topuntilHasMoreis false. - Patch semantics on updates. Every
update_*tool changes only the fields you pass; omitted/null fields keep their current value. A passed list field replaces the whole list. - IDs come from resolvers. Mutating tools require exact numeric IDs from prior
search_*/list_*/filter_*output. The descriptions repeat one rule verbatim: “Never invent, estimate, default, or ask the user.” - Approvals are addressed by pair. Approve/reject/regenerate identify a Jason draft by
sequenceId+contactId— there is no separate draft/message ID. - Batches are bounded and explicit. Bulk tools cap at 100 items.
reply_bulk_approve_messagesis atomic (any stale reference rejects the whole batch; nothing is sent). Contact batches return per-item results (Affected/AffectedContactIds/NotProcessed) — the authoritative record of what actually happened; report exact counts (“reassigned 48 of 50”).
Enum quick reference
Every closed value set the server declares (in schemas or tool descriptions), in one place. All are case-insensitive unless noted:
| Field | Values | Used by |
|---|---|---|
channel | Email, LinkedIn | send_inbox_reply, list_pending_approvals filter |
Per-sequence contact status | Active, Paused, Finished, Inactive, OutOfOffice | change_status_in_sequence |
Sequence search status | New, Active, Paused | search_sequences |
Reply mode | Review, Autonomous (+ sendExistingDrafts boolean) | set_sequence_reply_mode |
toneOfVoice | Confident, Persuasive, Witty, Straightforward, Empathetic | reply handlers, reengagement cards |
responseLength | SuperShort, Short, Medium, Long | reply handlers, reengagement cards |
taskType | ToDo, Call, Meeting, LinkedIn, ManualEmail, Sms, WhatsApp | create_task, list_my_tasks |
linkedInTaskType | Message, Connect, InMail, ViewProfile | create_task (required when taskType=LinkedIn) |
callResolution | Positive, ToCall, Negative | complete_task (recommended for Call tasks) |
Playbook visibility | Team (default), Organization | create_playbook, duplicate_playbook |
category (schema enum) | integrations, reporting, sequences, contacts, email, linkedIn, ai, other | report_unsupported_request |
sortMode | NewestFirst (default), OldestFirst | list_pending_approvals |
3. Response envelopes and error model
Transport. Responses are SSE frames (text/event-stream) whose data: lines carry ordinary JSON-RPC payloads. Read the last data: frame for the result.
Success envelope. A successful tools/call returns result.isError = false, and the actual payload is a JSON string inside result.content[0].text:
{ "Success": true, "Data": { "Items": [ ... ], "HasMore": false } }
Error envelope. Tool failures are not HTTP errors — they come back as HTTP 200, JSON-RPC success, with result.isError = true and the error as a JSON string in result.content[0].text:
{ "Success": false, "ErrorCode": "InvalidArguments", "ErrorMessage": "..." }
Parse the inner JSON; branch on Success, then on ErrorCode. Real captured examples:
{"Success":false,"ErrorCode":"InvalidArguments","ErrorMessage":"Tool 'reply_get_sequence_steps' arguments failed validation: SequenceId: 'Sequence Id' must be greater than '0'."}
{"Success":false,"ErrorCode":"InvalidArguments","ErrorMessage":"Tool 'reply_send_inbox_reply' is missing required argument(s): message. Supply a real value for each; null, empty strings, and empty arrays are not accepted for required fields."}
{"Success":false,"ErrorCode":"InvalidArguments","ErrorMessage":"Tool 'reply_search_contacts' arguments failed validation: : At least one of Email or LinkedIn must be provided. If the user gave only a name or company, ask them for an email address or LinkedIn URL instead."}
Error layers to handle:
- Transport / auth.
401(missing/invalid key),403(valid key, missing scope or plan feature),429(rate limit — back off usingX-Rate-Limit-Reset),5xx(transient). - Tool-level
ErrorCodes (inside the envelope):InvalidArguments,NotFound,Forbidden,Conflict,InvalidInput,InvalidParameter,UpstreamFailure,ServiceUnavailable, plus domain-specific codes named per tool in the reference below (NoEmailAccounts,NoContacts,ContactLimitExceeded,ChannelMismatch,ContactOptedOut,ThreadSendFailed,InvalidStatusTransition,ArticleNotFound,PERMISSION_DENIED, …). Each tool’s description states which codes it can return and what to do about each. - Per-item partial results. Batch tools report per-contact skips in
NotProcessed(e.g.ContactAlreadyInSequence,ContactInBlackList,NotFound) while the call as a whole succeeds. Read them; never claim an item succeeded unless it appears in the affected list.
Safe-retry matrix.
- Auto-retry once on transient
ServiceUnavailable/UpstreamFailure/timeout: all 📖 read tools —search_*,list_*,get_*,filter_*,*_stats,compare_*,get_app_map,search_knowledge_base. - Retry only after a verifying read:
create_*,update_*,add_contact_to_sequence,change_status_in_sequence,assign_*,attach_*,complete_task,mark_contacts_as_replied. - Never auto-retry — confirm with the user first:
send_inbox_reply,approve_message,bulk_approve_messages,reject_message,start_sequence,blacklist_contact,change_contact_owner, and switching to Autonomous. A timed-out send may already have succeeded server-side; verify with a read before retrying.
4. Design principles for agents
Resolve before you mutate. Almost every mutating tool takes exact numeric IDs (sequence, contact, task, thread, user, email-account, LinkedIn-account, schedule, offer, playbook, knowledge-base). Never invent an ID, and never ask the user for one — users don’t know internal IDs. Search → confirm the match → act → verify:
User: "Add John from Acme to the Q3 outbound sequence."
1. reply_search_contacts(email or LinkedIn URL) — note: this tool needs an email/LinkedIn,
not a name; if you only have a name, ask the user for an email first.
2. reply_search_sequences(name: "Q3 outbound")
3. If exactly one contact and one sequence match, confirm and call
reply_add_contact_to_sequence(sequenceId, [contactId]).
4. Read NotProcessed in the result; verify with reply_get_contact_activity(contactId).
Gate high-stakes actions. The server executes a successful call immediately — there is no undo. Confirm with the user before anything that sends to a prospect, starts outreach, enrolls contacts, changes ownership, blacklists, bulk-approves, or switches Jason to Autonomous. Two traps worth naming: reply_reject_message doesn’t just discard a draft — it removes the contact from the sequence entirely (to merely revise a draft, use reply_regenerate_message); and reply_send_inbox_reply supports only threadId + channel + message in v1 — no Cc/Bcc, attachments, or scheduling, 32,000-char max, channel must match the thread’s.
Separate discovery, configuration, and execution. Discover objects and IDs (search_* / list_* / get_*), configure the sequence (mailboxes, schedules, offers, knowledge bases, playbooks, reply mode), then execute (start, approve, send, complete). reply_start_sequence fails with NoEmailAccounts or NoContacts if you skip configuration.
MCP is the interactive surface; REST is the exhaustive one. These 70 tools cover most day-to-day operations. Drop to the REST API (api.reply.io/v3) for bulk imports and updates, background jobs, deep report exports, and anything absent from tools/list.
5. Tool index (70 tools)
One line per tool. Full signatures, per-argument documentation, enum values, and per-tool failure modes live on the dedicated reference page: /mcp/tools (markdown twin: /mcp/tools.md). Badges: 📖 read-only (readOnlyHint) · ✏️ mutation (destructiveHint) · ⚠️ prospect-visible or irreversible — confirm with the user first.
Sequences — discover & inspect
| Tool | What it does | |
|---|---|---|
reply_search_sequences | 📖 | Returns a paginated list of sequences (campaigns) the user owns or has access to, optionally filtered by name substring, status, and archive flag. |
reply_get_sequence_steps | 📖 | Returns the ordered steps of a sequence: each step’s type, delay, position in the flow, and how many message content variants it has. |
reply_get_sequence_step_variants | 📖 | Returns the content variants (A/B variations) of a single sequence step: subject, message body, enabled flag, and attachment flag. |
reply_get_sequence_stats | 📖 | Returns email and LinkedIn performance metrics for one sequence: contact volume, delivered/opened/replied/bounced rates, LinkedIn connection and message stat… |
reply_compare_sequence_performance | 📖 | Returns side-by-side email + LinkedIn performance metrics for multiple sequences in a single call. |
Sequences — control & configuration
| Tool | What it does | |
|---|---|---|
reply_start_sequence | ✏️⚠️ | Starts (or resumes) a sequence so it begins sending outreach. |
reply_pause_sequence | ✏️ | Pauses a sequence so it stops sending outreach. |
reply_add_contact_to_sequence | ✏️⚠️ | Adds one or more existing contacts to a sequence so they begin receiving its steps. |
reply_change_status_in_sequence | ✏️ | Sets the per-sequence status of a single contact inside one sequence. |
reply_assign_email_account_to_sequence | ✏️ | Links an email account (mailbox) to a sequence so the sequence can send from it. |
reply_assign_linkedin_account_to_sequence | ✏️ | Links a LinkedIn account to a sequence so the sequence can run LinkedIn steps from it. |
reply_assign_schedule_to_sequence | ✏️ | Sets the sending schedule (business-hours window) on a sequence. |
reply_attach_offer_to_sequence | ✏️ | Attaches an offer to an AI SDR sequence so Jason pitches it for that sequence’s outreach. |
reply_attach_playbook_to_sequence | ✏️ | Attaches a playbook to an AI SDR sequence so Jason follows it for that sequence’s outreach. |
reply_attach_knowledge_base_to_sequence | ✏️ | Attaches a knowledge base to an AI SDR sequence so Jason uses it when answering prospects in that sequence. |
reply_set_sequence_reply_mode | ✏️⚠️ | Sets how the AI SDR (Jason) handles outgoing messages for one sequence. |
Contacts
| Tool | What it does | |
|---|---|---|
reply_search_contacts | 📖 | Looks up contacts by exact email address or LinkedIn URL. |
reply_filter_contacts | 📖 | Lists contacts narrowed by list membership, sequence membership and/or a free-text search term applied to name/email/company. |
reply_create_contact | ✏️ | Creates a new contact in the workspace. |
reply_update_contact | ✏️ | Updates fields on an existing contact. |
reply_get_contact_activity | 📖 | Returns the activity history for one contact: emails sent / opened / replied, LinkedIn actions, calls, manual events, ordered newest first. |
reply_mark_contacts_as_replied | ✏️ | Marks one or more contacts as having replied (or clears that flag), the same action as manually flagging a reply in Reply.io. |
reply_change_contact_owner | ✏️⚠️ | Reassigns one or more contacts to a different Reply.io user. |
reply_blacklist_contact | ✏️⚠️ | Adds the contact’s email (or the contact’s whole email domain) to the workspace blacklist so future outreach to that address (or any address on that domain)… |
Inbox & conversations
| Tool | What it does | |
|---|---|---|
reply_get_inbox_emails | 📖 | Returns inbox threads (email + LinkedIn replies), typically newest first by LastActivityDate as ordered by the underlying service, with a short body preview,… |
reply_send_inbox_reply | ✏️⚠️ | Sends a reply on an existing inbox thread. |
reply_change_inbox_category | ✏️ | Assigns (or clears) the workspace-defined category on one inbox thread. |
Jason AI SDR — approvals & autopilot
| Tool | What it does | |
|---|---|---|
reply_list_pending_approvals | 📖 | Returns the queue of AI SDR (Jason) draft messages waiting for the user’s approval before they are sent, newest first by default. |
reply_approve_message | ✏️⚠️ | Approves a single AI SDR draft and sends it to the contact immediately. |
reply_bulk_approve_messages | ✏️⚠️ | Approves multiple AI SDR drafts at once and sends them all immediately. |
reply_reject_message | ✏️⚠️ | Rejects a single AI SDR draft. |
reply_regenerate_message | ✏️ | Asks the AI SDR to rewrite a single pending draft, optionally guided by the user’s feedback. |
Jason AI SDR — knowledge bases
| Tool | What it does | |
|---|---|---|
reply_list_knowledge_bases | 📖 | Lists the AI SDR (Jason) knowledge bases in the workspace: the bundles of company information Jason uses to answer prospects, which can be attached to sequen… |
reply_get_knowledge_base | 📖 | Returns one AI SDR (Jason) knowledge base in full: its name, its free-text Instructions, the web-page URL sources it contains (with their source ids), and ho… |
reply_create_knowledge_base | ✏️ | Creates a new AI SDR (Jason) knowledge base. |
reply_update_knowledge_base | ✏️ | Updates an existing AI SDR (Jason) knowledge base. |
reply_add_knowledge_base_source | ✏️ | Adds a web-page URL as a source to an AI SDR (Jason) knowledge base, so Jason can use that page’s content when answering prospects. |
reply_delete_knowledge_base_source | ✏️ | Removes a URL source from an AI SDR (Jason) knowledge base. |
Jason AI SDR — reply handlers
| Tool | What it does | |
|---|---|---|
reply_list_reply_handlers | 📖 | Lists the reply handlers in an AI SDR (Jason) knowledge base. |
reply_get_reply_handler | 📖 | Returns one reply handler from an AI SDR (Jason) knowledge base in full: its question type, instructions, sample answer, tone of voice, response length, link… |
reply_create_reply_handler | ✏️ | Adds a reply handler to an AI SDR (Jason) knowledge base so Jason knows how to answer a specific kind of prospect question. |
reply_update_reply_handler | ✏️ | Updates a reply handler in an AI SDR (Jason) knowledge base. |
reply_delete_reply_handler | ✏️ | Removes a reply handler from an AI SDR (Jason) knowledge base. |
Jason AI SDR — reengagement cards
| Tool | What it does | |
|---|---|---|
reply_list_reengagement_cards | 📖 | Lists the reengagement cards in an AI SDR (Jason) knowledge base. |
reply_get_reengagement_card | 📖 | Returns one reengagement card from an AI SDR (Jason) knowledge base in full: its name, instructions, sample answer, send-after days, tone of voice, response… |
reply_create_reengagement_card | ✏️ | Adds a reengagement card to an AI SDR (Jason) knowledge base so Jason knows how to win back a prospect who went quiet. |
reply_update_reengagement_card | ✏️ | Updates a reengagement card in an AI SDR (Jason) knowledge base. |
reply_delete_reengagement_card | ✏️ | Removes a reengagement card from an AI SDR (Jason) knowledge base. |
Jason AI SDR — offers
| Tool | What it does | |
|---|---|---|
reply_list_offers | 📖 | Lists AI SDR (Jason) offers: what Jason can pitch to prospects. |
reply_get_offer | 📖 | Returns one AI SDR (Jason) offer in full: company name and description, ideal customer profile (ICP), reason for outreach, and the lists of case studies, pai… |
reply_create_offer | ✏️ | Creates a new AI SDR (Jason) offer that Jason can pitch. |
reply_update_offer | ✏️ | Updates an existing AI SDR (Jason) offer. |
reply_generate_offer_from_website | 📖 | Asks Jason to draft offer content from a company website URL (and optional extra notes). |
Jason AI SDR — playbooks
| Tool | What it does | |
|---|---|---|
reply_list_playbooks | 📖 | Lists AI SDR (Jason) playbooks: the named sets of selling instructions Jason can follow. |
reply_get_playbook | 📖 | Returns one AI SDR (Jason) playbook in full, including its instruction Body (the prompt that tells Jason how to sell), visibility type, and the names of any… |
reply_create_playbook | ✏️ | Creates a new AI SDR (Jason) playbook: a named set of selling instructions. |
reply_update_playbook | ✏️ | Updates an existing AI SDR (Jason) playbook. |
reply_duplicate_playbook | ✏️ | Duplicates an existing AI SDR (Jason) playbook into a new one with the same description and instruction Body. |
Tasks
| Tool | What it does | |
|---|---|---|
reply_list_my_tasks | 📖 | Returns the user’s tasks (To Do, Call, Meeting, LinkedIn, Manual Email, Sms, WhatsApp), filterable by status, type, due window, and contact. |
reply_create_task | ✏️ | Creates a new task (ToDo / Call / Meeting / LinkedIn / ManualEmail / Sms / WhatsApp) for the user. |
reply_complete_task | ✏️ | Marks an existing task as completed. |
Workspace resolvers & accounts
| Tool | What it does | |
|---|---|---|
reply_list_email_accounts | 📖 | Returns the email accounts (mailboxes) configured in the workspace, with their connection status, daily send limit, default flag, and tags. |
reply_list_linkedin_accounts | 📖 | Returns the LinkedIn accounts connected to the workspace, with status, cookie health, account tier, and ownership. |
reply_list_schedules | 📖 | Returns all sending schedules (business-hours / sending-window configurations) in the workspace, with timezone, default flag, and counts of main + follow-up… |
reply_search_lists | 📖 | Resolves contact lists (a.k.a. |
reply_search_team_members | 📖 | Resolves teammates in the current workspace to their numeric UserId by name or email substring. |
Help & meta
| Tool | What it does | |
|---|---|---|
reply_search_knowledge_base | 📖 | Searches the Reply.io Help Center for articles that answer product how-to and support questions (for example ‘how do I add an account’, ‘what does autopilot… |
reply_get_knowledge_base_article | 📖 | Returns the full text and source URL of a single Reply.io Help Center article identified by its slug (obtained from reply_search_knowledge_base). |
reply_get_app_map | 📖 | Returns the catalog of Reply.io app areas: each entry has a title, a short description, the exact in-app navigation steps, and a relative URL. |
reply_report_unsupported_request | 📖 | Records, for the product team, that the user asked for a capability Reply.io does not currently have. |
6. Workflow recipes
Concrete call graphs an agent can follow. Each resolves IDs first, configures where needed, confirms before high-stakes steps, and verifies after.
Launch a sequence safely
reply_search_sequencesby name → resolve the exactsequenceId(ask the user if ambiguous).reply_get_sequence_steps→ see which channels the sequence uses.- If it has email steps:
reply_list_email_accounts, thenreply_assign_email_account_to_sequenceif none is attached. - If it has LinkedIn steps:
reply_list_linkedin_accounts, thenreply_assign_linkedin_account_to_sequence; warn if the account is unhealthy. reply_list_schedules, thenreply_assign_schedule_to_sequenceif none is set.- Optional AI SDR:
reply_attach_offer_to_sequence/reply_attach_playbook_to_sequence/reply_attach_knowledge_base_to_sequence, thenreply_set_sequence_reply_mode. - Confirm with the user: “Start sequence X? This begins outreach to its contacts.”
reply_start_sequence— expectNoContacts/NoEmailAccounts/Archivedif configuration was skipped.reply_get_sequence_statsorreply_search_sequencesto confirm it is Active.
Add a contact to a sequence
reply_search_contactsby email or LinkedIn URL (the tool does not accept names — ask the user for an email if that’s all you have).- If missing and the user confirms details,
reply_create_contact(needs a name plus at least one of email/LinkedIn URL). reply_search_sequencesfor the target sequence.- Confirm, then
reply_add_contact_to_sequence(up to 100 IDs; per-contact skips arrive inNotProcessed, e.g.ContactAlreadyInSequence,ContactInBlackList). reply_get_contact_activityto verify enrollment.
Supervise Jason in Review mode
reply_set_sequence_reply_mode→ Review (if not already).reply_list_pending_approvals— filter by sequence, owner, or channel.- For each draft (addressed by
sequenceId+contactId):- inspect the contact and context, compare against the attached playbook/knowledge base;
reply_approve_message(optionally overriding body/subject) — sends immediately;reply_regenerate_messagewith specific feedback to revise the draft;reply_reject_messageonly if the contact should leave the sequence entirely — rejection is irreversible and removes them from the sequence.
reply_bulk_approve_messagesonly after every draft in the batch was reviewed — the batch is atomic: one stale reference rejects the whole batch and nothing is sent.
Switch Jason to Autonomous
- Verify the sequence has an offer, playbook, and knowledge base attached and reviewed.
- Confirm explicitly: Autonomous mode sends replies without per-message approval.
reply_set_sequence_reply_mode→ Autonomous.- Keep watching
reply_get_inbox_emailsandreply_get_sequence_stats.
Reply to an inbox thread
reply_get_inbox_emails(pagination only in v1 — no filters; previews only, not full bodies) → resolve the exactthreadIdand note its channel.- Draft the reply and show it to the user for approval.
reply_send_inbox_replywith the matchingchannel(‘Email’ or ‘LinkedIn’) — v1 supports message body only (max 32,000 chars); no Cc/Bcc, attachments, or scheduling. ExpectChannelMismatch,ContactOptedOut, orThreadSendFailedas the named failure modes.- Optionally
reply_change_inbox_categoryto reflect the new state.
Handle an unsupported request
- Confirm no tool in
tools/listcan do it. reply_get_app_map— the action may be a UI-only setting; return the exact in-app link.reply_search_knowledge_base+reply_get_knowledge_base_article— answer a how-to and cite the source.- Only if genuinely missing,
reply_report_unsupported_requestwith a stable kebab-caserequestKeyand a category from its enum (integrations, reporting, sequences, contacts, email, linkedIn, ai, other) — then tell the user plainly you cannot do it. Offer the REST API if it covers the gap.
7. High-stakes tools
Require explicit confirmation in almost any agent UX — each reaches a prospect or changes ownership/state the instant it succeeds:
reply_start_sequence— begins outreach processing.reply_add_contact_to_sequence— enrolls people into outreach.reply_send_inbox_reply— sends a real message to a contact.reply_approve_message/reply_bulk_approve_messages— send Jason’s drafts (bulk is atomic, ≤100).reply_reject_message— irreversible: discards the draft AND removes the contact from the sequence. Usereply_regenerate_messageif the user merely dislikes the draft.reply_blacklist_contact— suppresses an email (or, withblockEntireDomain, a whole company domain — including future contacts) from all outreach.reply_change_contact_owner— changes visibility and responsibility; trust onlyAffectedContactIdswhen reporting what changed.reply_set_sequence_reply_mode→ Autonomous — Jason sends without per-message review.
Usually worth confirming too (production-affecting, but not prospect-visible): reply_pause_sequence, reply_change_status_in_sequence, the reply_assign_* / reply_attach_* configuration tools, reply_complete_task, and any create/update/delete on knowledge bases, reply handlers, reengagement cards, offers, or playbooks. The server’s destructiveHint annotation marks all 39 mutations — use it as the machine-readable gate.
8. Relationship to the REST API (v3)
MCP and the REST API are the same platform and the same account — two surfaces over one product. Base REST URL https://api.reply.io/v3, Authorization: Bearer auth, 100 req/min and 3000 req/hour.
- MCP — interactive agent actions and natural-language workflows; 70 curated, annotated tools.
- REST — bulk imports/updates, background jobs, report exports, webhooks, and template/schedule/mailbox management not exposed as tools.
Rough mapping of MCP tool areas to the REST modules in the API catalog:
| MCP area | REST module |
|---|---|
| Sequence discover/control | Sequence API |
| Contact search/CRUD | Contact Data API |
| Inbox tools | Conversations & Inbox API |
| Jason KB / offers / playbooks / approvals | AI SDR API (Jason) |
| Tasks | Tasks API |
| Email/LinkedIn account resolvers | Mailbox Management · LinkedIn Accounts |
| Sequence/contact stats | Analytics API |
reply_blacklist_contact | Suppression & Blacklist API |
9. Agent prompt guidance
Drop this into an agent’s system prompt when it has Reply MCP tools:
You have access to Reply.io MCP tools. For every request:
1. Classify it: read-only, configuration, outreach-changing, or prospect-visible send.
The server annotates every tool (readOnlyHint / destructiveHint) — honor them.
2. For any mutation, resolve exact numeric IDs first with search/list/filter tools.
Never guess an ID and never ask the user for one.
3. For high-stakes actions (send, approve, reject, start, enroll, blacklist, change owner,
go Autonomous), summarize the target and side effect, then ask the user to confirm.
Remember: reject_message removes the contact from the sequence — it is not "discard draft".
4. Parse results from result.content[0].text: {"Success":true,"Data":...} or
{"Success":false,"ErrorCode":...,"ErrorMessage":...}. Branch on ErrorCode.
Read per-item results (NotProcessed / AffectedContactIds) and report exact counts.
5. Do not pass unknown arguments (schemas are additionalProperties:false) and never send
empty strings/arrays for required fields.
6. Paginate with top/skip until HasMore is false.
7. On failure, follow the tool's own failure-mode guidance. Do not blindly retry sends,
approvals, starts, or enrollments — a timeout may already have succeeded; verify first.
8. If no tool fits, try reply_get_app_map and reply_search_knowledge_base before saying
you can't; then reply_report_unsupported_request if it is truly missing.
10. Reproduce this
The reference on this page is not hand-maintained trust — regenerate it in seconds:
curl -s -X POST https://mcp2.reply.io/ \
-H "x-api-key: YOUR_REPLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"probe","version":"0.1"}}}'
# then:
curl -s -X POST https://mcp2.reply.io/ \
-H "x-api-key: YOUR_REPLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
Responses are SSE — take the JSON after the last data: line. If the returned tool set differs from this page, the server is newer — trust the server. This reference was captured 2026-07-05.
Frequently asked questions
Is the MCP server real, and how current is this page?
Real and live. Endpoint https://mcp2.reply.io/, server Reply.Mcp v1.0.0.0, MCP protocol 2025-06-18. Every tool, parameter, enum value, annotation, envelope shape, and error mode on this page and the full tool reference (/mcp/tools) was read from the running server via authenticated initialize + tools/list and safe validation probes on 2026-07-05 — not from documentation. Re-probe any time; the surface grows.
How does authentication work?
Send your Reply.io API key as an x-api-key header or an Authorization Bearer token — this server accepts either. The endpoint also advertises OAuth 2.0 protected-resource metadata (authorization server oauth.sandbox.replyapp.io, scopes reply-web-api and mcp:tools) for clients that prefer an OAuth flow. Get an API key in the Reply.io app under Settings → API Key. No session header is required — initialize and tools/list work without Mcp-Session-Id.
How do I know which tools are safe to call?
The server tells you, machine-readably. Every tool carries MCP annotations — readOnlyHint (31 tools) or destructiveHint (39 tools). Agents can auto-gate on them; anything destructive that reaches a prospect or changes ownership (start, enroll, send, approve, reject, blacklist, change owner, go Autonomous) should also get explicit user confirmation. Note reply_reject_message is irreversible — it removes the contact from the sequence entirely.
What do responses look like?
Responses arrive as SSE (text/event-stream) frames carrying JSON-RPC payloads. The tool result is a JSON string inside result.content[0].text — {"Success":true,"Data":{...}} on success, {"Success":false,"ErrorCode":"...","ErrorMessage":"..."} on failure (with result.isError=true, HTTP still 200). Parse the inner JSON; branch on Success and ErrorCode.
When should an agent use MCP instead of the REST API?
Use MCP for interactive, natural-language work — 70 tools cover most day-to-day operations including the full Jason AI SDR autopilot. Use REST (api.reply.io/v3) for bulk imports, scheduled backend syncs, deep report exports, and anything tools/list does not expose.
Is the Jason autopilot really callable here?
Yes. The approval queue, the Review↔Autonomous switch, and the whole knowledge base / offer / playbook / reply-handler / reengagement-card surface are live MCP tools — even where the equivalent REST v3 autopilot endpoints are still rolling out.