MCP OAuth flow never triggers for servers that return 200 OK on initialize without auth (Google Drive MCP)
- Dominant language
- TypeScript
- Stars
- 156k
- Forks
- 24.6k
- Avg merge
- 22h 9m
- Merged PRs (30d)
- 610
Description
### Self Checks
- [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
- [x] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general).
- [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
- [x] I confirm that I am using English to submit this report, otherwise it will be closed.
- [x] 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
- [x] Please do not modify this template :) and fill in all the required fields.
### Dify version
1.14.1
### Cloud or Self Hosted
Self Hosted (Docker)
### Steps to reproduce
1. In Google Cloud Console, enable `drivemcp.googleapis.com` and `drive.googleapis.com`. Create OAuth 2.0 Web Application credentials. Add `http:///console/api/mcp/oauth/callback` as an Authorized redirect URI.
2. In Dify: Tools → MCP → Add MCP Server (HTTP).
3. Server URL: `https://drivemcp.googleapis.com/mcp/v1`. Disable "Use Dynamic Client Registration". Paste Client ID + Client Secret.
4. Click **Add & Authorize**.
5. Add the resulting `Google Drive` MCP to any agent.
6. In chat: ask the agent to list recent files in Google Drive.
### Backend evidence
Direct curl shows that Google's MCP server returns 200 OK on `initialize` even with a garbage Bearer (no 401 challenge — so Dify never enters its OAuth flow):
```bash
$ curl -i -X POST -H "Authorization: Bearer garbage" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' \
https://drivemcp.googleapis.com/mcp/v1
HTTP/2 200
content-type: application/json; charset=UTF-8
{"id":1,"jsonrpc":"2.0","result":{"capabilities":{...},"protocolVersion":"2025-06-18","serverInfo":{"name":"StatelessServer","version":"ESF"}}}
```
DB inspection of `tool_mcp_providers.encrypted_credentials` after the "successful" authorization (no `tokens` key, only `client_information` and `code_verifier`):
```json
{
"client_information": {
"client_id": "...",
"client_name": "Dify",
"is_dynamic_registration": false,
"encrypted_client_secret": "..."
},
"code_verifier": "..."
}
```
Backend traceback when the agent invokes a tool:
```
core.mcp.error.MCPAuthError: Authentication failed - no token received
File "/app/api/core/mcp/auth_client.py", line 109, in _handle_auth_error
core.tools.errors.ToolInvokeError: Failed to connect to MCP server: Authentication failed - no token received
File "/app/api/core/tools/mcp_tool/tool.py", line 282, in invoke_remote_mcp_tool
```
### Workarounds attempted (none worked)
- Adding a dummy `Authorization: Bearer x` header in the MCP server's Headers tab to provoke a 401 — Google still returns 200 to `initialize`.
- Clicking "Re-authorize" on the existing server — backend logs show only further `initialize` probes (HTTP 200), never `discover_oauth_metadata` or `start_authorization`.
### Suggested fix
Either:
- During `MCPClient` connect in `ToolMCPAuthApi.post`, also issue a representative authenticated call (e.g. `tools/call`) — if it 401s, treat as needing OAuth and fall through to `auth()`.
- Or unconditionally call `discover_oauth_metadata` when `tokens` are absent; if the server publishes `.well-known/oauth-protected-resource` with `authorization_code` grant support, run `start_authorization` even when `initialize` succeeded.
Google's MCP exposes `.well-known/oauth-protected-resource/` (visible in our logs as `GET https://drivemcp.googleapis.com/.well-known/oauth-protected-resource/list_recent_files "HTTP/1.1 200 OK"`), so discovery is feasible without needing a 401 challenge.
### References
- Google's official Drive MCP docs: https://developers.google.com/workspace/drive/api/guides/configure-mcp-server
### ✔️ Expected Behavior
Clicking "Add & Authorize" should open Google's OAuth consent screen in a new browser tab/popup. After the user authorizes, Dify stores access_token + refresh_token in `tool_mcp_providers.encrypted_credentials`, and subsequent tool invocations send the bearer token correctly.
### ❌ Actual Behavior
No popup opens. The MCP server card immediately shows green "Authorized". Inspecting the DB row reveals `authed=true` but `encrypted_credentials` only contains `client_information` and `code_verifier` — no `tokens`. The first tool invocation from an agent fails with `MCPAuthError: Authentication failed - no token received`. Re-authorize button does not start a fresh OAuth flow.
Contributor guide
Assessment
This issue has not been assessed yet.