Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.08% covered (success)
98.08%
51 / 52
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
McpServerCommand
98.08% covered (success)
98.08%
51 / 52
75.00% covered (warning)
75.00%
3 / 4
10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 configure
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 showServerInfo
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
5
1<?php
2
3/**
4 * phpMyFAQ MCP Server Console Command
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * @package   phpMyFAQ
11 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2025 phpMyFAQ Team
13 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14 * @link      https://www.phpmyfaq.de
15 * @since     2025-08-16
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Command;
21
22use Exception;
23use phpMyFAQ\Service\McpServer\McpServerRuntimeInterface;
24use Symfony\Component\Console\Attribute\AsCommand;
25use Symfony\Component\Console\Command\Command;
26use Symfony\Component\Console\Input\InputInterface;
27use Symfony\Component\Console\Input\InputOption;
28use Symfony\Component\Console\Output\OutputInterface;
29use Symfony\Component\Console\Style\SymfonyStyle;
30
31/**
32 * Class McpServerCommand
33 *
34 * Console command to run the phpMyFAQ MCP (Model Context Protocol) server.
35 * This command starts the MCP server that allows LLM models to query
36 * the phpMyFAQ knowledge base through the MCP protocol.
37 */
38#[AsCommand(name: 'phpmyfaq:mcp:server', description: 'Run the phpMyFAQ MCP server for LLM integration')]
39class McpServerCommand extends Command
40{
41    public function __construct(
42        private readonly McpServerRuntimeInterface $phpMyFaqMcpServer,
43    ) {
44        parent::__construct();
45    }
46
47    protected function configure(): void
48    {
49        $this
50            ->setDescription(description: 'Run the phpMyFAQ MCP server for LLM integration')
51            ->setHelp(
52                help: 'This command starts the MCP server that allows LLM models to search and query phpMyFAQ installations.',
53            )
54            ->addOption(
55                name: 'info',
56                shortcut: 'i',
57                mode: InputOption::VALUE_NONE,
58                description: 'Show server information instead of running the server',
59            );
60    }
61
62    protected function execute(InputInterface $input, OutputInterface $output): int
63    {
64        $symfonyStyle = new SymfonyStyle($input, $output);
65
66        if ($input->getOption(name: 'info')) {
67            $this->showServerInfo($symfonyStyle);
68            return Command::SUCCESS;
69        }
70
71        $symfonyStyle->title(message: 'phpMyFAQ MCP Server');
72        $symfonyStyle->info(message: 'Starting MCP server for phpMyFAQ knowledge base...');
73        $symfonyStyle->info(message: 'The server will handle MCP protocol requests from LLM clients.');
74        $symfonyStyle->warning(message: 'Press Ctrl+C to stop the server.');
75
76        try {
77            $this->phpMyFaqMcpServer->runConsole($input, $output);
78            return Command::SUCCESS;
79        } catch (Exception $exception) {
80            $symfonyStyle->error('Failed to start MCP server: ' . $exception->getMessage());
81            return Command::FAILURE;
82        }
83    }
84
85    private function showServerInfo(SymfonyStyle $symfonyStyle): void
86    {
87        $serverInfo = $this->phpMyFaqMcpServer->getServerInfo();
88        $capabilities = $serverInfo['capabilities'] ?? [];
89        $capabilities = is_array($capabilities) ? $capabilities : [];
90
91        $symfonyStyle->title((string) ($serverInfo['name'] ?? ''));
92        $symfonyStyle->definitionList(
93            ['Version' => $serverInfo['version'] ?? ''],
94            ['Description' => $serverInfo['description'] ?? ''],
95            ['Capabilities' => implode(separator: ', ', array: array_keys(array_filter($capabilities)))],
96        );
97
98        $symfonyStyle->section(message: 'Available Tools');
99
100        $toolsTable = [];
101        $tools = $serverInfo['tools'] ?? [];
102        foreach (is_array($tools) ? $tools : [] as $tool) {
103            if (!is_array($tool)) {
104                continue;
105            }
106
107            $toolsTable[] = [(string) ($tool['name'] ?? ''), (string) ($tool['description'] ?? '')];
108        }
109
110        $symfonyStyle->table(['Name', 'Description'], $toolsTable);
111
112        $symfonyStyle->section(message: 'Usage Examples');
113        $symfonyStyle->text([
114            'Start the server:',
115            '  php bin/console phpmyfaq:mcp:server',
116            '',
117            'The server will accept MCP protocol requests and provide access to:',
118            '  • FAQ search functionality',
119            '  • Knowledge base querying',
120            '  • Contextual information for LLM models',
121        ]);
122    }
123}