Skip to main content
The Slack plugin gives your MCP tools access to Slack channels and messaging on behalf of your users. You can retrieve the list of channels visible to the connected account and post messages to any channel, including replies in existing threads. All Slack tokens are managed by Toolshed’s encrypted auth layer — your tools never handle Slack credentials directly.

Authentication

The plugin uses OAuth 2.0 with the channels:read, chat:write, and groups:read scopes. To connect a user’s Slack workspace, redirect them to the login endpoint:
GET /api/auth/slack/login?userId=YOUR_USER_ID
Toolshed handles the OAuth redirect, code exchange, and encrypted token storage. After the user authorizes the app in their Slack workspace, the callback stores their credentials and they are ready to use Slack tools.
YOUR_USER_ID is the identifier your application uses to track users. It is stored alongside the encrypted token so Toolshed can retrieve the right credentials at tool invocation time.

Connecting a user

1

Initiate the OAuth flow

Send the user to the login URL. In a web app this is typically a redirect; in a CLI you can open it in the browser.
GET /api/auth/slack/login?userId=user_abc123
2

User authorizes in Slack

Slack presents the standard OAuth consent screen. The user approves the requested scopes for their workspace.
3

Toolshed stores the token

The callback handler exchanges the code, encrypts the access token, and stores it against the userId. No further action is required.

Disconnecting

To revoke and remove a user’s Slack connection, send:
DELETE /api/auth/slack?userId=YOUR_USER_ID
Toolshed attempts to revoke the token at Slack and removes the stored credentials.

Available tools

The Slack plugin exposes two tools. slack.channels.list is a read-only lookup and is safe to auto-approve by MCP clients. slack.messages.post is marked destructive and requires explicit user confirmation via the MCP elicitation flow before any message is sent.
Lists Slack channels visible to the authenticated user. This includes public channels and private groups the user is a member of, up to the specified limit. The tool uses the channels:read and groups:read scopes granted during OAuth.Parameters:
ParameterTypeRequiredDefaultDescription
limitintegerNo50Maximum number of channels to return (must be positive)
Returns:An object with a channels array. Each channel contains:
FieldTypeDescription
idstringSlack channel ID (e.g. C012AB3CD)
namestringChannel name without the # prefix
topicstringChannel topic text
memberCountnumberNumber of members in the channel
Example invocation:
{
  "tool": "slack.channels.list",
  "input": {
    "limit": 20
  }
}
Posts a message to a Slack channel. You can address the channel by its Slack channel ID or by name. Optionally supply a thread timestamp (threadTs) to post as a reply in an existing thread rather than creating a new top-level message.This tool is marked destructive — Toolshed will pause and present the user with a confirmation prompt showing the channel and a preview of the message text before sending. If the user declines or cancels, the operation is aborted and nothing is posted.
This tool requires user confirmation via the MCP elicitation flow. Your MCP host must support elicitation for this tool to complete successfully.
Parameters:
ParameterTypeRequiredDescription
channelstringYesChannel ID (e.g. C012AB3CD) or channel name (e.g. general)
textstringYesMessage text to post (Slack mrkdwn formatting supported)
threadTsstringNoThread timestamp to reply to. Omit to post a new top-level message
Returns:
FieldTypeDescription
tsstringTimestamp of the posted message, usable as a future threadTs
channelstringChannel ID the message was posted to
Example invocation:
{
  "tool": "slack.messages.post",
  "input": {
    "channel": "C012AB3CD",
    "text": "Deployment to production completed successfully."
  }
}
Example reply in a thread:
{
  "tool": "slack.messages.post",
  "input": {
    "channel": "C012AB3CD",
    "text": "Rollback complete. Services are healthy.",
    "threadTs": "1715000000.123456"
  }
}

Composing tools

A common pattern is to look up the channel ID first, then post to it:
// 1. Find the channel
{ "tool": "slack.channels.list", "input": { "limit": 100 } }

// 2. Post a message using the channel ID from the results
{ "tool": "slack.messages.post", "input": { "channel": "C012AB3CD", "text": "Hello from Toolshed!" } }
Use the channel id from slack.channels.list rather than the name when calling slack.messages.post. Channel names can be renamed, but IDs are stable.