Slack

io.github.mindstonePublished by GitHub account mindstonev0.3.5Updated Nov 4, 2026

Slack MCP server: channels, messages, threads, reactions, users, files, and scheduled messages

Overview

AI-generated overview

Slack MCP server that lets an assistant search, read, send and manage Slack messages, channels, threads, users, files and pins in a connected workspace.

What you can do
  • Search and read messages, saved items, permalinks, channel history, unread messages and thread replies
  • Send, compose, reply, schedule, edit and delete messages, and send yourself a note
  • Manage channels: list, create, mark read, invite users, and handle pins and bookmarks
  • Look up users by name or email, open DMs, and add or remove emoji reactions
  • Download and upload file attachments, and manage reminders (experimental)
  • Check workspace connection status and token health
When to use it
Useful when you want an assistant to work inside a Slack workspace: finding past discussions, drafting or posting replies, triaging unread channels, or pulling attachments into a task. It suits users who already have a host application that handles Slack OAuth and keeps tokens on their own machine.
Requirements
Runs locally via npx with Node.js 20+ and npm. Requires a host application that performs the Slack OAuth flow and writes per-workspace token files; the server only reads them. Required environment variables: SLACK_CONFIG_PATH and SLACK_TEAM_ID. Optional: SLACK_CLIENT_ID and SLACK_CLIENT_SECRET for refreshing rotating tokens, SLACK_DISABLE_REFRESH, SLACK_REQUEST_TIMEOUT_MS, SLACK_MAX_RETRIES, MCP_WORKSPACE_PATH.
Before you install
Needs Slack OAuth app credentials (SLACK_CLIENT_SECRET) and stores per-workspace tokens on disk. Many tools write or delete data: posting, replying, scheduling, editing, deleting messages, creating channels, inviting users, pinning, bookmarking and uploading files; deletions and cancellations cannot be undone. Uploads are limited to MCP_WORKSPACE_PATH. Slack content is returned as untrusted text, and reminder tools rely on a partially deprecated API.

Installation

In SourceWeft

  1. Open Slack in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

@mindstone/mcp-server-slack

[npm version] [License: FSL-1.1-MIT]

Slack workspace MCP server — channels, messages, threads, reactions, users, files, bookmarks, and scheduled messages via the Slack Web API.

Multi-workspace Slack MCP. Host-driven OAuth, per-workspace credentials files on disk, and a security review on every release.

Status

Why this exists

When we started building this connector, Slack had not yet released an official MCP server — that came later (announced February 2026, generally available April 2026). The community Slack MCPs available at the time each got parts of the job right, but none of them combined fast user-name lookups for small and medium workspaces, the correct mention format for modern Slack (most still used the deprecated link_names=true), support for more than one Slack workspace from the same user account, and tokens that stay on the user's own machine. Slack's official server now exists and is a fine choice for many use cases. We continue to maintain this one because the host application handles the login flow, each workspace has its own credentials file on disk under the user's control, and the connector goes through our own security review before each release.

Example interaction

"Find the most recent message from Alice in #q3-planning and react with :eyes:."

Tools the host calls:

  1. lookup_user_by_email — resolves Alice's email to her Slack user ID.
  2. search_slack_messages — searches #q3-planning for her most recent message, returning the channel + timestamp.
  3. add_slack_reaction — adds the eyes reaction to that message.

Response (trimmed):

json
{  "match": {    "channel": "C08X...",    "ts": "1715953812.004200",    "user": "U07Z...",    "text": "Pushed the updated forecast to the doc, ready for review."  },  "reaction": {    "ok": true,    "name": "eyes"  }}

Requirements

  • Node.js 20+
  • npm
  • A host application that performs the Slack OAuth flow and writes per-workspace token files to ${SLACK_CONFIG_PATH}/workspaces/{teamId}.json. This server reads those files; it does not initiate OAuth itself.

One-click install

[Add to Cursor] [Add to VS Code] [Add to VS Code Insiders]

After clicking the button, your host will prompt you to fill: SLACK_CONFIG_PATH, SLACK_TEAM_ID, SLACK_CLIENT_SECRET, SLACK_REQUEST_TIMEOUT_MS, SLACK_MAX_RETRIES.

Manual config for Claude Desktop / Claude Code / Goose / Continue.dev (Slack)
json
{  "mcpServers": {    "Slack": {      "command": "npx",      "args": [        "-y",        "@mindstone/mcp-server-slack"      ],      "env": {        "SLACK_CONFIG_PATH": "",        "SLACK_TEAM_ID": "",        "SLACK_CLIENT_SECRET": "",        "SLACK_REQUEST_TIMEOUT_MS": "60000",        "SLACK_MAX_RETRIES": "10"      }    }  }}

Quick Start

Install & build

bash
cd <path-to-repo>/connectors/slacknpm installnpm run build

npx (once published)

bash
npx -y @mindstone/mcp-server-slack

Local

bash
node dist/index.js

Configuration

This server is designed to run alongside a host application that performs the Slack OAuth flow on its own. The host writes credentials to disk; this server reads them.

Required environment variables

  • SLACK_CONFIG_PATH — Path to the Slack config directory (host-managed). Contains config.json (workspace metadata) and workspaces/{teamId}.json (per-workspace tokens, mode 0600).
  • SLACK_TEAM_ID — Workspace team ID (per-workspace instance).

Optional environment variables

  • SLACK_CLIENT_ID — OAuth Connected App client ID. Only needed to refresh a rotating token. Saved non-rotating tokens authorize the Slack API directly without it. When a refresh is required but this is absent, the server fails loud with REFRESH_NO_CLIENT_CREDENTIALS and directs the host to re-authenticate.
  • SLACK_CLIENT_SECRET — OAuth Connected App client secret. Same conditions as SLACK_CLIENT_ID.
  • SLACK_DISABLE_REFRESH — Set to 1 to disable token refresh on this surface. The server will fail-closed with a structured auth_required response on token expiry instead of attempting an oauth.v2.access refresh. Use this on the cloud surface so desktop remains the sole refresh authority and avoids racing for single-use refresh tokens.
  • SLACK_REQUEST_TIMEOUT_MS — Override the default 60s upstream timeout. Must be a positive integer ≤ 300000 (5 minutes).
  • MCP_WORKSPACE_PATH — Directory that upload_slack_file reads are constrained to. Paths outside it (including symlinks pointing outside) are refused. Defaults to the system temp dir when unset.

Authentication flow

The host calls the authenticate_slack_workspace tool. The OSS server returns a structured auth_required response of the form:

json
{  "status": "auth_required",  "user_action": {    "id": "slack.connect_workspace",    "label": "Connect Slack",    "instruction": "Click \"Connect Slack\" in the side panel to authorise the workspace."  },  "agent_action": {    "instruction": "Tell the user to click the Connect Slack button in the connector settings to authorise. Then call list_slack_workspaces to verify."  },  "setupToolName": "authenticate_slack_workspace"}

The host's MCP service recognises this shape and dispatches to its registered Slack OAuth orchestrator (the desktop browser flow). Once the user signs in, the host writes tokens to ${SLACK_CONFIG_PATH}/workspaces/{teamId}.json and the server picks them up on the next call.

The OSS server never initiates OAuth itself.

Host configuration examples

This server is designed for host-orchestrated OAuth: the host writes per-workspace token files to disk and the server reads them. The examples below show the env shape — your host application is responsible for populating ${SLACK_CONFIG_PATH}/workspaces/{teamId}.json before tool calls succeed.

Claude Desktop / Cursor

json
{  "mcpServers": {    "Slack": {      "command": "npx",      "args": ["-y", "@mindstone/mcp-server-slack"],      "env": {        "SLACK_CONFIG_PATH": "/absolute/path/to/slack-config",        "SLACK_TEAM_ID": "T0123ABCD",        "SLACK_CLIENT_ID": "your-slack-app-client-id",        "SLACK_CLIENT_SECRET": "your-slack-app-client-secret"      }    }  }}

Until the host has written ${SLACK_CONFIG_PATH}/workspaces/T0123ABCD.json for that team, every tool call returns a structured auth_required response (see the Authentication flow above).

Local development (no npm publish needed)

json
{  "mcpServers": {    "Slack": {      "command": "node",      "args": ["<path-to-repo>/connectors/slack/dist/index.js"],      "env": {        "SLACK_CONFIG_PATH": "/absolute/path/to/slack-config",        "SLACK_TEAM_ID": "T0123ABCD",        "SLACK_CLIENT_ID": "your-slack-app-client-id",        "SLACK_CLIENT_SECRET": "your-slack-app-client-secret"      }    }  }}

People reads and authorization

list_slack_users, get_slack_user_profile, lookup_user_by_email, message name enrichment and the profile shown by open_slack_dm use user authorization first. If it is absent or refused for authorization, scope or token-type reasons, the read may try bot authorization once. A retry starts the read again, including pagination and username resolution. Neither authorization can supply permissions it was not granted; email lookup still needs users:read.email.

Other errors returned to the read runner do not trigger this retry. Writes keep their identity: opening a DM uses user authorization once, and send_myself_a_note uses only bot authorization. If Slack refuses the app's authorization, a notified note cannot be sent even while other Slack actions still work. Reconnecting may restore it.

list_slack_workspaces tests bot and user authorization independently with auth.test. connected means at least one passed; tokenHealth.botToken and tokenHealth.userToken report each result separately (valid, refused, unavailable, or missing / not_configured). Having a saved token does not establish that Slack accepts it.

invalid_auth, token_expired, token_revoked and account_inactive stay unchanged in the result's code field, alongside recovery guidance and next_step. When these people reads, DM opening or notified-note sending surface a credential refusal, the result also includes a fixed token_role (user or bot) when the attempt is known. Structured errors acquiring credentials keep their existing recovery shape.

Tools (39)

Authentication

  • authenticate_slack_workspace — Returns structured auth_required response; the host drives OAuth.
  • list_slack_workspaces — Check Slack connection status (connected, token health, near-expiry).

Messages

  • search_slack_messages — Search across all channels (Slack search modifiers supported). query may be left out when to_me, after or before is given; a call with none of them is refused. Uses Slack's Real-Time Search API (assistant.search.context) when the connected app holds the granular search:read.* scopes; otherwise falls back to legacy search.messages, whose results are equally complete. The response records which backend ran in search_backend; that field is diagnostic only and the fallback is not narrated to the user, because enabling the Real-Time Search path is an app-configuration change rather than anything the person asking can do. The fallback is cached per workspace only for installation-scoped refusals (missing_scope, not_allowed_token_type, feature_not_enabled, endpoint-deprecation codes) — a resource-specific access_denied surfaces as an ordinary error and RTS is retried on the next call.
  • get_slack_saved_messages — Get messages saved for later (uses is:saved). Same search-backend reporting as search_slack_messages.
  • get_slack_message_by_link — Retrieve a message from its permalink URL.
  • compose_slack_message — Open an inline editable compose form before sending; the form posts via post_slack_message when the user clicks Send.
  • post_slack_message — Post a message; DM recipient verification baked in. Self-DMs are blocked and redirected to send_myself_a_note (a user-token self-DM never notifies).
  • reply_to_slack_thread — Reply to an existing thread.
  • schedule_slack_message — Schedule a message for the future. Self-DMs are blocked (scheduled self-notes are not supported yet).
  • list_scheduled_slack_messages — List pending scheduled messages (optionally per channel), with the IDs needed to cancel them.
  • delete_scheduled_slack_message — Cancel a scheduled message before it posts.
  • update_slack_message — Edit a message you posted.
  • delete_slack_message — Permanently delete a message you posted.
  • send_myself_a_note — Send yourself a note that actually notifies you (posts a DM from the bot to the authenticated user). Use this for "jot something down" / reminders instead of a user-token self-DM.

Text sent as you (post_slack_message, reply_to_slack_thread, schedule_slack_message, update_slack_message, and the upload_slack_file comment) writes a mention of the connector's own bot user as plain @name text when the workspace record has a bot user ID, so a host that listens for your mentions of its bot is not retriggered by its own replies. Other users' mentions are sent unchanged.

A workspace record can describe a personal app: appKind: "own" with its own appId, clientId, clientSecret and appName. Then thread replies post as that app's bot, and token refresh uses the record's clientId/clientSecret pair instead of SLACK_CLIENT_ID/SLACK_CLIENT_SECRET. If the bot is not in the channel, the reply is posted as you and the tool result says so, with a hint to invite the app. Records without appKind behave as before: replies are sent as you.

Compose send status

In hosts that remember send status, sending a message closes its other compose copies. Reloaded cards show "Message sent" with the send time and hide Reopen because they do not have the sent contents. The copy used to send keeps its posted contents in a read-only sent view, including when confirmation follows a lost reply. After an error or block reply, a later sent status from another copy shows only the sent bar, without this copy's contents. While a send is in progress, other copies show “Sending…” with Send, Retry, Cancel and Save draft (where available) disabled. Replies to this copy’s own requests keep those controls locked until the other send ends. If the send ends without a confirmed outcome, those copies return to editing and keep any earlier uncertainty. A copy waiting for its own Send reply keeps its sending view. Sent views stay read-only, and uncertainty remains until a send is confirmed. After an error or missing confirmation, check whether the message was sent before using Retry; the notice stays visible while editing and returns on Reopen. Collapsing the card does not resolve that uncertainty. Policy-block explanations stay visible while editing with Send disabled. Cancel says "Nothing sent" only when no send may have gone through, including a not-dispatched failure before the request left the device.

When sending is blocked by your settings, your organization or security policy, the card hides Retry and keeps Cancel. If the server is stopped, Retry remains available.

Send requests declare _meta: { 'mcp-app/cardOutcome': 'sent' } to supporting hosts.

Channels

  • list_slack_channels — List channels (filterable, paginated).
  • get_slack_channel_history — Get recent messages from a channel.
  • create_slack_channel — Create a new channel (public or private).
  • mark_slack_channel_as_read — Mark messages read up to a timestamp.
  • get_slack_unread_messages — Get unread messages based on your read position.
  • invite_user_to_channel — Add users to a channel (bulk).

Threads

  • get_slack_thread_replies — Get all replies in a thread.

Reactions

  • add_slack_reaction — Add an emoji reaction to a message.
  • remove_slack_reaction — Remove your own reaction from a message.
  • list_slack_emoji — List the workspace's custom emoji (name → URL/alias, both wrapped in <untrusted-content> envelopes). Entries that violate Slack's emoji name/value constraints are dropped and reported (omitted_invalid_entries), never forwarded.

Pins

  • list_slack_pins — List messages pinned in a channel.
  • pin_slack_message — Pin a message to a channel.
  • unpin_slack_message — Remove a message from a channel's pinned items (the message itself is not deleted).

Users

  • list_slack_users — List active users (auto-paginates name filter).
  • get_slack_user_profile — Get detailed profile for a user.
  • lookup_user_by_email — Find a user by exact email (preferred resolution method).
  • open_slack_dm — Open a DM with a user (returns DM channel + verified recipient identity).

Files

  • download_slack_file — Download a file attachment by ID or URL.
  • upload_slack_file — Upload a local file (workspace-constrained, race-free reads; max 50MB) and optionally share it to a channel or thread. Uses the 3-step external upload flow.

Workspace

  • add_slack_bookmark — Add a bookmark to a channel.
  • list_slack_bookmarks — List a channel's bookmarks.
  • add_slack_reminder — [EXPERIMENTAL] Create a reminder (Slack API partially deprecated; prefer schedule_slack_message).
  • list_slack_reminders — [EXPERIMENTAL] List your reminders.
  • complete_slack_reminder — [EXPERIMENTAL] Mark a reminder complete.
  • delete_slack_reminder — [EXPERIMENTAL] Permanently delete a reminder.

Security notes

  • Slack-owned download URL guard — download_slack_file validates that the Slack-supplied url_private_download is HTTPS and on slack.com / *.slack.com before attaching the workspace bearer token. The download helper also sets redirect: 'manual' and re-validates every redirect hop, so a 302 from a compromised Slack edge to an attacker-controlled host can never replay the bearer token (added in 0.1.3 to close finding slack-010).
  • Untrusted-content envelopes — every tool that returns external text wraps it in <untrusted-content source="…">…</untrusted-content> envelopes per AGENTS.md invariant #6, with close-tag breakout escaping. This applies to message text, channel topics/purposes, search results, thread replies, unread messages, and downloaded file content/names. Hosts must keep the envelopes intact when surfacing tool output to the model (added in 0.1.3 to close findings slack-001..007).
  • Atomic, durable token persistence — token files are written via temp-file + fsync + rename, then chmod 0600, so a crash mid-write cannot lose Slack's single-use refresh token.
  • Refresh-failure differentiation — transient network errors, HTTP 429 rate-limits, Slack auth rejections (invalid_grant), and malformed responses produce distinct error codes so hosts can react correctly without retrying unrecoverable failures.
  • No host-internal vocabulary — host-side bridge identifiers and bundled HTTP paths are explicitly absent from the published artefact (enforced by scripts/check-no-bridge-strings.sh during prepublishOnly, and by scripts/check-internal-refs.mjs — also run as npm run security:internal-refs — which additionally rejects internal issue-tracker references in src/ and dist/).
  • Race-free upload source reads — upload_slack_file validates the source path inside the workspace, then opens it once (no-follow, non-blocking), enforces regular-file-only and the 50MB cap via fstat on the opened descriptor, re-verifies the descriptor's dev+inode against a fresh confined path resolution (defeats post-validation replacement, including swapped ancestor directories), and reads the bytes through the descriptor with the cap enforced on what is actually read.
  • Envelope parity on add-paths — add_slack_bookmark and add_slack_reminder envelope the Slack-returned title/text exactly like the list paths, with close-tag breakout escaping.

Full implementation-level notes (request-timeout composition, MSW request manifest, token-file error states, server-version drift checks, etc.) live in docs/connectors/slack-cohort-hygiene.md.

Live probe

A live probe gate is committed at test/live-probe.ts. It is not auto-run; trigger it manually:

bash
LIVE_PROBE_BOT_TOKEN=xoxb-... \LIVE_PROBE_USER_TOKEN=xoxp-... \LIVE_PROBE_TEAM_ID=T... \npm run probe:live

The probe runs against the packed tarball (not the workspace source), exercising initialize + tools/list + 5 read-only + 2 write tool calls, and logs search.messages P95 latency to validate the 60s timeout default.

By default the probe is read-only: write probes (post_slack_message, add_slack_reaction) only run when LIVE_PROBE_TEST_CHANNEL_ID is set, otherwise they are skipped and the probe still exits OK.

Publish-gate mode

For pre-publish certification, run:

bash
LIVE_PROBE_BOT_TOKEN=xoxb-... \LIVE_PROBE_USER_TOKEN=xoxp-... \LIVE_PROBE_TEAM_ID=T... \LIVE_PROBE_TEST_CHANNEL_ID=C... \npm run probe:live:gate

probe:live:gate sets LIVE_PROBE_REQUIRE_WRITES=1, which causes the probe to fail rather than skip if LIVE_PROBE_TEST_CHANNEL_ID is missing or any write probe doesn't complete cleanly. Use this before cutting a release.

Licence

FSL-1.1-MIT — Functional Source License, Version 1.1, with MIT future licence. The software converts to MIT licence on 2030-04-08.

Source: connectors/slack/README.md at commit 5510a4b

Tools

39

authenticate_slack_workspace

Connect a Slack workspace to enable all Slack operations. ACTION REQUIRED: Call this tool when: 1. list_slack_workspaces shows no workspace connected 2. User asks to connect, set up, or configure Slack 3. Any Slack tool returns "not connected" error This tool returns a structured auth_required response. The host will recognise it and dispatch to the desktop OAuth flow. After the user completes sign-in: 1. Call list_slack_workspaces to verify the connection 2. Slack tools become available immediately (no restart needed)

Takes no parameters.

list_slack_workspaces

Check Slack connection status. Call FIRST before any Slack operation. Returns: - connected: true/false - workspaces: array of connected workspaces with team names - tokenHealth: bot/user token status (valid|refused|unavailable|missing|not_configured) CRITICAL: If response shows connected=false, call authenticate_slack_workspace to start the connection flow. The host will guide the user through OAuth.

Takes no parameters.

search_slack_messages

Search messages across all channels in the Slack workspace. Requires user authorization. Uses Slack's Real-Time Search API (assistant.search.context) when the connected app has the granular search:read.* scopes; otherwise falls back to legacy search.messages, whose results are equally complete. The search_backend field records which one ran; it is diagnostic only. Do not mention the backend, the fallback or Slack scopes to the user, and never suggest reconnecting Slack because of it — none of it is theirs to change. Supports Slack search modifiers: - from:@username — Messages from a specific user - in:#channel — Messages in a specific channel - before:YYYY-MM-DD / after:YYYY-MM-DD — Date filters - has:link / has:reaction — Content filters Set to_me=true to prepend "to:@<your_username>" automatically. query may be left out when to_me, after or before is set.

Parameterspagesortaftercountqueryto_mebeforesort_dirmax_resultsresponse_format

get_slack_saved_messages

Get messages you've saved for later in Slack. Uses Slack search with the is:saved modifier (Real-Time Search API when the connected app has the granular search:read.* scopes, otherwise legacy search.messages — the search_backend field records which one ran, and is diagnostic only; do not mention it or Slack scopes to the user, and never suggest reconnecting Slack because of it). Additional filters: in:#channel, from:@username, before:/after:DATE, has:link, has:reaction.

Parameterspagesortcountquerysort_dirresponse_format

send_myself_a_note

Send yourself a Slack note that actually notifies you. This sends a direct message from the Slack app to you, so Slack treats it as a real notification. It is separate from your own self-DM "notes to self" space — same idea, different conversation, fewer mysteriously silent messages. PARAMETER: text. Use text, not message, note, or channel.

Parameterstextrequired

compose_slack_message

Open an inline editable message compose form before sending to Slack. Use this when the user wants to write or send a Slack message so they can review and edit it first. Does NOT send directly — the form posts the message (via post_slack_message) when the user clicks Send. PARAMETERS: target (channel ID, #channel-name, or a DM channel), text. For a DM target the recipient identity is resolved and locked into the draft so the send is verified.

Parameterstextrequiredtargetrequired

post_slack_message

Post a message to a Slack channel as yourself. DM SAFETY: For direct messages (D... channels), intended_recipient (the recipient User ID) is REQUIRED. Without it the message is NOT sent — a DM has no visible recipient name, so sending unverified risks reaching the wrong person. The tool also refuses to send if intended_recipient does not match the actual DM recipient. To get a User ID use lookup_user_by_email, then open_slack_dm for their DM channel. PARAMETERS: channel, text, intended_recipient. Do not use channel_id or message — these are not the parameter names. Posted as the user — messages are editable in Slack.

Parameterstextrequiredchannelrequiredintended_recipient

reply_to_slack_thread

Reply to an existing message thread in Slack. A personal app replies as its bot; shared apps reply as you. If a personal app's bot is not in the channel, the reply is posted as you with a hint to invite the app. PARAMETERS: channel, thread_ts, text. The thread_ts comes from ts_slack / thread_ts_slack on a message returned by get_slack_channel_history.

Parameterstextrequiredchannelrequiredthread_tsrequired

schedule_slack_message

Schedule a message to be posted at a future time. post_at is a Unix timestamp in SECONDS (not ms). Max 30 scheduled messages per channel per 5 minutes. Max 120 days in advance.

Parameterstextrequiredchannelrequiredpost_atrequired

list_scheduled_slack_messages

List your pending scheduled messages (optionally filtered to one channel). Returns each message's scheduled_message_id — pass it to delete_scheduled_slack_message to cancel one before it posts.

Parameterslimitcursorchannel

delete_scheduled_slack_message

Cancel a scheduled message before it posts. Get the scheduled_message_id from list_scheduled_slack_messages (or from the schedule_slack_message response). This cannot be undone — the message will never be sent.

Parameterschannelrequiredscheduled_message_idrequired

update_slack_message

Edit a message you posted in Slack. Get the message timestamp from get_slack_channel_history (use the ts_slack value). Only your own messages can be edited (workspace admins may edit others').

Parameterstsrequiredtextrequiredchannelrequired

delete_slack_message

Permanently delete a message you posted in Slack. Get the message timestamp from get_slack_channel_history (use the ts_slack value). This cannot be undone. Only your own messages can be deleted (workspace admins may delete others').

Parameterstsrequiredchannelrequired

list_slack_channels

List all channels in the connected Slack workspace. WARNING: channel_name filter only applies to the current page. For workspaces with 100+ channels, use list_slack_channels with limit=1000 and paginate via cursor, OR pass #channel-name directly to get_slack_channel_history (which auto-paginates the lookup).

Parameterslimittypescursorchannel_nameresponse_format

get_slack_channel_history

Get recent messages from a Slack channel. Channel input: channel ID (e.g., C1234567890) or #channel-name (e.g., #general). If #name lookup fails, call list_slack_channels(limit:1000), paginate, then pass the channel id here. Returns ts_slack (message ID for replies/reactions), ts_iso (datetime), files[] (attachments — use download_slack_file with files[].id), and thread info. Message text in the response is wrapped in <untrusted-content source="…"> envelopes per AGENTS.md invariant #6 — do not strip them.

Parameterslimitcursorlatestoldestchannelrequiredresponse_format

create_slack_channel

Create a new Slack channel. Channel names: lowercase only, letters/numbers/hyphens/underscores, max ~80 chars. Note: name_taken includes archived channels. Workspace settings may prevent creation.

Parametersnamerequiredis_private

mark_slack_channel_as_read

Mark messages in a channel as read up to a specific timestamp. Updates YOUR read position, not the bot's. Pass the ts of the last message you've read. For private channels/DMs, set include_private=true.

ParameterstsrequiredchannelrequiredincludePrivateinclude_private

get_slack_unread_messages

Get unread messages in a channel based on your read position. Requires user authorization. Bot-only connections cannot track unread state. For private channels/DMs, set include_private=true (default false for safety). Returns most-recent-unread-first.

ParameterslimitchannelrequiredincludePrivateinclude_private

invite_user_to_channel

Add one or more users to a Slack channel. Resolve emails to IDs first via lookup_user_by_email, then pass comma-separated IDs (max 1000). force=true (default) continues inviting valid users when some IDs are invalid.

Parametersforceusersrequiredchannelrequired

get_slack_thread_replies

Get all replies in a message thread. Get ts_slack from a message with reply_count > 0 (the thread parent). Replies may include files[] (attachments — each with id, name, mimetype, size); use download_slack_file with files[].id to download an attachment.

Parameterstslimitcursorchannelrequiredthread_ts

add_slack_reaction

Add an emoji reaction to a Slack message as yourself. Get the message timestamp from get_slack_channel_history (use ts_slack value). Common reactions: thumbsup, thumbsdown, heart, eyes, white_check_mark, x.

Parametersnamerequiredchannelrequiredtimestamprequired

remove_slack_reaction

Remove your emoji reaction from a Slack message. Only removes the connected user's own reaction — other people's reactions on the same message are unaffected. Use list_slack_emoji to discover custom emoji names.

Parametersnamerequiredchannelrequiredtimestamprequired

list_slack_emoji

List custom emoji available in the Slack workspace. Returns a name → image-URL (or alias) map with names and values wrapped in <untrusted-content> envelopes (third-party-authored content). Use the names with add_slack_reaction / remove_slack_reaction — Slack's built-in emoji always work without being listed here.

Takes no parameters.

list_slack_users

List active (non-bot, non-deleted) users in the Slack workspace. When name filter is provided, auto-paginates across up to 5 pages to find matches. For exact email match, prefer lookup_user_by_email.

Parametersnamelimitcursorresponse_format

get_slack_user_profile

Get detailed profile for a specific Slack user. Get user ID from list_slack_users or from a message, or use @username format.

Parametersuserrequired

lookup_user_by_email

Find a Slack user by their email address. PREFERRED method for resolving users — exact match, no ambiguity. WHEN TO USE: Always use this tool (instead of list_slack_users name search) when you have the user's email. It returns an exact match. WORKFLOW for sending DMs: 1. lookup_user_by_email({ email: "[email protected]" }) → get user.id 2. open_slack_dm({ user: "<user_id>" }) → get DM channel 3. post_slack_message({ channel: "<dm_channel>", text: "...", intended_recipient: "<user_id>" }) Requires users:read.email scope (may need admin approval).

Parametersemailrequired

open_slack_dm

Open or get the DM channel with a user by their Slack User ID. REQUIRES a Slack User ID (U... or W...) — does NOT accept names or usernames. Use lookup_user_by_email (preferred, exact match) or list_slack_users to get the User ID first. Returns the DM channel ID (D...) plus verified recipient identity for use with post_slack_message. Does NOT send a notification. WORKFLOW: 1. lookup_user_by_email({ email: "[email protected]" }) → get user.id 2. open_slack_dm({ user: "U1234567890" }) → get DM channel + verified recipient 3. post_slack_message({ channel: "D...", text: "...", intended_recipient: "U1234567890" })

Parametersuserrequired

download_slack_file

Download a file attachment from Slack by its file ID. WORKFLOW: 1. get_slack_channel_history(channel, response_format: 'detailed') 2. Each file has { id: "F...", name, mimetype, size } 3. Pass id here Returns base64 for binary files, plain text for text files. Size limit: 10MB default (max 50MB via max_size_mb). Don't pass message permalinks or thread_ts.

Parametersfile_idfile_urlmax_size_mb

upload_slack_file

Upload a local file to Slack (and optionally share it to a channel). Uses Slack's 3-step external upload flow (files.getUploadURLExternal → POST bytes → files.completeUploadExternal); the legacy files.upload endpoint was sunset by Slack in November 2025. WORKSPACE CONSTRAINT (security invariant): file_path must resolve inside the host's workspace directory (MCP_WORKSPACE_PATH, or the system temp dir when unset). Paths outside it — including symlinks pointing outside — are refused. Max file size: 50MB.

Parameterstitlechannelfilenamefile_pathrequiredthread_tsinitial_comment

list_slack_pins

List messages pinned in a Slack channel. Pinned items are the channel's curated highlights — useful for "what's pinned in #channel" meeting-prep questions.

Parameterschannelrequired

pin_slack_message

Pin a message in a Slack channel so it appears in the channel's pinned items. Get the message timestamp from get_slack_channel_history (use the ts_slack value).

Parameterschannelrequiredtimestamprequired

unpin_slack_message

Remove a message from a Slack channel's pinned items. The message itself is NOT deleted — it is only removed from pinned items. Get the message timestamp from list_slack_pins or get_slack_channel_history (use the ts_slack value).

Parameterschannelrequiredtimestamprequired

add_slack_bookmark

Add a bookmark link to a channel's bookmarks bar. Max 100 bookmarks per channel. Useful for pinning important links like project docs, dashboards, or meeting notes.

Parameterslinkrequiredemojititlerequiredchannelrequired

add_slack_reminder

[EXPERIMENTAL] Create a reminder for yourself or another user. Slack's reminders API has been partially deprecated since 2023 ("Save it for Later"). May become unreliable or stop working. For reliable timed messages, prefer schedule_slack_message. The 'time' parameter accepts a Unix timestamp (seconds) or natural language like "in 2 hours", "tomorrow at 9am", "next Monday".

Parameterstextrequiredtimerequireduser

list_slack_reminders

[EXPERIMENTAL] List your Slack reminders (pending and completed). Slack's reminders API has been partially deprecated since 2023 ("Save it for Later"). May become unreliable or stop working. Returns each reminder's id — pass it to complete_slack_reminder or delete_slack_reminder to manage one.

Takes no parameters.

complete_slack_reminder

[EXPERIMENTAL] Mark a Slack reminder as complete. Get the reminder_id from list_slack_reminders.

Parametersreminder_idrequired

delete_slack_reminder

[EXPERIMENTAL] Permanently delete a Slack reminder. Get the reminder_id from list_slack_reminders. This cannot be undone.

Parametersreminder_idrequired

list_slack_bookmarks

List the bookmarks on a channel's bookmarks bar.

Parameterschannelrequired

Version history

6
  1. v0.3.5LatestNov 4, 2026
  2. v0.3.4Nov 3, 2026
  3. v0.3.3Oct 31, 2026
  4. v0.3.2Oct 31, 2026
  5. v0.3.1Oct 29, 2026
  6. v0.3.0Sep 16, 2026

Score

80% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts

    Declare a license in the repository or the registry entry.