Skip to content

fix: force OAuth flow when server accepts unauthenticated connections#26236

Open
Sanjay-doppalapudi wants to merge 1 commit into
anomalyco:devfrom
Sanjay-doppalapudi:fix/mcp-oauth-false-success
Open

fix: force OAuth flow when server accepts unauthenticated connections#26236
Sanjay-doppalapudi wants to merge 1 commit into
anomalyco:devfrom
Sanjay-doppalapudi:fix/mcp-oauth-false-success

Conversation

@Sanjay-doppalapudi
Copy link
Copy Markdown

@Sanjay-doppalapudi Sanjay-doppalapudi commented May 7, 2026

Issue for this PR

Closes #26195

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

The Google Drive MCP server (drivemcp.googleapis.com) accepts the initial initialize request 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:

  1. Forced OAuth in startAuth(): When client.connect() succeeds without throwing UnauthorizedError, but the user configured OAuth credentials and no tokens exist, we call the SDK's auth() function directly to force the OAuth discovery/redirect flow. This produces an authorization URL so the browser flow proceeds.

  2. 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 typecheck passes in packages/opencode
  • All 35 MCP tests pass (bun test test/mcp/)
  • Added two new tests in oauth-auto-connect.test.ts:
    • Verifies startAuth() returns an authorization URL when the server accepts unauthenticated connections but OAuth is configured
    • Verifies authenticate() succeeds when tokens already exist (legitimate no-redirect path)
  • Updated mock in oauth-browser.test.ts to export auth from the SDK mock (imported by source now)

Screenshots / recordings

N/A — no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

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.
@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels May 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@yanniznik
Copy link
Copy Markdown

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: connect() succeeds without auth, so the SDK never triggers OAuth. Your forced auth() call in startAuth() addresses that well.

However, there's a second problem that affects Google specifically: after forcing auth(), the SDK calls discoverOAuthMetadata() which does a GET /.well-known/oauth-authorization-server against the MCP server URL (e.g. googleapis.com). Google doesn't implement RFC 8414 discovery, so that fetch fails and the OAuth flow still doesn't complete.

Our PR (#26912) addresses both:

  1. The same auth-trigger fix (forcing auth() when no tokens exist)
  2. A discoveryState() / saveDiscoveryState() implementation on McpOAuthProvider that lets users specify authorizationEndpoint and tokenEndpoint in config — the SDK checks discoveryState() before attempting .well-known discovery, so it skips the failing fetch entirely

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.

@Sanjay-doppalapudi
Copy link
Copy Markdown
Author

Hey @yanniznik,
Good catch on the RFC 8414 discovery issue ,I hadn't hit that in testing since the Google Drive server I was working with was failing earlier in the flow.
Your approach of implementing discoveryState() / saveDiscoveryState() on McpOAuthProvider with configurable authorizationEndpoint and tokenEndpoint seems like the right way to handle servers that don't support .well-known discovery. The SDK checks discoveryState() first, so if we save the endpoints there, it skips the failing fetch.
I think the cleanest path is:

  1. Merge this PR (fix: force OAuth flow when server accepts unauthenticated connections #26236) - it handles the core fix (forcing the OAuth trigger when the server silently accepts unauthenticated connections)
  2. You rebase your discovery piece on top of it - that way you get the forced auth() call for free and just need the discoveryState/config plumbing
    The two changes touch different parts of the codebase (mine is in startAuth/authenticate, yours is in the McpOAuthProvider and config schema), so they compose cleanly without conflicts.
    If the maintainers prefer a single combined PR instead, I'm happy to either pull your discovery changes into this one or close mine in favor of yours. Whatever's easiest for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

opencode mcp auth fails to open browser for OAuth flow (Google Drive MCP)

2 participants