slack-cdp
Integrates with Slack as the signed-in user through the desktop app's session, enabling AI agents to list workspaces and conversations, retrieve channel and thread history, search messages, send replies, upload files, add reactions, manage status, and listen to new Slack events.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@slack-cdpsend a message to #general saying deploy done :rocket:"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
slack-cdp
Script Slack as yourself, through the desktop app's own session. No Slack app, no bot token, no OAuth: slack-cdp attaches to the Slack desktop app over the Chrome DevTools Protocol, makes Web API calls inside the app's page with the page's session, and listens to the events the page receives on its own websocket.
Comes as a library (with TypeScript types), a CLI, and an MCP server for AI agents. Node 22+, no dependencies.
While Slack's DevTools port is open, any process on your machine can take over your
Slack session. The port binds to 127.0.0.1, which only keeps out other machines. Open
it only while you need it. With launch: true / --launch, slack-cdp restarts Slack
without the port when it's done.
Unofficial: it relies on Slack internals that can change without notice (run
slack-cdp doctor when something breaks), and everything it does, it does as you. Check
your workspace's rules before automating your account.
Install
npm install github:kinduff/slack-cdpRelated MCP server: slack-user-mcp-server
Start Slack with the port
connect({ launch: true }) and --launch quit Slack and start it again with the port.
Or start it yourself:
Install | Command |
Linux flatpak |
|
Linux deb/rpm/snap |
|
macOS |
|
Windows |
|
Quit Slack fully first: if it's already running, the new launch just focuses it. Only the flatpak launcher has been tested; the Microsoft Store build of Slack isn't supported.
Then check the chain:
npx slack-cdp doctorok app: found Slack flatpak
ok port: 127.0.0.1:9222 answers (Chrome/138.0.7204.251)
ok page: https://app.slack.com/client/T029JKK3Y/D08CLGLHL0J
ok session: 2 workspaces: Acme, Side Project
ok api params: every workspace has API params to copy
ok auth Acme: signed in as kinduff (U08CHMKQ9NZ)Library
import { connect } from "slack-cdp";
const slack = await connect({ launch: true });
for await (const m of slack.messages()) {
if (m.self || m.bot) continue;
if (m.text.startsWith("!ping")) await slack.reply(m, "pong");
}await slack.postMessage("#general", "deploy done :rocket:", { team: "acme" });
await slack.postMessage("@max", "lunch?");
await slack.upload("#releases", { path: "./changelog.md", comment: "v2 notes" });
const hits = await slack.search("from:@max in:#general deploy");
const thread = await slack.history("#general", { threadTs: "1792699294.295379" });
const body = await slack.api("emoji.list"); // any Web API methodMore in docs/recipes.md and examples/.
Workspaces
Every call takes { team }: a workspace ID or a name prefix ("acme"). Without it, calls
go to the workspace active in the app, which changes when you click another workspace.
Events arrive from every workspace, each with its team, so answer with slack.reply(m, …)
or pass { team: m.team }.
Channels
Methods that take a channel accept an ID (C…, G…, D…), #name or name for a
conversation you're in, or @person or a user ID for their DM, opened if needed.
API
Call | Returns |
| A |
| Any Web API method's response body. Objects in |
| Async iterator over every item of a cursor-paginated method |
| The |
| The |
| Edits or deletes your message |
| Adds a reaction |
|
|
| DM or group DM channel ID |
| Messages, newest first; a thread's replies with |
|
|
| Every conversation you're in |
|
|
| Lookup or |
| Display name / |
| A channel ID from any channel reference |
| Signed-in workspaces / your user IDs / whether an ID is you |
| Your status |
| Async iterators of new events until |
| Runs JS in the Slack page |
| Detaches; |
Events (slack.on(…)):
Event | Payload |
|
|
|
|
|
|
|
|
| Every raw websocket event: typing, presence, channel joins, … |
| Connection state; reconnects follow a |
You get events for the conversations you're in, as the app does. text is Slack markup;
plainText(text, idToName) renders mentions, channel links and URLs readably, and
mentions(text) lists the user IDs to look up first.
Also exported: doctor(), detectApp(), restartSlack(), serveMcp(), and the pure
event parsers. Types are in index.d.ts.
CLI
slack-cdp doctor
slack-cdp tail --org acme --channel general --mentions
slack-cdp send '#general' 'hello'
echo 'from stdin' | slack-cdp send @max
slack-cdp history '#general' -n 50
slack-cdp search 'from:@max deploy'
slack-cdp api emoji.list --org acme
slack-cdp tail --json | jq .textslack-cdp --help lists everything. Add --launch to open the port if it isn't open.
MCP server
slack-cdp mcp serves Slack to AI agents over stdio, with tools for workspaces,
conversations, history, search, send, react, and an inbox of new messages. For Claude
Code, in .mcp.json:
{ "mcpServers": { "slack": { "command": "npx", "args": ["slack-cdp", "mcp", "--launch"] } } }The agent posts as you. Give it to agents you'd hand your Slack account to.
How it works
CDP
Runtime.evaluateon theapp.slack.compage target. The page'slocalStorage.localConfig_v2holds each signed-in workspace's token and URL.The API accepts the page's credentialed requests only with the app's own
_x_*query params, so they're copied from the page's most recent/api/call. Right after Slack starts there is none yet; calls wait up to 30 s for one (no_template_call).The token never crosses CDP: it's read and sent inside the page. Responses do come back.
CDP
Network.enableplusNetwork.webSocketFrameReceivedtaps the page's websocket, whose frames are Slack's RTM-style JSON events.
Development
npm testTests run against a fake DevTools port (test/fake-slack.js) that evaluates the real page
expressions in a sandbox, so they need no Slack. See AGENTS.md before changing
things.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted Slack MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Catch up on Slack without reading it. Unreads, threads, search. Browser-session or hosted OAuth.
Enable interaction with Slack workspaces. Supports subscribing to Slack events through Resources.
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI assistants to interact with Slack workspaces, including listing channels, posting messages, replying to threads, adding reactions, and retrieving user information.1012 npmMIT
- FlicenseAqualityDmaintenanceEnables AI agents to interact with Slack using a user token, providing full access to message search, channel history, DMs, and posting as the user.8-
- AlicenseBqualityCmaintenanceEnables AI assistants to interact with Slack workspaces, providing tools for reading messages, posting content, managing channels, and more.2243MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants like Cursor and Claude Desktop to interact with Slack workspaces, allowing message sending, channel reading, user management, and file operations through natural language.MIT