### Basic Server Setup Source: https://github.com/dtyq/php-mcp/blob/master/docs/cn/server/stdio-server.md This snippet shows how to set up a basic STDIO server with PHP MCP, including dependency injection, configuration, and starting the server. ```php services[\Psr\Log\LoggerInterface::class] = new \Psr\Log\NullLogger(); $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; // 配置 $config = [ 'sdk_name' => 'my-mcp-server', 'transports' => [ 'stdio' => [ 'enabled' => true, 'buffer_size' => 8192, 'timeout' => 30, 'validate_messages' => true, ], ], ]; // 创建应用程序和服务器 $app = new Application($container, $config); $server = new McpServer('my-server', '1.0.0', $app); // 启动 STDIO 传输 $server->stdio(); ``` -------------------------------- ### Add Resources Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/quick-start.md Example of how to provide data access through resources in PHP-MCP. ```php use Dtyq\PhpMcp\Server\FastMcp\Resources\RegisteredResource; use Dtyq\PhpMcp\Types\Resources\Resource; use Dtyq\PhpMcp\Types\Resources\TextResourceContents; function createTimeResource(): RegisteredResource { $resource = new Resource( 'time://current', 'Current Time', 'Get the current time', 'text/plain' ); return new RegisteredResource($resource, function (string $uri): TextResourceContents { return new TextResourceContents($uri, date('Y-m-d H:i:s'), 'text/plain'); }); } $server->registerResource(createTimeResource()); ``` -------------------------------- ### Client Configuration Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/http-client.md Example of a general client configuration array. ```php $config = [ 'sdk_name' => 'my-http-client', 'timeout' => 30, // Default timeout 'max_retries' => 3, // Maximum retry attempts 'retry_delay' => 1000, // Retry delay in milliseconds 'logging' => [ 'level' => 'info', // Log level 'enabled' => true, // Enable logging ], 'http' => [ 'user_agent' => 'PHP-MCP-Client/1.0', // Default User-Agent 'verify_ssl' => true, // SSL verification 'follow_redirects' => true, // Follow HTTP redirects ], ]; ``` -------------------------------- ### Basic Client Setup Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/stdio-client.md Demonstrates how to set up a basic STDIO client connection to the Sequential Thinking MCP Server. ```php services[\Psr\Log\LoggerInterface::class] = new class extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []): void { $timestamp = date('Y-m-d H:i:s'); $contextStr = empty($context) ? '' : ' ' . json_encode($context); echo "[{$timestamp}] {$level}: {$message}{$contextStr}\n"; } }; $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; // Configuration $config = ['sdk_name' => 'my-mcp-client']; // Create application and client $app = new Application($container, $config); $client = new McpClient('my-client', '1.0.0', $app); // ✅ Recommended: Use typed configuration with shortcut method use Dtyq\PhpMcp\Client\Configuration\StdioConfig; // Connect to Sequential Thinking MCP Server $config = new StdioConfig('npx', ['-y', '@modelcontextprotocol/server-sequential-thinking']); $session = $client->stdio($config); // Initialize session $session->initialize(); echo "Connected to Sequential Thinking MCP server!\n"; ``` -------------------------------- ### Complete STDIO Server Example Source: https://github.com/dtyq/php-mcp/blob/master/docs/cn/server/stdio-server.md A full implementation of an STDIO server, including a simple container, configuration, a calculator tool, and server setup. ```php services[\Psr\Log\LoggerInterface::class] = new class extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []): void { $timestamp = date('Y-m-d H:i:s'); $contextStr = empty($context) ? '' : ' ' . json_encode($context); file_put_contents('server.log', "[{$timestamp}] {$level}: {$message}{$contextStr}\n", FILE_APPEND); } }; $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; // 配置 $config = [ 'sdk_name' => 'complete-stdio-server', 'transports' => [ 'stdio' => [ 'enabled' => true, 'buffer_size' => 8192, 'timeout' => 30, 'validate_messages' => true, ], ], ]; // 创建计算器工具 function createCalculatorTool(): RegisteredTool { $tool = new Tool( 'calculate', [ 'type' => 'object', 'properties' => [ 'operation' => ['type' => 'string', 'enum' => ['add', 'subtract', 'multiply', 'divide']], 'a' => ['type' => 'number'], 'b' => ['type' => 'number'], ], 'required' => ['operation', 'a', 'b'], ], '执行数学运算' ); return new RegisteredTool($tool, function (array $args): array { $a = $args['a'] ?? 0; $b = $args['b'] ?? 0; $operation = $args['operation'] ?? 'add'; switch ($operation) { case 'add': $result = $a + $b; break; case 'subtract': $result = $a - $b; break; case 'multiply': $result = $a * $b; break; case 'divide': if ($b == 0) throw new \Dtyq\PhpMcp\Shared\Exceptions\ValidationError('除零错误'); $result = $a / $b; break; default: throw new \Dtyq\PhpMcp\Shared\Exceptions\ValidationError('未知操作: ' . $operation); } return [ 'operation' => $operation, 'operands' => [$a, $b], 'result' => $result, ]; }); } // 创建应用程序和服务器 $app = new Application($container, $config); $server = new McpServer('complete-stdio-server', '1.0.0', $app); // 注册组件 $server ->registerTool(createCalculatorTool()) ->stdio(); // 启动 STDIO 传输 ``` -------------------------------- ### Working with Prompts Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/http-client.md Demonstrates listing available prompts, showing prompt arguments, and getting a dynamic prompt with parameters. ```php use Dtyq\PhpMcp\Types\Content\TextContent; // List available prompts $promptsResult = $session->listPrompts(); echo "Available prompts:\n"; foreach ($promptsResult->getPrompts() as $prompt) { echo "- {$prompt->getName()}: {$prompt->getDescription()}\n"; // Show prompt arguments foreach ($prompt->getArguments() as $arg) { $required = $arg->isRequired() ? ' (required)' : ' (optional)'; echo " * {$arg->getName()}: {$arg->getDescription()}{$required}\n"; } } // Get a dynamic prompt try { $promptResult = $session->getPrompt('email_template', [ 'type' => 'welcome', 'user_name' => 'John Doe', 'company' => 'Acme Corp', ]); echo "Email Template: " . ($promptResult->getDescription() ?? 'No description') . "\n"; echo "Generated Content:\n"; foreach ($promptResult->getMessages() as $message) { $content = $message->getContent(); if ($content instanceof TextContent) { echo "- Role: {$message->getRole()}\n"; echo " Content: {$content->getText()}\n"; } } } catch (Exception $e) { echo "Prompt failed: " . $e->getMessage() . "\n"; } ``` -------------------------------- ### My First Server (my-server.php) Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/quick-start.md Creates a simple MCP server with a greeting tool. ```php services[\Psr\Log\LoggerInterface::class] = new \Psr\Log\NullLogger(); $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; // Create a simple greeting tool function createGreetingTool(): RegisteredTool { $tool = new Tool( 'greet', [ 'type' => 'object', 'properties' => [ 'name' => ['type' => 'string', 'description' => 'Name to greet'], ], 'required' => ['name'], ], 'Greet someone by name' ); return new RegisteredTool($tool, function (array $args): string { $name = $args['name'] ?? 'World'; return "Hello, {$name}! Welcome to PHP MCP!"; }); } // Create and configure server $config = ['sdk_name' => 'my-first-server']; $app = new Application($container, $config); $server = new McpServer('my-first-server', '1.0.0', $app); // Register the tool and start server $server ->registerTool(createGreetingTool()) ->stdio(); ``` -------------------------------- ### Basic HTTP Client Setup Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/http-client.md Demonstrates how to set up a basic HTTP client, including dependency injection, configuration, and initializing a session with a typed HttpConfig. ```php services[\Psr\Log\LoggerInterface::class] = new class extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []): void { $timestamp = date('Y-m-d H:i:s'); $contextStr = empty($context) ? '' : ' ' . json_encode($context); echo "[{$timestamp}] {$level}: {$message}{$contextStr}\n"; } }; $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; // Configuration $config = ['sdk_name' => 'my-http-client']; // Create application and client $app = new Application($container, $config); $client = new McpClient('my-http-client', '1.0.0', $app); // ✅ Recommended: Use typed configuration with shortcut method use Dtyq\PhpMcp\Client\Configuration\HttpConfig; $config = new HttpConfig('https://your-mcp-server.com/mcp'); $config->setTimeout(30); $config->setHeaders([ 'Authorization' => 'Bearer your-api-token', 'Content-Type' => 'application/json', ]); $session = $client->http($config); // Initialize session $session->initialize(); echo "Connected to HTTP MCP server!\n"; ``` -------------------------------- ### Production Configuration Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/quick-start.md Example of an enhanced container with file logging for production environments. ```php // Enhanced container with file logging $container = new class implements \Psr\Container\ContainerInterface { private array $services = []; public function __construct() { $this->services[\Psr\Log\LoggerInterface::class] = new class extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []): void { $timestamp = date('Y-m-d H:i:s'); $contextStr = empty($context) ? '' : ' ' . json_encode($context); file_put_contents('app.log', "[{$timestamp}] {$level}: {$message}{$contextStr}\n", FILE_APPEND); } }; // ... rest of container setup } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; ``` -------------------------------- ### Business Service Example Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/server/hyperf-integration.md Example of a UserService class demonstrating methods for retrieving user information, user lists based on permissions, report generation, and system statistics. ```php ['id' => 'admin', 'name' => 'Administrator', 'role' => 'admin'], 'user1' => ['id' => 'user1', 'name' => 'Alice', 'role' => 'user'], 'user2' => ['id' => 'user2', 'name' => 'Bob', 'role' => 'user'], ]; if (!isset($users[$userId])) { throw ValidationError::requiredFieldMissing('user', 'User {$userId} not found'); } return ['user' => $users[$userId]]; } public function getUsersListJson(AuthInfo $authInfo): string { $permissions = $authInfo->getMetadata('permissions', []); // Return different user lists based on permissions if (in_array('admin', $permissions)) { $users = [ ['id' => 'admin', 'name' => 'Administrator', 'role' => 'admin'], ['id' => 'user1', 'name' => 'Alice', 'role' => 'user'], ['id' => 'user2', 'name' => 'Bob', 'role' => 'user'], ]; } else { $users = [ ['id' => 'user1', 'name' => 'Alice', 'role' => 'user'], ['id' => 'user2', 'name' => 'Bob', 'role' => 'user'], ]; } return json_encode(['users' => $users]); } public function getReportsJson(): string { return json_encode([ 'reports' => [ ['id' => 1, 'title' => 'Daily Report', 'date' => date('Y-m-d')], ['id' => 2, 'title' => 'Weekly Report', 'date' => date('Y-m-d', strtotime('last monday'))], ] ]); } public function getSystemStats(): array { return [ 'stats' => [ 'total_users' => 3, 'active_sessions' => 1, 'uptime' => '2 hours', 'memory_usage' => round(memory_get_usage() / 1024 / 1024, 2) . ' MB', ] ]; } } ``` -------------------------------- ### Add a Calculator Tool Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/quick-start.md Example of how to create and register a custom tool in PHP-MCP. ```php // Add a calculator tool function createCalculatorTool(): RegisteredTool { $tool = new Tool( 'add', [ 'type' => 'object', 'properties' => [ 'a' => ['type' => 'number'], 'b' => ['type' => 'number'], ], 'required' => ['a', 'b'], ], 'Add two numbers' ); return new RegisteredTool($tool, function (array $args): array { return [ 'result' => ($args['a'] ?? 0) + ($args['b'] ?? 0), 'operation' => 'addition', ]; }); } // Register it in your server $server->registerTool(createCalculatorTool()); ``` -------------------------------- ### Project Setup and Execution Source: https://github.com/dtyq/php-mcp/blob/master/README.md Commands to clone the repository, install dependencies, and run tests. ```bash git clone https://github.com/dtyq/php-mcp.git cd php-mcp composer install composer test ``` -------------------------------- ### Basic Stdio Server Example Source: https://github.com/dtyq/php-mcp/blob/master/src/Server/Transports/README.md Example of how to set up and start a basic MCP server with the Stdio transport. ```php use Dtyq\PhpMcp\Server\McpServer; use Dtyq\PhpMcp\Shared\Kernel\Application; // Create application $app = new Application($container, $config); // Create MCP server $server = new McpServer('my-server', '1.0.0', $app); // Register tools, prompts, resources $server ->registerTool($myTool) ->registerPrompt($myPrompt) ->registerResource($myResource); // Start stdio transport $server->stdio(); ``` -------------------------------- ### Basic HTTP Server Setup Source: https://github.com/dtyq/php-mcp/blob/master/docs/cn/server/http-server.md This snippet demonstrates how to set up a basic HTTP server, process incoming requests, and route them to the MCP endpoints. ```php 'Not Found']); exit; } // 仅允许 POST 方法处理 JSON-RPC if ($method !== 'POST') { http_response_code(405); header('Content-Type: application/json'); echo json_encode([ 'jsonrpc' => '2.0', 'error' => ['code' => -32601, 'message' => 'Method not allowed'], 'id' => null, ]); exit; } // 创建服务器 $container = createContainer(); $app = new Application($container, getConfig()); $server = new McpServer('http-server', '1.0.0', $app); // 注册您的工具、资源和提示 $server ->registerTool(createEchoTool()) ->registerResource(createSystemInfoResource()); // 处理 HTTP 请求并发送响应 $response = $server->http($request); // 发送 HTTP 响应 http_response_code($response->getStatusCode()); foreach ($response->getHeaders() as $name => $values) { foreach ($values as $value) { header("{$name}: {$value}"); } } echo $response->getBody()->getContents(); ``` -------------------------------- ### Custom Authenticator Example Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/server/hyperf-integration.md Example implementation of a custom API key authenticator. ```php getRequestApiKey(); if (empty($apiKey)) { throw new AuthenticationError('No API key provided'); } // Validate API Key $userInfo = $this->validateApiKey($apiKey); if (!$userInfo) { throw new AuthenticationError('Invalid API key'); } return AuthInfo::create( subject: $userInfo['user_id'], scopes: $userInfo['scopes'], metadata: [ 'user' => $userInfo, 'permissions' => $userInfo['permissions'], 'api_key' => $apiKey, ] ); } private function getRequestApiKey(): string { // Support multiple ways to pass API Key $apiKey = $this->request->header('authorization', $this->request->input('key', '')); if (empty($apiKey)) { // Also support X-API-Key header $apiKey = $this->request->header('x-api-key', ''); } if (empty($apiKey)) { return ''; } // Handle Bearer token format if (str_starts_with($apiKey, 'Bearer ')) { $apiKey = substr($apiKey, 7); } return $apiKey; } private function validateApiKey(string $apiKey): ?array { // Mock API Key validation logic // In real projects, this should be database queries or external API calls $validKeys = [ 'admin-key-123' => [ 'user_id' => 'admin', 'scopes' => ['*'], 'permissions' => ['admin', 'user_management', 'read_users', 'read_reports'], ], 'user-key-456' => [ 'user_id' => 'user1', 'scopes' => ['read', 'write'], 'permissions' => ['read_users'], ], ]; return $validKeys[$apiKey] ?? null; } } ``` -------------------------------- ### cURL Testing Examples Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/server/http-server.md Examples of using cURL to test the HTTP server endpoints. ```bash # Test basic endpoint curl -X POST http://localhost/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/list", "id": 1 }' # Test tool call curl -X POST http://localhost/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "web_info", "arguments": {"include_headers": true} }, "id": 2 }' ``` -------------------------------- ### Testing HTTP Servers with cURL Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/http-client.md Examples of using cURL to test HTTP server availability and call tools. ```bash # Test server availability curl -X POST https://your-server.com/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-token" \ -d '{ "jsonrpc": "2.0", "method": "tools/list", "id": 1 }' # Test tool call curl -X POST https://your-server.com/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-token" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "web_info", "arguments": {"include_headers": true} }, "id": 2 }' ``` -------------------------------- ### Complete Annotation Example Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/server/hyperf-integration.md A complete service class demonstrating the usage of McpTool, McpPrompt, and McpResource annotations in Hyperf. ```php $message, 'timestamp' => time(), ]; } #[McpPrompt(description: 'Generate a welcome message')] public function welcome(string $username): GetPromptResult { $message = new PromptMessage( ProtocolConstants::ROLE_USER, new TextContent("Welcome {$username} to our MCP server!") ); return new GetPromptResult('Welcome message', [$message]); } #[McpResource(description: 'Current server status')] public function status(): TextResourceContents { $status = [ 'status' => 'healthy', 'uptime' => time() - $_SERVER['REQUEST_TIME'], 'memory' => round(memory_get_usage() / 1024 / 1024, 2) . ' MB', ]; return new TextResourceContents( 'mcp://server/status', json_encode($status, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), 'application/json' ); } } ``` -------------------------------- ### Complete HTTP Client Implementation Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/http-client.md A full example demonstrating how to set up the container, connect to an MCP server, list and call tools, read resources, and retrieve statistics using the PHP MCP HTTP client. ```php services[\Psr\Log\LoggerInterface::class] = new class extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []): void { $timestamp = date('Y-m-d H:i:s'); $contextStr = empty($context) ? '' : ' ' . json_encode($context, JSON_UNESCAPED_SLASHES); file_put_contents('http-client.log', "[{$timestamp}] {$level}: {$message}{$contextStr}\n", FILE_APPEND); } }; $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; echo "=== PHP MCP HTTP Client Demo ===\n"; try { // Create client $app = new Application($container, ['sdk_name' => 'demo-http-client']); $client = new McpClient('demo-http-client', '1.0.0', $app); // Connect to HTTP server echo "1. Connecting to HTTP server...\n"; $session = $client->connect('http', [ 'url' => 'https://your-mcp-server.com/mcp', 'headers' => [ 'Authorization' => 'Bearer your-token-here', 'Content-Type' => 'application/json', ], 'timeout' => 30, ]); $session->initialize(); echo " ✓ Connected and initialized\n"; // Test tools echo "\n2. Testing tools...\n"; $tools = $session->listTools(); echo " Available tools: " . count($tools->getTools()) . "\n"; if (count($tools->getTools()) > 0) { $firstTool = $tools->getTools()[0]; echo " Testing tool: " . $firstTool->getName() . "\n"; // Call a web-specific tool if ($firstTool->getName() === 'web_info') { $result = $session->callTool('web_info', ['include_headers' => true]); $content = $result->getContent(); if (!empty($content) && $content[0] instanceof TextContent) { $data = json_decode($content[0]->getText(), true); echo " Server info: " . ($data['server_info']['software'] ?? 'unknown') . "\n"; } } } // Test resources echo "\n3. Testing resources...\n"; $resources = $session->listResources(); echo " Available resources: " . count($resources->getResources()) . "\n"; if (count($resources->getResources()) > 0) { $firstResource = $resources->getResources()[0]; echo " Testing resource: " . $firstResource->getUri() . "\n"; $resourceResult = $session->readResource($firstResource->getUri()); foreach ($resourceResult->getContents() as $content) { if ($content instanceof TextResourceContents) { $text = $content->getText(); if ($text !== null) { echo " Resource type: " . $content->getMimeType() . "\n"; echo " Content preview: " . substr($text, 0, 100) . "...\n"; } } } } // Show statistics echo "\n4. Session statistics...\n"; $stats = $client->getStats(); echo " Connection attempts: " . $stats->getConnectionAttempts() . "\n"; echo " Connection errors: " . $stats->getConnectionErrors() . "\n"; echo " Status: " . $stats->getStatus() . "\n"; } catch (Exception $e) { echo "\n❌ Error: " . $e->getMessage() . "\n"; echo "Stack trace:\n" . $e->getTraceAsString() . "\n"; } finally { // Always close the client if (isset($client)) { echo "\n5. Closing client...\n"; $client->close(); echo " ✓ Client closed\n"; } } echo "\n=== Demo completed ===\n"; ``` -------------------------------- ### My First Client (my-client.php) Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/quick-start.md Creates a simple MCP client that connects to the server and calls the greeting tool. ```php services[\Psr\Log\LoggerInterface::class] = new \Psr\Log\NullLogger(); $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; echo "=== My First MCP Client ===\n"; try { // Create client $app = new Application($container, ['sdk_name' => 'my-first-client']); $client = new McpClient('my-first-client', '1.0.0', $app); // Connect to our server using the new shortcut method echo "1. Connecting to server...\n"; $config = new StdioConfig('php', [__DIR__ . '/my-server.php']); $session = $client->stdio($config); $session->initialize(); echo " ✓ Connected!\n"; // List available tools echo "\n2. Available tools:\n"; $tools = $session->listTools(); foreach ($tools->getTools() as $tool) { echo " - {$tool->getName()}: {$tool->getDescription()}\n"; } // Call our greeting tool echo "\n3. Calling greeting tool:\n"; $result = $session->callTool('greet', ['name' => 'PHP Developer']); foreach ($result->getContent() as $content) { if ($content instanceof TextContent) { echo " " . $content->getText() . "\n"; } } echo "\n✅ Success! Your first MCP interaction is complete.\n"; } catch (Exception $e) { echo "\n❌ Error: " . $e->getMessage() . "\n"; } finally { if (isset($client)) { $client->close(); } } ``` -------------------------------- ### Basic HTTP Server Setup Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/server/http-server.md This snippet demonstrates how to set up a basic HTTP server for PHP MCP, including handling requests, routing, and registering tools/resources. ```php 'Not Found']); exit; } // Only allow POST method for JSON-RPC if ($method !== 'POST') { http_response_code(405); header('Content-Type: application/json'); echo json_encode([ 'jsonrpc' => '2.0', 'error' => ['code' => -32601, 'message' => 'Method not allowed'], 'id' => null, ]); exit; } // Create server $container = createContainer(); $app = new Application($container, getConfig()); $server = new McpServer('http-server', '1.0.0', $app); // Register your tools, resources, and prompts $server ->registerTool(createEchoTool()) ->registerResource(createSystemInfoResource()); // Handle HTTP request and send response $response = $server->http($request); // Send HTTP response http_response_code($response->getStatusCode()); foreach ($response->getHeaders() as $name => $values) { foreach ($values as $value) { header("{$name}: {$value}"); } } echo $response->getBody()->getContents(); ``` -------------------------------- ### Complete STDIO Server Implementation Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/server/stdio-server.md A full example of a STDIO server implementation in PHP, including dependency injection, tool registration, and transport startup. ```php services[\Psr\Log\LoggerInterface::class] = new class extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []): void { $timestamp = date('Y-m-d H:i:s'); $contextStr = empty($context) ? '' : ' ' . json_encode($context); file_put_contents('server.log', "[{$timestamp}] {$level}: {$message}{$contextStr}\n", FILE_APPEND); } }; $this->services[\Psr\EventDispatcher\EventDispatcherInterface::class] = new class implements \Psr\EventDispatcher\EventDispatcherInterface { public function dispatch(object $event): object { return $event; } }; } public function get($id) { return $this->services[$id]; } public function has($id): bool { return isset($this->services[$id]); } }; // Configuration $config = [ 'sdk_name' => 'complete-stdio-server', 'transports' => [ 'stdio' => [ 'enabled' => true, 'buffer_size' => 8192, 'timeout' => 30, 'validate_messages' => true, ], ], ]; // Create tools function createCalculatorTool(): RegisteredTool { $tool = new Tool( 'calculate', [ 'type' => 'object', 'properties' => [ 'operation' => ['type' => 'string', 'enum' => ['add', 'subtract', 'multiply', 'divide']], 'a' => ['type' => 'number'], 'b' => ['type' => 'number'], ], 'required' => ['operation', 'a', 'b'], ], 'Perform mathematical operations' ); return new RegisteredTool($tool, function (array $args): array { $a = $args['a'] ?? 0; $b = $args['b'] ?? 0; $operation = $args['operation'] ?? 'add'; switch ($operation) { case 'add': $result = $a + $b; break; case 'subtract': $result = $a - $b; break; case 'multiply': $result = $a * $b; break; case 'divide': if ($b == 0) throw new \Dtyq\PhpMcp\Shared\Exceptions\ValidationError('Division by zero'); $result = $a / $b; break; default: throw new \Dtyq\PhpMcp\Shared\Exceptions\ValidationError('Unknown operation: ' . $operation); } return [ 'operation' => $operation, 'operands' => [$a, $b], 'result' => $result, ]; }); } // Create application and server $app = new Application($container, $config); $server = new McpServer('complete-stdio-server', '1.0.0', $app); // Register components $server ->registerTool(createCalculatorTool()) ->stdio(); // Start STDIO transport ``` -------------------------------- ### Batch Operations Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/http-client.md An example demonstrating how to perform multiple operations efficiently in a batch, including tools and resource reads, and processing the results or errors. ```php // Perform multiple operations efficiently $operations = [ ['type' => 'tool', 'name' => 'web_info', 'args' => ['url' => 'https://example.com']], ['type' => 'tool', 'name' => 'api_call', 'args' => ['endpoint' => '/status']], ['type' => 'resource', 'uri' => 'config://app/settings'], ]; $results = []; foreach ($operations as $op) { try { if ($op['type'] === 'tool') { $result = $session->callTool($op['name'], $op['args']); $results[] = ['type' => 'tool', 'name' => $op['name'], 'result' => $result]; } elseif ($op['type'] === 'resource') { $result = $session->readResource($op['uri']); $results[] = ['type' => 'resource', 'uri' => $op['uri'], 'result' => $result]; } } catch (Exception $e) { $results[] = ['type' => 'error', 'operation' => $op, 'error' => $e->getMessage()]; } } // Process results foreach ($results as $result) { if ($result['type'] === 'error') { echo "Error in operation: " . $result['error'] . "\n"; } else { echo "Success: " . $result['type'] . "\n"; } } ``` -------------------------------- ### Async Operations (Future Enhancement) Source: https://github.com/dtyq/php-mcp/blob/master/docs/en/client/stdio-client.md Conceptual example demonstrating how async tool calls might be handled in the future using Promises. ```php // Note: This is a conceptual example for future async support /* use React\Promise\Promise; // Async tool calls $promises = []; $promises[] = $session->callToolAsync('tool1', ['param' => 'value1']); $promises[] = $session->callToolAsync('tool2', ['param' => 'value2']); Promise::all($promises)->then(function ($results) { foreach ($results as $i => $result) { echo "Tool " . ($i + 1) . " result: " . json_encode($result) . "\n"; } }); */ ``` -------------------------------- ### Basic Server Example Source: https://github.com/dtyq/php-mcp/blob/master/README.md A basic example of setting up an MCP server with a registered tool. ```php 'my-server']); $server = new McpServer('my-server', '1.0.0', $app); // Add a tool $server->registerTool( new \Dtyq\PhpMcp\Types\Tools\Tool('echo', [ 'type' => 'object', 'properties' => ['message' => ['type' => 'string']], 'required' => ['message'] ], 'Echo a message'), function(array $args): array { return ['response' => $args['message']]; } ); // Start server $server->stdio(); // or $server->http($request) ```