mcp-slack
Provides tools for reading Slack messages via a browser session, including search, channel history, threads, DMs, user profiles, and optional message posting.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-slack search for messages from @alice about the outage"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-slack
An MCP server for reading Slack through your own browser session, for workspaces where installing a Slack app isn't an option. Ten tools: six primitives, three multi-call operations, one write that is off by default.
It authenticates as you, not as a bot. Everything you can see, it can read; anything it posts is indistinguishable from a message you typed. Browser-session auth is not an officially supported Slack integration path, so check your workspace's policies first.
The tools take explicit ranges and neutral defaults — no assumed reporting cadence, channel naming scheme, or truncation limit — so workflows can be built on top rather than baked in.
Install
Copy the d cookie from your browser (developer tools → Application → Cookies →
https://app.slack.com) into ~/.slack-tokens.yml:
slack:
- name: myworkspace.slack.com
token: xoxd-your-cookie-value-here
xoxc: null # auto-populated on first runThe short-lived xoxc API token is derived automatically and written back, so
later runs skip that step. Both values are session credentials — chmod 600 the
file, and expect to recopy the cookie whenever your browser session ends.
Then install the server and register it:
uv tool install --editable .{
"mcpServers": {
"slack": {
"command": "/Users/you/.local/bin/mcp-slack",
"args": [],
"lifecycle": "lazy"
}
}
}To skip installing, point at the repo-root shim instead — it carries a PEP 723
header, so uv resolves dependencies on the fly:
"command": "uv", "args": ["run", "/path/to/mcp-slack/server.py"].
Related MCP server: Slack MCP Server
Tools
Tool | Purpose |
| Native Slack search syntax ( |
| Messages from one channel over a time window |
| Every reply in a thread |
| DM history with one person |
| Resolve a username or user ID to a profile |
| Channel discovery by glob and member count (expensive) |
Three tools stitch many calls into one result. They exist because their deduplication isn't reproducible from outside: a message found by search, by channel history, and by thread expansion is the same message, and only the server sees all three passes.
Tool | Purpose |
| Everything one person said or received in a range, with optional surrounding context and thread expansion, grouped by channel |
| History for many channels at once, by list or glob, with replies nested under their parents |
| Batch profiles with custom fields resolved to labels |
Time ranges accept YYYY-MM-DD, an epoch, or a relative offset like -7d.
slack_post_message posts as you, and refuses unless
SLACK_MCP_ALLOW_WRITE=1 is set in the server's environment:
"env": { "SLACK_MCP_ALLOW_WRITE": "1" }Behavior worth knowing
A channel with no messages can't be resolved by name. Names resolve via
search.messages, becauseconversations.listis throttled to the point of uselessness on Enterprise Grid — measured at 11m48s of consecutive 429 backoffs without reaching the target channel. Pass a channel ID (C…) for empty or archived channels, and prefer a channel name overslack_list_channels, which still enumerates and may returnrate_limited.Glob discovery only sees channels you've joined. It uses
users.conversationsfor the same throttling reason.Failures come back as data, not exceptions:
{"error": "not_found", ...}. Codes arenot_found,rate_limited,auth_failed, andwrite_disabled. An expired cookie shows up asauth_failed.Rate-limit waits are bounded. A cumulative sleep budget (45s, reset each tool call) means a call returns
rate_limitedrather than hanging. Library callers who don't mind waiting can raise it:SlackClient(ws, wait_budget=600).Messages are projected, not passed through. Raw Slack records run to several KB each; tools return
ts,time,user,user_name,text, andpermalink, plus thread fields when meaningful. Mentions and links are rewritten to readable text, and permalinks are built locally, so citing a message costs no extra call.Lookups are cached, message content is not. One JSON file per workspace, with a timestamp per entry:
Cached
TTL
DM channel ID
never
assigned once per pair of users
user name → ID
30d
only a handle change invalidates it
user ID → name
7d
display names change occasionally
channel name → ID
7d
renames are rare but real
team profile schema
30d
effectively static
channel member counts
24h
drifts slowly, only gates a filter
failed lookups
1h
stops a typo being re-searched in a loop
A negative is only recorded after a search completes and matches nothing, so a rate limit or transport error is never cached as "does not exist".
Library use
The multi-call operations are plain functions in slack_mcp/aggregate.py
(user_activity, channels_history, profiles) taking an explicit
SlackClient. Import them directly rather than speaking MCP to a subprocess.
License
MIT
Available Tools
10 toolsslack_channel_historyA
Read messages from one channel over a time window.
Accepts a channel name ('project-x' or '#project-x') or a channel ID. Name lookups are cached. Returns top-level messages only — use slack_thread to expand any message whose reply_count is non-zero.
Args: channel: Channel name or ID. oldest: Start bound as 'YYYY-MM-DD', 'YYYY-MM-DD HH:MM:SS', an epoch, or a relative offset like '-7d'. latest: End bound, same formats. A bare date means end-of-day. limit: Maximum messages (default 100). resolve_names: Resolve user IDs to display names (costs one call per user). include_broadcasts: When False, drop @here/@channel/@everyone messages.
Inputs: channel (required), limit, latest, oldest, +2 more. Returns: object
slack_channels_historyA
History for several channels over one time range, threads nested inline.
Give either an explicit channels list or a pattern to discover them.
Replies are attached to their parent message rather than returned flat,
which matters for channels whose substance lives in threads.
Discovery by pattern only sees channels you have joined — a matching
channel you are not a member of is invisible. That limit is deliberate:
enumerating an entire Enterprise Grid workspace is throttled past usability.
Args:
channels: Channel names or IDs. Mutually exclusive with pattern.
pattern: fnmatch glob over joined channel names, e.g. 'team-*'.
oldest: Window start — 'YYYY-MM-DD', an epoch, or an offset like '-7d'.
latest: Window end, same formats. Defaults to now.
expand_threads: Fetch replies for messages that have them.
min_members: With pattern, skip channels below this membership. Costs
one extra (cached) API call per matching channel.
max_text: Truncate message text to this many characters. None keeps all.
Inputs: latest, oldest, pattern, channels, +3 more. Returns: object
slack_dm_historyA
Read direct-message history with one person.
Args: user: Username, @username, or user ID. limit: Maximum messages (default 50). oldest: Optional start bound as 'YYYY-MM-DD' or epoch. resolve_names: Resolve user IDs to display names.
Inputs: user (required), limit, oldest, resolve_names. Returns: object
slack_list_channelsA
Discover channels by glob pattern and minimum member count.
EXPENSIVE: this enumerates conversations.list, which Enterprise Grid throttles hard, so it may return a rate_limited error on large workspaces. If you already know the channel name, skip this and pass the name straight to slack_channel_history — that resolves via one fast search call. For a glob over channels you have joined, slack_channels_history is far cheaper.
Args: pattern: fnmatch glob against the channel name, e.g. 'team-*'. min_members: Only return channels with at least this many members. include_private: Include private channels you have joined. limit: Maximum channels to return (default 200).
Inputs: limit, pattern, min_members, include_private. Returns: object
slack_post_messageA
Post a message to Slack as yourself. DISABLED by default.
Requires SLACK_MCP_ALLOW_WRITE=1 in the server environment. Without it this tool refuses and returns an error, so no agent action can post by accident.
Args: channel: Channel name or ID to post into. text: Message body (Slack mrkdwn). thread_ts: Optional thread parent timestamp, to reply in-thread.
Inputs: text (required), channel (required), thread_ts. Returns: object
slack_profilesA
Look up full profiles for several people at once.
Richer than slack_user: resolves workspace custom fields to their labels and
rewrites user-typed fields (for example Manager or Direct Reports) from raw
IDs to display names. Returns field_definitions alongside profiles. Use
slack_user for a quick single ID-to-name lookup; use this to populate
records for several people.
Args: handles: Usernames, @usernames, or user IDs. Unresolvable entries come back as {'handle': ..., 'error': ...} rather than failing the batch.
Inputs: handles (required). Returns: object
slack_searchA
Search Slack messages using native Slack search syntax.
Supports operators like from:@user, in:#channel, after:2026-01-01,
before:2026-02-01, has:link, and quoted phrases. This is the widest
net for "where was X discussed" questions across the whole workspace.
Args: query: Slack search query, e.g. 'from:@alice in:#project-x deadline'. count: Maximum matches to return (default 50). sort: 'timestamp' for newest-first, or 'score' for relevance. include_broadcasts: When False, drop @here/@channel/@everyone messages.
Inputs: query (required), sort, count, include_broadcasts. Returns: object
slack_threadA
Fetch every reply in a thread, including the parent message.
Args:
channel: Channel name or ID containing the thread.
thread_ts: Timestamp of the thread parent (the ts or thread_ts
field from a previous result).
limit: Maximum messages to return (default 100).
resolve_names: Resolve user IDs to display names.
Inputs: channel (required), thread_ts (required), limit, resolve_names. Returns: object
slack_userA
Resolve a username or user ID to a profile.
Use this to turn a raw user ID from another result (e.g. 'U01234ABCDE') into a name, or to look up someone's title, timezone, and custom fields.
Args: name_or_id: Username, @username, display name, or user ID. include_custom_fields: Resolve workspace custom profile fields to labels (costs one extra API call).
Inputs: name_or_id (required), include_custom_fields. Returns: object
slack_user_activityA
Everything one person said or received in a time range, grouped by channel.
Searches messages from and to the user, optionally pulls surrounding channel
history so replies have antecedents, and optionally expands every thread
touched. Returns messages grouped by channel with replies nested under their
parents, plus a stats block.
Prefer this over assembling the same result from slack_search plus slack_channel_history plus slack_thread: it deduplicates across all three passes, which a sequence of separate calls cannot do without replaying every message. Cost scales with the number of channels the user was active in.
Args:
user: Slack handle or user ID. Defaults to the authenticated user.
oldest: Window start — 'YYYY-MM-DD', an epoch, or a relative offset such
as '-7d'. Defaults to one day before latest.
latest: Window end, same formats. A bare date means end-of-day. Defaults
to now.
context_window: Seconds of surrounding channel history to include on
either side of the user's own messages. 0 (the default) fetches no
context; a few thousand seconds gives conversational lead-in.
expand_threads: Fetch replies for threads that were touched.
max_text: Truncate message text to this many characters. None keeps the
full text.
Inputs: user, latest, oldest, max_text, +2 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Most tools have clearly distinct purposes: search, channel history, thread expansion, DM history, user lookup, and posting. Minor overlap exists between slack_user_activity and the composition of search/history/threads, and between slack_user vs slack_profiles, but descriptions clarify their intended uses.
All tools share the slack_ prefix and use lowercase snake_case, which is consistent. Some names are verbs (search, list, post) while others are nouns (thread, user, profiles), and history variants differ (channel_history vs channels_history), but the pattern is readable and predictable overall.
Ten tools is well within the ideal range for a Slack-focused server. The count covers search, messaging history, threads, DMs, channels, users, profiles, and posting without being bloated or sparse.
The tool set provides solid coverage of read operations: search, channel/thread/DM history, multi-channel history, user activity, and profile lookups. Minor gaps exist such as channel metadata, reactions, or message send (disabled by default), but core agent workflows are well supported.
Related MCP Connectors
Hosted Slack MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Catch up on Slack without reading it. Unreads, threads, search. Browser-session or hosted OAuth.
A hosted LinkedIn MCP server for your own account. Paste one address into Claude, ChatGPT, Cursor or n8n to read your inbox, send messages and invitations, and search people. Free to start. Not made by LinkedIn.
Your own WhatsApp as an MCP server: read, search and send from any MCP client.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceRead-only MCP server for Slack with OAuth 2.1 authentication, enabling message retrieval, thread replies, search, user and channel listing.9Apache 2.0
- AlicenseNot gradedqualityCmaintenanceA production-ready MCP server for the Slack API that enables searching, listing channels, reading history, inspecting users, fetching threads, and sending messages through controlled Slack tools.53,839 npmMIT
- AlicenseNot gradedqualityDmaintenanceMCP server for interacting with Slack using a user token. It allows reading channels, DMs, threads, search, and posting messages as the authenticated user.156 npmMIT
- AlicenseNot gradedqualityBmaintenanceMCP server that gives AI agents access to your Slack workspaces using session tokens.2MIT