Lines
90.00%
36 / 40
Methods
60.00%
3 / 5
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| runConsole | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| getServerInfo | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| faqSearch | 100.00% | 14 / 14 | 100.00% | 1 / 1 | 4 | ||
| buildServer | 86.95% | 20 / 23 | 0.00% | 0 / 1 | 3.02 | ||
| 28 | final readonly class McpSdkRuntime implements McpServerRuntimeInterface | |
| 29 | { | |
| 30 | /** | |
| 31 | * @param array<string, mixed> $serverInfo | |
| 32 | */ | |
| 33 | public function __construct( | |
| 34 | private FaqSearchTool $faqSearchTool, | |
| 35 | private array $serverInfo, | |
| 36 | ) { | |
| 37 | } | |
| 38 | ||
| 39 | public function runConsole(InputInterface $input, OutputInterface $output): void | |
| 40 | { | |
| 41 | $this->buildServer()->run(new StdioTransport()); | |
| 42 | } | |
| 43 | ||
| 44 | public function getServerInfo(): array | |
| 45 | { | |
| 46 | return $this->serverInfo; | |
| 47 | } | |
| 48 | ||
| 49 | /** | |
| 50 | * Adapter method for mcp/sdk manual tool registration. | |
| 51 | * | |
| 52 | * Returns the decoded JSON payload for successful searches and a string for | |
| 53 | * user-facing errors, matching the intent of the current Symfony MCP runtime. | |
| 54 | * | |
| 55 | * @return array<string, mixed>|string | |
| 56 | */ | |
| 57 | public function faqSearch( | |
| 58 | string $query, | |
| 59 | ?int $category_id = null, | |
| 60 | int $limit = 10, | |
| 61 | bool $all_languages = false, | |
| 62 | ): array|string { | |
| 63 | $result = $this->faqSearchTool->execute([ | |
| 64 | 'query' => $query, | |
| 65 | 'category_id' => $category_id, | |
| 66 | 'limit' => $limit, | |
| 67 | 'all_languages' => $all_languages, | |
| 68 | ]); | |
| 69 | ||
| 70 | $content = (string) ($result['content'] ?? ''); | |
| 71 | $decoded = json_decode($content, associative: true); | |
| 72 | if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { | |
| 73 | $normalized = []; | |
| 74 | foreach ($decoded as $decodedKey => $decodedValue) { | |
| 75 | $normalized[(string) $decodedKey] = $decodedValue; | |
| 76 | } | |
| 77 | ||
| 78 | return $normalized; | |
| 79 | } | |
| 80 | ||
| 81 | return $content; | |
| 82 | } | |
| 83 | ||
| 84 | private function buildServer(): Server | |
| 85 | { | |
| 86 | if (!class_exists(Server::class) || !class_exists(StdioTransport::class)) { | |
| 87 | throw new RuntimeException( | |
| 88 | 'The mcp/sdk package is not installed or does not expose the expected server classes.', | |
| 89 | ); | |
| 90 | } | |
| 91 | ||
| 92 | $definition = $this->faqSearchTool->getDefinition(); | |
| 93 | ||
| 94 | return Server::builder() | |
| 95 | ->setServerInfo( | |
| 96 | (string) $this->serverInfo['name'], | |
| 97 | (string) $this->serverInfo['version'], | |
| 98 | (string) ($this->serverInfo['description'] ?? null), | |
| 99 | ) | |
| 100 | ->addTool( | |
| 101 | $this->faqSearch(...), | |
| 102 | $definition->name, | |
| 103 | null, | |
| 104 | $definition->description, | |
| 105 | null, | |
| 106 | $definition->inputSchema, | |
| 107 | null, | |
| 108 | null, | |
| 109 | $definition->outputSchema, | |
| 110 | ) | |
| 111 | ->build(); | |
| 112 | } | |
| 113 | } |