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
Wordware
Run your Wordware apps locally with an interactive setup.
Praison AI
AI Agents framework with 64+ built-in MCP tools for search, memory, workflows, code execution, and file operations. Install via `uvx praisonai-mcp`
DevTools Debugger MCP
Exposes full Chrome DevTools Protocol debugging capabilities, including breakpoints, call stacks, and source maps.
GitHub Actions
An MCP Server for the GitHub Actions API, enabling AI assistants to manage and operate GitHub Actions workflows.
Claude Desktop
An MCP server for interacting with Anthropic's Claude on the desktop, based on a DeepLearning.ai course example.
Authless Remote MCP Server on Cloudflare
An example of a remote MCP server deployable on Cloudflare Workers without authentication.
Specifai
Integrate and automate Specifai projects with any MCP-compatible AI tool.
context-mem
Context optimization for AI coding assistants — 99% token savings via 14 content-aware summarizers, 3-layer search, and progressive disclosure. No LLM dependency.
CocoaPods Package README
Retrieve README files and package information from CocoaPods.
maximumsats-mcp
Bitcoin Lightning + Nostr Web-of-Trust tools for agents (L402 pay-per-call endpoints)