php-mcp / laravel
The official Laravel integration for the PHP MCP Server package.
Requires
- php: ^8.1
- laravel/framework: ^9.46 || ^10.34 || ^11.29 || ^12.0
- php-mcp/server: ^2.2
Requires (Dev)
- laravel/pint: ^1.13
- mockery/mockery: ^1.6
- orchestra/pest-plugin-testbench: ^2.1
- orchestra/testbench: ^8.0 || ^9.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpunit/phpunit: ^10.0 || ^11.0
- react/http: ^1.11
README
Seamlessly integrate the Model Context Protocol (MCP) into your Laravel applications.
This package is a Laravel compatible wrapper for the powerful php-mcp/server
library. It allows you to effortlessly expose parts of your Laravel application as MCP Tools, Resources, and Prompts, enabling standardized communication with AI assistants like Anthropic's Claude, Cursor IDE, and others.
Key Features:
- Effortless Integration: Designed from the ground up for Laravel, leveraging its service container, configuration, caching, logging, and Artisan console.
- Fluent Element Definition: Define MCP elements programmatically with a clean, Laravely API using the
Mcp
Facade (e.g.,Mcp::tool(...)->description(...)
). - Attribute-Based Discovery: Alternatively, use PHP 8 attributes (
#[McpTool]
, etc.) on your classes and methods, then run a simple Artisan command to discover and cache them. - Flexible Transports:
- Integrated HTTP+SSE: Serve MCP requests directly through your Laravel application's routes, ideal for many setups.
- Dedicated HTTP+SSE Server: Launch a high-performance, standalone ReactPHP-based HTTP server via an Artisan command for demanding scenarios.
- STDIO: Run an MCP server over standard input/output, perfect for CLI-driven clients.
- Robust Configuration: Manage all aspects of your MCP server via the
config/mcp.php
file. - Artisan Commands: Includes commands for serving, discovering elements, and listing registered components.
- Event-Driven Updates: Integrates with Laravel's event system to notify clients of dynamic changes to your MCP elements.
This package utilizes php-mcp/server
v2.1.0+ which supports the 2024-11-05
version of the Model Context Protocol.
Requirements
- PHP >= 8.1
- Laravel >= 10.0
php-mcp/server
^2.1.0 (automatically installed)
Installation
-
Require the Package:
composer require php-mcp/laravel
-
Publish Configuration:
php artisan vendor:publish --provider="PhpMcp\Laravel\Server\McpServiceProvider" --tag="mcp-config"
Configuration
All MCP server settings are managed in config/mcp.php
. Here are the key sections:
Server Information
server
: Basic server identity settingsname
: Your MCP server's name (default: 'Laravel MCP')version
: Server version numberinstructions
: Optional initialization instructions for clients
Discovery Settings
discovery
: Controls how MCP elements are discoveredbase_path
: Root directory for scanning (defaults tobase_path()
)directories
: Paths to scan for MCP attributes (default:['app/Mcp']
)exclude_dirs
: Directories to skip during scans (e.g., 'vendor', 'tests', etc.)definitions_file
: Path to manual element definitions (default:routes/mcp.php
)auto_discover
: Enable automatic discovery in development (default:true
)save_to_cache
: Cache discovery results (default:true
)
Transport Configuration
transports
: Available communication methodsstdio
: CLI-based transportenabled
: Enable themcp:serve
command withstdio
option.
http_dedicated
: Standalone HTTP serverenabled
: Enable themcp:serve
command withhttp
option.host
,port
,path_prefix
settings
http_integrated
: Laravel route-based serverenabled
: Serve through Laravel routesroute_prefix
: URL prefix (default: 'mcp')middleware
: Applied middleware (default: 'web')
Cache & Performance
cache
: Caching configurationstore
: Laravel cache store to usettl
: Cache lifetime in seconds
pagination_limit
: Maximum items returned in list operations
Feature Control
capabilities
: Toggle MCP features- Enable/disable tools, resources, prompts
- Control subscriptions and change notifications
logging
: Server logging configurationchannel
: Laravel log channellevel
: Default log level
Review the published config/mcp.php
file for detailed documentation of all available options and their descriptions.
Defining MCP Elements
PHP MCP Laravel provides two approaches to define your MCP elements: manual registration using a fluent API or attribute-based discovery.
Manual Registration
The recommended approach is using the fluent Mcp
facade to manually register your elements in routes/mcp.php
(this path can be changed in config/mcp.php via the discovery.definitions_file key).
Mcp::tool([MyHandlers::class, 'calculateSum']); Mcp::resource( 'status://app/health', [MyHandlers::class, 'getAppStatus']); Mcp::prompt(MyInvokableTool::class); Mcp::resourceTemplate('user://{id}/data', [MyHandlers::class, 'getUserData']);
The facade provides several registration methods, each with optional fluent configuration methods:
Tools (Mcp::tool()
)
Defines an action or function the MCP client can invoke. Register a tool by providing either:
- Just the handler:
Mcp::tool(MyTool::class)
- Name and handler:
Mcp::tool('my_tool', [MyClass::class, 'method'])
Available configuration methods:
name()
: Override the inferred namedescription()
: Set a custom description
Resources (Mcp::resource()
)
Defines a specific, static piece of content or data identified by a URI. Register a resource by providing:
$uri
(required
): The unique URI for this resource instance (e.g.,config://app/settings
).$handler
: The handler that will return the resource's content.
Available configuration methods:
name(string $name): self
: Sets a human-readable name. Inferred if omitted.description(string $description): self
: Sets a description. Inferred if omitted.mimeType(string $mimeType): self
: Specifies the resource's MIME type. Can sometimes be inferred from the handler's return type or content.size(?int $size): self
: Specifies the resource size in bytes, if known.annotations(array $annotations): self
: Adds MCP-standard annotations (e.g., ['audience' => ['user']]).
Resource Template (Mcp::resourceTemplate()
)
Defines a handler for resource URIs that contain variable parts, allowing dynamic resource instance generation. Register a resource template by providing:
$uriTemplate
(required
): The URI template string (RFC 6570
), e.g.,user://{userId}/profile
.$handler
: The handler method. Its parameters must match the variables in the$uriTemplate
.
Available configuration methods:
name(string $name): self
: Sets a human-readable name for the template type.description(string $description): self
: Sets a description for the template.mimeType(string $mimeType): self
: Sets a default MIME type for resources resolved by this template.annotations(array $annotations): self
: Adds MCP-standard annotations.
Prompts (Mcp::prompt()
)
Defines a generator for MCP prompt messages, often used to construct conversations for an LLM. Register a prompt by providing just the handler, or the name and handler.
$name
(optional
): The MCP prompt name. Inferred if omitted.$handler
: The handler method. Its parameters become the prompt's input arguments.
The package automatically resolves handlers through Laravel's service container, allowing you to inject dependencies through constructor injection. Each registration method accepts either an invokable class or a [class, method]
array.
The fluent methods like description()
, name()
, and mimeType()
are optional. When omitted, the package intelligently infers these values from your handler's method signatures, return types, and DocBlocks. Use these methods only when you need to override the automatically generated metadata.
Manually registered elements are always available regardless of cache status and take precedence over discovered elements with the same identifier.
Attribute-Based Discovery
As an alternative, you can use PHP 8 attributes to mark your methods or invokable classes as MCP elements. That way, you don't have to manually register them in the definitions file:
namespace App\Mcp; use PhpMcp\Server\Attributes\McpTool; use PhpMcp\Server\Attributes\McpResource; class DiscoveredElements { #[McpTool(name: 'echo_discovered')] public function echoMessage(string $message): string { return "Discovered echo: {$message}"; } #[McpResource(uri: 'status://server/health', mimeType: 'application/json')] public function getServerHealth(): array { return ['status' => 'healthy', 'uptime' => 123]; } }
When auto_discover
enabled in your config, these elements are automatically discovered when needed. For production or to manually trigger discovery, run:
php artisan mcp:discover
This command scans the configured directories, registers the discovered elements, and caches the results for improved performance. Use the --no-cache
flag to skip caching or --force
to perform a fresh scan regardless of cache status.
See the php-mcp/server
documentation for detailed information on attribute parameters and return value formatting.
Running the MCP Server
PHP MCP Laravel offers three transport options to serve your MCP elements.
Integrated HTTP+SSE via Laravel Routes
The most convenient option for getting started is serving MCP directly through your Laravel application's routes:
// Client connects to: http://your-app.test/mcp/sse // No additional processes needed
Configuration:
- Ensure
mcp.transports.http_integrated.enabled
istrue
in your config - The package registers routes at
/mcp/sse
(GET) and/mcp/message
(POST) by default - You can customize the prefix, middleware, and domain in
config/mcp.php
CSRF Protection: You must exclude the MCP message endpoint from CSRF verification:
For Laravel 11+:
// bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ config('mcp.transports.http_integrated.route_prefix') . '/message', ]); })
For Laravel 10 and below:
// app/Http/Middleware/VerifyCsrfToken.php protected $except = [ 'mcp/message', // Adjust if you changed the route prefix ];
Server Environment Considerations: Standard synchronous servers like PHP's built-in server or basic PHP-FPM setups can struggle with SSE connections. For eg, a single PHP-FPM worker will be tied up for each active SSE connection. For production, consider using Laravel Octane with Swoole/RoadRunner or properly configured Nginx with sufficient PHP-FPM workers.
Dedicated HTTP+SSE Server (Recommended)
For production environments or high-traffic applications, the dedicated HTTP server provides better performance and isolation:
php artisan mcp:serve --transport=http
This launches a standalone ReactPHP-based HTTP server specifically for MCP traffic:
Configuration:
- Ensure
mcp.transports.http_dedicated.enabled
istrue
in your config - Default server listens on
127.0.0.1:8090
with path prefix/mcp
- Configure through any of these methods:
- Environment variables:
MCP_HTTP_DEDICATED_HOST
,MCP_HTTP_DEDICATED_PORT
,MCP_HTTP_DEDICATED_PATH_PREFIX
- Edit values directly in
config/mcp.php
- Override at runtime:
--host=0.0.0.0 --port=8091 --path-prefix=custom_mcp
- Environment variables:
This is a blocking, long-running process that should be managed with Supervisor, systemd, or Docker in production environments.
STDIO Transport for Direct Client Integration
Ideal for Cursor IDE and other MCP clients that directly launch server processes:
php artisan mcp:serve
# or explicitly:
php artisan mcp:serve --transport=stdio
Client Configuration: Configure your MCP client to execute this command directly. For example, in Cursor:
// .cursor/mcp.json { "mcpServers": { "my-laravel-stdio": { "command": "php", "args": [ "/full/path/to/your/laravel/project/artisan", "mcp:serve" ] } } }
Important: When using STDIO transport, your handler code must not write to STDOUT using echo, print, or similar functions. Use Laravel's logger or STDERR for any debugging output.
Listing Registered Elements
To see which MCP elements your server has registered (both manual and discovered/cached):
php artisan mcp:list # Specific types: php artisan mcp:list tools php artisan mcp:list resources # JSON output: php artisan mcp:list --json
Dynamic Updates (Events)
If your available MCP elements or resource content change while the server is running, you can notify connected clients (most relevant for HTTP transports).
-
List Changes (Tools, Resources, Prompts): Dispatch the corresponding Laravel event. The package includes listeners to send the appropriate MCP notification.
use PhpMcp\Laravel\Server\Events\ToolsListChanged; use PhpMcp\Laravel\Server\Events\ResourcesListChanged; use PhpMcp\Laravel\Server\Events\PromptsListChanged; ToolsListChanged::dispatch(); // ResourcesListChanged::dispatch(); // PromptsListChanged::dispatch();
-
Specific Resource Content Update: Dispatch the
PhpMcp\Laravel\Server\Events\ResourceUpdated
event with the URI of the changed resource.use PhpMcp\Laravel\Server\Events\ResourceUpdated; $resourceUri = 'file:///path/to/updated_file.txt'; // ... your logic that updates the resource ... ResourceUpdated::dispatch($resourceUri);
The
McpNotificationListener
will handle sending thenotifications/resource/updated
MCP notification to clients subscribed to that URI.
Testing
For your application tests, you can mock the Mcp
facade or specific MCP handlers as needed. When testing MCP functionality itself, consider integration tests that make HTTP requests to your integrated MCP endpoints (if used) or command tests for Artisan commands.
Contributing
Please see CONTRIBUTING.md in the main php-mcp/server
repository for general contribution guidelines. For issues or PRs specific to this Laravel package, please use this repository's issue tracker.
License
The MIT License (MIT). See LICENSE.