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 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-03-04 07:38:27 +00:00
parent 1bf7f2a21c
commit f37aa26654

View file

@ -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;
}
/**