Skip to content

Add SSE streaming to the HTTP transport GET endpoint - #300

Draft
sarthak-19 wants to merge 1 commit into
WordPress:trunkfrom
sarthak-19:feature/http-transport-sse
Draft

Add SSE streaming to the HTTP transport GET endpoint#300
sarthak-19 wants to merge 1 commit into
WordPress:trunkfrom
sarthak-19:feature/http-transport-sse

Conversation

@sarthak-19

Copy link
Copy Markdown

Summary

Fixes #280.

The HTTP transport's GET endpoint has always returned 405 Method Not Allowed, so the only documented way to reach a WordPress MCP server was some form of STDIO on the client side: wp mcp-adapter serve running locally, or the @automattic/mcp-wordpress-remote proxy, which is also a locally-spawned process that just forwards to HTTP behind the scenes. Either way, the client needs to be able to launch a local process — which doesn't work for Claude in Chat/Cowork mode, since that runs in a hosted sandbox.

This PR completes the existing HttpTransport's Streamable HTTP support by implementing the GET (SSE) endpoint, so clients that support remote/custom MCP connectors can point straight at the site's REST endpoint over HTTPS (with an Application Password), without any local proxy.

  • GET now validates the session and protocol version exactly like POST does, then opens a real text/event-stream response with periodic keep-alive comments.
  • The stream is held open for a bounded, filterable duration (30s by default) and then closes; compliant SSE/EventSource clients reconnect automatically. This is a deliberate choice for a synchronous PHP-FPM/mod_php request model: an indefinitely-held connection would tie up a worker per client, which the MCP Streamable HTTP spec doesn't require (a server may omit GET/SSE support entirely and stay compliant).
  • New filters: mcp_adapter_enable_http_sse_stream (opt back out to the old 405 behavior), mcp_adapter_sse_stream_duration, mcp_adapter_sse_ping_interval.
  • The actual byte streaming runs through a rest_pre_serve_request filter scoped to the specific request, so it only fires during a real WP_REST_Server dispatch — calling the transport/handler directly (as the existing unit tests do) never blocks.
  • Docs updated with a "connecting directly over HTTP" section and a curl example; updated the stale "SSE not yet implemented" notes elsewhere.

Out of scope: OAuth-based authorization for browser-driven connector setups. That's a much larger, security-sensitive feature (essentially an OAuth provider for WordPress) and deserves its own design discussion rather than being bundled into this fix. This PR only completes the transport-level piece; sites can already authenticate remote HTTP access today via Application Passwords.

Test plan

  • composer test (full PHPUnit suite via wp-env) — all passing.
  • composer lint / composer phpstan — no new warnings or errors.
  • Manually verified end-to-end against a real WordPress install in wp-env: initialized a session over POST, opened the GET SSE stream with curl -N, confirmed Content-Type: text/event-stream, the initial stream-open comment, a ping keep-alive at the configured interval, and correct 400/404 responses for missing/invalid sessions.
  • Verified the SSE feature can be disabled via mcp_adapter_enable_http_sse_stream to restore the previous 405 behavior.

The HTTP transport's GET endpoint returned 405 unconditionally, so the
only documented way to reach a WordPress MCP server was some form of
STDIO on the client side (wp mcp-adapter serve locally, or the
mcp-wordpress-remote proxy forwarding to HTTP). Clients that run in a
hosted sandbox and can't launch local processes had no way to connect.

GET now opens a real Server-Sent Events stream per the MCP Streamable
HTTP transport, after the same session and protocol-version validation
POST already performs. The stream is held open for a bounded, filterable
duration (30s default) with periodic keep-alive pings, then closes;
compliant clients reconnect automatically, so a slow or idle connection
never ties up a PHP-FPM worker indefinitely. Streaming happens outside
the normal WP_REST_Server JSON envelope via a scoped rest_pre_serve_request
filter, so calling the handler directly (as tests do) never blocks.

Clients that support remote/custom MCP connectors can now point straight
at the site's existing REST endpoint over HTTPS with an Application
Password, with no local proxy required.
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.38462% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.97%. Comparing base (07c9912) to head (50595e4).

Files with missing lines Patch % Lines
includes/Transport/Infrastructure/SseStream.php 74.41% 11 Missing ⚠️
...es/Transport/Infrastructure/HttpRequestHandler.php 77.27% 5 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##              trunk     #300      +/-   ##
============================================
- Coverage     88.17%   87.97%   -0.21%     
- Complexity     1259     1277      +18     
============================================
  Files            54       55       +1     
  Lines          4120     4182      +62     
============================================
+ Hits           3633     3679      +46     
- Misses          487      503      +16     
Flag Coverage Δ
unit 87.97% <75.38%> (-0.21%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add real HTTP transport support

1 participant