Automattic / Automattic/mcp-wordpress-remote
Implicit OAuth can block MCP initialize for the five-minute lock lifetime
- Dominant language
- TypeScript
- Stars
- 180
- Forks
- 35
- PR merge metrics
- No merged PRs in 30d
Description
## 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
1. Configure implicit OAuth with no cached token.
2. Start the stdio proxy in a headless environment.
3. Send a valid newline-delimited MCP `initialize` request.
4. 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.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the WordPressProxy initialize path and trace transport detection through getOAuthTokens() to PersistentWPOAuthClientProvider.waitForAuthorizationResult(). Run the no-token headless reproduction alongside the JWT_TOKEN control, then add fake-timer and initialize-path regression coverage. Done means OAuth and lock waits respect the operation budget while successful interactive OAuth and multi-process coordination still work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100