Skip to main content
Glama
PhononX

Carbon Voice

by PhononX

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
LOG_DIRNoDirectory for log files. Default: /tmp/cv-mcp-server/logs/tmp/cv-mcp-server/logs
LOG_LEVELNoControls verbosity of logging. Options: info (default), debug, warn, error.info
CARBON_VOICE_API_KEYYesYour Carbon Voice API key. Required for stdio transport.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_messagesA

List messages with filtering by date, conversation, folder, workspace, creator or language. USE WHEN: The general-purpose message reader; full bodies incl. transcript and AI summary. Max date span 183 days. user_ids filters by SENDER — for messages exchanged WITH someone, pass conversation_id from list_conversations. Use presigned URLs as-is. USE INSTEAD: get_recent_messages for a quick look at the latest few (hard-capped at 10, no paging). search_message_ids for filters this cannot express — notified state, mentions or labels. FIRST: workspace_id comes from get_workspaces_basic_info (field id) — call it first if you don't have one. EXAMPLE: {"workspace_id":"ws-abc","start_date":"2026-09-01T00:00:00Z","size":25} RETURNS: {page, size, sort_direction, total, results_count, has_next_page, filters, results: [{id, transcript?, ai_summary?, audio_url?, creator_id, conversation_id?, duration_ms, reply_count, status, type, created_at, ...}]}. Page on has_next_page/total — do not guess. NARROW: pass response_fields ["total","has_next_page","results.id","results.transcript","results.created_at"] unless you need more — the full payload is much larger.

get_messageA

Get one message by ID, optionally expanded with related records. USE WHEN: You have a message ID. fields ADDS related data (conversation, creator, labels) — it does not narrow the response. Use response_fields to narrow. USE INSTEAD: list_messages when you do not have an ID, or need several messages — it already returns full bodies, so fetching each one again is wasted. FIRST: id comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"msg-abc","fields":"creator"} RETURNS: {message: {id, transcript?, ai_summary?, audio_url?, creator_id, duration_ms, status, type, attachments?, created_at, ...}}.

get_recent_messagesA

Get up to 10 of the most recent messages, each with its conversation, creator and labels. USE WHEN: A quick "what just happened" glance. Pre-joined, so no follow-up calls for creator or conversation names. USE INSTEAD: list_messages whenever you need more than 10, any date range, paging, or a filter other than conversation and language — this tool supports none of those. EXAMPLE: {"conversation_id":"conv-abc"} RETURNS: {results: [{message: {...}, conversation: {...}, creator: {...}, labels: [...]}]}. No total and no paging: the cap of 10 is the whole answer.

create_conversation_messageA

Post a message into an existing conversation, or reply in a thread. USE WHEN: You have a conversation_id. Pass parent_id (a message ID) to reply as a thread. Either transcript or links is required — the schema marks neither individually, so both param descriptions say so. USE INSTEAD: create_direct_message to reach people who are not already in a conversation. create_voicememo_message for a standalone memo. FIRST: id comes from list_conversations (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"conv-abc","transcript":"Agreed, shipping Friday."} RETURNS: {message: {id, link, transcript?, status, type, conversation_id, created_at, ...}}. ERROR BAD_REQUEST: Neither transcript nor links was provided. — Pass at least one of them.

create_direct_messageA

Send a direct message to one or more people, by user ID or email. USE WHEN: Reaching people outside an existing conversation. Address it with to.user_ids or to.emails. Requires transcript or links. USE INSTEAD: create_conversation_message when a conversation already exists — a DM starts a separate thread rather than joining it. FIRST: to.user_ids comes from search_users (field id) — call it first if you don't have one. EXAMPLE: {"to":{"user_ids":["user-abc"]},"transcript":"Quick question about the deck."} RETURNS: {message: {id, link, transcript?, status, conversation_id, created_at, ...}}. ERROR BAD_REQUEST: A user ID is invalid, or neither transcript nor links was provided. — Resolve people with search_users — never pass a display name as a user ID — and include a transcript or links.

create_voicememo_messageA

Create a voice memo, either from text (spoken via text-to-speech) or from an audio file at a URL. USE WHEN: Pass transcript (2-5000 chars) to have Carbon Voice speak the text, or an https audio_url to upload audio, which wins over transcript. File it with folder_id, whose type must match, or a workspace_id. USE INSTEAD: create_conversation_message to post into an existing conversation, or create_direct_message to send to specific people. A voice memo is standalone and lives in a folder or workspace. EXAMPLE: {"transcript":"Reminder to review the pricing deck before Friday."} RETURNS: {message: {id, link, transcript?, audio_url?, duration_ms, status, type, created_at, ...}}. status is often processing at first. ERROR INVALID_AUDIO_URL: audio_url is not https, unreachable, too large, timed out, embeds credentials, or resolves to a private address. — The message gives the reason. Use a public https URL, or pass transcript instead. ERROR BAD_REQUEST: None of transcript, audio_url or links was provided, or the transcript is outside 2-5000 characters. — Provide one of the three, and keep the transcript within the length limits.

add_attachments_to_messageA

Attach one or more link URLs to an existing message. USE WHEN: Adding external links to a message that already exists. USE INSTEAD: create_message_share_link to share a Carbon Voice message outward — that produces a link, this consumes them. FIRST: id comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"msg-abc","links":["https://example.com/spec"]} RETURNS: {...} confirmation with the resulting attachments.

get_userA

Get a user's full profile by ID — names, languages, voice settings, workspace roles. USE WHEN: You already have a user ID and need complete details. USE INSTEAD: search_user / search_users to FIND someone by email, phone or name. get_current_user for the caller — this tool needs an explicit ID and will not default to you. FIRST: id comes from search_users (field id) — call it first if you don't have one. EXAMPLE: {"id":"user-abc"} RETURNS: {id, first_name, last_name?, languages, voice_gender, workspace_ids, workspace_roles, user_type, created_at, ...}. NARROW: pass response_fields ["id","first_name","last_name","workspace_ids"] unless you need more — the full payload is much larger.

search_userA

Find a single user by email, phone or name. USE WHEN: Resolving ONE person. Supply exactly one of email, phone or name. Name search only matches your own contacts. USE INSTEAD: search_users for several people in one call — it takes arrays and saves a round trip per person. get_user when you already have the ID. EXAMPLE: {"email":"someone@example.com"} RETURNS: {id, full_name, first_name, last_name?, link, image_url?, languages?, ...}. Use id wherever another tool asks for a user ID. ERROR NOT_FOUND: Nobody matched, or a name search hit a non-contact. — Try an email or phone instead of a name; name search is limited to your contacts.

search_usersA

Resolve several users at once by emails, phones, IDs or names. USE WHEN: Turning a list of people into user IDs in one call — the right first step before any tool that takes user IDs. Name search only matches your contacts. USE INSTEAD: search_user for a single lookup. get_user for a full profile once you have the ID. EXAMPLE: {"names":["Brett"]} RETURNS: Array of {id, full_name, first_name, last_name?, link, languages?, ...}. If a name returns more than one candidate, ask which person was meant rather than guessing. NARROW: pass response_fields ["id","full_name"] unless you need more — the full payload is much larger.

get_current_userA

Get the calling user's own identity, workspaces and settings. USE WHEN: Establishing who you are acting as, or finding the caller’s workspace IDs before a workspace-scoped call. Takes no arguments. USE INSTEAD: get_user for somebody else (it requires an explicit ID). get_workspaces_basic_info if you only need workspace IDs and names — it is far smaller than this response. EXAMPLE: {} RETURNS: {success, user: {user_guid, first_name, last_name?, email_txt?, phone_txt?, workspace_guids, identities, entries, environments, lifecycle_events, notification_settings, settings, ...}, settings: {...}}. This payload is LARGE — several unbounded arrays and an open settings map. NARROW: pass response_fields ["user.user_guid","user.first_name","user.email_txt","user.workspace_guids"] unless you need more — the full payload is much larger.

list_conversationsA

List your conversations from the last 6 months, optionally filtered by participants, type and name. USE WHEN: Finding a conversation_id. Filter with user_ids plus match, types and name — YOUR DM with someone is user_ids: ["<their id>"], types: ["directMessage"]. You are always an implicit participant, so never pass your own ID. Filters AND together; if several match, ask which was meant. USE INSTEAD: get_conversation when you already have an ID and want full detail — this returns only id, name, workspace_id and type. EXAMPLE: {"user_ids":["user-abc"],"types":["directMessage"]} RETURNS: {results_count, results: [{id, name, workspace_id, type}]} where type is directMessage | customerConversation | namedConversation | asyncMeeting. No paging: results_count is what is returned, after filtering. name adds unfiltered_count: rows the name was matched against, AFTER user_ids/types. ALWAYS check it before saying no such conversation exists. 0 of 47 means none matched that string (misspelt, or >6 months old); 0 of 0 means your other filters left nothing — not that the caller has none. Widen the filters or ask; never report it does not exist.

get_conversationA

Get one conversation by ID, with full metadata. USE WHEN: You have a conversation_id and need its description, visibility, owner or workspace name. USE INSTEAD: get_conversation_users for the participant list. list_messages with conversation_id for its messages — this returns neither. FIRST: id comes from list_conversations (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"conv-abc"} RETURNS: {id, name, description?, link, workspace_id, workspace_name, owner_id, type, visibility, ...}.

get_conversation_usersA

List the people in a conversation. USE WHEN: Finding out who is in a conversation, or collecting participant user IDs. USE INSTEAD: search_users to resolve people by name or email generally — this is scoped to one conversation. FIRST: id comes from list_conversations (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"conv-abc"} RETURNS: Array of user objects with id and profile fields. NARROW: pass response_fields ["id","full_name"] unless you need more — the full payload is much larger.

summarize_conversationA

Summarize a conversation by running an AI Action over its recent messages. USE WHEN: You want a conversation summarized and have a conversation_id. Message selection is handled for you — omit message_ids and the most recent messages are used. USE INSTEAD: run_ai_action if you already know exactly which message_ids to process, or want a non-summary AI Action. FIRST: prompt_id comes from list_ai_actions (field id) — call it first if you don't have one. FIRST: conversation_id comes from list_conversations (field results[].id) — call it first if you don't have one. EXAMPLE: {"conversation_id":"conv-abc","prompt_id":"prompt-abc","limit":50} RETURNS: Same as run_ai_action: {id, prompt_id, message_ids, responses: [{language, text?, markdown?, ...}], ...}. ERROR BAD_REQUEST: prompt_id is not a valid AI Action ID. — Call list_ai_actions to get valid prompt_id values.

get_root_foldersA

List the root folders of a workspace for a given folder type. USE WHEN: Orienting in the folder tree, or finding a folder_id. type is required: voicememo or prerecorded. include_all_tree returns nested folders too. USE INSTEAD: get_folder to inspect one folder. get_folder_with_messages when you want a folder’s messages rather than its structure. EXAMPLE: {"type":"voicememo","workspace_id":"ws-abc"} RETURNS: {type, workspace_id?, include_all_tree?, sort_by, sort_direction, results: [{id, name, parent_folder_id?, subfolder_ids?, total_nested_folders_count, total_nested_messages_count, ...}]}. Not paginated — this is the complete set. NARROW: pass response_fields ["results.id","results.name","results.total_nested_messages_count"] unless you need more — the full payload is much larger.

create_folderA

Create a folder in a workspace, optionally nested under another. USE WHEN: Organising memos. name, type and workspace_id are all required; add parent_folder_id to nest. USE INSTEAD: move_folder to relocate a folder that already exists. FIRST: workspace_id comes from get_workspaces_basic_info (field id) — call it first if you don't have one. EXAMPLE: {"name":"Q4 planning","type":"voicememo","workspace_id":"ws-abc"} RETURNS: The created folder, same shape as get_folder.

get_folderA

Get one folder's metadata and, optionally, its immediate subfolders. USE WHEN: Inspecting a folder. Set include_first_level_tree: true to get subfolders. Both date AND direction are silently ignored unless you do — upstream only documented that caveat on date. USE INSTEAD: get_folder_with_messages when you want the messages inside the folder — this returns structure and counts only. FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"folder-abc","include_first_level_tree":true} RETURNS: {id, name, type, workspace_id, parent_folder_id?, path?, subfolder_ids?, message_ids?, total_nested_folders_count, total_nested_messages_count, subfolders?, ...}.

get_folder_with_messagesA

Get a folder together with the messages stored directly in it. USE WHEN: Reading a folder’s contents. Only messages at that folder’s own level are returned — nested folders are not walked. USE INSTEAD: get_folder for structure and counts without message bodies. list_messages with folder_id when you need date filtering or paging, which this tool does not support. FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"folder-abc"} RETURNS: {folder: {...}, messages: [{...}]}. NARROW: pass response_fields ["folder.id","folder.name","messages"] unless you need more — the full payload is much larger.

update_folder_nameA

Rename a folder. USE WHEN: Changing only the name. name is the sole editable field here. USE INSTEAD: move_folder to change where a folder sits in the tree. FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"folder-abc","name":"Q4 planning (final)"} RETURNS: The updated folder, same shape as get_folder.

delete_folderA

Permanently delete a folder, including every nested folder and all their messages. USE WHEN: Only when the whole subtree should be destroyed. This cascades and cannot be undone. USE INSTEAD: move_folder to get a folder out of the way, or move_message_to_folder to relocate its messages first. Check total_nested_messages_count via get_folder before calling — the cascade is easy to underestimate. FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"folder-abc"} RETURNS: Deletion confirmation.

move_folderA

Move a folder into another folder, or up to a workspace root. USE WHEN: Relocating a folder. Pass folder_id for a new parent folder, or workspace_id to move it to the workspace root — one or the other, not both. USE INSTEAD: update_folder_name to rename in place. move_message_to_folder for a single message rather than a folder. FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"folder-abc","folder_id":"folder-parent"} RETURNS: The moved folder, same shape as get_folder. ERROR BAD_REQUEST: Both folder_id and workspace_id were given, or neither, or the move would nest a folder inside itself. — Pass exactly one destination.

move_message_to_folderA

Move a message into a folder, or out to a workspace. USE WHEN: Filing a memo. Only voicememo/prerecorded messages you created can be moved, and the message type must match the folder's type. Pass exactly one of folder_id or workspace_id. USE INSTEAD: move_folder to relocate a whole folder. create_voicememo_message with folder_id to file a memo at creation time instead of moving it after. FIRST: message_id comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"message_id":"msg-abc","folder_id":"folder-abc"} RETURNS: The updated message with its new placement. ERROR BAD_REQUEST: The message type is not voicememo/prerecorded, it does not match the destination folder's type, or both/neither destination was given. — Check type via get_message and the folder type via get_folder; they must match. Pass exactly one destination.

get_workspaces_basic_infoA

List every workspace you belong to, as id and name only. USE WHEN: The cheapest way to resolve a workspace name to an ID before a workspace-scoped call. Takes no arguments. USE INSTEAD: get_current_user if you need more than ids and names — but note that response is much larger, so prefer this one when ids suffice. EXAMPLE: {} RETURNS: Array of {id, name}. Nothing else, and no paging.

list_ai_actionsA

List the AI Actions (Prompts) available to you — each has an id usable as prompt_id. USE WHEN: Before calling run_ai_action or summarize_conversation, to find a prompt_id. Also to show the user which AI Actions exist. Filter by owner_type (user = your own, workspace = shared, system = Carbon Voice built-ins). USE INSTEAD: get_ai_action_responses if you want results that were already generated rather than the list of available actions. EXAMPLE: {"owner_type":"system"} RETURNS: Array of {id, name, description?, prompt, owner_type, workspace_id?, response_format?, created_at, last_updated_at}. Use id as prompt_id elsewhere. NARROW: pass response_fields ["id","name","description","owner_type"] unless you need more — the full payload is much larger.

run_ai_actionA

Run an AI Action (Prompt) against one or more specific messages. USE WHEN: You have concrete message_ids and a prompt_id, and want the AI Action applied to exactly those messages. USE INSTEAD: summarize_conversation if you want a whole conversation summarized and would otherwise have to list its messages yourself — it does that selection for you. FIRST: prompt_id comes from list_ai_actions (field id) — call it first if you don't have one. FIRST: message_ids comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"prompt_id":"prompt-abc","message_ids":["msg-1","msg-2"],"language":"english"} RETURNS: {id, prompt_id, message_ids, creator_id, channel_id?, workspace_id?, responses: [{language, text?, markdown?, html?, json?}], created_at}. The generated output is in responses[], one entry per language. ERROR BAD_REQUEST: prompt_id or one of message_ids is not a valid ID. — Call list_ai_actions for valid prompt_id values and list_messages for valid message IDs; do not retry with the same IDs.

run_ai_action_for_shared_linkA

Run an AI Action (Prompt) against one or more shared messages, addressed by share link ID. USE WHEN: You have share link IDs — from create_message_share_link, or a link someone gave you — and want an AI Action applied to the messages behind them. USE INSTEAD: run_ai_action if you have the message IDs directly; going through a share link adds nothing when you already have access. FIRST: share_link_ids comes from create_message_share_link (field id) — call it first if you don't have one. FIRST: prompt_id comes from list_ai_actions (field id) — call it first if you don't have one. EXAMPLE: {"prompt_id":"prompt-abc","share_link_ids":["share-abc"]} RETURNS: {share_link_ids, responses: [{language, text?, markdown?, html?, json?}], ...}. ERROR NOT_FOUND: A share link ID does not exist, or its access has been revoked or expired. — Create a fresh link with create_message_share_link, or verify the ID with get_message_share_link.

get_ai_action_responsesA

Retrieve AI Action results that were generated previously. USE WHEN: You want existing output rather than a fresh run — e.g. showing what an AI Action already produced for a message or conversation. Combine prompt_id, message_id and channel_id to narrow. USE INSTEAD: run_ai_action (or summarize_conversation) to generate new output; this tool only reads what already exists and returns an empty array if nothing has been generated. EXAMPLE: {"channel_id":"conv-abc","limit":10} RETURNS: Array of {id, prompt_id, creator_id, message_ids, channel_id?, workspace_id?, responses: [{language, text?, markdown?, html?, json?}], created_at}. NARROW: pass response_fields ["id","prompt_id","responses"] unless you need more — the full payload is much larger.

create_message_share_linkA

Create a shareable link to an existing message (e.g. a voice memo), and get the URL back. USE WHEN: share_type: "link" for a shareable URL; "forward" to attach the share onto another message (also needs message_id). Also how you get a share_link_ids value. USE INSTEAD: add_attachments_to_message to attach an external URL to a message, rather than share a Carbon Voice message outward. FIRST: shared_message_id comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"shared_message_id":"msg-abc","share_type":"link","access_type":"public"} RETURNS: {id, link, share_type, access_type, created_by, specified_access?, end_access_at?, revoked_at?, shared_message: {...}}. link is the URL to hand out; id is the share_link_ids value other tools take. NARROW: pass response_fields ["id","link","share_type","access_type"] unless you need more — the full payload is much larger. ERROR BAD_REQUEST: shared_message_id is invalid, or share_type is "forward" without message_id. — Confirm the ID with get_message; when forwarding, also pass message_id.

get_message_share_linkA

Look up an existing message share link by its ID, including the message behind it. USE WHEN: You have a share link ID and want its URL, access settings, or whether it is still valid — check revoked_at and end_access_at before relying on it. USE INSTEAD: create_message_share_link to make a new link; this only reads existing ones. get_message if you have the message ID and do not care about the share. FIRST: share_link_id comes from create_message_share_link (field id) — call it first if you don't have one. EXAMPLE: {"share_link_id":"share-abc"} RETURNS: Same shape as create_message_share_link: {id, link, share_type, access_type, revoked_at?, end_access_at?, shared_message: {...}, ...}. NARROW: pass response_fields ["id","link","revoked_at","end_access_at"] unless you need more — the full payload is much larger. ERROR NOT_FOUND: No share link with that ID, or it is no longer accessible. — Create a new one with create_message_share_link; do not retry the same ID.

list_my_action_itemsA

List your action items across every conversation and folder: those assigned to you, PLUS unassigned ones you created. USE WHEN: Answering "what do I owe / what is on my plate" — but check assigned_to before calling something the user's own commitment: a null one is an item they raised that nobody has picked up. Filter by status (todo open, suggested AI-proposed, done complete). Page with starting_after. USE INSTEAD: list_action_items when you want one specific conversation or folder rather than everything of yours. EXAMPLE: {"status":"todo","limit":25} RETURNS: {results: [{id, title, status, notes_text?, assigned_to?, due_date?, container_id?, container_type?, source_message_id?, creator_id, ...}], total?, results_count?, has_more?, next_cursor?, filters?}. Keep paging while has_more is true, passing next_cursor as starting_after. NARROW: pass response_fields ["results.id","results.title","results.status","results.assigned_to","results.due_date"] unless you need more — the full payload is much larger.

list_action_itemsA

List action items belonging to one container — a conversation, a folder, or home. USE WHEN: You have a container_id and want its action items. container_type is channel for a conversation, folder for a folder, or home. A conversation id is NOT a folder id — resolve container_id with the tool matching your container_type. Filter by status or assigned_to (pass the string null for unassigned). USE INSTEAD: list_my_action_items for everything assigned to you regardless of where it lives. FIRST: container_id comes from list_conversations (field results[].id) when container_type is channel — call it first if you don't have one. FIRST: container_id comes from get_root_folders (field results[].id) when container_type is folder — call it first if you don't have one. EXAMPLE: {"container_type":"channel","container_id":"conv-abc","status":"todo"} RETURNS: Same as list_my_action_items: {results: [...], total?, results_count?, has_more?, next_cursor?, filters?}. NARROW: pass response_fields ["results.id","results.title","results.status","results.assigned_to"] unless you need more — the full payload is much larger.

get_action_itemA

Get one action item by its ID, with full detail. USE WHEN: You have an action item ID and need its notes, assignee, due date, or source message. USE INSTEAD: list_my_action_items or list_action_items if you do not have an ID yet — they already return the same fields per item, so a follow-up call is usually wasted. FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"ai-abc"} RETURNS: {id, title, status, notes_text?, creator_id, assigned_to?, due_date?, container_id?, container_type?, source_message_id?, last_updated_by, ...}.

create_action_itemA

Create an action item, optionally attached to a conversation or folder. USE WHEN: Recording a task. Only title is required. Attach it by passing both container_type and container_id, and link it to what prompted it with source_message_id. USE INSTEAD: suggest_action_items_from_messages to have tasks extracted from message content automatically instead of writing each one yourself. EXAMPLE: {"title":"Send the pricing deck","assigned_to":"user-abc"} RETURNS: {id, title, status, notes_text?, assigned_to?, due_date?, container_id?, container_type?, creator_id, ...}. New items start at status todo. ERROR BAD_REQUEST: assigned_to is not a valid user ID, or container_id does not match container_type. — Resolve people with search_users (never pass a name) and containers with list_conversations or get_root_folders.

update_action_itemA

Change an action item's title, notes, assignee, or due date. USE WHEN: Editing item content. Send only the fields you want changed — omitted fields are left as they are. USE INSTEAD: set_action_item_status to move an item between todo / done / suggested; status is not editable here. FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"ai-abc","due_date":"2026-10-01"} RETURNS: The updated action item, same shape as get_action_item.

set_action_item_statusA

Move an action item between suggested, todo and done. USE WHEN: Completing an item (done), reopening it (todo), or accepting an AI-suggested item by promoting it from suggested to todo. USE INSTEAD: update_action_item for title, notes, assignee or due date; this tool only sets status. FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"ai-abc","status":"done"} RETURNS: The updated action item, same shape as get_action_item.

delete_action_itemA

Permanently delete an action item. USE WHEN: The item was created in error and should not exist at all. USE INSTEAD: set_action_item_status with done to complete an item — that keeps the record. Deleting cannot be undone, so prefer it only when the item is genuinely spurious. FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one. EXAMPLE: {"id":"ai-abc"} RETURNS: Deletion confirmation for the removed item.

suggest_action_items_from_messageA

Extract action items from ONE message and return them immediately. USE WHEN: Turning a single message into tasks — "what did she ask me to do?". The items come back in this call, already saved with status: "suggested"; promote the ones you want with set_action_item_status. Prefer this over suggest_action_items_from_messages whenever there is exactly one message, since it needs no polling. USE INSTEAD: suggest_action_items_from_messages for two or more messages — it reasons over the whole set at once and can catch commitments that span messages, which calling this tool repeatedly cannot. create_action_item when you already know the task. FIRST: message_id comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"message_id":"msg-1"} RETURNS: Array of the created action items, each with id, title, assigned_to, due_date, notes_text and status: "suggested". An empty array means the model found nothing actionable. Runs the extraction inline, so expect this call to take a few seconds.

suggest_action_items_from_messagesA

Queue AI extraction of candidate action items from specific messages. Runs in the background. USE WHEN: Turning a conversation into tasks — "what did we agree to?". Pass the message_ids to analyse, then POLL list_my_action_items or list_action_items with status: "suggested" for the results, and promote the ones you want with set_action_item_status. USE INSTEAD: suggest_action_items_from_message (singular) for a SINGLE message — it returns the items directly, with no polling. create_action_item when you already know the task and do not need it inferred — that returns the item synchronously, with an id. FIRST: message_ids comes from list_messages (field results[].id) — call it first if you don't have one. EXAMPLE: {"message_ids":["msg-1","msg-2"]} RETURNS: ACKNOWLEDGEMENT ONLY — no items are returned. Extraction is queued and runs in the background, so poll a listing tool with status: "suggested" to see the results.

search_message_idsA

Find message IDs by notified state, mentions, labels, creator, conversation or workspace — returning IDs plus cursor metadata. USE WHEN: Any filter list_messages cannot express: whether you were notified (notified_status), whether you were tagged (tagged_user_ids), or by label_ids. Cheap in tokens because it returns IDs only — hydrate the ones you need with get_message. USE INSTEAD: list_messages when a date range, conversation or workspace filter is all you need and you want full message bodies in one call. search_messages_by_heard_status for unread/listened state, which this tool cannot filter on. EXAMPLE: {"notified_status":"notified","limit":50} RETURNS: {ids: [{...}], has_more, next_cursor?}. Keep paging while has_more is true, passing next_cursor back as next_cursor. ERROR BAD_REQUEST: An ID list contains names rather than IDs, or exceeds 50 entries. — Resolve people to IDs with search_users and conversations with list_conversations; split lists longer than 50.

search_messages_by_heard_statusA

Find messages by whether you have listened to them, and get per-conversation unheard counts. USE WHEN: "What have I not listened to yet" / "catch me up". heardStatus: "unheard" is the unread filter. The response also carries unheard_counts_by_channel, so you can prioritise conversations without fetching their messages. USE INSTEAD: search_message_ids for notified state, mentions or date anchors — this tool accepts no date filter (see note below). list_messages for plain recent history. EXAMPLE: {"heardStatus":"unheard","limit":25} RETURNS: {messages: [{message_guid, creator_guid, creator_first_name, channel_guids, transcript_txt, message_ts, heard_status, ...}], unheard_counts_by_channel: {conversation_id: count}, success}. Use unheard_counts_by_channel to decide where to look first. NARROW: pass response_fields ["unheard_counts_by_channel","messages.message_guid","messages.channel_guids","messages.creator_first_name","messages.transcript_txt","messages.message_ts"] unless you need more — the full payload is much larger.

list_inbox_notificationsA

List your inbox notifications, with a total unread count. USE WHEN: Answering "what did I miss" or "where was I mentioned" — pass category: "mentions" for mentions. The response includes total_unread, so you can report a count without paging. USE INSTEAD: search_message_ids with notified_status if you want the messages themselves rather than notification records. search_messages_by_heard_status for unlistened messages. EXAMPLE: {"category":"mentions","limit":25} RETURNS: {results: [...], total_results, total_unread, filters}. Pages with skip/limit, not cursors. NARROW: pass response_fields ["results","total_unread","total_results"] unless you need more — the full payload is much larger.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.3/5.0

Scored across 42 tools

Disambiguation4/5

Most tools have distinct purposes, and the detailed USE INSTEAD notes clarify boundaries. However, a few pairs are easy to confuse: search_user vs search_users (singular/plural), suggest_action_items_from_message vs suggest_action_items_from_messages (singular/plural, sync/async), and get_folder vs get_folder_with_messages. These are distinguishable but require careful reading.

Naming Consistency3/5

Names are all snake_case and mostly verb_noun, but the verbs vary widely: list, get, create, update, delete, set, move, search, run, summarize, add, suggest. Some names are quite long (run_ai_action_for_shared_link, search_messages_by_heard_status) and the verb_prefix is not uniform (search_user vs list_messages vs get_conversation). Overall readable but not a tight pattern.

Tool Count3/5

42 tools is high for a single server, but the domain spans messages, conversations, folders, action items, AI actions, share links, users, and workspaces, so the scope is broad. Still, several tools are near-duplicates that could be merged (search_user/search_users, get_folder/get_folder_with_messages, the two suggest_action_items variants), which suggests the surface could be tightened to ~30 tools.

Completeness4/5

The tool set covers most lifecycle operations for the core entities: messages (create, list, get, move, attach, share), folders (create, get, update, delete, move), action items (create, list, get, update, delete, set status, suggest), and AI actions (list, run, get responses). Minor gaps: no tool to delete a conversation, no way to update a message's transcript, and no explicit tool to revoke a share link (only via error handling). These are workaroundable.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive