Spike: Slack MCP Server Feasibility & Auth Model
Date: 2026-04-02 Author: Pranav Narahari Ticket: EDE3-6 Status: Go — all tests passed, MCP fully operational
1. Summary
Verdict: Go.
The Slack MCP server is fully operational. All blocking steps have been completed: App Assistant enabled, granular scopes added, MCP connection confirmed live. initialize handshake succeeds, 13 tools discovered, search and read channel tested end-to-end with real Eden data. Ticket 9b can proceed.
2. Auth Model
Confirmed: user token (xoxp) required. Bot token (xoxb) is rejected.
| Token | MCP initialize result | Notes |
|---|---|---|
xoxp (user token) | {"code": -32600, "message": "App is not enabled..."} | Correct token type — blocked only by App Assistant config |
xoxb (bot token) | {"code": -32001, "message": "invalid_token_type"} | Permanently rejected for MCP |
This confirms the architecture decision from EDE3-2: the xoxp token is the right token for MCP. The bot token (xoxb) cannot be used for MCP under any configuration.
Current scope gap
The xoxp token currently has: identify, search:read
MCP requires these granular user scopes (per Slack MCP docs):
| MCP capability | Required scope |
|---|---|
| Search messages (public channels) | search:read.public |
| Search messages (private channels) | search:read.private |
| Search messages (group DMs) | search:read.mpim |
| Search messages (DMs) | search:read.im |
| Search files | search:read.files |
| Read channel/thread history | channels:history, groups:history, mpim:history, im:history |
| User profiles | users:read, users:read.email |
Action required: Add the search:read.* granular scopes to User Token Scopes in the Slack app, then reinstall to regenerate the xoxp token. The read history scopes are bot scopes already set up in EDE3-2.
3. MCP Setup Steps (Completed)
Both steps were required and have been completed:
- Enable App Assistant (
https://api.slack.com/apps/A0AQCJN54LB/app-assistant): Toggle “Model Context Protocol” to ON. The “Agent or Assistant” toggle does NOT need to be enabled. - Add granular user scopes (User Token Scopes in OAuth & Permissions) and reinstall:
search:read.public,search:read.private,search:read.mpim,search:read.im,search:read.files,search:read.userschannels:history,groups:history,im:history,mpim:historyusers:read,users:read.email,canvases:read,chat:write,canvases:write
Confirmed working initialize response:
{
"result": {
"serverInfo": {"name": "Slack MCP", "version": "1.0.0"},
"protocolVersion": "2025-06-18",
"capabilities": {"tools": {"listChanged": true}, "resources": {"listChanged": true}}
}
}4. Available Tools (Confirmed via tools/list)
13 tools returned. These are the actual tool names from the live Eden MCP connection:
| Tool | Capability |
|---|---|
slack_search_public | Keyword search across public channels only |
slack_search_public_and_private | Keyword search across all channels, DMs, group DMs |
slack_search_channels | Find channels by name/description |
slack_search_users | Find users by name, email, profile attributes |
slack_read_channel | Read channel messages (newest first, paginated via cursor) |
slack_read_thread | Read a specific thread and all replies |
slack_read_canvas | Retrieve canvas content and section ID map |
slack_read_user_profile | Get detailed user profile (contact, status, timezone) |
slack_send_message | Post a message to a channel or DM |
slack_send_message_draft | Create a draft (not sent) in a channel |
slack_schedule_message | Schedule a message for future delivery |
slack_create_canvas | Create a new Canvas document |
slack_update_canvas | Update an existing Canvas (append/prepend/replace) |
Key observation: The tool set exactly mirrors the Brainforge Slack MCP tools the platform already has. This strongly suggests the MCP server is the same Slack-provided service — the integration path for EDE3-9b will be straightforward using existing Mastra MCP tool patterns.
5. Response Format & PII Surface
Confirmed via live MCP calls.
MCP responses are structured JSON strings containing both display names AND user IDs. Example from slack_search_public_and_private:
Channel: #eden-technologies-operations (ID: C0AMCTGHYLA)
From: Daniel Dietz (ID: U05TX3GBC1F)
Time: 2026-03-26 19:37:40 EDT
Message_ts: 1774568260.261399
Text: Ya that's clear with a couple other priorities...
Observed RTS API behavior (live test for comparison): RTS API also returns hydrated display names in results:
{
"text": "Ya that's clear with a couple other priorities...",
"username": "daniel",
"channel": "eden-technologies-operations"
}PII implication for EDE3-8 (updated): MCP responses include both display names AND user IDs in structured fields. This is actually better than pure markdown — the From: Daniel Dietz (ID: U05TX3GBC1F) pattern is regex-parseable. EDE3-8 should redact:
- Structured
From:fields (display name + ID) - Inline
<@USERID|displayname>mentions in message text (also present in read_channel responses) - Names appearing in free-form message text (NER still needed for this case)
- The
context before/aftersnippets also contain names and must be scanned
6. Rate Limits
RTS API burst test (8 rapid calls, ~3 seconds total): All 8 returned ok: true. No throttling observed. This is consistent with Slack’s Tier 2/3 limits being generous (20–100+ req/min for non-Marketplace apps).
MCP rate limits (from docs, not directly observed):
- Read channel/thread: Tier 3 (50+/min) — adequate for the agent’s use case
- Search: Special limits (same as
search.messagesWeb API) — historically generous for internal apps - Send message:
chat.postMessagelimits apply (Tier 3 for most workspaces)
Assessment: Rate limits are not a practical blocker for this use case. The agent will not be calling Slack at high frequency.
7. Bot Channel Memberships
Observed: The bot (xoxb token) is not a member of any channels. conversations.history returns not_in_channel for all tested channels.
Implication: For the read_channel MCP tool to work, the bot must be invited to every channel it needs to read. For the Command Center use case (broad workspace context), this means:
- Option A: Invite the bot to all relevant channels (manual, channel-by-channel)
- Option B: Use the xoxp user token for channel history reads instead — the user token sees all channels the authorizing user is in
The MCP server uses xoxp for all operations (confirmed above), so Option B is the path — the user token’s access level determines channel visibility.
8. Semantic Search
RTS API test with natural language query: "what are our priorities this quarter" returned 2,536 results with keyword-matched content (individual words matched, not semantic meaning):
"sheryl" → general: "New quarters are all about growth and advancement..."
"caitlin" → product-launch-microdose: "So that's a quarterly plan for 696..."
"daniel" → eden-technologies-operations: "Ya that's clear with a couple other priorities..."
These are keyword matches, not semantic results. This indicates either:
- Eden is on Slack Pro (semantic search unavailable), or
- The RTS API never does semantic search (semantic is MCP-only via
assistant.search.context)
Cannot confirm plan tier: The team.info call requires team:read scope (not currently on either token). Add team:read as a bot scope to confirm Eden’s plan.
Recommendation: Flag to CSO that semantic search availability is unconfirmed. If Eden is on Pro, MCP search will also be keyword-only. If Business+, MCP may offer semantic ranking. Either way, keyword search with 2,536+ results demonstrates sufficient data coverage.
9. Go/No-Go Recommendation
Verdict: Go — proceed with MCP path (Ticket 9b is unblocked).
Rationale
| Factor | Finding | Verdict |
|---|---|---|
| Auth model | xoxp confirmed, working | Go |
| MCP connectivity | Live — initialize succeeds, 13 tools available | Go |
| Tools | All key tools present: search, read, send, canvas | Go |
| Rate limits | Generous, not a constraint | Go |
| Response format | Structured JSON with both display names + IDs — parseable | Go |
| Scope coverage | All required scopes added and confirmed | Go |
| Semantic search | Unconfirmed, does not block initial integration | Go |
| Bot channel access | xoxp user token covers all user-visible channels | Go |
What Ticket 9b needs from this spike
- xoxp token — store in Secret Manager / 1Password; rotate before production
- MCP endpoint:
https://mcp.slack.com/mcp(JSON-RPC 2.0, POST,Authorization: Bearer <xoxp>) - Key tools for the agent:
slack_search_public_and_private,slack_read_channel,slack_read_thread,slack_read_user_profile - Pagination: Both search and read_channel return cursors — agent must handle multi-page results
Constraints for downstream tickets
- EDE3-8 (PII redaction): Must handle markdown text with inline display names, not just JSON user IDs. Named entity recognition or display-name lookup against the identity mapping table will be needed.
- EDE3-9b (Mastra integration): MCP transport is JSON-RPC 2.0 over HTTP to
https://mcp.slack.com/mcp, xoxp token in Authorization header. No SSE support.
10. Fallback Plan (if App Assistant is plan-gated and unavailable)
If enabling App Assistant requires Eden to upgrade their Slack plan and they decline, fall back to custom Slack tools using the Web API directly:
| Capability | Web API method | Token |
|---|---|---|
| Search messages | search.messages (RTS) | xoxp |
| Channel history | conversations.history | xoxb (after bot invite) |
| User lookup | users.info | xoxb |
| Thread read | conversations.replies | xoxb |
Effort estimate: ~14 pts (per ticket notes). This path is already partially validated — both tokens work, RTS search is confirmed functional with 1,187+ results, and channel history works once the bot is invited.