Slack Managed MCP Server
The Slack managed MCP server is the canonical user-delegated OAuth example for Redpanda Agentic Data Plane. Each agent caller authenticates against Slack with their own credentials, and Redpanda injects their token at call time.
Which Slack account the tools act as depends on the OAuth provider the server points at, not on the fact that each caller owns a connection. See Choose the posting identity.
After reading this page, you will be able to:
-
Configure the Slack managed MCP server with user-delegated OAuth
-
Walk through the consent flow and verify the connection on the Connections page
-
Send a test message through the Inspector
What this MCP server does
The Slack managed type exposes the following tools:
-
list_channels: List the conversations the server’s Slack account can see, and resolve a channel name to the channel ID every other tool needs. Optionally filter by name, and include private or archived channels. Each entry carries the channel’s ID, name, whether it’s private or archived, whether the account is a member, the member count, the topic and purpose text, and, for a direct message, the conversation type and the peer’s user ID. -
read_channel: Read a page of a channel’s message history, most recent first, given a channel ID. Thread replies aren’t included: a thread appears as its parent message with a reply count. Paginate with the returned cursor, and useread_threadto read a thread’s replies. -
read_thread: Read all messages in a thread, given a channel ID and thread timestamp. -
post: Send a message to a channel, optionally as a threaded reply, using plain text or Block Kit blocks. Returns the posted message’s timestamp and channel, so an agent can reply in a thread under its own post, read that post back, or react to it. -
react: Add or remove an emoji reaction on a message. -
whoami: Report the Slack account and workspace the server is connected as, and whether that account is a workspace bot or a person. Call it when a channel looks unreachable, because membership of that account governs access. -
search_messages: Search messages with Slack’s query syntax, for examplein:engineering rollback after:2026-09-01. Each match carries its text, author, channel ID, and canonical link. Available only on a server that usesUser OAuth, and the call needs a Slack user token carryingsearch:read. -
search_files: Search files the same way. Returns file metadata rather than file contents, and has the same user-token requirement assearch_messages. -
get_file_info: Look up one file’s metadata and its authenticated download links, given a file ID. Needsfiles:read. -
get_user_info: Resolve a Slack user ID, such as the author of a search result, to a name and compact profile. Needsusers:read. The tool doesn’t return email addresses or custom profile fields. -
get_channel_info: Look up one channel’s name, topic, purpose, and membership by ID, without paging throughlist_channels. -
get_message_permalink: Get Slack’s canonical link to a message or thread reply, given a channel ID and the message timestamp.
Which of these tools a server registers depends on how it authenticates. A server that uses User OAuth registers every tool. A server that uses a shared Bot Token registers every tool except search_messages and search_files, because searching runs only as a person. See Authentication scopes.
Before an agent pages through list_channels, keep the following in mind:
-
The results are capped by the
limityou pass, which defaults to 100 channels. When more matches sit on the page where the server stopped scanning, the response setstruncated. Those matches aren’t reachable by paging, so narrow the name filter or raiselimit(up to 200) instead of following the cursor. -
A name filter is applied as the server scans, so an empty result with
has_next_pageset means not found yet, not that no such channel exists. Passnext_cursorto keep scanning. -
An absent membership flag means unknown, not that the account isn’t a member. The flag can be missing for some conversations, direct messages among them, and membership isn’t the only gate in any case, because scopes govern access too. A one-to-one direct message is reported as private.
Both search tools return one page per call:
-
countdefaults to 20 results and caps at 100.pagedefaults to 1 and caps at 100. Sort byscore(relevance, the default) ortimestamp, indesc(the default) orascorder. -
The response reports the page number, the page size, the total number of matches, and the total number of pages. To continue, increment
pageand keep the query and the other options the same. -
Matches past page 100 aren’t reachable. When the reported total exceeds 100 pages, narrow the query rather than paging further.
-
Search doesn’t scan channel listings the way
list_channelsdoes, so a match can name a channel an agent hasn’t enumerated. Pass the match’s channel ID toget_channel_infoand its author ID toget_user_infoto fill in that context.
Prerequisites
Before you create the server, make sure you have:
-
A Slack workspace where you can install or authorize an OAuth app.
-
Your own Slack OAuth app, created in your Slack workspace.
-
An OAuth Provider configured in Agentic Data Plane on the Outbound providers tab of Integrations setup, pointing at Slack’s authorize/token URLs and carrying the OAuth app’s client credentials. See Configure an OAuth Provider. Decide the provider’s
Slack OAuth token typebefore you create it, because you can’t change it afterward. See Choose the posting identity. -
Familiarity with Configure User-Delegated OAuth.
Configure
Create a new Slack MCP server in Agentic Data Plane:
-
Open MCP servers in the sidebar.
-
Click Add MCP server.
-
Click the Slack card in the marketplace picker.
-
Replace the suggested
Name, and optionally add aDescription. -
In the Slack configuration form:
-
Auth Method: ChooseBot Token(a sharedxoxb-token from the secret store) orUser OAuth(a connection per caller).-
For
User OAuth: Pick the Slack OAuth provider you configured and setRequired scopesfor the tools you use. See Authentication scopes. The provider’s Slack OAuth token type decides whether the tools act as the app or as the person who authorizes, so pick the provider that carries the identity you want. See Choose the posting identity.
-
-
Post options(optional): Toggle markdown formatting, link unfurling, media unfurling, and automatic link names. -
Reaction options(optional): Maximum concurrent reaction calls. Defaults to 64.
-
-
Click Create server.
There’s no workspace field. The bot token or the user’s OAuth grant determines the workspace.
The create form turns
Enable code modeon by default for this server type.rpk ai mcp-server createleaves it off unless you pass--code-mode. See Code Mode.
Test the consent flow
After creating the server, run a tool that requires Slack authentication to verify the consent flow end-to-end:
-
Open the Inspector tab.
-
Run a tool that needs a Slack connection, for example
post. -
The first call fails with a connection-required result that carries a Slack authorization URL.
-
Open the authorization URL. Slack asks you to pick the workspace and approve the requested scopes.
-
Slack redirects back to Agentic Data Plane. Your connection now appears under Connections.
-
Run the original tool call again. The message posts as the identity the provider’s Slack OAuth token type selects. By default that’s the app’s bot user. If the provider uses a
User OAuth Token, the message posts as you.
Choose the posting identity
The Slack account a tool acts as comes from the OAuth provider, and it’s fixed when you create that provider. On a Slack provider, the create form carries a Slack OAuth token type setting with two choices:
| Token type | What the tools do |
|---|---|
|
Every tool acts as the Slack app’s bot user. Messages post as the app, and channel access follows the app’s own membership. The provider’s scope field reads |
|
Every tool acts as the person who authorized the connection. Messages post as that person, and reads and reactions are theirs too. The provider’s scope field reads |
Three consequences are worth planning around:
-
The token type is immutable. Like the client ID, it’s set at creation and can’t be edited, so an existing connection can’t silently change identity. To move to personal identity, register a second provider, for example
rp-slack-user, chooseUser OAuth Token, and connect your account to that one. Point a separate MCP server at it if the bot server has to stay available. Both providers can use the same Slack app. -
Existing providers keep their bot identity. A Slack provider registered before this setting existed goes on requesting bot authorization, and nobody has to reconnect.
-
User OAuth Tokenneeds the standard Slack endpoints. The setting is offered only for a provider whose authorization and token endpoints arehttps://slack.com/oauth/v2/authorizeandhttps://slack.com/api/oauth.v2.access, and it isn’t available on a provider set up by discovery from an MCP server URL.
To confirm which identity a server ended up with, run the whoami tool. It names the account and workspace and reports whether that account is a bot. The Slack provider picker in the MCP server form also appends the token type to each provider’s name, so you can tell two providers apart while configuring the server.
Authentication scopes
When you use user-delegated OAuth, the tools need Slack scopes that match what they do:
-
postneedschat:write. On aBot User OAuth Tokenprovider, addchat:write.publicto let the app post in public channels it hasn’t joined. That scope isn’t available for user tokens. -
read_threadandread_channelneed a history scope for the channel type, for examplechannels:history(public) orgroups:history(private). -
reactneedsreactions:write. -
list_channelsneedschannels:read. To include private channels, addgroups:readas well, or the call fails withmissing_scoperather than quietly returning public channels only. -
get_channel_infoneeds a read scope for the conversation type:channels:readfor a public channel,groups:readfor a private one, andim:readormpim:readfor a direct message. -
get_user_infoneedsusers:read. -
get_file_infoneedsfiles:read. -
search_messagesandsearch_filesneedsearch:read, and they need it on a Slack user token. -
get_message_permalinkneeds no scope of its own, but the token must be able to reach the conversation the message sits in.
Other gotchas:
-
Check the provider’s own scope list before you require a scope on the server. The Slack provider preset doesn’t request
search:read,files:read, or the direct-message scopesim:readandmpim:read, so add any scope you need to the provider first, then require it on the server, then have users reconnect. Requiring a scope the provider never asks for doesn’t stop you from saving the server. Instead, every call to the tools that need it fails for every user until the provider requests that scope too. -
The scope list the provider requests comes from its token type. A
Bot User OAuth Tokenprovider requests Slack’s Bot Token Scopes, and aUser OAuth Tokenprovider requests its User Token Scopes. Don’t copy a bot provider’s scopes into a user provider without checking each one. See Choose the posting identity. -
Tokens are workspace-scoped: the same user authorizing twice across two workspaces produces two separate connections.
Use with agents
After the server is created and at least one user has consented, you can point an agent at the Server URL on the server’s Connection tab. Each user calling the agent will trigger their own consent flow if they haven’t connected yet.
Troubleshooting
Common symptoms and fixes:
| Symptom | What to check |
|---|---|
|
The token might be revoked or expired with no refresh. Check Connections; disconnect and reconnect if needed. |
|
The server’s required scopes were widened after the user consented. The user reconnects to grant the new scope. |
|
Reading a private channel’s thread needs the |
|
The call asked for private channels without |
A tool reports no access to a channel that looks reachable |
The account behind the token might not be a member. Run |
A search tool reports that search needs a user token, not a bot token |
The connection carries a bot token. Search runs only as a person, so register an OAuth provider with |
|
The user token doesn’t carry |
|
The token doesn’t carry |
Messages post as the app when you expected them to post as a person |
The OAuth provider carries a |
|
The OAuth Provider’s client credentials are wrong, or the OAuth app has been suspended in Slack. Check the provider config. |
Limitations
This page does not cover:
-
Configuring the Slack OAuth app: Slack-side configuration (creating the app, picking redirect URIs, choosing scopes) happens in api.slack.com, not in Agentic Data Plane.
-
Looking up a user by handle or email:
get_user_infotakes a Slack user ID. Nothing resolves a handle or an email address to a person, andwhoamireports the token’s own account rather than looking anyone up. -
Reading file contents: The file tools return metadata and links, not file contents or file comments. The private links they return still need a Slack token carrying
files:read, and no tool on this server downloads a file. -
Block Kit content in search results: A search match carries the message text, not the Block Kit blocks the message was posted with.