A Laravel package for implementing secure Model Context Protocol servers using Streamable HTTP and SSE transport, providing real-time communication and a sca...
Documentation
Laravel MCP Server by OP.GG
Build a route-first MCP server in Laravel and Lumen
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-server2) 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=/mcpQuick 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-toolsFull 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 - 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.jsonUseful 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.jsonExample 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-openapiEnable 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
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.
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
'username',
'description' => 'User name',
'required' => true,
],
];
public string $text = 'Welcome, {username}!';
}Example Resource Class
$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/pintTranslation
pip install -r scripts/requirements.txt
export ANTHROPIC_API_KEY='your-api-key'
python scripts/translate_readme.pyTranslate selected languages:
python scripts/translate_readme.py es koLicense
This project is distributed under the MIT license.
Similar MCP
Based on tags & features
Trending MCP
Most active this week