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, '/');