Install
$ agentstack add mcp-llm-agents-php-mcp-server ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
PHP MCP Server SDK
[](https://packagist.org/packages/llm/mcp-server) [](https://packagist.org/packages/llm/mcp-server) [](LICENSE) [](https://packagist.org/packages/llm/mcp-server)
A comprehensive PHP SDK for building Model Context Protocol (MCP) servers. Create production-ready MCP servers in PHP with modern architecture, flexible transport options, and comprehensive feature support.
Table of Contents
- [Requirements](#requirements)
- [Installation](#installation)
- [Framework Integration](#framework-integration)
- [Quick Start](#quick-start)
- [Core Concepts](#core-concepts)
- [Transport Options](#transport-options)
- [STDIO Transport](#stdio-transport-recommended-for-cli)
- [HTTP Transport with SSE](#http-transport-with-sse)
- [Streamable HTTP Transport](#streamable-http-transport)
- [Working with Tools](#working-with-tools)
- [Basic Tool Registration](#basic-tool-registration)
- [Advanced Tool with Multiple Content Types](#advanced-tool-with-multiple-content-types)
- [Error Handling in Tools](#error-handling-in-tools)
- [Working with Resources](#working-with-resources)
- [Working with Prompts](#working-with-prompts)
- [HTTP Middleware](#http-middleware)
- [Built-in Middleware](#built-in-middleware)
- [CORS Middleware](#cors-middleware)
- [Authentication Middleware](#authentication-middleware)
- [Custom Middleware](#custom-middleware)
- [Advanced Configuration](#advanced-configuration)
- [Complete Server Setup](#complete-server-setup)
- [Event Store for Resumability](#event-store-for-resumability)
- [Common Patterns](#common-patterns)
- [Handler Factory Pattern](#handler-factory-pattern)
- [Decorator Pattern for Handlers](#decorator-pattern-for-handlers)
- [Class-Based Tool Handlers with Schema Mapping](#class-based-tool-handlers-with-schema-mapping)
- [Ecosystem & Extensions](#ecosystem--extensions)
- [Contributing](#contributing)
- [License](#license)
- [Acknowledgments](#acknowledgments)
> This SDK implements the MCP 2025-03-26 specification with full backward compatibility support.
Features
- Complete MCP Implementation: Full support for tools, resources, prompts, and logging
- Multiple Transport Options: STDIO, HTTP with SSE, and streamable HTTP transports
- Session Management: Built-in session handling with configurable storage backends
- Event-Driven Architecture: ReactPHP-powered asynchronous operations
- Middleware Support: PSR-15 compatible HTTP middleware system
- Type Safety: Full PHP 8.3+ type declarations and comprehensive error handling
- Extensible Design: Pluggable components with clear interfaces
- Production Ready: Comprehensive logging, error handling, and testing support
What's NOT Included
This SDK focuses on core MCP functionality and intentionally does not include:
- Resource Discovery: Automatic scanning and registration of resources from filesystem or annotations
- Schema Generation: Automatic generation of JSON schemas from PHP code or docblocks
- Request Validation: Built-in validation of incoming requests against defined schemas
- Framework Integration: Direct integration with web frameworks (Laravel, Symfony, etc.)
Why? These features are better implemented as separate packages or framework-specific bridges that can:
- Provide opinionated conventions for specific use cases
- Integrate deeply with framework ecosystems
- Offer different approaches to schema management
- Maintain focused, single-responsibility packages
Requirements
- PHP >= 8.3 (required for advanced type features and performance)
- Extensions:
json,mbstring,pcre(typically bundled with PHP)
Installation
composer require llm/mcp-server
Framework Integration
For enhanced developer experience with automatic discovery and validation:
Spiral Framework: Use the spiral/mcp-server bridge
composer require spiral/mcp-server
Other Frameworks: Framework-specific bridges are planned. Contributions welcome!
Quick Start
Here's a minimal working example that demonstrates core functionality:
['type' => 'string', 'description' => 'Name to greet']],
);
$greetHandler = new CallableHandler(function($args) {
return [TextContent::make("Hello, " . ($args['name'] ?? 'World') . "!")];
});
$registry->registerTool($greetTool, $greetHandler);
// Create and start server
$server = new Server($protocol, $sessionManager, $logger);
$transport = new StdioServerTransport();
$server->listen($transport);
Expected Output: The server will listen on STDIN/STDOUT and respond to MCP requests.
To Test: Save as server.php and run php server.php, then send MCP messages via STDIN.
Core Concepts
Architecture Overview
The SDK follows a layered architecture:
┌─────────────────┐
│ Transport │ (STDIO, HTTP, Streamable HTTP)
├─────────────────┤
│ Protocol │ (MCP message handling)
├─────────────────┤
│ Dispatcher │ (Route requests to handlers)
├─────────────────┤
│ Registry │ (Tools, Resources, Prompts)
├─────────────────┤
│ Handlers │ (Your business logic)
└─────────────────┘
Key Components
- Server: Main orchestrator that binds protocol to transport
- Protocol: Handles MCP message parsing and session management
- Registry: Manages tools, resources, and prompts registration
- Transport: Communication layer (STDIO, HTTP, etc.)
- Session Manager: Handles client sessions and state persistence
Transport Options
STDIO Transport (Recommended for CLI)
Perfect for command-line tools and process-based communication:
use Mcp\Server\Transports\StdioServerTransport;
$transport = new StdioServerTransport();
$server->listen($transport);
Use Cases: CLI tools, subprocess communication, development/testing
HTTP Transport with SSE
For web-based applications with real-time communication:
use Mcp\Server\Transports\HttpServer;
use Mcp\Server\Transports\HttpServerTransport;
use React\EventLoop\Loop;
$loop = Loop::get();
$httpServer = new HttpServer($loop, '127.0.0.1', 8080, '/mcp');
$transport = new HttpServerTransport($httpServer);
$server->listen($transport);
Use Cases: Web applications, browser-based clients, dashboard integrations
Streamable HTTP Transport
Advanced HTTP transport with JSON response and resumability support:
use Mcp\Server\Transports\StreamableHttpServerTransport;
use Mcp\Server\Defaults\InMemoryEventStore;
$eventStore = new InMemoryEventStore();
$transport = new StreamableHttpServerTransport(
httpServer: $httpServer,
enableJsonResponse: true,
stateless: false,
eventStore: $eventStore
);
$server->listen($transport);
Use Cases: High-performance applications, stateless deployments, fault-tolerant systems
Working with Tools
Tools are executable functions that AI assistants can call to perform actions.
Basic Tool Registration
use PhpMcp\Schema\Tool;
use Mcp\Server\Defaults\CallableHandler;
use PhpMcp\Schema\Content\TextContent;
// Define tool schema
$calculatorTool = Tool::make(
name: 'calculator',
description: 'Performs basic mathematical operations',
inputSchema: [
'operation' => [
'type' => 'string',
'enum' => ['add', 'subtract', 'multiply', 'divide'],
'description' => 'The operation to perform'
],
'a' => ['type' => 'number', 'description' => 'First number'],
'b' => ['type' => 'number', 'description' => 'Second number']
]
);
// Create handler
$calculatorHandler = new CallableHandler(function($args) {
$a = $args['a'];
$b = $args['b'];
$operation = $args['operation'];
$result = match($operation) {
'add' => $a + $b,
'subtract' => $a - $b,
'multiply' => $a * $b,
'divide' => $b !== 0 ? $a / $b : throw new InvalidArgumentException('Division by zero'),
default => throw new InvalidArgumentException('Unknown operation')
};
return [TextContent::make("Result: $result")];
});
$registry->registerTool($calculatorTool, $calculatorHandler);
Advanced Tool with Multiple Content Types
use PhpMcp\Schema\Content\ImageContent;
use PhpMcp\Schema\Content\BlobResourceContents;
$imageProcessorHandler = new CallableHandler(function($args) {
$imagePath = $args['image_path'];
// Process image (example)
$imageData = file_get_contents($imagePath);
$base64Image = base64_encode($imageData);
return [
TextContent::make("Processed image: $imagePath"),
ImageContent::make($base64Image, 'image/jpeg'),
];
});
Error Handling in Tools
use Mcp\Server\Exception\ValidationException;
$validatedToolHandler = new CallableHandler(function($args) {
if (!isset($args['required_param'])) {
throw new ValidationException([
[
'pointer' => '/required_param',
'keyword' => 'required',
'message' => 'This parameter is required'
]
]);
}
// Tool logic here
return [TextContent::make('Success!')];
});
Working with Resources
Resources provide read-only access to data that AI assistants can reference.
Static Resources
use PhpMcp\Schema\Resource;
use PhpMcp\Schema\Content\TextResourceContents;
$docResource = Resource::make(
uri: 'file:///docs/readme.txt',
name: 'README Documentation',
description: 'Application documentation',
mimeType: 'text/plain'
);
$docHandler = new CallableHandler(function($args) {
$content = file_get_contents(__DIR__ . '/README.txt');
return [TextResourceContents::make($args['uri'], 'text/plain', $content)];
});
$registry->registerResource($docResource, $docHandler);
Dynamic Resource Templates
Resource templates use URI patterns to handle multiple similar resources:
use PhpMcp\Schema\ResourceTemplate;
$userTemplate = ResourceTemplate::make(
uriTemplate: 'user://{user_id}/profile',
name: 'User Profile Template',
description: 'Access user profile data',
mimeType: 'application/json'
);
$userHandler = new CallableHandler(function($args) {
$userId = $args['user_id'];
// Fetch user data from database/API
$userData = getUserData($userId);
return [TextResourceContents::make(
$args['uri'],
'application/json',
json_encode($userData)
)];
});
$registry->registerResourceTemplate($userTemplate, $userHandler);
Resource with Completion Providers
use Mcp\Server\Defaults\ListCompletionProvider;
$completionProvider = new ListCompletionProvider(['admin', 'user', 'guest']);
$registry->registerResourceTemplate(
$userTemplate,
$userHandler,
completionProviders: ['user_id' => $completionProvider]
);
Working with Prompts
Prompts provide templated text generation for AI assistants.
Basic Prompt
use PhpMcp\Schema\Prompt;
use PhpMcp\Schema\Content\PromptMessage;
use PhpMcp\Schema\Enum\Role;
$codeReviewPrompt = Prompt::make(
name: 'code_review',
description: 'Generate code review prompt',
arguments: [
'code' => ['type' => 'string', 'required' => true, 'description' => 'Code to review'],
'language' => ['type' => 'string', 'description' => 'Programming language']
]
);
$codeReviewHandler = new CallableHandler(function($args) {
$code = $args['code'];
$language = $args['language'] ?? 'unknown';
$systemPrompt = "You are a senior software engineer reviewing {$language} code.";
$userPrompt = "Please review this code:\n\n```{$language}\n{$code}\n```";
return [
PromptMessage::make(Role::User, TextContent::make($systemPrompt)),
PromptMessage::make(Role::User, TextContent::make($userPrompt))
];
});
$registry->registerPrompt($codeReviewPrompt, $codeReviewHandler);
Advanced Prompt with Multiple Message Types
$conversationPrompt = new CallableHandler(function($args) {
$context = $args['context'];
$question = $args['question'];
return [
[
'role' => 'user',
'content' => [
'type' => 'text',
'text' => "Context: $context"
]
],
[
'role' => 'user',
'content' => [
'type' => 'text',
'text' => "Question: $question"
]
]
];
});
Session Management
Custom Session Handlers
Implement the SessionHandlerInterface for custom storage:
use Mcp\Server\Contracts\SessionHandlerInterface;
class DatabaseSessionHandler implements SessionHandlerInterface
{
public function __construct(private PDO $pdo) {}
public function read(string $id): string|false
{
$stmt = $this->pdo->prepare('SELECT data FROM sessions WHERE id = ?');
$stmt->execute([$id]);
return $stmt->fetchColumn() ?: false;
}
public function write(string $id, string $data): bool
{
$stmt = $this->pdo->prepare(
'INSERT INTO sessions (id, data, updated_at) VALUES (?, ?, NOW())
ON DUPLICATE KEY UPDATE data = VALUES(data), updated_at = NOW()'
);
return $stmt->execute([$id, $data]);
}
public function destroy(string $id): bool
{
$stmt = $this->pdo->prepare('DELETE FROM sessions WHERE id = ?');
return $stmt->execute([$id]);
}
public function gc(int $maxLifetime): array
{
$stmt = $this->pdo->prepare(
'DELETE FROM sessions WHERE updated_at execute([$maxLifetime]);
return []; // Return deleted session IDs if needed
}
}
Cache-Based Session Storage
use Mcp\Server\Session\CacheSessionHandler;
use Mcp\Server\Defaults\FileCache;
$cache = new FileCache('/tmp/mcp_sessions.cache');
$sessionHandler = new CacheSessionHandler($cache, ttl: 7200);
$sessionManager = new SessionManager($sessionHandler, $logger, $loop);
HTTP Middleware
Built-in Middleware
CORS Middleware
use Mcp\Server\Transports\Middleware\CorsMiddleware;
$corsMiddleware = new CorsMiddleware(
allowedOrigins: ['https://myapp.com', 'https://localhost:3000'],
allowedMethods: ['GET', 'POST', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Mcp-Session-Id'],
maxAge: 86400,
);
$httpServer = new HttpServer(
$loop,
'127.0.0.1',
8080,
'/mcp',
middleware: [$corsMiddleware],
);
Authentication Middleware
use Mcp\Server\Transports\Middleware\AuthenticationMiddleware;
$authMiddleware = new AuthenticationMiddleware(
authenticator: function($request, $authHeader) {
// Bearer token validation
if (!str_starts_with($authHeader, 'Bearer ')) {
return false;
}
$token = substr($authHeader, 7);
return validateToken($token); // Your validation logic
},
protectedPaths: ['/mcp']
);
Custom Middleware
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class LoggingMiddleware implements MiddlewareInterface
{
public function __construct(private LoggerInterface $logger) {}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$start = microtime(true);
$this->logger->info('Request started', [
'method' => $request->getMethod(),
'path' => $request->getUri()->getPath()
]);
$response = $handler->handle($request);
$duration = microtim
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [llm-agents-php](https://github.com/llm-agents-php)
- **Source:** [llm-agents-php/mcp-server](https://github.com/llm-agents-php/mcp-server)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.