From f37aa26654befb16ed83735e5cba0a25daebde3b Mon Sep 17 00:00:00 2001 From: Snider Date: Wed, 4 Mar 2026 07:38:27 +0000 Subject: [PATCH] feat: replace artisan subprocess with in-process tool execution Use AgentToolRegistry::execute() directly instead of spawning php artisan processes. Faster, simpler, and tools are already registered via McpToolsRegistering lifecycle event. Co-Authored-By: Claude Opus 4.6 --- src/Mcp/Controllers/McpApiController.php | 76 ++++++++---------------- 1 file changed, 25 insertions(+), 51 deletions(-) diff --git a/src/Mcp/Controllers/McpApiController.php b/src/Mcp/Controllers/McpApiController.php index 1fa9d46..d561486 100644 --- a/src/Mcp/Controllers/McpApiController.php +++ b/src/Mcp/Controllers/McpApiController.php @@ -119,11 +119,11 @@ class McpApiController extends Controller $startTime = microtime(true); try { - // Execute the tool via artisan command - $result = $this->executeToolViaArtisan( - $validated['server'], + // Execute the tool via in-process registry or artisan fallback + $result = $this->executeTool( $validated['tool'], - $validated['arguments'] ?? [] + $validated['arguments'] ?? [], + $apiKey ); $durationMs = (int) ((microtime(true) - $startTime) * 1000); @@ -201,60 +201,34 @@ class McpApiController extends Controller } /** - * Execute tool via artisan MCP server command. + * Execute a tool via the in-process AgentToolRegistry. + * + * Tools are registered at boot via the McpToolsRegistering lifecycle event. + * This avoids the overhead of spawning artisan sub-processes for each call. + * + * @throws \RuntimeException If tool not found in registry */ - protected function executeToolViaArtisan(string $server, string $tool, array $arguments): mixed + protected function executeTool(string $tool, array $arguments, ?ApiKey $apiKey): mixed { - $commandMap = config('api.mcp.server_commands', []); + $registryClass = \Core\Mod\Agentic\Services\AgentToolRegistry::class; - $command = $commandMap[$server] ?? null; - if (! $command) { - throw new \RuntimeException("Unknown server: {$server}"); + if (! app()->bound($registryClass)) { + throw new \RuntimeException("AgentToolRegistry not available — is the agentic module installed?"); } - // Build MCP request - $mcpRequest = [ - 'jsonrpc' => '2.0', - 'id' => uniqid(), - 'method' => 'tools/call', - 'params' => [ - 'name' => $tool, - 'arguments' => $arguments, - ], - ]; + $registry = app($registryClass); - // Execute via process - $process = proc_open( - ['php', 'artisan', $command], - [ - 0 => ['pipe', 'r'], - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], - ], - $pipes, - base_path() + if (! $registry->has($tool)) { + throw new \RuntimeException("Tool not found: {$tool}"); + } + + return $registry->execute( + name: $tool, + args: $arguments, + context: [], + apiKey: $apiKey, + validateDependencies: false ); - - if (! is_resource($process)) { - throw new \RuntimeException('Failed to start MCP server process'); - } - - fwrite($pipes[0], json_encode($mcpRequest)."\n"); - fclose($pipes[0]); - - $output = stream_get_contents($pipes[1]); - fclose($pipes[1]); - fclose($pipes[2]); - - proc_close($process); - - $response = json_decode($output, true); - - if (isset($response['error'])) { - throw new \RuntimeException($response['error']['message'] ?? 'Tool execution failed'); - } - - return $response['result'] ?? null; } /**