diff --git a/application/api/controller/mcp/Mcp.php b/application/api/controller/mcp/Mcp.php index 368f6aa..08c7656 100644 --- a/application/api/controller/mcp/Mcp.php +++ b/application/api/controller/mcp/Mcp.php @@ -6,29 +6,44 @@ class Mcp extends Base { // 工具定义常量 private const ADD_FUNCTION = [ + [ 'name' => 'add', - 'description' => '计算两个数字的和', - 'toolType' => 'function', - 'parameters' => [ + 'description' => "计算两个数字的和", + 'inputSchema' => [ + 'type' => 'object', + 'properties' => [ 'a' => [ 'description' => '第一个加数(必填)', - 'example' => 10 + 'example' => 10, + 'type' => 'number', ], 'b' => [ 'description' => '第二个加数(必填)', - 'example' => 20 + 'example' => 20, + 'type' => 'number', ] + ] + ] + ], + [ + 'name' => 'sub', + 'description' => "计算两个数字的减法", + 'inputSchema' => [ + 'type' => 'object', + 'properties' => [ + 'a' => [ + 'description' => '第一个减数(必填)', + 'example' => 10, + 'type' => 'number', + ], + 'b' => [ + 'description' => '第二个减数(必填)', + 'example' => 20, + 'type' => 'number', + ] + ] + ] ], - 'metadata' => [ - 'capability' => [ - 'streaming' => false, - 'batch' => true, - 'transactional' => false - ], - 'version' => '1.0.0', - 'vendor' => 'MyCompany', - 'protocol' => 'json-rpc-2.0' - ] ]; @@ -75,7 +90,7 @@ class Mcp extends Base $this->sendJsonRpcResponse($request['id'] ?? null, ['result' => 'success']); break; case 'tools/list': - $this->sendJsonRpcResponse($request['id'] ?? null, ['tools' => [self::ADD_FUNCTION]]); + $this->sendJsonRpcResponse($request['id'] ?? null, ['tools' => self::ADD_FUNCTION]); break; default: $this->handleOtherRequests($request); @@ -99,7 +114,7 @@ class Mcp extends Base $this->sendJsonRpcResponse($id, [ 'capabilities' => [ 'progress' => true, - 'functions' => [self::ADD_FUNCTION] + 'functions' => self::ADD_FUNCTION ], 'serverInfo' => [ 'name' => 'Calculator Server', @@ -151,7 +166,7 @@ class Mcp extends Base $result = $this->calculateAdd($a, $b); $this->sendJsonRpcResponse($id, [ -// 'result' => [ +// '' => [ 'operation' => 'add', 'result' => $result, 'expression' => "$a + $b = $result", diff --git a/application/api/controller/mcp/My.php b/application/api/controller/mcp/My.php new file mode 100644 index 0000000..e699127 --- /dev/null +++ b/application/api/controller/mcp/My.php @@ -0,0 +1,311 @@ + 'my', + 'method' => 'my', + 'description' => "介绍焦钰锟是谁的mcp", + 'toolType' => 'function', + 'inputSchema' => [ // 补充完整的参数定义 + 'type' => 'object', + 'properties' => [ + 'desc' => [ + 'description' => '具体想问什么', + 'example' => "所有", + 'type' => 'string' + ] + ], + 'required' => [] + ] + ] + ]; + + + 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'] ?? []; + + + $function = $request['params']['name'] ?? 'my'; + + switch ($function){ + case 'my': + +// $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; +// } +// $result = $this->calculateAdd($a, $b); + // 模拟处理延迟 + sleep(1); + + $result = "我是焦钰锟,今年30岁,男,php程序员,240斤,喜欢玩电脑游戏:死亡搁浅,艾尔登法环"; + //用jsonrpc2.0应答 + $this->sendJsonRpcResponse($id, [ + 'content' => [ + [ + 'type' => 'text', + 'text' => $result // 返回格式化的时间和时区信息 + ] + ] + ]); + +// $this->sendEvent('result', [ +// 'content' => [ +// [ +// 'type' => 'text', +// 'text' => $result // 返回格式化的时间和时区信息 +// ] +// ] +// ]); + + break; + + } + + } + + /** + * 验证加法参数 + * @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'] === 'my' || $request['function'] === 'tools/call') { + $function = $request['params']['name'] ?? 'my'; + + switch ($function){ + case 'my': + +// $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; +// } +// $result = $this->calculateAdd($a, $b); + // 模拟处理延迟 + sleep(1); + + $result = "我是焦钰锟,今年30岁,男,php程序员,240斤,喜欢玩电脑游戏:死亡搁浅,艾尔登法环"; + $this->sendEvent('result', [ + 'operation' => 'my', + 'result' => $result, + 'expression' =>$result + ]); + + + break; + + } + + + + + } 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(); + } +} \ No newline at end of file diff --git a/application/api/controller/sse/Demo.php b/application/api/controller/sse/Demo.php new file mode 100644 index 0000000..86496fe --- /dev/null +++ b/application/api/controller/sse/Demo.php @@ -0,0 +1,44 @@ + date('Y-m-d H:i:s'), + 'message' => 'hallo word ' . ($i+1) + ]; + + // 发送数据 + echo "data: " . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n"; + + // 刷新输出缓冲 + flush(); + ob_flush(); + + // 休眠1秒 + sleep(1); + } + + // 结束连接 + echo "data: {\"complete\":true}\n\n"; + ob_end_flush(); + } +} \ No newline at end of file