All posts
MCP education··7 min read

Slack's MCP server is live. Your users still can't connect their own workspace.

A customer asked whether their end users could connect their own Slack through our widget. The Slack MCP server is well built and its user-token model is exactly right for per-visitor tools. But there is no dynamic client registration, and Slack permits MCP access only to Marketplace-listed apps and internal apps, which rules out the bring-your-own-app pattern every embedded assistant relies on. Here is what I measured against Slack's live endpoints, and why we shipped no Slack tile.

Orhan
Founder

A customer asked me a reasonable question. Their end users live inside their product all day. Could those users connect their own Slack workspace to the assistant, so they could say "post this release note to my #product channel" and have it happen?

I spent a day on it and the answer is no. Not because of anything in our stack. Slack's MCP server is real, it is well built, and its token model is exactly the one you want for per-user tools. A distribution rule sitting on top of it makes the end-user case impossible for anyone who is not already listed in the Slack Marketplace. Here is everything I measured, re-checked live on 15 September 2026 before publishing this.

The server is real and it behaves correctly

https://mcp.slack.com/mcp speaks JSON-RPC 2.0 over Streamable HTTP. An unauthenticated initialize gets back a textbook MCP-spec 401, with the resource metadata pointer the spec asks for:

http
HTTP/2 401
www-authenticate: Bearer resource_metadata="https://mcp.slack.com/.well-known/oauth-protected-resource"

{"jsonrpc":"2.0","id":null,"error":{"code":-32001,"message":"missing_token"}}

That is more than most production MCP servers get right. Nothing about the transport layer is the problem here.

The token model is the one you want

Read the authorization server metadata and the interesting field is the authorize endpoint:

json
{
  "issuer": "https://mcp.slack.com",
  "authorization_endpoint": "https://slack.com/oauth/v2_user/authorize",
  "token_endpoint": "https://slack.com/api/oauth.v2.user.access",
  "grant_types_supported": ["authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:jwt-bearer"],
  "code_challenge_methods_supported": ["S256"]
}

v2_user, not the bot install flow. Slack MCP runs on user tokens. The token belongs to the person who clicked approve, and it can see exactly the channels that person can see. No shared service account, no over-broad bot that reads every private channel in the workspace. The metadata lists 30 scopes, covering messages, channels, search, canvases, files and lists, and PKCE with S256 is supported.

For a widget that runs inside someone else's product and acts on behalf of whoever is looking at the screen, that design is close to ideal. Which is why the next two sections were so annoying to write.

There is no registration endpoint

Our connect flow prefers dynamic client registration. If a provider advertises a registration_endpoint and a real POST to it succeeds, nobody has to create an app: the user clicks Connect, approves, done. That is how Linear, Notion and Atlassian work for our end users today.

Slack publishes no such endpoint. Two checks, both run today:

  • oauth-authorization-server and openid-configuration both omit registration_endpoint entirely.
  • POST https://mcp.slack.com/register answers 302, a redirect into the Slack web app. There is no registration API behind it.

Slack's MCP documentation confirms it rather than leaving you to discover it, and also says MCP clients must be backed by a registered Slack app with a hardcoded, fixed app ID. So zero-setup connect is off the table by design. Fine. Plenty of providers need you to create an app first. You create one, you ship a setup step, you move on.

The real blocker is who is allowed to distribute that app

Slack's MCP page states that only apps published in the Slack Marketplace and internal apps may use MCP, and that "unlisted apps are prohibited from using MCP" (docs.slack.dev).

"Internal" means installed in the developer's own workspace and nowhere else. "Published in the Slack Marketplace" means it passed Slack Marketplace review. There is no third category for an app that installs into arbitrary customer workspaces without review.

Now line that up against the pattern every embedded-assistant vendor uses for connectors that have no dynamic registration: the customer creates their own app, pastes a Client ID and Secret, and their users connect through it. For Slack that is a distributed unlisted app, which is the case the rule forbids. The OAuth dance still completes and the token still comes back. The rejection happens later, at mcp.slack.com, with no explanation your support team can act on.

The four clients Slack lists as already working are Claude.ai, Claude Code, Perplexity and Cursor. All four are Marketplace-listed partner apps. The rule is enforced, not aspirational.

Slack's general distribution docs disagree, and they are not the ones that apply

Slack's general distribution documentation says public distribution needs no review and takes effect immediately, and that Marketplace submission is only for commercial listings. That contradicts the MCP page. The MCP page is more specific, more recent, states the restriction twice, and describes the system that actually rejects your token. Go with the MCP page.

Why we shipped nothing instead of a tile that looks fine

Our end-user connector catalog resolves each provider to one of three enable modes, in precedence order: automatic registration, then a Command+K-owned shared OAuth app, then the customer's own credentials. For Slack the first is impossible, and the second would require a Command+K Slack app that has passed Marketplace review, which does not exist. So the resolver lands on the third mode, the one Slack prohibits.

A Slack tile shipped on that basis renders as a working tile whose recommended path is the forbidden one. An owner would create a Slack app, wire the callback, watch their visitors approve it, and then field complaints about an assistant that cannot reach Slack. That is worse than an absent tile, so there is no Slack tile in our end-user marketplace. The assistant-level Slack connector still exists, because a team connecting its own workspace is the internal-app case and that is allowed.

One implementation detail worth stealing if you do build against Slack. Slack returns failures with HTTP 200 and {"ok": false, "error": "..."} in the body. Standard OAuth client code checks the status, finds 200, looks for access_token, does not find it, and reports something useless. Read the envelope and surface Slack's own error string.

The check to run before you promise a connector

Reading a provider's OAuth metadata tells you what it claims. It does not tell you what will happen. We learned the same lesson from ten marketplace servers whose advertised dynamic registration did not work. Slack is the inverse case: the metadata is honest, the server is honest, and the blocker is in a prose paragraph on a docs page that no discovery document will ever hand you.

Two questions, not one

Before you put a provider on a roadmap, answer both. Can a client register and get a token without human setup? And is your specific distribution shape, one app installed into many customer workspaces, something the provider's terms actually permit? The second question lives in the terms, not in the protocol, and it is the one that kills features after they are built.

If you want the connectors that do work per end user without anyone creating an app, the end-user OAuth documentation lists which providers we verified with a live registration call and which ones need an app first.

FAQ

Does the Slack MCP server support dynamic client registration?
No. Its authorization server metadata at mcp.slack.com/.well-known/oauth-authorization-server has no registration_endpoint, and a POST to /register returns a 302 redirect into the Slack web app rather than a registration API. Slack's own MCP documentation states it plainly. Every MCP client has to be backed by a Slack app you created by hand, with a fixed app ID.
Can my customers connect their own Slack workspace through my product?
Only if your Slack app is published in the Slack Marketplace. Slack restricts MCP access to Marketplace-listed apps and internal apps, where internal means installed in your own workspace only. An unlisted app distributed to customer workspaces is the exact case Slack prohibits, so it will fail at mcp.slack.com even though the OAuth flow itself completes.
Does the Slack MCP server use bot tokens or user tokens?
User tokens. The authorize endpoint is slack.com/oauth/v2_user/authorize and the token endpoint is slack.com/api/oauth.v2.user.access, so the token belongs to the person who approved it and sees only what that person can see in Slack. For a per-visitor assistant that is the right model, which is what makes the distribution rule so frustrating.
Why did my Slack token exchange fail without an error message?
Slack returns failures as HTTP 200 with an ok:false body. Generic OAuth code that checks the status code and then reads access_token will report a missing token instead of Slack's actual reason. Parse the envelope and surface the error field.

Keep reading

Go deeper