> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel MCP

> LaravelアプリケーションにModel Context Protocol(MCP)サーバーを組み込む方法を学びましょう。AI コーディングエージェントがあなたのアプリケーションと対話できるツール、リソース、プロンプトを定義できます。

## MCPとは

**Model Context Protocol（MCP）** は、AIクライアント（Claude、Cursor、GitHub Copilotなど）とアプリケーションが標準化されたプロトコルで通信するための仕様です。MCPサーバーを実装することで、AIエージェントはあなたのLaravelアプリケーションのデータにアクセスしたり、アクションを実行したりできるようになります。

<Info>
  Laravel MCP は Laravel 13 で追加された公式パッケージです。`laravel/mcp` として提供されており、MCPサーバーの構築に必要な一連の機能を提供します。
</Info>

MCPサーバーが提供できる機能は主に3つです。

| 機能                  | 説明                               |
| ------------------- | -------------------------------- |
| **ツール（Tools）**      | AIクライアントが呼び出せる関数。検索・更新・外部API連携など |
| **リソース（Resources）** | AIクライアントが読み込めるデータやコンテキスト情報       |
| **プロンプト（Prompts）**  | 再利用可能なプロンプトテンプレート                |

## インストール

Composerでパッケージをインストールします。

```shell theme={null}
composer require laravel/mcp
```

インストール後、`vendor:publish` Artisanコマンドを実行して `routes/ai.php` ファイルを生成します。

```shell theme={null}
php artisan vendor:publish --tag=ai-routes
```

このコマンドにより `routes/ai.php` ファイルが作成されます。ここにMCPサーバーの登録を記述します。

## サーバーの作成

`make:mcp-server` Artisanコマンドでサーバークラスを生成します。

```shell theme={null}
php artisan make:mcp-server WeatherServer
```

`app/Mcp/Servers` ディレクトリにサーバークラスが生成されます。

```php theme={null}
<?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
{
    protected array $tools = [
        // GetCurrentWeatherTool::class,
    ];

    protected array $resources = [
        // WeatherGuidelinesResource::class,
    ];

    protected array $prompts = [
        // DescribeWeatherPrompt::class,
    ];
}
```

### サーバーの登録

サーバーを作成したら `routes/ai.php` で登録します。登録方法には **Webサーバー** と **ローカルサーバー** の2種類があります。

#### Webサーバー

WebサーバーはHTTP POSTリクエストでアクセスできます。リモートのAIクライアントやWebベースの連携に最適です。

```php theme={null}
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

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

通常のルートと同様にミドルウェアを適用できます。

```php theme={null}
Mcp::web('/mcp/weather', WeatherServer::class)
    ->middleware(['throttle:mcp']);
```

#### ローカルサーバー

ローカルサーバーはArtisanコマンドとして動作します。Claude DesktopなどのローカルAIクライアントとの連携に使います。

```php theme={null}
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

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

<Tip>
  ローカルサーバーは通常、MCPクライアントが自動的に起動します。手動で `mcp:start` Artisanコマンドを実行する必要はありません。
</Tip>

## ツール

ツールはAIクライアントが呼び出せる関数です。データの取得、外部APIとの連携、データベースの操作などを実装できます。

### ツールの作成

`make:mcp-tool` Artisanコマンドでツールクラスを生成します。

```shell theme={null}
php artisan make:mcp-tool CurrentWeatherTool
```

作成したツールをサーバーの `$tools` プロパティに登録します。

```php theme={null}
use App\Mcp\Tools\CurrentWeatherTool;
use Laravel\Mcp\Server;

class WeatherServer extends Server
{
    protected array $tools = [
        CurrentWeatherTool::class,
    ];
}
```

基本的なツールクラスの実装例です。

```php theme={null}
<?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
{
    public function handle(Request $request): Response
    {
        $location = $request->get('location');

        // 天気データを取得する...

        return Response::text('The weather is sunny, 22°C.');
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'location' => $schema->string()
                ->description('The location to get the weather for.')
                ->required(),
        ];
    }
}
```

### ツールの名前と説明

クラス名からデフォルトの名前とタイトルが自動生成されます。`CurrentWeatherTool` であれば名前は `current-weather`、タイトルは `Current Weather Tool` になります。`Name` と `Title` 属性でカスタマイズできます。

```php theme={null}
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
{
    // ...
}
```

<Warning>
  ツールの説明（`Description`）は自動生成されません。AIモデルがツールの使い方を理解するために必須なので、必ず意味のある説明を設定してください。
</Warning>

### 入力スキーマ

`schema` メソッドで入力パラメーターのスキーマを定義します。LaravelのJSONスキーマビルダーを使って型や制約を指定できます。

```php theme={null}
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'),
    ];
}
```

### 出力スキーマ

`outputSchema` メソッドでレスポンスの構造を定義できます。AIクライアントがレスポンスを解析しやすくなります。

```php theme={null}
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(),
    ];
}
```

### バリデーション

`handle` メソッド内でLaravelの標準バリデーション機能を使えます。

```php theme={null}
public function handle(Request $request): Response
{
    $validated = $request->validate([
        'location' => 'required|string|max:100',
        'units' => 'in:celsius,fahrenheit',
    ], [
        'location.required' => 'You must specify a location. For example, "New York City" or "Tokyo".',
        'units.in' => 'You must specify either "celsius" or "fahrenheit" for the units.',
    ]);

    // バリデーション済みのデータを使って処理を行う...
}
```

<Tip>
  バリデーション失敗時にAIクライアントはエラーメッセージを参考に再試行します。具体的で実行可能なエラーメッセージを提供してください。
</Tip>

### 依存性注入

Laravelのサービスコンテナを通じてツールが解決されるため、コンストラクタや `handle` メソッドで依存関係を型ヒントできます。

```php theme={null}
<?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 __construct(
        protected WeatherRepository $weather,
    ) {}

    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $location = $request->get('location');
        $forecast = $weather->getForecastFor($location);

        return Response::text("Forecast: {$forecast}");
    }
}
```

### アノテーション

ツールにアノテーションを追加することで、AIクライアントにツールの振る舞いに関する追加情報を提供できます。

```php theme={null}
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]`   | ツールが外部エンティティと対話する可能性があることを示す |

### 条件付き登録

`shouldRegister` メソッドを実装することで、実行時にツールを条件付きで登録できます。

```php theme={null}
public function shouldRegister(Request $request): bool
{
    return $request?->user()?->subscribed() ?? false;
}
```

`false` を返すとそのツールはAIクライアントから見えなくなります。

### レスポンス

ツールは `Laravel\Mcp\Response` のインスタンスを返す必要があります。

<AccordionGroup>
  <Accordion title="テキストレスポンス">
    ```php theme={null}
    return Response::text('Weather Summary: Sunny, 22°C');
    ```
  </Accordion>

  <Accordion title="エラーレスポンス">
    ```php theme={null}
    return Response::error('Unable to fetch weather data. Please try again.');
    ```
  </Accordion>

  <Accordion title="画像・音声レスポンス">
    ```php theme={null}
    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');

    // ストレージから直接読み込む（MIMEタイプは自動検出）
    return Response::fromStorage('weather/radar.png');
    ```
  </Accordion>

  <Accordion title="複数コンテンツのレスポンス">
    ```php theme={null}
    public function handle(Request $request): array
    {
        return [
            Response::text('Weather Summary: Sunny, 22°C'),
            Response::text("**Detailed Forecast**\n- Morning: 18°C\n- Afternoon: 25°C"),
        ];
    }
    ```
  </Accordion>

  <Accordion title="構造化レスポンス">
    AIクライアントが解析しやすい構造化データを返します。

    ```php theme={null}
    return Response::structured([
        'temperature' => 22.5,
        'conditions' => 'Partly cloudy',
        'humidity' => 65,
    ]);
    ```
  </Accordion>

  <Accordion title="ストリーミングレスポンス">
    長時間かかる処理で途中経過をリアルタイム送信します。

    ```php theme={null}
    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));
        }
    }
    ```
  </Accordion>
</AccordionGroup>

## プロンプト

プロンプトは再利用可能なプロンプトテンプレートです。AIクライアントが言語モデルと対話する際に使う定型的なクエリを標準化した形で提供できます。

### プロンプトの作成

```shell theme={null}
php artisan make:mcp-prompt DescribeWeatherPrompt
```

サーバーの `$prompts` プロパティに登録します。

```php theme={null}
use App\Mcp\Prompts\DescribeWeatherPrompt;

class WeatherServer extends Server
{
    protected array $prompts = [
        DescribeWeatherPrompt::class,
    ];
}
```

### プロンプトの引数

`arguments` メソッドでプロンプトのパラメーターを定義します。

```php theme={null}
<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    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,
            ),
        ];
    }
}
```

### プロンプトのレスポンス

プロンプトの `handle` メソッドではユーザーメッセージとアシスタントメッセージを返せます。`asAssistant()` でアシスタント側のメッセージとして扱います。

```php theme={null}
<?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): 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 Tokyo?';

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

## リソース

リソースはAIクライアントがコンテキストとして読み込めるデータや情報です。ドキュメント、設定情報、動的データなど、AIの応答品質を向上させる情報を提供できます。

### リソースの作成

```shell theme={null}
php artisan make:mcp-resource WeatherGuidelinesResource
```

サーバーの `$resources` プロパティに登録します。

```php theme={null}
use App\Mcp\Resources\WeatherGuidelinesResource;

class WeatherServer extends Server
{
    protected array $resources = [
        WeatherGuidelinesResource::class,
    ];
}
```

```php theme={null}
<?php

namespace App\Mcp\Resources;

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

#[Description('Comprehensive guidelines for using the Weather API.')]
class WeatherGuidelinesResource extends Resource
{
    public function handle(Request $request): Response
    {
        $guidelines = "# Weather API Guidelines\n\n- Always specify a location...";

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

### URIとMIMEタイプ

デフォルトではクラス名からURIが自動生成されます（例: `weather://resources/weather-guidelines`）。`Uri` と `MimeType` 属性でカスタマイズできます。

```php theme={null}
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変数を持つ動的リソースを定義するには `HasUriTemplate` インターフェースを実装します。

```php theme={null}
<?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
{
    public function uriTemplate(): UriTemplate
    {
        return new UriTemplate('file://users/{userId}/files/{fileId}');
    }

    public function handle(Request $request): Response
    {
        $userId = $request->get('userId');
        $fileId = $request->get('fileId');

        // ファイルコンテンツを取得して返す...

        return Response::text("File {$fileId} for user {$userId}");
    }
}
```

URIからの変数は自動的にリクエストに取り込まれ、`get` メソッドで取得できます。

### リソースのアノテーション

リソースにはオーディエンス、優先度、最終更新日などのアノテーションを付けられます。

```php theme={null}
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 または配列 | 対象オーディエンス（`Role::User`、`Role::Assistant`、または両方） |
| `#[Priority]`     | float      | 重要度スコア（0.0〜1.0）                                 |
| `#[LastModified]` | string     | ISO 8601形式の最終更新日時                               |

## アプリ

Laravel MCPは[MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview)をサポートしています。これはModel Context Protocolの拡張機能で、ツールがサポートされたホスト内のサンドボックスiframe上でインタラクティブなHTMLアプリケーションをレンダリングできるようにします。これにより、プレーンテキストのレスポンスを超えた、ダッシュボード、フォーム、ビジュアライゼーション、その他のリッチな体験を構築できます。

MCPアプリは以下の2つのパーツが連携して動作します。

* **アプリリソース** — アプリケーションの自己完結型HTMLを返します。
* **ツール** — `#[RendersApp]` アトリビュートを使ってアプリリソースにリンクされます。ツールが呼び出されると、ホストがリンクされたリソースを取得してレンダリングします。

### アプリリソースの作成

`make:mcp-app-resource` Artisanコマンドでアプリリソースを作成できます。

```shell theme={null}
php artisan make:mcp-app-resource WeatherDashboardApp
```

このコマンドは2つのファイルを作成します。`app/Mcp/Resources` 内のPHPクラスと `resources/views/mcp` 内のBladeビューです。ビュー名はクラス名から自動的に推測されます。たとえば `WeatherDashboardApp` は `mcp.weather-dashboard-app` にマッピングされます。

```php theme={null}
<?php

namespace App\Mcp\Resources;

use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\AppMeta;
use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\AppResource;

#[Description('An interactive weather dashboard.')]
#[AppMeta]
class WeatherDashboardApp extends AppResource
{
    /**
     * Handle the app resource request.
     */
    public function handle(Request $request): Response
    {
        return Response::view('mcp.weather-dashboard-app', [
            'title' => $this->title(),
        ]);
    }
}
```

`AppResource` はベースの `Resource` クラスを継承し、MCP Apps仕様で要求される `ui://` URIスキームと `text/html;profile=mcp-app` MIMEタイプを自動的に設定します。他のリソースと同様に、サーバーの `$resources` 配列に登録する必要があります。

生成されたBladeビューは `<x-mcp::app>` コンポーネントを使用します。このコンポーネントはクライアントサイドのMCP SDKがバンドルされた完全なHTMLドキュメントをレンダリングします。

```blade theme={null}
<x-mcp::app :title="$title">
    <x-slot:head>
        <script type="module">
        createMcpApp(async (app) => {
            document.getElementById('run-btn').addEventListener('click', async () => {
                const result = await app.callServerTool('get-weather-data', {});
                document.getElementById('output').textContent = result.content[0]?.text ?? '';
            });
        });
        </script>
    </x-slot:head>

    <div id="app">
        <button id="run-btn">Refresh</button>
        <p id="output"></p>
    </div>
</x-mcp::app>
```

`createMcpApp` グローバル関数はバンドルされたSDKが提供します。iframeのサーバーへの接続、ホストテーマの適用、`callServerTool`・`sendMessage`・`openLink`などのヘルパーやイベントコールバックの公開を処理します。完全なクライアントサイドAPIについては[MCP Apps仕様](https://modelcontextprotocol.io/extensions/apps/overview)を参照してください。

### ツールからアプリをレンダリング

アプリリソースを表示するには、`#[RendersApp]` アトリビュートを使ってツールにリンクします。ツールが呼び出されると、Laravel MCPはリソースのURIをツールのメタデータに含め、ホストがサンドボックスiframe内でアプリをレンダリングできるようにします。

```php theme={null}
<?php

namespace App\Mcp\Tools;

use App\Mcp\Resources\WeatherDashboardApp;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\RendersApp;
use Laravel\Mcp\Server\Tool;

#[RendersApp(resource: WeatherDashboardApp::class)]
class ShowWeatherDashboard extends Tool
{
    /**
     * Handle the tool request.
     */
    public function handle(Request $request): Response
    {
        return Response::text('Weather dashboard loaded.');
    }
}
```

<Info>
  `AppResource` が登録されると、Laravel MCPは自動的に `io.modelcontextprotocol/ui` ケイパビリティをアドバタイズします。追加のサーバー設定は不要です。
</Info>

### アプリツールの可視性

各 `#[RendersApp]` ツールは `visibility` 引数で呼び出し元を制限できます。これは、UIがデータを読み込み・更新するために呼び出すプライベートなアプリ専用ツールを、モデルからは見えないようにする場合に便利です。

```php theme={null}
use Laravel\Mcp\Server\Attributes\RendersApp;
use Laravel\Mcp\Server\Ui\Enums\Visibility;

#[RendersApp(resource: WeatherDashboardApp::class, visibility: [Visibility::App])]
class GetWeatherData extends Tool
{
    // ...
}
```

`Visibility` enumには `Model` と `App` の2つのケースがあり、デフォルトは両方です。UIが直接呼び出すバックエンドアクションには `[Visibility::App]` を、UIからツールを利用不可にするには `[Visibility::Model]` を使います。

### アプリの設定

アプリリソースの `#[AppMeta]` アトリビュートで、iframeのContent Security Policy、ブラウザ権限、ビューの `<head>` に含めるライブラリスクリプトを設定します。

```php theme={null}
use Laravel\Mcp\Server\Attributes\AppMeta;
use Laravel\Mcp\Server\Ui\Enums\Library;
use Laravel\Mcp\Server\Ui\Enums\Permission;

#[AppMeta(
    connectDomains: ['https://api.weather.com'],
    permissions: [Permission::Geolocation],
    libraries: [Library::Tailwind, Library::Alpine],
)]
class WeatherDashboardApp extends AppResource
{
    // ...
}
```

`Library` enumには `Library::Tailwind` や `Library::Alpine` など一般的なフロントエンドライブラリのCDNスクリプトが事前設定されており、CDNオリジンは自動的にCSPにマージされます。`Permission` enumは `Camera`・`Microphone`・`Geolocation`・`ClipboardWrite` などのブラウザ権限をカバーします。

<Tip>
  動的な設定が必要な場合は、`Laravel\Mcp\Server\Ui` 名前空間の `AppMeta`・`Csp`・`Permissions` フルエントビルダーを使ってリソースの `appMeta` メソッドをオーバーライドします。
</Tip>

### Boostを使ったアプリ開発

Laravel MCPにはMCP Appsを構築するための専用[Boost](/jp/boost)スキルリファレンスが含まれています。Laravel Boostがインストールされていれば、AIコーディングエージェントが `mcp-development` スキルを呼び出し、アプリリソース、Bladeビュー、リンクされたツールを自動生成できます。

プロトコルの完全なリファレンス（クライアントサイドAPIやスキーマの詳細を含む）については、公式の[MCP Appsドキュメント](https://modelcontextprotocol.io/extensions/apps/overview)を参照してください。

## メタデータ

MCP仕様の `_meta` フィールドをツール、リソース、プロンプトのレスポンスに付加できます。

```php theme={null}
// レスポンスコンテンツへのメタデータ
return Response::text('The weather is sunny.')
    ->withMeta(['source' => 'weather-api', 'cached' => true]);
```

レスポンスエンベロープ全体にメタデータを付ける場合は `Response::make` を使います。

```php theme={null}
return Response::make(
    Response::text('The weather is sunny.')
)->withMeta(['request_id' => '12345']);
```

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

```php theme={null}
class CurrentWeatherTool extends Tool
{
    protected ?array $meta = [
        'version' => '2.0',
        'author' => 'Weather Team',
    ];
}
```

## 認証

WebサーバーはLaravelの標準的なミドルウェアで認証できます。

### Sanctum

[Laravel Sanctum](https://laravel.com/docs/sanctum) を使ったトークン認証です。MCPクライアントは `Authorization: Bearer <token>` ヘッダーを送信します。

```php theme={null}
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

Mcp::web('/mcp/weather', WeatherServer::class)
    ->middleware('auth:sanctum');
```

### OAuth 2.1

[Laravel Passport](https://laravel.com/docs/passport) を使ったOAuth認証です。より堅牢なセキュリティが必要な場合に適しています。

```php theme={null}
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;

Mcp::oauthRoutes();

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

OAuth認証を使う場合は、Passportの認可ビューを公開してサービスプロバイダーに設定します。

```shell theme={null}
php artisan vendor:publish --tag=mcp-views
```

```php theme={null}
// AppServiceProvider::boot()
use Laravel\Passport\Passport;

Passport::authorizationView(function ($parameters) {
    return view('mcp.authorize', $parameters);
});
```

## 認可

`$request->user()` で認証済みユーザーを取得し、ツールやリソース内で認可チェックを行えます。

```php theme={null}
public function handle(Request $request): Response
{
    if (! $request->user()->can('read-weather')) {
        return Response::error('Permission denied.');
    }

    // 処理を続行...
}
```

## テスト

### MCP Inspector

MCPサーバーの動作確認には、インタラクティブなデバッグツール「MCP Inspector」を使います。

```shell theme={null}
# Webサーバー
php artisan mcp:inspector mcp/weather

# ローカルサーバー（名前が "weather" の場合）
php artisan mcp:inspector weather
```

コマンドを実行するとMCP Inspectorが起動し、クライアント設定をコピーできます。認証ミドルウェアを設定している場合は、Authorizationヘッダーを含めて接続してください。

### ユニットテスト

ツール・リソース・プロンプトに対してユニットテストを書けます。

<CodeGroup>
  ```php Pest theme={null}
  test('tool', function () {
      $response = WeatherServer::tool(CurrentWeatherTool::class, [
          'location' => 'Tokyo',
          'units' => 'celsius',
      ]);

      $response
          ->assertOk()
          ->assertSee('The current weather in Tokyo is 22°C and sunny.');
  });
  ```

  ```php PHPUnit theme={null}
  public function test_tool(): void
  {
      $response = WeatherServer::tool(CurrentWeatherTool::class, [
          'location' => 'Tokyo',
          'units' => 'celsius',
      ]);

      $response
          ->assertOk()
          ->assertSee('The current weather in Tokyo is 22°C and sunny.');
  }
  ```
</CodeGroup>

プロンプトとリソースも同様にテストできます。

```php theme={null}
$response = WeatherServer::prompt(DescribeWeatherPrompt::class, ['tone' => 'casual']);
$response = WeatherServer::resource(WeatherGuidelinesResource::class);
```

認証済みユーザーとして実行するには `actingAs` を使います。

```php theme={null}
$response = WeatherServer::actingAs($user)->tool(CurrentWeatherTool::class, [...]);
```

主なアサーションメソッドは次のとおりです。

```php theme={null}
$response->assertOk();           // エラーがないことを確認
$response->assertSee('...');     // 特定のテキストが含まれることを確認
```
