# Laravel

> An SDK building Laravel MCP servers

- **Type:** MCP server
- **Install:** `agentstack add mcp-php-mcp-laravel`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [php-mcp](https://agentstack.voostack.com/s/php-mcp)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [php-mcp](https://github.com/php-mcp)
- **Source:** https://github.com/php-mcp/laravel

## Install

```sh
agentstack add mcp-php-mcp-laravel
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Laravel MCP Server SDK

[](https://packagist.org/packages/php-mcp/laravel)
[](https://packagist.org/packages/php-mcp/laravel)
[](LICENSE)

**A comprehensive Laravel SDK for building [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) servers with enterprise-grade features and Laravel-native integrations.**

This SDK provides a Laravel-optimized wrapper for the powerful [`php-mcp/server`](https://github.com/php-mcp/server) library, enabling you to expose your Laravel application's functionality as standardized MCP **Tools**, **Resources**, **Prompts**, and **Resource Templates** for AI assistants like Anthropic's Claude, Cursor IDE, OpenAI's ChatGPT, and others.

## Key Features

- **Laravel-Native Integration**: Deep integration with Laravel's service container, configuration, caching, logging, sessions, and Artisan console
- **Fluent Element Definition**: Define MCP elements with an elegant, Laravel-style API using the `Mcp` facade
- **Attribute-Based Discovery**: Use PHP 8 attributes (`#[McpTool]`, `#[McpResource]`, etc.) with automatic discovery and caching
- **Advanced Session Management**: Laravel-native session handlers (file, database, cache, redis) with automatic garbage collection
- **Flexible Transport Options**:
  - **Integrated HTTP**: Serve through Laravel routes with middleware support
  - **Dedicated HTTP Server**: High-performance standalone ReactPHP server
  - **STDIO**: Command-line interface for direct client integration
- **Streamable Transport**: Enhanced HTTP transport with resumability and event sourcing
- **Artisan Commands**: Commands for serving, discovery, and element management
- **Full Test Coverage**: Comprehensive test suite ensuring reliability

This package supports the **2025-03-26** version of the Model Context Protocol.

## Requirements

- **PHP** >= 8.1
- **Laravel** >= 10.0
- **Extensions**: `json`, `mbstring`, `pcre` (typically enabled by default)

## Installation

Install the package via Composer:

```bash
composer require php-mcp/laravel:^3.0 -W
```

Publish the configuration file:

```bash
php artisan vendor:publish --provider="PhpMcp\Laravel\McpServiceProvider" --tag="mcp-config"
```

For database session storage, publish the migration:

```bash
php artisan vendor:publish --provider="PhpMcp\Laravel\McpServiceProvider" --tag="mcp-migrations"
php artisan migrate
```

## Configuration

All MCP server settings are managed through `config/mcp.php`, which contains comprehensive documentation for each option. The configuration covers server identity, capabilities, discovery settings, session management, transport options, caching, and logging. All settings support environment variables for easy deployment management.

Key configuration areas include:
- **Server Info**: Name, version, and basic identity
- **Capabilities**: Control which MCP features are enabled (tools, resources, prompts, etc.)
- **Discovery**: How elements are found and cached from your codebase
- **Session Management**: Multiple storage backends (file, database, cache, redis) with automatic garbage collection
- **Transports**: STDIO, integrated HTTP, and dedicated HTTP server options
- **Performance**: Caching strategies and pagination limits

Review the published `config/mcp.php` file for detailed documentation of all available options and their environment variable overrides.

## Defining MCP Elements

Laravel MCP provides two powerful approaches for defining MCP elements: **Manual Registration** (using the fluent `Mcp` facade) and **Attribute-Based Discovery** (using PHP 8 attributes). Both can be combined, with manual registrations taking precedence.

### Element Types

- **Tools**: Executable functions/actions (e.g., `calculate`, `send_email`, `query_database`)
- **Resources**: Static content/data accessible via URI (e.g., `config://settings`, `file://readme.txt`)
- **Resource Templates**: Dynamic resources with URI patterns (e.g., `user://{id}/profile`)
- **Prompts**: Conversation starters/templates (e.g., `summarize`, `translate`)

### 1. Manual Registration

Define your MCP elements using the elegant `Mcp` facade in `routes/mcp.php`:

```php
name('add_numbers')
    ->description('Add two numbers together');

// Register an invokable class as a tool
Mcp::tool(EmailService::class)
    ->description('Send emails to users');

// Register a closure as a tool with custom input schema
Mcp::tool(function(float $x, float $y): float {
    return $x * $y;
})
    ->name('multiply')
    ->description('Multiply two numbers')
    ->inputSchema([
        'type' => 'object',
        'properties' => [
            'x' => ['type' => 'number', 'description' => 'First number'],
            'y' => ['type' => 'number', 'description' => 'Second number'],
        ],
        'required' => ['x', 'y'],
    ]);

// Register a resource with metadata
Mcp::resource('config://app/settings', [UserService::class, 'getAppSettings'])
    ->name('app_settings')
    ->description('Application configuration settings')
    ->mimeType('application/json')
    ->size(1024);

// Register a closure as a resource
Mcp::resource('system://time', function(): string {
    return now()->toISOString();
})
    ->name('current_time')
    ->description('Get current server time')
    ->mimeType('text/plain');

// Register a resource template for dynamic content
Mcp::resourceTemplate('user://{userId}/profile', [UserService::class, 'getUserProfile'])
    ->name('user_profile')
    ->description('Get user profile by ID')
    ->mimeType('application/json');

// Register a closure as a resource template
Mcp::resourceTemplate('file://{path}', function(string $path): string {
    if (!file_exists($path) || !is_readable($path)) {
        throw new \InvalidArgumentException("File not found or not readable: {$path}");
    }
    return file_get_contents($path);
})
    ->name('file_reader')
    ->description('Read file contents by path')
    ->mimeType('text/plain');

// Register a prompt generator
Mcp::prompt([PromptService::class, 'generateWelcome'])
    ->name('welcome_user')
    ->description('Generate a personalized welcome message');

// Register a closure as a prompt
Mcp::prompt(function(string $topic, string $tone = 'professional'): array {
    return [
        [
            'role' => 'user',
            'content' => "Write a {$tone} summary about {$topic}. Make it informative and engaging."
        ]
    ];
})
    ->name('topic_summary')
    ->description('Generate topic summary prompts');
```

**Available Fluent Methods:**

**For All Elements:**
- `name(string $name)`: Override the inferred name
- `description(string $description)`: Set a custom description

**For Tools:**
- `annotations(ToolAnnotations $annotations)`: Add MCP tool annotations
- `inputSchema(array $schema)`: Define custom JSON schema for parameters

**For Resources:**
- `mimeType(string $mimeType)`: Specify content type
- `size(int $size)`: Set content size in bytes
- `annotations(Annotations $annotations)`: Add MCP annotations

**For Resource Templates:**
- `mimeType(string $mimeType)`: Specify content type
- `annotations(Annotations $annotations)`: Add MCP annotations

**Handler Formats:**
- `[ClassName::class, 'methodName']` - Class method
- `InvokableClass::class` - Invokable class with `__invoke()` method
- `function(...) { ... }` - Callables (v3.2+)

### 2. Attribute-Based Discovery

Alternatively, you can use PHP 8 attributes to mark your methods or classes as MCP elements, in which case, you don't have to register them in them `routes/mcp.php`:

```php
 123,
            'email' => $email,
            'role' => $role,
            'created_at' => now()->toISOString(),
        ];
    }

    /**
     * Get application configuration.
     */
    #[McpResource(
        uri: 'config://app/settings',
        mimeType: 'application/json'
    )]
    public function getAppSettings(): array
    {
        return [
            'theme' => config('app.theme', 'light'),
            'timezone' => config('app.timezone'),
            'features' => config('app.features', []),
        ];
    }

    /**
     * Get user profile by ID.
     */
    #[McpResourceTemplate(
        uriTemplate: 'user://{userId}/profile',
        mimeType: 'application/json'
    )]
    public function getUserProfile(string $userId): array
    {
        return [
            'id' => $userId,
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'profile' => [
                'bio' => 'Software developer',
                'location' => 'New York',
            ],
        ];
    }

    /**
     * Generate a welcome message prompt.
     */
    #[McpPrompt(name: 'welcome_user')]
    public function generateWelcome(string $username, string $role = 'user'): array
    {
        return [
            [
                'role' => 'user',
                'content' => "Create a personalized welcome message for {$username} with role {$role}. Be warm and professional."
            ]
        ];
    }
}
```

**Discovery Process:**

Elements marked with attributes are automatically discovered when:
- `auto_discover` is enabled in configuration (default: `true`)
- You run `php artisan mcp:discover` manually

```bash
# Discover and cache MCP elements
php artisan mcp:discover

# Force re-discovery (ignores cache)
php artisan mcp:discover --force

# Discover without saving to cache
php artisan mcp:discover --no-cache
```

### Element Precedence

- **Manual registrations** always override discovered elements with the same identifier
- **Discovered elements** are cached for performance
- **Cache** is automatically invalidated on fresh discovery runs

## Running the MCP Server

Laravel MCP offers three transport options, each optimized for different deployment scenarios:

### 1. STDIO Transport

**Best for:** Direct client execution, Cursor IDE, command-line tools

```bash
php artisan mcp:serve --transport=stdio
```

**Client Configuration (Cursor IDE):**

```json
{
    "mcpServers": {
        "my-laravel-app": {
            "command": "php",
            "args": [
                "/absolute/path/to/your/laravel/project/artisan",
                "mcp:serve",
                "--transport=stdio"
            ]
        }
    }
}
```

> ⚠️ **Important**: When using STDIO transport, never write to `STDOUT` in your handlers (use Laravel's logger or `STDERR` for debugging). `STDOUT` is reserved for JSON-RPC communication.

### 2. Integrated HTTP Transport

**Best for:** Development, applications with existing web servers, quick setup

The integrated transport serves MCP through your Laravel application's routes:

```php
// Routes are automatically registered at:
// GET  /mcp       - Streamable connection endpoint
// POST /mcp       - Message sending endpoint  
// DELETE /mcp     - Session termination endpoint

// Legacy mode (if enabled):
// GET  /mcp/sse   - Server-Sent Events endpoint
// POST /mcp/message - Message sending endpoint
```

**CSRF Protection Configuration:**

Add the MCP routes to your CSRF exclusions:

**Laravel 11+:**
```php
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'mcp',           // For streamable transport (default)
        'mcp/*',   // For legacy transport (if enabled)
    ]);
})
```

**Laravel 10 and below:**
```php
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'mcp',           // For streamable transport (default)
    'mcp/*',   // For legacy transport (if enabled)
];
```

**Configuration Options:**

```php
'http_integrated' => [
    'enabled' => true,
    'route_prefix' => 'mcp',           // URL prefix
    'middleware' => ['api'],           // Applied middleware
    'domain' => 'api.example.com',     // Optional domain
    'legacy' => false,                 // Use legacy SSE transport instead
],
```

**Client Configuration:**

```json
{
    "mcpServers": {
        "my-laravel-app": {
            "url": "https://your-app.test/mcp"
        }
    }
}
```

**Server Environment Considerations:**

Standard synchronous servers struggle with persistent SSE connections, as each active connection ties up a worker process. This affects both development and production environments.

**For Development:**
- **PHP's built-in server** (`php artisan serve`) won't work - the SSE stream locks the single process
- **Laravel Herd** (recommended for local development)
- **Properly configured Nginx** with multiple PHP-FPM workers
- **Laravel Octane** with Swoole/RoadRunner for async handling
- **Dedicated HTTP server** (`php artisan mcp:serve --transport=http`)

**For Production:**
- **Dedicated HTTP server** (strongly recommended)
- **Laravel Octane** with Swoole/RoadRunner
- **Properly configured Nginx** with sufficient PHP-FPM workers

### 3. Dedicated HTTP Server (Recommended for Production)

**Best for:** Production environments, high-traffic applications, multiple concurrent clients

Launch a standalone ReactPHP-based HTTP server:

```bash
# Start dedicated server
php artisan mcp:serve --transport=http

# With custom configuration
php artisan mcp:serve --transport=http \
    --host=0.0.0.0 \
    --port=8091 \
    --path-prefix=mcp_api
```

**Configuration Options:**

```php
'http_dedicated' => [
    'enabled' => true,
    'host' => '127.0.0.1',              // Bind address
    'port' => 8090,                     // Port number
    'path_prefix' => 'mcp',             // URL path prefix
    'legacy' => false,                  // Use legacy transport
    'enable_json_response' => false,    // JSON mode vs SSE streaming
    'event_store' => null,              // Event store for resumability
    'ssl_context_options' => [],        // SSL configuration
],
```

**Transport Modes:**

- **Streamable Mode** (`legacy: false`): Enhanced transport with resumability and event sourcing
- **Legacy Mode** (`legacy: true`): Deprecated HTTP+SSE transport. 

**JSON Response Mode:**

```php
'enable_json_response' => true,  // Returns immediate JSON responses
'enable_json_response' => false, // Uses SSE streaming (default)
```

- **JSON Mode**: Returns immediate responses, best for fast-executing tools
- **SSE Mode**: Streams responses, ideal for long-running operations

**Production Deployment:**

This creates a long-running process that should be managed with:

- **Supervisor** (recommended)
- **systemd** 
- **Docker** containers
- **Process managers**

Example Supervisor configuration:

```ini
[program:laravel-mcp]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel/artisan mcp:serve --transport=http
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/laravel-mcp.log
```

For comprehensive production deployment guides, see the [php-mcp/server documentation](https://github.com/php-mcp/server#-production-deployment).

## Artisan Commands

Laravel MCP includes several Artisan commands for managing your MCP server:

### Discovery Command

Discover and cache MCP elements from your codebase:

```bash
# Discover elements and update cache
php artisan mcp:discover

# Force re-discovery (ignore existing cache)
php artisan mcp:discover --force

# Discover without updating cache
php artisan mcp:discover --no-cache
```

**Output Example:**
```
Starting MCP element discovery...
Discovery complete.

┌─────────────────────┬───────┐
│ Element Type        │ Count │
├─────────────────────┼───────┤
│ Tools               │ 5     │
│ Resources           │ 3     │
│ Resource Templates  │ 2     │
│ Prompts             │ 1     │
└─────────────────────┴───────┘

MCP element definitions updated and cached.
```

### List Command

View registered MCP elements:

```bash
# List all elements
php artisan mcp:list

# List specific type
php artisan mcp:list tools
php artisan mcp:list resources
php artisan mcp:list prompts
php artisan mcp:list templates

# JSON output
php artisan mcp:list --json
```

**Output Example

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [php-mcp](https://github.com/php-mcp)
- **Source:** [php-mcp/laravel](https://github.com/php-mcp/laravel)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-php-mcp-laravel
- Seller: https://agentstack.voostack.com/s/php-mcp
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
