Cursor's Agent mode puts Slack MCP tools right next to the code you're editing, which changes the shape of what's worth automating: instead of "post a build notification," the compelling use cases are "tell the team what this diff does" and "pull the bug report thread that prompted this fix into context." This topic covers connecting the server, sharing code/PR context to Slack, pulling bug threads into fixes, and Cursor's specific rough edges with MCP tool calls.
Connecting Slack MCP to Cursor Agent Mode
Cursor reads MCP servers from .cursor/mcp.json (project-scoped) or ~/.cursor/mcp.json (global). Project scope is the right default for a team-shared Slack integration since it lets everyone on the repo use the same channel routing without redoing setup:
{
"mcpServers": {
"slack": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": {
"SLACK_BOT_TOKEN": "${env:SLACK_BOT_TOKEN}",
"SLACK_TEAM_ID": "${env:SLACK_TEAM_ID}",
"SLACK_CHANNEL_IDS": "${env:SLACK_CHANNEL_IDS}"
}
}
}
}
Enable it in Cursor Settings → Features → MCP, where each configured server shows a green dot when its subprocess is up and a tool count. Cursor lists the individual tools (slack_post_message, slack_get_channel_history, etc.) with toggle switches — you can disable specific tools per-server here, which is worth doing immediately for anything you don't want Agent mode reaching for, like reactions:write if your workflow never needs emoji reactions.
Because .cursor/mcp.json is typically committed for team-shared configs, never put a literal token in it — the ${env:VAR} interpolation keeps the file safe, but only if every teammate actually has SLACK_BOT_TOKEN exported locally, which is worth documenting in your repo's README rather than assuming:
SLACK_BOT_TOKEN=xoxb-your-token-here
SLACK_TEAM_ID=T0123456
SLACK_CHANNEL_IDS=C0123ABCXYZ
In Agent mode, invoke Slack tools by asking naturally — Cursor's agent decides when a Slack tool is relevant to the request, same as it decides when to open a file or run a terminal command. You'll see the tool call rendered inline in the chat panel with an Run tool / accept-reject affordance before it executes, assuming you haven't pre-approved that tool globally.
Summarize what this diff does in 2 sentences and post it to #eng-updates
as an FYI, tagging @sre-team if it touches anything in /infra.
Tips
- Disable individual Slack tools you don't need (likereactions:write) in Cursor's MCP settings panel rather than leaving the full toolset enabled by default.
- Document required env vars in a committed.env.examplewhen.cursor/mcp.jsonis team-shared — interpolation only works if every teammate has actually set the variable.
- Watch for the inline accept/reject affordance on each tool call; don't pre-approveslack_post_messageglobally until you trust the specific workflow generating the draft.
Sharing Code Context and PR Status to Slack from Cursor
The workflow that actually justifies having Slack MCP inside the IDE (rather than just using the terminal) is posting updates that reference live code context Cursor already has open — a diff, a specific function, a PR description you're mid-edit on.
I just finished the refactor in src/payments/retry.ts. Post to
#payments-team a short update: what changed (idempotency key now
persisted before the retry loop starts, not after), why (we were
double-charging on retry after a timeout), and link to the PR
(use the URL from the current git remote + branch).
A realistic resulting message, using a Block Kit layout suited to a technical audience that will want to click through:
{
"channel": "C0912PAYTEAM",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Fixed:* double-charge on payment retry after timeout\n*Root cause:* idempotency key was persisted *after* the retry loop, not before\n*Fix:* key now persisted first — retries are safe even if the process crashes mid-loop"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "Review PR #482" },
"url": "https://github.com/org/repo/pull/482"
}
]
}
]
}
For PR status updates specifically (opened, review requested, merged), the value is in triggering the post from the same context where you're already looking at the PR, without alt-tabbing to Slack and re-explaining what changed from memory — you write the technical summary once, Cursor drafts the Slack-appropriate version from it.
A pattern worth adopting: ask Cursor to draft the message and the PR description from the same prompt, so they stay consistent instead of writing two independent explanations of the same change that quietly diverge:
Write the PR description for this branch (summary, testing done,
risk level) and also draft a shorter Slack version for #eng-updates
that links to the PR once it's created. Show me both before I open
the PR or post anything.
Tips
- Draft the PR description and the Slack summary from the same prompt so they stay consistent instead of independently drifting.
- Use Slack MCP from Cursor specifically for updates that reference live code context already open in the editor — that's the actual advantage over a terminal-based CLI here.
- Keep code-context Slack posts scoped to the team channel that owns the affected code, not a broad channel — the audience for "idempotency key fix in retry.ts" is narrow by nature.
Pulling Bug Reports from Slack Threads into Code Fixes
The reverse workflow — starting from a Slack thread and ending at code — is just as valuable and less commonly set up. A user or support person reports a bug in a thread; instead of manually re-transcribing the repro steps into a ticket or a code comment, pull the thread directly into your editing context.
Fetch the thread at channel C0345SUPPORT, ts 1700050000.000200 using
slack_get_thread_replies. Extract the repro steps and any error message
or stack trace mentioned. Then look at src/api/checkout.ts and tell me
if you can identify the bug from the repro steps.
This works well when the thread contains concrete technical detail (an error message, a request payload, a screenshot description someone typed out) and works poorly when the thread is mostly back-and-forth clarification with the actual bug detail buried three replies deep — which is most real support threads. Be explicit about wanting the synthesized repro, not a raw transcript dump, so Cursor does the work of separating signal from the "can you try again?" / "still broken" back-and-forth:
Don't paste the raw thread. Synthesize: what does the user actually
do, what do they expect, what happens instead. If the thread doesn't
have enough detail to reproduce, tell me exactly what's missing
instead of guessing.
That last instruction — telling the model to admit insufficient detail rather than guess — is worth keeping as a standing rule for this workflow specifically. A confidently wrong guess at repro steps, chased down as if it were confirmed, wastes far more time than an honest "the thread doesn't specify which browser this happened in."
Once you've identified and fixed the bug, close the loop by posting back to the original thread rather than leaving the reporter wondering if anyone saw it:
Post to the same thread (channel C0345SUPPORT, thread_ts 1700050000.000200):
"Found it — the checkout total wasn't recalculating after a coupon
was removed. Fixed in PR #491, will be in tomorrow's deploy."
Tips
- Ask for synthesized repro steps, not a raw thread dump — real support threads bury the actual technical detail inside several rounds of clarification.
- Instruct the model to explicitly flag missing repro detail rather than guess; a confident wrong guess costs more debugging time than an honest gap.
- Close the loop by replying in the original thread once fixed — it's a small habit that meaningfully improves trust between engineering and whoever reported the issue.
Known Limitations and Workarounds for Slack MCP in Cursor
No persistent cross-session channel memory. Cursor doesn't remember "we always post payments updates to C0912PAYTEAM" across sessions unless you write it down. Put channel-routing conventions in .cursor/rules or a project AGENTS.md-equivalent so the agent doesn't have to be told the channel ID fresh every time:
## Slack channel routing
- Payments team updates -> #payments-team (C0912PAYTEAM)
- Support/bug threads -> #support (C0345SUPPORT)
- Deploy notifications -> #deploys (C0123ABCXYZ)
- Never post to #general or #random without explicit instruction
Tool call context window cost. Fetching a large channel history or long thread consumes context the same as reading a large file would — on a long Cursor session already holding several open files and a big diff, a 100-message thread fetch can meaningfully crowd out other context. For heavy Slack reads, consider a fresh Agent conversation rather than appending to a long-running coding session.
No native scheduling or webhooks. Same limitation as OpenCode — Cursor has no built-in mechanism to trigger a Slack post on an external event (a webhook, a cron tick) without you being in an active session asking for it. Recurring or event-triggered Slack automation belongs in a separate CI/cron process, not inside interactive Cursor sessions.
Ambiguous channel resolution without SLACK_CHANNEL_IDS. Same risk as every other client covered in this module — if the bot token has broad access and you haven't set the allowlist, asking to "post an update" with no channel specified leaves Cursor guessing, and it will sometimes guess based on whichever channel name appeared most recently in the conversation rather than the channel that's actually appropriate. Always name the channel explicitly, or set the allowlist tight enough that there's only one sane option.
Tips
- Write channel-routing conventions into a committed rules file so the agent doesn't guess a channel from conversational recency.
- Start a fresh Agent conversation for heavy Slack history/thread reads rather than appending them to a long coding session already holding significant file context.
- Don't rely on Cursor for scheduled or event-triggered Slack automation — route those through an external CI/cron process instead.
Tips
Tips
- Commit.cursor/mcp.jsonwith${env:VAR}interpolation and document required env vars in.env.exampleso team-shared config doesn't silently fail for teammates who haven't set the token.
- Use Slack MCP from Cursor specifically for workflows that benefit from live code context — sharing diff summaries, pulling bug threads into a fix — rather than for generic notifications better handled by CI.
- Write standing channel-routing and tone rules into a project rules file; Cursor won't remember them across sessions otherwise, and unspecified channel targets get guessed rather than asked about.