diff --git a/app/Mcp/Tools/AppInfoTool.php b/app/Mcp/Tools/AppInfoTool.php index 491143a..cc6a045 100644 --- a/app/Mcp/Tools/AppInfoTool.php +++ b/app/Mcp/Tools/AppInfoTool.php @@ -2,15 +2,19 @@ namespace App\Mcp\Tools; +use Composer\InstalledVersions; use Illuminate\Contracts\JsonSchema\JsonSchema; +use Illuminate\Foundation\Application; use Illuminate\JsonSchema\Types\Type; use Laravel\Mcp\Request; use Laravel\Mcp\Response; use Laravel\Mcp\Server\Attributes\Description; +use Laravel\Mcp\Server\Attributes\Name; use Laravel\Mcp\Server\Tool; use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly; -#[Description('Returns Super Stack app name, environment, and key package versions (Laravel, Filament, NativePHP Mobile, Laravel MCP).')] +#[Name('app-info')] +#[Description('Returns Super Stack app name, environment, and key package versions (Laravel, Filament, NativePHP Mobile, Web UI, Laravel MCP).')] #[IsReadOnly] class AppInfoTool extends Tool { @@ -20,10 +24,11 @@ class AppInfoTool extends Tool public function handle(Request $request): Response { $packages = [ - 'laravel/framework' => \Illuminate\Foundation\Application::VERSION, - 'filament/filament' => \Composer\InstalledVersions::getPrettyVersion('filament/filament'), - 'nativephp/mobile' => \Composer\InstalledVersions::getPrettyVersion('nativephp/mobile'), - 'laravel/mcp' => \Composer\InstalledVersions::getPrettyVersion('laravel/mcp'), + 'laravel/framework' => Application::VERSION, + 'filament/filament' => InstalledVersions::getPrettyVersion('filament/filament'), + 'nativephp/mobile' => InstalledVersions::getPrettyVersion('nativephp/mobile'), + 'nativephp/web-ui' => InstalledVersions::getPrettyVersion('nativephp/web-ui'), + 'laravel/mcp' => InstalledVersions::getPrettyVersion('laravel/mcp'), ]; $lines = [ diff --git a/tests/Feature/McpServerTest.php b/tests/Feature/McpServerTest.php new file mode 100644 index 0000000..e390c05 --- /dev/null +++ b/tests/Feature/McpServerTest.php @@ -0,0 +1,62 @@ +postJson('/mcp/superstack', [ + 'jsonrpc' => '2.0', + 'id' => 1, + 'method' => 'tools/list', + 'params' => [], + ]); + + $response->assertStatus(200) + ->assertJson([ + 'jsonrpc' => '2.0', + 'id' => 1, + 'result' => [ + 'tools' => [ + [ + 'name' => 'app-info', + ], + ], + ], + ]); +}); + +test('mcp server executes app-info tool successfully', function () { + $response = $this->postJson('/mcp/superstack', [ + 'jsonrpc' => '2.0', + 'id' => 1, + 'method' => 'tools/call', + 'params' => [ + 'name' => 'app-info', + 'arguments' => [], + ], + ]); + + $response->assertStatus(200) + ->assertJsonPath('result.isError', false) + ->assertJsonPath('result.content.0.type', 'text'); + + expect($response->json('result.content.0.text')) + ->toContain('Super Stack') + ->toContain('laravel/framework') + ->toContain('filament/filament') + ->toContain('nativephp/mobile') + ->toContain('laravel/mcp'); +}); + +test('mcp server handles unknown tool gracefully with jsonrpc error', function () { + $response = $this->postJson('/mcp/superstack', [ + 'jsonrpc' => '2.0', + 'id' => 1, + 'method' => 'tools/call', + 'params' => [ + 'name' => 'non-existent-tool', + 'arguments' => [], + ], + ]); + + $response->assertStatus(200) + ->assertJsonPath('error.code', -32602) + ->assertJsonPath('error.message', 'Tool [non-existent-tool] not found.'); +});