MCP: no OAuth 2.0 support for remote MCP servers (SSE/streamable-http), static headers only
Problem
Qwen-Agent's MCP client (qwen_agent/tools/mcp_manager.py) can only authenticate to remote MCP servers with static headers (e.g. a pre-configured Authorization: Bearer ...). There is no OAuth 2.0 client flow, so remote MCP servers that follow the standard MCP authorization model (authorization-code flow with PKCE, dynamic client registration, token refresh) cannot be used at all:
- Tokens from a static header cannot be refreshed when they expire mid-session.
- No authorization-server discovery (
.well-known/oauth-authorization-server) is performed. - No callback/redirect support for the browser-based consent step.
The Python MCP SDK ships this client capability (mcp.client.auth in the current SDK: OAuthClientProvider, PKCEParameters, TokenStorage, "authorization code flow with PKCE and automatic token refresh"), and the sibling product Qwen Code already supports OAuth 2.0 for remote MCP servers over SSE and HTTP transports (qwen mcp add --transport sse oauth-server <url> --oauth-client-id ... --oauth-redirect-uri ..., see QwenLM/qwen-code docs/users/features/mcp.md). Qwen-Agent is the gap.
Use case (self-hosted / local deployments)
Local agents (e.g. Qwen-Agent on a self-hosted box driving a local model via Ollama) pointing at remote, OAuth-protected MCP servers (GitHub MCP server, hosted reference servers, or any server registered through the standard OAuth flow) currently cannot connect. Static bearer tokens are only a workaround for servers that accept long-lived tokens, and they break as soon as the token expires or the server supports only the OAuth discovery flow.
Evidence inspected
qwen_agent/tools/mcp_manager.pyat main: theurlconfig supportstype: sse(default) andtype: streamable-http, both using onlyheadersfrom the config; there is no OAuth/authorization code path (grep -ri oauth qwen_agent/returns nothing).- Docs
qwen-agent-docs/.../guide/core_moduls/mcp.mddocument only stdio servers; theurl/headers/typekeys and any auth story for remote servers are undocumented. - Current MCP SDK (what
pip install -U mcpresolves to, and what PR #950 is adapting to) exposesmcp.client.authwith PKCE and token refresh; Qwen-Agent depends onmcpunpinned (setup.pyextras:'mcp': ['mcp']). - Qwen Code (QwenLM/qwen-code) documents and implements OAuth 2.0 for remote MCP servers over SSE and HTTP transports — feature parity exists in the sibling project.
Expected behavior
Allow an MCP server entry to opt into the OAuth client flow, e.g.:
{
"mcpServers": {
"github": {
"type": "streamable-http",
"url": "https://remote.example.com/mcp",
"oauth": { "client_id": "...", "scopes": [] }
}
}
}and have Qwen-Agent perform discovery + authorization-code flow (with a browser callback), cache the token, and refresh it automatically — at minimum matching what the SDK's mcp.client.auth provides and what Qwen Code does for the same servers.
Suggested implementation shape
- Reuse
mcp.client.auth(OAuthClientProvider / TokenStorage) instead of hand-rolling OAuth. - Accept an
oauthblock in the server config; when present, build the SDK auth provider and pass it to the SSE/streamable-http client instead of raw headers. - Provide a token-storage location (e.g. under the user config dir, env-overridable) so tokens survive restarts.
- Decide the SDK 1.x vs 2.x compatibility envelope together with the in-flight #949 / PR #950 streamable-http SDK-2.0 work, since the OAuth API surface differs across SDK versions.
Duplicate search
No existing issue/PR covers OAuth for MCP in this repo (searched all states: oauth -> 0 results repo-wide). Related but distinct threads concern only static headers: #681 / #691 / #765 / #612 (headers on streamable-http, supported at main since 2025-05), and #571 / PR #795 (resource templates). #949/#950 are about SDK v2 import compatibility, not OAuth.
Willingness to contribute
Happy to implement this (config schema + SDK auth integration + docs). Maintainer steer would help on: (1) target SDK version envelope (mcp>=2.0 only vs both 1.x and 2.x), and (2) acceptable UX for the authorization step in headless setups (browser callback vs device flow vs pre-auth CLI like qwen mcp add).
Source: QwenLM/Qwen-Agent