MCP tool catalog

Everything a connected assistant can do, and the scope that gates each capability. Setup lives in Connect your AI.

How to read this

  • Scope(s) — the assistant's key must hold every listed scope or the tool is not even shown to it (tools/list filters by scope; tools/call enforces it again).
  • read / write / destructive — mirrors the MCP annotations clients use for their permission UI: read = readOnlyHint; destructive = destructiveHint (irreversible: sends, deletes, secret rotation) — a good client confirms these with the user.
  • Every tool is a thin proxy over the matching REST v2 route — same validation, scopes, audit and webhooks. Deletes are soft (recoverable) but still flagged destructive, because that is how they read to the user.
  • Mutating tools that support it accept an idempotency_key argument so a retried call cannot double-apply — always pass one when sending email.

Identity & teams

ToolWhat it doesScope(s)
whoamiReturn the authenticated user and the key/scopes this connection has. The quickest way to confirm the connection works and see what it can do.noneread
list_teamsList the teams (organisations) this connection can act within. A team id is needed to list boards and search CRM contacts.boards.readread
get_teamGet a single team by id.boards.readread

Boards, lists & custom fields

ToolWhat it doesScope(s)
list_boardsList the boards a team owns. Pass team_id from whoami/list_teams.boards.readread
get_boardGet a single board by its opaque id (brd_…).boards.readread
list_board_listsList a board's task lists (columns). A list id (lst_…) is where you create or move tasks.lists.readread
list_board_membersList a board's active members. Use a member's email wherever a person is needed: the task assignee, person custom fields, sub-task assignees and @email mentions in comments.boards.readread
list_board_custom_fieldsList a board's custom fields with their types and (for tag/status/select/multiselect) options {id,label} — use a field id when setting values with update_task (options by id or label). Type tasks is a sub-task list (change it with add_subtask/update_subtask/delete_subtask). Fields flagged ai: true (managed by Sortd AI) take values like any other; setting Response Status to Actioned clears the AI fields.customfields.readread
list_board_templatesThe available board templates — each shows the lists (columns) and custom fields it creates. Use a template's key with create_board; the 'sales' template creates a sales board (deal cards).boards.readread
create_boardCreate a team board — plain, or from a template (see list_board_templates): the template provisions lists, custom fields and sample tasks, and 'sales' makes it a sales board.boards.writewrite
update_boardRename a board.boards.writewrite
delete_boardSoft-delete a board (recoverable).boards.writedestructive
create_listAdd a task list (column) to a board.lists.writewrite
update_listRename a list.lists.writewrite
reorder_listReposition a list (column) on its board. Pass after_list_id to place it directly after a specific list, or position "start"/"end". The response reports the position the server actually recorded.lists.writewrite
delete_listSoft-delete a list (recoverable).lists.writedestructive
create_custom_fieldCreate a custom field on a board — any type the app offers. Option types (select/status/tag/multiselect) take an options list. person = a board member, contact/company = a CRM record, tasks = a sub-task list, attachment = links.customfields.writewrite
update_custom_fieldUpdate a custom field (name, options, display_on_card). Fields flagged ai: true are managed by Sortd AI and their settings cannot be changed.customfields.writewrite
delete_custom_fieldSoft-delete a custom field on a board. Fields flagged ai: true are managed by Sortd AI and cannot be deleted.customfields.writedestructive

Tasks

ToolWhat it doesScope(s)
list_tasksList/search tasks. Provide ONE scope: list_id, board_id, thread_id (raw Gmail hex), contact_id (con_…) or team_id (searches EVERY board you can access in the team — requires at least one filter). Optional filters (board/list/team scope): q, completed, shade, due_before, due_after, assigned_to (email/name), custom_field_id (+ custom_field_value — matched on the typed value: an option label or id, a member email, true/false, a number). Cursor-paginated.tasks.readread
get_taskGet a single task by its opaque id (tsk_…): title, list, assignee, colour, status (open/completed; won/lost/abandoned on sales cards), next_step, read state, link attachments, deal/contact on sales cards, linked thread_ids, and typed custom_fields (options as {id,label}, people as {email,name}, contacts as {id,name}, numbers, true/false checkboxes, sub-task lists).tasks.readread
create_taskCreate a task on a list. New tasks go to the TOP by default — when adding several in sequence, pass position "bottom" (or anchor each with after_task_id) or the batch ends up in reverse order. On a Sales board the new card is a sales card (status open; set deal/contact_id with update_task).tasks.writewrite
create_task_from_emailTurn an email thread into a task on a list — the API equivalent of dragging the email onto a board. The task title defaults to the email subject; pass title only to override it. notes and due_at work here just as they do on create_task. The thread stays linked to the task, so replies keep landing on it. Use add_thread_to_task to link further emails. Call suggest_tasks_for_email first: if the email belongs on an existing card, link it there instead of creating a duplicate. On a Sales board this creates a sales card.tasks.write + email.metadata.readwrite
add_thread_to_taskLink another email thread to an existing task — a task can carry several. Linking a thread that is already on the task does nothing, so this is safe to repeat.tasks.write + email.metadata.readwrite
remove_thread_from_taskUnlink an email thread from a task (undo add_thread_to_task, or fix a mis-filed email). The thread stays in the mailbox and the task stays; only the link goes. unarchive=true also moves the mail back to the inbox (needs email.metadata.write). Not-found if the thread is not on the task.tasks.write + email.metadata.readwrite
update_taskUpdate a task. Set title (rename it; 1–1000 characters, cannot be cleared), next_step (the card's one-line next step; "" clears), read (mark the task read/unread), status (tasks: open|completed; sales cards: open|won|lost|abandoned), deal (sales cards: {value, source, close_date, loss_reason} — send only what changes) and contact_id (sales cards: con_… or null), notes (replaces the task note; "" clears), due_at (shared due date, null clears), planned_at (YOUR personal planned day, null clears), shade (colour name, "none" clears) and/or custom_fields (array of {field_id, value}; values are typed per property: option id or label for select/status (one) and tag/multiselect (list), board member email for person, con_/cmp_ id for contact/company, true/false for checkbox, number, YYYY-MM-DD for date, null clears; sub-tasks via add_subtask/update_subtask).tasks.writewrite
list_task_commentsA task's comment thread, newest first — the team conversation on the task. Authors are member emails/display names.tasks.readread
add_task_commentComment on a task — leave your reasoning where the team reads it (e.g. why you set a status or filed the email). Plain text. To @-mention a board member write @ then their email, e.g. "@sam@acme.com can you check this?" — they are notified and follow the task; a non-member address is rejected (list_board_members). Live board updates behave exactly as a UI comment.comments.writewrite
delete_task_commentSoft-delete a comment YOU wrote (other members’ comments cannot be deleted through the API).comments.writedestructive
get_task_historyA task's activity log, newest first — created, moves, status/assignee/due-date/custom-field changes. Everything you do through these tools lands here exactly as a manual change would, so the team can always see what the assistant did.tasks.readread
get_task_reminderYOUR reminder on a task (reminders are per-user — this never shows other members'). null when none is set.tasks.readread
set_task_reminderSet (or replace) YOUR personal reminder on a task — one per user per task. Delivery follows the product scheduler: notify "email" sends a reminder mail, "popup" notifies in-app (default ["email"]).tasks.writewrite
clear_task_reminderRemove YOUR reminder from a task. Idempotent — clearing an unset reminder is a no-op.tasks.writewrite
assign_taskAssign a task to a board member by email, or pass an empty/omitted assignee to clear it. The email must belong to an active member of the task's board (see list_board_members). Only one assignee is supported — assigning REPLACES the current assignee, as in the app.tasks.writewrite
complete_taskMark a task complete (status completed; the card stays on the board — use archive_task to hide it). For sales cards use update_task status won/lost/abandoned instead.tasks.writewrite
reopen_taskReopen a completed task (status open). For sales cards use update_task status open.tasks.writewrite
move_taskMove a task to a DIFFERENT list — on the same board, another board, or the user's private board (moves between teams follow the team's privacy setting, as in the app). To change a task's position within the list it is already on, use reorder_task instead.tasks.writewrite
reorder_taskChange where a task sits WITHIN its current list — this is how you act on a prioritisation. Pass after_task_id to place it directly below a specific task, or position "top"/"bottom". To impose a whole new order, walk the list front to back and anchor each task to the one that should precede it. The response reports the position the server actually recorded.tasks.writewrite
delete_taskSoft-delete a task (recoverable; hidden from reads).tasks.deletedestructive
archive_taskArchive a task — move it off the board into the board archive (the app's "Archive"). Not the same as complete_task: completing changes status, archiving hides the card. Its email threads are left in the mailbox. Restore with unarchive_task; find archived tasks with list_archived_tasks.tasks.writewrite
unarchive_taskRestore an archived task to its board — to the list it was archived from, or to list_id (a list on the same board). No-op if the task is not archived.tasks.writewrite
list_archived_tasksA board's archived tasks, most recently archived first (Task objects plus archived_at). Optional q filters on the title. Cursor-paginated.tasks.readread
suggest_tasks_for_emailExisting tasks an email probably belongs on (the app's "add to existing card" suggestions): matches the subject against cards, and the sender when they are outside your team. Call it BEFORE create_task_from_email so a follow-up email lands on the existing card (add_thread_to_task) instead of a duplicate. Pass thread_id, or sender and/or subject.tasks.readread
merge_tasksMerge one task into another (deduplicate): the task_id task's notes, comments and email threads move to into_task_id, then task_id is DELETED. IRREVERSIBLE for task_id — confirm with the user first. Needs tasks.delete too.tasks.write + tasks.deletedestructive
add_task_attachmentAttach an http(s) link to a task (shows with the card's attachments). Returns the attachment id.tasks.writewrite
remove_task_attachmentRemove an attachment from a task (attachment id from the task's attachments).tasks.writewrite
add_subtaskAdd a sub-task to a task's "Task list" custom property (field_id from list_board_custom_fields, type tasks). Optional assignee (board member email) and position (0 = first; default last).tasks.write + customfields.writewrite
update_subtaskChange one sub-task: rename (title), tick/untick (completed), assign/unassign (assignee email or null), or move (position).tasks.write + customfields.writewrite
delete_subtaskDelete one sub-task from a task's Task list property.tasks.write + customfields.writewrite
remove_task_from_listTake a task off its board without deleting it (the app's "Remove from list"): it moves into your own private space and leaves the team's boards; its emails stay linked. Use move_task to re-file it. Prefer archive_task to tidy a board.tasks.writewrite

CRM — contacts & companies

ToolWhat it doesScope(s)
search_contactsSearch a team's CRM contacts (company-grouped). Pass team_id; optional q, type, stage. Requires the team's Contacts feature.contacts.readread
get_contactGet a CRM contact by opaque id (con_…).contacts.readread
create_contactCreate a CRM contact. team_id + name required; link a company via company_id or company_name.contacts.writewrite
update_contactUpdate a CRM contact (partial).contacts.writewrite
delete_contactSoft-delete a CRM contact.contacts.writedestructive
list_companiesList/search a team's CRM companies. Pass team_id; optional q.contacts.readread
get_companyGet a CRM company by opaque id (cmp_…).contacts.readread
create_companyCreate a CRM company. team_id required.contacts.writewrite
update_companyUpdate a CRM company (partial).contacts.writewrite
delete_companySoft-delete a CRM company.contacts.writedestructive

Email — read & thread state

ToolWhat it doesScope(s)
get_mailboxReport the owner's mailbox connection state (connected / not_connected / reauth_required). Reads no mail.email.metadata.readread
list_email_labelsList the mailbox's Gmail labels (system + user) for building search queries.email.metadata.readread
search_email_threadsSearch the mailbox with a Gmail query. Provide at least one of q / label / category. Returns thread metadata (no bodies). Cursor-paginated. Gmail only.email.metadata.readread
get_email_threadGet an email thread by raw Gmail thread id (hex). Set include_messages=true to include message bodies (needs the email.body.read scope).email.metadata.readread
list_email_draftsList the Gmail drafts on a thread.email.metadata.readread
get_new_emailNew mail since YOUR last call — the server keeps the cursor per connection key, so just call it again to get what arrived in between; each call advances the cursor. Returns HEADER ENVELOPES ONLY (subject, snippet, addresses, dates, thread_id — never bodies; use get_email_thread for content), covering the mail Sortd’s pipeline processes: inbox + sent, with spam/trash, filtered categories, auto-replies and Sortd sync copies excluded. Delivery is at-least-once — dedupe on message_id. The very first call initialises the cursor and returns an empty batch. CHECK AT LEAST DAILY. A stale-but-covered cursor is served normally; only once messages may genuinely have expired does the call fail with new_mail_expired — its details include the old cursor_position and a ready-made backfill_query. RECOVER IN THIS ORDER: (1) call again with reset=true — re-baselines to now and echoes previous_cursor_position; (2) if the gap matters, backfill it with search_email_threads using that backfill_query, deduping on message_id. Reset-first turns timing seams into duplicates, never losses. Typical loop: get_new_email → classify_email → create_task_from_email / apply_email_thread_labels.email.metadata.readread
set_email_thread_read_stateMark a thread read or unread.email.metadata.writewrite
archive_email_threadArchive a thread (remove from Inbox).email.metadata.writewrite
unarchive_email_threadUnarchive a thread (return to Inbox).email.metadata.writewrite
apply_email_thread_labelsAdd and/or remove Gmail labels on a thread (raw label ids). At least one of add/remove.email.metadata.writewrite
snooze_email_threadSnooze a thread until a future time (ISO-8601).email.metadata.writewrite

Email — drafts & sending

ToolWhat it doesScope(s)
list_email_templatesThe team's email templates (name, subject, body) — use one as the starting point when drafting if the team wants consistent wording; adapt freely. Read-only (templates are managed in the Sortd app).drafts.writeread
create_email_draftCreate a Gmail draft reply on a thread for a human to review and send (this server never sends mail). Body required; recipients/subject optional (default Re: thread).drafts.writewrite
create_draftCreate a brand-new Gmail draft (no thread) for a human to review and send. to + subject + body required.drafts.writewrite
delete_email_draftPermanently delete a Gmail draft on a thread — the same as discarding it in Gmail (no Trash, no undo). Never sends. Get the draft_id from create_email_draft / create_draft / list_email_drafts; a draft not on the thread returns not-found and nothing is deleted. On a board that shares drafts it is discarded for every member. Drafts may be ones the user wrote themselves — confirm with the user before deleting anything you did not create.drafts.writedestructive
send_email_draftSend a Gmail draft that already exists (from create_email_draft / create_draft / list_email_drafts). The "approve by sending" pattern: one key prepares the draft, a human or a key holding drafts.send releases it. IRREVERSIBLE — confirm with the user first.drafts.senddestructive
reply_to_email_threadReply on an existing thread. You control ONLY the body — recipients are derived server-side from the conversation and cannot be supplied, so a reply can never reach anyone not already on the thread. This is the safest send for an agent. mode "reply" = sender only (honouring Reply-To), "reply_all" = keep the To/Cc audience. IRREVERSIBLE — confirm with the user first.email.replydestructive
send_emailCompose and send a NEW email to recipients you specify, from the connected mailbox. Optionally onto an existing thread via thread_id. This is the widest email capability — it can reach anyone — so prefer reply_to_email_thread when replying, or create_draft when a human should review first. IRREVERSIBLE — always confirm the recipients and body with the user before calling.email.senddestructive

AI

ToolWhat it doesScope(s)
classify_emailGet Sortd's AI read on an email thread (status / urgency / sentiment / risk). Returns a cached analysis instantly or a job to poll with get_ai_job. Untrusted email content is returned only as structured labels.ai.classifyread
get_thread_analysesRead cached AI analyses for an email thread.ai.classifyread
get_ai_jobPoll an async AI classification job by id (job_…) for its status/result.ai.classifyread

Automations

ToolWhat it doesScope(s)
list_automationsA team's automations — the rules that act on incoming mail and tasks (triggers, conditions, actions, enabled state, board). Read these FIRST to learn the product's automation vocabulary before creating or editing one.automations.readread
create_automationCreate an automation on a board. The definition (actOn, trigger, conditions, actions, settings) is the product's automation JSON — copy the shape from list_automations examples. Validated by the same rules as the app; AI-gated actions require the team's AI tier.automations.writewrite
update_automationReplace an automation's definition (same payload as create_automation). It stays on its board.automations.writewrite
enable_automationRe-enable a disabled automation.automations.writewrite
disable_automationPause an automation without deleting it — the definition is kept and can be re-enabled.automations.writewrite
delete_automationDelete an automation from its board. Prefer disable_automation when the rule may come back.automations.writedestructive

Webhooks

ToolWhat it doesScope(s)
create_webhookSubscribe an HTTPS target_url to one or more event types. The response includes the signing secret once.webhooks.managewrite
list_webhooksList webhook subscriptions (never the signing secret).webhooks.manageread
update_webhookUpdate a webhook subscription (events, target_url, status active/disabled, filters).webhooks.managewrite
delete_webhookDelete a webhook subscription.webhooks.managedestructive
rotate_webhook_secretRotate a webhook signing secret (returns the new secret once). Invalidates the old secret immediately — deliveries will fail signature checks until the new one is deployed.webhooks.managedestructive
test_webhookSend a test ping to a webhook subscription.webhooks.managewrite
list_webhook_deliveriesList a webhook subscription's recent delivery log.webhooks.manageread
replay_webhook_deliveryReplay a previous webhook delivery by id.webhooks.managewrite

Not exposed, on purpose

  • Zapier helper routes — platform plumbing, not agent tools.
  • Anything beyond the key's scopes — there is no override; widen the key if the assistant needs more, or mint a second, wider key for a separate connection.

Next: connect a client, or read the send-scope ladder before granting send capability.