Problem
When implicit OAuth has no cached token, the stdio MCP initialize path authenticates before returning its initialize response. PersistentWPOAuthClientProvider::waitForAuthorizationResult() waits with CONFIG.LOCK_TIMEOUT (five minutes) rather than the configured OAuth timeout. A headless or unattended client therefore appears unreachable until its outer connection budget expires.
The same extended wait can occur when another process owns the auth lock.
Reproduction
- Configure implicit OAuth with no cached token.
- Start the stdio proxy in a headless environment.
- Send a valid newline-delimited MCP
initialize request.
- Do not complete the browser callback.
Observed with the current bundled 0.3.4 path: no initialize response or diagnostic is emitted within 60 seconds. A control run with JWT_TOKEN set returns the fallback initialize response immediately, isolating the stall to OAuth coordination rather than stdio, Node, proxy discovery, or backend transport.
Root cause
WordPressProxy awaits transport detection during initialize.
- Transport detection calls
getOAuthTokens().
- Implicit OAuth waits for authorization completion.
waitForAuthorizationResult() uses the five-minute lock lifetime instead of the OAuth operation timeout.
Expected
Authentication waiting is bounded by the OAuth/initialization operation budget. MCP initialize returns a structured fallback response with experimental.connectionFailed when interactive authentication is not completed in time. Lock lifetime remains a coordination concern, not the caller-visible operation timeout.
Acceptance
- Bound authorization callback waiting by the configured OAuth timeout.
- Bound waiting behind another auth owner independently of lock lifetime.
- Add deterministic fake-timer coverage proving absent callback rejection occurs at the OAuth timeout.
- Add an initialize-path regression proving headless implicit OAuth returns a structured response within the initialization budget.
- Preserve successful interactive OAuth and multi-process lock coordination.
AI assistance
OpenAI openai/gpt-5.6-sol via OpenCode traced the initialize/auth call chain, compared token and no-token controls, and drafted this report. Chris Huber reviewed and owns the result.
Problem
When implicit OAuth has no cached token, the stdio MCP
initializepath authenticates before returning its initialize response.PersistentWPOAuthClientProvider::waitForAuthorizationResult()waits withCONFIG.LOCK_TIMEOUT(five minutes) rather than the configured OAuth timeout. A headless or unattended client therefore appears unreachable until its outer connection budget expires.The same extended wait can occur when another process owns the auth lock.
Reproduction
initializerequest.Observed with the current bundled
0.3.4path: no initialize response or diagnostic is emitted within 60 seconds. A control run withJWT_TOKENset returns the fallback initialize response immediately, isolating the stall to OAuth coordination rather than stdio, Node, proxy discovery, or backend transport.Root cause
WordPressProxyawaits transport detection during initialize.getOAuthTokens().waitForAuthorizationResult()uses the five-minute lock lifetime instead of the OAuth operation timeout.Expected
Authentication waiting is bounded by the OAuth/initialization operation budget. MCP initialize returns a structured fallback response with
experimental.connectionFailedwhen interactive authentication is not completed in time. Lock lifetime remains a coordination concern, not the caller-visible operation timeout.Acceptance
AI assistance
OpenAI
openai/gpt-5.6-solvia OpenCode traced the initialize/auth call chain, compared token and no-token controls, and drafted this report. Chris Huber reviewed and owns the result.