
List the bookmarks pinned to a channel's header. Returns each bookmark's ID, title, link and emoji. Use listchannels to find the channelid, and use this tool to get the bookmarkid that editbookmark and remove_bookmark require.
Pin a link to a channel's header as a bookmark. Use listchannels to find the channelid. Slack currently only supports link bookmarks. Returns the new bookmark's ID for later editbookmark or removebookmark calls.
Change an existing channel bookmark's title, link or emoji. Only the fields you pass are changed. Use listbookmarks to find the bookmarkid and listchannels for the channelid.
Remove a bookmark from a channel's header. Use listbookmarks to find the bookmarkid and listchannels for the channelid. This cannot be undone; re-add with add_bookmark.
Create a new standalone Slack canvas with optional title and markdown content. Returns the canvas ID.
Write to or edit an existing Slack canvas by applying one or more change operations. Use 'insertatend' to append content, 'insertatstart' to prepend, or 'replace'/'delete' with a section_id for targeted edits.
Permanently delete a Slack canvas by ID. This action cannot be undone.
Create a canvas linked to a Slack channel. The canvas appears in the channel's canvas tab. Provide an optional markdown body for the initial content.
List channels in the workspace (public and private; direct messages are excluded by default). Returns a lean set of fields by default (id, name, isprivate, isarchived, ismember, nummembers, topic); request more via the 'fields' parameter. Paginate with cursor/pageinfo. For multi-workspace org-wide tokens, pass teamid (omitting it returns an error listing workspace IDs).
Create a new channel
Get information about a channel using Channel ID (not channel name)
Join a channel
Close a direct message or group direct message, removing it from your own sidebar. Not a delete: Slack cannot delete a DM, and the other participants keep seeing it. Use opendm or getusersconversations to find the conversation ID. For a channel use leavechannel, which this does not accept.
Leave a public or private channel you are a member of. Use listchannels to find channel IDs. To leave a DM or group DM use closeconversation instead.
Archive a channel, making it read-only for everyone. Use listchannels to find channel IDs. Reversible with unarchivechannel. You cannot archive the general channel or a DM.
Restore a previously archived channel to active use. Use listchannels with excludearchived false to find archived channel IDs.
Get members of a channel
Invite one or more users to a channel by ID. When inviting multiple users, set force=true to invite the valid ones even if some IDs are invalid or already in the channel; without force, one bad ID fails the whole call.
Remove a user from a channel
Set the topic for a channel
Set the purpose for a channel
Rename a channel
Get a file's metadata: name, type, size, owner and share locations. Use listfiles to find file IDs. This does not return the file contents; use getfile_content for the bytes.
List files in the workspace, most recent first by default. sort (created|timestamp) and sortdir (asc|desc) order the returned page only - files.list has no server-side sort, so ordering is not consistent across pages. Uploader and channels resolve to username/channel_names; raw IDs stay in user/channels. Paginate with count/page.
Permanently delete a file and remove it from every conversation it was shared in. Use list_files to find file IDs. This cannot be undone.
Share an existing file into one or more channels by posting its permalink, which Slack unfurls into a file attachment. Use listfiles to find the fileid and listchannels for channel IDs. This does NOT make the file publicly accessible; use makefile_public for that.
Get the content of a file. Text-like files return plain text in 'content'. Binary files (images, PDFs, etc.) return base64-encoded bytes in 'contentbase64' with 'mimetype' and 'encoding' set, so the caller can base64-decode back to the exact original file. For name, size or owner only, use getfile_info, which does not download.
Create a public share URL for a file, readable without a Slack account. Use listfiles to find file IDs. Reverse it with revokefilepublicurl.
Revoke a file's public share URL, so it is again readable only inside Slack. Use list_files to find file IDs.
Upload a file or image to Slack. Provide the bytes as base64 in content, not a URL and not plain text, OR a filereference from the file upload API (POST /api/v1/files/) for files up to 100 MB, which streams in without entering the model's context. Set channelid to post it; use listchannels for channel IDs. Set alttxt for images.
Send a message to a Slack channel using Channel ID (not channel name). Set mrkdwn=false to post text literally with no Slack formatting applied.
Update an existing message in Slack. Slack rejects changing text/blocks and reply_broadcast in the same edit - send a broadcast edit with content unchanged, then edit content separately. Every edit requires text or blocks: metadata-only edits must resend the existing text.
Delete a message from Slack
Get a permanent link to a message
Get message history from a channel by Channel ID. Filter by Unix timestamps (oldest='1640995200.123456', latest=...) or convenience params (daysago, hoursago, startdate, enddate). inclusive=True includes boundary messages. includeallmetadata=true adds each message's eventtype/eventpayload metadata (off by default).
Schedule a message to be sent later
Delete a scheduled message
Add an emoji reaction to a message
Read the emoji reactions on a message: which emoji, how many people used each, and the user IDs who did. Names come back canonicalised, so a reaction added as 'thumbsup' reads back as '+1'; match on the returned name, not the one you sent. Use listchannels for the channel ID and getconversationhistory for the message timestamp. addreaction and remove_reaction are the write counterparts.
Remove an emoji reaction from a message
Get all replies in a Slack thread. MUST be called whenever a message has replycount > 0 (from getconversationhistory, searchmessages, etc.) to get full context. Set includeallmetadata=true to include each message's eventtype/eventpayload metadata (off by default). When presenting results, show username/displayname instead of userid.
Get all unread direct messages and group DMs with their message content. When presenting results to users, always display username/displayname instead of userid for better readability.
Get all unread messages from channels with their message content. Uses smart prioritization to check most recently active channels first. When presenting results to users, always display username/displayname instead of userid for better readability.
List scheduled messages that haven't been sent yet
Get all unread messages from a specific channel. Uses the channel's lastread timestamp to accurately identify unread messages. When presenting results to users, always display username/displayname instead of user_id for better readability.
Get all unread direct messages from a specific user. When presenting results to users, always display username/displayname instead of userid for better readability.
Send a message to a person or channel by name instead of ID. Resolves display name, real name, username, email, or channel name and sends the message. With org-wide tokens spanning multiple workspaces, optionally pass team_id to scope the lookup. If you already have a Slack user/channel ID, pass it as name to skip the search.
List all pinned messages and items in a channel
Pin a message to a channel
Remove a pinned message from a channel
Search Slack semantically, built for agents. Prefer over searchmessages for natural-language questions. Searches public channels ONLY unless channeltypes names privatechannel/im/mpim. Cannot be scoped to one channel: use searchmessages with in:#channel. Also searches files and channels via content_types. before/after are Unix seconds. Max 20 per page; paginate with cursor.
Search Slack messages using Slack's exact search syntax. For time windows use date modifiers (after:YYYY-MM-DD, before:YYYY-MM-DD) or the convenience params (daysago, hoursago, startdate, enddate). With from:@username, never guess a username - call list_users first for the exact one. Paginated.
Search for files across Slack using keywords with enhanced timestamp handling and automatic pagination. Supports channel filtering, file type filtering, and efficient date-based searches. IMPORTANT: When using from:@username, NEVER guess usernames - use list_users tool first to find the exact username/display name.
Get complete user information including workspace role, permissions, and profile
Resolve the authenticated user ('me'/'myself') to their Slack user ID and profile. Call this first whenever a request refers to the current user (e.g. 'send me a DM', 'message myself') to get the user_id to open a DM or post to.
List users in the workspace. Returns a lean set of fields by default (id, name, realname, displayname, email, isbot, deleted); request more via the 'fields' parameter. Paginate with cursor/pageinfo. Use lookupuserbyemail or searchusers to find a specific person. For multi-workspace org-wide tokens, pass team_id (omitting it returns an error listing workspace IDs).
Resolve an email address to a Slack user, returning their ID and profile. Use this when you have an address; use list_users to browse or search by name. The address must match the one on the account exactly.
Check whether a user is active or away. Use listusers or lookupuserbyemail to find user IDs. Querying yourself returns the extra connection and last-activity detail.
Set your own presence status (auto or away)
Turn on Do Not Disturb for your own account for a number of minutes from now. Calling this again replaces the current snooze rather than extending it. This is separate from setuserpresence, which only controls the away indicator and does not silence notifications.
Set profile information for a user
Get conversations a user is a member of. For org-wide tokens spanning multiple workspaces, pass team_id; if omitted, the error lists the available workspace IDs to choose from.
Set your status text and emoji. statustext is required: pass an empty string to clear it. For statusemoji, an empty string clears it and null leaves the current emoji untouched.
Clear the status for a user
List the workspace's user groups (mentionable @handles, also called subteams). Returns each group's ID, name, handle, description, default channels and member count. Use this to find the usergroupid every other user group tool needs. Set includeusers=true to get member IDs inline. Slack returns all groups at once, so there is no pagination.
Create a user group (a mentionable @handle). Name and handle must both be unique in the workspace; Slack returns namealreadyexists or handlealreadyexists otherwise, so call listusergroups first to check. The optional channels list sets the default channels new members are added to; use listchannels to find channel IDs. Add members afterwards with setusergroupusers.
Update a user group's name, handle, description, or default channels. Use listusergroups for the usergroupid and listchannels for channel IDs. Only the fields you pass change. channels replaces the default-channel list applied to future members; it does not add current members to those channels. For that use inviteusergrouptochannel. To change membership use setusergroupusers.
Re-enable a disabled user group so it can be mentioned again. Use listusergroups with includedisabled=true to find disabled groups and their IDs.
Disable a user group so it can no longer be mentioned. Slack has no delete for user groups, so this is how a group is retired; its membership is preserved and enableusergroup restores it. Use listusergroups to find the usergroup_id.
List the member user IDs of one user group. Use listusergroups to find the usergroupid, and getuserinfo or listusers to turn the returned IDs into names. Read the current members with this before calling setusergroup_users, which replaces the whole list. Slack returns all members at once, so there is no pagination.
Replace a user group's entire membership with the given user IDs. This is an absolute set, not an add: anyone not in userids is removed. To add or remove a few people, call listusergroupusers first and pass the modified full list. Slack rejects an empty list, so use disableusergroup to retire a group. Use listusergroups for the usergroupid and lookupuserby_email for user IDs.
Invite every current member of a user group to a channel. Slack has no single API for this, so the tool expands the group's membership, skips anyone already in the channel, and invites the rest. Use listusergroups for the usergroupid and listchannels for the channelid. This adds people now; to set the channels future members join automatically, use update_usergroup instead.
Validate Slack credentials. Verifies credentials during setup.
Mark a channel as read up to a given message, clearing its unread badge for the authenticated user. Pass the timestamp of the newest message you have processed; get it from getconversationhistory or the unread tools. Use listchannels to find the channelid.
Open a direct message conversation with one user, or a group DM with several, and return the conversation ID to pass to postmessage. Safe to call repeatedly; Slack returns the existing conversation if one is already open. Use lookupuserbyemail or list_users to find user IDs.
Post a message only one user can see in a channel, leaving no trace for anyone else. Useful for a private nudge or confirmation without adding channel noise. Delivery is not guaranteed: the user must be active in Slack and a member of the channel. Use listchannels for the channelid and lookupuserbyemail for the userid.
Get the authenticated user's Slack workspace: its ID, name, slug and email domain. Use this when you need the workspace ID (teamid) that listchannels, list_users and the user group tools accept for org-wide tokens.
Get a user's full Slack profile including title, phone, timezone, status and any workspace custom fields. Richer than getuserinfo, which returns only core account fields. Omit userid for the authenticated user. Use lookupuserbyemail or list_users to find IDs.

In an mcp.json file, add the configuration below, and restart Cursor.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "url": "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
5 "headers": {
6 "Authorization": "Bearer yMt*****"
7 }
8 }
9 }
10}
11Open your Claude Desktop configuration file and add the server configuration below. You'll also need to restart the application for the changes to take effect.
Make sure Claude is using the Node v20+.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "yMt*****"
14 }
15 }
16 }
17}Open your Windsurf MCP configuration file and add the server configuration below.
Click on the refresh button in the top right of the Manage MCP server page or in the top right of the chat box in the box icon.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api.merge.dev/api/v1/tool-packs/<tool-pack-id>/registered-users/<registered-user-id>/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "<ah-production-access-key>"
14 }
15 }
16 }
17 }In Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows), run "MCP: Open User Configuration".
You can then add the configuration below and press "start" right under servers. Enter the auth token when prompted.
Learn more in the official documentation ↗
1{
2 "inputs": [
3 {
4 "type": "promptString",
5 "id": "agent-handler-auth",
6 "description": "Agent Handler AUTH_TOKEN", // "yMt*****" when prompt
7 "password": true
8 }
9 ],
10 "servers": {
11 "agent-handler": {
12 "type": "stdio",
13 "command": "npx",
14 "args": [
15 "-y",
16 "mcp-remote@latest",
17 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
18 "--header",
19 "Authorization: Bearer ${input:agent-handler-auth}"
20 ]
21 }
22 }
23}The Slack MCP server allows AI agents to search channels and files, send and read messages, fetch user profiles, and much more.
To use Slack with Merge Agent Handler, you'd use Agent Handler’s standard flow:
Merge Agent Handler provides built-in authentication flows, user onboarding, and dynamic authorization handling so Slack credentials are managed securely and consistently.
The Security Gateway actively scans Slack tool inputs and outputs for sensitive information and can block, redact, or mask data. This protects against data misuse across Slack interactions.
Agent Handler logs every tool call and underlying Slack API request. These server Logs are fully searchable, allowing you to easily debug, audit, and optimize your agentic workflows with Slack.
Merge Agent Handler’s Slack MCP server already includes 50+ tools. But you can modify existing ones and add any with ease.
Merge handles all Slack credential workflows—including onboarding prompts, dynamic authorization flows, and individual vs. shared authentication configuration—through Merge Agent Handler and built-in auth logic.
For each connector in a Tool Pack, you can determine whether Slack requires individual authentication or can use shared authentication.
Yes. Agent Handler supports:
For example, you can set rules that block post_message calls that contain credit card numbers before they're sent to Slack channels; redact social security numbers from search_messages responses; and log any get_user_profile calls that access employee phone numbers.
Yes, Agent Handler for Employees lets your employees connect Claude, ChatGPT, Microsoft Copilot, Cursor, and other MCP-compatible AI tools to Slack without bypassing IT governance.
Instead of setting up direct connections with personal credentials that IT can't monitor or revoke, each employee authenticates through Agent Handler and gets individual credentials tied to their identity.
IT also provisions access by role or group via SCIM. A sales rep, for example, gets Slack access to coordinate deals, Salesforce to track pipeline, and Gong to review call recordings; while an engineer gets Slack access to collaborate with the team, GitLab to manage code and issues, and Datadog to monitor service health.
Every tool call an employee's AI makes to Slack is also inspected against your DLP rules and logged to a searchable audit trail, giving security teams full visibility into what data was accessed and by whom.
Whether you're an engineer experimenting with agents or a product manager looking to add tools, you can get started for free now