メインコンテンツまでスキップ
バージョン: master

Laravel MCP (Laravel MCP)

導入 (Introduction)

Laravel MCP は、AI クライアントが モデルコンテキストプロトコル を通じて Laravel アプリケーションと対話するためのシンプルかつエレガントな方法を提供します。サーバー、ツール、リソース、プロンプトを定義するための表現力豊かで流暢なインターフェイスを提供し、AI を活用したアプリケーションとの対話を可能にします。

インストール (Installation)

まず、Composer パッケージ マネージャーを使用して Laravel MCP をプロジェクトにインストールします。

composer require laravel/mcp

ルートの公開

Laravel MCP をインストールした後、vendor:publish Artisan コマンドを実行して、MCP サーバーを定義する routes/ai.php ファイルを公開します。

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

このコマンドは、アプリケーションの routes ディレクトリに routes/ai.php ファイルを作成します。このファイルは、MCP サーバーの登録に使用されます。

サーバーの作成 (Creating Servers)

make:mcp-server Artisan コマンドを使用して MCP サーバーを作成できます。サーバーは、ツール、リソース、プロンプトなどの MCP 機能を AI クライアントに公開する中央の通信ポイントとして機能します。

php artisan make:mcp-server WeatherServer

このコマンドは、app/Mcp/Servers ディレクトリに新しいサーバー クラスを作成します。生成されたサーバークラスは、Laravel MCP の基本 Laravel\Mcp\Server クラスを拡張し、サーバーを構成し、ツール、リソース、プロンプトを登録するための属性とプロパティを提供します。

<?php

namespace App\Mcp\Servers;

use Laravel\Mcp\Server\Attributes\Instructions;
use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Attributes\Version;
use Laravel\Mcp\Server;

#[Name('Weather Server')]
#[Version('1.0.0')]
#[Instructions('This server provides weather information and forecasts.')]
class WeatherServer extends Server
{
/**
* The tools registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
*/
protected array $tools = [
// GetCurrentWeatherTool::class,
];

/**
* The resources registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
*/
protected array $resources = [
// WeatherGuidelinesResource::class,
];

/**
* The prompts registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
*/
protected array $prompts = [
// DescribeWeatherPrompt::class,
];
}

サーバー登録

サーバーを作成したら、それを routes/ai.php ファイルに登録してアクセスできるようにする必要があります。 Laravel MCP は、サーバーを登録するための 2 つの方法を提供します。HTTP アクセス可能なサーバー用の web と、コマンドライン サーバー用の local です。

ウェブサーバー

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 コマンドとして実行され、Laravelブースト のようなローカル AI アシスタント統合の構築に最適です。 local メソッドを使用してローカル サーバーを登録します。

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

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

一度登録すると、通常は mcp:start Artisan コマンドを自分で手動で実行する必要はありません。代わりに、サーバーを起動するか、MCP検査官 を使用するように MCP クライアント (AI エージェント) を構成します。

ツール (Tools)

ツールを使用すると、サーバーは AI クライアントが呼び出すことができる機能を公開できます。これらにより、言語モデルがアクションを実行したり、コードを実行したり、外部システムと対話したりできるようになります。

<?php

namespace App\Mcp\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\Tool;

#[Description('Fetches the current weather forecast for a specified location.')]
class CurrentWeatherTool extends Tool
{
/**
* Handle the tool request.
*/
public function handle(Request $request): Response
{
$location = $request->get('location');

// Get weather...

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

/**
* Get the tool's input schema.
*
* @return array<string, \Illuminate\JsonSchema\Types\Type>
*/
public function schema(JsonSchema $schema): array
{
return [
'location' => $schema->string()
->description('The location to get the weather for.')
->required(),
];
}
}

ツールの作成

ツールを作成するには、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 属性を使用してカスタマイズできます。

use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Attributes\Title;

#[Name('get-optimistic-weather')]
#[Title('Get Optimistic Weather Forecast')]
class CurrentWeatherTool extends Tool
{
// ...
}

ツールの説明は自動生成されません。常に Description 属性を使用して意味のある説明を提供する必要があります。

use Laravel\Mcp\Server\Attributes\Description;

#[Description('Fetches the current weather forecast for a specified location.')]
class CurrentWeatherTool extends Tool
{
//
}

説明はツールのメタデータの重要な部分であり、AI モデルがツールをいつどのように効果的に使用するかを理解するのに役立ちます。

ツール入力スキーマ

ツールは入力スキーマを定義して、AI クライアントから受け入れる引数を指定できます。 Laravel の Illuminate\Contracts\JsonSchema\JsonSchema ビルダを使用して、ツールの入力要件を定義します。

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
/**
* Get the tool's input schema.
*
* @return array<string, \Illuminate\JsonSchema\Types\Type>
*/
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'),
];
}
}

ツール出力スキーマ

ツールは 出力スキーマ を定義して応答の構造を指定できます。これにより、解析可能なツール結果を必要とする AI クライアントとの統合が可能になります。 outputSchema メソッドを使用して、ツールの出力構造を定義します。

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
/**
* Get the tool's output schema.
*
* @return array<string, \Illuminate\JsonSchema\Types\Type>
*/
public function outputSchema(JsonSchema $schema): array
{
return [
'temperature' => $schema->number()
->description('Temperature in Celsius')
->required(),

'conditions' => $schema->string()
->description('Weather conditions')
->required(),

'humidity' => $schema->integer()
->description('Humidity percentage')
->required(),
];
}
}

ツールの引数の検証

JSON スキーマ定義はツール引数の基本構造を提供しますが、より複雑な検証ルールを強制することもできます。

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
{
//
}

利用可能な注釈は次のとおりです。

注釈タイプ説明
#[IsReadOnly]ブール値ツールが環境を変更しないことを示します。
#[IsDestructive]ブール値ツールが破壊的な更新を実行する可能性があることを示します (読み取り専用でない場合にのみ意味があります)。
#[IsIdempotent]ブール値同じ引数で繰り返し呼び出しても追加の効果がないことを示します (読み取り専用でない場合)。
#[IsOpenWorld]ブール値ツールが外部エンティティと対話する可能性があることを示します。

注釈値は、ブール引数を使用して明示的に設定できます。

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

#[IsReadOnly(true)]
#[IsDestructive(false)]
#[IsOpenWorld(false)]
#[IsIdempotent(true)]
class CurrentWeatherTool extends Tool
{
//
}

条件付きツールの登録

ツール クラスに 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.');

画像または音声コンテンツを返すには、image メソッドと audio メソッドを使用します。

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

return Response::audio(file_get_contents(storage_path('weather/alert.mp3')), 'audio/mp3');

fromStorage メソッドを使用して、Laravel ファイルシステム ディスクから画像と音声のコンテンツを直接ロードすることもできます。 MIME タイプはファイルから自動的に検出されます。

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

必要に応じて、特定のディスクを指定するか、MIME タイプをオーバーライドできます。

return Response::fromStorage('weather/radar.png', disk: 's3');

return Response::fromStorage('weather/radar.png', mimeType: 'image/webp');

複数のコンテンツ応答

ツールは、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')
];
}

構造化された応答

ツールは、structured メソッドを使用して 構造化されたコンテンツ を返すことができます。これにより、JSON エンコードされたテキスト表現との下位互換性を維持しながら、AI クライアントに解析可能なデータが提供されます。

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

構造化コンテンツと一緒にカスタム テキストを提供する必要がある場合は、レスポンス ファクトリで withStructuredContent メソッドを使用します。

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

ストリーミング応答

長時間実行される操作またはリアルタイム データ ストリーミングの場合、ツールは 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
{
/**
* 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)

Prompts を使用すると、AI クライアントが言語モデルと対話するために使用できる再利用可能なプロンプト テンプレートをサーバーで共有できるようになります。これらは、一般的なクエリと対話を構造化するための標準化された方法を提供します。

プロンプトの作成

プロンプトを作成するには、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
{
/**
* The prompts registered with this MCP server.
*
* @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
*/
protected array $prompts = [
DescribeWeatherPrompt::class,
];
}

プロンプト名、タイトル、および説明

デフォルトでは、プロンプトの名前とタイトルはクラス名から派生します。たとえば、DescribeWeatherPrompt の名前は describe-weather、タイトルは Describe Weather Prompt になります。これらの値は、Name 属性と Title 属性を使用してカスタマイズできます。

use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Attributes\Title;

#[Name('weather-assistant')]
#[Title('Weather Assistant Prompt')]
class DescribeWeatherPrompt extends Prompt
{
// ...
}

プロンプトの説明は自動的には生成されません。常に Description 属性を使用して意味のある説明を提供する必要があります。

use Laravel\Mcp\Server\Attributes\Description;

#[Description('Generates a natural-language explanation of the weather for a given location.')]
class DescribeWeatherPrompt extends Prompt
{
//
}

説明は、AI モデルがプロンプトをいつどのように最大限に活用するかを理解するのに役立つため、プロンプトのメタデータの重要な部分です。

プロンプト引数

プロンプトでは、AI クライアントが特定の値を使用してプロンプト テンプレートをカスタマイズできるようにする引数を定義できます。 arguments メソッドを使用して、プロンプトが受け入れる引数を定義します。

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

プロンプト引数の検証

プロンプト引数はその定義に基づいて自動的に検証されますが、より複雑な検証ルールを適用することもできます。

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
{
/**
* 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 サービスコンテナ は、すべてのプロンプトを解決するために使用されます。その結果、プロンプトのコンストラクターで必要な依存関係をタイプヒントで指定できるようになります。宣言された依存関係は自動的に解決され、プロンプト インスタンスに挿入されます。

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

//
}

コンストラクターの注入に加えて、プロンプトの handle メソッドでタイプヒントの依存関係を使用することもできます。サービスコンテナーは、メソッドが呼び出されるときに依存関係を自動的に解決して挿入します。

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

// ...
}
}

条件付きプロンプト登録

プロンプト クラスに shouldRegister メソッドを実装することで、実行時にプロンプ​​トを条件付きで登録できます。この方法を使用すると、アプリケーションの状態、構成、または要求パラメーターに基づいてプロンプトを使用可能にするかどうかを決定できます。

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

プロンプトの shouldRegister メソッドが false を返す場合、そのプロンプトは使用可能なプロンプトのリストに表示されず、AI クライアントによって呼び出すことはできません。

迅速な対応

プロンプトは、単一の 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)

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
{
/**
* 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 属性を使用してカスタマイズできます。

use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Attributes\Title;

#[Name('weather-api-docs')]
#[Title('Weather API Documentation')]
class WeatherGuidelinesResource extends Resource
{
// ...
}

リソースの説明は自動的には生成されません。常に Description 属性を使用して意味のある説明を提供する必要があります。

use Laravel\Mcp\Server\Attributes\Description;

#[Description('Comprehensive guidelines for using the Weather API.')]
class WeatherGuidelinesResource extends Resource
{
//
}

説明は、AI モデルがリソースをいつどのように効果的に使用するかを理解するのに役立つため、リソースのメタデータの重要な部分です。

リソーステンプレート

リソーステンプレート を使用すると、サーバーは URI パターンと変数を照合する動的リソースを公開できるようになります。リソースごとに静的 URI を定義する代わりに、テンプレート パターンに基づいて複数の URI を処理する単一のリソースを作成できます。

リソーステンプレートの作成

リソース テンプレートを作成するには、リソース クラスに HasUriTemplate インターフェイスを実装し、UriTemplate インスタンスを返す uriTemplate メソッドを定義します。

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\Attributes\MimeType;
use Laravel\Mcp\Server\Contracts\HasUriTemplate;
use Laravel\Mcp\Server\Resource;
use Laravel\Mcp\Support\UriTemplate;

#[Description('Access user files by ID')]
#[MimeType('text/plain')]
class UserFileResource extends Resource implements HasUriTemplate
{
/**
* Get the URI template for this resource.
*/
public function uriTemplate(): UriTemplate
{
return new UriTemplate('file://users/{userId}/files/{fileId}');
}

/**
* Handle the resource request.
*/
public function handle(Request $request): Response
{
$userId = $request->get('userId');
$fileId = $request->get('fileId');

// Fetch and return the file content...

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

リソースが HasUriTemplate インターフェイスを実装すると、静的リソースではなくリソース テンプレートとして登録されます。 AI クライアントは、テンプレート パターンに一致する URI を使用してリソースをリクエストできるようになり、URI からの変数が自動的に抽出され、リソースの handle メソッドで使用できるようになります。

URI テンプレートの構文

URI テンプレートは、中括弧で囲まれたプレースホルダーを使用して、URI 内の変数セグメントを定義します。

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

テンプレート変数へのアクセス

URI がリソース テンプレートと一致すると、抽出された変数は自動的にリクエストにマージされ、get メソッドを使用してアクセスできるようになります。

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Contracts\HasUriTemplate;
use Laravel\Mcp\Server\Resource;
use Laravel\Mcp\Support\UriTemplate;

class UserProfileResource extends Resource implements HasUriTemplate
{
public function uriTemplate(): UriTemplate
{
return new UriTemplate('file://users/{userId}/profile');
}

public function handle(Request $request): Response
{
// Access the extracted variable
$userId = $request->get('userId');

// Access the full URI if needed
$uri = $request->uri();

// Fetch user profile...

return Response::text("Profile for user {$userId}");
}
}

Request オブジェクトは、抽出された変数と要求された元の URI の両方を提供し、リソース要求を処理するための完全なコンテキストを提供します。

リソース URI と MIME タイプ

各リソースは一意の URI によって識別され、AI クライアントがリソースの形式を理解するのに役立つ MIME タイプが関連付けられています。

デフォルトでは、リソースの URI はリソース名に基づいて生成されるため、WeatherGuidelinesResource の URI は weather://resources/weather-guidelines になります。デフォルトの MIME タイプは text/plain です。

これらの値は、Uri 属性と MimeType 属性を使用してカスタマイズできます。

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Server\Attributes\MimeType;
use Laravel\Mcp\Server\Attributes\Uri;
use Laravel\Mcp\Server\Resource;

#[Uri('weather://resources/guidelines')]
#[MimeType('application/pdf')]
class WeatherGuidelinesResource extends Resource
{
}

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

リソースの注釈

annotations を使用してリソースを拡張し、追加のメタデータを AI クライアントに提供できます。注釈は属性を介してリソースに追加されます。

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Enums\Role;
use Laravel\Mcp\Server\Annotations\Audience;
use Laravel\Mcp\Server\Annotations\LastModified;
use Laravel\Mcp\Server\Annotations\Priority;
use Laravel\Mcp\Server\Resource;

#[Audience(Role::User)]
#[LastModified('2025-01-12T15:00:58Z')]
#[Priority(0.9)]
class UserDashboardResource extends Resource
{
//
}

利用可能な注釈は次のとおりです。

注釈タイプ説明
#[Audience]役割または配列対象読者 (Role::UserRole::Assistant、または両方) を指定します。
#[Priority]フロートリソースの重要性を示す 0.0 ~ 1.0 の数値スコア。
#[LastModified]リソースが最後に更新された時間を示す ISO 8601 タイムスタンプ。

条件付きリソースの登録

リソース クラスに 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 タイプはリソースに構成されている MIME タイプによって決まります。

<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Server\Attributes\MimeType;
use Laravel\Mcp\Server\Resource;

#[MimeType('image/png')]
class WeatherGuidelinesResource extends Resource
{
//
}

エラー応答

リソースの取得中にエラーが発生したことを示すには、error() メソッドを使用します。

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

メタデータ (Metadata)

Laravel MCP は、特定の MCP クライアントまたは統合で必要な MCP仕様 で定義されている _meta フィールドもサポートしています。メタデータは、ツール、リソース、プロンプトとその応答を含むすべての MCP プリミティブに適用できます。

withMeta メソッドを使用して、個々の応答コンテンツにメタデータを添付できます。

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

応答エンベロープ全体に適用される結果レベルのメタデータの場合、応答を 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']);
}

メタデータをツール、リソース、またはプロンプト自体に添付するには、クラスで $meta プロパティを定義します。

use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\Tool;

#[Description('Fetches the current weather forecast.')]
class CurrentWeatherTool extends Tool
{
protected ?array $meta = [
'version' => '2.0',
'author' => 'Weather Team',
];

// ...
}

認証 (Authentication)

ルートと同様に、ミドルウェアを使用して Web MCP サーバーを認証できます。 MCP サーバーに認証を追加すると、ユーザーはサーバーの機能を使用する前に認証する必要があります。

MCP サーバーへのアクセスを認証するには 2 つの方法があります。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 ルートに適用します。

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 の インストールおよび展開ガイド に従って、Passport をアプリケーションに追加します。次に進む前に、OAuthenticatable モデル、新しい認証ガード、およびPassport キーを用意する必要があります。

次に、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 エージェントの認証試行を拒否または承認するための認証中にエンドユーザーに表示されます。

認証画面例

このシナリオでは、基盤となる認証可能なモデルへの変換レイヤーとして OAuth を使用しているだけです。スコープなど、OAuth の多くの側面を無視しています。

既存のPassportインストールの使用

アプリケーションがすでに Laravel Passport を使用している場合、Laravel MCP は既存の Passport インストール内でシームレスに動作するはずですが、OAuth は主に基盤となる認証可能なモデルへの変換レイヤーとして使用されるため、カスタム スコープは現在サポートされていません。

Laravel MCP は、上で説明した Mcp::oauthRoutes メソッドを介して、単一の mcp:use スコープを追加、アドバタイズ、および使用します。

Passport vs. Sanctum

OAuth2.1 はモデル コンテキスト プロトコル仕様で文書化された認証メカニズムであり、MCP クライアント間で最も広くサポートされています。そのため、可能な限りPassportを使用することをお勧めします。

アプリケーションがすでに Sanctum を使用している場合、Passport の追加は面倒な場合があります。この場合、OAuth のみをサポートする MCP クライアントを使用するための明確な必要な要件が得られるまで、Passport なしで Sanctum を使用することをお勧めします。

Sanctum

Sanctum を使用して MCP サーバーを保護したい場合は、routes/ai.php ファイルで Sanctum の認証ミドルウェアをサーバーに追加するだけです。次に、認証が成功するように、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 リクエストを認証できます。

認可 (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 インスペクターを使用するか、単体テストを作成することによって、MCP サーバーをテストできます。

MCP検査官

MCP検査官 は、MCP サーバーをテストおよびデバッグするための対話型ツールです。これを使用してサーバーに接続し、認証を確認し、ツール、リソース、プロンプトを試します。

登録されている任意のサーバーに対してインスペクタを実行できます。

# Web server...
php artisan mcp:inspector mcp/weather

# Local server named "weather"...
php artisan mcp:inspector weather

このコマンドは MCP インスペクターを起動し、すべてが正しく構成されていることを確認するために MCP クライアントにコピーできるクライアント設定を提供します。 Web サーバーが認証ミドルウェアによって保護されている場合は、接続時に Authorization ベアラー トークンなどの必要なヘッダーを必ず含めてください。

単体テスト

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