james2037 / mcp-php-server
Model Context Protocol server framework in PHP
Requires
- php: ^8.1
- laminas/laminas-diactoros: ^3.6
- laminas/laminas-httphandlerrunner: ^2.9
- nyholm/psr7: ^1.8
- nyholm/psr7-server: ^1.0
- psr/http-message: ^1.0 || ^2.0
- psr/log: ^1.1 || ^2.0 || ^3.0
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.4
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.11
- dev-master
- dev-fix/json-batch-parsing
- dev-fix-phpstan-errors
- dev-jules_wip_14016435911978854069
- dev-feature/http-transport-coverage
- dev-remove-preferSseStream
- dev-refactor-transport-abstraction
- dev-jules_wip_18065023031522284717
- dev-cover-tool-branches
- dev-feature/improve-jsonrpcmessage-coverage
- dev-feature/test-fromJson-response-coverage
- dev-feature/tool-ergonomics-and-method-rename
- dev-fix/blobresource-toarray-coverage
- dev-remove-erroneous-tool
- dev-feature/refactor-content-classes
- dev-fix/getclassfromfile-token-get-all
- dev-test-coverage-registry
- dev-test/increase-jsonrpcmessage-coverage
- dev-test/method-not-supported-exception-coverage
- dev-fix/tools-capability-coverage
- dev-phpstan-impossible-paths
- dev-jules_wip_8715358967716627061
- dev-fix/phpstan-errors
- dev-update-todo-list
- dev-update-readme-packagist
- dev-feat/improve-examples-and-docs
- dev-feat/update-readme-with-examples
- dev-phpstan-level-7
- dev-phpstan-phpcs-cleanup
- dev-fix/run-all-tests
- dev-phpstan-level-6
- dev-style/docblock-comment-cleanup
- dev-fix/improve-stdio-transport-coverage
- dev-test/stdio-transport-coverage
- dev-test-runhttprequestcycle
- dev-fix/phpstan-phpcs-issues
- dev-jules_wip_10366462034624510826
- dev-refactor/capability-lifecycle-testing
- dev-test/resources-capability-coverage
- dev-fix-phpunit-deprecation
- dev-test/tools-capability-coverage
- dev-feature/improve-php-tooling
- dev-refine-phpstan-config
- dev-http-transport-spec-updates
- dev-refactor/filereader-isreadable
- dev-jules_wip_115773707081378946
- dev-fix/phpcs-violations
- dev-fix/suppress-line-length-error
- dev-fix/http-transport-tests
- dev-http-transport-test-syntax-error
- dev-jules_wip_4715121555117343309
- dev-update-jules-md-readme-ref
- dev-cleanup-test-outputs
- dev-psr12-compliance
- dev-feature/JULES-101-test-script-updates-partial
- dev-finalize-readme-custom-examples
- dev-fix/server-test-response-handling
- dev-fix/phpunit-tests
- dev-jules_wip_4688623927930992078
- dev-fix/test-runner-visibility
- dev-add-jules-setup-script
- dev-feature/mcp-2025-03-26-update-p1
This package is auto-updated.
Last update: 2025-06-05 07:27:42 UTC
README
PHP Model Context Protocol Server SDK
This project provides a PHP implementation of the Model Context Protocol (MCP), enabling you to build servers that can provide context (data and tools) to Large Language Models (LLMs).
MCP is an open protocol that standardizes how applications interact with LLMs. For more information about MCP, please visit the official website: https://modelcontextprotocol.io
Features
This PHP MCP SDK provides the following core features:
- Server Implementation: Easily create MCP compliant servers.
- Capabilities:
Tools
: Expose functionalities for LLMs to execute.Resources
: Provide data and content to LLMs.
- Transports:
StdioTransport
: For command-line based MCP servers.HttpTransport
: For exposing MCP servers over HTTP (compatible with standard PHP web server environments like Apache/Nginx with PHP-FPM/mod_php).
- JSON-RPC Handling: Manages request parsing and response formatting.
- Attribute-Based Configuration: Use PHP attributes to define tools, resources, and their parameters.
Getting Started
This guide will walk you through creating simple MCP servers using this SDK.
Prerequisites
- PHP 8.1 or higher
- Composer for dependency management
Installation
Install the dependencies using Composer:
composer require james2037/mcp-php-server
Creating an STDIO Server
An STDIO server communicates over standard input and standard output. This is commonly used for local tools or development purposes.
The following example demonstrates a server with:
- An
EchoTool
: Takes a string and returns it. - A
GreetingResource
: Provides a static greeting message.
The full code for this example can be found in examples/stdio_server.php
.
Key parts of examples/stdio_server.php
:
<?php // Autoload dependencies require_once __DIR__ . '/../vendor/autoload.php'; // Required MCP SDK classes use MCP\Server\Server; use MCP\Server\Transport\StdioTransport; use MCP\Server\Capability\ToolsCapability; use MCP\Server\Capability\ResourcesCapability; // For defining the tool use MCP\Server\Tool\Tool as BaseTool; use MCP\Server\Tool\Attribute\Tool as ToolAttribute; use MCP\Server\Tool\Attribute\Parameter; // For defining the resource use MCP\Server\Resource\Resource as BaseResource; use MCP\Server\Resource\Attribute\ResourceUri; use MCP\Server\Resource\ResourceContents; // 1. Define a Tool #[ToolAttribute(name: "echo", description: "Echoes back the provided message.")] class EchoTool extends BaseTool { protected function doExecute(array $arguments): array { // Access parameters from the $arguments array $message = $arguments['message'] ?? 'Default message if not provided'; return [$this->createTextContent("Echo: " . $message)]; } } // 2. Define a Resource #[ResourceUri(uri: "greeting://welcome", description: "Provides a welcome greeting.")] class GreetingResource extends BaseResource { public function __construct() { parent::__construct("Welcome Greeting", "text/plain"); } public function read(array $parameters = []): ResourceContents { return $this->text("Hello from your MCP server!"); } } // 3. Instantiate the Server $server = new Server('MySimpleServer (STDIO)', '1.0.0'); // 4. Setup and Add Tools Capability $toolsCapability = new ToolsCapability(); $toolsCapability->addTool(new EchoTool()); $server->addCapability($toolsCapability); // 5. Setup and Add Resources Capability $resourcesCapability = new ResourcesCapability(); $resourcesCapability->addResource(new GreetingResource()); $server->addCapability($resourcesCapability); // 6. Connect StdioTransport $transport = new StdioTransport(); $server->connect($transport); // 7. Run the Server fwrite(STDERR, "STDIO Server listening...\n"); // Optional: message to stderr $server->run();
(Note: The EchoTool::doExecute
method uses array $arguments
as its parameter. This is because the base Tool
class passes all arguments as an associative array to this method. Your tool logic should then access specific parameters from this array, e.g., $arguments['message']
.)
Running the STDIO Server:
Execute the script from your terminal:
php examples/stdio_server.php
The server will listen for JSON-RPC messages on standard input.
Creating an HTTP Server
You can also expose your MCP server over HTTP using the HttpTransport
. This example uses the same EchoTool
and GreetingResource
.
The full code for this example is in examples/http_server.php
. This script requires PSR-7 and PSR-17 HTTP message implementations (e.g., nyholm/psr7
and nyholm/psr7-server
, which are included in composer.json
).
Key parts of examples/http_server.php
:
<?php // Autoload dependencies require_once __DIR__ . '/../vendor/autoload.php'; // Required MCP SDK classes & PSR implementations use MCP\Server\Server; use MCP\Server\Transport\HttpTransport; use MCP\Server\Capability\ToolsCapability; use MCP\Server\Capability\ResourcesCapability; use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7Server\ServerRequestCreator; // Tool and Resource definitions (e.g., EchoTool, GreetingResource) // would be included here, same as in the STDIO example. // For brevity, they are omitted from this snippet but are in the actual file. // --- Assume EchoTool is defined as in the STDIO example --- use MCP\Server\Tool\Tool as BaseTool; use MCP\Server\Tool\Attribute\Tool as ToolAttribute; // Parameter attribute is on the actual class, not repeated in every snippet. // use MCP\Server\Tool\Attribute\Parameter; #[ToolAttribute(name: "echo", description: "Echoes back the provided message.")] class EchoTool extends BaseTool { protected function doExecute(array $arguments): array { // Changed signature $message = $arguments['message'] ?? 'Default message if not provided'; // Added logic return [$this->createTextContent("Echo: " . $message)]; } } // --- Assume GreetingResource is defined as in the STDIO example --- use MCP\Server\Resource\Resource as BaseResource; use MCP\Server\Resource\Attribute\ResourceUri; use MCP\Server\Resource\ResourceContents; #[ResourceUri(uri: "greeting://welcome", description: "Provides a welcome greeting.")] class GreetingResource extends BaseResource { public function __construct() { parent::__construct("Welcome Greeting", "text/plain"); } public function read(array $parameters = []): ResourceContents { return $this->text("Hello from your MCP server!"); } } // 1. Create PSR-7 request and factories $psr17Factory = new Psr17Factory(); $requestCreator = new ServerRequestCreator( $psr17Factory, // ServerRequestFactory $psr17Factory, // UriFactory $psr17Factory, // UploadedFileFactory $psr17Factory // StreamFactory ); $request = $requestCreator->fromGlobals(); // 2. Instantiate the Server $server = new Server('MySimpleServer (HTTP)', '1.0.0'); // 3. Setup and Add Capabilities (Tools, Resources) // Similar to STDIO example: $toolsCapability = new ToolsCapability(); $toolsCapability->addTool(new EchoTool()); $server->addCapability($toolsCapability); $resourcesCapability = new ResourcesCapability(); $resourcesCapability->addResource(new GreetingResource()); $server->addCapability($resourcesCapability); // 4. Instantiate and connect HttpTransport $transport = new HttpTransport($request, $psr17Factory, $psr17Factory); $server->connect($transport); // 5. Run the Server // For HTTP, run() processes the current request and sends the response. $server->run();
Running the HTTP Server:
Use PHP's built-in web server for development:
php -S localhost:8000 examples/http_server.php
Then, send MCP requests using an HTTP client like curl
.
Example curl
request for the echo
tool:
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"echo","arguments":{"message":"Hello HTTP"}},"id":1}' http://localhost:8000/
Expected JSON-RPC Response:
{"jsonrpc":"2.0","result":{"content":[{"type":"text","text":"Echo: Hello HTTP"}],"isError":false},"id":1}
Using with PHP-FPM or mod_php
The examples/http_server.php
script is designed to be compatible with common PHP web server setups like Apache or Nginx using PHP-FPM or mod_php
.
Key Points:
- Single Request Processing: The script, particularly
(new HttpTransport(...))->run()
, processes a single HTTP request and then exits. This model fits perfectly with how PHP-FPM andmod_php
handle PHP requests. Each incoming HTTP request to your web server that's routed to this script will be a fresh execution. - PSR-7
fromGlobals()
: The use ofServerRequestCreator::fromGlobals()
correctly populates the PSR-7 request object from PHP's global variables (e.g.,$_SERVER
,$_POST
), which are populated by the web server. - Output Handling: The SDK's
HttpTransport
uses a SAPI emitter (likeLaminas\HttpHandlerRunner\Emitter\SapiEmitter
) internally, which correctly sends headers and body content to the web server for transmission to the client.
Conceptual Webserver Configuration:
You would configure your web server (e.g., Nginx or Apache) to pass requests to your http_server.php
script.
-
Nginx Example (conceptual):
server { listen 80; server_name your-mcp-server.example.com; root /path/to/your/project/examples; # Or wherever http_server.php is location / { try_files $uri /http_server.php$is_args$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust to your PHP-FPM version/socket fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
-
Apache Example (conceptual, using
.htaccess
in theexamples
directory ifAllowOverride
is enabled):RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ http_server.php [L,QSA]
Ensure
mod_rewrite
is enabled. Your Apache VirtualHost would also need to be configured to execute PHP scripts.
Running the Server:
Unlike the php -S localhost:8000 examples/http_server.php
command (which runs PHP's built-in development server), in a PHP-FPM/mod_php setup, your main web server (Nginx/Apache) is responsible for receiving the request and passing it to the PHP interpreter. You don't run a separate PHP command to "start" the server in the same way.
The curl
commands provided earlier for testing the HTTP server would remain the same, targeting the URL configured in your web server (e.g., http://your-mcp-server.example.com/
).
Further Information
For more detailed information on MCP concepts, capabilities, and advanced usage, please refer to the source code and the official Model Context Protocol documentation.