MCP auth retry leaves orphaned transport/session when 401 occurs during initialize
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- python
- Domain
- api, authentication, backend
Research direction
Start in api/core/mcp/auth_client.py, tracing _execute_with_retry, enter, _initialize, and connect_server, then inspect the repro assertion for the partial-session case. Verify that a 401 during initialization closes the existing ExitStack and clears session state before retrying, while the fully initialized path still retries correctly.
Written by the indexing model from the issue text.
Description
Problem
MCPClientWithAuthRetry._execute_with_retry only tears down the MCP transport/ClientSession ExitStack when self._initialized is already True.
MCPClient.__enter__ sets _initialized = True after _initialize() returns. Inside _initialize → connect_server, the streamable-HTTP/SSE transport and ClientSession are already pushed onto _exit_stack before ClientSession.initialize() runs. A 401 from that handshake raises MCPAuthError while _initialized is still False.
On auth refresh + retry, the client therefore:
- Updates
Authorizationheaders - Calls
_initialize()again without closing the first ExitStack entries - Opens a second transport + session while the expired-token connection stays alive until the outer context exits
Why this matters
- Core MCP OAuth / session-binding path used by tool list + invoke
- Leaks concurrent MCP sessions (servers that bind one session per client can reject or confuse the second connect)
- Stale connection with the old token remains open alongside the refreshed one
Evidence
# Current gate in api/core/mcp/auth_client.py
if self._initialized:
self._exit_stack.close()
self._session = None
self._initialized = False
self._initialize()
self._initialized = True
Repro unit assertion (fails on main): after MCPAuthError with _initialized is False and a partial _session already attached, _exit_stack.close() is never called before the retry.
Proposed fix
Always close _exit_stack, clear _session, reset _initialized, and replace the ExitStack before retrying. Only call _initialize() again when the client was already fully initialized (list_tools / invoke path). The __enter__ retry path re-enters and initializes itself.
Related (not the same root cause)
- #41499 / #41482 — orphaned JSON-RPC responses crashing the receive loop (
base_session.py) - #42326 / #42327 — invoke skipping OAuth when custom headers are set (
mcp_tool/tool.py)
- Dominant language
- TypeScript
- Stars
- 157k
- Forks
- 24.7k
- Avg merge
- 22h 32m
- Merged PRs (30d)
- 611
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from langgenius/dify
-
Annotation Reply: a stored score threshold of 0.0 is silently replaced with 1, disabling the feature Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
langgenius/dify#42639 · 1 comment · 1 reaction ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
langgenius/dify#42468 · 1 comment · 1 reaction ·
-
🐞 bug
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
langgenius/dify#42446 · 1 reaction ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
langgenius/dify#42355 · 1 comment · 1 reaction ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
langgenius/dify#42350 · 1 comment · 1 reaction ·
Similar issues
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100