Skip to content

Feature/update mcp sdk#4091

Merged
thorsten merged 7 commits intomainfrom
feature/update-mcp-sdk
Mar 19, 2026
Merged

Feature/update mcp sdk#4091
thorsten merged 7 commits intomainfrom
feature/update-mcp-sdk

Conversation

@thorsten
Copy link
Owner

@thorsten thorsten commented Mar 18, 2026

Summary by CodeRabbit

  • New Features

    • MCP Server integration via the official SDK for FAQ search and runtime; MCP Server version now shown in system info
  • Documentation

    • Expanded MCP server docs with examples, configuration, tool discovery, transport notes, and troubleshooting
  • Chores

    • Composer requirements updated for MCP SDK and dev packages; pre-commit/pre-push lint invocation standardized; dependency injection/services wired for the new runtime
  • Tests

    • Added runtime/tool unit tests; removed legacy executor/metadata tests and updated related tests

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Introduces an MCP runtime abstraction and SDK integration: adds McpServerRuntimeInterface, McpSdkRuntime, McpToolDefinition, McpToolExecutorInterface and FaqSearchTool; removes legacy executor/metadata; updates PhpMyFaqMcpServer to delegate to a runtime; updates DI, tests, docs, composer, and husky hooks.

Changes

Cohort / File(s) Summary
Husky Git Hooks
\.husky/pre-commit, \.husky/pre-push
Replace direct pnpm eslint . calls with pnpm run eslint in pre-commit and pre-push chains.
Composer
composer.json
Replace symfony/mcp-sdk (dev-main) with mcp/sdk ^0.4.0; pin phpdocumentor/reflection-docblock to ^5.6.
MCP Interfaces & Models
phpmyfaq/src/phpMyFAQ/Service/McpServer/McpServerRuntimeInterface.php, .../McpToolExecutorInterface.php, .../McpToolDefinition.php
Add runtime interface, tool-executor interface, and readonly McpToolDefinition value object.
Runtime Implementation & Wiring
phpmyfaq/src/phpMyFAQ/Service/McpServer/McpSdkRuntime.php, phpmyfaq/src/services.php
Add McpSdkRuntime implementing the runtime interface; register faq-search tool and runtime services and alias the runtime interface.
Tool Implementation (new)
phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php
Add FaqSearchTool implementing McpToolExecutorInterface: defines input/output schemas, executes searches, formats JSON responses and error handling.
Removed Legacy Tooling
phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchToolExecutor.php, .../FaqSearchToolMetadata.php
Delete legacy executor and metadata classes (functionality migrated into new tool and definition).
Server Refactor
phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php
Now implements McpServerRuntimeInterface, accepts optional runtime dependency, delegates runConsole/getServerInfo to runtime, removes JsonRpcHandler/toolchain wiring and local version constant.
Command & Tests updated
phpmyfaq/src/phpMyFAQ/Command/McpServerCommand.php, tests/.../Command/McpServerCommandTest.php
Command and its test now depend on McpServerRuntimeInterface instead of concrete PhpMyFaqMcpServer.
Search API
phpmyfaq/src/phpMyFAQ/Search.php
Change setCategoryId(int $categoryId)setCategoryId(?int $categoryId) (nullable).
System / Controller / Changelog / Docs
phpmyfaq/src/phpMyFAQ/System.php, phpmyfaq/src/phpMyFAQ/Controller/Administration/SystemInformationController.php, CHANGELOG.md, docs/mcp-server.md
Add MCP server version constant and getter; expose MCP Server Version in system info; update docs to reflect migration to mcp/sdk and STDIO transport; add changelog entry.
Tests — removed
tests/phpMyFAQ/Service/McpServer/FaqSearchToolExecutorTest.php, .../FaqSearchToolMetadataTest.php
Remove tests tied to deleted legacy executor and metadata.
Tests — added/updated
tests/phpMyFAQ/Service/McpServer/FaqSearchToolTest.php, .../McpSdkRuntimeTest.php, .../McpToolDefinitionTest.php, tests/.../PhpMyFaqMcpServerTest.php
Add tests for FaqSearchTool, McpSdkRuntime, McpToolDefinition; update PhpMyFaqMcpServer tests to use McpServerRuntimeInterface mocks and adjust expectations.
Misc tests metadata
tests/phpMyFAQ/KernelTest.php
Add #[UsesClass(System::class)] attribute to KernelTest.

Sequence Diagram(s)

sequenceDiagram
    participant Client as MCP Client
    participant Runtime as McpSdkRuntime
    participant Tool as FaqSearchTool
    participant Search as Search Service
    participant Config as Configuration

    Client->>Runtime: call "faq_search"(query, category_id, limit, all_languages)
    Runtime->>Tool: getDefinition()
    Tool-->>Runtime: McpToolDefinition (name, schemas)
    Runtime->>Tool: execute(arguments)
    Tool->>Config: read defaults / build base URL
    Tool->>Search: setCategoryId(category_id) / search(query, all_languages)
    Search-->>Tool: results array
    Tool->>Tool: formatResultsAsJson()
    Tool-->>Runtime: {content, type, mimeType}
    Runtime-->>Client: MCP response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

A rabbit hops through schemas new,
I wire runtimes, tools, and SDK glue,
From STDIO whispers to JSON light,
FAQ hops back, returned just right, 🐰
Hop—search—reply—everything’s in view!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feature/update mcp sdk' is vague and uses generic phrasing. While it references MCP SDK, it doesn't clearly convey the actual scope of changes, which include refactoring the server implementation to use the new MCP SDK, dependency updates, and significant architectural changes to the tool execution layer. Consider a more descriptive title such as 'Refactor MCP server to use mcp/sdk package' or 'Migrate MCP server implementation to official mcp/sdk library' to better communicate the primary change to reviewers.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/update-mcp-sdk
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
tests/phpMyFAQ/Service/McpServer/McpSdkRuntimeTest.php (1)

89-110: Test does not verify actual runConsole behavior.

This test only checks that the runConsole method exists and that mock objects can be created. It doesn't actually invoke runConsole or verify any behavior. Consider removing this test or making it meaningful by invoking the method.

♻️ Suggested improvement

Either remove this test as it provides no value, or actually invoke runConsole:

 public function testRunConsoleMethodAcceptsConsoleInterfaces(): void
 {
     $runtime = new McpSdkRuntime(
         $this->createConfigurationMock(),
         new FaqSearchTool(
             $this->createConfigurationMock(),
             $this->createMock(Search::class),
             $this->createMock(Faq::class),
         ),
         [
             'name' => 'phpMyFAQ MCP Server',
             'version' => '0.1.0-dev',
             'description' => 'Model Context Protocol server for phpMyFAQ installations',
             'capabilities' => ['tools' => true],
             'tools' => [['name' => 'faq_search', 'description' => 'Search through phpMyFAQ installations']],
         ],
     );

-    $this->assertTrue(method_exists($runtime, 'runConsole'));
-    $this->assertInstanceOf(InputInterface::class, $this->createMock(InputInterface::class));
-    $this->assertInstanceOf(OutputInterface::class, $this->createMock(OutputInterface::class));
+    $input = $this->createMock(InputInterface::class);
+    $output = $this->createMock(OutputInterface::class);
+    
+    // Verify method can be called without exception (or expect specific behavior)
+    $this->expectNotToPerformAssertions();
+    // Note: Actual invocation may require additional mocking of MCP SDK internals
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/phpMyFAQ/Service/McpServer/McpSdkRuntimeTest.php` around lines 89 -
110, The test testRunConsoleMethodAcceptsConsoleInterfaces currently only
asserts existence of runConsole and mock types; either delete this test or make
it meaningful by actually calling McpSdkRuntime::runConsole with mocked
InputInterface and OutputInterface and asserting observable behavior (e.g.,
return value, calls on the OutputInterface mock, or side effects). Specifically,
in the test body instantiate McpSdkRuntime as shown, create mocks for
InputInterface and OutputInterface, set expected method calls on the
OutputInterface or expected return on runConsole, invoke
$runtime->runConsole($inputMock, $outputMock) and assert the expected
interactions or return; alternatively remove the entire test method if no
behavior needs verifying.
phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php (1)

156-173: Inconsistent JSON encoding for empty vs non-empty results.

Empty results use json_encode() without JSON_PRETTY_PRINT (line 164), while non-empty results use JSON_PRETTY_PRINT (line 172). Consider using consistent formatting.

Proposed fix for consistency
         if ($results === []) {
             $jsonData = [
                 'results' => [],
                 'total_found' => 0,
             ];

-            return json_encode($jsonData);
+            return json_encode($jsonData, JSON_PRETTY_PRINT);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php` around lines 156 -
173, The method formatResultsAsJson currently encodes empty results with
json_encode($jsonData) and non-empty with json_encode($jsonData,
JSON_PRETTY_PRINT), causing inconsistent output; update formatResultsAsJson to
consistently use the same encoding flag (e.g. JSON_PRETTY_PRINT) for both
branches — either remove the separate empty-results branch and always build
$jsonData then return json_encode($jsonData, JSON_PRETTY_PRINT), or pass
JSON_PRETTY_PRINT in the json_encode call inside the empty-results branch so
both returns use identical encoding.
phpmyfaq/src/phpMyFAQ/Service/McpServer/McpSdkRuntime.php (1)

39-42: Unused $input and $output parameters.

Static analysis correctly flags these as unused. The MCP SDK's StdioTransport handles I/O directly via stdin/stdout, bypassing Symfony's console abstractions. Consider suppressing the warning with an annotation and adding a docblock explaining why.

Proposed fix
+    /**
+     * Run the MCP server using stdio transport.
+     *
+     * Note: $input and $output are not used because the MCP SDK's StdioTransport
+     * handles I/O directly via stdin/stdout, bypassing Symfony's console abstractions.
+     *
+     * `@SuppressWarnings`(PHPMD.UnusedFormalParameter)
+     */
     public function runConsole(InputInterface $input, OutputInterface $output): void
     {
         $this->buildServer()->run(new \Mcp\Server\Transport\StdioTransport());
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/McpSdkRuntime.php` around lines 39 -
42, The runConsole method in McpSdkRuntime declares $input and $output but never
uses them; keep the method signature for interface compatibility but suppress
the static-analysis warning and document why: add a docblock above runConsole
explaining that StdioTransport uses native stdin/stdout and Symfony
InputInterface/OutputInterface are intentionally unused, include `@param`
annotations for InputInterface $input and OutputInterface $output, and add a
static-analysis suppression tag such as `@psalm-suppress` UnusedMethodParameter
(or the project’s preferred suppressor) to silence the warning while preserving
the signature.
phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php (2)

94-110: Duplicate server info definition.

This createServerInfo() method duplicates the server info array defined in services.php (lines 696-707). Changes must be synchronized manually. Consider extracting to a shared constant or configuration.

Option: Use a shared constant
// In a new file or McpServerRuntimeInterface
final class McpServerInfo
{
    public const NAME = 'phpMyFAQ MCP Server';
    public const VERSION = '0.1.0-dev';
    public const DESCRIPTION = 'Model Context Protocol server for phpMyFAQ installations';
    
    public static function toArray(): array
    {
        return [
            'name' => self::NAME,
            'version' => self::VERSION,
            'description' => self::DESCRIPTION,
            'capabilities' => ['tools' => true],
            'tools' => [
                ['name' => 'faq_search', 'description' => 'Search through phpMyFAQ installations'],
            ],
        ];
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php` around lines
94 - 110, The createServerInfo() method duplicates the server info defined
elsewhere, causing manual sync issues; replace the inline array in
PhpMyFaqMcpServer::createServerInfo() by returning a single shared source of
truth (e.g., a new McpServerInfo class or adding constants/method to an existing
McpServerRuntimeInterface) and update createServerInfo() to call that shared
toArray()/get() method or constant values; ensure the shared symbol (suggested
name McpServerInfo::toArray(), or constants McpServerInfo::NAME, ::VERSION,
::DESCRIPTION) contains capabilities and tools (including faq_search) so both
createServerInfo() and the other service consumer use the same data.

36-38: Class implements the same interface it wraps.

PhpMyFaqMcpServer now implements McpServerRuntimeInterface while also holding a private $runtime: McpServerRuntimeInterface. This decorator/facade pattern is valid, but given the DI wiring (where McpServerCommand receives McpSdkRuntime directly via the interface alias), this class may not be instantiated in production flows.

Consider whether this class should be the resolved implementation for McpServerRuntimeInterface to ensure the language detection logic executes, or document when this class is intended to be used.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php` around lines
36 - 38, PhpMyFaqMcpServer currently both implements McpServerRuntimeInterface
and wraps a private McpServerRuntimeInterface $runtime, which means the
decorator's language-detection logic may never run unless the DI container
resolves PhpMyFaqMcpServer for that interface; fix by either (A)
registering/binding PhpMyFaqMcpServer as the concrete for
McpServerRuntimeInterface in your DI setup so McpServerCommand (which depends on
McpSdkRuntime via the interface alias) receives this decorator, or (B) remove
the interface implementation from PhpMyFaqMcpServer and treat it as a named
decorator/wrapper (rename if needed) and ensure callers explicitly wrap the
original runtime with this class; update documentation accordingly to state when
PhpMyFaqMcpServer vs McpSdkRuntime should be used.
phpmyfaq/src/services.php (1)

693-710: Server info is duplicated between services.php and PhpMyFaqMcpServer.

The server info array (name, version, description, capabilities, tools) is defined here and also in PhpMyFaqMcpServer::createServerInfo(). This violates DRY and risks the values drifting out of sync. Consider extracting to a single source of truth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/services.php` around lines 693 - 710, The server info array is
duplicated between the service definition in services.php
(phpmyfaq.service.mcp-server.runtime / McpSdkRuntime::class) and
PhpMyFaqMcpServer::createServerInfo(), so extract the array into a single source
of truth (e.g., a public constant or a configuration entry) and have both places
read from it; add a public static SERVER_INFO constant or move the array into
the existing configuration service and update services.php to reference that
constant/service instead of inlining the array, and modify
PhpMyFaqMcpServer::createServerInfo() to return the same constant/config value
so both McpSdkRuntime construction and createServerInfo() use the identical
centralized data.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Line 25: The "eslint" npm script was narrowed to specific directories,
excluding lintable files like eslint.config.mjs, vite.config.ts, phpmyfaq/sw.js,
etc.; restore global coverage by changing the package.json "eslint" script (the
"eslint" key) to run ESLint across the repository rather than only
"phpmyfaq/assets/src" and "phpmyfaq/admin/assets/src", ensuring it targets
.js/.mjs/.ts files and lets the existing ESLint overrides (e.g., for
phpmyfaq/sw.js) apply rather than using a restrictive file list.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php`:
- Around line 117-118: The foreach in FaqSearchTool (inside FaqSearchTool.php)
is emitting debug-level var_export of each $searchResult via
$this->configuration->getLogger()->info(...); remove this unconditional verbose
logging or gate it behind a debug check (e.g., use
$this->configuration->getLogger()->isDebugEnabled() or a config flag) and
replace the info call with a debug-level log that outputs only necessary fields
(or remove entirely) to avoid performance and privacy issues.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/McpSdkRuntime.php`:
- Around line 75-107: The addTool() call in buildServer() is passing unsupported
extra positional arguments (several nulls and $definition->outputSchema) that
are not part of the mcp/sdk v0.4.0 API and will cause a runtime error; update
the addTool invocation inside Mcp\Server::builder() in the buildServer() method
to only pass the supported parameters (handler, name, description, annotations,
inputSchema) — remove the extra nulls and the outputSchema argument so the call
supplies the lambda handler, $definition->name, $definition->description, the
annotations (null), and $definition->inputSchema only.

In `@phpmyfaq/src/services.php`:
- Around line 710-718: The console alias for McpServerRuntimeInterface resolves
to McpSdkRuntime so PhpMyFaqMcpServer (which runs language detection and calls
setLanguage()) is never instantiated; either change the DI alias
'phpmyfaq.service.mcp-server.runtime' to point to PhpMyFaqMcpServer instead of
McpSdkRuntime so PhpMyFaqMcpServer is constructed when McpServerRuntimeInterface
is injected, or explicitly perform language initialization in console bootstrap
(call the same logic PhpMyFaqMcpServer uses or invoke its setLanguage()) before
search operations run; update references to McpServerRuntimeInterface,
phpmyfaq.service.mcp-server.runtime, PhpMyFaqMcpServer, McpSdkRuntime,
McpServerCommand and LanguageListener accordingly.

---

Nitpick comments:
In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php`:
- Around line 156-173: The method formatResultsAsJson currently encodes empty
results with json_encode($jsonData) and non-empty with json_encode($jsonData,
JSON_PRETTY_PRINT), causing inconsistent output; update formatResultsAsJson to
consistently use the same encoding flag (e.g. JSON_PRETTY_PRINT) for both
branches — either remove the separate empty-results branch and always build
$jsonData then return json_encode($jsonData, JSON_PRETTY_PRINT), or pass
JSON_PRETTY_PRINT in the json_encode call inside the empty-results branch so
both returns use identical encoding.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/McpSdkRuntime.php`:
- Around line 39-42: The runConsole method in McpSdkRuntime declares $input and
$output but never uses them; keep the method signature for interface
compatibility but suppress the static-analysis warning and document why: add a
docblock above runConsole explaining that StdioTransport uses native
stdin/stdout and Symfony InputInterface/OutputInterface are intentionally
unused, include `@param` annotations for InputInterface $input and OutputInterface
$output, and add a static-analysis suppression tag such as `@psalm-suppress`
UnusedMethodParameter (or the project’s preferred suppressor) to silence the
warning while preserving the signature.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php`:
- Around line 94-110: The createServerInfo() method duplicates the server info
defined elsewhere, causing manual sync issues; replace the inline array in
PhpMyFaqMcpServer::createServerInfo() by returning a single shared source of
truth (e.g., a new McpServerInfo class or adding constants/method to an existing
McpServerRuntimeInterface) and update createServerInfo() to call that shared
toArray()/get() method or constant values; ensure the shared symbol (suggested
name McpServerInfo::toArray(), or constants McpServerInfo::NAME, ::VERSION,
::DESCRIPTION) contains capabilities and tools (including faq_search) so both
createServerInfo() and the other service consumer use the same data.
- Around line 36-38: PhpMyFaqMcpServer currently both implements
McpServerRuntimeInterface and wraps a private McpServerRuntimeInterface
$runtime, which means the decorator's language-detection logic may never run
unless the DI container resolves PhpMyFaqMcpServer for that interface; fix by
either (A) registering/binding PhpMyFaqMcpServer as the concrete for
McpServerRuntimeInterface in your DI setup so McpServerCommand (which depends on
McpSdkRuntime via the interface alias) receives this decorator, or (B) remove
the interface implementation from PhpMyFaqMcpServer and treat it as a named
decorator/wrapper (rename if needed) and ensure callers explicitly wrap the
original runtime with this class; update documentation accordingly to state when
PhpMyFaqMcpServer vs McpSdkRuntime should be used.

In `@phpmyfaq/src/services.php`:
- Around line 693-710: The server info array is duplicated between the service
definition in services.php (phpmyfaq.service.mcp-server.runtime /
McpSdkRuntime::class) and PhpMyFaqMcpServer::createServerInfo(), so extract the
array into a single source of truth (e.g., a public constant or a configuration
entry) and have both places read from it; add a public static SERVER_INFO
constant or move the array into the existing configuration service and update
services.php to reference that constant/service instead of inlining the array,
and modify PhpMyFaqMcpServer::createServerInfo() to return the same
constant/config value so both McpSdkRuntime construction and createServerInfo()
use the identical centralized data.

In `@tests/phpMyFAQ/Service/McpServer/McpSdkRuntimeTest.php`:
- Around line 89-110: The test testRunConsoleMethodAcceptsConsoleInterfaces
currently only asserts existence of runConsole and mock types; either delete
this test or make it meaningful by actually calling McpSdkRuntime::runConsole
with mocked InputInterface and OutputInterface and asserting observable behavior
(e.g., return value, calls on the OutputInterface mock, or side effects).
Specifically, in the test body instantiate McpSdkRuntime as shown, create mocks
for InputInterface and OutputInterface, set expected method calls on the
OutputInterface or expected return on runConsole, invoke
$runtime->runConsole($inputMock, $outputMock) and assert the expected
interactions or return; alternatively remove the entire test method if no
behavior needs verifying.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f84ba2e-e7ee-4ba3-9606-c68294f310fc

📥 Commits

Reviewing files that changed from the base of the PR and between 065df83 and 2389e06.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • .husky/pre-commit
  • .husky/pre-push
  • composer.json
  • docs/mcp-server.md
  • package.json
  • phpmyfaq/src/phpMyFAQ/Command/McpServerCommand.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchToolExecutor.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchToolMetadata.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/McpSdkRuntime.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/McpServerRuntimeInterface.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/McpToolDefinition.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/McpToolExecutorInterface.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php
  • phpmyfaq/src/services.php
  • tests/phpMyFAQ/Command/McpServerCommandTest.php
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolExecutorTest.php
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolMetadataTest.php
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolTest.php
  • tests/phpMyFAQ/Service/McpServer/McpSdkRuntimeTest.php
  • tests/phpMyFAQ/Service/McpServer/McpToolDefinitionTest.php
  • tests/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServerTest.php
💤 Files with no reviewable changes (4)
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolExecutorTest.php
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolMetadataTest.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchToolMetadata.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchToolExecutor.php

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php (1)

55-63: Optional: remove duplicated runtime initialization call.

initializeServer($runtime) is invoked in both branches (Line 55 and Line 62). You can simplify the constructor flow without changing behavior.

♻️ Suggested simplification
-        if ($detectionEnabled) {
-            $language->setLanguageWithDetection($configLang);
-            $this->configuration->setLanguage($language);
-            $this->initializeServer($runtime);
-            return;
-        }
-
-        $language->setLanguageFromConfiguration($configLang);
-        $this->configuration->setLanguage($language);
-
-        $this->initializeServer($runtime);
+        if ($detectionEnabled) {
+            $language->setLanguageWithDetection($configLang);
+        } else {
+            $language->setLanguageFromConfiguration($configLang);
+        }
+
+        $this->configuration->setLanguage($language);
+        $this->initializeServer($runtime);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php` around lines
55 - 63, The constructor currently calls initializeServer($runtime) in both
branches, causing a duplicated call; remove the first call and ensure
initializeServer($runtime) is invoked once after handling the language setup
(i.e., keep the calls to $language->setLanguageFromConfiguration($configLang)
and $this->configuration->setLanguage($language) and place a single
$this->initializeServer($runtime) after them), updating the constructor flow
around the initializeServer, setLanguageFromConfiguration, and setLanguage
usages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php`:
- Around line 106-108: The category filter can leak because FaqSearchTool reuses
the same $this->search instance but only calls
$this->search->setCategoryId((int) $categoryId) when $categoryId !== null;
change the logic so you explicitly clear the category filter when none is
provided—call $this->search->setCategoryId(null) (or the Search API's clear
value) before/inside the execution flow when $categoryId is null, and keep the
existing set call when it's present; update the block around
$this->search->setCategoryId to always reset or set the filter to prevent state
bleed.

In `@phpmyfaq/src/services.php`:
- Around line 697-699: The metadata array currently hardcodes the MCP version
('0.1.0-dev'); replace that literal with a runtime call to
phpMyFAQ\System::getMcpServerVersion() so the 'version' key reflects the
canonical server version. Locate the metadata declaration in services.php (the
array containing 'name', 'version', 'description') and set 'version' to the
result of phpMyFAQ\System::getMcpServerVersion() (ensuring the class is imported
or fully-qualified) and retain the existing keys/structure.

In `@tests/phpMyFAQ/Service/McpServer/FaqSearchToolTest.php`:
- Around line 173-174: In FaqSearchToolTest update the string assignments that
currently use double-quoted interpolation for $obj->question and $obj->answer
(and the similar occurrences at the later lines) to use single-quoted strings
with concatenation instead; replace "Question $i" and "Answer $i" with 'Question
' . $i and 'Answer ' . $i to conform to the repository single-quote rule and
maintain identical values.

---

Nitpick comments:
In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php`:
- Around line 55-63: The constructor currently calls initializeServer($runtime)
in both branches, causing a duplicated call; remove the first call and ensure
initializeServer($runtime) is invoked once after handling the language setup
(i.e., keep the calls to $language->setLanguageFromConfiguration($configLang)
and $this->configuration->setLanguage($language) and place a single
$this->initializeServer($runtime) after them), updating the constructor flow
around the initializeServer, setLanguageFromConfiguration, and setLanguage
usages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c333e2d6-3b9a-42bf-8459-cd8b54994eb2

📥 Commits

Reviewing files that changed from the base of the PR and between 2389e06 and 85166f3.

📒 Files selected for processing (9)
  • phpmyfaq/src/phpMyFAQ/Controller/Administration/SystemInformationController.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServer.php
  • phpmyfaq/src/phpMyFAQ/System.php
  • phpmyfaq/src/services.php
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolTest.php
  • tests/phpMyFAQ/Service/McpServer/McpSdkRuntimeTest.php
  • tests/phpMyFAQ/Service/McpServer/McpToolDefinitionTest.php
  • tests/phpMyFAQ/Service/McpServer/PhpMyFaqMcpServerTest.php

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php (1)

152-169: Consider adding error handling for json_encode failure.

json_encode() can return false on encoding failure, which would cause a type mismatch with the string return type. While unlikely with this controlled data, defensive coding would handle this edge case.

💡 Proposed fix
     private function formatResultsAsJson(array $results): string
     {
         if ($results === []) {
             $jsonData = [
                 'results' => [],
                 'total_found' => 0,
             ];

-            return json_encode($jsonData);
+            return json_encode($jsonData) ?: '{"results":[],"total_found":0}';
         }

         $jsonData = [
             'results' => $results,
             'total_found' => count($results),
         ];

-        return json_encode($jsonData, JSON_PRETTY_PRINT);
+        return json_encode($jsonData, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php` around lines 152 -
169, In formatResultsAsJson, json_encode can return false and violate the string
return type; after calling json_encode (both branches), check if the result ===
false and if so handle the error by obtaining json_last_error_msg() and either
throw a RuntimeException (or return a deterministic fallback JSON string) that
includes that error message; update formatResultsAsJson to perform this check
for both the empty-results branch and the non-empty branch so callers always
receive a valid string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@phpmyfaq/src/phpMyFAQ/Search.php`:
- Around line 57-59: The PHPDoc for setCategoryId() incorrectly documents the
parameter as `@param` int while the method signature accepts a nullable int
(?int); update the docblock to `@param` int|null $categoryId (or `@param` null|int
$categoryId) to match the nullable setter signature and prevent static-analysis
warnings for the setCategoryId method.

---

Nitpick comments:
In `@phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php`:
- Around line 152-169: In formatResultsAsJson, json_encode can return false and
violate the string return type; after calling json_encode (both branches), check
if the result === false and if so handle the error by obtaining
json_last_error_msg() and either throw a RuntimeException (or return a
deterministic fallback JSON string) that includes that error message; update
formatResultsAsJson to perform this check for both the empty-results branch and
the non-empty branch so callers always receive a valid string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 604adab4-770d-4168-8f56-2fb942eab12d

📥 Commits

Reviewing files that changed from the base of the PR and between 85166f3 and 5651313.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • phpmyfaq/src/phpMyFAQ/Search.php
  • phpmyfaq/src/phpMyFAQ/Service/McpServer/FaqSearchTool.php
  • phpmyfaq/src/services.php
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolTest.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/phpMyFAQ/Service/McpServer/FaqSearchToolTest.php

@thorsten thorsten force-pushed the feature/update-mcp-sdk branch from 8003aaf to f67ad64 Compare March 19, 2026 17:11
@thorsten
Copy link
Owner Author

@coderabbitai resume

@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

✅ Actions performed

Reviews resumed.

@thorsten thorsten merged commit 53af644 into main Mar 19, 2026
10 checks passed
@thorsten thorsten deleted the feature/update-mcp-sdk branch March 19, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant