fix(mcp): satisfy larastan (level 5)

- Correct schema() @return to array<string, mixed> (the JsonSchema builder
  returns Type objects, not the JsonSchema contract; the abstract Tool::schema
  uses mixed).
- Narrow the MCP user to App\Models\User via instanceof before gating.
- Fix the $tools property covariance annotation.
- Exempt app/Mcp from public.method.unused (framework entry points invoked by
  laravel/mcp via reflection), matching how controllers/jobs/policies are treated.
This commit is contained in:
Víctor Falcón 2026-07-17 15:42:18 +02:00
parent de5fc229d5
commit 4e6be10885
9 changed files with 15 additions and 8 deletions

View File

@ -13,6 +13,7 @@ use Laravel\Mcp\Server;
use Laravel\Mcp\Server\Attributes\Instructions;
use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Attributes\Version;
use Laravel\Mcp\Server\Tool;
#[Name('Whisper Money')]
#[Version('1.0.0')]
@ -30,7 +31,7 @@ analysing spending, cashflow and net worth.
MARKDOWN)]
class WhisperMoneyServer extends Server
{
/** @var array<int, class-string> */
/** @var array<int, class-string<Tool>> */
protected array $tools = [
SearchTransactions::class,
SpendingByCategory::class,

View File

@ -15,7 +15,7 @@ use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
class GetCashflow extends McpTool
{
/**
* @return array<string, JsonSchema>
* @return array<string, mixed>
*/
public function schema(JsonSchema $schema): array
{

View File

@ -15,7 +15,7 @@ use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
class GetNetWorth extends McpTool
{
/**
* @return array<string, JsonSchema>
* @return array<string, mixed>
*/
public function schema(JsonSchema $schema): array
{

View File

@ -15,7 +15,7 @@ use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
class ListAccounts extends McpTool
{
/**
* @return array<string, JsonSchema>
* @return array<string, mixed>
*/
public function schema(JsonSchema $schema): array
{

View File

@ -15,7 +15,7 @@ use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
class ListCategories extends McpTool
{
/**
* @return array<string, JsonSchema>
* @return array<string, mixed>
*/
public function schema(JsonSchema $schema): array
{

View File

@ -31,7 +31,7 @@ abstract class McpTool extends Tool
{
$user = $request->user();
if ($user === null) {
if (! $user instanceof User) {
return Response::error('Authentication required.');
}

View File

@ -15,7 +15,7 @@ use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
class SearchTransactions extends McpTool
{
/**
* @return array<string, JsonSchema>
* @return array<string, mixed>
*/
public function schema(JsonSchema $schema): array
{

View File

@ -16,7 +16,7 @@ use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
class SpendingByCategory extends McpTool
{
/**
* @return array<string, JsonSchema>
* @return array<string, mixed>
*/
public function schema(JsonSchema $schema): array
{

View File

@ -23,6 +23,12 @@ parameters:
path: app/Http/Controllers/*
- identifier: public.method.unused
path: app/Http/Controllers/**/*
# MCP servers and tools are entry points invoked by laravel/mcp via
# reflection, not called from PHP code.
- identifier: public.method.unused
path: app/Mcp/*
- identifier: public.method.unused
path: app/Mcp/**/*
- identifier: public.method.unused
path: app/Http/Middleware/*
- identifier: public.property.unused