Add a new MCP tool to list channels the calling user is a member of,
using the users.conversations API. Follows the same pattern as
usergroups_me vs usergroups_list.
Unlike channels_list which returns all workspace channels, channels_me
returns only channels the user has joined — useful on large workspaces
where channels_list returns thousands of results.
Supports channel_types, sort (by popularity), limit, and cursor
parameters.
Add three new tools for managing Slack's "Save for Later" panel,
replacing the deprecated stars.* API (March 2023). Uses internal
saved.list, saved.update, and saved.clearCompleted endpoints.
- saved_list: List saved items with filter (saved/completed/archived),
auto-pagination, and optional message content fetching
- saved_update: Mark items as completed and/or set due dates
- saved_clear_completed: Bulk-clear all completed items
All tools require browser session tokens (xoxc/xoxd) and are guarded
at registration time for bot/OAuth tokens.
Includes unit tests for CSV format, field extraction, timestamp
formatting, parameter validation, and response parsing.
Made-with: Cursor
Add two new MCP tools for channel membership management:
- conversations_join: Join public channels via conversations.join API.
Idempotent — joining a channel you're already in is a no-op.
Requires channels:join (xoxb) or channels:write (xoxp) scope.
- conversations_leave: Leave channels, group conversations, or DMs
via conversations.leave API. Marked as destructive.
Requires channels:manage (xoxb) or channels:write (xoxp) scope.
On Enterprise Grid with session tokens (xoxc/xoxd), routes through
the edge API to bypass enterprise_is_restricted errors.
Both tools accept channel IDs (Cxxxxxxxxxx) or names (#channel-name)
using the existing resolveChannelID helper.
Updated docs/01-authentication-setup.md with new OAuth scopes
(channels:join, channels:manage) and docs/03-configuration-and-usage.md
with the new tool names in the available tools list.
* fix: pre-check token type to avoid faulty ClientCounts call
client.counts only works with browser session tokens (xoxc/xoxd). OAuth
tokens (xoxp) get 'not_allowed_token_type' and bot tokens (xoxb) have no
concept of user-level unreads.
Instead of calling ClientCounts and catching the error after the fact,
pre-check the token type using the existing IsOAuth()/IsBotToken()
infrastructure and route directly to the appropriate path:
- xoxc/xoxd: fast path via client.counts (unchanged)
- xoxp: conversations.info fallback (no wasted API call)
- xoxb: clear error message
Follows the same pattern used by SearchUsers and GetConversationsContext
which already branch on token type.
Addresses review comments on korotovsky/slack-mcp-server#171.
* fix: exclude conversations_unreads tool for bot tokens
Bot tokens (xoxb) don't support unread tracking — it's a user-level
concept. Don't register the tool at all for bot token users, matching
the same pattern used for conversations_search_messages.
This gives a clean UX: bot users simply don't see the tool, rather
than getting a runtime error.
* fix: cap xoxp fallback scan depth and document limitations
The xoxp path previously scanned ALL channels (~2000+ API calls on large
workspaces). Slack's API has no bulk unread endpoint for xoxp tokens —
every other open-source implementation (agent-kit, NextNotifier, wee-slack)
uses the same per-channel scanning approach.
Changes:
- Cap scan depth to budget*2 per type group (~300 API calls max with
default max_channels=50, down from ~2000+)
- Return scan metadata (channels scanned, API calls) from each type group
- Prepend an xoxp limitation note to response text so the LLM knows
results may be partial
- Update tool description to explain xoxc vs xoxp behavior
- Fix inaccurate comment about conversations.list sort order
* fix: validate GetMutedChannels response to surface xoxp failures
Add validate() call after ParseResponse in GetMutedChannels (prefs.go),
matching the pattern used in ClientCounts. Without this, xoxp tokens
receive {ok:false, error:missing_scope} but ParseResponse only checks
HTTP status — the error was silently swallowed, returning nil/nil.
This caused muted channels to leak into xoxp results (17/28 channels
were muted in testing). Now the error propagates to the handler's
existing warn-and-proceed logic.
Also surface the limitation in the xoxp response note so the LLM
knows muted filtering is unavailable.
* fix: add shouldAddTool gating for conversations_unreads and conversations_mark
Both tools were missing Tool* constants, ValidToolNames entries, and
shouldAddTool() wrapping — breaking the established pattern used by
every other tool in the server. This prevented selective enable/disable
via the enabledTools config.
Also fixes indentation on conversations_mark registration block.
Verifies that the error recovery middleware correctly converts handler
errors into isError tool results instead of JSON-RPC protocol errors.
Uses mcp-go client/server wired via stdio pipes to test the full
middleware chain without external dependencies.
- Merge shouldAddTool and shouldAddWriteTool into single function
- Remove redundant comments
- Add envVarName parameter for write tools requiring explicit enablement
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Write tools (conversations_add_message, reactions_add, reactions_remove,
attachment_get_data) now require explicit enablement:
- If ENABLED_TOOLS explicitly includes the tool, register it
- If ENABLED_TOOLS is empty, only register if tool-specific env var is set
- If ENABLED_TOOLS excludes the tool, don't register
This resolves the conflict where ENABLED_TOOLS="" would register all tools
but SLACK_MCP_ADD_MESSAGE_TOOL="" would fail at runtime with an error.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Tool* constants to avoid magic strings in tool registration
- Add ValidToolNames slice and ValidateEnabledTools function
- Validate tool names at startup, fail with helpful error message
- Update tests to use constants
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Simplify the logic so that:
- ENABLED_TOOLS only controls which tools are registered/exposed via MCP
- Empty ENABLED_TOOLS = all tools registered (no filtering)
- Runtime permissions (ADD_MESSAGE_TOOL, REACTION_TOOL, ATTACHMENT_TOOL)
are always enforced in handlers regardless of ENABLED_TOOLS
This keeps the two concerns separate:
1. Registration/visibility (ENABLED_TOOLS)
2. Runtime permissions (individual tool env vars)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>