Fix - Streamable HTTP transport (issue #5)
Bugfix: Streamable HTTP transport corrupted every JSON-RPC response
Fixes #5.
/wp-json/wp/v2/wpmcp/streamable hand-wrote HTTP/1.1 chunked transfer-encoding framing into the response body and set the hop-by-hop Transfer-Encoding and Connection headers itself. Transfer encoding belongs to the web server / SAPI layer.
On nginx + PHP-FPM the FastCGI layer drops the hop-by-hop header and re-frames the body, so clients de-chunk one layer and are left with the application's framing bytes inside the payload — every JSON-RPC response failed to parse. HTTP/2 has no chunked encoding at all and failed the same way. Apache + mod_php happened to honour the header, which is why this went unnoticed.
The transport now returns a single, complete application/json body with a correct Content-Length, as the MCP Streamable HTTP transport specifies for a JSON response to a POST.
Also fixed
Mcp-Session-Idwas silently dropped for batches of more than 5 messages — that path set the header after body output.- Notification-only requests now return a genuinely empty
202body instead of a stray0\r\n\r\n. - Removed references to a decommissioned demo host from the setup docs,
static-files/openapi.json, and connection logging.mcp-proxy.phpnow takes the endpoint URL from argv orMCPFOWO_URLinstead of hard-coding one.
Added
tests/e2e/— raw-byte HTTP tests for the streamable endpoint covering both the JWT and JWT-disabled proxy paths, plus a disposable nginx + PHP-FPM container stack.
Affected clients
Any backend MCP client following the transport spec, including laravel/mcp's WebClient and the official MCP SDK StreamableHTTPClientTransport.
Thanks to @sertacdemirtas for a report that pinned the root cause precisely.