Идёт обновление сайта. Несколько дней возможны сбои в оформлении и переводах. Документация работает — если страница выглядит сломанной, обновите её позже.

Документация
L Laravel L intervention/image
Войти

Laravel MCP

10.x 7 мар 2026 г.

#Введение

Laravel MCP предоставляет простой и элегантный способ для AI-клиентов взаимодействовать с вашим приложением Laravel через Model Context Protocol. Он предлагает выразительный, удобный интерфейс для определения серверов, инструментов, ресурсов и подсказок, которые обеспечивают взаимодействие с приложением на базе ИИ.

#Установка

Для начала установите Laravel MCP в ваш проект с помощью менеджера пакетов Composer:

composer require laravel/mcp

#Публикация маршрутов

После установки Laravel MCP выполните Artisan-команду vendor:publish, чтобы опубликовать файл routes/ai.php, в котором вы будете определять ваши MCP-серверы:

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

Эта команда создаст файл routes/ai.php в директории routes вашего приложения, который вы будете использовать для регистрации MCP-серверов.

#Создание серверов

Вы можете создать MCP-сервер с помощью Artisan-команды make:mcp-server. Серверы выступают центральной точкой коммуникации, которая предоставляет возможности MCP, такие как инструменты, ресурсы и подсказки, для AI-клиентов:

php artisan make:mcp-server WeatherServer

Эта команда создаст новый класс сервера в директории app/Mcp/Servers. Сгенерированный класс сервера расширяет базовый класс Laravel\Mcp\Server Laravel MCP и предоставляет свойства для регистрации инструментов, ресурсов и подсказок:

<?php

namespace App\Mcp\Servers;

use Laravel\Mcp\Server;

class WeatherServer extends Server
{
    /**
     * Инструменты, зарегистрированные на этом MCP-сервере.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
     */
    protected array $tools = [
        // ExampleTool::class,
    ];

    /**
     * Ресурсы, зарегистрированные на этом MCP-сервере.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
     */
    protected array $resources = [
        // ExampleResource::class,
    ];

    /**
     * Подсказки, зарегистрированные на этом MCP-сервере.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
     */
    protected array $prompts = [
        // ExamplePrompt::class,
    ];
}

#Регистрация сервера

После создания сервера его необходимо зарегистрировать в файле routes/ai.php, чтобы сделать доступным. Laravel MCP предоставляет два способа регистрации серверов: web для серверов, доступных по HTTP, и local для серверов командной строки.

#Веб-серверы

Веб-серверы — наиболее распространённый тип серверов, доступных через HTTP POST-запросы, что делает их идеальными для удалённых AI-клиентов или веб-интеграций. Зарегистрируйте веб-сервер с помощью метода web:

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

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

Как и для обычных маршрутов, вы можете применять middleware для защиты ваших веб-серверов:

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-агента) для запуска сервера. Команда mcp:start предназначена для вызова клиентом, который будет управлять запуском и остановкой сервера по необходимости:

php artisan mcp:start weather

#Инструменты

Инструменты позволяют вашему серверу предоставлять функциональность, которую AI-клиенты могут вызывать. Они дают языковым моделям возможность выполнять действия, запускать код или взаимодействовать с внешними системами.

#Создание инструментов

Для создания инструмента выполните Artisan-команду make:mcp-tool:

php artisan make:mcp-tool CurrentWeatherTool

После создания инструмента зарегистрируйте его в свойстве $tools вашего сервера:

<?php

namespace App\Mcp\Servers;

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

class WeatherServer extends Server
{
    /**
     * Инструменты, зарегистрированные на этом MCP-сервере.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
     */
    protected array $tools = [
        CurrentWeatherTool::class,
    ];
}

#Имя, заголовок и описание инструмента

По умолчанию имя и заголовок инструмента выводятся из имени класса. Например, CurrentWeatherTool будет иметь имя current-weather и заголовок Current Weather Tool. Вы можете настроить эти значения, определив свойства $name и $title в вашем инструменте:

class CurrentWeatherTool extends Tool
{
    /**
     * Имя инструмента.
     */
    protected string $name = 'get-optimistic-weather';

    /**
     * Заголовок инструмента.
     */
    protected string $title = 'Get Optimistic Weather Forecast';

    // ...
}

Описание инструмента не генерируется автоматически. Вы всегда должны предоставлять осмысленное описание, определяя свойство $description в вашем инструменте:

class CurrentWeatherTool extends Tool
{
    /**
     * Описание инструмента.
     */
    protected string $description = 'Fetches the current weather forecast for a specified location.';

    //
}
Примечание

Описание является важной частью метаданных инструмента, так как помогает языковым моделям понять, когда и как эффективно использовать инструмент.

#Схемы ввода инструментов

Инструменты могут определять схемы ввода, чтобы указать, какие аргументы они принимают от AI-клиентов. Используйте конструктор Illuminate\JsonSchema\JsonSchema Laravel для определения требований к вводу вашего инструмента:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Возвращает схему входных данных для инструмента.
     *
     * @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
{
    /**
     * Обработать запрос инструмента.
     */
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'location' => 'required|string|max:100',
            'units' => 'in:celsius,fahrenheit',
        ]);

        // Получить данные о погоде, используя проверенные аргументы...
    }
}

При ошибках валидации 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 service container используется для разрешения всех инструментов. В результате вы можете указывать типы любых зависимостей, которые нужны вашему инструменту, в его конструкторе. Объявленные зависимости автоматически разрешаются и внедряются в экземпляр инструмента:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Создать новый экземпляр инструмента.
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    // ...
}

Кроме внедрения через конструктор, вы также можете указывать зависимости в методе handle() вашего инструмента. Service container автоматически разрешит и внедрит зависимости при вызове метода:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Обработать запрос инструмента.
     */
    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $location = $request->get('location');

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

        // ...
    }
}

#Аннотации инструментов

Вы можете расширить ваши инструменты с помощью аннотаций, чтобы предоставить дополнительную метаинформацию AI-клиентам. Эти аннотации помогают языковым моделям понять поведение и возможности инструмента. Аннотации добавляются к инструментам через атрибуты:

<?php

namespace App\Mcp\Tools;

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

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

Доступные аннотации включают:

Аннотация Тип Описание
#[IsReadOnly] boolean Указывает, что инструмент не изменяет своё окружение.
#[IsDestructive] boolean Указывает, что инструмент может выполнять разрушительные обновления (актуально, если не read-only).
#[IsIdempotent] boolean Указывает, что повторные вызовы с одинаковыми аргументами не имеют дополнительного эффекта (если не read-only).
#[IsOpenWorld] boolean Указывает, что инструмент может взаимодействовать с внешними сущностями.

#Условная регистрация инструментов

Вы можете условно регистрировать инструменты во время выполнения, реализовав метод shouldRegister в классе инструмента. Этот метод позволяет определить, должен ли инструмент быть доступен в зависимости от состояния приложения, конфигурации или параметров запроса:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Определить, должен ли инструмент регистрироваться.
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

Если метод shouldRegister инструмента возвращает false, он не будет отображаться в списке доступных инструментов и не сможет быть вызван AI-клиентами.

#Ответы инструментов

Инструменты должны возвращать экземпляр Laravel\Mcp\Response. Класс Response предоставляет несколько удобных методов для создания различных типов ответов:

Для простых текстовых ответов используйте метод text:

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

/**
 * Обработать запрос инструмента.
 */
public function handle(Request $request): Response
{
    // ...

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

Чтобы указать, что во время выполнения инструмента произошла ошибка, используйте метод error:

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

#Ответы с несколькими частями контента

Инструменты могут возвращать несколько частей контента, возвращая массив экземпляров Response:

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

/**
 * Обработать запрос инструмента.
 *
 * @return array<int, \Laravel\Mcp\Response>
 */
public function handle(Request $request): array
{
    // ...

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

#Потоковые ответы

Для длительных операций или потоковой передачи данных в реальном времени инструменты могут возвращать генератор из метода 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
{
    /**
     * Обработать запрос инструмента.
     *
     * @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));
        }
    }
}

При использовании веб-серверов потоковые ответы автоматически открывают SSE (Server-Sent Events) поток, отправляя каждое сгенерированное сообщение как событие клиенту.

#Подсказки

Подсказки позволяют вашему серверу предоставлять повторно используемые шаблоны подсказок, которые AI-клиенты могут использовать для взаимодействия с языковыми моделями. Они обеспечивают стандартизированный способ структурирования общих запросов и взаимодействий.

#Создание подсказок

Для создания подсказки выполните Artisan-команду make:mcp-prompt:

php artisan make:mcp-prompt DescribeWeatherPrompt

После создания подсказки зарегистрируйте её в свойстве $prompts вашего сервера:

<?php

namespace App\Mcp\Servers;

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

class WeatherServer extends Server
{
    /**
     * Подсказки, зарегистрированные на этом MCP-сервере.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
     */
    protected array $prompts = [
        DescribeWeatherPrompt::class,
    ];
}

#Имя, заголовок и описание подсказки

По умолчанию имя и заголовок подсказки выводятся из имени класса. Например, DescribeWeatherPrompt будет иметь имя describe-weather и заголовок Describe Weather Prompt. Вы можете настроить эти значения, определив свойства $name и $title в вашей подсказке:

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Имя подсказки.
     */
    protected string $name = 'weather-assistant';

    /**
     * Заголовок подсказки.
     */
    protected string $title = 'Weather Assistant Prompt';

    // ...
}

Описание подсказки не генерируется автоматически. Вы всегда должны предоставлять осмысленное описание, определяя свойство $description в вашей подсказке:

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Описание подсказки.
     */
    protected string $description = 'Generates a natural-language explanation of the weather for a given location.';

    //
}
Примечание

Описание является важной частью метаданных подсказки, так как помогает языковым моделям понять, когда и как максимально эффективно использовать подсказку.

#Аргументы подсказок

Подсказки могут определять аргументы, которые позволяют AI-клиентам настраивать шаблон подсказки с конкретными значениями. Используйте метод arguments для определения принимаемых аргументов:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Получить аргументы подсказки.
     *
     * @return array<int, \Laravel\Mcp\Server\Prompts\Argument>
     */
    public function arguments(): array
    {
        return [
            new Argument(
                name: 'tone',
                description: 'The tone to use in the weather description (e.g., formal, casual, humorous).',
                required: true,
            ),
        ];
    }
}

#Валидация аргументов подсказок

Аргументы подсказок автоматически валидируются на основе их определения, но вы также можете применять более сложные правила валидации.

Laravel MCP интегрируется с валидацией Laravel. Вы можете валидировать входящие аргументы подсказки внутри метода handle вашей подсказки:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Обработать запрос подсказки.
     */
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'tone' => 'required|string|max:50',
        ]);

        $tone = $validated['tone'];

        // Сгенерировать ответ подсказки с использованием заданного тона...
    }
}

При ошибках валидации 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 используется для разрешения всех подсказок. В результате вы можете указывать типы любых зависимостей, которые нужны вашей подсказке, в её конструкторе. Объявленные зависимости автоматически разрешаются и внедряются в экземпляр подсказки:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Создать новый экземпляр подсказки.
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    //
}

Кроме внедрения через конструктор, вы также можете указывать зависимости в методе handle() вашей подсказки. Service container автоматически разрешит и внедрит зависимости при вызове метода:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Обработать запрос подсказки.
     */
    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $isAvailable = $weather->isServiceAvailable();

        // ...
    }
}

#Условная регистрация подсказок

Вы можете условно регистрировать подсказки во время выполнения, реализовав метод shouldRegister в классе подсказки. Этот метод позволяет определить, должна ли подсказка быть доступна в зависимости от состояния приложения, конфигурации или параметров запроса:

<?php

namespace App\Mcp\Prompts;

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

class CurrentWeatherPrompt extends Prompt
{
    /**
     * Определить, должна ли подсказка регистрироваться.
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

Если метод shouldRegister подсказки возвращает false, она не будет отображаться в списке доступных подсказок и не сможет быть вызвана AI-клиентами.

#Ответы подсказок

Подсказки могут возвращать один экземпляр 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
{
    /**
     * Обработать запрос подсказки.
     *
     * @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-ассистента, в то время как обычные сообщения считаются пользовательским вводом.

#Ресурсы

Ресурсы позволяют вашему серверу предоставлять данные и контент, которые AI-клиенты могут читать и использовать как контекст при взаимодействии с языковыми моделями. Они обеспечивают способ обмена статической или динамической информацией, такой как документация, конфигурация или любые данные, которые помогают формировать ответы AI.

#Создание ресурсов

Для создания ресурса выполните Artisan-команду make:mcp-resource:

php artisan make:mcp-resource WeatherGuidelinesResource

После создания ресурса зарегистрируйте его в свойстве $resources вашего сервера:

<?php

namespace App\Mcp\Servers;

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

class WeatherServer extends Server
{
    /**
     * Ресурсы, зарегистрированные на этом MCP-сервере.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
     */
    protected array $resources = [
        WeatherGuidelinesResource::class,
    ];
}

#Имя, заголовок и описание ресурса

По умолчанию имя и заголовок ресурса выводятся из имени класса. Например, WeatherGuidelinesResource будет иметь имя weather-guidelines и заголовок Weather Guidelines Resource. Вы можете настроить эти значения, определив свойства $name и $title в вашем ресурсе:

class WeatherGuidelinesResource extends Resource
{
    /**
     * Имя ресурса.
     */
    protected string $name = 'weather-api-docs';

    /**
     * Заголовок ресурса.
     */
    protected string $title = 'Weather API Documentation';

    // ...
}

Описание ресурса не генерируется автоматически. Вы всегда должны предоставлять осмысленное описание, определяя свойство $description в вашем ресурсе:

class WeatherGuidelinesResource extends Resource
{
    /**
     * Описание ресурса.
     */
    protected string $description = 'Comprehensive guidelines for using the Weather API.';

    //
}
Примечание

Описание является важной частью метаданных ресурса, так как помогает языковым моделям понять, когда и как эффективно использовать ресурс.

#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
{
    /**
     * URI ресурса.
     */
    protected string $uri = 'weather://resources/guidelines';

    /**
     * MIME-тип ресурса.
     */
    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
{
    /**
     * Обработать запрос ресурса.
     */
    public function handle(Request $request): Response
    {
        // ...
    }
}

#Внедрение зависимостей в ресурсы

Laravel service container используется для разрешения всех ресурсов. В результате вы можете указывать типы любых зависимостей, которые нужны вашему ресурсу, в его конструкторе. Объявленные зависимости автоматически разрешаются и внедряются в экземпляр ресурса:

<?php

namespace App\Mcp\Resources;

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

class WeatherGuidelinesResource extends Resource
{
    /**
     * Создать новый экземпляр ресурса.
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    // ...
}

Кроме внедрения через конструктор, вы также можете указывать зависимости в методе handle() вашего ресурса. Service container автоматически разрешит и внедрит зависимости при вызове метода:

<?php

namespace App\Mcp\Resources;

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

class WeatherGuidelinesResource extends Resource
{
    /**
     * Обработать запрос ресурса.
     */
    public function handle(WeatherRepository $weather): Response
    {
        $guidelines = $weather->guidelines();

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

#Условная регистрация ресурсов

Вы можете условно регистрировать ресурсы во время выполнения, реализовав метод shouldRegister в классе ресурса. Этот метод позволяет определить, должен ли ресурс быть доступен в зависимости от состояния приложения, конфигурации или параметров запроса:

<?php

namespace App\Mcp\Resources;

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

class WeatherGuidelinesResource extends Resource
{
    /**
     * Определить, должен ли ресурс регистрироваться.
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

Если метод shouldRegister ресурса возвращает false, он не будет отображаться в списке доступных ресурсов и не сможет быть доступен AI-клиентам.

#Ответы ресурсов

Ресурсы должны возвращать экземпляр Laravel\Mcp\Response. Класс Response предоставляет несколько удобных методов для создания различных типов ответов:

Для простого текстового контента используйте метод text:

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

/**
 * Обработать запрос ресурса.
 */
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
{
    /**
     * MIME-тип ресурса.
     */
    protected string $mimeType = 'image/png';

    //
}

#Ответы с ошибками

Чтобы указать, что при получении ресурса произошла ошибка, используйте метод error():

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

#Аутентификация

Вы можете аутентифицировать веб MCP-серверы с помощью middleware так же, как и маршруты. Это потребует аутентификации пользователя перед использованием любых возможностей сервера.

Существует два способа аутентификации доступа к вашему MCP-серверу: простая аутентификация на основе токена через Laravel Sanctum или любые другие произвольные API-токены, передаваемые через HTTP-заголовок Authorization. Либо вы можете аутентифицироваться через OAuth с помощью Laravel Passport.

#OAuth 2.1

Самый надёжный способ защитить ваши веб MCP-серверы — использовать OAuth через Laravel Passport.

При аутентификации MCP-сервера через OAuth вызовите метод Mcp::oauthRoutes в файле routes/ai.php для регистрации необходимых маршрутов OAuth2 discovery и регистрации клиентов. Затем примените middleware auth:api Passport к маршруту Mcp::web в файле routes/ai.php:

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, новый guard аутентификации и ключи Passport перед продолжением.

Далее опубликуйте предоставленное Laravel MCP представление авторизации Passport:

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

Затем укажите Passport использовать это представление с помощью метода Passport::authorizationView. Обычно этот метод вызывается в методе boot вашего AppServiceProvider:

use Laravel\Passport\Passport;

/**
 * Инициализация сервисов приложения.
 */
public function boot(): void
{
    Passport::authorizationView(function ($parameters) {
        return view('mcp.authorize', $parameters);
    });
}

Это представление будет отображаться конечному пользователю во время аутентификации для отклонения или одобрения попытки аутентификации AI-агента.

Authorization screen example

Примечание

В этом сценарии мы используем OAuth просто как слой трансляции к базовой модели аутентификации. Мы игнорируем многие аспекты OAuth, такие как scopes.

#Использование существующей установки Passport

Если ваше приложение уже использует Laravel Passport, Laravel MCP должен работать без проблем в вашей существующей установке Passport, но пользовательские scopes в настоящее время не поддерживаются, так как OAuth используется в основном как слой трансляции к базовой модели аутентификации.

Laravel MCP через метод Mcp::oauthRoutes(), описанный выше, добавляет, объявляет и использует единственный scope mcp:use.

#Passport против Sanctum

OAuth2.1 — это документированный механизм аутентификации в спецификации Model Context Protocol и наиболее широко поддерживаемый среди MCP-клиентов. По этой причине мы рекомендуем использовать Passport, когда это возможно.

Если ваше приложение уже использует Sanctum, добавление Passport может быть неудобным. В этом случае мы рекомендуем использовать Sanctum без Passport, пока у вас не появится явная необходимость использовать MCP-клиент, который поддерживает только OAuth.

#Sanctum

Если вы хотите защитить ваш MCP-сервер с помощью Sanctum, просто добавьте middleware аутентификации 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-сервер, назначая любое middleware вашим маршрутам Mcp::web. Ваше пользовательское middleware может вручную проверять заголовок Authorization для аутентификации входящего запроса MCP.

#Авторизация

Вы можете получить доступ к текущему аутентифицированному пользователю через метод $request->user(), что позволяет выполнять проверки авторизации внутри ваших MCP-инструментов и ресурсов:

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

/**
 * Обработать запрос инструмента.
 */
public function handle(Request $request): Response
{
    if (! $request->user()->can('read-weather')) {
        return Response::error('Permission denied.');
    }

    // ...
}

#Тестирование серверов

Вы можете тестировать ваши MCP-серверы с помощью встроенного MCP Inspector или написания модульных тестов.

#MCP Inspector

MCP Inspector — это интерактивный инструмент для тестирования и отладки ваших MCP-серверов. Используйте его для подключения к серверу, проверки аутентификации и тестирования инструментов, ресурсов и подсказок.

Вы можете запустить инспектор для любого зарегистрированного сервера (например, локального сервера с именем "weather"):

php artisan mcp:inspector weather

Эта команда запускает MCP Inspector и предоставляет настройки клиента, которые вы можете скопировать в ваш MCP-клиент для правильной настройки. Если ваш веб-сервер защищён middleware аутентификации, убедитесь, что при подключении включены необходимые заголовки, такие как токен 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.');
});
/**
 * Тест инструмента.
 */
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();