- Введение
- Установка
- Создание серверов
- Инструменты
- Подсказки
- Ресурсы
- Аутентификация
- Авторизация
- Тестирование серверов
#Введение
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-агента.
В этом сценарии мы используем 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();