跳轉至內容

Laravel MCP

簡介

Laravel MCP 提供了一種簡單且優雅的方式,讓 AI 客戶端能夠透過 模型上下文協議 (Model Context Protocol) 與您的 Laravel 應用程式進行互動。它提供了一個富有表現力且流暢的介面,用於定義伺服器、工具、資源和提示詞,從而實現 AI 驅動的應用程式互動。

安裝

要開始使用,請使用 Composer 包管理器將 Laravel MCP 安裝到您的專案中

1composer require laravel/mcp

釋出路由

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

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

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

建立伺服器

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

1php artisan make:mcp-server WeatherServer

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

1<?php
2 
3namespace App\Mcp\Servers;
4 
5use Laravel\Mcp\Server\Attributes\Instructions;
6use Laravel\Mcp\Server\Attributes\Name;
7use Laravel\Mcp\Server\Attributes\Version;
8use Laravel\Mcp\Server;
9 
10#[Name('Weather Server')]
11#[Version('1.0.0')]
12#[Instructions('This server provides weather information and forecasts.')]
13class WeatherServer extends Server
14{
15 /**
16 * The tools registered with this MCP server.
17 *
18 * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
19 */
20 protected array $tools = [
21 // GetCurrentWeatherTool::class,
22 ];
23 
24 /**
25 * The resources registered with this MCP server.
26 *
27 * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
28 */
29 protected array $resources = [
30 // WeatherGuidelinesResource::class,
31 ];
32 
33 /**
34 * The prompts registered with this MCP server.
35 *
36 * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
37 */
38 protected array $prompts = [
39 // DescribeWeatherPrompt::class,
40 ];
41}

伺服器註冊

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

Web 伺服器

Web 伺服器是最常見的伺服器型別,可以透過 HTTP POST 請求進行訪問,非常適合遠端 AI 客戶端或基於 Web 的整合。使用 web 方法註冊 Web 伺服器

1use App\Mcp\Servers\WeatherServer;
2use Laravel\Mcp\Facades\Mcp;
3 
4Mcp::web('/mcp/weather', WeatherServer::class);

與普通路由一樣,您可以應用中介軟體來保護您的 Web 伺服器

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

本地伺服器

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

1use App\Mcp\Servers\WeatherServer;
2use Laravel\Mcp\Facades\Mcp;
3 
4Mcp::local('weather', WeatherServer::class);

註冊完成後,通常不需要手動執行 mcp:start Artisan 命令。相反,應配置您的 MCP 客戶端(AI 智慧體)來啟動伺服器,或者使用 MCP Inspector

工具

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

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Illuminate\Contracts\JsonSchema\JsonSchema;
6use Laravel\Mcp\Request;
7use Laravel\Mcp\Response;
8use Laravel\Mcp\Server\Attributes\Description;
9use Laravel\Mcp\Server\Tool;
10 
11#[Description('Fetches the current weather forecast for a specified location.')]
12class CurrentWeatherTool extends Tool
13{
14 /**
15 * Handle the tool request.
16 */
17 public function handle(Request $request): Response
18 {
19 $location = $request->get('location');
20 
21 // Get weather...
22 
23 return Response::text('The weather is...');
24 }
25 
26 /**
27 * Get the tool's input schema.
28 *
29 * @return array<string, \Illuminate\JsonSchema\Types\Type>
30 */
31 public function schema(JsonSchema $schema): array
32 {
33 return [
34 'location' => $schema->string()
35 ->description('The location to get the weather for.')
36 ->required(),
37 ];
38 }
39}

建立工具

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

1php artisan make:mcp-tool CurrentWeatherTool

建立工具後,將其註冊到伺服器的 $tools 屬性中

1<?php
2 
3namespace App\Mcp\Servers;
4 
5use App\Mcp\Tools\CurrentWeatherTool;
6use Laravel\Mcp\Server;
7 
8class WeatherServer extends Server
9{
10 /**
11 * The tools registered with this MCP server.
12 *
13 * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
14 */
15 protected array $tools = [
16 CurrentWeatherTool::class,
17 ];
18}

工具名稱、標題和描述

預設情況下,工具的名稱和標題派生自類名。例如,CurrentWeatherTool 的名稱將為 current-weather,標題為 Current Weather Tool。您可以使用 NameTitle 屬性自定義這些值

1use Laravel\Mcp\Server\Attributes\Name;
2use Laravel\Mcp\Server\Attributes\Title;
3 
4#[Name('get-optimistic-weather')]
5#[Title('Get Optimistic Weather Forecast')]
6class CurrentWeatherTool extends Tool
7{
8 // ...
9}

工具描述不會自動生成。您應該始終使用 Description 屬性提供有意義的描述

1use Laravel\Mcp\Server\Attributes\Description;
2 
3#[Description('Fetches the current weather forecast for a specified location.')]
4class CurrentWeatherTool extends Tool
5{
6 //
7}

描述是工具元資料的關鍵部分,因為它有助於 AI 模型理解何時以及如何有效地使用該工具。

工具輸入架構

工具可以定義輸入架構,以指定它們接受 AI 客戶端的哪些引數。使用 Laravel 的 Illuminate\Contracts\JsonSchema\JsonSchema 構建器來定義工具的輸入要求

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Illuminate\Contracts\JsonSchema\JsonSchema;
6use Laravel\Mcp\Server\Tool;
7 
8class CurrentWeatherTool extends Tool
9{
10 /**
11 * Get the tool's input schema.
12 *
13 * @return array<string, \Illuminate\JsonSchema\Types\Type>
14 */
15 public function schema(JsonSchema $schema): array
16 {
17 return [
18 'location' => $schema->string()
19 ->description('The location to get the weather for.')
20 ->required(),
21 
22 'units' => $schema->string()
23 ->enum(['celsius', 'fahrenheit'])
24 ->description('The temperature units to use.')
25 ->default('celsius'),
26 ];
27 }
28}

工具輸出架構

工具可以定義 輸出架構 以指定其響應結構。這使得能夠更好地與需要可解析工具結果的 AI 客戶端整合。使用 outputSchema 方法定義工具的輸出結構

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Illuminate\Contracts\JsonSchema\JsonSchema;
6use Laravel\Mcp\Server\Tool;
7 
8class CurrentWeatherTool extends Tool
9{
10 /**
11 * Get the tool's output schema.
12 *
13 * @return array<string, \Illuminate\JsonSchema\Types\Type>
14 */
15 public function outputSchema(JsonSchema $schema): array
16 {
17 return [
18 'temperature' => $schema->number()
19 ->description('Temperature in Celsius')
20 ->required(),
21 
22 'conditions' => $schema->string()
23 ->description('Weather conditions')
24 ->required(),
25 
26 'humidity' => $schema->integer()
27 ->description('Humidity percentage')
28 ->required(),
29 ];
30 }
31}

驗證工具引數

JSON Schema 定義為工具引數提供了基本結構,但您可能還希望強制執行更復雜的驗證規則。

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

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Response;
7use Laravel\Mcp\Server\Tool;
8 
9class CurrentWeatherTool extends Tool
10{
11 /**
12 * Handle the tool request.
13 */
14 public function handle(Request $request): Response
15 {
16 $validated = $request->validate([
17 'location' => 'required|string|max:100',
18 'units' => 'in:celsius,fahrenheit',
19 ]);
20 
21 // Fetch weather data using the validated arguments...
22 }
23}

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

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

工具依賴注入

Laravel 服務容器 用於解析所有工具。因此,您可以在工具的建構函式中對所需的任何依賴項進行型別提示。宣告的依賴項將自動解析並注入到工具例項中

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use App\Repositories\WeatherRepository;
6use Laravel\Mcp\Server\Tool;
7 
8class CurrentWeatherTool extends Tool
9{
10 /**
11 * Create a new tool instance.
12 */
13 public function __construct(
14 protected WeatherRepository $weather,
15 ) {}
16 
17 // ...
18}

除了建構函式注入外,您還可以在工具的 handle() 方法中對依賴項進行型別提示。當呼叫該方法時,服務容器會自動解析並注入這些依賴項

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use App\Repositories\WeatherRepository;
6use Laravel\Mcp\Request;
7use Laravel\Mcp\Response;
8use Laravel\Mcp\Server\Tool;
9 
10class CurrentWeatherTool extends Tool
11{
12 /**
13 * Handle the tool request.
14 */
15 public function handle(Request $request, WeatherRepository $weather): Response
16 {
17 $location = $request->get('location');
18 
19 $forecast = $weather->getForecastFor($location);
20 
21 // ...
22 }
23}

工具註解

您可以使用 註解 來增強工具,向 AI 客戶端提供額外的元資料。這些註解有助於 AI 模型理解工具的行為和功能。註解透過屬性 (attributes) 新增到工具中

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Laravel\Mcp\Server\Tools\Annotations\IsIdempotent;
6use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
7use Laravel\Mcp\Server\Tool;
8 
9#[IsIdempotent]
10#[IsReadOnly]
11class CurrentWeatherTool extends Tool
12{
13 //
14}

可用的註解包括

註解 型別 描述
#[IsReadOnly] boolean 表示該工具不會修改其環境。
#[IsDestructive] boolean 表示該工具可能會執行破壞性更新(僅在非只讀時有意義)。
#[IsIdempotent] boolean 表示使用相同引數的重複呼叫沒有額外影響(在非只讀時)。
#[IsOpenWorld] boolean 表示該工具可能與外部實體互動。

註解值可以使用布林引數顯式設定

1use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
2use Laravel\Mcp\Server\Tools\Annotations\IsDestructive;
3use Laravel\Mcp\Server\Tools\Annotations\IsOpenWorld;
4use Laravel\Mcp\Server\Tools\Annotations\IsIdempotent;
5use Laravel\Mcp\Server\Tool;
6 
7#[IsReadOnly(true)]
8#[IsDestructive(false)]
9#[IsOpenWorld(false)]
10#[IsIdempotent(true)]
11class CurrentWeatherTool extends Tool
12{
13 //
14}

條件性工具註冊

您可以透過在工具類中實現 shouldRegister 方法來在執行時有條件地註冊工具。此方法允許您根據應用程式狀態、配置或請求引數來確定工具是否可用

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Server\Tool;
7 
8class CurrentWeatherTool extends Tool
9{
10 /**
11 * Determine if the tool should be registered.
12 */
13 public function shouldRegister(Request $request): bool
14 {
15 return $request?->user()?->subscribed() ?? false;
16 }
17}

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

工具響應

工具必須返回 Laravel\Mcp\Response 的例項。Response 類提供了多種便捷方法來建立不同型別的響應

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

1use Laravel\Mcp\Request;
2use Laravel\Mcp\Response;
3 
4/**
5 * Handle the tool request.
6 */
7public function handle(Request $request): Response
8{
9 // ...
10 
11 return Response::text('Weather Summary: Sunny, 72°F');
12}

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

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

要返回影像或音訊內容,請使用 imageaudio 方法

1return Response::image(file_get_contents(storage_path('weather/radar.png')), 'image/png');
2 
3return Response::audio(file_get_contents(storage_path('weather/alert.mp3')), 'audio/mp3');

您也可以使用 fromStorage 方法直接從 Laravel 檔案系統磁碟載入影像和音訊內容。MIME 型別將自動從檔案中檢測

1return Response::fromStorage('weather/radar.png');

如果需要,您可以指定特定的磁碟或覆蓋 MIME 型別

1return Response::fromStorage('weather/radar.png', disk: 's3');
2 
3return Response::fromStorage('weather/radar.png', mimeType: 'image/webp');

多內容響應

工具可以透過返回 Response 例項陣列來返回多個內容片段

1use Laravel\Mcp\Request;
2use Laravel\Mcp\Response;
3 
4/**
5 * Handle the tool request.
6 *
7 * @return array<int, \Laravel\Mcp\Response>
8 */
9public function handle(Request $request): array
10{
11 // ...
12 
13 return [
14 Response::text('Weather Summary: Sunny, 72°F'),
15 Response::text('**Detailed Forecast**\n- Morning: 65°F\n- Afternoon: 78°F\n- Evening: 70°F')
16 ];
17}

結構化響應

工具可以使用 structured 方法返回 結構化內容。這為 AI 客戶端提供了可解析的資料,同時保持了與 JSON 編碼文字表示的向後相容性

1return Response::structured([
2 'temperature' => 22.5,
3 'conditions' => 'Partly cloudy',
4 'humidity' => 65,
5]);

如果您需要在結構化內容之外提供自定義文字,請在響應工廠上使用 withStructuredContent 方法

1return Response::make(
2 Response::text('Weather is 22.5°C and sunny')
3)->withStructuredContent([
4 'temperature' => 22.5,
5 'conditions' => 'Sunny',
6]);

流式響應

對於長時間執行的操作或即時資料流,工具可以從其 handle 方法返回一個 生成器 (generator)。這使得在最終響應之前能夠向客戶端傳送中間更新

1<?php
2 
3namespace App\Mcp\Tools;
4 
5use Generator;
6use Laravel\Mcp\Request;
7use Laravel\Mcp\Response;
8use Laravel\Mcp\Server\Tool;
9 
10class CurrentWeatherTool extends Tool
11{
12 /**
13 * Handle the tool request.
14 *
15 * @return \Generator<int, \Laravel\Mcp\Response>
16 */
17 public function handle(Request $request): Generator
18 {
19 $locations = $request->array('locations');
20 
21 foreach ($locations as $index => $location) {
22 yield Response::notification('processing/progress', [
23 'current' => $index + 1,
24 'total' => count($locations),
25 'location' => $location,
26 ]);
27 
28 yield Response::text($this->forecastFor($location));
29 }
30 }
31}

使用基於 Web 的伺服器時,流式響應會自動開啟 SSE (伺服器傳送事件) 流,將每個產生的訊息作為事件傳送給客戶端。

Prompts

提示詞 (Prompts) 使您的伺服器能夠共享可重用的提示詞模板,AI 客戶端可以使用這些模板與語言模型進行互動。它們提供了一種標準化方式來組織常見的查詢和互動。

建立提示詞 (Prompts)

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

1php artisan make:mcp-prompt DescribeWeatherPrompt

建立提示詞後,將其註冊到伺服器的 $prompts 屬性中

1<?php
2 
3namespace App\Mcp\Servers;
4 
5use App\Mcp\Prompts\DescribeWeatherPrompt;
6use Laravel\Mcp\Server;
7 
8class WeatherServer extends Server
9{
10 /**
11 * The prompts registered with this MCP server.
12 *
13 * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
14 */
15 protected array $prompts = [
16 DescribeWeatherPrompt::class,
17 ];
18}

提示詞名稱、標題和描述

預設情況下,提示詞的名稱和標題派生自類名。例如,DescribeWeatherPrompt 的名稱將為 describe-weather,標題為 Describe Weather Prompt。您可以使用 NameTitle 屬性自定義這些值

1use Laravel\Mcp\Server\Attributes\Name;
2use Laravel\Mcp\Server\Attributes\Title;
3 
4#[Name('weather-assistant')]
5#[Title('Weather Assistant Prompt')]
6class DescribeWeatherPrompt extends Prompt
7{
8 // ...
9}

提示詞描述不會自動生成。您應該始終使用 Description 屬性提供有意義的描述

1use Laravel\Mcp\Server\Attributes\Description;
2 
3#[Description('Generates a natural-language explanation of the weather for a given location.')]
4class DescribeWeatherPrompt extends Prompt
5{
6 //
7}

描述是提示詞元資料的關鍵部分,因為它有助於 AI 模型理解何時以及如何最好地使用該提示詞。

提示詞引數

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

1<?php
2 
3namespace App\Mcp\Prompts;
4 
5use Laravel\Mcp\Server\Prompt;
6use Laravel\Mcp\Server\Prompts\Argument;
7 
8class DescribeWeatherPrompt extends Prompt
9{
10 /**
11 * Get the prompt's arguments.
12 *
13 * @return array<int, \Laravel\Mcp\Server\Prompts\Argument>
14 */
15 public function arguments(): array
16 {
17 return [
18 new Argument(
19 name: 'tone',
20 description: 'The tone to use in the weather description (e.g., formal, casual, humorous).',
21 required: true,
22 ),
23 ];
24 }
25}

驗證提示詞引數

提示詞引數會根據定義自動驗證,但您可能還希望強制執行更復雜的驗證規則。

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

1<?php
2 
3namespace App\Mcp\Prompts;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Response;
7use Laravel\Mcp\Server\Prompt;
8 
9class DescribeWeatherPrompt extends Prompt
10{
11 /**
12 * Handle the prompt request.
13 */
14 public function handle(Request $request): Response
15 {
16 $validated = $request->validate([
17 'tone' => 'required|string|max:50',
18 ]);
19 
20 $tone = $validated['tone'];
21 
22 // Generate the prompt response using the given tone...
23 }
24}

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

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

提示詞依賴注入

Laravel 服務容器 用於解析所有提示詞。因此,您可以在提示詞的建構函式中對所需的任何依賴項進行型別提示。宣告的依賴項將自動解析並注入到提示詞例項中

1<?php
2 
3namespace App\Mcp\Prompts;
4 
5use App\Repositories\WeatherRepository;
6use Laravel\Mcp\Server\Prompt;
7 
8class DescribeWeatherPrompt extends Prompt
9{
10 /**
11 * Create a new prompt instance.
12 */
13 public function __construct(
14 protected WeatherRepository $weather,
15 ) {}
16 
17 //
18}

除了建構函式注入外,您還可以在提示詞的 handle 方法中對依賴項進行型別提示。當呼叫該方法時,服務容器會自動解析並注入這些依賴項

1<?php
2 
3namespace App\Mcp\Prompts;
4 
5use App\Repositories\WeatherRepository;
6use Laravel\Mcp\Request;
7use Laravel\Mcp\Response;
8use Laravel\Mcp\Server\Prompt;
9 
10class DescribeWeatherPrompt extends Prompt
11{
12 /**
13 * Handle the prompt request.
14 */
15 public function handle(Request $request, WeatherRepository $weather): Response
16 {
17 $isAvailable = $weather->isServiceAvailable();
18 
19 // ...
20 }
21}

條件性提示詞註冊

您可以透過在提示詞類中實現 shouldRegister 方法來在執行時有條件地註冊提示詞。此方法允許您根據應用程式狀態、配置或請求引數來確定提示詞是否可用

1<?php
2 
3namespace App\Mcp\Prompts;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Server\Prompt;
7 
8class CurrentWeatherPrompt extends Prompt
9{
10 /**
11 * Determine if the prompt should be registered.
12 */
13 public function shouldRegister(Request $request): bool
14 {
15 return $request?->user()?->subscribed() ?? false;
16 }
17}

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

提示詞響應

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

1<?php
2 
3namespace App\Mcp\Prompts;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Response;
7use Laravel\Mcp\Server\Prompt;
8 
9class DescribeWeatherPrompt extends Prompt
10{
11 /**
12 * Handle the prompt request.
13 *
14 * @return array<int, \Laravel\Mcp\Response>
15 */
16 public function handle(Request $request): array
17 {
18 $tone = $request->string('tone');
19 
20 $systemMessage = "You are a helpful weather assistant. Please provide a weather description in a {$tone} tone.";
21 
22 $userMessage = "What is the current weather like in New York City?";
23 
24 return [
25 Response::text($systemMessage)->asAssistant(),
26 Response::text($userMessage),
27 ];
28 }
29}

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

資源

資源 (Resources) 使您的伺服器能夠公開資料和內容,AI 客戶端在與語言模型互動時可以讀取和使用這些內容作為上下文。它們提供了一種共享靜態或動態資訊的方式,例如文件、配置或任何有助於為 AI 響應提供資訊的其他資料。

建立資源

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

1php artisan make:mcp-resource WeatherGuidelinesResource

建立資源後,將其註冊到伺服器的 $resources 屬性中

1<?php
2 
3namespace App\Mcp\Servers;
4 
5use App\Mcp\Resources\WeatherGuidelinesResource;
6use Laravel\Mcp\Server;
7 
8class WeatherServer extends Server
9{
10 /**
11 * The resources registered with this MCP server.
12 *
13 * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
14 */
15 protected array $resources = [
16 WeatherGuidelinesResource::class,
17 ];
18}

資源名稱、標題和描述

預設情況下,資源的名稱和標題派生自類名。例如,WeatherGuidelinesResource 的名稱將為 weather-guidelines,標題為 Weather Guidelines Resource。您可以使用 NameTitle 屬性自定義這些值

1use Laravel\Mcp\Server\Attributes\Name;
2use Laravel\Mcp\Server\Attributes\Title;
3 
4#[Name('weather-api-docs')]
5#[Title('Weather API Documentation')]
6class WeatherGuidelinesResource extends Resource
7{
8 // ...
9}

資源描述不會自動生成。您應該始終使用 Description 屬性提供有意義的描述

1use Laravel\Mcp\Server\Attributes\Description;
2 
3#[Description('Comprehensive guidelines for using the Weather API.')]
4class WeatherGuidelinesResource extends Resource
5{
6 //
7}

描述是資源元資料的關鍵部分,因為它有助於 AI 模型理解何時以及如何有效地使用該資源。

資源模板

資源模板 使您的伺服器能夠公開與帶有變數的 URI 模式匹配的動態資源。您可以建立單個資源來處理基於模板模式的多個 URI,而不是為每個資源定義靜態 URI。

建立資源模板

要建立資源模板,請在資源類上實現 HasUriTemplate 介面,並定義一個返回 UriTemplate 例項的 uriTemplate 方法

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Response;
7use Laravel\Mcp\Server\Attributes\Description;
8use Laravel\Mcp\Server\Attributes\MimeType;
9use Laravel\Mcp\Server\Contracts\HasUriTemplate;
10use Laravel\Mcp\Server\Resource;
11use Laravel\Mcp\Support\UriTemplate;
12 
13#[Description('Access user files by ID')]
14#[MimeType('text/plain')]
15class UserFileResource extends Resource implements HasUriTemplate
16{
17 /**
18 * Get the URI template for this resource.
19 */
20 public function uriTemplate(): UriTemplate
21 {
22 return new UriTemplate('file://users/{userId}/files/{fileId}');
23 }
24 
25 /**
26 * Handle the resource request.
27 */
28 public function handle(Request $request): Response
29 {
30 $userId = $request->get('userId');
31 $fileId = $request->get('fileId');
32 
33 // Fetch and return the file content...
34 
35 return Response::text($content);
36 }
37}

當資源實現了 HasUriTemplate 介面時,它將被註冊為資源模板而不是靜態資源。AI 客戶端隨後可以使用與模板模式匹配的 URI 請求資源,來自 URI 的變數將自動提取並可在資源的 handle 方法中使用。

URI 模板語法

URI 模板使用花括號括起來的佔位符來定義 URI 中的變數段

1new UriTemplate('file://users/{userId}');
2new UriTemplate('file://users/{userId}/files/{fileId}');
3new UriTemplate('https://api.example.com/{version}/{resource}/{id}');

訪問模板變數

當 URI 與您的資源模板匹配時,提取的變數將自動合併到請求中,可以使用 get 方法進行訪問

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Response;
7use Laravel\Mcp\Server\Contracts\HasUriTemplate;
8use Laravel\Mcp\Server\Resource;
9use Laravel\Mcp\Support\UriTemplate;
10 
11class UserProfileResource extends Resource implements HasUriTemplate
12{
13 public function uriTemplate(): UriTemplate
14 {
15 return new UriTemplate('file://users/{userId}/profile');
16 }
17 
18 public function handle(Request $request): Response
19 {
20 // Access the extracted variable
21 $userId = $request->get('userId');
22 
23 // Access the full URI if needed
24 $uri = $request->uri();
25 
26 // Fetch user profile...
27 
28 return Response::text("Profile for user {$userId}");
29 }
30}

Request 物件提供了提取的變數和請求的原始 URI,為您處理資源請求提供了完整的上下文。

資源 URI 和 MIME 型別

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

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

您可以使用 UriMimeType 屬性自定義這些值

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Server\Attributes\MimeType;
6use Laravel\Mcp\Server\Attributes\Uri;
7use Laravel\Mcp\Server\Resource;
8 
9#[Uri('weather://resources/guidelines')]
10#[MimeType('application/pdf')]
11class WeatherGuidelinesResource extends Resource
12{
13}

URI 和 MIME 型別有助於 AI 客戶端確定如何適當處理和解釋資源內容。

資源請求

與工具和提示詞不同,資源不能定義輸入架構或引數。但是,您仍然可以在資源的 handle 方法中與請求物件進行互動

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Response;
7use Laravel\Mcp\Server\Resource;
8 
9class WeatherGuidelinesResource extends Resource
10{
11 /**
12 * Handle the resource request.
13 */
14 public function handle(Request $request): Response
15 {
16 // ...
17 }
18}

資源依賴注入

Laravel 服務容器 用於解析所有資源。因此,您可以在資源的建構函式中對所需的任何依賴項進行型別提示。宣告的依賴項將自動解析並注入到資源例項中

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use App\Repositories\WeatherRepository;
6use Laravel\Mcp\Server\Resource;
7 
8class WeatherGuidelinesResource extends Resource
9{
10 /**
11 * Create a new resource instance.
12 */
13 public function __construct(
14 protected WeatherRepository $weather,
15 ) {}
16 
17 // ...
18}

除了建構函式注入外,您還可以在資源的 handle 方法中對依賴項進行型別提示。當呼叫該方法時,服務容器會自動解析並注入這些依賴項

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use App\Repositories\WeatherRepository;
6use Laravel\Mcp\Request;
7use Laravel\Mcp\Response;
8use Laravel\Mcp\Server\Resource;
9 
10class WeatherGuidelinesResource extends Resource
11{
12 /**
13 * Handle the resource request.
14 */
15 public function handle(WeatherRepository $weather): Response
16 {
17 $guidelines = $weather->guidelines();
18 
19 return Response::text($guidelines);
20 }
21}

資源註解

您可以使用 註解 來增強資源,向 AI 客戶端提供額外的元資料。註解透過屬性新增到資源中

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Enums\Role;
6use Laravel\Mcp\Server\Annotations\Audience;
7use Laravel\Mcp\Server\Annotations\LastModified;
8use Laravel\Mcp\Server\Annotations\Priority;
9use Laravel\Mcp\Server\Resource;
10 
11#[Audience(Role::User)]
12#[LastModified('2025-01-12T15:00:58Z')]
13#[Priority(0.9)]
14class UserDashboardResource extends Resource
15{
16 //
17}

可用的註解包括

註解 型別 描述
#[Audience] 角色或陣列 指定預期的受眾(Role::UserRole::Assistant 或兩者兼有)。
#[Priority] 浮點數 0.0 到 1.0 之間的數值分數,表示資源的重要性。
#[LastModified] string 一個 ISO 8601 時間戳,顯示資源上次更新的時間。

條件性資源註冊

您可以透過在資源類中實現 shouldRegister 方法來在執行時有條件地註冊資源。此方法允許您根據應用程式狀態、配置或請求引數來確定資源是否可用

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Request;
6use Laravel\Mcp\Server\Resource;
7 
8class WeatherGuidelinesResource extends Resource
9{
10 /**
11 * Determine if the resource should be registered.
12 */
13 public function shouldRegister(Request $request): bool
14 {
15 return $request?->user()?->subscribed() ?? false;
16 }
17}

當資源的 shouldRegister 方法返回 false 時,它將不會出現在可用資源列表中,也無法被 AI 客戶端訪問。

資源響應

資源必須返回 Laravel\Mcp\Response 的例項。Response 類提供了多種便捷方法來建立不同型別的響應

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

1use Laravel\Mcp\Request;
2use Laravel\Mcp\Response;
3 
4/**
5 * Handle the resource request.
6 */
7public function handle(Request $request): Response
8{
9 // ...
10 
11 return Response::text($weatherData);
12}

Blob 響應

要返回二進位制大物件 (blob) 內容,請使用 blob 方法,並提供 blob 內容

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

返回 blob 內容時,MIME 型別將由您資源配置的 MIME 型別決定

1<?php
2 
3namespace App\Mcp\Resources;
4 
5use Laravel\Mcp\Server\Attributes\MimeType;
6use Laravel\Mcp\Server\Resource;
7 
8#[MimeType('image/png')]
9class WeatherGuidelinesResource extends Resource
10{
11 //
12}

錯誤響應

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

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

元資料 (Metadata)

Laravel MCP 還支援 MCP 規範 中定義的 _meta 欄位,這是某些 MCP 客戶端或整合所必需的。元資料可以應用於所有 MCP 原語,包括工具、資源和提示詞,以及它們的響應。

您可以使用 withMeta 方法將元資料附加到單獨的響應內容

1use Laravel\Mcp\Request;
2use Laravel\Mcp\Response;
3 
4/**
5 * Handle the tool request.
6 */
7public function handle(Request $request): Response
8{
9 return Response::text('The weather is sunny.')
10 ->withMeta(['source' => 'weather-api', 'cached' => true]);
11}

對於適用於整個響應信封的結果級元資料,請使用 Response::make 包裝您的響應,並在返回的響應工廠例項上呼叫 withMeta

1use Laravel\Mcp\Request;
2use Laravel\Mcp\Response;
3use Laravel\Mcp\ResponseFactory;
4 
5/**
6 * Handle the tool request.
7 */
8public function handle(Request $request): ResponseFactory
9{
10 return Response::make(
11 Response::text('The weather is sunny.')
12 )->withMeta(['request_id' => '12345']);
13}

要將元資料附加到工具、資源或提示詞本身,請在類上定義一個 $meta 屬性

1use Laravel\Mcp\Server\Attributes\Description;
2use Laravel\Mcp\Server\Tool;
3 
4#[Description('Fetches the current weather forecast.')]
5class CurrentWeatherTool extends Tool
6{
7 protected ?array $meta = [
8 'version' => '2.0',
9 'author' => 'Weather Team',
10 ];
11 
12 // ...
13}

認證

就像路由一樣,您可以使用中介軟體驗證 Web MCP 伺服器。向您的 MCP 伺服器新增身份驗證將要求使用者在執行伺服器的任何功能之前進行身份驗證。

有兩種方法可以驗證對 MCP 伺服器的訪問:透過 Laravel Sanctum 進行簡單的基於令牌的身份驗證,或者任何透過 Authorization HTTP 頭傳遞的令牌。或者,您可以使用 Laravel Passport 透過 OAuth 進行身份驗證。

OAuth 2.1

保護基於 Web 的 MCP 伺服器的最穩健方法是使用 Laravel Passport 進行 OAuth 身份驗證。

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

1use App\Mcp\Servers\WeatherExample;
2use Laravel\Mcp\Facades\Mcp;
3 
4Mcp::oauthRoutes();
5 
6Mcp::web('/mcp/weather', WeatherExample::class)
7 ->middleware('auth:api');

全新安裝 Passport

如果您的應用程式尚未使用 Laravel Passport,請遵循 Passport 的 安裝和部署指南 將其新增到您的應用程式中。在繼續之前,您應該擁有一個 OAuthenticatable 模型、新的身份驗證守衛 (guard) 和 Passport 金鑰。

接下來,您應該釋出 Laravel MCP 提供的 Passport 授權檢視

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

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

1use Laravel\Passport\Passport;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(): void
7{
8 Passport::authorizationView(function ($parameters) {
9 return view('mcp.authorize', $parameters);
10 });
11}

此檢視將在身份驗證期間顯示給終端使用者,以拒絕或批准 AI 智慧體的身份驗證嘗試。

Authorization screen example

在這種情況下,我們只是將 OAuth 用作到底層可驗證模型的轉換層。我們忽略了 OAuth 的許多方面,例如作用域 (scopes)。

使用現有的 Passport 安裝

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

Laravel MCP 透過上述討論的 Mcp::oauthRoutes 方法,新增、宣告並使用單個 mcp:use 作用域。

Passport 與 Sanctum

OAuth2.1 是模型上下文協議規範中記錄的身份驗證機制,也是 MCP 客戶端中支援最廣泛的機制。因此,我們建議儘可能使用 Passport。

如果您的應用程式已經在使用 Sanctum,那麼新增 Passport 可能會很繁瑣。在這種情況下,我們建議在您有明確、必要的需求去使用僅支援 OAuth 的 MCP 客戶端之前,先使用 Sanctum 而不使用 Passport。

Sanctum

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

1use App\Mcp\Servers\WeatherExample;
2use Laravel\Mcp\Facades\Mcp;
3 
4Mcp::web('/mcp/demo', WeatherExample::class)
5 ->middleware('auth:sanctum');

自定義 MCP 身份驗證

如果您的應用程式發行了自己的自定義 API 令牌,您可以透過為 Mcp::web 路由分配您想要的任何中介軟體來驗證您的 MCP 伺服器。您的自定義中介軟體可以手動檢查 Authorization 頭,以驗證傳入的 MCP 請求。

授權

您可以透過 $request->user() 方法訪問當前經過身份驗證的使用者,從而允許您在 MCP 工具和資源中執行 授權檢查

1use Laravel\Mcp\Request;
2use Laravel\Mcp\Response;
3 
4/**
5 * Handle the tool request.
6 */
7public function handle(Request $request): Response
8{
9 if (! $request->user()->can('read-weather')) {
10 return Response::error('Permission denied.');
11 }
12 
13 // ...
14}

測試伺服器

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

MCP Inspector

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

您可以為任何已註冊的伺服器執行 Inspector

1# Web server...
2php artisan mcp:inspector mcp/weather
3 
4# Local server named "weather"...
5php artisan mcp:inspector weather

此命令會啟動 MCP Inspector 並提供您可以複製到 MCP 客戶端的客戶端設定,以確保一切配置正確。如果您的 Web 伺服器受身份驗證中介軟體保護,請確保在連線時包含必要的頭,例如 Authorization 持有者令牌。

單元測試

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

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

1test('tool', function () {
2 $response = WeatherServer::tool(CurrentWeatherTool::class, [
3 'location' => 'New York City',
4 'units' => 'fahrenheit',
5 ]);
6 
7 $response
8 ->assertOk()
9 ->assertSee('The current weather in New York City is 72°F and sunny.');
10});
1/**
2 * Test a tool.
3 */
4public function test_tool(): void
5{
6 $response = WeatherServer::tool(CurrentWeatherTool::class, [
7 'location' => 'New York City',
8 'units' => 'fahrenheit',
9 ]);
10 
11 $response
12 ->assertOk()
13 ->assertSee('The current weather in New York City is 72°F and sunny.');
14}

同樣,您可以測試提示詞和資源

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

您還可以透過在呼叫基元之前連結 actingAs 方法,以經過身份驗證的使用者身份進行操作

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

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

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

1$response->assertOk();

您可以使用 assertSee 方法斷言響應包含特定文字

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

您可以使用 assertHasErrors 方法斷言響應包含錯誤

1$response->assertHasErrors();
2 
3$response->assertHasErrors([
4 'Something went wrong.',
5]);

您可以使用 assertHasNoErrors 方法斷言響應不包含錯誤

1$response->assertHasNoErrors();

您可以使用 assertName()assertTitle()assertDescription() 方法斷言響應包含特定元資料

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

您可以使用 assertSentNotificationassertNotificationCount 方法斷言已傳送通知

1$response->assertSentNotification('processing/progress', [
2 'step' => 1,
3 'total' => 5,
4]);
5 
6$response->assertSentNotification('processing/progress', [
7 'step' => 2,
8 'total' => 5,
9]);
10 
11$response->assertNotificationCount(5);

最後,如果您想檢查原始響應內容,可以使用 dddump 方法輸出響應以進行除錯

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