Automattic / Automattic/mcp-wordpress-remote

Implicit OAuth can block MCP initialize for the five-minute lock lifetime

Open
#103 0 comments 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.