From 76df6e2ca25f6acb66b66090ce0898b546a3db23 Mon Sep 17 00:00:00 2001 From: Jan-PhilippKalus Date: Tue, 22 Sep 2026 16:30:37 +0200 Subject: [PATCH] Make react/http an optional dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only HttpServerTransport and StreamableHttpServerTransport use react/http, yet every consumer of this package installs it — including stdio users and framework integrations that drive Server/Protocol/Dispatcher themselves. The cost is not just unused packages. Every release of react/http, v1.0.0 through v1.11.1, requires psr/http-message ^1.0, so this package transitively pins its host project's PSR-7 interfaces to 1.x. On a project already on psr/http-message 2.0 a fresh install silently resolves it down to 1.1, and an existing install cannot update at all. react/http moves to suggest, and to require-dev so this repository's own suite is unaffected. psr/http-message becomes a declared dependency at ^1.0 || ^2.0: src/Context.php type-hints ServerRequestInterface and is not transport-specific, so the dependency already exists — it is merely undeclared, and reaches the tree only through react/http, which is also what narrows it to 1.x. Both HTTP transports now fail with a TransportException naming the package and the command to install it, rather than letting a "class not found" escape. Co-Authored-By: Claude Opus 5 --- README.md | 10 +++++++++- composer.json | 6 ++++-- src/Transports/HttpServerTransport.php | 6 ++++++ src/Transports/StreamableHttpServerTransport.php | 6 ++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 60f2e63..0a85619 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This package supports the **2025-03-26** version of the Model Context Protocol w - **PHP** >= 8.1 - **Composer** -- **For HTTP Transport**: An event-driven PHP environment (CLI recommended) +- **For HTTP Transport**: An event-driven PHP environment (CLI recommended) and the optional `react/http` package (see Installation) - **Extensions**: `json`, `mbstring`, `pcre` (typically enabled by default) ## 📦 Installation @@ -39,6 +39,14 @@ This package supports the **2025-03-26** version of the Model Context Protocol w composer require php-mcp/server ``` +The HTTP transports need `react/http`, which is an optional dependency so that +projects using only the stdio transport or their own framework integration are +not tied to its dependency tree: + +```bash +composer require react/http +``` + > **💡 Laravel Users**: Consider using [`php-mcp/laravel`](https://github.com/php-mcp/laravel) for enhanced framework integration, configuration management, and Artisan commands. ## ⚡ Quick Start: Stdio Server with Discovery diff --git a/composer.json b/composer.json index aed46e4..23311cb 100644 --- a/composer.json +++ b/composer.json @@ -29,10 +29,10 @@ "phpdocumentor/reflection-docblock": "^5.6", "psr/clock": "^1.0", "psr/container": "^1.0 || ^2.0", + "psr/http-message": "^1.0 || ^2.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", "react/event-loop": "^1.5", - "react/http": "^1.11", "react/promise": "^3.0", "react/stream": "^1.4", "symfony/finder": "^6.4 || ^7.2" @@ -43,10 +43,12 @@ "pestphp/pest": "^2.36.0|^3.5.0", "react/async": "^4.0", "react/child-process": "^0.6.6", + "react/http": "^1.11", "symfony/var-dumper": "^6.4.11|^7.1.5" }, "suggest": { - "ext-pcntl": "For signal handling support when using StdioServerTransport with StreamSelectLoop" + "ext-pcntl": "For signal handling support when using StdioServerTransport with StreamSelectLoop", + "react/http": "Required for HttpServerTransport and StreamableHttpServerTransport (^1.11)" }, "autoload": { "psr-4": { diff --git a/src/Transports/HttpServerTransport.php b/src/Transports/HttpServerTransport.php index c609dab..8db2c72 100644 --- a/src/Transports/HttpServerTransport.php +++ b/src/Transports/HttpServerTransport.php @@ -71,6 +71,12 @@ public function __construct( private readonly ?array $sslContext = null, private array $middlewares = [] ) { + if (! class_exists(HttpServer::class)) { + throw new TransportException( + 'react/http is not installed. It is an optional dependency, required only by the HTTP transports. Install it with "composer require react/http".' + ); + } + $this->logger = new NullLogger(); $this->loop = Loop::get(); $this->ssePath = '/' . trim($mcpPathPrefix, '/') . '/sse'; diff --git a/src/Transports/StreamableHttpServerTransport.php b/src/Transports/StreamableHttpServerTransport.php index 9d9a349..1316a85 100644 --- a/src/Transports/StreamableHttpServerTransport.php +++ b/src/Transports/StreamableHttpServerTransport.php @@ -82,6 +82,12 @@ public function __construct( ?EventStoreInterface $eventStore = null, private array $middlewares = [] ) { + if (! class_exists(HttpServer::class)) { + throw new TransportException( + 'react/http is not installed. It is an optional dependency, required only by the HTTP transports. Install it with "composer require react/http".' + ); + } + $this->logger = new NullLogger(); $this->loop = Loop::get(); $this->mcpPath = '/' . trim($mcpPath, '/');