Laravel MCP服务器

为Laravel和Lumen提供基于路由的MCP端点注册服务,支持动态工具过滤和Swagger/OpenAPI集成。

  • by opgginc
  • PHP
  • 本地部署
  • 330 星标
  • 更新于
在 GitHub 查看 opgginc/laravel-mcp-server

使用说明

Laravel MCP Server by OP.GG

Build a route-first MCP server in Laravel and Lumen

Official Website

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

重大变化2.0.0

  • 端点设置从配置驱动的注册转移到路由驱动的注册。
  • 流式HTTP是唯一支持的传输方式。
  • 服务器元数据变异体被整合到 setServerInfo(...).
  • 已从运行时中删除旧工具传输方法(messageType(), ProcessMessageType::SSE).

完整迁移指南: docs/migrations/v2.0.0-migration.md

概述

Laravel MCP Server为Laravel和Lumen提供基于路由的MCP端点注册。

要点:

  • 可流式HTTP传输
  • 路由优先配置(Route::mcp(...) / McpRoute::register(...))
  • 每个端点的工具、资源、资源模板和提示注册
  • 路由缓存兼容端点元数据

需求

  • PHP>=8.2
  • Laravel(发光)>=9.x
  • 流明>=9.x(可选)

快速开始

1) 安装

composer require opgginc/laravel-mcp-server

2) 注册一个端点(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,
    ]);

如果您需要与不支持的客户端兼容 2025-11-25,设置:

->setProtocolVersion(ProtocolVersion::V2025_06_18)

3) 验证

php artisan route:list | grep mcp
php artisan mcp:test-tool --list --endpoint=/mcp

快速JSON-RPC检查:

curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

按查询字符串进行动态工具筛选

如果一个端点需要根据传入的URL公开不同的工具集,请将动态工具解析器附加到路由。 解析器拥有端点的声明工具目录和每个请求的可见子集。

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);

请求示例:

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

相同的过滤工具集一致地应用于:

  • tools/list
  • tools/call
  • tools/execute
  • POST /tools/{tool_name} 当 ->enabledApi() 已启用

如果同一端点也使用 POST /tools/{tool_name},您可以选择公开 consumedQueryParameters(): array 只应使用查询键的解析器挂钩 用于过滤,而不是作为工具参数转发。这个钩子是一个有记录的惯例 不属于 DynamicToolResolverInterface;省略它的解析器将转发这些查询键 作为工具论证。

管腔设置

// 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,
    ]);

最低安全(生产)

在MCP路由组上使用Laravel中间件。

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迁移说明(从v1.0.0开始)

  • MCP端点设置从配置转移到路由注册。
  • 流式HTTP是唯一的传输方式。
  • 服务器元数据变异体被整合到 setServerInfo(...).
  • 工具迁移命令可用于旧签名:
php artisan mcp:migrate-tools

完整指南: docs/migrations/v2.0.0-migration.md

高级功能(快速链接)

  • 创建工具: php artisan make:mcp-tool ToolName
  • 创建资源: php artisan make:mcp-resource ResourceName
  • 创建资源模板: php artisan make:mcp-resource-template TemplateName
  • 创建提示: php artisan make:mcp-prompt PromptName
  • 创建通知: php artisan make:mcp-notification HandlerName --method=notifications/method
  • 从OpenAPI生成: php artisan make:swagger-mcp-tool <spec-url-or-file>
  • 将工具导出到OpenAPI: php artisan mcp:export-openapi --output=storage/api-docs-mcp/api-docs.json

代码参考:

  • 工具示例: src/Services/ToolService/Examples/
  • 资源示例: src/Services/ResourceService/Examples/
  • 及时服务: src/Services/PromptService/
  • 通知处理程序: src/Server/Notification/
  • 路线建设者: src/Routing/McpRouteBuilder.php

Swagger/OpenAPI->MCP工具

根据Swagger/OpenAPI规范生成MCP工具:

# 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

有用的选项:

php artisan make:swagger-mcp-tool ./specs/openapi.json \
  --group-by=tag \
  --prefix=Billing \
  --test-api
  • --group-by: tag, path,或 none
  • --prefix:生成的工具/资源的类名前缀
  • --test-api:生成前测试端点连接

生成行为:

  • 在交互模式下,您可以为每个端点选择“工具”或“资源”。
  • 在非交互模式下, GET 端点作为资源生成,其他方法作为工具生成。

增强的交互式预览

如果你运行命令时没有 --group-by,生成器在创建之前显示文件夹结构和文件计数的交互式预览。

php artisan make:swagger-mcp-tool ./specs/openapi.json

预览输出示例:

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/

生成后,在MCP端点上注册生成的工具类:

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工具->OpenAPI导出

导出所有已注册 ToolInterface 课程(通过 Route::mcp(...)->tools([...]) 或 ->dynamicTools(...))使用每个工具创建OpenAPI JSON文档 inputSchema(). 只有配置了的端点 ->enabledApi() 包含在此导出中,并通过以下方式公开 POST /tools/{tool_name}. 操作按端点分组 name 使用OpenAPI tags. 如果多个端点注册了相同的工具名称,则操作将保留首次注册行为,并将所有匹配的端点名称合并到 tags. 如果缺少路线注册,该命令会自动在默认路径下发现工具: app/MCP/Tools 和 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

启用工具API路由生成:

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测试提示:

  • 导出操作使用 query parameters 仅(否 requestBody)用于更简单的手动测试。
  • 每个工具的必填字段 inputSchema().required 反映在Swagger参数验证中。
  • 枚举字段导出时使用 schema.enum 因此Swagger呈现下拉选择。
  • 数组字段导出时使用 style=form + explode=true (重复密钥格式,例如。 desired_output_fields=items&desired_output_fields=runes).
  • /tools/{tool_name} 参数解析更喜欢查询参数而不是正文/表单有效载荷,以避免Swagger冲突。
  • 无显式枚举字段 default/example 从第一个枚举值(或第一个非空枚举值)自动填充。
  • 具有以下描述的字符串字段 e.g., en_US, ko_KR, ja_JP 自动推断第一个样本值为 default 和 example.

工具类示例

<?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生成器(Laravel风格)

此包在下面提供了自己的JsonSchema构建器 OPGG\LaravelMcpServer 命名空间。 你可以用Laravel 12风格的流畅格式定义工具模式,同时保持 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];
    }
}

笔记:

  • 仍然支持现有的完整JSON模式数组。
  • enum() 接受数组或 BackedEnum::class.
  • compact() 之后可以用链子锁住 enum() 移除 enum 从已发出的模式中提取并附加一个简洁的提示 description (compact(), compact(null), compact(3),或 compact('custom hint')).
  • 默认压缩示例计数为 3,并且可以通过以下方式对每个端点进行覆盖 Route::mcp(...)->setConfig(compactEnumExampleCount: N).
  • 导出时(tools/listOpenAPI),属性映射会自动标准化为JSON模式对象格式。

提示类示例

<?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}!';
}

示例资源类

<?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),
        ];
    }
}

在路线上注册示例

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]);

测试和质量命令

vendor/bin/pest
vendor/bin/phpstan analyse
vendor/bin/pint

翻译

pip install -r scripts/requirements.txt
export ANTHROPIC_API_KEY='your-api-key'
python scripts/translate_readme.py

翻译所选语言:

python scripts/translate_readme.py es ko

许可证

这个项目是在MIT许可下分发的。