Agentic Data Plane
Preview

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 use read_thread to 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 example in:engineering rollback after:2026-09-01. Each match carries its text, author, channel ID, and canonical link. Available only on a server that uses User OAuth, and the call needs a Slack user token carrying search:read.

  • search_files: Search files the same way. Returns file metadata rather than file contents, and has the same user-token requirement as search_messages.

  • get_file_info: Look up one file’s metadata and its authenticated download links, given a file ID. Needs files:read.

  • get_user_info: Resolve a Slack user ID, such as the author of a search result, to a name and compact profile. Needs users: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 through list_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 limit you pass, which defaults to 100 channels. When more matches sit on the page where the server stopped scanning, the response sets truncated. Those matches aren’t reachable by paging, so narrow the name filter or raise limit (up to 200) instead of following the cursor.

  • A name filter is applied as the server scans, so an empty result with has_next_page set means not found yet, not that no such channel exists. Pass next_cursor to 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:

  • count defaults to 20 results and caps at 100. page defaults to 1 and caps at 100. Sort by score (relevance, the default) or timestamp, in desc (the default) or asc order.

  • The response reports the page number, the page size, the total number of matches, and the total number of pages. To continue, increment page and 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_channels does, so a match can name a channel an agent hasn’t enumerated. Pass the match’s channel ID to get_channel_info and its author ID to get_user_info to 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 type before 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:

  1. Open MCP servers in the sidebar.

  2. Click Add MCP server.

  3. Click the Slack card in the marketplace picker.

  4. Replace the suggested Name, and optionally add a Description.

  5. In the Slack configuration form:

    • Auth Method: Choose Bot Token (a shared xoxb- token from the secret store) or User OAuth (a connection per caller).

      • For User OAuth: Pick the Slack OAuth provider you configured and set Required scopes for 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.

  6. 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 mode on by default for this server type. rpk ai mcp-server create leaves it off unless you pass --code-mode. See Code Mode.

After creating the server, run a tool that requires Slack authentication to verify the consent flow end-to-end:

  1. Open the Inspector tab.

  2. Run a tool that needs a Slack connection, for example post.

  3. The first call fails with a connection-required result that carries a Slack authorization URL.

  4. Open the authorization URL. Slack asks you to pick the workspace and approve the requested scopes.

  5. Slack redirects back to Agentic Data Plane. Your connection now appears under Connections.

  6. 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

Bot User OAuth Token (the default)

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 Bot Token Scopes.

User OAuth Token

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 User Token Scopes.

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, choose User 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 Token needs the standard Slack endpoints. The setting is offered only for a provider whose authorization and token endpoints are https://slack.com/oauth/v2/authorize and https://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:

  • post needs chat:write. On a Bot User OAuth Token provider, add chat:write.public to let the app post in public channels it hasn’t joined. That scope isn’t available for user tokens.

  • read_thread and read_channel need a history scope for the channel type, for example channels:history (public) or groups:history (private).

  • react needs reactions:write.

  • list_channels needs channels:read. To include private channels, add groups:read as well, or the call fails with missing_scope rather than quietly returning public channels only.

  • get_channel_info needs a read scope for the conversation type: channels:read for a public channel, groups:read for a private one, and im:read or mpim:read for a direct message.

  • get_user_info needs users:read.

  • get_file_info needs files:read.

  • search_messages and search_files need search:read, and they need it on a Slack user token.

  • get_message_permalink needs 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 scopes im:read and mpim: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 Token provider requests Slack’s Bot Token Scopes, and a User OAuth Token provider 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

connection_required even after consent

The token might be revoked or expired with no refresh. Check Connections; disconnect and reconnect if needed.

scope_upgrade_required

The server’s required scopes were widened after the user consented. The user reconnects to grant the new scope.

channel_not_found on a channel the user can see in Slack

Reading a private channel’s thread needs the groups:history scope. Add it to the server’s required scopes and have users reconnect.

missing_scope from list_channels

The call asked for private channels without groups:read. Add it to the server’s required scopes and have users reconnect, or leave private channels out of the call.

A tool reports no access to a channel that looks reachable

The account behind the token might not be a member. Run whoami to see which account and workspace the server is connected as, then run list_channels or get_channel_info and check the channel’s membership flag. Posting and reading history both need membership. An absent flag means unknown rather than not a member, so check the token’s scopes as well.

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 User OAuth Token, point the server at that provider, and reconnect. See Choose the posting identity.

missing_scope from search_messages or search_files

The user token doesn’t carry search:read. Add it to the provider’s User Token Scopes and to the server’s required scopes, then have users reconnect.

missing_scope from get_file_info

The token doesn’t carry files:read. The Slack provider preset doesn’t request it, so add it to the provider’s scopes first, then have users reconnect.

Messages post as the app when you expected them to post as a person

The OAuth provider carries a Bot User OAuth Token, which is the default. The token type is immutable, so register a separate provider with User OAuth Token and connect to that one. See Choose the posting identity.

invalid_auth from Slack

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_info takes a Slack user ID. Nothing resolves a handle or an email address to a person, and whoami reports 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.