mcpField
L
Laravel MCP Server by OP.GG

Laravel MCP Server by OP.GG

Local
op.ggDeveloper Tools330Updated 6d ago

About Laravel MCP Server by OP.GG

Laravel MCP Server by OP.GG is a Laravel package for registering MCP endpoints through routes in Laravel and Lumen. It uses Streamable HTTP transport and targets PHP teams building MCP servers into existing applications.

Key features

  1. 01Route-based MCP endpoint registration
  2. 02Streamable HTTP as the only transport
  3. 03Tools, resources, templates and prompts per endpoint
  4. 04Dynamic tool filtering by query string
  5. 05Generation of MCP tools from OpenAPI specs

Use cases

  1. 01Adding an MCP interface to an existing Laravel application
  2. 02Converting Swagger or OpenAPI endpoints into MCP tools
  3. 03Exposing different tool sets to clients by URL parameter

MCP support

As an MCP server, it exposes registered tools, resources, prompts and notification handlers to MCP clients through route endpoints, and supports route caching.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

No install method listed yet

We haven’t collected a package or remote endpoint for this server. Follow the instructions in the project README.

Repository

Tools

No tool list yet

Local servers expose tools only once running on your machine, and the maintainer has not provided a tool list.

Details

From the project README

Laravel MCP Server by OP.GG

Build a route-first MCP server in Laravel and Lumen

Build Status Total Downloads Latest Stable Version License

Official Website

English | Português do Brasil | 한국어 | Русский | 简体中文 | 繁體中文 | Polski | Español

Laravel MCP Server Demo

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"}'
Dynamic Tool Filtering by Query String

If one endpoint needs to expose different tool sets based on the incoming URL, attach a dynamic tools resolver to the route. The resolver owns both the declared tool catalog for the endpoint and the per-request visible subset.

use OPGG\LaravelMcpServer\Data\ToolResolutionContext;
use OPGG\LaravelMcpServer\Routing\McpEndpointDefinition;
use OPGG\LaravelMcpServer\Services\ToolService\DynamicToolResolverInterface;

final class LolPhaseToolResolver implements DynamicToolResolverInterface
{
    public function declaredTools(McpEndpointDefinition $endpoint): array
    {
        return [
            \App\MCP\Tools\LolSearchChampionMetaTool::class,
            \App\MCP\Tools\LolGetChampionAnalysisTool::class,
            \App\MCP\Tools\LolGetLiveItemRecommendationsTool::class,
        ];
    }

    public function resolve(
        McpEndpointDefinition $endpoint,
        ToolResolutionContext $context,
    ): array {
        return match ($context->queryParameters['phase'] ?? null) {
            'lobby' => [
                \App\MCP\Tools\LolSearchChampionMetaTool::class,
                \App\MCP\Tools\LolGetChampionAnalysisTool::class,
            ],
            'inprogress' => [
                \App\MCP\Tools\LolGetLiveItemRecommendationsTool::class,
            ],
            default => $this->declaredTools($endpoint),
        };
    }

    public function consumedQueryParameters(): array
    {
        return ['phase'];
    }
}
Route::mcp('/mcp/voice/lol/live')
    ->setServerInfo(
        name: 'OP.GG MCP Server - Voice lol Live',
        version: '1.0.0',
    )
    ->dynamicTools(LolPhaseToolResolver::class);

Example requests:

/mcp/voice/lol/live?phase=lobby
/mcp/voice/lol/live?phase=inprogress

The same filtered tool set is applied consistently to:

  • tools/list
  • tools/call
  • tools/execute
  • POST /tools/{tool_name} when ->enabledApi() is enabled

If the same endpoint also uses POST /tools/{tool_name}, you can optionally expose a public consumedQueryParameters(): array hook on the resolver for query keys that should be used only for filtering and not forwarded as tool arguments. This hook is a documented convention and is not part of DynamicToolResolverInterface; resolvers that omit it will forward those query keys as tool arguments.

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, or none
  • --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, GET endpoints 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([...]) or ->dynamicTools(...)) 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 parameters only (no requestBody) for simpler manual testing.
  • Required fields from each tool inputSchema().required are reflected in Swagger parameter validation.
  • Enum fields are exported with schema.enum so 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/example are 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_JP auto-infer first sample value as default and example.

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 a BackedEnum::class.
  • compact() can be chained after enum() to remove enum from emitted schema and append a compact hint to description (compact(), compact(null), compact(3), or compact('custom hint')).
  • Default compact example count is 3, and it can be overridden per endpoint via Route::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.

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.