From ee83aabca064f9931f8b81a2a98c88dc6c090363 Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 18:03:26 +0000 Subject: [PATCH] fix(api): pass MCP tool version through execution Co-Authored-By: Virgil --- .../src/Api/Controllers/McpApiController.php | 38 ++++++++++------ .../Tests/Feature/McpApiControllerTest.php | 43 +++++++++++++++++++ 2 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 src/php/src/Api/Tests/Feature/McpApiControllerTest.php diff --git a/src/php/src/Api/Controllers/McpApiController.php b/src/php/src/Api/Controllers/McpApiController.php index c5b6fc8..d50fd5f 100644 --- a/src/php/src/Api/Controllers/McpApiController.php +++ b/src/php/src/Api/Controllers/McpApiController.php @@ -271,7 +271,8 @@ class McpApiController extends Controller $result = $this->executeToolViaArtisan( $validated['server'], $validated['tool'], - $validated['arguments'] ?? [] + $validated['arguments'] ?? [], + $toolVersion?->version ); $durationMs = (int) ((microtime(true) - $startTime) * 1000); @@ -538,23 +539,14 @@ class McpApiController extends Controller /** * Execute tool via artisan MCP server command. */ - protected function executeToolViaArtisan(string $server, string $tool, array $arguments): mixed + protected function executeToolViaArtisan(string $server, string $tool, array $arguments, ?string $version = null): mixed { $command = $this->resolveMcpServerCommand($server); if (! $command) { throw new \RuntimeException("Unknown server: {$server}"); } - // Build MCP request - $mcpRequest = [ - 'jsonrpc' => '2.0', - 'id' => uniqid(), - 'method' => 'tools/call', - 'params' => [ - 'name' => $tool, - 'arguments' => $arguments, - ], - ]; + $mcpRequest = $this->buildToolCallRequest($tool, $arguments, $version); // Execute via process $process = proc_open( @@ -590,6 +582,28 @@ class McpApiController extends Controller return $response['result'] ?? null; } + /** + * Build the JSON-RPC payload for an MCP tool call. + */ + protected function buildToolCallRequest(string $tool, array $arguments, ?string $version = null): array + { + $params = [ + 'name' => $tool, + 'arguments' => $arguments, + ]; + + if ($version !== null && $version !== '') { + $params['version'] = $version; + } + + return [ + 'jsonrpc' => '2.0', + 'id' => uniqid(), + 'method' => 'tools/call', + 'params' => $params, + ]; + } + /** * Read resource via artisan MCP server command. */ diff --git a/src/php/src/Api/Tests/Feature/McpApiControllerTest.php b/src/php/src/Api/Tests/Feature/McpApiControllerTest.php new file mode 100644 index 0000000..88c6a23 --- /dev/null +++ b/src/php/src/Api/Tests/Feature/McpApiControllerTest.php @@ -0,0 +1,43 @@ +buildToolCallRequest($tool, $arguments, $version); + } + }; + + $payload = $controller->payload('search', ['query' => 'status'], '1.2.3'); + + expect($payload['jsonrpc'])->toBe('2.0'); + expect($payload['method'])->toBe('tools/call'); + expect($payload['params'])->toMatchArray([ + 'name' => 'search', + 'arguments' => ['query' => 'status'], + 'version' => '1.2.3', + ]); +}); + +it('omits the version field when one is not requested', function () { + $controller = new class extends McpApiController + { + public function payload(string $tool, array $arguments, ?string $version = null): array + { + return $this->buildToolCallRequest($tool, $arguments, $version); + } + }; + + $payload = $controller->payload('search', ['query' => 'status']); + + expect($payload['params'])->toMatchArray([ + 'name' => 'search', + 'arguments' => ['query' => 'status'], + ]); + expect($payload['params'])->not->toHaveKey('version'); +});