Turn the forked slack-mcp-server into a CLI so running many agents no
longer means one resident MCP process each. Every command is a
short-lived process that reads the shared on-disk cache.
- rename module to github.com/paymog/slack-cli (go install/homebrew/ldflags)
- internal/toolcall: invoke the upstream tool handlers in-process; the only
mcp-go coupling lives here, so pkg/handler and pkg/provider are reused
byte-for-byte (clean upstream merges, fork-and-extend)
- internal/{cli,cmds,config,credstore,runtime,output}: cobra command tree,
keyring-backed credential profiles, provider bootstrap, result printing
- 21 tools as subcommands (channels, conversations, users, usergroups,
saved, reactions, attachments, cache); write tools keep their env gating
- goreleaser + homebrew release workflow; ships a skills/slack-cli skill
- unit tests for config/credstore/toolcall; MCP server still builds
The MCP server (cmd/slack-mcp-server) is kept intact.
- Restore IsReady() polling loop before ServeStdio() to fix cold-start
regression where tool calls fail for 60-90s on first run (no cache)
- Add fetchUsersMu/fetchChannelsMu mutexes to serialize fetchAndStore*
calls, preventing race between ForceRefresh and background refresh
- Use atomic file writes (temp + os.Rename) to prevent corrupt cache
files on crash
- Guard against empty API results overwriting valid cache
- Guard against empty cache files being treated as valid data
- Fix typo: TestRefreshingFlagPreventsConucrrentRefreshes → Concurrent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On large workspaces (41K+ users), the server blocks for ~90 seconds
during startup while fetching all users/channels from the Slack API,
exceeding MCP client connection timeouts.
Changes:
- Load expired cache files immediately, mark server ready, then refresh
in background via goroutine (stale-while-revalidate pattern)
- Convert usersReady/channelsReady to atomic.Bool for race-free reads
- Add refreshingUsers/refreshingChannels atomic.Bool to coalesce
concurrent background refreshes via CompareAndSwap
- Remove stdio IsReady() polling loop (no longer needed)
- Increase default cache TTL from 1h to 24h
- Document SLACK_MCP_CACHE_TTL and SLACK_MCP_MIN_REFRESH_INTERVAL
env vars in docs/03-configuration-and-usage.md
Fixes startup timeout on large workspaces. Server now starts in under
1 second regardless of workspace size when a cache file exists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the busy-wait loop that blocks the stdio transport from
responding to MCP initialize until users/channels caches are fully
loaded. On large workspaces this causes MCP clients with connection
timeouts (e.g. 30-60s) to drop the server.
Changes:
- stdio transport now starts the MCP server immediately, matching the
existing SSE/HTTP behavior. Caches continue loading in a background
goroutine. Tool calls made before caches are ready return a graceful
"not ready" error (already handled by the error recovery middleware).
- Add --no-cache CLI flag to skip cache loading entirely for
environments that only use channel/user IDs (never #name or @name
lookups). This makes startup instant regardless of workspace size.
- Add SkipCache() method on ApiProvider that marks both caches as
ready without loading data.
Fixes#271
- 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>
Add a new CLI flag `--enabled-tools` (alias `-e`) and environment variable
`SLACK_MCP_ENABLED_TOOLS` to allow users to specify which MCP tools should
be loaded. This provides flexibility to limit tool exposure based on
security requirements or use case.
- If not set, all tools are enabled (backward compatible)
- Accepts comma-separated tool names
- CLI flag takes precedence over environment variable
Available tools: conversations_history, conversations_replies,
conversations_add_message, reactions_add, reactions_remove,
attachment_get_data, conversations_search_messages, channels_list
Example usage:
slack-mcp-server --enabled-tools=conversations_history,channels_list
SLACK_MCP_ENABLED_TOOLS=channels_list slack-mcp-server
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Based on maintainer feedback, updated the logging fix to be transport-aware:
- stdio transport: Logs to stderr (fixes JSON-RPC protocol conflicts)
- sse transport: Logs to stdout (preserves existing behavior)
This approach addresses the original stdio compatibility issue while
maintaining backward compatibility for SSE users who may rely on
stdout logging for debugging and monitoring.
Changes:
- Modified newLogger() to accept transport parameter
- Added conditional outputPath logic based on transport type
- Updated main() to pass transport to newLogger()
Tested both transport modes successfully.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The server was outputting structured JSON logs to stdout when using stdio
transport, breaking JSON-RPC 2.0 protocol compliance with MCP clients like
Claude Code.
Root cause: zap logger configured with OutputPaths: ["stdout"] was sending
all diagnostic logs to stdout, interfering with JSON-RPC messages that MCP
clients expect exclusively on stdout.
Solution: Redirect all console logs to stderr while preserving stdout
exclusively for JSON-RPC protocol communication.
Fixes compatibility with all MCP clients using stdio transport including
Claude Code CLI, MCP Inspector, and other implementations.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add support for User OAuth tokens (xoxp-) as alternative to session-based auth
- Maintain backward compatibility with existing XOXC/XOXD token authentication
- XOXP tokens take priority when both authentication methods are available
- Update demo mode detection to support both authentication methods
- Add comprehensive documentation for User OAuth token setup and configuration
- Include configuration examples for both npx and Docker deployments
This enhancement provides a more secure authentication option that doesn't
require browser session extraction while preserving all existing functionality.