MCP Stateless Protocol (2026‑07‑28): Technical Guide and Implementation Walkthrough

This article explains the 2026‑07‑28 MCP stateless protocol changes, the removal of session concepts, new self‑describing request mechanisms, and provides step‑by‑step examples using the webman‑mcp PHP SDK and Neuron‑AI integration, along with compatibility challenges and mitigation strategies.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
MCP Stateless Protocol (2026‑07‑28): Technical Guide and Implementation Walkthrough

1. Overview: Stateless Protocol

The MCP 2026‑07‑28 release candidate introduces the core change of making the protocol layer completely stateless. Six SEP enhancements together with the W3C Trace Context convention (SEP‑414) remove the initialize handshake, the Mcp-Session-Id header, long‑lived SSE streams, and the free‑floating server‑to‑client request channel, replacing them with explicit self‑describing metadata.

Replace initialize handshake with version/identity/capability fields inside each request’s _meta (SEP‑2575).

Replace session‑sticky routing with a stateless explicit handle ( create_basket() → basket_id) (SEP‑2567).

Replace persistent SSE with inline InputRequiredResult (MRTR) (SEP‑2260 / SEP‑2322).

Replace deep‑packet parsing for routing with Mcp-Method / Mcp-Name header mirroring (SEP‑2243).

Introduce cache‑control fields ttlMs and cacheScope for list results (SEP‑2549).

Propagate trace context via _meta keys traceparent, tracestate, baggage (SEP‑414).

2. Protocol Changes Compared to 2025‑11‑25

2.1 Handshake and Session Removal – SEP‑2575 / SEP‑2567

Previously (2025‑11‑25) the client performed a POST initialize, received a Mcp-Session-Id, and then attached that header to every request, causing routing to be pinned to the instance that issued the ID. After the 2026‑07‑28 change, the protocol version, client software identity, and client capabilities are carried inside the request body’s _meta field, making each request self‑contained.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "query_order_snapshot",
    "arguments": {"order_no": "ORDER-20260621-1001"},
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {"name": "neuron-agent", "version": "1.0.0"},
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

The three fields protocolVersion, clientInfo, and clientCapabilities are mandatory and must be declared per request, without inferring anything from prior traffic.

The protocol version is also mirrored in the HTTP header MCP-Protocol-Version; the header and body must match.

A new optional RPC server/discover lets a client query the server’s supported version, capabilities, and identity; if the version mismatches the server returns UnsupportedProtocolVersionError with a list of supported versions.

Missing required capabilities trigger MissingRequiredClientCapabilityError (code -32003, HTTP 400).

2.2 Server‑to‑Client Request Reconstruction – SEP‑2260 / SEP‑2322 (MRTR)

Even a stateless protocol sometimes needs the server to ask the client for additional input (elicitation, sampling, or roots/list queries). SEP‑2260 mandates that such server‑initiated requests can only be issued while handling the original client request, prohibiting free‑floating server pushes. SEP‑2322 replaces the previous SSE‑based reply with an inline InputRequiredResult payload.

{
  "resultType": "inputRequired",
  "inputRequests": {
    "confirm": {
      "type": "elicitation",
      "message": "确认删除 3 个文件吗?",
      "schema": {"type": "boolean"}
    }
  },
  "requestState": "eyJzdGVwIjoxLCJmaWxlcyI6WyJhIiwiYiIsImMiXX0="
}
inputRequests

maps keys to request shapes such as CreateMessageRequest, ElicitRequest, or ListRootsRequest. requestState is an opaque server‑encoded state that the client must return unchanged.

After the client supplies the answers, it re‑issues the original request with the original parameters plus inputResponses (keyed the same as inputRequests) and the unchanged requestState, allowing any server replica to retry without sticky routing.

2.3 Routable and Cacheable Traffic – SEP‑2243 / SEP‑2549

SEP‑2243 requires every streamable HTTP POST to include the Mcp-Method header (mirroring the JSON‑RPC method) and the Mcp-Name header (mirroring params.name or params.uri). The server must reject mismatched header/body pairs with HeaderMismatch (HTTP 400).

POST /mcp/order HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: query_order_snapshot

SEP‑2243 also adds the x-mcp-header JSON‑Schema extension, allowing tools to expose basic‑type parameters as Mcp-Param-{Name} headers for region/tenant routing. Non‑ASCII values must be base64‑encoded.

SEP‑2549 introduces the CacheableResult interface for list‑type RPCs, with mandatory fields ttlMs (milliseconds, 0 means immediate expiry) and cacheScope ("public" or "private"). This provides a stable cache key at the deployment level, supplementing but not replacing HTTP Cache‑Control.

3. Practical Implementation with webman‑mcp

3.1 Installation and Scaffold

composer require tinywan/webman-mcp
php webman make:mcp-server Calculator
php webman make:mcp-tool Calculator

The commands generate app/mcp/CalculatorServer.php and app/mcp/CalculatorTool.php.

3.2 Defining a Tool

<?php
declare(strict_types=1);
namespace app\mcp;
use Tinywan\Mcp\Contracts\ToolInterface;
use Tinywan\Mcp\Runtime\ExecutionContext;
use Tinywan\Mcp\Tool\Content\TextContent;
use Tinywan\Mcp\Tool\ToolCall;
use Tinywan\Mcp\Tool\ToolDefinition;
use Tinywan\Mcp\Tool\ToolResult;

final class CalculatorTool implements ToolInterface {
    public function definition(): ToolDefinition {
        return new ToolDefinition(
            'calculate',
            'Add two numbers.',
            [
                'type' => 'object',
                'properties' => [
                    'left'  => ['type' => 'number'],
                    'right' => ['type' => 'number']
                ],
                'required' => ['left', 'right'],
                'additionalProperties' => false,
            ],
            [
                'type' => 'object',
                'properties' => [
                    'value' => ['type' => 'number']
                ],
                'required' => ['value'],
                'additionalProperties' => false,
            ]
        );
    }

    public function call(ToolCall $call, ExecutionContext $context): ToolResult {
        $value = (float) $call->arguments['left'] + (float) $call->arguments['right'];
        return ToolResult::success(
            content: [new TextContent((string) $value)],
            structuredContent: ['value' => $value]
        );
    }
}

The ToolDefinition declares both inputSchema and outputSchema; webman‑mcp validates them against JSON Schema 2020‑12 before and after execution.

3.3 Registering the Server

<?php
declare(strict_types=1);
namespace app\mcp;
use Tinywan\Mcp\Registry\RegisteredTool;
use Tinywan\Mcp\Registry\ServerDefinition;
use Tinywan\Mcp\Registry\ServerIdentity;
use Tinywan\Mcp\Security\AllowAllAuthorizer;
use Tinywan\Mcp\Security\AllowAnonymousAuthenticator;

final class CalculatorServer {
    public static function definition(): ServerDefinition {
        $tool = new CalculatorTool();
        return new ServerDefinition(
            'calculator',
            '/mcp/calculator',
            new ServerIdentity('Calculator', '1.0.0'),
            [new RegisteredTool($tool->definition(), CalculatorTool::class)],
            new AllowAnonymousAuthenticator(), // demo only
            new AllowAllAuthorizer()          // demo only
        );
    }
}

Register the server in config/plugin/tinywan/webman-mcp/servers.php:

<?php
use app\mcp\CalculatorServer;
return [
    'servers' => [CalculatorServer::definition()],
];

3.4 Running and Validation

# List registered servers
php webman mcp:list
# Validate configuration
php webman mcp:inspect
# Start the webman process
php start.php start

Example curl request (note that _meta and the three MCP headers are mandatory):

curl -X POST http://127.0.0.1:8118/mcp/calculator \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-protocol-version: 2026-07-28" \
  -H "mcp-method: tools/call" \
  -H "mcp-name: calculate" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "calculate",
      "arguments": {"left": 2, "right": 3},
      "_meta": {
        "io.modelcontextprotocol/protocolVersion": "2026-07-28",
        "io.modelcontextprotocol/clientCapabilities": {},
        "io.modelcontextprotocol/clientInfo": {"name": "curl", "version": "1.0.0"}
      }
    }
  }'
_meta

must be an object containing the three namespaced fields.

The three MCP headers ( mcp-protocol-version, mcp-method, mcp-name) must mirror the body; otherwise the server returns HeaderMismatch (‑32020).

Any missing field causes the request to be rejected – this is the self‑describing requirement of the 2026‑07‑28 protocol.

4. Consuming the MCP Server with Neuron‑AI

4.1 Local MCP Server (stdio)

<?php
declare(strict_types=1);
namespace app
euron;
use NeuronAI\MCP\McpConnector;
use NeuronAI\Agent;

final class CalculatorAgent extends Agent {
    protected function tools(): array {
        return [
            ...McpConnector::make([
                'command' => 'php',
                'args'    => ['/var/www/chunfen/mcp_server.php'],
            ])->tools(),
        ];
    }
}

4.2 Remote MCP Server (Streamable HTTP)

protected function tools(): array {
    return [
        ...McpConnector::make([
            'url'    => 'http://erp.chutang66.com/mcp/order',
            'token'  => env('MCP_TOKEN'),
            'timeout'=> 30,
            'headers'=> ['X-Tenant' => 'chunfen'],
        ])->tools(),
    ];
}

When the agent decides to call a tool, Neuron automatically builds the appropriate MCP request, sends it to the server, and returns the result as if the tool were defined locally.

5. Compatibility Friction and Mitigation

No _meta : Server returns “params._meta must be an object” because the new protocol requires every request to be self‑describing.

No header mirroring : Server returns Header mismatch (‑32020) as SEP‑2243 mandates matching headers.

Attempting initialize : Server returns “Method not found” (‑32601) because the handshake was removed.

Protocol version mismatch : Server returns “Unsupported protocol version” (‑32022) because the version is hard‑coded and no downgrade is performed.

Recommended mitigation paths (ordered by preference):

A. Wait for or push client upgrades to the 2026‑07‑28 SDKs (Go, Python) that support the stateless mode natively.

B. Add a “lenient mode” switch to webman‑mcp that makes _meta and header checks optional and provides a compatibility stub for initialize. This eases transition but deviates from the spec.

C. Deploy a protocol‑translation gateway (e.g., mcpsense‑proxy) that speaks the old handshake protocol externally and translates to the new stateless format internally.

D. Extend webman‑mcp to support dual‑stack operation, handling both the old 2025‑11‑25 handshake and the new stateless flow.

Short‑term: use option B or D for a smooth transition. Long‑term: follow option A and migrate fully to the pure stateless protocol. If you control all clients (custom agents), you can adopt 2026‑07‑28 immediately without friction.

References

SEP‑2575 — Make MCP Stateless

SEP‑2567 — Sessionless MCP via Explicit State Handles

SEP‑2260 — Require Server requests to be associated with a Client request

SEP‑2322 — Multi Round‑Trip Requests (MRTR)

SEP‑2243 — HTTP Header Standardization for Streamable HTTP Transport

SEP‑2549 — TTL for List Results

SEP‑414 — Document OpenTelemetry Trace Context Propagation Conventions

Official announcement: 2026‑07‑28 release candidate

Reference document: muster — Stateless protocol (MCP 2026‑07‑28)

webman‑mcp · Neuron‑AI · Neuron MCP Connector documentation

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MCPOpenTelemetryPHPTrace ContextWebmanNeuron-AIStateless Protocol
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.