slack-personal-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| SLACK_ENV_FILE | No | Read this file instead of .env next to server.py; empty reads none | .env |
| SLACK_READ_ONLY | No | 1 hides every tool that changes Slack or local files | |
| SLACK_FILE_ROOTS | No | Folders, separated by :, that uploads read from and downloads write to; default home and temp | |
| SLACK_STYLE_GATE | No | off sends without the style gate (default on) | on |
| SLACK_WRITE_CHANNELS | No | Comma-separated ids (C..., D..., U...) writes may target; a DM by user id needs that U... listed; unset allows any | |
| SLACK_USER_TOKEN_<ALIAS> | No | User token for one workspace. <ALIAS> is an uppercase alias, e.g. ACME becomes alias acme. Each one adds a workspace. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| slack_list_emojiA | List custom emoji by case-insensitive name substring, with URLs or alias targets. Needs emoji:read. |
| slack_list_usergroupsA | List user groups and counts; include_users adds member IDs. Needs usergroups:read. |
| slack_get_reactionsA | Get message reaction names, counts and users; users_complete flags partial lists. Needs reactions:read and users:read for cached user names. |
| slack_read_canvasA | Read full canvas content as Markdown (default) or HTML via canvases.getContent. Needs canvases:read. |
| slack_searchB | Search with RTS and cursor; type lists default to messages in public_channel. Needs search:read.public; optionally search:read.private, search:read.im, search:read.mpim, search:read.files, search:read.users. User tokens need no action_token. |
| slack_lintA | Dry-run the style gate on a draft without sending. clean=true means it would pass. |
| slack_send_messageA | Post a Slack message AS THE USER (no app badge), via personal user token. Style gate (enforced before send unless SLACK_STYLE_GATE=off): no AI typography (em/en dash, ellipsis char, curly quotes, nbsp, bullet) - use plain ASCII; no AI-slop phrases; no concrete promises/deadlines unless allow_promise=true. Write short and plain, in the user's own voice and language. workspace: explicit alias from slack_list_workspaces. channel_id: C.../G.../D..., or a user id U... to write into the DM with that person (needs im:write). thread_ts: reply in a thread. reply_broadcast: with thread_ts, also show the reply in the channel. format: markdown (default; standard Markdown, up to 12,000 chars) or mrkdwn (Slack's own: bold, <url|label>). unfurl_links: show link previews (off by default). |
| slack_add_reactionA | Add an emoji reaction to a message AS THE USER (reactions.add, needs reactions:write). channel_id: as in slack_send_message. ts: the message timestamp. name: emoji name without colons, e.g. eyes. |
| slack_remove_reactionA | Remove the user's emoji reaction from a message (reactions.remove, needs reactions:write). |
| slack_upload_fileA | Upload a local file to a Slack channel/DM AS THE USER, with an optional comment. Same style gate as slack_send_message applies to initial_comment and title. channel_id: C.../G.../D..., or a user id U... to upload into the DM with that person (your own id = your self-DM; needs im:write). thread_ts: upload as a thread reply. file_path: absolute path inside SLACK_FILE_ROOTS (default: home and temp folders; hidden files and ~/Library refused). title: file title, defaults to the filename. |
| slack_file_infoA | File metadata by id (files.info, needs files:read): name, type, size, owner, mode, and every message that shares it (channel, ts, thread_ts). External files carry external_url. |
| slack_list_filesA | List files, newest first (files.list, needs files:read). Filter by channel_id and/or user_id (uploader). types: comma list of all, spaces, snippets, images, gdocs, zips, pdfs. page: 1-based; the reply says how many pages there are. |
| slack_download_fileA | Download a Slack file by id to a local folder (needs files:read). Returns the saved path. Saved as <file_id>-, replacing an earlier copy only once the new one is complete. dest_dir: inside SLACK_FILE_ROOTS, like slack_upload_file. External files (Google Drive and the like) are not downloaded: the reply gives their external_url. |
| slack_get_permalinkB | Link to a message (chat.getPermalink): opens it in Slack, inside its thread for replies. |
| slack_edit_messageA | Replace the text of one of YOUR messages (chat.update, chat:write). Messages by others are refused even with an admin token. Same style gate and format as slack_send_message. |
| slack_delete_messageA | Delete one of YOUR messages (chat.delete, chat:write). Messages by others are refused even with an admin token. Cannot be undone. |
| slack_schedule_messageA | Schedule a message AS THE USER (chat.scheduleMessage, chat:write). post_at: ISO 8601 with a timezone (2026-10-23T09:00:00+03:00) or unix seconds, up to 120 days ahead. Other arguments and the style gate as in slack_send_message. |
| slack_list_scheduledB | Your messages scheduled but not yet sent (chat.scheduledMessages.list), soonest first within a page. Pass next_cursor as cursor for the next page. |
| slack_cancel_scheduledC | Cancel a scheduled message (chat.deleteScheduledMessage, chat:write). |
| slack_set_statusA | Set the user's Slack status (users.profile.set, needs users.profile:write). Empty text and emoji clear it. emoji: name like palm_tree. expires_in_minutes: 0 keeps it until changed. The style gate applies to text: everyone in the workspace sees it. |
| slack_unreadA | How many messages arrived after your read marker in each of up to 20 channels/DMs (conversations.info + conversations.history). Slack's API has no full unread inbox like the app, so name the channels. count stops at limit; has_more tells there are more. |
| slack_mark_readA | Move your read marker in a channel/DM to ts (conversations.mark; needs channels:write, groups:write, im:write or mpim:write for that kind of conversation). |
| slack_list_workspacesA | List configured workspace aliases and verify token identities (auth.test; no extra scopes). |
| slack_search_messagesB | Search visible messages with raw Slack query and optional filters; returns total/page/pages. Needs search:read and users:read for cached author names; count is 1-100. |
| slack_read_channelA | Read one history page with cursor and Slack timestamp bounds; returns messages/next_cursor/has_more. Needs the conversation's channels:history, groups:history, im:history or mpim:history; users:read for names. |
| slack_read_threadA | Read thread pages from cursor within timestamp bounds; all_pages stops at max_pages (default 10). Returns complete=false while more remain. Needs channels:history/groups:history/im:history/mpim:history; users:read. |
| slack_find_userA | Find people by name via cached users.list (users:read); refresh bypasses the one-hour cache. Exact email uses users.lookupByEmail (users:read.email); U.../W... uses users.info (users:read). |
| slack_find_channelA | Find non-archived conversations by name; types: public_channel,private_channel,im,mpim (comma-separated). Needs channels:read/groups:read/im:read/mpim:read by type; users:read for DM names. Refresh reloads the cache. |
| slack_user_infoB | A user's name, title, email, timezone, status and role via users.info. Needs users:read, and users:read.email for the email. |
| slack_channel_infoB | Name, kind, topic, purpose, member count and your read marker via conversations.info; needs channels:read/groups:read/im:read/mpim:read for the conversation type. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 30 tools
Most tools target a distinct resource+action, but slack_search and slack_search_messages are genuinely confusable: both search messages, one via RTS with cursors and one via raw query with filters, and an agent can easily pick the wrong one. A few others (slack_unread vs slack_read_channel, slack_lint vs the style gate inside slack_send_message) require reading descriptions carefully to separate.
The dominant pattern is slack_verb_noun (send_message, edit_message, list_files, add_reaction), which is predictable once learned. Minor deviations exist: bare-verb slack_search, and noun-only names like slack_user_info, slack_channel_info, slack_file_info, and slack_unread break the verb-first convention, while verbs vary between get/read/find for similar lookups.
30 tools is on the heavy side for a personal Slack client, and the surface spans many sub-domains (messages, files, channels, users, reactions, scheduling, status, canvases, emoji, usergroups). Each tool covers real functionality, but the count is borderline and a few could be folded together.
Message lifecycle is well covered (send, edit, delete, schedule, cancel, reactions, thread reading, permalink), along with files, users, and info lookups. Gaps remain: there is no tool to list the channels/conversations you belong to (slack_find_channel requires a name, and slack_unread requires naming channels), and no pin/bookmark or channel create/join operations.