> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reply.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Building agents

> Design principles, high-stakes gating, and a drop-in system prompt for agents that use Reply MCP.

Reply MCP executes a successful call **immediately** — there is no undo. These principles keep an
agent safe and effective. They pair with the [tool contract](/mcp/tool-contract) (how calls behave)
and the [workflow recipes](/mcp/recipes) (concrete call graphs). For the platform-wide,
surface-independent versions of these rules, see [Agent safety rules](/agents/safety) and
[Drop-in system prompts](/agents/prompts).

## Design principles

### 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:

```text theme={null}
User: "Add John from Acme to the Q3 outbound sequence."
1. reply_search_contacts(email or LinkedIn URL) — 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

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`.
* **`reply_send_inbox_reply` supports only `threadId` + `channel` + `message` in v1** — no Cc/Bcc,
  attachments, or scheduling; 32,000-char max; the 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-reference/introduction)
(`api.reply.io/v3`) for bulk imports and updates, background jobs, deep report exports, and anything
absent from `tools/list`.

## High-stakes tools

Each of these reaches a prospect or changes ownership/state the instant it succeeds. Require
explicit confirmation in almost any agent UX:

| Tool                                                    | Why it's high-stakes                                                                                                                                  |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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. Use `reply_regenerate_message` if the user merely dislikes the draft |
| `reply_blacklist_contact`                               | Suppresses an email (or, with `blockEntireDomain`, a whole company domain — including future contacts) from all outreach                              |
| `reply_change_contact_owner`                            | Changes visibility and responsibility; trust only `AffectedContactIds` when 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.

## Drop-in system prompt

Add this to an agent's system prompt when it has Reply MCP tools:

```text theme={null}
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.
```

Next: [workflow recipes](/mcp/recipes) turn these principles into concrete call graphs.
