---
name: mcp-development
description: "Use this skill for Laravel MCP development only. Trigger when creating or editing MCP tools, resources, prompts, or servers in Laravel projects. Covers: artisan make:mcp-* generators, mcp:inspector, routes/ai.php, Tool/Resource/Prompt classes, schema validation, shouldRegister(), OAuth setup, URI templates, read-only attributes, and MCP debugging. Do not use for non-Laravel MCP projects or generic AI features without MCP."
license: MIT
metadata:
  author: laravel
---
@php
/** @var \Laravel\Boost\Install\GuidelineAssist $assist */
@endphp
# MCP Development

## Documentation First

**CRITICAL**: Always use `search-docs` BEFORE writing MCP code. The documentation is version-specific, comprehensive, and always up-to-date.

@boostsnippet("Search MCP Documentation", "bash")
# Example searches
search-docs(['mcp tools', 'mcp resources', 'mcp validation'])
@endboostsnippet

## Quick Reference

### Artisan Commands

Create MCP Primitives
```bash
{{ $assist->artisanCommand('make:mcp-tool ToolName') }}
{{ $assist->artisanCommand('make:mcp-resource ResourceName') }}
{{ $assist->artisanCommand('make:mcp-prompt PromptName') }}
{{ $assist->artisanCommand('make:mcp-server ServerName') }}
```

### Basic Tool Implementation

@boostsnippet("Tool Example", "php")
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;

class MyTool extends Tool
{
    protected string $description = 'Tool description for LLM';

    public function schema(JsonSchema $schema): array
    {
        return [
            'param' => $schema->string()->required(),
        ];
    }

    public function handle(Request $request): Response
    {
        return Response::text($request->get('param'));
    }
}
@endboostsnippet

### Basic Resource Implementation

@boostsnippet("Resource Example", "php")
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Resource;

class MyResource extends Resource
{
    protected string $description = 'Resource description';
    protected string $uri = 'file://path/to/resource';
    protected string $mimeType = 'text/markdown';

    public function handle(): Response
    {
        return Response::text($content);
    }
}
@endboostsnippet

### Response Methods

@boostsnippet("Available Responses", "php")
Response::text('Text content');
Response::error('Error message');
Response::structured(['key' => 'value']);
@endboostsnippet

## Testing MCP Primitives

Test tools, resources, and prompts directly on their server:

@boostsnippet("Test MCP Primitives", "php")
// Test a tool
$response = MyServer::tool(MyTool::class, ['param' => 'value']);
$response->assertOk()->assertSee('Expected text');

// Test as authenticated user
$response = MyServer::actingAs($user)->tool(MyTool::class, [...]);

// Available assertions
$response->assertOk();
$response->assertSee('text');
$response->assertHasErrors();
$response->assertHasNoErrors();
$response->assertName('tool-name');
$response->assertSentNotification('event/type', ['data' => 'value']);
@endboostsnippet

### MCP Inspector

Test interactively using the inspector:

<!--Launch MCP Inspector-->
```bash
{{ $assist->artisanCommand('mcp:inspector mcp/my-server') }}  # Web server
{{ $assist->artisanCommand('mcp:inspector my-server') }}      # Local server
```

## Available Features

The following features exist—**use `search-docs` for implementation details**:

- **Tools**: `schema()`, validation, annotations (`#[IsReadOnly]`, `#[IsDestructive]`, etc.)
- **Resources**: URI templates (`HasUriTemplate`), Dynamic resources
- **Prompts**: Arguments, multi-message responses
- **All primitives**: Dependency injection, `shouldRegister()`, validation
- **Responses**: Text, error, structured, streaming, metadata
- **Server registration**: Web routes, local routes, OAuth

## Critical Imports

@boostsnippet("Correct Imports", "php")
use Laravel\Mcp\Request;           // NOT Laravel\Mcp\Server\Request
use Laravel\Mcp\Response;          // NOT Laravel\Mcp\Server\Response
use Laravel\Mcp\Server\Tool;
use Laravel\Mcp\Server\Resource;
use Laravel\Mcp\Server\Prompt;
use Illuminate\Contracts\JsonSchema\JsonSchema;
@endboostsnippet

## Common Pitfalls

- **Not using `search-docs` before implementation**
- Wrong imports: `Laravel\Mcp\Server\Request` (wrong) vs `Laravel\Mcp\Request` (correct)
- Forgetting `schema()` method for tools with parameters
- Missing required properties: `$description`, `$uri`, `$mimeType`
- Wrong response pattern: `new Response()` instead of `Response::text()`
- Running `mcp:start` command locally (hangs waiting for stdin)
