MCP remote server OAuth authentication#51768
Conversation
3e23841 to
3f1ef87
Compare
📏 PR Size: 4173 lines changed (size/XL)Please note: this PR exceeds the 400 LOC soft limit.
|
3f1ef87 to
fd04ab0
Compare
3cc3a73 to
335405b
Compare
|
I found a bug in the browser flow where it will sometimes hang at the last redirect. @bennetbo potentially found a second one that isn't as easy to reproduce (yet). So I'm converting this PR back to draft until these are addressed. |
335405b to
f536d50
Compare
|
The bug I could easily reproduce is fixed in f536d50. I'll investigate the other one next. |
|
I can reproduce the redirects on safari with the Linear MCP server, not with the Notion MCP server. But I think it's a Linear + Safari issue rather than linked to this PR, because I see the same redirect loop when logging in through Claude Code. Let's discuss tomorrow. |
When you logged out, then logged back in, sometimes the browser would hang on the redirect to the Zed callback server if both log in attempts used the same port (common case because there is a preferred port). This happened because on the second log in flow, the editor spawned a new callback server on the same port, and the browser still has a connection pool to the old one (keep alive). To avoid this stale connection state, this commit makes the server return a Keep-Alive header with timeout=0,max=0 to disable keep alive.
f536d50 to
fd89c2d
Compare
|
Ok I think we're in a good place now. The consecutive redirects happen only with the Linear MCP with Safari, and they happen in that setup with Claude Code as well, so I don't think this is a problem on our end. I confirmed that linear, notion and cloudflare MCPs work with OAuth and DCR just fine on Firefox, Chrome and Safari (with the exception of linear + safari, but even there, it works in the end). I removed the preferred port binding. The spec says the port should not matter, so let's go with a random port always at first. That eliminates the keepalive issues with the browser hanging on to connections for which the tiny_http server doesn't exist anymore and us rebinding to the same port. Happy to pair on any of this if there are questions. |
The feature was implemented in #51768.
Closes zed-industries#43162 Implements the OAuth 2.0 Authorization Code + PKCE authentication flow for remote MCP servers using Streamable HTTP transport, as specified by the [MCP auth specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). Previously, connecting to a remote MCP server that required OAuth would silently fail with a timeout — the server's 401 response was never handled. Now, Zed detects the 401, performs OAuth discovery, and guides the user through browser-based authentication. Step-up authentication and pre-registered clients are not in scope for this PR, but will be done as follow-ups. ## Overview - **401 detection** — When the HTTP transport receives a 401 during server startup, it surfaces a typed `TransportError::AuthRequired` with parsed `WWW-Authenticate` header info. - **OAuth discovery** — Protected Resource Metadata (RFC 9728) and Authorization Server Metadata (RFC 8414) are fetched to locate the authorization and token endpoints. - **Client registration** — Zed first tries CIMD (Client ID Metadata Document) hosted at `zed.dev`. If the server doesn't support CIMD, falls back to Dynamic Client Registration (DCR). - **Browser flow** — A loopback HTTP callback server starts on a preferred fixed port (27523, listed in the CIMD), the user's browser opens to the authorization URL, and Zed waits for the callback with the authorization code. - **Token exchange & persistence** — The code is exchanged for access/refresh tokens using PKCE. The session is persisted in the system keychain so subsequent startups restore it without another browser flow. - **Automatic refresh** — The HTTP transport transparently refreshes expired tokens using the refresh token, and persists the updated session to the keychain. ## UI changes - Servers requiring auth show a warning indicator with an **"Authenticate"** button - During auth, a spinner and **"Waiting for authorization..."** message are shown - A **"Log Out"** option is available in the server settings menu for OAuth-authenticated servers - The configure server modal handles the auth flow inline when configuring a new server that needs authentication. Release Notes: - Added OAuth authentication support for remote MCP servers. Servers requiring OAuth now show an "Authenticate" button when they need you to log in. You will be redirected in your browser to the authorization server of the MCP server to go through the authorization flow. --------- Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
The feature was implemented in #51768. Release Notes: - N/A --------- Co-authored-by: Kunall Banerjee <hey@kimchiii.space>
|
@tomhoule can you check this is working with figma remote mcp (https://mcp.figma.com/mcp)? It is not working for me with errr but i cannot understand if it is my or implementation problem |
|
Hey @gohryt, it look like Figma has an allow list of clients they accept dynamic client registration from, and Zed is not in it (yet). The workaround is a preregistered client. Support will be added with that issue: #52198 (WIP, should land very soon). So as of right now I don't think there's a workaround, but soon there will be. I'll see if we can reach out to Figma to add us to the allow list, so no workaround is needed in the first place. |
|
Quick update on this: Figma apps can't be configured with the mcp scope expected by the Figma MCP server, so we'll have to get on their allowlist for Zed to work as a client to Figma MCP. |
working on this with the figma folks now |
Closes #43162
Implements the OAuth 2.0 Authorization Code + PKCE authentication flow for remote MCP servers using Streamable HTTP transport, as specified by the MCP auth specification.
Previously, connecting to a remote MCP server that required OAuth would silently fail with a timeout — the server's 401 response was never handled. Now, Zed detects the 401, performs OAuth discovery, and guides the user through browser-based authentication.
Step-up authentication and pre-registered clients are not in scope for this PR, but will be done as follow-ups.
Overview
TransportError::AuthRequiredwith parsedWWW-Authenticateheader info.zed.dev. If the server doesn't support CIMD, falls back to Dynamic Client Registration (DCR).UI changes
Release Notes: