Laravel MCP
簡介
Laravel MCP 提供了一個簡單優雅的方式,讓 AI 客戶端可以透過 Model Context Protocol 與您的 Laravel 應用程式互動。它提供了一個表達性強、流暢的介面,用於定義伺服器、工具、資源和提示,以實現由 AI 驅動的應用程式互動。
安裝
首先,使用 Composer 套件管理工具將 Laravel MCP 安裝到您的專案中:
composer require laravel/mcp
發佈路由
安裝 Laravel MCP 後,執行 vendor:publish
Artisan 命令來發佈 routes/ai.php
檔案,您將在此檔案中定義您的 MCP 伺服器:
php artisan vendor:publish --tag=ai-routes
此命令會在您應用程式的 routes
目錄中建立 routes/ai.php
檔案,您將使用此檔案來註冊您的 MCP 伺服器。
建立伺服器
您可以使用 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
{
/**
* The tools registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
*/
protected array $tools = [
// ExampleTool::class,
];
/**
* The resources registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
*/
protected array $resources = [
// ExampleResource::class,
];
/**
* The prompts registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
*/
protected array $prompts = [
// ExamplePrompt::class,
];
}
伺服器註冊
建立伺服器後,您必須在 routes/ai.php
檔案中註冊它,使其可存取。Laravel MCP 提供了兩種註冊伺服器的方法:web
用於 HTTP 可存取的伺服器,local
用於命令列伺服器。
Web 伺服器
Web 伺服器是最常見的伺服器類型,可透過 HTTP POST 請求存取,非常適合遠端 AI 客戶端或基於 Web 的整合。使用 web
方法註冊 Web 伺服器:
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::web('/mcp/weather', WeatherServer::class);
就像一般路由一樣,您可以套用中介層來保護您的 Web 伺服器:
Mcp::web('/mcp/weather', WeatherServer::class)
->middleware(['throttle:mcp']);
本地伺服器
本地伺服器作為 Artisan 命令執行,非常適合開發、測試或本地 AI 助理整合。使用 local
方法註冊本地伺服器:
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::local('weather', WeatherServer::class);
一旦註冊,您通常不需要手動執行 mcp:start
。相反,請設定您的 MCP 客戶端 (AI agent) 來啟動伺服器。mcp:start
命令旨在由客戶端呼叫,客戶端將根據需要處理伺服器的啟動和停止:
php artisan mcp:start weather
工具
工具讓您的伺服器能夠向 AI 用戶端公開可呼叫的功能。它們允許語言模型執行動作、執行程式碼或與外部系統互動。
建立工具
若要建立工具,請執行 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
{
/**
* The tools registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
*/
protected array $tools = [
CurrentWeatherTool::class,
];
}
工具名稱、標題與說明
依預設,工具的名稱和標題是從類別名稱衍生而來。例如,CurrentWeatherTool
將具有 current-weather
的名稱和 Current Weather Tool
的標題。您可以透過定義工具的 $name
和 $title
屬性來客製化這些值:
class CurrentWeatherTool extends Tool
{
/**
* The tool's name.
*/
protected string $name = 'get-optimistic-weather';
/**
* The tool's title.
*/
protected string $title = 'Get Optimistic Weather Forecast';
// ...
}
工具說明不會自動生成。您應該始終透過在工具上定義 $description
屬性來提供有意義的說明:
class CurrentWeatherTool extends Tool
{
/**
* The tool's description.
*/
protected string $description = 'Fetches the current weather forecast for a specified location.';
//
}
📌 備註
說明是工具中繼資料的關鍵部分,因為它有助於 AI 模型理解何時以及如何有效地使用此工具。
工具輸入結構描述
工具可以定義輸入結構描述,以指定它們從 AI 用戶端接受哪些引數。請使用 Laravel 的 Illuminate\JsonSchema\JsonSchema
產生器來定義工具的輸入要求:
<?php
namespace App\Mcp\Tools;
use Illuminate\JsonSchema\JsonSchema;
use Laravel\Mcp\Server\Tool;
class CurrentWeatherTool extends Tool
{
/**
* Get the tool's input 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->enum(['celsius', 'fahrenheit'])
->description('The temperature units to use.')
->default('celsius'),
];
}
}
驗證工具引數
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
{
/**
* Handle the tool request.
*/
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.',
]);
工具依賴注入
Laravel 服務容器用於解析所有工具。因此,您可以在工具的建構子中指定工具可能需要的任何依賴項。宣告的依賴項將自動解析並注入到工具實例中:
<?php
namespace App\Mcp\Tools;
use App\Repositories\WeatherRepository;
use Laravel\Mcp\Server\Tool;
class CurrentWeatherTool extends Tool
{
/**
* Create a new tool instance.
*/
public function __construct(
protected WeatherRepository $weather,
) {}
// ...
}
除了建構子注入外,您還可以在工具的 handle()
方法中指定依賴項。當該方法被呼叫時,服務容器將自動解析並注入依賴項:
<?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
{
/**
* Handle the tool request.
*/
public function handle(Request $request, WeatherRepository $weather): Response
{
$location = $request->get('location');
$forecast = $weather->getForecastFor($location);
// ...
}
}
工具註解
您可以透過 annotations 來增強工具,以向 AI 用戶端提供額外中繼資料。這些註解有助於 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
{
//
}
可用的註解包括:
Annotation | Type | Description |
---|---|---|
#[IsReadOnly] | boolean | 表示工具不修改其環境。 |
#[IsDestructive] | boolean | 表示工具可能會執行破壞性更新(僅在非唯讀時才有意義)。 |
#[IsIdempotent] | boolean | 表示以相同引數重複呼叫不會產生額外效果(在非唯讀時)。 |
#[IsOpenWorld] | boolean | 表示工具可能與外部實體互動。 |
條件式工具註冊
您可以透過在工具類別中實作 shouldRegister
方法,在執行時期條件式地註冊工具。此方法允許您根據應用程式狀態、設定或請求參數來決定工具是否應該可用:
<?php
namespace App\Mcp\Tools;
use Laravel\Mcp\Request;
use Laravel\Mcp\Server\Tool;
class CurrentWeatherTool extends Tool
{
/**
* Determine if the tool should be registered.
*/
public function shouldRegister(Request $request): bool
{
return $request?->user()?->subscribed() ?? false;
}
}
當工具的 shouldRegister
方法回傳 false
時,它將不會出現在可用工具列表中,也無法由 AI 用戶端呼叫。
工具回應
工具必須回傳 Laravel\Mcp\Response
的實例。Response 類別提供了幾種方便的方法來建立不同類型的回應:
對於簡單的文字回應,請使用 text
方法:
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
/**
* Handle the tool request.
*/
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.');
多內容回應
工具可以透過回傳 Response
實例的陣列來回傳多個內容片段:
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
/**
* Handle the tool request.
*
* @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')
];
}
串流回應
對於長時間執行的操作或即時資料串流,工具可以從其 handle
方法中回傳一個 產生器。這使得在最終回應之前,可以向客戶端發送中繼更新:
<?php
namespace App\Mcp\Tools;
use Generator;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;
class CurrentWeatherTool extends Tool
{
/**
* Handle the tool request.
*
* @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 讓你的伺服器能夠分享可重複使用的提示模板,供 AI 客戶端用於與語言模型互動。它們提供了一種標準化的方式來建構常見的查詢和互動。
建立提示
要建立一個 Prompt,請執行 make:mcp-prompt
Artisan 指令:
php artisan make:mcp-prompt DescribeWeatherPrompt
建立 Prompt 後,請將其註冊到你伺服器的 $prompts
屬性中:
<?php
namespace App\Mcp\Servers;
use App\Mcp\Prompts\DescribeWeatherPrompt;
use Laravel\Mcp\Server;
class WeatherServer extends Server
{
/**
* The prompts registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
*/
protected array $prompts = [
DescribeWeatherPrompt::class,
];
}
提示名稱、標題與描述
預設情況下,Prompt 的名稱和標題是從類別名稱派生而來。例如,DescribeWeatherPrompt
的名稱將是 describe-weather
,標題則是 Describe Weather Prompt
。你可以透過在 Prompt 上定義 $name
和 $title
屬性來客製化這些值:
class DescribeWeatherPrompt extends Prompt
{
/**
* The prompt's name.
*/
protected string $name = 'weather-assistant';
/**
* The prompt's title.
*/
protected string $title = 'Weather Assistant Prompt';
// ...
}
Prompt 的描述不會自動產生。你應該始終透過在 Prompt 上定義 $description
屬性來提供有意義的描述:
class DescribeWeatherPrompt extends Prompt
{
/**
* The prompt's description.
*/
protected string $description = 'Generates a natural-language explanation of the weather for a given location.';
//
}
📌 備註
描述是 Prompt 元資料的關鍵部分,因為它有助於 AI 模型理解何時以及如何有效地使用此 Prompt。
提示引數
Prompts 可以定義引數,允許 AI 客戶端使用特定值來客製化提示模板。使用 arguments
方法來定義你的 Prompt 接受哪些引數:
<?php
namespace App\Mcp\Prompts;
use Laravel\Mcp\Server\Prompt;
use Laravel\Mcp\Server\Prompts\Argument;
class DescribeWeatherPrompt extends Prompt
{
/**
* Get the prompt's arguments.
*
* @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,
),
];
}
}
驗證提示引數
Prompt 引數會根據其定義自動驗證,但你也可能想強制執行更複雜的驗證規則。
Laravel MCP 與 Laravel 的驗證功能無縫整合。你可以在 Prompt 的 handle
方法中驗證傳入的 Prompt 引數:
<?php
namespace App\Mcp\Prompts;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Prompt;
class DescribeWeatherPrompt extends Prompt
{
/**
* Handle the prompt request.
*/
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".',
]);
提示依賴注入
Laravel 的 service container 用於解析所有 Prompts。因此,你可以在 Prompt 的建構函式中類型提示任何它可能需要的依賴。宣告的依賴將會自動解析並注入到 Prompt 實例中:
<?php
namespace App\Mcp\Prompts;
use App\Repositories\WeatherRepository;
use Laravel\Mcp\Server\Prompt;
class DescribeWeatherPrompt extends Prompt
{
/**
* Create a new prompt instance.
*/
public function __construct(
protected WeatherRepository $weather,
) {}
//
}
除了建構函式注入之外,你還可以在 Prompt 的 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
{
/**
* Handle the prompt request.
*/
public function handle(Request $request, WeatherRepository $weather): Response
{
$isAvailable = $weather->isServiceAvailable();
// ...
}
}
條件式提示註冊
你可以透過在 Prompt 類別中實作 shouldRegister
方法,在執行時條件式地註冊 Prompts。此方法允許你根據應用程式狀態、設定或請求參數來決定 Prompt 是否可用:
<?php
namespace App\Mcp\Prompts;
use Laravel\Mcp\Request;
use Laravel\Mcp\Server\Prompt;
class CurrentWeatherPrompt extends Prompt
{
/**
* Determine if the prompt should be registered.
*/
public function shouldRegister(Request $request): bool
{
return $request?->user()?->subscribed() ?? false;
}
}
當 Prompt 的 shouldRegister
方法回傳 false
時,它將不會出現在可用 Prompts 的列表中,也無法被 AI 客戶端呼叫。
提示回應
Prompts 可以回傳單一的 Laravel\Mcp\Response
實例,或是一個 Laravel\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
{
/**
* Handle the prompt request.
*
* @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 讓你的伺服器能夠公開資料和內容,供 AI 客戶端在與語言模型互動時讀取和用作上下文。它們提供了一種方式來分享靜態或動態資訊,例如文件、設定或任何有助於 AI 回應的資料。
建立資源
若要建立一個資源,請執行 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
{
/**
* The resources registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
*/
protected array $resources = [
WeatherGuidelinesResource::class,
];
}
資源名稱、標題和說明
預設情況下,資源的名稱和標題是從類別名稱派生而來。例如,WeatherGuidelinesResource
的名稱將是 weather-guidelines
,標題將是 Weather Guidelines Resource
。您可以透過在資源上定義 $name
和 $title
屬性來客製化這些值:
class WeatherGuidelinesResource extends Resource
{
/**
* The resource's name.
*/
protected string $name = 'weather-api-docs';
/**
* The resource's title.
*/
protected string $title = 'Weather API Documentation';
// ...
}
資源說明不會自動生成。您應始終透過在資源上定義 $description
屬性來提供有意義的說明:
class WeatherGuidelinesResource extends Resource
{
/**
* The resource's description.
*/
protected string $description = 'Comprehensive guidelines for using the Weather API.';
//
}
📌 備註
說明是資源中繼資料的關鍵部分,它有助於 AI 模型了解何時以及如何有效使用資源。
資源 URI 與 MIME 類型
每個資源都由一個唯一的 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
{
/**
* The resource's URI.
*/
protected string $uri = 'weather://resources/guidelines';
/**
* The resource's MIME type.
*/
protected string $mimeType = 'application/pdf';
}
URI 和 MIME 類型可幫助 AI 用戶端確定如何適當地處理和解釋資源內容。
資源請求
與工具和提示不同,資源無法定義輸入結構描述或引數。但是,您仍然可以在資源的 handle
方法中與請求物件互動:
<?php
namespace App\Mcp\Resources;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Resource;
class WeatherGuidelinesResource extends Resource
{
/**
* Handle the resource request.
*/
public function handle(Request $request): Response
{
// ...
}
}
資源依賴注入
Laravel 服務容器用於解析所有資源。因此,您可以在資源的建構子中型別提示資源可能需要的任何依賴。宣告的依賴將自動解析並注入到資源實例中:
<?php
namespace App\Mcp\Resources;
use App\Repositories\WeatherRepository;
use Laravel\Mcp\Server\Resource;
class WeatherGuidelinesResource extends Resource
{
/**
* Create a new resource instance.
*/
public function __construct(
protected WeatherRepository $weather,
) {}
// ...
}
除了建構子注入之外,您還可以在資源的 handle
方法中型別提示依賴。當方法被呼叫時,服務容器將自動解析並注入依賴:
<?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
{
/**
* Handle the resource request.
*/
public function handle(WeatherRepository $weather): Response
{
$guidelines = $weather->guidelines();
return Response::text($guidelines);
}
}
條件式資源註冊
您可以透過在資源類別中實作 shouldRegister
方法來在執行時條件式註冊資源。此方法允許您根據應用程式狀態、設定或請求參數來判斷資源是否應該可用:
<?php
namespace App\Mcp\Resources;
use Laravel\Mcp\Request;
use Laravel\Mcp\Server\Resource;
class WeatherGuidelinesResource extends Resource
{
/**
* Determine if the resource should be registered.
*/
public function shouldRegister(Request $request): bool
{
return $request?->user()?->subscribed() ?? false;
}
}
當資源的 shouldRegister
方法回傳 false
時,它將不會出現在可用資源清單中,AI 用戶端也無法存取它。
資源回應
資源必須回傳 Laravel\Mcp\Response
實例。Response 類別提供了幾種方便的方法來建立不同類型的回應:
對於簡單的文字內容,請使用 text
方法:
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
/**
* Handle the resource request.
*/
public function handle(Request $request): Response
{
// ...
return Response::text($weatherData);
}
Blob 回應
若要回傳 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
{
/**
* The resource's MIME type.
*/
protected string $mimeType = 'image/png';
//
}
錯誤回應
若要指示資源檢索期間發生錯誤,請使用 error()
方法:
return Response::error('Unable to fetch weather data for the specified location.');
認證
您可以透過中介層來認證 web MCP 伺服器,就像您對路由所做的那樣。這將要求使用者在使用伺服器的任何功能之前進行認證。
認證您的 MCP 伺服器有兩種方式:簡單的基於權杖的認證,透過 Laravel Sanctum,或任何透過 Authorization
HTTP 標頭傳遞的任意 API 權杖。或者,您可以透過 OAuth 使用 Laravel Passport 進行認證。
OAuth 2.1
保護您的 Web 型 MCP 伺服器最穩健的方式是透過 OAuth 與 Laravel Passport。
透過 OAuth 認證您的 MCP 伺服器時,您將在 routes/ai.php
檔案中呼叫 Mcp::oauthRoutes
方法來註冊所需的 OAuth2 探索與客戶端註冊路由。然後,在您的 routes/ai.php
檔案中,將 Passport 的 auth:api
中介層應用到您的 Mcp::web
路由上:
use App\Mcp\Servers\WeatherExample;
use Laravel\Mcp\Facades\Mcp;
Mcp::oauthRoutes();
Mcp::web('/mcp/weather', WeatherExample::class)
->middleware('auth:api');
新 Passport 安裝
如果您的應用程式尚未正在使用 Laravel Passport,請先依照 Passport 的安裝與部署步驟進行。在繼續之前,您應該具備 OAuthenticatable
模型、新的認證守衛,以及 Passport 金鑰。
接著,您應該發佈 Laravel MCP 提供的 Passport 授權視圖:
php artisan vendor:publish --tag=mcp-views
然後,指示 Passport 使用 Passport::authorizationView
方法來使用此視圖。通常,此方法應在應用程式 AppServiceProvider
的 boot
方法中呼叫:
use Laravel\Passport\Passport;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::authorizationView(function ($parameters) {
return view('mcp.authorize', $parameters);
});
}
此視圖將在認證期間顯示給終端使用者,以拒絕或批准 AI 代理的認證嘗試。
📌 備註
在此情境中,我們僅將 OAuth 用作基礎可認證模型 (authenticatable model) 的轉換層。我們忽略了 OAuth 的許多方面,例如 scopes。
使用現有的 Passport 安裝
如果您的應用程式已經在使用 Laravel Passport,Laravel MCP 應該能無縫地在您現有的 Passport 安裝中運作,但目前不支援自訂 scopes,因為 OAuth 主要用作基礎可認證模型 (authenticatable model) 的轉換層。
Laravel MCP 透過上方討論的 Mcp::oauthRoutes()
方法,新增、廣告並使用單一 mcp:use
scope。
Passport 與 Sanctum 的比較
OAuth2.1 是 Model Context Protocol 規範中記載的認證機制,也是 MCP 客戶端中最廣泛支援的。基於此原因,我們建議盡可能使用 Passport。
如果您的應用程式已經在使用 Sanctum,那麼新增 Passport 可能會很麻煩。在此情況下,我們建議您在尚未有明確且必要的需求,必須使用僅支援 OAuth 的 MCP 客戶端時,暫時繼續使用 Sanctum 而不新增 Passport。
Sanctum
如果您希望使用 Sanctum 保護您的 MCP 伺服器,只需將 Sanctum 的認證中介層加入到您伺服器的 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 認證
如果您的應用程式發行自己的自訂 API 權杖,您可以透過將任何您希望的中介層指派給您的 Mcp::web
路由來認證您的 MCP 伺服器。您的自訂中介層可以手動檢查 Authorization
標頭來認證傳入的 MCP 請求。
授權
您可以透過 $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.');
}
// ...
}
測試伺服器
您可以使用內建的 MCP Inspector 或撰寫單元測試來測試您的 MCP 伺服器。
MCP Inspector
MCP Inspector 是一個互動式工具,用於測試和偵錯您的 MCP 伺服器。您可以使用它來連接到您的伺服器,驗證認證,並試用工具、資源和提示。
您可以為任何已註冊的伺服器執行檢查器 (例如,名為 "weather" 的本地伺服器):
php artisan mcp:inspector weather
此指令會啟動 MCP Inspector,並提供用戶端設定,您可以將其複製到您的 MCP 用戶端以確保一切設定正確。如果您的 Web 伺服器受到認證中介層保護,請務必在連接時包含所需的標頭,例如 Authorization
Bearer 權杖。
單元測試
您可以為您的 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.');
});
/**
* Test a tool.
*/
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()
方法斷言回應包含特定中繼資料:
$response->assertName('current-weather');
$response->assertTitle('Current Weather Tool');
$response->assertDescription('Fetches the current weather forecast for a specified location.');
您可以使用 assertSentNotification
和 assertNotificationCount
方法斷言已發送通知:
$response->assertSentNotification('processing/progress', [
'step' => 1,
'total' => 5,
]);
$response->assertSentNotification('processing/progress', [
'step' => 2,
'total' => 5,
]);
$response->assertNotificationCount(5);
最後,如果您希望檢查原始回應內容,您可以使用 dd
或 dump
方法輸出回應以進行偵錯:
$response->dd();
$response->dump();