Laravel MCP
- Вступ
- Встановлення
- Створення серверів
- Інструменти
- Підказки
- Ресурси
- Метадані
- Автентифікація
- Авторизація
- Тестування серверів
Вступ
Laravel MCP надає простий та елегантний спосіб для AI-клієнтів взаємодіяти з вашим Laravel застосунком через Model Context Protocol. Він пропонує виразний, гнучкий інтерфейс для визначення серверів, інструментів, ресурсів та підказок, які забезпечують взаємодію з вашим застосунком на основі AI.
Встановлення
Щоб розпочати, встановіть Laravel MCP у свій проєкт за допомогою менеджера пакетів компонувальник:
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 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('Сервер погоди')] #[Version('1.0.0')] #[Instructions('Цей сервер надає інформацію про погоду та прогнози.')] class WeatherServer extends Server { /** * Інструменти, зареєстровані на цьому MCP-сервері. * * @var array<int, class-string<\Laravel\Mcp\Server\Tool>> */ protected array $tools = [ // GetCurrentWeatherTool::class, ]; /** * Ресурси, зареєстровані на цьому MCP-сервері. * * @var array<int, class-string<\Laravel\Mcp\Server\Resource>> */ protected array $resources = [ // WeatherGuidelinesResource::class, ]; /** * Промпти, зареєстровані на цьому MCP-сервері. * * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>> */ protected array $prompts = [ // DescribeWeatherPrompt::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-асистентів, таких як Laravel Boost. Зареєструйте локальний сервер за допомогою методу local:
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::local('weather', WeatherServer::class);
Після реєстрації зазвичай не потрібно вручну запускати команду Artisan mcp:start. Натомість налаштуйте свого MCP-клієнта (AI-агента) для запуску сервера або скористайтеся MCP Inspector.
Інструменти
Інструменти дозволяють вашому серверу відкривати функціональність, до якої можуть звертатися 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('Отримує поточний прогноз погоди для вказаної локації.')] class CurrentWeatherTool extends Tool { /** * Обробити запит до інструмента. */ public function handle(Request $request): Response { $location = $request->get('location'); // Отримати погоду... return Response::text('Погода така...'); } /** * Отримати схему вхідних даних інструмента. * * @return array<string, \Illuminate\JsonSchema\Types\Type> */ public function schema(JsonSchema $schema): array { return [ 'location' => $schema->string() ->description('Локація, для якої потрібно отримати погоду.') ->required(), ]; } }
Створення інструментів
Щоб створити інструмент, виконайте 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:
use Laravel\Mcp\Server\Attributes\Name; use Laravel\Mcp\Server\Attributes\Title; #[Name('get-optimistic-weather')] #[Title('Отримати оптимістичний прогноз погоди')] class CurrentWeatherTool extends Tool { // ... }
Опис інструментів не генерується автоматично. Ви завжди повинні вказувати змістовний опис, використовуючи атрибут Description:
use Laravel\Mcp\Server\Attributes\Description; #[Description('Отримує поточний прогноз погоди для вказаної локації.')] class CurrentWeatherTool extends Tool { // }
Опис є важливою частиною метаданих інструмента, оскільки він допомагає AI-моделям зрозуміти, коли і як ефективно використовувати цей інструмент.
Схеми введення інструментів
Інструменти можуть визначати схеми введення, щоб вказати, які аргументи вони приймають від AI-клієнтів. Використовуйте конструктор Illuminate\Contracts\JsonSchema\JsonSchema Laravel для визначення вимог до введення вашого інструменту:
<?php namespace App\Mcp\Tools; use Illuminate\Contracts\JsonSchema\JsonSchema; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * Отримати схему вхідних даних інструмента. * * @return array<string, \Illuminate\JsonSchema\Types\Type> */ public function schema(JsonSchema $schema): array { return [ 'location' => $schema->string() ->description('Локація, для якої потрібно отримати погоду.') ->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 { /** * Отримати схему вихідних даних інструмента. * * @return array<string, \Illuminate\JsonSchema\Types\Type> */ public function outputSchema(JsonSchema $schema): array { return [ 'temperature' => $schema->number() ->description('Температура в Цельсіях') ->required(), 'conditions' => $schema->string() ->description('Погодні умови') ->required(), 'humidity' => $schema->integer() ->description('Відсоток вологості') ->required(), ]; } }
Валідація аргументів інструменту
Визначення 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' => 'Ви маєте вказати локацію, для якої потрібно отримати погоду. Наприклад, "New York City" або "Tokyo".', 'units.in' => 'Ви маєте вказати для одиниць вимірювання або "celsius", або "fahrenheit".', ]);
Ін'єкція залежностей інструментів
Laravel Сервіс-контейнер використовується для вирішення всіх інструментів. В результаті ви можете вказати будь-які залежності, які потрібні вашому інструменту, у його конструкторі. Оголошені залежності будуть автоматично вирішені та впроваджені в екземпляр інструменту:
<?php namespace App\Mcp\Tools; use App\Repositories\WeatherRepository; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * Створити новий екземпляр інструмента. */ public function __construct( protected WeatherRepository $weather, ) {} // ... }
Окрім ін'єкції через конструктор, ви також можете вказати залежності через type-hint у методі 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 { /** * Обробити запит до інструмента. */ public function handle(Request $request, WeatherRepository $weather): Response { $location = $request->get('location'); $forecast = $weather->getForecastFor($location); // ... } }
Анотації інструментів
Ви можете розширити свої інструменти за допомогою анотацій, щоб надати додаткові метадані AI-клієнтам. Ці анотації допомагають AI-моделям зрозуміти поведінку та можливості інструменту. Анотації додаються до інструментів через атрибути:
<?php
namespace App\Mcp\Tools;
use Laravel\Mcp\Server\Tools\Annotations\IsIdempotent;
use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly;
use Laravel\Mcp\Server\Tool;
#[IsIdempotent]
#[IsReadOnly]
class CurrentWeatherTool extends Tool
{
//
}
Доступні анотації включають:
| Annotation | Type | Description |
|---|---|---|
#[IsReadOnly] |
boolean | Indicates the tool does not modify its environment. |
#[IsDestructive] |
boolean | Indicates the tool may perform destructive updates (only meaningful when not read-only). |
#[IsIdempotent] |
boolean | Indicates repeated calls with same arguments have no additional effect (when not read-only). |
#[IsOpenWorld] |
boolean | Indicates the tool may interact with external entities. |
Значення анотацій можна явно встановлювати за допомогою булевих аргументів:
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 { /** * Визначити, чи слід зареєструвати інструмент. */ 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('Зведення погоди: сонячно, 72°F'); }
Щоб вказати, що під час виконання інструменту сталася помилка, використовуйте метод error:
return Response::error('Не вдалося отримати дані про погоду. Будь ласка, спробуйте ще раз.');
Щоб повернути зображення або аудіо контент, використовуйте методи 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');
Ви також можете завантажувати зображення та аудіо безпосередньо з диска файлової системи Laravel за допомогою методу fromStorage. 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; /** * Обробити запит до інструмента. * * @return array<int, \Laravel\Mcp\Response> */ public function handle(Request $request): array { // ... return [ Response::text('Зведення погоди: сонячно, 72°F'), Response::text('**Detailed Forecast**\n- Morning: 65°F\n- Afternoon: 78°F\n- Evening: 70°F') ]; }
Структуровані відповіді
Інструменти можуть повертати структурований вміст за допомогою методу structured. Це забезпечує дані, які можна аналізувати, для AI-клієнтів, зберігаючи зворотну сумісність із текстовим представленням у форматі JSON:
return Response::structured([ 'temperature' => 22.5, 'conditions' => 'Мінлива хмарність', 'humidity' => 65, ]);
Якщо вам потрібно надати власний текст разом зі структурованим вмістом, використовуйте метод withStructuredContent у фабриці відповідей:
return Response::make( Response::text('Погода 22.5°C і сонячно') )->withStructuredContent([ 'temperature' => 22.5, 'conditions' => 'Сонячно', ]);
Потокові відповіді
Для тривалих операцій або потокової передачі даних у реальному часі інструменти можуть повертати генератор з їхнього методу 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, ]; }
Назва підказки, Заголовок та Опис
За замовчуванням ім'я та заголовок prompt отримуються з імені класу. Наприклад, DescribeWeatherPrompt матиме ім'я describe-weather і заголовок Describe Weather Prompt. Ви можете налаштувати ці значення за допомогою атрибутів Name та Title:
use Laravel\Mcp\Server\Attributes\Name; use Laravel\Mcp\Server\Attributes\Title; #[Name('weather-assistant')] #[Title('Промпт помічника погоди')] class DescribeWeatherPrompt extends Prompt { // ... }
Опис підказки не генерується автоматично. Ви завжди повинні вказувати змістовний опис, використовуючи атрибут Description:
use Laravel\Mcp\Server\Attributes\Description; #[Description('Генерує пояснення погоди природною мовою для вказаної локації.')] 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 { /** * Отримати аргументи промпту. * * @return array<int, \Laravel\Mcp\Server\Prompts\Argument> */ public function arguments(): array { return [ new Argument( name: 'tone', description: 'Тон, який слід використовувати в описі погоди (наприклад, формальний, неформальний, гумористичний).', 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.*' => 'Ви маєте вказати тон для опису погоди. Прикладами можуть бути "formal", "casual" або "humorous".', ]);
Впровадження залежностей у підказках
Laravel Сервіс-контейнер використовується для вирішення всіх підказок. В результаті ви можете вказати тип будь-яких залежностей, які може знадобитися вашій підказці у її конструкторі. Оголошені залежності будуть автоматично вирішені та впроваджені у екземпляр підказки:
<?php namespace App\Mcp\Prompts; use App\Repositories\WeatherRepository; use Laravel\Mcp\Server\Prompt; class DescribeWeatherPrompt extends Prompt { /** * Створити новий екземпляр промпту. */ public function __construct( protected WeatherRepository $weather, ) {} // }
Окрім ін'єкції через конструктор, ви також можете вказати залежності через type-hint у методі handle вашого prompt. Сервіс-контейнер автоматично вирішить та впровадить залежності під час виклику методу:
<?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 = "Ви — корисний помічник з питань погоди. Будь ласка, надайте опис погоди в тоні {$tone}."; $userMessage = "Яка зараз погода в 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:
use Laravel\Mcp\Server\Attributes\Name; use Laravel\Mcp\Server\Attributes\Title; #[Name('weather-api-docs')] #[Title('Документація API погоди')] class WeatherGuidelinesResource extends Resource { // ... }
Опис ресурсів не генерується автоматично. Ви завжди повинні надавати змістовний опис, використовуючи атрибут Description:
use Laravel\Mcp\Server\Attributes\Description; #[Description('Повні рекомендації щодо використання 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('Отримати доступ до файлів користувача за ID')] #[MimeType('text/plain')] class UserFileResource extends Resource implements HasUriTemplate { /** * Отримати шаблон URI для цього ресурсу. */ 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($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 { // Отримати доступ до витягнутої змінної $userId = $request->get('userId'); // тримати доступ до повного URI за потреби $uri = $request->uri(); // Отримати профіль користувача... return Response::text("Профіль користувача {$userId}"); } }
Об'єкт Request надає як витягнуті змінні, так і оригінальний URI, який було запрошено, забезпечуючи повний контекст для обробки запиту до ресурсу.
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\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 { /** * Обробити запит до ресурсу. */ 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 { /** * Створити новий екземпляр ресурсу. */ public function __construct( protected WeatherRepository $weather, ) {} // ... }
Окрім ін'єкції через конструктор, ви також можете вказати залежності через type-hint у методі 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 { /** * Обробити запит до ресурсу. */ public function handle(WeatherRepository $weather): Response { $guidelines = $weather->guidelines(); return Response::text($guidelines); } }
Анотації ресурсів
Ви можете розширити свої ресурси за допомогою анотацій, щоб надати додаткові метадані 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
{
//
}
Доступні анотації включають:
| Annotation | Type | Description |
|---|---|---|
#[Audience] |
Role or array | Specifies the intended audience (Role::User, Role::Assistant, or both). |
#[Priority] |
float | A numerical score between 0.0 and 1.0 indicating resource importance. |
#[LastModified] |
string | An ISO 8601 timestamp showing when the resource was last updated. |
Умовна реєстрація ресурсів
Ви можете умовно реєструвати ресурси під час виконання, реалізувавши метод 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-тип буде визначено налаштованим 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('Не вдалося отримати дані про погоду для вказаної локації.');
Метадані
Laravel MCP також підтримує поле _meta, як визначено у специфікації MCP, яке є обов'язковим для деяких клієнтів або інтеграцій MCP. Метадані можуть застосовуватися до всіх примітивів MCP, включаючи інструменти, ресурси та підказки, а також їх відповіді.
Ви можете додати метадані до окремого вмісту відповіді за допомогою методу withMeta:
use Laravel\Mcp\Request; use Laravel\Mcp\Response; /** * Обробити запит до інструмента. */ public function handle(Request $request): Response { return Response::text('Сонячна погода.') ->withMeta(['source' => 'weather-api', 'cached' => true]); }
Для метаданих на рівні результату, які застосовуються до всього конверта відповіді, обгорніть ваші відповіді за допомогою Response::make і викликайте withMeta на повернутому екземплярі фабрики відповідей:
use Laravel\Mcp\Request; use Laravel\Mcp\Response; use Laravel\Mcp\ResponseFactory; /** * Обробити запит до інструмента. */ public function handle(Request $request): ResponseFactory { return Response::make( Response::text('Сонячна погода.') )->withMeta(['request_id' => '12345']); }
Щоб додати метадані до інструменту, ресурсу або самого запиту, визначте властивість $meta у класі:
use Laravel\Mcp\Server\Attributes\Description; use Laravel\Mcp\Server\Tool; #[Description('Отримує поточний прогноз погоди.')] class CurrentWeatherTool extends Tool { protected ?array $meta = [ 'version' => '2.0', 'author' => 'Weather Team', ]; // ... }
Автентифікація
Так само, як і маршрути, ви можете автентифікувати веб-сервери MCP за допомогою middleware. Додавання автентифікації до вашого MCP-сервера вимагатиме від користувача автентифікації перед використанням будь-якої можливості сервера.
Існує два способи автентифікації доступу до вашого MCP-сервера: проста автентифікація на основі токенів через Laravel Sanctum або будь-який токен, який передається через HTTP-заголовок Authorization. Або ви можете автентифікуватися через OAuth, використовуючи Laravel Passport.
OAuth 2.1
Найбільш надійний спосіб захистити ваші MCP сервери на основі вебу — це використання OAuth разом із Laravel Passport.
Під час автентифікації вашого MCP-сервера через OAuth, викликайте метод Mcp::oauthRoutes у вашому файлі routes/ai.php, щоб зареєструвати необхідні маршрути для виявлення OAuth2 та реєстрації клієнта. Потім застосуйте middleware Passport auth:api до вашого маршруту 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, щоб додати Passport до вашого застосунку. Ви повинні мати модель OAuthenticatable, новий guard автентифікації та ключі passport перед тим, як продовжити.
Далі слід опублікувати надане Passport представлення авторизації Laravel MCP:
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, таких як області.
Використання наявної інсталяції Passport
Якщо ваш застосунок вже використовує Laravel Passport, Laravel MCP повинен працювати безперешкодно у вашій існуючій інсталяції Passport, але власні області наразі не підтримуються, оскільки OAuth в основному використовується як шар трансляції до базової моделі, що може бути автентифікована.
Laravel MCP, за допомогою методу Mcp::oauthRoutes, розглянутого вище, додає, рекламує та використовує єдиний скоуп mcp:use.
Passport vs. 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('Доступ заборонено.'); } // ... }
Тестування серверів
Ви можете протестувати свої MCP-сервери за допомогою вбудованого MCP Inspector або написавши модульні тести.
Інспектор MCP
MCP Inspector — це інтерактивний інструмент для тестування та налагодження ваших MCP серверів. Використовуйте його для підключення до вашого сервера, перевірки автентифікації, а також для випробування інструментів, ресурсів і підказок.
Ви можете запустити інспектор для будь-якого зареєстрованого сервера:
# Web server...
php artisan mcp:inspector mcp/weather
# Local server named "weather"...
php artisan mcp:inspector weather
Ця команда запускає MCP Inspector і надає налаштування клієнта, які ви можете скопіювати у свій MCP клієнт, щоб переконатися, що все налаштовано правильно. Якщо ваш веб-сервер захищений аутентифікаційним middleware, переконайтеся, що ви додаєте необхідні заголовки, такі як Authorization bearer token, під час підключення.
Юніт-тести
Ви можете писати модульні тести для ваших MCP серверів, інструментів, ресурсів та підказок.
Щоб почати, створіть новий тестовий випадок і викличте потрібний примітив на сервері, який його реєструє. Наприклад, щоб протестувати інструмент на WeatherServer:
test('tool', function () { $response = WeatherServer::tool(CurrentWeatherTool::class, [ 'location' => 'New York City', 'units' => 'fahrenheit', ]); $response ->assertOk() ->assertSee('Поточна погода в New York City — 72°F і сонячно.'); });
/** * Протестувати інструмент. */ public function test_tool(): void { $response = WeatherServer::tool(CurrentWeatherTool::class, [ 'location' => 'New York City', 'units' => 'fahrenheit', ]); $response ->assertOk() ->assertSee('Поточна погода в New York City — 72°F і сонячно.'); }
Аналогічно, ви можете тестувати підказки та ресурси:
$response = WeatherServer::prompt(...);
$response = WeatherServer::resource(...);
Ви також можете діяти як автентифікований користувач, додавши метод actingAs перед викликом примітива:
$response = WeatherServer::actingAs($user)->tool(...);
Після отримання відповіді ви можете використовувати різні методи ствердження для перевірки вмісту та статусу відповіді.
Ви можете перевірити, що відповідь є успішною, використовуючи метод assertOk. Це перевіряє, що у відповіді немає жодних помилок:
$response->assertOk();
Ви можете перевірити, що відповідь містить певний текст, за допомогою методу assertSee:
$response->assertSee('Поточна погода в New York City — 72°F і сонячно.');
Ви можете перевірити, що відповідь містить помилку, використовуючи метод assertHasErrors:
$response->assertHasErrors(); $response->assertHasErrors([ 'Щось пішло не так.', ]);
Ви можете переконатися, що відповідь не містить помилки, використовуючи метод assertHasNoErrors:
$response->assertHasNoErrors();
Ви можете стверджувати, що відповідь містить певні метадані, використовуючи методи assertName(), assertTitle() та assertDescription():
$response->assertName('current-weather'); $response->assertTitle('Інструмент поточної погоди'); $response->assertDescription('Отримує поточний прогноз погоди для вказаної локації.');
Ви можете перевірити, що сповіщення були надіслані, використовуючи методи 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();
