langgenius / langgenius/dify

MCP OAuth flow never triggers for servers that return 200 OK on initialize without auth (Google Drive MCP)

Open
#36,230 8 comments 1 reaction 0 assignees View on GitHub
🐞 bug 1.14.0
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.