fix: force OAuth flow when server accepts unauthenticated connections#26236
fix: force OAuth flow when server accepts unauthenticated connections#26236Sanjay-doppalapudi wants to merge 1 commit into
Conversation
Some MCP servers (like Google Drive) accept the initial connection without authentication but enforce it at the tool-call level. OpenCode would skip the OAuth flow entirely and report 'Authentication successful!' without obtaining any tokens, leaving the server unusable. When startAuth() detects that the server accepted the connection without requiring OAuth but the user has configured OAuth credentials and no tokens exist, we now force the OAuth discovery/redirect flow via the SDK's auth() function. As a safety net, authenticate() also checks whether tokens were actually obtained before reporting success when OAuth was configured.
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
|
Hey @Sanjay-doppalapudi — nice work on this, we hit the exact same issue with Google's MCP servers and independently filed #26912 to fix it. Our PRs overlap on the core problem: However, there's a second problem that affects Google specifically: after forcing Our PR (#26912) addresses both:
Happy to collaborate on this — we could merge the approaches, or I could rebase our discovery piece on top of yours if the maintainers prefer that structure. Let me know what makes sense. |
|
Hey @yanniznik,
|
Issue for this PR
Closes #26195
Type of change
What does this PR do?
The Google Drive MCP server (
drivemcp.googleapis.com) accepts the initialinitializerequest with HTTP 200 even without authentication. The MCP SDK only triggers OAuth when it sees a 401 response, so OpenCode would connect successfully, print "Authentication successful!", and save an empty token entry ({"gdrive": {}}). Actual tool calls would then fail with "Unauthorized" because the server enforces auth at the operation level.Two changes in
packages/opencode/src/mcp/index.ts:Forced OAuth in
startAuth(): Whenclient.connect()succeeds without throwingUnauthorizedError, but the user configured OAuth credentials and no tokens exist, we call the SDK'sauth()function directly to force the OAuth discovery/redirect flow. This produces an authorization URL so the browser flow proceeds.Safety net in
authenticate(): If the "already connected" path is taken but OAuth was configured and no tokens were saved, returns{ status: "failed" }instead of falsely reporting success.How did you verify your code works?
bun typecheckpasses inpackages/opencodebun test test/mcp/)oauth-auto-connect.test.ts:startAuth()returns an authorization URL when the server accepts unauthenticated connections but OAuth is configuredauthenticate()succeeds when tokens already exist (legitimate no-redirect path)oauth-browser.test.tsto exportauthfrom the SDK mock (imported by source now)Screenshots / recordings
N/A — no UI changes.
Checklist