Reference
MCP
Every Tinbox deployment exposes a Model Context Protocol endpoint at /mcp. Connect the Claude app, Claude Code, or any MCP agent and it gets the exact same tools the in-app assistant runs — search mail, summarize threads, draft and send, and manage audiences and campaigns.
84 tools over MCP
Connect a client
Point your MCP client at the deployment's /mcp URL. The Claude app one-click-connects via OAuth; CLI agents use a static tbx_… bearer token.
{
"mcpServers": {
"tinbox": {
"url": "https://acme.com/mcp"
}
}
}search_docs
The endpoint also exposes a search_docs tool: a full-text search over these docs (guides + the tool, CLI, and SDK reference) so an agent can look up how a capability works before calling it.
Tools exposed over MCP
Each links to its full schema and example payload. See the capability matrix for how these correspond to the CLI and SDK.
search_emailsFull-text search the user's mail by subject, sender, or body. Call this to find relevant emails BEFORE answering — never answer from memory about specific mail. Returns matching messages with threadId, inboxId, subject, sender, and a body preview.
list_threadsList recent conversation threads (most recent first). Use to browse an inbox or get an overview. Returns thread summaries with id, subject, participants, and message count.
get_threadFetch one thread with its full message history (sender, recipients, subject, body) and attachments. Call this to read a conversation before summarizing or drafting a reply.
create_draftCreate a reply DRAFT (never sends on its own — a human reviews and sends, or use send_email if enabled). Provide the inboxId and, for a reply, the threadId. Returns the new draft's id and version.
update_draftEdit an existing draft (compare-and-swap on baseVersion to avoid clobbering concurrent edits). Pass the draft id, the baseVersion you last saw, and the fields to change.
summarize_threadSummarize an email thread: who's involved, what they want, the state, and what needs a response. Use when the user asks for a summary or 'what's this about'. Reads the thread, then summarizes.
send_emailSEND an email now (this actually dispatches mail — it is not a draft). Requires a human approval step in chat. Use only when the user explicitly asks to send. Prefer create_draft when unsure.
get_delivery_statusCheck the delivery status of a specific sent email by its id. Returns the current status, delivery events timeline, and any errors. Use to verify if an email was delivered, bounced, or is still pending.
send_campaignSend an approved campaign immediately to all recipients. This is irreversible — the emails will be sent. Requires the campaign to be in approved status.
send_test_campaignSend a one-off test of a campaign draft to a single verified address (e.g. yourself) before the real send. Goes only to that address; it does NOT touch the recipient list or ledger. The natural last check before approve_campaign.
draft_outreach_bodyDraft (or re-draft) one prospect's personalized cold body from the campaign's first sequence-step instruction (or an override) + the prospect's qualification signal. Moves the prospect sourced → drafted; nothing sends. Needs a model wired.
draft_all_pendingDraft a personalized cold body for EVERY sourced (not-yet-drafted) prospect in a campaign, in one bounded pass. Moves each sourced → drafted; nothing sends. Returns a tally. Needs a model wired.
get_send_readinessCheck whether this deployment can send a given campaign type right now, and if not, exactly what's missing. Returns an ordered checklist per lane (broadcast, outreach, journey) with fix hints and deep-links. Use before creating or launching a campaign to know what to set up first. Pass phase 'send' to treat an empty audience as a hard blocker (would send to 0 people); 'create' is permissive.
check_sending_domainCheck a domain's live DNS / verification state — re-runs the DNS check now and returns which records are verified (MX/SPF/DKIM/DMARC) and which are still missing, plus whether receiving and sending are valid. Read-only (it changes no config; it just checks). Use to answer 'is my domain verified yet?' during onboarding, or to point the operator at the exact records still to add in Settings → Domains. Give the domain (e.g. yourdomain.com).
set_thread_directiveAttach follow-up logic to a thread: when a reply arrives (or after a delay), the platform drafts/sends/asks/notifies per your instructions. Use it when the user wants a standing reply plan on a conversation ('if they reply, draft an answer in my voice'; 'remind me if no reply in 3 days'). `trigger`: 'reply' fires on the next inbound; 'no_reply_after'/'after' are timers (set `after` like '3d'/'7d'). `action.mode`: 'draft' (default — lands in Review), 'send' (auto-sends, if the deployment permits; otherwise downgraded to a draft), 'ask' (parks a check-in question), 'notify' (notification only). Cancel with cancel_thread_directive.
list_thread_directivesList the follow-up directives on a thread — the reply logic attached to it (trigger, mode, status, how many times it's fired, when it expires). Read-only; use it to check what will happen when a reply lands before setting or canceling one.
cancel_thread_directiveCancel a thread follow-up directive by id (from list_thread_directives) so it never fires again. The undo for set_thread_directive. Idempotent — canceling an already-canceled or already-fired directive is a safe no-op.
Other
create_disposable_mailboxMint a throwaway email address and a pollToken to read its mail with poll_disposable_mailbox. Ideal for grabbing a one-time code (OTP) without touching a real inbox. By default the ADDRESS is kept (a catch-all keeps routing its mail) and the TOKEN never expires — pass expiresIn (e.g. '2h', '30m', '7d') to expire the token, and expireAddress:true to also tear the address down at that time.
poll_disposable_mailboxRead the mail that has arrived at a disposable mailbox, newest first (returns ALL messages — a fresh box holds under 10). Pass the pollToken from create_disposable_mailbox. Use format='simplifiedMD' or 'otpOnly' to get a one-time code fast: any code the OTP skill detected is surfaced first.
drop_disposable_mailboxStop NEW mail from arriving at a disposable address (e.g. once a newsletter or signup starts spamming it) while KEEPING the mail already received and the poll token. You can still poll what's there; future mail to the address is rejected. Use burn_disposable_mailbox instead to also delete everything.
burn_disposable_mailboxImmediately destroy a disposable mailbox and EVERYTHING in it — the address, the stored mail, and the token (don't wait for expiry). Pass the pollToken. Use drop_disposable_mailbox instead if you only want to stop NEW mail but keep what's there.
company_briefTrace and summarize the whole relationship with a company (everyone you've emailed at a domain). Use when the user asks 'what's going on with <company>' or 'summarize our relationship with X'. Searches mail from that domain, groups by person, and summarizes.
list_templatesList all email templates available for campaigns. Returns each template's name, preview, and last update time.
get_templateGet a specific email template's full content (HTML with merge tags). Use to review or copy template content.
create_templateCreate a new email template. Provide HTML content with optional merge tags like {{contact.name}}, {{contact.email}}, {{urls.unsub}}.
update_templateUpdate an existing email template's name or HTML content.
preview_templateRender a template's merge-tag HTML with sample data to see what a recipient would receive. Pass a saved template `id`, or raw `html` to preview an unsaved draft.
list_personalized_reviewRead the per-recipient review queue for a personalized warm campaign — each subscriber's drafted (or approved) body. Use to review the rewritten bodies before approving them to send.
approve_personalizedBulk-approve (or revert) per-recipient warm bodies by their review-row ids. Approving marks them ready to send on the next campaign send — gated on the newsletter:send capability. This is the content lock for personalized sends.
source_prospectsSource + qualify prospects into a cold campaign WITHOUT sending. Resolve a candidate set from explicit org domains and/or a Contacts search (plus the campaign's stored sourcing config), run the GTM qualifier over each, and persist the qualified rows (idempotent per recipient). Writes sourced rows only — no email goes out.
list_review_queueRead the ranked review queue for a cold campaign — every prospect (optionally one stage), hottest-first by qualification score, with whether each has a drafted body. Use to review what's ready before approving prospects to send.
approve_prospectsApprove specific prospects (drafted → approved) so they become eligible to send on the next scheduled tick. Capability-gated (outreach:send) AND routed through the HARD cold-domain gate server-side: a prospect can never be approved on a warm/unverified domain. This begins real, irreversible cold sends.
deny_prospectsReject specific prospects out of the review queue (→ denied). Denying never sends, so it's reversible (re-source or re-draft to bring rows back). Capability-gated (outreach:send) like approve.
launch_outreachLaunch a cold campaign (review → approved) — the content lock that makes its approved prospects dispatchable. Capability-gated (outreach:send) AND routed through the HARD cold-domain gate: a campaign whose from/reply-to isn't on a VERIFIED cold subdomain is rejected. Actual sends fire on the scheduled tick (throttled + ramped). Irreversible: begins real outreach.
pause_outreachHold a cold campaign mid-sequence (→ paused). Resumable — no prospects are lost; sending stops until resumed. Reversible.
outreach_replies_digestA reply-intent triage summary for a cold campaign: how many prospects replied (of how many sent), with a pointer to the Inbox where the actual reply conversations live (the one place an AI summary of intent earns its keep). Use to triage 'who replied to my outreach?'.
list_journeysList email automation journeys (triggered multi-step sequences like welcome series or drips), newest first, with each journey's status, step count, and per-status run counts. Use to discover journeys before inspecting, editing, activating, or enrolling contacts.
get_journeyGet one journey with its ordered steps (email/delay/condition/tag) and trigger. Use before editing, activating, or enrolling contacts.
create_journeyCreate a new email automation journey (draft) for an audience. A journey is a triggered, multi-step sequence (e.g. a 3-email welcome series). It starts in 'draft' with no steps — add steps with add_journey_step, then activate_journey to turn it on. Optionally set a trigger (e.g. { type: "api_event" } for contacts enrolled via enroll_in_journey, or { type: "signup" }).
add_journey_stepAppend a step to a journey (or insert it at `order`). Step types and their `config`: - email: { subject: string, bodyMd?: string } — the email to send. ALWAYS write the body (`bodyMd`, markdown), not just a subject, so the draft is complete and reviewable. - delay: { amount: number, unit: 'minutes'|'hours'|'days' } (wait before the next step) - condition: { conditions: { match: 'all'|'any', rules: [...] }, onPass?: 'continue'|'skip'|'exit', onFail?: 'continue'|'skip'|'exit' } — branch on subscriber attributes or prior-email engagement (rule op 'opened_prev'/'clicked_prev' needs the previous email to be a tracked email step with a delay after it). onPass/onFail route the run: 'continue' = fall through, 'skip' = jump the next step, 'exit' = end the run. Defaults: onPass 'continue', onFail 'exit' (a plain gate). - tag: { tag: string } (apply a tag to the contact) Build the sequence by adding steps in order; the journey must have ≥1 step before it can be activated. If the requested logic can't be expressed (only 4 trigger types; conditions test the immediately-preceding email + segment attributes; branching is continue/skip/exit only, no arbitrary goto), say so in the create_journey `rationale` rather than silently building the wrong graph.
activate_journeyActivate a journey (draft|paused → active). Once active, triggers enroll contacts and the scheduler sends the journey's email steps. The journey must have at least one step. This starts REAL sends — treat like sending a campaign.
pause_journeyPause an active journey (active → paused). Existing runs freeze and no new contacts enroll until it's activated again. The off-switch for activate_journey.
enroll_in_journeyEnroll a contact into an api_event journey by contact id or email — the manual trigger. The journey must be active. Ledger-safe: it only enrolls (the send happens on the next scheduler tick). A non-reentrant duplicate is a no-op (enrolled:false).
dispatch_notificationDispatch a notification to a subscriber across their active channels matching the topic. payload should include a title and body. Returns per-channel delivery results.
list_forwarding_rulesList inbound forwarding rules — which inbound addresses forward a copy to which external destinations.
add_forwarding_ruleForward a copy of inbound mail to an external address. matchAddress restricts to one inbound address; omit it to forward ALL inbound mail.
search_imagesFind stock images (or generate an AI placeholder) for a campaign or newsletter body. mode='search' queries the okslop stock library by keyword; mode='generate' returns a deterministic AI-generated placeholder for a prompt (use when nothing fits or you need a hero image). Returns image URLs you can drop into markdown as . Read-only — picking an image is your job; nothing is inserted or sent.
get_setup_stateCheck how set up this deployment is and what's left to configure. Returns the ordered onboarding checklist — every milestone (add a sending domain, verify DNS, confirm inbound routing, create an inbox, receive/send the first email, enable the assistant, invite the team) with its state (done | pending | blocked), a fix hint, and a deep link to the exact settings pane. Use this to answer 'what's left to set up?' and to walk the operator through remaining steps ONE at a time. For 'can I send a campaign right now?' use get_send_readiness instead. Read-only; never fabricate DNS or dashboard steps — take them from this tool's hints.
create_inboxCreate ONE new inbox at a mailbox address (e.g. support@yourdomain.com). ORG-ADMIN ONLY and requires a human approval step in chat — the approval card shows the exact address and type before it's created. Use for the onboarding 'set up your first mailbox' step or when the operator asks to add a shared/personal inbox. Provide localPart (the bit before @); domain defaults to the deployment's sending domain. type 'shared' is a team inbox (support@, sales@), 'personal' is one person's. To create a SET of role addresses at once, tell the operator to use Settings → Inboxes presets (this tool creates one at a time).
get_handbookRead the team handbook — the operator's standing policies (plain-language lines like 'Never email competitor domains'). Returns every active entry with its id, text, topic, source, and creation time; pass `topic` to filter to one section. Use it to check what standing behavior applies before acting, or when the user asks what's in the handbook. Read-only.
update_handbookRecord, edit, or archive a standing policy in the team handbook. Use this when the user states a standing preference or corrects your behavior ('from now on…', 'always…', 'never…'): propose the exact one-line wording, get their confirmation, THEN call this with op:'add'. Never record anything silently. If the new preference contradicts an existing line (check get_handbook), use op:'edit' on that line's entryId instead of adding a duplicate. op:'archive' retires a line that no longer applies. Reversible: nothing is ever hard-deleted — an add is undone by archive, an edit by another edit. `entryId` accepts the full id or the short [hbk_*] handle.
Audiences
search_contactsFind people the user corresponds with — by name or email prefix. Use to resolve a recipient before drafting/sending, or to look someone up. Returns matching contacts (recent correspondents first).
upsert_contactRegister a person in the contacts registry (add-or-update by email). Use to save someone you found or were asked to track. Provide `sourceUrl` + `confidence` when the contact came from web research. Auto-commits (reversible via undo).
tag_contactApply one or more labels to a contact (by contactId or email). Labels are created if new. Idempotent — re-tagging is a no-op. Auto-commits.
untag_contactRemove one or more labels (by name or label id) from a contact (by contactId or email). No-op for a label the contact doesn't carry. Auto-commits.
set_contact_lifecycleSet a contact's lifecycle stage: `prospect` (unverified), `active` (engaged), or `invalid` (bad/bounced). Identify by contactId or email. Auto-commits.
add_contactsAdd many contacts in ONE batch (e.g. results of a research task). FLOW: find companies/people via web_search, THEN call add_contacts with each row's `sourceUrl` + `confidence` (the research provenance) and any `labels`. Returns a batch summary you can later filter the directory by. Auto-commits.
delete_contactDelete a contact (by contactId or email). This is a REVERSIBLE quarantine — the contact drops out of the registry but can be restored from Trash for 30 days before it's permanently purged. Safe to run without asking.
list_audiencesList all mailing list audiences (subscriber lists). Returns each audience's name, subscriber count, and settings. Use before adding subscribers or creating campaigns to find the right audience id.
get_audienceGet detailed info about a specific audience (mailing list), including subscriber stats by status (subscribed, unsubscribed, pending, cleaned).
create_audienceCreate a new mailing list (audience). The agent can list audiences and add subscribers, but needs this to create the list to add them to. Set the sender identity (fromName/fromEmail) and reply-to.
update_audienceUpdate a mailing list's settings (name, sender identity, reply-to, double opt-in). Partial — only the fields you pass change.
list_subscribersList subscribers (members) in an audience, optionally filtered by status or tag. Returns email, name, status, and subscription date.
add_subscriberAdd or update a subscriber in an audience. If the email already exists, updates their info. Use to subscribe new contacts or update existing ones.
remove_subscriberUnsubscribe a member from an audience (sets status to unsubscribed). The contact record is preserved for compliance. Use when someone wants to stop receiving emails.
list_campaignsList all email campaigns (newsletters). Returns each campaign's title, status, audience, and send progress.
get_campaignGet detailed info about a specific campaign, including content, status, audience, and send progress/analytics.
create_campaignCreate a COMPLETE email campaign (newsletter) draft in one call: audience (and optional segment), subject, body, sender identity (from/reply-to), a PROPOSED send time, and a short rationale for your choices. The draft lands in the campaign builder for human review — it never sends or schedules itself. Use list_audiences / list_segments first to resolve ids by name, and get_send_readiness('broadcast') before creating.
update_campaignUpdate a campaign's settings or content. Only works for campaigns in draft or in_review status. Use to edit subject, content, audience/segment, sender details (from/reply-to/preview text), or move/clear the proposed send time (null clears it).
approve_campaignApprove a campaign for sending (moves from in_review → approved). Requires newsletter:send capability. After approval, the campaign can be scheduled or sent immediately.
schedule_campaignSchedule an approved campaign to send at a specific time. The campaign must be in 'approved' status. Provide a Unix timestamp (milliseconds) for when to send.
get_campaign_reportGet a sent campaign's performance: open/click/unsubscribe analytics plus recipient-ledger progress (sent/pending/failed/suppressed) and the resolved recipient count. Use to answer 'how did my last newsletter do?'. Distinct from get_campaign (which only returns status/content).
preview_segmentCount and sample the subscribers in an audience that match a set of conditions, WITHOUT saving a segment. Lets you reason about reach before composing a campaign (e.g. 'how many active subscribers tagged VIP?'). `conditions` is { match: 'all'|'any', rules: [{ field, op, value }] }.
list_segmentsList an audience's SAVED segments (rule-based and static) with live member counts. Use to resolve a segment by name (e.g. 'active customers') before targeting a campaign at it via segmentId. For an ad-hoc, unsaved condition check use preview_segment instead.
personalize_campaignDraft PER-RECIPIENT warm bodies for a campaign from a list of subscribers + their first-party usage stats — the LLM rewrites the body for each. Flips the campaign to per-recipient mode and lands each body in the shared Review queue (drafted). Nothing sends. Needs a model wired.
list_outreach_campaignsList all cold outreach campaigns (the 1:1-at-bulk Campaign surface), newest first, each with its sourced/to-review/sent/replied rollup. Use to find a campaign id before sourcing, reviewing, or launching.
get_outreach_campaignGet one cold outreach campaign's settings (name, brief, sender identity, cold sending domain, daily cap) plus its per-stage rollup (sourced/drafted/approved/denied/sent/replied). Use to inspect a campaign before acting on it.
create_outreach_campaignCreate a new cold outreach campaign DRAFT. Provide a name and a brief (the ICP / goal prompt that drives sourcing + drafting). Bind the COLD sending domain (`sendingDomainId` + `fromEmail`/`replyTo` on it) — a domain that doesn't exist, or a deployment with no cold BYO-SMTP transport, is REFUSED here with a fix-link (run get_send_readiness('outreach') first to see what's missing). Optionally set `sourcingConfig` to source via a tenant agentic skill (kind:'agentic_skill' + skillId). Starts in draft; nothing sends — source prospects, draft bodies, and review before launch.
list_subscriber_channelsList the notification channels (email/push/webhook) registered for a subscriber (contact). Use to see where a subscriber can be reached before dispatching.
add_subscriber_channelRegister a delivery channel for a subscriber. type=email|push|webhook. For webhook, endpoint must be an http(s) URL; a signing secret is returned. Optional topics restrict which notification topics this channel receives (e.g. ['order.*']).
import_contactsBulk-import contacts from user-supplied rows INTO an audience (mailing list). ORG-ADMIN ONLY and requires a human approval step in chat — the approval card shows how many rows and which audience before it runs. Provide `csv`: a header row with an `email` column (optional `name` + any merge-field columns), then one row per contact. Re-importing the same email updates rather than duplicates. Use when the operator pastes or supplies a list of people to add to a list. `status` sets the initial membership state for new members (default the audience's — usually subscribed/pending). This is the ONLY way to bulk-add people via the assistant; single contacts go through add_subscriber/upsert_contact.
create_segmentSave a multi-condition SEGMENT of an audience (a reusable rule-based slice, e.g. 'members tagged vip who opened the last campaign'). Requires a human approval step in chat — the approval card shows the segment name and how many members currently match (a live preview of the conditions). For a 'saved' segment, provide `conditions` (a match mode + rules); a 'static' segment has none (members are added manually later). To just PREVIEW reach without saving, use preview_segment instead. `newsletter:send` permission is required.
Activity
get_activityView recent email activity (sends, receives, bounces) across accessible inboxes. Use to check what happened recently, see delivery statuses, or find sends by a specific origin (API, agent, human).
outreach_campaign_statusGet a cold campaign's sent/replied/qualified rollup — the per-stage funnel (sourced → drafted → approved → sent) plus delivery (bounced/failed/suppressed) and replies. Use to answer 'how is my outreach doing?'.