Context
Our integration tests today all go through the official MCP SDK client. The SDK is a well-behaved client and intentionally hides three things our streamable-HTTP transport contract still needs assertions on. This issue tracks adding a narrow raw-HTTP suite for exactly those things.
Companion issue in apify-mcp-server-internal: apify/apify-mcp-server-internal#566 (covers the hosted-only slice — auth 401, Origin, Redis-backed session lookup).
Why raw HTTP
The SDK hides:
- HTTP status codes (200/202/400/404). The SDK surfaces JSON-RPC errors but not the codes; ops dashboards, load balancers, and the SDK's own session-recovery logic key off them.
- HTTP-only headers (
Mcp-Session-Id, future MCP-Protocol-Version enforcement). The SDK manages these internally; a client can't read them.
- Misbehavior the SDK refuses to do — no session, malformed JSON. These come from broken proxies, fuzzers, browser dev tools, and other-language clients.
Anything inside the SDK's happy path (ping, capability errors, tool-not-found, pagination, structured output) stays SDK-mediated in tests/integration/suite.ts.
Tests to add
Initialization & session lifecycle
HTTP envelope
Protocol-version negotiation
Scope boundary
Tests that depend on hosted-stack behavior (auth 401, WWW-Authenticate, foreign-origin 403, Redis-backed cross-node session lookup) live in apify-mcp-server-internal — see apify/apify-mcp-server-internal#566.
Implementation notes
A small (~150 LOC) raw-HTTP helper plus a single new test file alongside tests/integration/suite.ts. A drafted client lives at apify/apify-mcp-server-internal#474 (closed) and can be ported as a starting point.
Context
Our integration tests today all go through the official MCP SDK client. The SDK is a well-behaved client and intentionally hides three things our streamable-HTTP transport contract still needs assertions on. This issue tracks adding a narrow raw-HTTP suite for exactly those things.
Companion issue in
apify-mcp-server-internal: apify/apify-mcp-server-internal#566 (covers the hosted-only slice — auth 401, Origin, Redis-backed session lookup).Why raw HTTP
The SDK hides:
Mcp-Session-Id, futureMCP-Protocol-Versionenforcement). The SDK manages these internally; a client can't read them.Anything inside the SDK's happy path (ping, capability errors, tool-not-found, pagination, structured output) stays SDK-mediated in
tests/integration/suite.ts.Tests to add
Initialization & session lifecycle
initializereturns 200 and anMcp-Session-Idheader (visible ASCII per spec)Mcp-Session-Id(and notinitialize) → 400Mcp-Session-Id→ 404 so SDK recovery starts a new sessionHTTP envelope
notifications/cancelledfor an unknownrequestId→ 202 (silent no-op per spec)Protocol-version negotiation
MCP-Protocol-Versionheader → 400Scope boundary
Tests that depend on hosted-stack behavior (auth 401,
WWW-Authenticate, foreign-origin 403, Redis-backed cross-node session lookup) live inapify-mcp-server-internal— see apify/apify-mcp-server-internal#566.Implementation notes
A small (~150 LOC) raw-HTTP helper plus a single new test file alongside
tests/integration/suite.ts. A drafted client lives at apify/apify-mcp-server-internal#474 (closed) and can be ported as a starting point.