Laravel MCP Server
A Laravel package for building secure Model Context Protocol servers with real-time communication using SSE.
Laravel MCP Server by OP.GG
Build a route-first MCP server in Laravel and Lumen
English | Português do Brasil | 한국어 | Русский | 简体中文 | 繁體中文 | Polski | Español
Breaking Changes 2.0.0
- Endpoint setup moved from config-driven registration to route-driven registration.
- Streamable HTTP is the only supported transport.
- Server metadata mutators are consolidated into
setServerInfo(...). - Legacy tool transport methods were removed from runtime (
messageType(),ProcessMessageType::SSE).
Full migration guide: docs/migrations/v2.0.0-migration.md
Overview
Laravel MCP Server provides route-based MCP endpoint registration for Laravel and Lumen.
Key points:
- Streamable HTTP transport
- Route-first configuration (
Route::mcp(...)/McpRoute::register(...)) - Tool, resource, resource template, and prompt registration per endpoint
- Route cache compatible endpoint metadata
Requirements
- PHP >= 8.2
- Laravel (Illuminate) >= 9.x
- Lumen >= 9.x (optional)
Quick Start
1) Install
composer require opgginc/laravel-mcp-server
2) Register an endpoint (Laravel)
use Illuminate\Support\Facades\Route;
use OPGG\LaravelMcpServer\Enums\ProtocolVersion;
use OPGG\LaravelMcpServer\Services\ToolService\Examples\HelloWorldTool;
use OPGG\LaravelMcpServer\Services\ToolService\Examples\VersionCheckTool;
Route::mcp('/mcp')
->setServerInfo(
name: 'OP.GG MCP Server',
version: '2.0.0',
)
->setConfig(
compactEnumExampleCount: 3,
)
->setProtocolVersion(ProtocolVersion::V2025_11_25)
->enabledApi()
->tools([
HelloWorldTool::class,
VersionCheckTool::class,
]);
If you need compatibility with clients that do not support 2025-11-25, set:
->setProtocolVersion(ProtocolVersion::V2025_06_18)
3) Verify
php artisan route:list | grep mcp
php artisan mcp:test-tool --list --endpoint=/mcp
Quick JSON-RPC check:
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Lumen Setup
// bootstrap/app.php
$app->withFacades();
$app->withEloquent();
$app->register(OPGG\LaravelMcpServer\LaravelMcpServerServiceProvider::class);
use OPGG\LaravelMcpServer\Routing\McpRoute;
use OPGG\LaravelMcpServer\Services\ToolService\Examples\HelloWorldTool;
McpRoute::register('/mcp')
->setServerInfo(
name: 'OP.GG MCP Server',
version: '2.0.0',
)
->tools([
HelloWorldTool::class,
]);
Minimal Security (Production)
Use Laravel middleware on your MCP route group.
use Illuminate\Support\Facades\Route;
Route::middleware([
'auth:sanctum',
'throttle:100,1',
])->group(function (): void {
Route::mcp('/mcp')
->setServerInfo(
name: 'Secure MCP',
version: '2.0.0',
)
->tools([
\App\MCP\Tools\MyCustomTool::class,
]);
});
v2.0.0 Migration Notes (from v1.0.0)
- MCP endpoint setup moved from config to route registration.
- Streamable HTTP is the only transport.
- Server metadata mutators are consolidated into
setServerInfo(...). - Tool migration command is available for legacy signatures:
php artisan mcp:migrate-tools
Full guide: docs/migrations/v2.0.0-migration.md
Advanced Features (Quick Links)
- Create tools:
php artisan make:mcp-tool ToolName - Create resources:
php artisan make:mcp-resource ResourceName - Create resource templates:
php artisan make:mcp-resource-template TemplateName - Create prompts:
php artisan make:mcp-prompt PromptName - Create notifications:
php artisan make:mcp-notification HandlerName --method=notifications/method - Generate from OpenAPI:
php artisan make:swagger-mcp-tool <spec-url-or-file> - Export tools to OpenAPI:
php artisan mcp:export-openapi --output=storage/api-docs-mcp/api-docs.json
Code references:
- Tool examples:
src/Services/ToolService/Examples/ - Resource examples:
src/Services/ResourceService/Examples/ - Prompt service:
src/Services/PromptService/ - Notification handlers:
src/Server/Notification/ - Route builder:
src/Routing/McpRouteBuilder.php
Swagger/OpenAPI -> MCP Tool
Generate MCP tools from a Swagger/OpenAPI spec:
# From URL
php artisan make:swagger-mcp-tool https://api.example.com/openapi.json
# From local file
php artisan make:swagger-mcp-tool ./specs/openapi.json
Useful options:
php artisan make:swagger-mcp-tool ./specs/openapi.json \
--group-by=tag \
--prefix=Billing \
--test-api
--group-by:tag,path, ornone--prefix: class-name prefix for generated tools/resources--test-api: test endpoint connectivity before generation
Generation behavior:
- In interactive mode, you can choose Tool or Resource per endpoint.
- In non-interactive mode,
GETendpoints are generated as Resources and other methods as Tools.
Enhanced Interactive Preview
If you run the command without --group-by, the generator shows an interactive preview of folder structure and file counts before creation.
php artisan make:swagger-mcp-tool ./specs/openapi.json
Example preview output:
Choose how to organize your generated tools and resources:
Tag-based grouping (organize by OpenAPI tags)
Total: 25 endpoints -> 15 tools + 10 resources
Examples: Tools/Pet, Tools/Store, Tools/User
Path-based grouping (organize by API path)
Total: 25 endpoints -> 15 tools + 10 resources
Examples: Tools/Api, Tools/Users, Tools/Orders
No grouping (everything in root folder)
Total: 25 endpoints -> 15 tools + 10 resources
Examples: Tools/, Resources/
After generation, register generated tool classes on your MCP endpoint:
use Illuminate\Support\Facades\Route;
Route::mcp('/mcp')
->setServerInfo(
name: 'Generated MCP Server',
version: '2.0.0',
)
->tools([
\App\MCP\Tools\Billing\CreateInvoiceTool::class,
\App\MCP\Tools\Billing\UpdateInvoiceTool::class,
]);
MCP Tools -> OpenAPI Export
Export all registered ToolInterface classes (via Route::mcp(...)->tools([...])) to an OpenAPI JSON document using each tool's inputSchema().
Only endpoints configured with ->enabledApi() are included in this export and exposed through POST /tools/{tool_name}.
Operations are grouped by endpoint name using OpenAPI tags.
If multiple endpoints register the same tool name, the operation keeps first-registration behavior and merges all matching endpoint names into tags.
If route registration is missing, the command auto-discovers tools under default paths: app/MCP/Tools and app/Tools.
# Default output: storage/api-docs-mcp/api-docs.json
php artisan mcp:export-openapi
# Custom output + metadata
php artisan mcp:export-openapi \
--output=storage/app/mcp.openapi.json \
--title="MCP Tools API" \
--api-version=2.1.0
# Limit to one endpoint (id or path)
php artisan mcp:export-openapi --endpoint=/mcp
# Discover tools from additional directory paths
php artisan mcp:export-openapi --discover-path=app/MCP/Tools
# Existing output is overwritten by default
php artisan mcp:export-openapi
Enable Tool API route generation:
use Illuminate\Support\Facades\Route;
Route::mcp('/mcp')
->setServerInfo(name: 'OP.GG MCP Server', version: '2.0.0')
->enabledApi()
->tools([
\App\MCP\Tools\GreetingTool::class,
]);
Swagger UI testing tip:
- Exported operations use
query parametersonly (norequestBody) for simpler manual testing. - Required fields from each tool
inputSchema().requiredare reflected in Swagger parameter validation. - Enum fields are exported with
schema.enumso Swagger renders dropdown selections. - Array fields are exported with
style=form+explode=true(repeat key format, e.g.desired_output_fields=items&desired_output_fields=runes). /tools/{tool_name}argument parsing prefers query parameters over body/form payloads to avoid Swagger conflicts.- Enum fields without explicit
default/exampleare auto-filled from the first enum value (or first non-null enum value). - String fields with descriptions like
e.g., en_US, ko_KR, ja_JPauto-infer first sample value asdefaultandexample.
Example Tool Class
<?php
namespace App\MCP\Tools;
use App\Enums\Platform;
use OPGG\LaravelMcpServer\JsonSchema\JsonSchema;
use OPGG\LaravelMcpServer\Services\ToolService\ToolInterface;
class GreetingTool implements ToolInterface
{
public function name(): string
{
return 'greeting-tool';
}
public function description(): string
{
return 'Return a greeting message.';
}
public function inputSchema(): array
{
return [
'name' => JsonSchema::string()
->description('Developer Name')
->required(),
'platform' => JsonSchema::string()
->enum(Platform::class)
->description('Client platform')
->compact(),
];
}
public function annotations(): array
{
return [
'readOnlyHint' => true,
'destructiveHint' => false,
];
}
public function execute(array $arguments): mixed
{
return [
'message' => 'Hello '.$arguments['name'],
];
}
}
JsonSchema Builder (Laravel-Style)
This package provides its own JsonSchema builder under the OPGG\LaravelMcpServer namespace.
You can define tool schemas in a Laravel 12-style fluent format while keeping inputSchema(): array.
<?php
namespace App\MCP\Tools;
use App\Enums\Platform;
use OPGG\LaravelMcpServer\JsonSchema\JsonSchema;
use OPGG\LaravelMcpServer\Services\ToolService\ToolInterface;
class WeatherTool implements ToolInterface
{
public function name(): string
{
return 'weather-tool';
}
public function description(): string
{
return 'Get weather by location.';
}
public function inputSchema(): array
{
return [
'location' => JsonSchema::string()
->description('Location to query')
->required(),
'platform' => JsonSchema::string()
->enum(Platform::class)
->description('Client platform'),
'days' => JsonSchema::integer()
->min(1)
->max(7)
->default(1),
];
}
public function annotations(): array
{
return [];
}
public function execute(array $arguments): mixed
{
return ['ok' => true];
}
}
Notes:
- Existing full JSON Schema arrays are still supported.
enum()accepts either an array or aBackedEnum::class.compact()can be chained afterenum()to removeenumfrom emitted schema and append a compact hint todescription(compact(),compact(null),compact(3), orcompact('custom hint')).- Default compact example count is
3, and it can be overridden per endpoint viaRoute::mcp(...)->setConfig(compactEnumExampleCount: N). - When exporting (
tools/list, OpenAPI), property maps are automatically normalized to JSON Schema object format.
Example Prompt Class
<?php
namespace App\MCP\Prompts;
use OPGG\LaravelMcpServer\Services\PromptService\Prompt;
class WelcomePrompt extends Prompt
{
public string $name = 'welcome-user';
public ?string $description = 'Generate a welcome message.';
public array $arguments = [
[
'name' => 'username',
'description' => 'User name',
'required' => true,
],
];
public string $text = 'Welcome, {username}!';
}
Example Resource Class
<?php
namespace App\MCP\Resources;
use OPGG\LaravelMcpServer\Services\ResourceService\Resource;
class BuildInfoResource extends Resource
{
public string $uri = 'app://build-info';
public string $name = 'Build Info';
public ?string $mimeType = 'application/json';
public function read(): array
{
return [
'uri' => $this->uri,
'mimeType' => $this->mimeType,
'text' => json_encode([
'version' => '2.0.0',
'environment' => app()->environment(),
], JSON_THROW_ON_ERROR),
];
}
}
Register Examples on a Route
use App\MCP\Prompts\WelcomePrompt;
use App\MCP\Resources\BuildInfoResource;
use App\MCP\Tools\GreetingTool;
use Illuminate\Support\Facades\Route;
Route::mcp('/mcp')
->setServerInfo(
name: 'Example MCP Server',
version: '2.0.0',
)
->tools([GreetingTool::class])
->resources([BuildInfoResource::class])
->prompts([WelcomePrompt::class]);
Testing and Quality Commands
vendor/bin/pest
vendor/bin/phpstan analyse
vendor/bin/pint
Translation
pip install -r scripts/requirements.txt
export ANTHROPIC_API_KEY='your-api-key'
python scripts/translate_readme.py
Translate selected languages:
python scripts/translate_readme.py es ko
License
This project is distributed under the MIT license.
관련 서버
Scout Monitoring MCP
스폰서Put performance and error data directly in the hands of your AI assistant.
Alpha Vantage MCP Server
스폰서Access financial market data: realtime & historical stock, ETF, options, forex, crypto, commodities, fundamentals, technical indicators, & more
Starwind UI
A server providing tools for developers working with Starwind UI components.
JS Development MCP Server
A server for JavaScript/TypeScript development with intelligent project tooling and testing capabilities.
AI Agent Playwright
An AI agent for the Playwright MCP server, enabling automated web testing and interaction.
Blynk MCP
Blynk's MCP server lets AI coding tools create device templates, manage devices, and read live sensor data on the Blynk IoT platform
ActionKit MCP Starter
A demonstration server for ActionKit, providing access to Slack actions via Claude Desktop.
Kubeshark
MCP access to cluster-wide L4 and L7 network traffic, packets, APIs, and complete payloads.
DevTools MCP Server
A comprehensive MCP server with 30+ developer tools including JSON/XML formatting, UUID generation, hashing, encoding, regex testing, color conversion, JWT decoding, timestamp conversion, and more.
Search Tools MCP Server
An MCP server that enhances code analysis with advanced search and dependency mapping capabilities.
Sequa MCP
A proxy that connects local STDIO with remote MCP servers, enabling IDEs to use MCP without extra infrastructure.
PyMilvus Code Generate Helper
Retrieves relevant code snippets and documents to assist in generating PyMilvus code, requiring a running Milvus instance.