LaravelDocs(中文)

MCP

Laravel MCP 提供 Model Context Protocol 整合

簡介 (Introduction)

Laravel MCP 為 AI 客戶端提供了一種簡單優雅的方式,透過 Model Context Protocol 與你的 Laravel 應用程式互動。它提供了一個表達力強、流暢的介面來定義伺服器、工具、資源和提示,從而實現與你的應用程式的 AI 驅動互動。

安裝 (Installation)

要開始使用,請使用 Composer 套件管理器將 Laravel MCP 安裝到你的專案中:

composer require laravel/mcp

發布路由 (Publishing Routes)

安裝 Laravel MCP 後,執行 vendor:publish Artisan 命令來發布 routes/ai.php 檔案,你將在其中定義你的 MCP 伺服器:

php artisan vendor:publish --tag=ai-routes

此命令會在你的應用程式的 routes 目錄中建立 routes/ai.php 檔案,你將使用它來註冊你的 MCP 伺服器。

建立伺服器 (Creating Servers)

你可以使用 make:mcp-server Artisan 命令建立一個 MCP 伺服器。伺服器充當中央通訊點,向 AI 客戶端公開 MCP 功能,如工具、資源和提示:

php artisan make:mcp-server WeatherServer

此命令將在 app/Mcp/Servers 目錄中建立一個新的伺服器類別。生成的伺服器類別繼承了 Laravel MCP 的基礎 Laravel\Mcp\Server 類別,並提供了用於註冊工具、資源和提示的屬性:

<?php

namespace App\Mcp\Servers;

use Laravel\Mcp\Server;

class WeatherServer extends Server
{
    /**
     * MCP 伺服器的名稱。
     */
    protected string $name = 'Weather Server';

    /**
     * MCP 伺服器的版本。
     */
    protected string $version = '1.0.0';

    /**
     * MCP 伺服器給 LLM 的指示。
     */
    protected string $instructions = 'This server provides weather information and forecasts.';

    /**
     * 註冊到此 MCP 伺服器的工具。
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
     */
    protected array $tools = [
        // GetCurrentWeatherTool::class,
    ];

    /**
     * 註冊到此 MCP 伺服器的資源。
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
     */
    protected array $resources = [
        // WeatherGuidelinesResource::class,
    ];

    /**
     * 註冊到此 MCP 伺服器的提示。
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
     */
    protected array $prompts = [
        // DescribeWeatherPrompt::class,
    ];
}

伺服器註冊 (Server Registration)

建立伺服器後,你必須在 routes/ai.php 檔案中註冊它以使其可存取。Laravel MCP 提供兩種註冊伺服器的方法:用於 HTTP 可存取伺服器的 web 和用於命令列伺服器的 local

Web 伺服器 (Web Servers)

Web 伺服器是最常見的伺服器類型,可透過 HTTP POST 請求存取,使其成為遠端 AI 客戶端或 Web 整合的理想選擇。使用 web 方法註冊 Web 伺服器:

use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

Mcp::web('/mcp/weather', WeatherServer::class);

就像普通路由一樣,你可以套用 middleware 來保護你的 Web 伺服器:

Mcp::web('/mcp/weather', WeatherServer::class)
    ->middleware(['throttle:mcp']);

本地伺服器 (Local Servers)

本地伺服器作為 Artisan 命令執行,非常適合建立本地 AI 助手整合,如 Laravel Boost。使用 local 方法註冊本地伺服器:

use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

Mcp::local('weather', WeatherServer::class);

一旦註冊,你通常不需要自己手動執行 mcp:start Artisan 命令。相反,設定你的 MCP 客戶端(AI 代理)來啟動伺服器或使用 MCP Inspector

工具 (Tools)

工具使你的伺服器能夠公開 AI 客戶端可以呼叫的功能。它們允許語言模型執行動作、執行程式碼或與外部系統互動:

<?php

namespace App\Mcp\Tools;

use Illuminate\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 工具的描述。
     */
    protected string $description = 'Fetches the current weather forecast for a specified location.';

    /**
     * 處理工具請求。
     */
    public function handle(Request $request): Response
    {
        $location = $request->get('location');

        // Get weather...

        return Response::text('The weather is...');
    }

    /**
     * 取得工具的輸入 schema。
     *
     * @return array<string, \Illuminate\JsonSchema\JsonSchema>
     */
    public function schema(JsonSchema $schema): array
    {
        return [
            'location' => $schema->string()
                ->description('The location to get the weather for.')
                ->required(),
        ];
    }
}

建立工具 (Creating Tools)

要建立工具,請執行 make:mcp-tool Artisan 命令:

php artisan make:mcp-tool CurrentWeatherTool

建立工具後,在伺服器的 $tools 屬性中註冊它:

<?php

namespace App\Mcp\Servers;

use App\Mcp\Tools\CurrentWeatherTool;
use Laravel\Mcp\Server;

class WeatherServer extends Server
{
    /**
     * 註冊到此 MCP 伺服器的工具。
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
     */
    protected array $tools = [
        CurrentWeatherTool::class,
    ];
}

工具名稱、標題和描述 (Tool Name Title Description)

預設情況下,工具的名稱和標題源自類別名稱。例如,CurrentWeatherTool 的名稱將為 current-weather,標題為 Current Weather Tool。你可以透過定義工具的 $name$title 屬性來自訂這些值:

class CurrentWeatherTool extends Tool
{
    /**
     * 工具的名稱。
     */
    protected string $name = 'get-optimistic-weather';

    /**
     * 工具的標題。
     */
    protected string $title = 'Get Optimistic Weather Forecast';

    // ...
}

工具描述不會自動生成。你應該始終透過在工具上定義 $description 屬性來提供有意義的描述:

class CurrentWeatherTool extends Tool
{
    /**
     * 工具的描述。
     */
    protected string $description = 'Fetches the current weather forecast for a specified location.';

    //
}

[!NOTE] 描述是工具 metadata 的關鍵部分,因為它幫助 AI 模型了解何時以及如何有效地使用該工具。

工具輸入 Schemas (Tool Input Schemas)

工具可以定義輸入 schemas 來指定它們接受來自 AI 客戶端的哪些參數。使用 Laravel 的 Illuminate\JsonSchema\JsonSchema 建構器來定義你的工具的輸入需求:

<?php

namespace App\Mcp\Tools;

use Illuminate\JsonSchema\JsonSchema;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 取得工具的輸入 schema。
     *
     * @return array<string, JsonSchema>
     */
    public function schema(JsonSchema $schema): array
    {
        return [
            'location' => $schema->string()
                ->description('The location to get the weather for.')
                ->required(),

            'units' => $schema->string()
                ->enum(['celsius', 'fahrenheit'])
                ->description('The temperature units to use.')
                ->default('celsius'),
        ];
    }
}

驗證工具參數 (Validating Tool Arguments)

JSON Schema 定義提供了工具參數的基本結構,但你可能還想強制執行更複雜的驗證規則。

Laravel MCP 與 Laravel 的驗證功能無縫整合。你可以在工具的 handle 方法中驗證傳入的工具參數:

<?php

namespace App\Mcp\Tools;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 處理工具請求。
     */
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'location' => 'required|string|max:100',
            'units' => 'in:celsius,fahrenheit',
        ]);

        // Fetch weather data using the validated arguments...
    }
}

驗證失敗時,AI 客戶端將根據你提供的錯誤訊息採取行動。因此,提供清晰且可操作的錯誤訊息至關重要:

$validated = $request->validate([
    'location' => ['required','string','max:100'],
    'units' => 'in:celsius,fahrenheit',
],[
    'location.required' => 'You must specify a location to get the weather for. For example, "New York City" or "Tokyo".',
    'units.in' => 'You must specify either "celsius" or "fahrenheit" for the units.',
]);

工具依賴注入 (Tool Dependency Injection)

Laravel service container 用於解析所有工具。因此,你可以在建構函式中對工具可能需要的任何依賴進行型別提示。宣告的依賴將自動解析並注入到工具實例中:

<?php

namespace App\Mcp\Tools;

use App\Repositories\WeatherRepository;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 建立一個新的工具實例。
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    // ...
}

除了建構函式注入外,你還可以在工具的 handle() 方法中對依賴進行型別提示。當方法被呼叫時,service container 將自動解析並注入依賴:

<?php

namespace App\Mcp\Tools;

use App\Repositories\WeatherRepository;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 處理工具請求。
     */
    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $location = $request->get('location');

        $forecast = $weather->getForecastFor($location);

        // ...
    }
}

工具註解 (Tool Annotations)

你可以使用 annotations 增強你的工具,以向 AI 客戶端提供額外的 metadata。這些註解幫助 AI 模型了解工具的行為和功能。註解透過屬性新增到工具中:

<?php

namespace App\Mcp\Tools;

use Laravel\Mcp\Server\Tools\Annotations\IsIdempotent;
use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
use Laravel\Mcp\Server\Tool;

#[IsIdempotent]
#[IsReadOnly]
class CurrentWeatherTool extends Tool
{
    //
}

可用的註解包括:

| 註解 | 類型 | 描述 | | ------------------ | ------- | ------------------------------------------------------ | | #[IsReadOnly] | boolean | 指示該工具不會修改其環境。 | | #[IsDestructive] | boolean | 指示該工具可能會執行破壞性更新(僅在非唯讀時有意義)。 | | #[IsIdempotent] | boolean | 指示使用相同參數重複呼叫沒有額外效果(當非唯讀時)。 | | #[IsOpenWorld] | boolean | 指示該工具可能會與外部實體互動。 |

條件式工具註冊 (Conditional Tool Registration)

你可以透過在工具類別中實作 shouldRegister 方法在執行時有條件地註冊工具。此方法允許你根據應用程式狀態、設定或請求參數判斷工具是否應該可用:

<?php

namespace App\Mcp\Tools;

use Laravel\Mcp\Request;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 判斷工具是否應該被註冊。
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

當工具的 shouldRegister 方法回傳 false 時,它將不會出現在可用工具列表中,並且無法被 AI 客戶端呼叫。

工具回應 (Tool Responses)

工具必須回傳 Laravel\Mcp\Response 的實例。Response 類別提供了幾種方便的方法來建立不同類型的回應:

對於簡單的文字回應,請使用 text 方法:

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;

/**
 * 處理工具請求。
 */
public function handle(Request $request): Response
{
    // ...

    return Response::text('Weather Summary: Sunny, 72°F');
}

要指示工具執行期間發生錯誤,請使用 error 方法:

return Response::error('Unable to fetch weather data. Please try again.');

多重內容回應 (Multiple Content Responses)

工具可以透過回傳 Response 實例的陣列來回傳多個內容片段:

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;

/**
 * 處理工具請求。
 *
 * @return array<int, \Laravel\Mcp\Response>
 */
public function handle(Request $request): array
{
    // ...

    return [
        Response::text('Weather Summary: Sunny, 72°F'),
        Response::text('**Detailed Forecast**\n- Morning: 65°F\n- Afternoon: 78°F\n- Evening: 70°F')
    ];
}

串流回應 (Streaming Responses)

對於長時間執行的操作或即時資料串流,工具可以從其 handle 方法回傳一個 generator。這使得在最終回應之前可以發送中間更新給客戶端:

<?php

namespace App\Mcp\Tools;

use Generator;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    /**
     * 處理工具請求。
     *
     * @return \Generator<int, \Laravel\Mcp\Response>
     */
    public function handle(Request $request): Generator
    {
        $locations = $request->array('locations');

        foreach ($locations as $index => $location) {
            yield Response::notification('processing/progress', [
                'current' => $index + 1,
                'total' => count($locations),
                'location' => $location,
            ]);

            yield Response::text($this->forecastFor($location));
        }
    }
}

使用 Web 伺服器時,串流回應會自動開啟 SSE (Server-Sent Events) 串流,將每個產生的訊息作為事件發送給客戶端。

提示 (Prompts)

Prompts 使你的伺服器能夠分享可重複使用的提示模板,AI 客戶端可以使用這些模板與語言模型互動。它們提供了一種標準化的方式來結構化常見的查詢和互動。

建立提示 (Creating Prompts)

要建立提示,請執行 make:mcp-prompt Artisan 命令:

php artisan make:mcp-prompt DescribeWeatherPrompt

建立提示後,在伺服器的 $prompts 屬性中註冊它:

<?php

namespace App\Mcp\Servers;

use App\Mcp\Prompts\DescribeWeatherPrompt;
use Laravel\Mcp\Server;

class WeatherServer extends Server
{
    /**
     * 註冊到此 MCP 伺服器的提示。
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
     */
    protected array $prompts = [
        DescribeWeatherPrompt::class,
    ];
}

提示名稱、標題和描述 (Prompt Name Title And Description)

預設情況下,提示的名稱和標題源自類別名稱。例如,DescribeWeatherPrompt 的名稱將為 describe-weather,標題為 Describe Weather Prompt。你可以透過定義提示的 $name$title 屬性來自訂這些值:

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 提示的名稱。
     */
    protected string $name = 'weather-assistant';

    /**
     * 提示的標題。
     */
    protected string $title = 'Weather Assistant Prompt';

    // ...
}

提示描述不會自動生成。你應該始終透過在提示上定義 $description 屬性來提供有意義的描述:

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 提示的描述。
     */
    protected string $description = 'Generates a natural-language explanation of the weather for a given location.';

    //
}

[!NOTE] 描述是提示 metadata 的關鍵部分,因為它幫助 AI 模型了解何時以及如何充分利用該提示。

提示參數 (Prompt Arguments)

提示可以定義參數,允許 AI 客戶端使用特定值自訂提示模板。使用 arguments 方法定義你的提示接受哪些參數:

<?php

namespace App\Mcp\Prompts;

use Laravel\Mcp\Server\Prompt;
use Laravel\Mcp\Server\Prompts\Argument;

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 取得提示的參數。
     *
     * @return array<int, \Laravel\Mcp\Server\Prompts\Argument>
     */
    public function arguments(): array
    {
        return [
            new Argument(
                name: 'tone',
                description: 'The tone to use in the weather description (e.g., formal, casual, humorous).',
                required: true,
            ),
        ];
    }
}

驗證提示參數 (Validating Prompt Arguments)

提示參數會根據其定義自動驗證,但你可能還想強制執行更複雜的驗證規則。

Laravel MCP 與 Laravel 的驗證功能無縫整合。你可以在提示的 handle 方法中驗證傳入的提示參數:

<?php

namespace App\Mcp\Prompts;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Prompt;

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 處理提示請求。
     */
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'tone' => 'required|string|max:50',
        ]);

        $tone = $validated['tone'];

        // Generate the prompt response using the given tone...
    }
}

驗證失敗時,AI 客戶端將根據你提供的錯誤訊息採取行動。因此,提供清晰且可操作的錯誤訊息至關重要:

$validated = $request->validate([
    'tone' => ['required','string','max:50'],
],[
    'tone.*' => 'You must specify a tone for the weather description. Examples include "formal", "casual", or "humorous".',
]);

提示依賴注入 (Prompt Dependency Injection)

Laravel service container 用於解析所有提示。因此,你可以在建構函式中對提示可能需要的任何依賴進行型別提示。宣告的依賴將自動解析並注入到提示實例中:

<?php

namespace App\Mcp\Prompts;

use App\Repositories\WeatherRepository;
use Laravel\Mcp\Server\Prompt;

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 建立一個新的提示實例。
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    //
}

除了建構函式注入外,你還可以在提示的 handle 方法中對依賴進行型別提示。當方法被呼叫時,service container 將自動解析並注入依賴:

<?php

namespace App\Mcp\Prompts;

use App\Repositories\WeatherRepository;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Prompt;

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 處理提示請求。
     */
    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $isAvailable = $weather->isServiceAvailable();

        // ...
    }
}

條件式提示註冊 (Conditional Prompt Registration)

你可以透過在提示類別中實作 shouldRegister 方法在執行時有條件地註冊提示。此方法允許你根據應用程式狀態、設定或請求參數判斷提示是否應該可用:

<?php

namespace App\Mcp\Prompts;

use Laravel\Mcp\Request;
use Laravel\Mcp\Server\Prompt;

class CurrentWeatherPrompt extends Prompt
{
    /**
     * 判斷提示是否應該被註冊。
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

當提示的 shouldRegister 方法回傳 false 時,它將不會出現在可用提示列表中,並且無法被 AI 客戶端呼叫。

提示回應 (Prompt Responses)

提示可以回傳單個 Laravel\Mcp\ResponseLaravel\Mcp\Response 實例的可迭代物件。這些回應封裝了將發送給 AI 客戶端的內容:

<?php

namespace App\Mcp\Prompts;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Prompt;

class DescribeWeatherPrompt extends Prompt
{
    /**
     * 處理提示請求。
     *
     * @return array<int, \Laravel\Mcp\Response>
     */
    public function handle(Request $request): array
    {
        $tone = $request->string('tone');

        $systemMessage = "You are a helpful weather assistant. Please provide a weather description in a {$tone} tone.";

        $userMessage = "What is the current weather like in New York City?";

        return [
            Response::text($systemMessage)->asAssistant(),
            Response::text($userMessage),
        ];
    }
}

你可以使用 asAssistant() 方法來指示回應訊息應被視為來自 AI 助手,而普通訊息則被視為使用者輸入。

資源 (Resources)

Resources 使你的伺服器能夠公開 AI 客戶端可以讀取並在與語言模型互動時用作上下文的資料和內容。它們提供了一種分享靜態或動態資訊(如文件、設定或任何有助於通知 AI 回應的資料)的方式。

建立資源 (Creating Resources)

要建立資源,請執行 make:mcp-resource Artisan 命令:

php artisan make:mcp-resource WeatherGuidelinesResource

建立資源後,在伺服器的 $resources 屬性中註冊它:

<?php

namespace App\Mcp\Servers;

use App\Mcp\Resources\WeatherGuidelinesResource;
use Laravel\Mcp\Server;

class WeatherServer extends Server
{
    /**
     * 註冊到此 MCP 伺服器的資源。
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
     */
    protected array $resources = [
        WeatherGuidelinesResource::class,
    ];
}

資源名稱、標題和描述 (Resource Name Title And Description)

預設情況下,資源的名稱和標題源自類別名稱。例如,WeatherGuidelinesResource 的名稱將為 weather-guidelines,標題為 Weather Guidelines Resource。你可以透過定義資源的 $name$title 屬性來自訂這些值:

class WeatherGuidelinesResource extends Resource
{
    /**
     * 資源的名稱。
     */
    protected string $name = 'weather-api-docs';

    /**
     * 資源的標題。
     */
    protected string $title = 'Weather API Documentation';

    // ...
}

資源描述不會自動生成。你應該始終透過在資源上定義 $description 屬性來提供有意義的描述:

class WeatherGuidelinesResource extends Resource
{
    /**
     * 資源的描述。
     */
    protected string $description = 'Comprehensive guidelines for using the Weather API.';

    //
}

[!NOTE] 描述是資源 metadata 的關鍵部分,因為它幫助 AI 模型了解何時以及如何有效地使用該資源。

資源 URI 和 MIME 類型 (Resource URI and MIME Type)

每個資源都由唯一的 URI 識別,並具有關聯的 MIME 類型,幫助 AI 客戶端了解資源的格式。

預設情況下,資源的 URI 是根據資源的名稱生成的,因此 WeatherGuidelinesResource 的 URI 將為 weather://resources/weather-guidelines。預設 MIME 類型為 text/plain

你可以透過定義資源的 $uri$mimeType 屬性來自訂這些值:

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Server\Resource;

class WeatherGuidelinesResource extends Resource
{
    /**
     * 資源的 URI。
     */
    protected string $uri = 'weather://resources/guidelines';

    /**
     * 資源的 MIME 類型。
     */
    protected string $mimeType = 'application/pdf';
}

URI 和 MIME 類型幫助 AI 客戶端判斷如何適當地處理和解釋資源內容。

資源請求 (Resource Request)

與工具和提示不同,資源無法定義輸入 schemas 或參數。但是,你仍然可以在資源的 handle 方法中與請求物件互動:

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Resource;

class WeatherGuidelinesResource extends Resource
{
    /**
     * 處理資源請求。
     */
    public function handle(Request $request): Response
    {
        // ...
    }
}

資源依賴注入 (Resource Dependency Injection)

Laravel service container 用於解析所有資源。因此,你可以在建構函式中對資源可能需要的任何依賴進行型別提示。宣告的依賴將自動解析並注入到資源實例中:

<?php

namespace App\Mcp\Resources;

use App\Repositories\WeatherRepository;
use Laravel\Mcp\Server\Resource;

class WeatherGuidelinesResource extends Resource
{
    /**
     * 建立一個新的資源實例。
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    // ...
}

除了建構函式注入外,你還可以在資源的 handle 方法中對依賴進行型別提示。當方法被呼叫時,service container 將自動解析並注入依賴:

<?php

namespace App\Mcp\Resources;

use App\Repositories\WeatherRepository;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Resource;

class WeatherGuidelinesResource extends Resource
{
    /**
     * 處理資源請求。
     */
    public function handle(WeatherRepository $weather): Response
    {
        $guidelines = $weather->guidelines();

        return Response::text($guidelines);
    }
}

條件式資源註冊 (Conditional Resource Registration)

你可以透過在資源類別中實作 shouldRegister 方法在執行時有條件地註冊資源。此方法允許你根據應用程式狀態、設定或請求參數判斷資源是否應該可用:

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Request;
use Laravel\Mcp\Server\Resource;

class WeatherGuidelinesResource extends Resource
{
    /**
     * 判斷資源是否應該被註冊。
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

當資源的 shouldRegister 方法回傳 false 時,它將不會出現在可用資源列表中,並且無法被 AI 客戶端存取。

資源回應 (Resource Responses)

資源必須回傳 Laravel\Mcp\Response 的實例。Response 類別提供了幾種方便的方法來建立不同類型的回應:

對於簡單的文字內容,請使用 text 方法:

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;

/**
 * 處理資源請求。
 */
public function handle(Request $request): Response
{
    // ...

    return Response::text($weatherData);
}

Blob 回應 (Resource Blob Responses)

要回傳 blob 內容,請使用 blob 方法,並提供 blob 內容:

return Response::blob(file_get_contents(storage_path('weather/radar.png')));

回傳 blob 內容時,MIME 類型將由資源類別上的 $mimeType 屬性值決定:

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Server\Resource;

class WeatherGuidelinesResource extends Resource
{
    /**
     * 資源的 MIME 類型。
     */
    protected string $mimeType = 'image/png';

    //
}

錯誤回應 (Resource Error Responses)

要指示資源擷取期間發生錯誤,請使用 error() 方法:

return Response::error('Unable to fetch weather data for the specified location.');

Metadata

Laravel MCP 也支援 MCP 規範中定義的 _meta 欄位,這某些 MCP 客戶端或整合需要此欄位。Metadata 可以套用到所有 MCP 原語,包括工具、資源和提示,以及它們的回應。

你可以使用 withMeta 方法將 metadata 附加到個別回應內容:

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;

/**
 * Handle the tool request.
 */
public function handle(Request $request): Response
{
    return Response::text('The weather is sunny.')
        ->withMeta(['source' => 'weather-api', 'cached' => true]);
}

對於套用到整個回應信封的結果級 metadata,使用 Response::make 包裝你的回應,並在回傳的回應工廠實例上呼叫 withMeta

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\ResponseFactory;

/**
 * Handle the tool request.
 */
public function handle(Request $request): ResponseFactory
{
    return Response::make(
        Response::text('The weather is sunny.')
    )->withMeta(['request_id' => '12345']);
}

要將 metadata 附加到工具、資源或提示本身,請在類別上定義 $meta 屬性:

use Laravel\Mcp\Server\Tool;

class CurrentWeatherTool extends Tool
{
    protected string $description = 'Fetches the current weather forecast.';

    protected ?array $meta = [
        'version' => '2.0',
        'author' => 'Weather Team',
    ];

    // ...
}

驗證 (Authentication)

就像路由一樣,你可以使用 middleware 驗證 Web MCP 伺服器。為你的 MCP 伺服器新增驗證將要求使用者在使用伺服器的任何功能之前進行驗證。

有兩種方法可以驗證對你的 MCP 伺服器的存取:透過 Laravel Sanctum 進行簡單的基於 token 的驗證,或透過 Authorization HTTP 標頭傳遞的任何 token。或者,你可以使用 Laravel Passport 透過 OAuth 進行驗證。

OAuth 2.1

保護你的 Web MCP 伺服器最強大的方法是使用 Laravel Passport 進行 OAuth。

透過 OAuth 驗證你的 MCP 伺服器時,在你的 routes/ai.php 檔案中呼叫 Mcp::oauthRoutes 方法以註冊所需的 OAuth2 發現和客戶端註冊路由。然後,將 Passport 的 auth:api middleware 套用到你的 routes/ai.php 檔案中的 Mcp::web 路由:

use App\Mcp\Servers\WeatherExample;
use Laravel\Mcp\Facades\Mcp;

Mcp::oauthRoutes();

Mcp::web('/mcp/weather', WeatherExample::class)
    ->middleware('auth:api');

新的 Passport 安裝 (New Passport Installation)

如果你的應用程式尚未使 ​​ 用 Laravel Passport,請按照 Passport 的安裝和部署指南將 Passport 新增到你的應用程式中。在繼續之前,你應該擁有一個 OAuthenticatable 模型、新的驗證 guard 和 passport keys。

接下來,你應該發布 Laravel MCP 提供的 Passport 授權視圖:

php artisan vendor:publish --tag=mcp-views

然後,使用 Passport::authorizationView 方法指示 Passport 使用此視圖。通常,此方法應在應用程式的 AppServiceProviderboot 方法中呼叫:

use Laravel\Passport\Passport;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Passport::authorizationView(function ($parameters) {
        return view('mcp.authorize', $parameters);
    });
}

此視圖將在驗證期間顯示給最終使用者,以拒絕或批准 AI 代理的驗證嘗試。

Authorization screen example

[!NOTE] 在這種情況下,我們只是使用 OAuth 作為底層可驗證模型的轉換層。我們忽略了 OAuth 的許多方面,例如 scopes。

使用現有的 Passport 安裝 (Using Existing Passport Installation)

如果你的應用程式已經在使用 Laravel Passport,Laravel MCP 應該可以在你現有的 Passport 安裝中無縫運作,但目前不支援自訂 scopes,因為 OAuth 主要用作底層可驗證模型的轉換層。

Laravel MCP 透過上面討論的 Mcp::oauthRoutes 方法,新增、宣傳並使用單個 mcp:use scope。

Passport vs. Sanctum

OAuth2.1 是 Model Context Protocol 規範中記錄的驗證機制,並且是 MCP 客戶端中最廣泛支援的。因此,我們建議在可能的情況下使用 Passport。

如果你的應用程式已經在使用 Sanctum,那麼新增 Passport 可能會很麻煩。在這種情況下,我們建議使用不帶 Passport 的 Sanctum,直到你有明確且必要的需求使用僅支援 OAuth 的 MCP 客戶端。

Sanctum

如果你想使用 Sanctum 保護你的 MCP 伺服器,只需將 Sanctum 的驗證 middleware 新增到你的 routes/ai.php 檔案中的伺服器即可。然後,確保你的 MCP 客戶端提供 Authorization: Bearer <token> 標頭以確保驗證成功:

use App\Mcp\Servers\WeatherExample;
use Laravel\Mcp\Facades\Mcp;

Mcp::web('/mcp/demo', WeatherExample::class)
    ->middleware('auth:sanctum');

自訂 MCP 驗證 (Custom MCP Authentication)

如果你的應用程式發布自己的自訂 API tokens,你可以透過將你希望的任何 middleware 指派給你的 Mcp::web 路由來驗證你的 MCP 伺服器。你的自訂 middleware 可以手動檢查 Authorization 標頭以驗證傳入的 MCP 請求。

授權 (Authorization)

你可以透過 $request->user() 方法存取目前驗證的使用者,允許你在 MCP 工具和資源中執行授權檢查

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;

/**
 * Handle the tool request.
 */
public function handle(Request $request): Response
{
    if (! $request->user()->can('read-weather')) {
        return Response::error('Permission denied.');
    }

    // ...
}

測試伺服器 (Testing Servers)

你可以使用內建的 MCP Inspector 或編寫單元測試來測試你的 MCP 伺服器。

MCP Inspector

MCP Inspector 是一個用於測試和除錯 MCP 伺服器的互動式工具。使用它連線到你的伺服器,驗證身分,並試用工具、資源和提示。

你可以為任何已註冊的伺服器執行 inspector:

# Web 伺服器...
php artisan mcp:inspector mcp/weather

# 名為 "weather" 的本地伺服器...
php artisan mcp:inspector weather

此命令啟動 MCP Inspector 並提供客戶端設定,你可以將其複製到你的 MCP 客戶端以確保一切設定正確。如果你的 Web 伺服器受驗證 middleware 保護,請確保在連線時包含所需的標頭,例如 Authorization bearer token。

單元測試 (Unit Tests)

你可以為你的 MCP 伺服器、工具、資源和提示編寫單元測試。

要開始使用,請建立一個新的測試案例,並在註冊它的伺服器上呼叫所需的原語。例如,要在 WeatherServer 上測試工具:

test('tool', function () {
    $response = WeatherServer::tool(CurrentWeatherTool::class, [
        'location' => 'New York City',
        'units' => 'fahrenheit',
    ]);

    $response
        ->assertOk()
        ->assertSee('The current weather in New York City is 72°F and sunny.');
});
/**
 * 測試工具。
 */
public function test_tool(): void
{
    $response = WeatherServer::tool(CurrentWeatherTool::class, [
        'location' => 'New York City',
        'units' => 'fahrenheit',
    ]);

    $response
        ->assertOk()
        ->assertSee('The current weather in New York City is 72°F and sunny.');
}

同樣地,你可以測試提示和資源:

$response = WeatherServer::prompt(...);
$response = WeatherServer::resource(...);

你也可以透過在呼叫原語之前鏈接 actingAs 方法來充當已驗證的使用者:

$response = WeatherServer::actingAs($user)->tool(...);

收到回應後,你可以使用各種斷言方法來驗證回應的內容和狀態。

你可以使用 assertOk 方法斷言回應成功。這會檢查回應是否沒有任何錯誤:

$response->assertOk();

你可以使用 assertSee 方法斷言回應包含特定文字:

$response->assertSee('The current weather in New York City is 72°F and sunny.');

你可以使用 assertHasErrors 方法斷言回應包含錯誤:

$response->assertHasErrors();

$response->assertHasErrors([
    'Something went wrong.',
]);

你可以使用 assertHasNoErrors 方法斷言回應不包含錯誤:

$response->assertHasNoErrors();

你可以使用 assertName()assertTitle()assertDescription() 方法斷言回應包含特定 metadata:

$response->assertName('current-weather');
$response->assertTitle('Current Weather Tool');
$response->assertDescription('Fetches the current weather forecast for a specified location.');

你可以使用 assertSentNotificationassertNotificationCount 方法斷言通知已發送:

$response->assertSentNotification('processing/progress', [
    'step' => 1,
    'total' => 5,
]);

$response->assertSentNotification('processing/progress', [
    'step' => 2,
    'total' => 5,
]);

$response->assertNotificationCount(5);

最後,如果你希望檢查原始回應內容,可以使用 dddump 方法輸出回應以進行除錯:

$response->dd();
$response->dump();