Use a lock for sessions to handle concurrency issue with session data
See https://github.com/modelcontextprotocol/php-sdk/issues/275
We implemented a lock
```php
// Serialize concurrent requests for the same MCP session.
//
// The PHP MCP SDK stores protocol state (outgoing queue, request counter,
// pending requests) in a shared session blob using a read-modify-write
// pattern with no locking. When multiple requests arrive concurrently for
// the same Mcp-Session-Id, each worker reads stale state, overwrites the
// others' changes on save, and can corrupt the session.
//
// See: https://github.com/modelcontextprotocol/php-sdk/issues/275
//
// The lock is per session so independent sessions are unaffected.
// initialize requests (no Mcp-Session-Id) need no lock.
// The session ID is hashed to produce a safe, bounded lock key regardless
// of the header value supplied by the client.
$sessionId = $psrRequest->getHeaderLine('Mcp-Session-Id') ?: NULL;
$lockName = $sessionId !== NULL ? 'mcp_session:' . hash('sha256', $sessionId) : NULL;
if ($lockName !== NULL && !$this->lock->acquire($lockName)) {
$this->lock->wait($lockName);
if (!$this->lock->acquire($lockName)) {
return new Response('MCP session lock timeout', Response::HTTP_SERVICE_UNAVAILABLE);
}
}
try {
$server = $this->serverFactory->createServer();
$psrResponse = $server->run($transport);
}
finally {
if ($lockName !== NULL) {
$this->lock->release($lockName);
}
}
```
issue