The Plain MCP connector routes your AI agent's tool calls to Plain's own MCP server through Scalekit. Each user signs in to Plain once, and Scalekit stores and refreshes their tokens, so your agent never handles credentials. It comes with 86 tools.
- Tools
- 86
- What they doRead · write · destructive
- 27 · 21 · 3827 read21 write38 destructive
- Users sign in with
- OAuth
- OAuth app
- Scalekit's or your own
Setup
Install the SDK
Terminal window npm install @scalekit-sdk/node dotenvTerminal window pip install scalekit-sdk-python python-dotenvSet your credentials
Add your Scalekit credentials to your
.envfile. Find values in app.scalekit.com > Developers > API Credentials..env SCALEKIT_ENVIRONMENT_URL=<your-environment-url>SCALEKIT_CLIENT_ID=<your-client-id>SCALEKIT_CLIENT_SECRET=<your-client-secret>Create the Plain MCP connection
In AgentKit > Connections, create a Plain MCP connection. The name you give it is the
connection_nameyour code passes. See Configure connections.Scalekit credentials are available for Plain MCP server, so you don't need to register an OAuth app.
Authorize a user and make your first call
quickstart.mts import { ScalekitClient } from '@scalekit-sdk/node'import 'dotenv/config'import { createInterface } from 'node:readline/promises'const scalekit = new ScalekitClient(process.env.SCALEKIT_ENVIRONMENT_URL,process.env.SCALEKIT_CLIENT_ID,process.env.SCALEKIT_CLIENT_SECRET,)const actions = scalekit.actionsconst connector = 'plainmcp'const identifier = 'user_123'// Generate an authorization link for the userconst { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })console.log('Authorize Plain MCP:', link)const rl = createInterface({ input: process.stdin, output: process.stdout })await rl.question('Press Enter after authorizing...')rl.close()// Make your first callconst result = await actions.executeTool({connector,identifier,toolName: 'plainmcp_getcustomers',toolInput: {},})console.log(result)Terminal window npx tsx quickstart.mtsquickstart.py import osfrom scalekit import ScalekitClientfrom dotenv import load_dotenvload_dotenv()scalekit_client = ScalekitClient(env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),client_id=os.getenv("SCALEKIT_CLIENT_ID"),client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),)actions = scalekit_client.actionsconnection_name = "plainmcp"identifier = "user_123"# Generate an authorization link for the userlink_response = actions.get_authorization_link(connection_name=connection_name,identifier=identifier,)print("Authorize Plain MCP:", link_response.link)input("Press Enter after authorizing...")# Make your first callresult = actions.execute_tool(tool_input={},tool_name="plainmcp_getcustomers",connection_name=connection_name,identifier=identifier,)print(result)Terminal window python quickstart.pyEach user signs in once. See Authorize a user for the full flow and statuses.
Tools
Pass the exact name toexecute_toolplainmcp_getcustomerdetailsFetch a customer's full profile including email, assignment, company, and timestamps.Read-onlyGetCustomerDetails
Fetch a customer's full profile including email, assignment, company, and timestamps.
Inputs
customerIdstringrequired- Plain customer ID (starts with c_). Get it from getCustomers or getCustomerDetails.
plainmcp_getcustomersReturn a paginated list of all customers in the workspace.Read-onlyGetCustomers
Return a paginated list of all customers in the workspace.
Inputs
cursorstring- No description.
firststring- No description.default
50 tenantIdentifiersstring- No description.
plainmcp_getcustomerthreadsReturn all threads belonging to a specific customer, with optional status filtering.Read-onlyGetCustomerThreads
Return all threads belonging to a specific customer, with optional status filtering.
Inputs
customerIdstringrequired- No description.
cursorstring- No description.
firststring- No description.default
10 statusDetailsstring- No description.
statusesstring- No description.
plainmcp_gethelpcenterarticleFetch a single Help Center article by its ID.Read-onlyGetHelpCenterArticle
Fetch a single Help Center article by its ID.
Inputs
idstringrequired- Unique identifier of the resource.
plainmcp_gethelpcenterarticlebyslugFetch a Help Center article by its URL slug.Read-onlyGetHelpCenterArticleBySlug
Fetch a Help Center article by its URL slug.
Inputs
helpCenterIdstringrequired- Plain Help Center ID (starts with hc_). Get it from getHelpCenters.
slugstringrequired- URL slug of the Help Center article.
plainmcp_gethelpcenterarticlegroupsReturn all article groups for a Help Center.Read-onlyGetHelpCenterArticleGroups
Return all article groups for a Help Center.
Inputs
helpCenterIdstringrequired- No description.
cursorstring- No description.
firststring- No description.default
50
plainmcp_gethelpcenterarticlesReturn a paginated list of articles in a Help Center.Read-onlyGetHelpCenterArticles
Return a paginated list of articles in a Help Center.
Inputs
helpCenterIdstringrequired- No description.
cursorstring- No description.
firststring- No description.default
50
plainmcp_gethelpcentersReturn all Help Centers in the workspace.Read-onlyGetHelpCenters
Return all Help Centers in the workspace.
Inputs
cursorstring- No description.
firststring- No description.default
50
plainmcp_getlabelsReturn all label types available in the workspace.Read-onlyGetLabels
Return all label types available in the workspace.
Inputs
cursorstring- No description.
firststring- No description.default
50
plainmcp_getmyassignedthreadsReturn threads assigned to the authenticated user, with optional status and priority filters.Read-onlyGetMyAssignedThreads
Return threads assigned to the authenticated user, with optional status and priority filters.
Inputs
userIdstringrequired- No description.
cursorstring- No description.
firststring- No description.default
10 prioritiesstring- No description.
statusDetailsstring- No description.
statusesstring- No description.
plainmcp_getmyuserReturn the profile of the currently authenticated workspace user.Read-onlyGetMyUser
Return the profile of the currently authenticated workspace user.
Inputs
This tool takes no inputs.
plainmcp_getmyworkspaceReturn details about the current workspace including its ID and name.Read-onlyGetMyWorkspace
Return details about the current workspace including its ID and name.
Inputs
This tool takes no inputs.
plainmcp_getsidekicksessionPoll a Sidekick session: read its status, its newest messages, and any approval it is blocked on.Read-onlyGetSidekickSession
Poll a Sidekick session: read its status, its newest messages, and any approval it is blocked on. Call this repeatedly after startSidekickSession or sendSidekickMessage.
Inputs
discussionIdstringrequired- No description.
beforestring- No description.
laststring- No description.default
10
plainmcp_getsnippetFetch a single snippet by ID, including soft-deleted snippets (where isDeleted is true).Read-onlyGetSnippet
Fetch a single snippet by ID, including soft-deleted snippets (where isDeleted is true). Use this when you already have a snippet ID from getSnippets or another tool.
Inputs
snippetIdstringrequired- Snippet ID (starts with sn_), from getSnippets or another tool.
plainmcp_getsnippetsFetch a paginated list of snippets from the workspace.Read-onlyGetSnippets
Fetch a paginated list of snippets from the workspace. Snippets are reusable reply templates that agents insert when composing replies. Soft-deleted snippets are excluded from this list.
Inputs
cursorstring- No description.
firststring- No description.default
50
plainmcp_gettenantdetailsFetch full details for a specific tenant by its ID.Read-onlyGetTenantDetails
Fetch full details for a specific tenant by its ID.
Inputs
tenantIdstringrequired- Plain tenant ID (starts with t_). Get it from getCustomers.
plainmcp_gettenantsReturn a paginated list of all tenants in the workspace.Read-onlyGetTenants
Return a paginated list of all tenants in the workspace.
Inputs
cursorstring- No description.
firststring- No description.default
50
plainmcp_getthreaddetailsFetch a thread's full details and timeline entries by thread ID.Read-onlyGetThreadDetails
Fetch a thread's full details and timeline entries by thread ID.
Inputs
threadIdstringrequired- No description.
timelineCursorstring- No description.
timelineFirststring- No description.default
50
plainmcp_getthreadfieldschemasReturn all custom thread field schemas defined in the workspace.Read-onlyGetThreadFieldSchemas
Return all custom thread field schemas defined in the workspace.
Inputs
cursorstring- No description.
firststring- No description.default
50
plainmcp_getthreadknowledgesourcecitationsFetch the knowledge sources cited by AI agent replies on a thread.Read-onlyGetThreadKnowledgeSourceCitations
Fetch the knowledge sources cited by AI agent replies on a thread. Currently only Ari, Plain's AI support agent, produces citations. Correlate timelineEntryId with the timeline entry id values from getThreadDetails to see which reply cited which source. Returns an empty list when the thread has no citations.
Inputs
threadIdstringrequired- Plain thread ID (starts with th_) to fetch citations for.
plainmcp_getthreadsReturn threads with flexible filtering by status, priority, assignee, customer, labels, or date range.Read-onlyGetThreads
Return threads with flexible filtering by status, priority, assignee, customer, labels, or date range.
Inputs
assignedToUserstring- No description.
createdAtAfterstring- No description.
createdAtBeforestring- No description.
cursorstring- No description.
customerIdsstring- No description.
firststring- No description.default
10 isAssignedstring- No description.
labelTypeIdsstring- No description.
prioritiesstring- No description.
slaStatusesstring- No description.
slaTypesstring- No description.
statusDetailsstring- No description.
statusesstring- No description.
surveyResponsestring- No description.
tenantIdentifiersstring- No description.
threadFieldsstring- No description.
plainmcp_getuserbyemailLook up a workspace user by their email address.Read-onlyGetUserByEmail
Look up a workspace user by their email address.
Inputs
emailstringrequired- Email address of the user.
plainmcp_listsidekicksessionsList Sidekick sessions in the workspace, most recent activity first.Read-onlyListSidekickSessions
List Sidekick sessions in the workspace, most recent activity first. Use this to resume a session from an earlier conversation, check whether a session landed after a timeout, or find sessions that need attention. Pass agentStatuses: [NEEDS_INPUT] for sessions blocked on a human approval decision, or agentStatuses: [IN_PROGRESS] for ones still working. statuses is the session's own lifecycle (OPEN/RESOLVED) and does not overlap with agentStatuses.
Inputs
afterstring- No description.
agentStatusesstring- No description.
createdByUserIdsstring- No description.
firststring- No description.default
20 statusesstring- No description.
plainmcp_searchcustomersSearch customers by name or email and return a paginated list of matches.Read-onlySearchCustomers
Search customers by name or email and return a paginated list of matches.
Inputs
searchstringrequired- No description.
cursorstring- No description.
firststring- No description.default
50 tenantIdentifiersstring- No description.
plainmcp_searchtenantsSearch tenants by name and return matching results.Read-onlySearchTenants
Search tenants by name and return matching results.
Inputs
searchTermstringrequired- No description.
cursorstring- No description.
firststring- No description.default
50
plainmcp_searchthreadlinkcandidatesSearch a connected issue tracker for external entities that can be linked to a thread via createThreadLink.Read-onlySearchThreadLinkCandidates
Search a connected issue tracker for external entities that can be linked to a thread via createThreadLink. Scope the search to one issue tracker with sourceType (e.g. jira_issue, incidentio_incident, shortcut_story, rootly_incident, github_issue) and match against issue titles or identifiers with the free-text searchQuery. Requires a connected issue tracker integration for the given sourceType.
Inputs
searchQuerystringrequired- No description.
sourceTypestringrequired- No description.
cursorstring- No description.
firststring- No description.default
25
plainmcp_searchthreadsSearch threads by text with optional filters for status, priority, assignee, customer, and labels.Read-onlySearchThreads
Search threads by text with optional filters for status, priority, assignee, customer, and labels.
Inputs
searchQuerystringrequired- No description.
assignedToUserstring- No description.
cursorstring- No description.
customerIdsstring- No description.
firststring- No description.default
50 labelTypeIdsstring- No description.
prioritiesstring- No description.
statusDetailsstring- No description.
statusesstring- No description.
tenantIdentifiersstring- No description.
plainmcp_createBroadcastCreate a new broadcast: a message authored once and posted to many Slack channels at once.WriteCreate Broadcast
Create a new broadcast: a message authored once and posted to many Slack channels at once. Creating one never sends it â a new broadcast is a DRAFT, and scheduling the real send is done by a human in the Plain app. Required input fields: `name`, `content`, `contentFormat`, `type`. - `name` identifies the broadcast internally and is never shown to recipients. It is what `searchBroadcasts` matches on. - `notificationTitle` is what recipients see in the notification the broadcast arrives as. It does leave Plain. Optional here, but the broadcast cannot be sent or tested until it is set. - `type` must be `SLACK`. It is fixed at creation: content is written against a channel's rendering rules, so a broadcast cannot be moved to another channel later. - `contentFormat` and `content` go together. From MCP, send `SLACK_BLOCK_KIT` and a JSON array of Slack blocks, as `chat.postMessage` would take. A one-paragraph body looks like this, passed as a string: "[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"Hello\"}}]" Buttons need a `url` â interactive elements do nothing in a broadcast. Images must be publicly reachable. This format cannot be edited in the Plain app. `TIPTAP` is still accepted (a serialised Tiptap document) and is what the app composer writes; do not use it unless you are copying content already stored that way. - `isLinkUnfurlingEnabled` controls whether Slack expands links and media. Defaults to true, which is Slack's own behaviour. - `appendUnsubscribeLink` controls whether Plain appends an unsubscribe footer when this broadcast is delivered. Omit to inherit the workspace default from `getBroadcastUnsubscribeLinkSetting`; pass true or false to override that default for this broadcast only. It controls footer emission, not whether unsubscribes are honoured. - `senderType` is who the broadcast is sent as: `PLAIN_WORKSPACE` posts under the workspace's own name and logo and takes no `senderUserId`; `PLAIN_USER` posts as a Plain user and requires `senderUserId`. Get user IDs from `getMyUser` or `getUserByEmail`. Leave `senderEmailAddress` unset: it belongs to a future email channel, not to a Slack broadcast. - `sendTarget` is who the broadcast reaches, resolved to concrete channels at send time. `scope: ALL_RECIPIENTS` means every connected, enabled customer channel and rejects `filters`; `scope: MATCHING` requires `filters`. Omit `scope` to target only the channels named in `recipients`. Inside `filters`, dimensions AND together and values within a dimension OR, and it must constrain something â reaching everyone is `ALL_RECIPIENTS`, not an empty filter. `audienceIds` reference saved audiences (`getBroadcastAudiences`), which must be of the same type as the broadcast. Preview the live resolved set with `getBroadcastSendTargetRecipients`. Both the sender and the target can be left unset here and filled in later with `updateBroadcast`. Use `sendTestBroadcast` to post a test copy to channels you name before a human schedules the real send.
Inputs
inputstringrequired- No description.
plainmcp_createBroadcastAudienceCreate a reusable broadcast audience: a named set of broadcast recipients, resolved to concrete Slack channels at send time rather than when saved.WriteCreate Broadcast Audience
Create a reusable broadcast audience: a named set of broadcast recipients, resolved to concrete Slack channels at send time rather than when saved. Required input fields: `name`, `type`, `filters`. - `name` identifies the audience internally and is never shown to recipients. - `type` must be `SLACK`. It is fixed at creation, and an audience can only be attached to a broadcast of the same type. - `filters` is what the audience selects. Dimensions on one node AND together and values within a dimension OR: `tierIds: [a, b]` means either tier, while `tierIds: [a]` plus `slackChannelNameContains: ["eng"]` means both must hold. An empty dimension cannot be written â omit it instead. - `tenantIds` / `tierIds` â get IDs from `getTenants` or `searchTenants`. - `tenantFields` â filter on a tenant field by its `externalFieldId`, supplying the value field matching the field's type. - `slackChannels` â channels pinned by ID, nothing re-resolves these, so an audience holding only these is a saved channel list. - `slackChannelNameContains` â unanchored, case-insensitive name substrings, ORed with each other and resolved at send time, so channels created or renamed later are picked up. - `and` / `or` / `not` hold further filters. `and` and `or` nest at most two levels deep. `not` may name a single dimension and nothing else. - `audienceIds` is rejected here: an audience cannot be defined in terms of another audience. It is only valid on a broadcast's own send target. - `filters: {}` â no rows at all â means every tenant, and is the only way to say so. Every nested node must constrain something. `filters` is validated against `type`, so a filter naming a dimension this type cannot resolve is rejected here rather than silently resolving to nobody at send time. Editing an audience later changes who every broadcast using it will reach on its next send.
Inputs
inputstringrequired- No description.
plainmcp_createWorkspaceSlackIntegrationFromAuthConnect workspace Slack notifications using a Slack connection the workspace already has.WriteCreate Workspace Slack Integration From Auth
Connect workspace Slack notifications using a Slack connection the workspace already has. There is no second OAuth install. Pass the id of an existing workspace Slack channel integration (`workspaceSlackChannelIntegrations`). Requires `workspaceSlackIntegration:create`. This does not choose the channel notifications post to, and it does not start posting. After it succeeds, set the `notification/slack/channel_id` setting on the new integration. Until that setting is present, Plain drops workspace Slack notifications for it.
Inputs
inputstringrequired- No description.
plainmcp_duplicateBroadcastCopy an existing broadcast into a new DRAFT.WriteDuplicate Broadcast
Copy an existing broadcast into a new DRAFT. Authoring fields (name prefixed with "Copy of", content, audience, sender, notification title, and related settings) are copied. Send history, schedule, recipients, and delivery stats are not â the copy is never scheduled or sent by this mutation. Returns the new draft's identity only. Call `getBroadcastDetails` with the returned id to read the copied content, sender, and audience. Requires `broadcast:create` and `broadcast:read`. Use `updateBroadcast` and `scheduleBroadcast` on the returned id if the draft should go out.
Inputs
inputstringrequired- No description.
plainmcp_getBroadcastAudienceDetailsFetch a single broadcast audience by its ID, or null if no audience with that ID exists.WriteGet Broadcast Audience Details
Fetch a single broadcast audience by its ID, or null if no audience with that ID exists. Returns soft-deleted audiences (where `isDeleted` is true), so the record of what a past broadcast was sent to survives. In `filters`, dimensions on one node AND together and values within a dimension OR. `slackChannels` are channels pinned by ID; the `slackChannelNameContains` substrings are re-resolved at send time. An audience with no filters at all means every tenant. `type` is fixed at creation and must match the type of any broadcast the audience is attached to. Audience IDs start with `ba_`. Do not invent IDs â only use values returned by the MCP tools.
Inputs
broadcastAudienceIdstringrequired- No description.
plainmcp_getBroadcastAudiencesFetch a paginated list of the workspace's broadcast audiences, newest first.WriteGet Broadcast Audiences
Fetch a paginated list of the workspace's broadcast audiences, newest first. An audience is a named, reusable set of broadcast recipients, resolved to concrete Slack channels at send time rather than when it was saved. Soft-deleted audiences are excluded. Pass `searchQuery` to narrow to audiences whose name contains it, matched case-insensitively and unanchored. The match happens in the database, so it finds audiences that are not on the current page. Use the `cursor` variable with the endCursor from the previous response's pageInfo to fetch the next page. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. Set `first` to control page size (default 50). In `filters`, dimensions on one node AND together and values within a dimension OR: `tierIds: [a, b]` means either tier, while `tierIds: [a]` plus `slackChannelNameContains: ["eng"]` means both must hold. `slackChannels` are channels pinned by ID, so an audience holding only those is a saved channel list. `slackChannelNameContains` is re-resolved at send time, so it picks up channels created or renamed since. An audience with no filters at all means every tenant. An audience's own filters never contain `audienceIds` â an audience cannot be defined in terms of another one. Audience IDs start with `ba_`. Do not invent IDs â only use values returned by the MCP tools.
Inputs
cursorstring- No description.
firststring- No description.default
50 searchQuerystring- Narrows to audiences whose name contains this, matched case-insensitively and unanchored. Searched in the database rather than on the page, so it finds audiences a client has not loaded.
plainmcp_getBroadcastDetailsFetch a single broadcast by its ID, including its authored content and who it is targeted at.WriteGet Broadcast Details
Fetch a single broadcast by its ID, including its authored content and who it is targeted at. Returns null if no broadcast with that ID exists, and returns soft-deleted broadcasts (where `isDeleted` is true). `content` is encoded as `contentFormat` says: `TIPTAP` is a serialised Tiptap JSON document (what the Plain app writes); `SLACK_BLOCK_KIT` is a JSON array of Slack blocks. Neither is plain text or markdown. `sendTarget` is who the broadcast reaches, resolved to concrete channels at send time rather than now. `scope: ALL_RECIPIENTS` means every connected, enabled customer channel and carries no `filters`; `scope: MATCHING` means only what `filters` selects. `recipients` are channels named outright and added to whatever `filters` resolves to; `excludeRecipients` are subtracted last. Inside `filters`, dimensions on one node AND together and values within a dimension OR. `audienceIds` reference saved audiences â read them with `getBroadcastAudienceDetails`. Preview the live resolved set with `getBroadcastSendTargetRecipients`. `appendUnsubscribeLink` is the per-broadcast override for whether Plain appends an unsubscribe footer when this broadcast is delivered. Null inherits the workspace default from `getBroadcastUnsubscribeLinkSetting`; true or false overrides that default for this broadcast only. It controls footer emission, not whether unsubscribes are honoured. `latestSend` is the most recent non-test send, and where progress lives. Use `getBroadcastSends` for the full send history, and `getBroadcastSendDeliveries` for the recipients of one send. Broadcast IDs start with `bc_`, audience IDs with `ba_`. Broadcast URL format: https://app.plain.com/workspace/{workspaceId}/broadcasts/{broadcastId} where {workspaceId} is fetched via `getMyWorkspace` (starts with `w_`). Do not invent IDs â only use values returned by the MCP tools.
Inputs
broadcastIdstringrequired- No description.
plainmcp_getBroadcastRecipientUnsubscribesFetch a paginated list of Slack channels that have opted out of broadcasts, newest first.WriteGet Broadcast Recipient Unsubscribes
Fetch a paginated list of Slack channels that have opted out of broadcasts, newest first. Use this to answer "is this channel unsubscribed?" or to audit who will be skipped on the next send. An unsubscribe is global per channel: the channel is excluded from every broadcast audience until someone resubscribes it. That is a different reason for missing a send than "the filter never matched" â check this list (or `getBroadcastSendTargetRecipients` / `SKIPPED_UNSUBSCRIBED` deliveries) before concluding a filter is wrong. Optionally narrow with `searchQuery`: matched case-insensitively and unanchored against the connected channel's current name or the Slack workspace (team) name. A channel-name hit only includes currently connected channels. A workspace-name hit returns every opted-out channel in that Slack workspace, including disconnected ones (`connectedSlackChannel` null). Disconnected channels also appear when listing without a query. Omit `searchQuery` rather than passing an empty string. A search hit is not proof the named channel is unsubscribed. Inspect each row: treat it as that channel only when `connectedSlackChannel.name` matches (after stripping a leading `#`) or `slackChannelId` matches. Other rows are siblings from a workspace whose name contained the query â do not report those as the channel the user asked about. Use the `cursor` variable with the endCursor from the previous response's pageInfo to fetch the next page. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. Set `first` to control page size (default 50). To remove an unsubscribe, call `resubscribeBroadcastRecipient` with the same `slackTeamId` + `slackChannelId`. To add one, call `unsubscribeBroadcastRecipient`. Unsubscribe IDs start with `bru_`. Do not invent IDs â only use values returned by the MCP tools.
Inputs
cursorstring- No description.
firststring- No description.default
50 searchQuerystring- Narrows to unsubscribes whose connected channel name contains this, or whose Slack workspace name contains this, matched case-insensitively and unanchored. Channel-name matches exclude disconnected channels; a workspace-name match returns every opted-out channel in that Slack workspace, including disconnected ones.
plainmcp_getBroadcastsFetch a paginated list of the workspace's broadcasts, newest first.WriteGet Broadcasts
Fetch a paginated list of the workspace's broadcasts, newest first. A broadcast is a message authored once and posted to many Slack channels at once. Soft-deleted broadcasts are excluded from this list. Optionally narrow the list with `statuses`, e.g. ["DRAFT"] for broadcasts still being written or ["SENT"] for ones already delivered. A broadcast's status comes from its latest real send, so no status reflects a test send. Omit `statuses` to list every status â an empty list is rejected. Use the `cursor` variable with the endCursor from the previous response's pageInfo to fetch the next page. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. Set `first` to control page size (default 50). `appendUnsubscribeLink` is the per-broadcast override for the unsubscribe footer (null inherits `getBroadcastUnsubscribeLinkSetting`). `latestSend` is the most recent non-test send and is where progress lives â read `deliveryCounts` from it rather than counting deliveries. `skippedUnsubscribed` is channels matched at resolve time but not posted because they opted out; it is not part of `total`. Use `getBroadcastSends` for a broadcast's full send history, and `getBroadcastSendDeliveries` for the recipients of one send. Broadcast IDs start with `bc_`. Broadcast URL format: https://app.plain.com/workspace/{workspaceId}/broadcasts/{broadcastId} where {workspaceId} is fetched via `getMyWorkspace` (starts with `w_`). Do not invent IDs â only use values returned by the MCP tools.
Inputs
cursorstring- No description.
firststring- No description.default
50 statusesstring- No description.
plainmcp_getBroadcastSendDeliveriesFetch the individual recipients of one broadcast send â which channel got the message, which did not, and why.WriteGet Broadcast Send Deliveries
Fetch the individual recipients of one broadcast send â which channel got the message, which did not, and why. Use this to answer "who missed it" or "did this channel get it". A delivery is one recipient's copy of the broadcast within one send. Narrow with `deliveryStatuses`, e.g. ["FAILED"], ["SENT"], or ["SKIPPED_UNSUBSCRIBED"]. `SKIPPED_UNSUBSCRIBED` means the channel matched the audience at send time but was not posted because it had opted out â that is a different reason for missing the message than a filter that never matched, or a `FAILED` delivery with a `failureReason`. Read `failureReason` for why a `FAILED` delivery did not land. Combine with `searchQuery` to find one recipient: matched case-insensitively and unanchored against the recorded Slack channel name, the Slack channel id, and the email address, so a delivery is found by whichever of those identifies it. The match happens in the database, so it finds deliveries that are not on the current page. Omit `searchQuery` rather than passing an empty string. `slackChannelName` is the name recorded when the send resolved, so it still names a channel that was later renamed or disconnected; it is null for deliveries from before the name was recorded. This reads the send named by `broadcastSendId`. Get the id from `getBroadcastSends`; use `isTest` to distinguish test from real sends there. An id belonging to another broadcast matches nothing. `cursor` and `first` page that send's deliveries. Use the endCursor from the previous response's `deliveries.pageInfo`; it stays valid because every page selects the same send. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. `deliveryCounts` on the send is the unfiltered summary of the whole send. `skippedUnsubscribed` is not part of `total`. `deliveries.totalCount` is how many rows match `deliveryStatuses` and `searchQuery`. A broadcast with hundreds of recipients has hundreds of deliveries, so prefer the counts plus a `deliveryStatuses: ["FAILED"]` or `["SKIPPED_UNSUBSCRIBED"]` query over paging the whole list. `edges` is empty when the broadcast has no send with that id. For the full send history use `getBroadcastSends`. For the live opted-out list independent of any send, use `getBroadcastRecipientUnsubscribes`. Broadcast IDs start with `bc_`, send IDs with `bcs_`, delivery IDs with `bcsd_`. Do not invent IDs â only use values returned by the MCP tools.
Inputs
broadcastIdstringrequired- No description.
broadcastSendIdstringrequired- No description.
cursorstring- No description.
deliveryStatusesstring- No description.
firststring- No description.default
50 searchQuerystring- No description.
plainmcp_getBroadcastSendsFetch the send history of one broadcast, newest first.WriteGet Broadcast Sends
Fetch the send history of one broadcast, newest first. Use this to answer "has this broadcast gone out, and how far did each run get". One send is one run of the broadcast. A broadcast that has been sent once and tested twice has three sends. Test sends post real messages and collect real deliveries, so check `isTest` before presenting an entry as a real send, or pass `isTest: false` to exclude them. `statuses` narrows to sends in particular states; `DRAFT` is not one of them, since it describes a broadcast with no send rather than a send. Omit a filter to leave that dimension unconstrained â an empty list is rejected. `deliveryCounts` is how far a send got, summarised across its recipients. It is one query per send regardless of how many recipients there are, so read it rather than counting recipients. `skippedUnsubscribed` is channels matched at resolve time but not posted because they opted out; it is recorded separately and is not part of `total`. For the individual recipients of one send â which channel got it, which failed and why, which were skipped as unsubscribed â use `getBroadcastSendDeliveries`. Use the `cursor` variable with the endCursor from the previous response's pageInfo to fetch the next page. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. Set `first` to control page size (default 20). Broadcast IDs start with `bc_`, send IDs with `bcs_`. Do not invent IDs â only use values returned by the MCP tools.
Inputs
broadcastIdstringrequired- No description.
cursorstring- No description.
firststring- No description.default
20 isTeststring- No description.
statusesstring- No description.
plainmcp_getBroadcastSendTargetRecipientsPreview who a broadcast send target resolves to right now â the live filter-to-recipient count, not a past send.WriteGet Broadcast Send Target Recipients
Preview who a broadcast send target resolves to right now â the live filter-to-recipient count, not a past send. Use this to answer "how many channels would get this?" and "why is the count zero?" before a human schedules the real send. Point-in-time: the number moves as tenants, tiers, tenant fields and connected channels change. Resolved through the same path a send uses, so it is what would actually be delivered to rather than an estimate assembled another way. Unsubscribed channels are excluded from `count` the same way a real send excludes them. Required input: `type` (must be `SLACK`) and `sendTarget`. - `sendTarget.scope: ALL_RECIPIENTS` means every connected, enabled customer channel and rejects `filters`. `scope: MATCHING` requires `filters`. Omit `scope` to target only channels named in `recipients`. - Inside `filters`, dimensions on one node AND together and values within a dimension OR. `audienceIds` reference saved audiences (`getBroadcastAudiences`). - `recipients` are channels named outright and added to whatever `filters` resolves to; `excludeRecipients` are subtracted last. When `count` is zero, read `emptyReason` before guessing â and treat an opt-out as a real possibility even when the reason is not `ALL_RECIPIENTS_UNSUBSCRIBED`: - `NO_TENANTS_MATCHED` â the filter itself matched no tenants. - `NO_RECIPIENTS_RESOLVED` â nothing reachable remained. That includes disabled / disconnected channels, and also every pin-by-id match (`filters.slackChannels` or named `recipients`) having opted out. Name / tenant filters usually surface the same opt-out as `ALL_RECIPIENTS_UNSUBSCRIBED` instead. Before telling the user a named channel is unreachable, call `getBroadcastRecipientUnsubscribes` (or resubscribe and re-preview) â an opt-out is not a broken connection. - `EXCLUDED_BY_AUDIENCE` â something matched, then the target's own exclusions removed all of it. - `ALL_RECIPIENTS_UNSUBSCRIBED` â something matched, and every channel it would have reached has opted out. That is not a broken filter; list the opted-out channels with `getBroadcastRecipientUnsubscribes` and restore one with `resubscribeBroadcastRecipient` if appropriate. `recipients` pages the channels that remain after unsubscribes are excluded. Use `searchQuery` to find one by name without changing `count`. Use the `cursor` variable with the endCursor from the previous response's pageInfo to fetch the next page. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. For a broadcast that has already sent, prefer `getBroadcastSendDeliveries` with `deliveryStatuses: ["SKIPPED_UNSUBSCRIBED"]` and the send's `deliveryCounts.skippedUnsubscribed` â those record what happened at send time rather than a live preview.
Inputs
inputstringrequired- No description.
cursorstring- No description.
firststring- No description.default
50 searchQuerystring- No description.
plainmcp_getBroadcastUnsubscribeLinkSettingRead whether this workspace appends an unsubscribe link to outgoing broadcasts by default.WriteGet Broadcast Unsubscribe Link Setting
Read whether this workspace appends an unsubscribe link to outgoing broadcasts by default. This is emission-only: it controls whether the footer link is rendered on delivered messages. It does not enable or disable unsubscribes themselves â channels can still be opted out via `unsubscribeBroadcastRecipient` or the public link, and audience resolution always honours existing unsubscribes regardless of this setting. Precedence when a broadcast is delivered: 1. If the broadcast has an explicit `appendUnsubscribeLink` override, that value wins for that broadcast only. 2. Otherwise this workspace default applies. Null on the broadcast means "inherit this setting". The default for a new workspace is false (no footer). Read a broadcast's own override with `getBroadcastDetails`.
Inputs
This tool takes no inputs.
plainmcp_markCustomerAsSpamFlag a customer as spam.WriteMark Customer As Spam
Flag a customer as spam. This hides their threads from the inbox and excludes them from metrics. Marking a customer that is already marked as spam returns a `customer_already_marked_as_spam` error. Pass the customer `id` (starts with `c_`) as `customerId`. Use `getCustomers`, `searchCustomers`, or `getCustomerDetails` to discover it.
Inputs
customerIdstringrequired- No description.
plainmcp_resubscribeBroadcastRecipientRemove an unsubscribe so a Slack channel can receive broadcasts again.WriteResubscribe Broadcast Recipient
Remove an unsubscribe so a Slack channel can receive broadcasts again. Idempotent: resubscribing a channel that was never unsubscribed is a no-op and returns `unsubscribe: null` with no error. Required input fields: `type`, `slackTeamId`, `slackChannelId`. - `type` must be `SLACK`. A channel id is only unique within its Slack team, so both `slackTeamId` and `slackChannelId` are required together. - When an unsubscribe existed, the response's `unsubscribe` field is the record that was removed (for confirmation). When nothing was opted out, `unsubscribe` is null and `error` is also null. After a successful resubscribe, the channel returns to normal audience resolution: if a filter or named recipient would have included it, it will again. Confirm with `getBroadcastSendTargetRecipients` or `getBroadcastRecipientUnsubscribes` rather than assuming. Prefer confirming the channel identity with the user before calling this.
Inputs
inputstringrequired- No description.
plainmcp_searchBroadcastsSearch broadcasts by name.WriteSearch Broadcasts
Search broadcasts by name. The search is case-insensitive, matches on any part of the name, ignores accents, and requires at least 2 characters. A broadcast's `name` is internal only â it is never shown to recipients, so it is safe to search on and to show back to the user. Soft-deleted broadcasts are excluded. Optionally narrow the results with `statuses`, applied on top of the name match. Omit it to search every status â an empty list is rejected. Use the `cursor` variable with the endCursor from the previous response's pageInfo to fetch the next page. The cursor is an opaque token: pass it back unchanged and do not construct, modify, or alter it. Set `first` to control page size (default 50). Broadcast IDs start with `bc_`. Broadcast URL format: https://app.plain.com/workspace/{workspaceId}/broadcasts/{broadcastId} where {workspaceId} is fetched via `getMyWorkspace` (starts with `w_`). Do not invent IDs â only use values returned by the MCP tools.
Inputs
searchQuerystringrequired- No description.
cursorstring- No description.
firststring- No description.default
50 statusesstring- No description.
plainmcp_sendTestBroadcastSend a test copy of a broadcast to Slack channels you name, so you can see what recipients will get before the real audience does.WriteSend Test Broadcast
Send a test copy of a broadcast to Slack channels you name, so you can see what recipients will get before the real audience does. This posts real messages into real channels. Everyone in the channels you name will see it. It carries a notice at the top marking it as a test, and it goes out through the same pipeline and under the broadcast's own sender, so what arrives is what any channel would have received. Confirm the channel list with the user before calling this. - `channels` takes between 1 and 10 `{ slackTeamId, slackChannelId }` pairs. A channel ID is only unique within its Slack team, so both are needed. Every channel must already be connected to this workspace, and naming the same channel twice posts to it once. - The channels are independent of the broadcast's own audience, which is left untouched. The broadcast needs a sender and a notification title, but it does not need any channels of its own â testing is what you do before choosing them. - A test send never changes the broadcast's `status`, and never locks or unlocks editing. Only available while the broadcast can still be edited: once its real send has started, it can no longer be tested. The response includes the test send's id. Pass it to `getBroadcastSendDeliveries` to see whether each channel got it. This does not schedule the real send. Queuing a broadcast to its actual audience is done by a human in the Plain app.
Inputs
inputstringrequired- No description.
plainmcp_unmarkCustomerAsSpamClear the spam flag from a customer, restoring their threads to the inbox and metrics.WriteUnmark Customer As Spam
Clear the spam flag from a customer, restoring their threads to the inbox and metrics. The `markedAsSpamAt` timestamp is cleared. Pass the customer `id` (starts with `c_`) as `customerId`. Use `getCustomers`, `searchCustomers`, or `getCustomerDetails` to discover it.
Inputs
customerIdstringrequired- No description.
plainmcp_unsubscribeBroadcastRecipientRecord that a Slack channel should not receive further broadcasts.WriteUnsubscribe Broadcast Recipient
Record that a Slack channel should not receive further broadcasts. Idempotent: unsubscribing a channel that is already unsubscribed is a no-op and returns the existing record. Required input fields: `type`, `slackTeamId`, `slackChannelId`. - `type` must be `SLACK`. A channel id is only unique within its Slack team, so both `slackTeamId` and `slackChannelId` are required together. - The channel does not need to still be connected to this workspace. An unsubscribe for a disconnected channel is still recorded and will apply if the channel is connected again later. - This does not recall messages already posted. It only affects future audience resolution and future sends. An unsubscribe is global per channel â there are no per-broadcast or per-category unsubscribes. After this call, the channel is excluded from every broadcast until `resubscribeBroadcastRecipient` removes the record. Prefer confirming the channel identity with the user before calling this. To list who is already opted out, use `getBroadcastRecipientUnsubscribes`.
Inputs
inputstringrequired- No description.
plainmcp_updateBroadcastUpdate one or more fields of an existing broadcast.WriteUpdate Broadcast
Update one or more fields of an existing broadcast. Only `broadcastId` is required; every other field is optional and omitting it leaves that field unchanged. `type` cannot be changed. Most fields use a wrapper input: pass `{ value: ... }` to set it, or omit the field entirely to leave it alone. `notificationTitle`, `senderUserId` and `senderEmailAddress` accept `{ value: null }` to clear them. - `content` is encoded as `contentFormat` says, so set `contentFormat` alongside it whenever the encoding of the new body differs from the stored one. From MCP, send `SLACK_BLOCK_KIT` and a JSON array of Slack blocks. A one-paragraph body looks like this, passed as a string: "[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"Hello\"}}]" Buttons need a `url`; images must be publicly reachable; this format cannot be edited in the Plain app. Switching format without matching `content` is rejected. If the stored body is `TIPTAP` and you are only tweaking it, read it with `getBroadcastDetails` and send `TIPTAP` again â replacing it with Block Kit is a wholesale rewrite. - `notificationTitle` is what recipients see in the notification. Clearing it leaves a broadcast that cannot be sent. - `senderType` is `PLAIN_WORKSPACE` (posts as the workspace, no `senderUserId`) or `PLAIN_USER` (requires `senderUserId`). Either half can be set on its own as long as the resulting pair is coherent. Leave `senderEmailAddress` unset: it belongs to a future email channel, not to a Slack broadcast. - `appendUnsubscribeLink` uses `{ value: true }`, `{ value: false }`, or `{ value: null }` to clear the override so the broadcast inherits the workspace default from `getBroadcastUnsubscribeLinkSetting` again. Omit the field to leave the override unchanged. It controls footer emission, not whether unsubscribes are honoured. - `sendTarget` replaces the current target wholesale rather than merging into it, so read the existing one with `getBroadcastDetails` and send the full shape you want. `scope: ALL_RECIPIENTS` rejects `filters`; `scope: MATCHING` requires them. Preview the live resolved set with `getBroadcastSendTargetRecipients`. A broadcast that is already scheduled has to stay sendable, so clearing its sender or its target is rejected. Once its send has started it cannot be edited at all.
Inputs
inputstringrequired- No description.
plainmcp_updateBroadcastAudienceUpdate a broadcast audience's name, filters, or both.WriteUpdate Broadcast Audience
Update a broadcast audience's name, filters, or both. Only `broadcastAudienceId` is required; omitting a field leaves it unchanged. - `name` uses a wrapper input: pass `{ value: "..." }` to set it. - `filters` replaces the stored filters wholesale rather than merging into them, so read the current ones with `getBroadcastAudienceDetails` and send the full shape you want. They are validated against the audience's existing `type`, which cannot be changed. Editing an audience changes who every broadcast using it will reach on its next send, including broadcasts someone else wrote â check `getBroadcastDetails` on the broadcasts that reference it before widening or narrowing an audience.
Inputs
inputstringrequired- No description.
plainmcp_addgeneratedreplyAdd an AI-generated reply to a thread in Plain.DestructiveAddGeneratedReply
Add an AI-generated reply to a thread in Plain.
Inputs
inputstringrequired- No description.
plainmcp_addlabelsAdd one or more labels to a thread.DestructiveAddLabels
Add one or more labels to a thread.
Inputs
inputstringrequired- No description.
plainmcp_archivelabeltypeArchive a label type so it can no longer be applied to threads.DestructiveArchiveLabelType
Archive a label type so it can no longer be applied to threads.
Inputs
inputstringrequired- No description.
plainmcp_assignthreadAssign a thread to a user or machine user.DestructiveAssignThread
Assign a thread to a user or machine user.
Inputs
inputstringrequired- No description.
plainmcp_bulkupsertthreadfieldsCreate or update multiple thread field values in a single call.DestructiveBulkUpsertThreadFields
Create or update multiple thread field values in a single call.
Inputs
inputstringrequired- No description.
plainmcp_changethreadpriorityUpdate the priority of a thread.DestructiveChangeThreadPriority
Update the priority of a thread. Valid priorities are 0 (urgent) through 3 (low).
Inputs
inputstringrequired- No description.
plainmcp_createlabeltypeCreate a new label type that can be applied to threads.DestructiveCreateLabelType
Create a new label type that can be applied to threads.
Inputs
inputstringrequired- No description.
plainmcp_createnoteAdd an internal note to a thread, visible only to workspace members.DestructiveCreateNote
Add an internal note to a thread, visible only to workspace members.
Inputs
inputstringrequired- No description.
plainmcp_createsnippetCreate a new snippet (reusable reply template) in the workspace.DestructiveCreateSnippet
Create a new snippet (reusable reply template) in the workspace. name is what agents search for when inserting the snippet; text is the plain-text body (required). Optionally provide markdown for rich-text channels, and path (alphanumeric only) to place the snippet in a folder in the Plain app. Snippet bodies may include template variables such as {{ customer.email }}, {{ customer.fullName }}, {{ user.publicName }}, {{ thread.ref }}.
Inputs
inputstringrequired- No description.
plainmcp_createthreadOpen a new support thread for an existing customer.DestructiveCreateThread
Open a new support thread for an existing customer. Does not send a message — follow up with replyToThread if needed.
Inputs
inputstringrequired- No description.
plainmcp_createthreadfieldschemaCreate a new custom thread field schema for the workspace.DestructiveCreateThreadFieldSchema
Create a new custom thread field schema for the workspace.
Inputs
inputstringrequired- No description.
plainmcp_createthreadlinkLink a thread to an external entity (e.g.DestructiveCreateThreadLink
Link a thread to an external entity (e.g. a Linear issue, Jira issue, incident.io incident, or another Plain thread/task). Provide threadId plus exactly one way to identify the link target: linearIssue, jiraIssue, plainThread, plainTask, or sourceId+sourceType (use searchThreadLinkCandidates to discover sourceId for a given sourceType).
Inputs
inputstringrequired- No description.
plainmcp_deleteBroadcastSoft-delete a broadcast.DestructiveDelete Broadcast
Soft-delete a broadcast. Deleted broadcasts are excluded from `getBroadcasts` and `searchBroadcasts` but remain fetchable by ID with `getBroadcastDetails`, where `isDeleted` is true â so the record of what was sent survives. Deleting a broadcast whose send is already underway does not recall the messages it has already posted.
Inputs
inputstringrequired- No description.
plainmcp_deleteBroadcastAudienceSoft-delete a broadcast audience.DestructiveDelete Broadcast Audience
Soft-delete a broadcast audience. Deleted audiences are excluded from `getBroadcastAudiences` but stay fetchable by ID with `getBroadcastAudienceDetails`, so the record of what a past broadcast was sent to survives. Rejected with `cannot_delete_broadcast_audience` while a broadcast targeting the audience is scheduled or being sent, because past `SCHEDULED` its author can no longer edit the reference away.
Inputs
inputstringrequired- No description.
plainmcp_deletethreadfieldschemaPermanently delete a custom thread field schema by key.DestructiveDeleteThreadFieldSchema
Permanently delete a custom thread field schema by key.
Inputs
inputstringrequired- No description.
plainmcp_deletethreadlinkRemove a link between a thread and an external entity.DestructiveDeleteThreadLink
Remove a link between a thread and an external entity. Pass the threadLinkId of the link to delete (the id returned by createThreadLink or listed under a thread's links in getThreadDetails).
Inputs
inputstringrequired- No description.
plainmcp_getattachmentdownloadurlGenerate a short-lived download URL for an attachment on a thread.DestructiveGetAttachmentDownloadUrl
Generate a short-lived download URL for an attachment on a thread. Use attachment IDs returned by getThreadDetails. The returned downloadUrl expires after 3 minutes. Requires the attachment:download permission.
Inputs
attachmentIdstringrequired- Attachment ID from a thread's timeline entries (e.g. NoteEntry, ChatEntry, EmailEntry), returned by getThreadDetails.
plainmcp_markthreadasdoneMark a thread as done, moving it out of the active queue.DestructiveMarkThreadAsDone
Mark a thread as done, moving it out of the active queue.
Inputs
inputstringrequired- No description.
plainmcp_markthreadastodoMark a thread as todo, returning it to the active queue.DestructiveMarkThreadAsTodo
Mark a thread as todo, returning it to the active queue.
Inputs
inputstringrequired- No description.
plainmcp_mergethreadMerge one Plain thread into another (a MERGED_INTO native thread link).DestructiveMergeThread
Merge one Plain thread into another (a MERGED_INTO native thread link). The child thread is merged into the parent thread; on success the child thread is marked as done. For a non-merging association between threads or to an external entity, use createThreadLink instead.
Inputs
childThreadIdstringrequired- Thread ID (starts with th_) of the thread to merge in. This thread will be marked as done.
parentThreadIdstringrequired- Thread ID (starts with th_) of the thread to merge into.
plainmcp_movelabeltypeReorder a label type within the workspace label list.DestructiveMoveLabelType
Reorder a label type within the workspace label list.
Inputs
inputstringrequired- No description.
plainmcp_removelabelsRemove one or more labels from a thread.DestructiveRemoveLabels
Remove one or more labels from a thread.
Inputs
inputstringrequired- No description.
plainmcp_reorderthreadfieldschemasChange the display order of custom thread field schemas.DestructiveReorderThreadFieldSchemas
Change the display order of custom thread field schemas.
Inputs
inputstringrequired- No description.
plainmcp_replytothreadSend a reply to the last message in a thread via email, Slack, or chat.DestructiveReplyToThread
Send a reply to the last message in a thread via email, Slack, or chat.
Inputs
inputstringrequired- No description.
plainmcp_resolvesidekickapprovalApprove or deny a Sidekick tool-call approval request.DestructiveResolveSidekickApproval
Approve or deny a Sidekick tool-call approval request. ASK THE USER BEFORE CALLING THIS - show them the justification and every requested call from getSidekickSession's approval-request entry, and wait for an explicit instruction. Approving authorises Sidekick's own credentials (usually broader than the user's), not the user's own action. Denying is always safe and only reduces what Sidekick may do.
Inputs
decisionstringrequired- No description.
leaseIdstringrequired- No description.
reviewerNotestring- No description.
plainmcp_sendsidekickmessageSend a follow-up message into an existing Sidekick session.DestructiveSendSidekickMessage
Send a follow-up message into an existing Sidekick session. Use this to answer a question from Sidekick, redirect it, or give it the next task in the same session. This tool returns as soon as the message is accepted - poll getSidekickSession for the reply.
Inputs
discussionIdstringrequired- Sidekick session handle (starts with thdis_) returned by startSidekickSession.
markdownContentstringrequired- The follow-up message to send into the session.
plainmcp_snoozethreadSnooze a thread until a specified date and time.DestructiveSnoozeThread
Snooze a thread until a specified date and time.
Inputs
inputstringrequired- No description.
plainmcp_startsidekicksessionStart a new Sidekick (Plain's AI agent) session and return the handle used by every other Sidekick tool.DestructiveStartSidekickSession
Start a new Sidekick (Plain's AI agent) session and return the handle used by every other Sidekick tool. Runs asynchronously; poll getSidekickSession with the returned discussion id to follow progress and collect the reply. On a timeout do NOT retry blindly - call listSidekickSessions first to check whether the first attempt landed.
Inputs
markdownContentstringrequired- No description.
additionalContextstring- No description.
threadIdstring- No description.
plainmcp_unarchivelabeltypeRestore an archived label type so it can be applied to threads again.DestructiveUnarchiveLabelType
Restore an archived label type so it can be applied to threads again.
Inputs
inputstringrequired- No description.
plainmcp_unassignthreadRemove the current assignee from a thread.DestructiveUnassignThread
Remove the current assignee from a thread.
Inputs
inputstringrequired- No description.
plainmcp_updatelabeltypeUpdate the name or color of an existing label type.DestructiveUpdateLabelType
Update the name or color of an existing label type.
Inputs
inputstringrequired- No description.
plainmcp_updatethreadfieldschemaUpdate the label or options of an existing thread field schema.DestructiveUpdateThreadFieldSchema
Update the label or options of an existing thread field schema.
Inputs
inputstringrequired- No description.
plainmcp_updatethreadtitleUpdate the title of an existing thread.DestructiveUpdateThreadTitle
Update the title of an existing thread.
Inputs
inputstringrequired- No description.
plainmcp_upsertcustomerCreate or update a customer by external ID, email, or customer ID.DestructiveUpsertCustomer
Create or update a customer by external ID, email, or customer ID.
Inputs
inputstringrequired- No description.
plainmcp_upserthelpcenterarticleCreate or update a Help Center article by slug.DestructiveUpsertHelpCenterArticle
Create or update a Help Center article by slug.
Inputs
inputstringrequired- No description.
plainmcp_upserttenantCreate or update a tenant by external ID or tenant ID.DestructiveUpsertTenant
Create or update a tenant by external ID or tenant ID.
Inputs
inputstringrequired- No description.
plainmcp_upserttenantfieldSet or update a custom field value on a tenant.DestructiveUpsertTenantField
Set or update a custom field value on a tenant.
Inputs
inputstringrequired- No description.
plainmcp_upsertthreadfieldSet or update a custom field value on a thread.DestructiveUpsertThreadField
Set or update a custom field value on a thread.
Inputs
inputstringrequired- No description.
No tools match.