Skip to content

v0.6.0

Choose a tag to compare

@paulbalandan paulbalandan released this 03 Aug 19:21
· 311 commits to 1.x since this release
v0.6.0
94e1f23

What's Changed

The tracked MCP specification moves from 2025-11-25 to 2026-07-28 with no compatibility layer, so this boundary is breaking throughout. BREAKING_CHANGES.md is the upgrade guide. The entries below are the inventory.

Added

  • The Streamable HTTP server transport. StreamableHttpServerTransport is a PSR-15 handler, and SecuredHttpEndpoint wraps it in CORS, DNS-rebinding protection, a body size limit, header validation, and an optional authentication slot. Responses stream as SSE or buffer as JSON.
  • The Streamable HTTP client transport. StreamableHttpClientTransport POSTs one envelope per exchange and parses SSE frame by frame, so progress notifications arrive mid-call. Requests are bounded by a progress-aware deadline set via ClientBuilder::setRequestTimeout().
  • The OAuth 2.1 client half. AuthorizedHttpClient discovers metadata on a 401, resolves a client identifier, runs the PKCE (S256) authorization-code exchange through UserAuthorizationInterface, binds the token to the MCP server it was issued for, and replays the request.
  • The OAuth 2.1 resource-server half. BearerAuthenticationMiddleware validates bearer tokens, binds the audience, and enforces scopes. ProtectedResourceMetadataHandler serves the RFC 9728 document. The validated token reaches handlers as $context->receiveContext->authInfo.
  • JwksAccessTokenValidator, a JWT validator riding the suggested firebase/php-jwt package.
  • subscriptions/listen on both sides. Client::listen() opens a notification stream, and the server serves it from a SubscriptionStore. The built-in stores became runtime-mutable and fire list_changed notifications.
  • The input-required flow. callTool(), readResource() and getPrompt() can answer with an InputRequiredResult, and the caller answers by calling again with inputResponses: and the echoed requestState:.
  • Completion registration grew ServerBuilder::addPromptCompletion() / addResourceTemplateCompletion() and the repeatable #[AsCompletion] attribute.
  • Stdio client supervision. A subprocess that exits unexpectedly is respawned behind the same transport under a restart budget, with lost read-only requests optionally retried.
  • Server-side lifecycle guards and the new protocol error codes (-32020 HeaderMismatch, -32021 MissingRequiredClientCapability, -32022 UnsupportedProtocolVersion).
  • ServerBuilder configuration: setPageSize(), setTtlMs(), setCacheScope(), setMaxInFlightDispatches(), setServerInfoDisclosure(), and the get*Store() accessors. ClientBuilder::setClientCapabilities() declares the client's capabilities.
  • Tool schemas accept full JSON Schema 2020-12 (SEP-2106), every top-level keyword preserved verbatim.
  • Streamable HTTP examples and a dockerised Keycloak end-to-end example (examples/keycloak-e2e/).

Changed

  • Client::discover() (server/discover) replaces the initialize handshake, and the SDK stamps the per-request _meta lifecycle fields on every outbound request.
  • Every result carries the required resultType discriminator, and cacheable results require the SEP-2549 ttlMs and cacheScope hints.
  • Client::sendRequest() takes the expected response-envelope class, an optional SendContext, and an optional per-request timeout.
  • The ServerRequest marker is renamed InputRequest, and elicitation is remodelled as bare InputRequest / InputResponse bodies riding InputRequiredResult.
  • A misrouted envelope is decided by its id alone, never the method name, uniformly across every parse-failure arm.
  • Reading an unknown resource answers -32602 with the requested URI in error.data.uri (SEP-2164) instead of an empty contents list.

Removed

  • The initialize / notifications/initialized handshake and Client::initialize(). Sessions go with it: no session id on TransportInterface, no Mcp-Session-Id header.
  • ping and Client::ping(), removed by the 2026-07-28 revision.
  • Roots, Sampling and the Logging emission path, deprecated by SEP-2577 and omitted per SEP-2596. The LoggingLevel enum survives only to round-trip the deprecated _meta logLevel field.
  • resources/subscribe and resources/unsubscribe, replaced by subscriptions/listen.
  • The task methods from core (they return as the tasks extension), Tool.execution, the ElicitationCompleteNotification, and the UrlElicitationRequiredError (-32042) mechanism.

Fixed

  • A handler argument-binding failure on an attribute-discovered method is reported as -32602 naming the offending argument, instead of surfacing as an internal error.
  • Resource::$size is typed int per the spec's integer, and NumberSchema bounds plus ElicitResult numeric content accept floats per the spec's number.

Full Changelog: v0.5.0...v0.6.0