Laravel MCP服务器SDK

一个全面的Laravel SDK,用于构建具有企业级功能和Laravel原生集成的Model Context Protocol (MCP)服务器。

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

使用说明

Laravel MCP服务器SDK

用于构建的全面Laravel SDK 模型上下文协议(MCP) 具有企业级功能和Laravel原生集成的服务器。

这个SDK为强大的应用程序提供了一个Laravel优化的包装器 php-mcp/server 库,使您能够将Laravel应用程序的功能作为标准化的MCP公开 工具, 资源, 提示,以及 资源模板 适用于Anthropic的Claude、Cursor IDE、OpenAI的ChatGPT等人工智能助手。

主要特点

  • Laravel原生集成:与Laravel的服务容器、配置、缓存、日志记录、会话和Artisan控制台深度集成
  • 流畅元素定义:使用优雅、拉威尔风格的API定义MCP元素 Mcp 立面
  • 基于属性的发现:使用PHP 8属性(#[McpTool], #[McpResource]等),具有自动发现和缓存功能
  • 高级会话管理:Laravel原生会话处理程序(文件、数据库、缓存、redis),具有自动垃圾收集功能
  • 灵活的运输方式:
    • 集成HTTP:通过Laravel路由提供服务,并支持中间件
    • 专用HTTP服务器:高性能独立ReactPHP服务器
    • 工作室:用于直接客户端集成的命令行界面
  • 可流动运输:具有可恢复性和事件源的增强HTTP传输
  • Artisan命令:用于服务、发现和元素管理的命令
  • 全面测试覆盖:全面的测试套件,确保可靠性

此软件包支持 2025-03-26 模型上下文协议的版本。

需求

  • PHP程序 >= 8.1
  • 拉瑞维尔 >= 10.0
  • 扩展: json, mbstring, pcre (通常默认启用)

安装

通过Composer安装软件包:

composer require php-mcp/laravel:^3.0 -W

发布配置文件:

php artisan vendor:publish --provider="PhpMcp\Laravel\McpServiceProvider" --tag="mcp-config"

对于数据库会话存储,发布迁移:

php artisan vendor:publish --provider="PhpMcp\Laravel\McpServiceProvider" --tag="mcp-migrations"
php artisan migrate

配置

所有MCP服务器设置都通过以下方式管理 config/mcp.php,其中包含每个选项的全面文档。配置包括服务器标识、功能、发现设置、会话管理、传输选项、缓存和日志记录。所有设置都支持环境变量,便于部署管理。

关键配置区域包括:

  • 察看连接信息:名称、版本和基本标识
  • 能力:控制启用哪些MCP功能(工具、资源、提示等)
  • 发现:如何从代码库中查找和缓存元素
  • 会话管理:具有自动垃圾回收功能的多个存储后端(文件、数据库、缓存、redis)
  • 运输:STDIO、集成HTTP和专用HTTP服务器选项
  • 演出:缓存策略和分页限制

查看已发布的 config/mcp.php 文件,以获取所有可用选项及其环境变量覆盖的详细文档。

定义MCP元素

Laravel MCP提供了两种强大的方法来定义MCP元素: 手动注册 (使用流利 Mcp 立面)以及 基于属性的发现 (使用PHP 8属性)。两者可以结合使用,手动注册优先。

元素类型

  • 工具:可执行的功能/动作(例如。, calculate, send_email, query_database)
  • 资源:可通过URI访问的静态内容/数据(例如。, config://settings, file://readme.txt)
  • 资源模板:具有URI模式的动态资源(例如。, user://{id}/profile)
  • 提示:对话发起者/模板(例如。, summarize, translate)

1.手动注册

使用优雅的 Mcp 立面 routes/mcp.php:

<?php

use PhpMcp\Laravel\Facades\Mcp;
use App\Services\{CalculatorService, UserService, EmailService, PromptService};

// Register a simple tool
Mcp::tool([CalculatorService::class, 'add'])
    ->name('add_numbers')
    ->description('Add two numbers together');

// Register an invokable class as a tool
Mcp::tool(EmailService::class)
    ->description('Send emails to users');

// Register a closure as a tool with custom input schema
Mcp::tool(function(float $x, float $y): float {
    return $x * $y;
})
    ->name('multiply')
    ->description('Multiply two numbers')
    ->inputSchema([
        'type' => 'object',
        'properties' => [
            'x' => ['type' => 'number', 'description' => 'First number'],
            'y' => ['type' => 'number', 'description' => 'Second number'],
        ],
        'required' => ['x', 'y'],
    ]);

// Register a resource with metadata
Mcp::resource('config://app/settings', [UserService::class, 'getAppSettings'])
    ->name('app_settings')
    ->description('Application configuration settings')
    ->mimeType('application/json')
    ->size(1024);

// Register a closure as a resource
Mcp::resource('system://time', function(): string {
    return now()->toISOString();
})
    ->name('current_time')
    ->description('Get current server time')
    ->mimeType('text/plain');

// Register a resource template for dynamic content
Mcp::resourceTemplate('user://{userId}/profile', [UserService::class, 'getUserProfile'])
    ->name('user_profile')
    ->description('Get user profile by ID')
    ->mimeType('application/json');

// Register a closure as a resource template
Mcp::resourceTemplate('file://{path}', function(string $path): string {
    if (!file_exists($path) || !is_readable($path)) {
        throw new \InvalidArgumentException("File not found or not readable: {$path}");
    }
    return file_get_contents($path);
})
    ->name('file_reader')
    ->description('Read file contents by path')
    ->mimeType('text/plain');

// Register a prompt generator
Mcp::prompt([PromptService::class, 'generateWelcome'])
    ->name('welcome_user')
    ->description('Generate a personalized welcome message');

// Register a closure as a prompt
Mcp::prompt(function(string $topic, string $tone = 'professional'): array {
    return [
        [
            'role' => 'user',
            'content' => "Write a {$tone} summary about {$topic}. Make it informative and engaging."
        ]
    ];
})
    ->name('topic_summary')
    ->description('Generate topic summary prompts');

可用流畅方法:

对于所有元素:

  • name(string $name):覆盖推断的名称
  • description(string $description):设置自定义描述

对于工具:

  • annotations(ToolAnnotations $annotations):添加MCP工具注释
  • inputSchema(array $schema):为参数定义自定义JSON模式

关于资源:

  • mimeType(string $mimeType):指定内容类型
  • size(int $size):设置内容大小(以字节为单位)
  • annotations(Annotations $annotations):添加MCP注释

对于资源模板:

  • mimeType(string $mimeType):指定内容类型
  • annotations(Annotations $annotations):添加MCP注释

处理程序格式:

  • [ClassName::class, 'methodName'] -类方法
  • InvokableClass::class -可调用类 __invoke() 方法
  • function(...) { ... } -可调用文件(v3.2+)

2.基于属性的发现

或者,您可以使用PHP 8属性将您的方法或类标记为MCP元素,在这种情况下,您不必在其中注册它们 routes/mcp.php:

<?php

namespace App\Services;

use PhpMcp\Server\Attributes\{McpTool, McpResource, McpResourceTemplate, McpPrompt};

class UserService
{
    /**
     * Create a new user account.
     */
    #[McpTool(name: 'create_user')]
    public function createUser(string $email, string $password, string $role = 'user'): array
    {
        // Create user logic
        return [
            'id' => 123,
            'email' => $email,
            'role' => $role,
            'created_at' => now()->toISOString(),
        ];
    }

    /**
     * Get application configuration.
     */
    #[McpResource(
        uri: 'config://app/settings',
        mimeType: 'application/json'
    )]
    public function getAppSettings(): array
    {
        return [
            'theme' => config('app.theme', 'light'),
            'timezone' => config('app.timezone'),
            'features' => config('app.features', []),
        ];
    }

    /**
     * Get user profile by ID.
     */
    #[McpResourceTemplate(
        uriTemplate: 'user://{userId}/profile',
        mimeType: 'application/json'
    )]
    public function getUserProfile(string $userId): array
    {
        return [
            'id' => $userId,
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'profile' => [
                'bio' => 'Software developer',
                'location' => 'New York',
            ],
        ];
    }

    /**
     * Generate a welcome message prompt.
     */
    #[McpPrompt(name: 'welcome_user')]
    public function generateWelcome(string $username, string $role = 'user'): array
    {
        return [
            [
                'role' => 'user',
                'content' => "Create a personalized welcome message for {$username} with role {$role}. Be warm and professional."
            ]
        ];
    }
}

发现过程:

在以下情况下,会自动发现标记有属性的元素:

  • auto_discover 在配置中启用(默认值: true)
  • 你跑 php artisan mcp:discover 手动地
# Discover and cache MCP elements
php artisan mcp:discover

# Force re-discovery (ignores cache)
php artisan mcp:discover --force

# Discover without saving to cache
php artisan mcp:discover --no-cache

元素优先级

  • 手动注册 始终用相同的标识符覆盖已发现的元素
  • 已发现的元素 为了提高性能而缓存
  • 缓存 在新发现运行时自动失效

运行MCP服务器

Laravel MCP提供了三种传输选项,每种选项都针对不同的部署场景进行了优化:

1.STDIO运输

最适合: 直接客户端执行、Cursor IDE、命令行工具

php artisan mcp:serve --transport=stdio

客户端配置(游标IDE):

{
    "mcpServers": {
        "my-laravel-app": {
            "command": "php",
            "args": [
                "/absolute/path/to/your/laravel/project/artisan",
                "mcp:serve",
                "--transport=stdio"
            ]
        }
    }
}

⚠️ 重要:使用STDIO传输时,切勿写入 STDOUT 在你的处理程序中(使用Laravel的logger或 STDERR 用于调试)。 STDOUT 保留用于JSON-RPC通信。

2.集成HTTP传输

最适合: 开发、使用现有web服务器的应用程序、快速设置

集成传输通过Laravel应用程序的路由为MCP提供服务:

// Routes are automatically registered at:
// GET  /mcp       - Streamable connection endpoint
// POST /mcp       - Message sending endpoint  
// DELETE /mcp     - Session termination endpoint

// Legacy mode (if enabled):
// GET  /mcp/sse   - Server-Sent Events endpoint
// POST /mcp/message - Message sending endpoint

CSRF保护配置:

将MCP路线添加到CSRF排除项中:

Laravel 11+:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'mcp',           // For streamable transport (default)
        'mcp/*',   // For legacy transport (if enabled)
    ]);
})

Laravel 10及以下版本:

// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'mcp',           // For streamable transport (default)
    'mcp/*',   // For legacy transport (if enabled)
];

配置选项:

'http_integrated' => [
    'enabled' => true,
    'route_prefix' => 'mcp',           // URL prefix
    'middleware' => ['api'],           // Applied middleware
    'domain' => 'api.example.com',     // Optional domain
    'legacy' => false,                 // Use legacy SSE transport instead
],

客户端配置:

{
    "mcpServers": {
        "my-laravel-app": {
            "url": "https://your-app.test/mcp"
        }
    }
}

服务器环境注意事项:

标准同步服务器难以处理持久的SSE连接,因为每个活动连接都会占用一个工作进程。这会影响开发和生产环境。

发展:

  • PHP内置服务器 (php artisan serve)不起作用-SSE流锁定单个进程
  • Laravel羊群 (建议用于当地开发)
  • 正确配置Nginx 拥有多名PHP-FPM员工
  • Laravel辛烷 使用Swoole/RoadRunner进行异步处理
  • 专用HTTP服务器 (php artisan mcp:serve --transport=http)

生产:

  • 专用HTTP服务器 (强烈推荐)
  • Laravel辛烷 与Swoole/RoadRunner合作
  • 正确配置Nginx 有足够的PHP-FPM工人

3.专用HTTP服务器(建议用于生产)

最适合: 生产环境、高流量应用程序、多个并发客户端

启动一个基于ReactPHP的独立HTTP服务器:

# Start dedicated server
php artisan mcp:serve --transport=http

# With custom configuration
php artisan mcp:serve --transport=http \
    --host=0.0.0.0 \
    --port=8091 \
    --path-prefix=mcp_api

配置选项:

'http_dedicated' => [
    'enabled' => true,
    'host' => '127.0.0.1',              // Bind address
    'port' => 8090,                     // Port number
    'path_prefix' => 'mcp',             // URL path prefix
    'legacy' => false,                  // Use legacy transport
    'enable_json_response' => false,    // JSON mode vs SSE streaming
    'event_store' => null,              // Event store for resumability
    'ssl_context_options' => [],        // SSL configuration
],

运输方式:

  • 流媒体模式 (legacy: false):通过可恢复性和活动来源加强运输
  • 传统模式 (legacy: true):弃用的HTTP+SSE传输。

JSON响应模式:

'enable_json_response' => true,  // Returns immediate JSON responses
'enable_json_response' => false, // Uses SSE streaming (default)
  • JSON模式:返回即时响应,最适合快速执行的工具
  • SSE模式:流式响应,非常适合长时间运行的操作

生产部署:

这将创建一个长时间运行的流程,应使用以下方式进行管理:

  • 主管 (推荐)
  • 系统守护进程
  • 码头工人 容器
  • 流程经理

主管配置示例:

[program:laravel-mcp]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel/artisan mcp:serve --transport=http
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/laravel-mcp.log

有关全面的生产部署指南,请参阅 php-mcp/服务器文档.

Artisan命令

Laravel MCP包含几个用于管理MCP服务器的Artisan命令:

发现命令

从代码库中发现并缓存MCP元素:

# Discover elements and update cache
php artisan mcp:discover

# Force re-discovery (ignore existing cache)
php artisan mcp:discover --force

# Discover without updating cache
php artisan mcp:discover --no-cache

输出示例:

Starting MCP element discovery...
Discovery complete.

┌─────────────────────┬───────┐
│ Element Type        │ Count │
├─────────────────────┼───────┤
│ Tools               │ 5     │
│ Resources           │ 3     │
│ Resource Templates  │ 2     │
│ Prompts             │ 1     │
└─────────────────────┴───────┘

MCP element definitions updated and cached.

list命令

查看已注册的MCP元素:

# List all elements
php artisan mcp:list

# List specific type
php artisan mcp:list tools
php artisan mcp:list resources
php artisan mcp:list prompts
php artisan mcp:list templates

# JSON output
php artisan mcp:list --json

输出示例:

Tools:
┌─────────────────┬──────────────────────────────────────────────┐
│ Name            │ Description                                  │
├─────────────────┼──────────────────────────────────────────────┤
│ add_numbers     │ Add two numbers together                     │
│ send_email      │ Send email to specified recipient            │
│ create_user     │ Create a new user account with validation    │
└─────────────────┴──────────────────────────────────────────────┘

Resources:
┌─────────────────────────┬───────────────────┬─────────────────────┐
│ URI                     │ Name              │ MIME                │
├─────────────────────────┼───────────────────┼─────────────────────┤
│ config://app/settings   │ app_settings      │ application/json    │
│ file://readme.txt       │ readme_file       │ text/plain          │
└─────────────────────────┴───────────────────┴─────────────────────┘

发球指挥

使用各种传输选项启动MCP服务器:

# Interactive mode (prompts for transport selection)
php artisan mcp:serve

# STDIO transport
php artisan mcp:serve --transport=stdio

# HTTP transport with defaults
php artisan mcp:serve --transport=http

# HTTP transport with custom settings
php artisan mcp:serve --transport=http \
    --host=0.0.0.0 \
    --port=8091 \
    --path-prefix=api/mcp

命令选项:

  • --transport:选择运输类型(stdio 或 http)
  • --host:HTTP传输的主机地址
  • --port:HTTP传输的端口号
  • --path-prefix:HTTP传输的URL路径前缀

动态更新和事件

Laravel MCP与Laravel的事件系统集成,为连接的客户端提供实时更新:

列出更改事件

当可用元素更改时通知客户端:

use PhpMcp\Laravel\Events\{ToolsListChanged, ResourcesListChanged, PromptsListChanged};

// Notify clients that available tools have changed
ToolsListChanged::dispatch();

// Notify about resource list changes
ResourcesListChanged::dispatch();

// Notify about prompt list changes  
PromptsListChanged::dispatch();

资源更新事件

特定资源内容更改时通知客户端:

use PhpMcp\Laravel\Events\ResourceUpdated;

// Update a file and notify subscribers
file_put_contents('/path/to/config.json', json_encode($newConfig));
ResourceUpdated::dispatch('file:///path/to/config.json');

// Update database content and notify
User::find(123)->update(['status' => 'active']);
ResourceUpdated::dispatch('user://123/profile');

高级功能

架构验证

服务器根据PHP类型提示和文档块自动生成工具参数的JSON模式。您可以通过以下方式对此进行增强 #[Schema] 高级验证的属性:

use PhpMcp\Server\Attributes\Schema;

class PostService
{
    public function createPost(
        #[Schema(minLength: 5, maxLength: 200)]
        string $title,
        
        #[Schema(minLength: 10)]
        string $content,
        
        #[Schema(enum: ['draft', 'published', 'archived'])]
        string $status = 'draft',
        
        #[Schema(type: 'array', items: ['type' => 'string'])]
        array $tags = []
    ): array {
        return Post::create([
            'title' => $title,
            'content' => $content,
            'status' => $status,
            'tags' => $tags,
        ])->toArray();
    }
}

架构特性:

  • 自动推理 来自PHP类型提示和文档块
  • 参数级别验证 使用 #[Schema] 属性
  • 对……的支持 字符串约束、数值范围、枚举、数组和对象
  • 两者都适用 手动注册和基于属性的发现

有关全面的模式文档和高级功能,请参阅 php-mcp/server模式文档.

完工供应商

为资源模板变量和提示参数提供自动补全建议,以帮助用户发现可用选项:

use PhpMcp\Server\Contracts\CompletionProviderInterface;
use PhpMcp\Server\Contracts\SessionInterface;
use PhpMcp\Server\Attributes\CompletionProvider;

class UserIdCompletionProvider implements CompletionProviderInterface
{
    public function getCompletions(string $currentValue, SessionInterface $session): array
    {
        return User::where('username', 'like', $currentValue . '%')
            ->limit(10)
            ->pluck('username')
            ->toArray();
    }
}

class UserService
{
    public function getUserData(
        #[CompletionProvider(UserIdCompletionProvider::class)]
        string $userId
    ): array {
        return User::where('username', $userId)->first()->toArray();
    }
}

完工特点:

  • 自动完成 用于资源模板变量和提示参数
  • Laravel集成 -使用Eloquent模型、集合等。
  • 会话感知 -完成情况可能因用户会话而异
  • 实时过滤 基于用户输入

有关完成提供程序的详细文档,请参阅 php-mcp/server完成文档.

依赖注入

你的MCP处理程序会自动受益于Laravel的服务容器:

class OrderService
{
    public function __construct(
        private PaymentGateway $gateway,
        private NotificationService $notifications,
        private LoggerInterface $logger
    ) {}

    #[McpTool(name: 'process_order')]
    public function processOrder(array $orderData): array
    {
        $this->logger->info('Processing order', $orderData);
        
        $payment = $this->gateway->charge($orderData['amount']);
        
        if ($payment->successful()) {
            $this->notifications->sendOrderConfirmation($orderData['email']);
            return ['status' => 'success', 'order_id' => $payment->id];
        }
        
        throw new \Exception('Payment failed: ' . $payment->error);
    }
}

异常处理

工具处理程序可以抛出异常,这些异常会自动转换为正确的JSON-RPC错误响应:

#[McpTool(name: 'get_user')]
public function getUser(int $userId): array
{
    $user = User::find($userId);
    
    if (!$user) {
        throw new \InvalidArgumentException("User with ID {$userId} not found");
    }
    
    if (!$user->isActive()) {
        throw new \RuntimeException("User account is deactivated");
    }
    
    return $user->toArray();
}

日志记录和调试

为您的MCP服务器配置全面的日志记录:

// config/mcp.php
'logging' => [
    'channel' => 'mcp',  // Use dedicated log channel
    'level' => 'debug',  // Set appropriate log level
],

在中创建专用日志通道 config/logging.php:

'channels' => [
    'mcp' => [
        'driver' => 'daily',
        'path' => storage_path('logs/mcp.log'),
        'level' => env('MCP_LOG_LEVEL', 'info'),
        'days' => 14,
    ],
],

迁移指南

从v3.0到v3.1

新处理程序类型:

Laravel MCP v3.1引入了对闭包处理程序的支持,扩展到了类方法和可调用类之外:

// v3.0 and earlier - Class-based handlers only
Mcp::tool([CalculatorService::class, 'add'])
    ->name('add_numbers');

Mcp::tool(EmailService::class)  // Invokable class
    ->name('send_email');

// v3.1+ - Now supports closures
Mcp::tool(function(float $x, float $y): float {
    return $x * $y;
})
    ->name('multiply')
    ->description('Multiply two numbers');

Mcp::resource('system://time', function(): string {
    return now()->toISOString();
})
    ->name('current_time');

输入模式支持:

工具现在可以为参数验证定义自定义JSON模式:

// v3.1+ - Custom input schema
Mcp::tool([CalculatorService::class, 'calculate'])
    ->inputSchema([
        'type' => 'object',
        'properties' => [
            'operation' => [
                'type' => 'string',
                'enum' => ['add', 'subtract', 'multiply', 'divide']
            ],
            'numbers' => [
                'type' => 'array',
                'items' => ['type' => 'number'],
                'minItems' => 2
            ]
        ],
        'required' => ['operation', 'numbers']
    ]);

增强的蓝图方法:

蓝图上提供了新的流畅方法:

->inputSchema(array $schema)  // Define custom parameter schema

无重大变更:

所有现有的v3.0代码无需修改即可继续工作。新功能是附加增强功能。

从v2.x到v3.x

配置更改:

// Old structure
'capabilities' => [
    'tools' => ['enabled' => true, 'listChanged' => true],
    'resources' => ['enabled' => true, 'subscribe' => true],
],

// New structure  
'capabilities' => [
    'tools' => true,
    'toolsListChanged' => true,
    'resources' => true,
    'resourcesSubscribe' => true,
],

会话配置:

// Old: Basic configuration
'session' => [
    'driver' => 'cache',
    'ttl' => 3600,
],

// New: Enhanced configuration
'session' => [
    'driver' => 'cache',
    'ttl' => 3600,
    'store' => config('cache.default'),
    'lottery' => [2, 100],
],

运输更新:

  • 默认传输已从sse更改为streaming
  • 新的CSRF排除模式: mcp 而不是 mcp/*
  • 通过自动垃圾收集增强会话管理

重大变更:

  • 删除了不推荐使用的方法,支持新的注册表API
  • 已更新元素注册以使用新的架构格式
  • 更改配置结构以实现更好的组织

示例和用例

电子商务整合

class EcommerceService
{
    #[McpTool(name: 'get_product_info')]
    public function getProductInfo(int $productId): array
    {
        return Product::with(['category', 'reviews'])
            ->findOrFail($productId)
            ->toArray();
    }

    #[McpTool(name: 'search_products')]
    public function searchProducts(
        string $query,
        ?string $category = null,
        int $limit = 10
    ): array {
        return Product::search($query)
            ->when($category, fn($q) => $q->where('category', $category))
            ->limit($limit)
            ->get()
            ->toArray();
    }

    #[McpResource(uri: 'config://store/settings', mimeType: 'application/json')]
    public function getStoreSettings(): array
    {
        return [
            'currency' => config('store.currency'),
            'tax_rate' => config('store.tax_rate'),
            'shipping_zones' => config('store.shipping_zones'),
        ];
    }
}

内容管理

class ContentService
{
    #[McpResourceTemplate(uriTemplate: 'post://{slug}', mimeType: 'text/markdown')]
    public function getPostContent(string $slug): string
    {
        return Post::where('slug', $slug)
            ->firstOrFail()
            ->markdown_content;
    }

    #[McpPrompt(name: 'content_summary')]
    public function generateContentSummary(string $postSlug, int $maxWords = 50): array
    {
        $post = Post::where('slug', $postSlug)->firstOrFail();
        
        return [
            [
                'role' => 'user',
                'content' => "Summarize this blog post in {$maxWords} words or less:\n\n{$post->content}"
            ]
        ];
    }
}

API集成

class ApiService
{
    #[McpTool(name: 'send_notification')]
    public function sendNotification(
        #[Schema(format: 'email')]
        string $email,
        
        string $subject,
        string $message
    ): array {
        $response = Http::post('https://api.emailservice.com/send', [
            'to' => $email,
            'subject' => $subject,
            'body' => $message,
        ]);

        if ($response->failed()) {
            throw new \RuntimeException('Failed to send notification: ' . $response->body());
        }

        return $response->json();
    }
}

贡献

我们欢迎捐款!请看 贡献.md 作为指导方针。

开发设置

# Clone the repository
git clone https://github.com/php-mcp/laravel.git
cd laravel

# Install dependencies
composer install

# Run tests
./vendor/bin/pest

# Check code style
./vendor/bin/pint

许可证

MIT许可证(MIT)。看 许可证 了解详情。

致谢