311 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			311 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| 
								 | 
							
								<?php
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace app\api\controller\mcp;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								class My extends Base
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    // 工具定义常量
							 | 
						|||
| 
								 | 
							
								    private const ADD_FUNCTION = [
							 | 
						|||
| 
								 | 
							
								        [
							 | 
						|||
| 
								 | 
							
								        'name' => '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();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |