'add', 'description' => '计算两个数字的和', 'toolType' => 'function', 'parameters' => [ 'a' => [ 'description' => '第一个加数(必填)', 'example' => 10 ], 'b' => [ 'description' => '第二个加数(必填)', 'example' => 20 ] ], 'metadata' => [ 'capability' => [ 'streaming' => false, 'batch' => true, 'transactional' => false ], 'version' => '1.0.0', 'vendor' => 'MyCompany', 'protocol' => 'json-rpc-2.0' ] ]; public function sse() { // 设置 CORS 头 header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization'); // 处理 OPTIONS 预检请求 if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } // 设置 SSE 响应头 header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); header('X-Accel-Buffering: no'); // 获取原始输入 $input = file_get_contents('php://input'); file_put_contents('mcp_debug.log', date('Y-m-d H:i:s').' Raw input: '.$input.PHP_EOL, FILE_APPEND); // 解析 JSON-RPC 请求 $request = json_decode($input, true); // 处理请求 if (isset($request['method'])) { switch($request['method']) { case 'initialize': $this->handleInitializeRequest($request); break; case 'function': case 'tools/call': // 新增支持tools/call方法 $this->handleFunctionRequest($request); break; case 'ping': $this->sendJsonRpcResponse($request['id'] ?? null, ['result' => 'pong']); break; case 'notifications/initialized': $this->sendJsonRpcResponse($request['id'] ?? null, ['result' => 'success']); break; case 'tools/list': $this->sendJsonRpcResponse($request['id'] ?? null, ['tools' => [self::ADD_FUNCTION]]); break; default: $this->handleOtherRequests($request); } } else { $this->handleOtherRequests($request); } } /** * 处理初始化请求 */ private function handleInitializeRequest($request) { $id = $request['id'] ?? null; // 记录完整的初始化请求内容 file_put_contents('mcp_debug.log', "Received initialize request: " . json_encode($request) . PHP_EOL, FILE_APPEND); // 发送初始化响应 $this->sendJsonRpcResponse($id, [ 'capabilities' => [ 'progress' => true, 'functions' => [self::ADD_FUNCTION] ], 'serverInfo' => [ 'name' => 'Calculator Server', 'version' => '1.0.0', 'vendor' => 'MyCompany', 'license' => 'MIT' ], 'protocolVersion' => '2025-03-26' ]); } /** * 处理函数调用请求 */ public function handleFunctionRequest($request) { $id = $request['id'] ?? null; $function = $request['params']['function'] ?? ''; $arguments = $request['params']['arguments'] ?? []; // // 恢复函数名验证 // if ($function !== 'add') { // $this->sendJsonRpcResponse($id, [ // 'error' => [ // 'code' => -32601, // 'message' => 'Unsupported function', // 'data' => "Function not found: $function" // ] // ]); // return; // } // // 提取参数验证为独立方法 // $validationResult = $this->validateAddParameters($arguments, $id); // if ($validationResult !== true) { // $this->sendJsonRpcResponse($id, $validationResult); // return; // } // 解构参数 $a = $arguments['a'] ?? 0; $b = $arguments['b'] ?? 0; // 发送进度通知 $this->sendNotification('progress', ['id' => $id, 'message' => '正在计算...']); // 模拟处理延迟 sleep(1); $result = $this->calculateAdd($a, $b); $this->sendJsonRpcResponse($id, [ // 'result' => [ 'operation' => 'add', 'result' => $result, 'expression' => "$a + $b = $result", 'timestamp' => time() // ] ]); } /** * 验证加法参数 * @param array $arguments * @param mixed $id * @return array|bool 返回true表示验证通过,否则返回错误响应数组 */ private function validateAddParameters(array $arguments, $id) { if (!isset($arguments['a'], $arguments['b'])) { return [ 'error' => [ 'code' => -32602, 'message' => 'Invalid params', 'data' => 'Missing required parameters: a and b' ] ]; } if (!is_numeric($arguments['a']) || !is_numeric($arguments['b'])) { return [ 'error' => [ 'code' => -32602, 'message' => 'Invalid params', 'data' => 'Parameters must be numbers' ] ]; } return true; } /** * 处理其他类型的请求 */ private function handleOtherRequests($request) { if (!$request || !isset($request['function'])) { $this->sendJsonRpcResponse($request['id'] ?? null, ['error' => 'Invalid request format']); return; } if ($request['function'] === 'add' || $request['function'] === 'tools/call') { $a = $request['params']['a'] ?? 0; $b = $request['params']['b'] ?? 0; if (!is_numeric($a) || !is_numeric($b)) { $this->sendEvent('error', 'Parameters must be numbers'); return; } // 模拟处理延迟 sleep(1); $result = $this->calculateAdd($a, $b); $this->sendEvent('result', [ 'operation' => 'add', 'result' => $result, 'expression' => "$a + $b = $result" ]); } else { $this->sendEvent('error', 'Unsupported function: ' . $request['function']); } } /** * 执行加法计算 */ private function calculateAdd(float $a, float $b): float { return $a + $b; } /** * 发送 JSON-RPC 响应 */ private function sendJsonRpcResponse($id, $resultOrError) { $response = [ 'jsonrpc' => '2.0', 'id' => $id ]; if (isset($resultOrError['error'])) { $response['error'] = $resultOrError['error']; } else { $response['result'] = $resultOrError; } $this->sendStreamData(json_encode($response, JSON_UNESCAPED_UNICODE)); } /** * 发送通知(用于进度更新等) */ private function sendNotification($method, $params) { $notification = [ 'jsonrpc' => '2.0', 'method' => $method, 'params' => $params ]; $this->sendStreamData(json_encode($notification, JSON_UNESCAPED_UNICODE)); } /** * 发送标准 SSE 事件 */ private function sendEvent($type, $data) { $jsonData = json_encode($data, JSON_UNESCAPED_UNICODE); echo "event: $type\n"; echo "data: $jsonData\n\n"; $this->flushBuffers(); file_put_contents('mcp_debug.log', "Sent event: $type - $jsonData".PHP_EOL, FILE_APPEND); } /** * 发送流数据 */ private function sendStreamData(string $data) { echo "data: $data\n\n"; $this->flushBuffers(); file_put_contents('mcp_debug.log', "JSON-RPC Response: $data".PHP_EOL, FILE_APPEND); } /** * 刷新输出缓冲区 */ private function flushBuffers() { ob_flush(); flush(); } }