Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас

Laravel MCP

Вступ

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

Встановлення

Для початку встановіть Laravel MCP у свій проєкт за допомогою менеджера пакетів Composer:

composer require laravel/mcp

Публікація маршрутів

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

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

Ця команда створює файл routes/ai.php у каталозі routes вашого застосунку, який ви використовуватимете для реєстрації своїх MCP-серверів.

Створення серверів

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

php artisan make:mcp-server WeatherServer

Ця команда створить новий клас сервера в каталозі app/Mcp/Servers. Згенерований клас сервера розширює базовий клас Laravel\Mcp\Server з Laravel MCP і надає атрибути та властивості для налаштування сервера й реєстрації інструментів, ресурсів і промптів:

<?php

namespace App\Mcp\Servers;

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

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

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

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

Реєстрація сервера

Щойно ви створили сервер, вам потрібно зареєструвати його у файлі routes/ai.php, щоб зробити його доступним. Laravel MCP пропонує два методи реєстрації серверів: 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']);

Локальні сервери

Локальні сервери працюють як артизан-команди - ідеально для створення локальних інтеграцій з AI-асистентами, як-от Laravel Boost. Зареєструйте локальний сервер методом local:

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

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

Щойно сервер зареєстровано, вам зазвичай не потрібно вручну запускати артизан-команду 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('Fetches the current weather forecast for a specified location.')]
class CurrentWeatherTool extends Tool
{
    /**
     * Handle the tool request.
     */
    public function handle(Request $request): Response
    {
        $location = $request->get('location');

        // Get weather...

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

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

Створення інструментів

Щоб створити інструмент, виконайте артизан-команду make:mcp-tool:

php artisan make:mcp-tool CurrentWeatherTool

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

<?php

namespace App\Mcp\Servers;

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

class WeatherServer extends Server
{
    /**
     * The tools registered with this MCP server.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Tool>>
     */
    protected array $tools = [
        CurrentWeatherTool::class,
    ];
}

Ім'я, заголовок і опис інструмента

За замовчуванням ім'я та заголовок інструмента виводяться з імені класу. Наприклад, CurrentWeatherTool матиме ім'я current-weather і заголовок Current Weather Tool. Ви можете змінити ці значення атрибутами Name і Title:

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

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

Описи інструментів не генеруються автоматично. Вам слід завжди надавати змістовний опис через атрибут Description:

use Laravel\Mcp\Server\Attributes\Description;

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

Опис - критично важлива частина метаданих інструмента, адже він допомагає AI-моделям зрозуміти, коли і як ефективно використовувати інструмент.

Вхідні схеми інструментів

Інструменти можуть визначати вхідні схеми, щоб указати, які аргументи вони приймають від AI-клієнтів. Скористайтеся білдером Illuminate\Contracts\JsonSchema\JsonSchema з Laravel, щоб визначити вимоги до вхідних даних вашого інструмента:

<?php

namespace App\Mcp\Tools;

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

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

            'units' => $schema->string()
                ->enum(['celsius', 'fahrenheit'])
                ->description('The temperature units to use.')
                ->default('celsius'),
        ];
    }
}

Вихідні схеми інструментів

Інструменти можуть визначати вихідні схеми, щоб указати структуру своїх відповідей. Це дає кращу інтеграцію з AI-клієнтами, яким потрібні придатні до розбору результати інструментів. Скористайтеся методом outputSchema, щоб визначити структуру виводу вашого інструмента:

<?php

namespace App\Mcp\Tools;

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

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

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

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

Валідація аргументів інструмента

Визначення JSON 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
{
    /**
     * Handle the tool request.
     */
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'location' => 'required|string|max:100',
            'units' => 'in:celsius,fahrenheit',
        ]);

        // Fetch weather data using the validated arguments...
    }
}

У разі невдалої валідації AI-клієнти діятимуть на основі наданих вами повідомлень про помилки. Тому критично важливо надавати зрозумілі повідомлення, з яких випливає, що робити:

$validated = $request->validate([
    'location' => ['required','string','max:100'],
    'units' => 'in:celsius,fahrenheit',
],[
    'location.required' => 'You must specify a location to get the weather for. For example, "New York City" or "Tokyo".',
    'units.in' => 'You must specify either "celsius" or "fahrenheit" for the units.',
]);

Впровадження залежностей в інструменти

Сервіс-контейнер Laravel використовується для створення всіх інструментів. Тому ви можете вказати типи будь-яких залежностей, потрібних вашому інструменту, у його конструкторі. Оголошені залежності будуть автоматично отримані й впроваджені в екземпляр інструмента:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Create a new tool instance.
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    // ...
}

Окрім впровадження через конструктор, ви також можете вказати типи залежностей у методі handle() свого інструмента. Сервіс-контейнер автоматично отримає й впровадить залежності під час виклику методу:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Handle the tool request.
     */
    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $location = $request->get('location');

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

        // ...
    }
}

Анотації інструментів

Ви можете збагатити свої інструменти анотаціями, щоб надати 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 Вказує, що інструмент не змінює своє середовище.
#[IsDestructive] boolean Вказує, що інструмент може виконувати руйнівні оновлення (має сенс лише коли не read-only).
#[IsIdempotent] boolean Вказує, що повторні виклики з тими самими аргументами не мають додаткового ефекту (коли не read-only).
#[IsOpenWorld] boolean Вказує, що інструмент може взаємодіяти із зовнішніми сутностями.

Значення анотацій можна задати явно булевими аргументами:

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

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

Умовна реєстрація інструментів

Ви можете умовно реєструвати інструменти під час виконання, реалізувавши метод shouldRegister у класі інструмента. Цей метод дозволяє визначити, чи має інструмент бути доступним, залежно від стану застосунку, конфігурації чи параметрів запиту:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Determine if the tool should be registered.
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

Коли метод shouldRegister інструмента повертає false, той не з'явиться у списку доступних інструментів і не може бути викликаний AI-клієнтами.

Відповіді інструментів

Інструменти мають повертати екземпляр Laravel\Mcp\Response. Клас Response надає кілька зручних методів для створення різних типів відповідей:

Для простих текстових відповідей скористайтеся методом text:

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

/**
 * Handle the tool request.
 */
public function handle(Request $request): Response
{
    // ...

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

Щоб позначити, що під час виконання інструмента сталася помилка, скористайтеся методом error:

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

Щоб повернути зображення чи аудіо, скористайтеся методами image та audio:

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

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

Ви також можете завантажити зображення й аудіо безпосередньо з диска файлової системи 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;

/**
 * Handle the tool request.
 *
 * @return array<int, \Laravel\Mcp\Response>
 */
public function handle(Request $request): array
{
    // ...

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

Структуровані відповіді

Інструменти можуть повертати структурований вміст методом structured. Це дає AI-клієнтам придатні до розбору дані, водночас зберігаючи зворотну сумісність із текстовим представленням у форматі JSON:

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

Якщо вам потрібно надати власний текст поряд зі структурованим вмістом, скористайтеся методом withStructuredContent на фабриці відповідей:

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

Потокові відповіді

Для довготривалих операцій чи потокової передачі даних у реальному часі інструменти можуть повертати генератор зі свого методу handle. Це дозволяє надсилати клієнту проміжні оновлення перед фінальною відповіддю:

<?php

namespace App\Mcp\Tools;

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

class CurrentWeatherTool extends Tool
{
    /**
     * Handle the tool request.
     *
     * @return \Generator<int, \Laravel\Mcp\Response>
     */
    public function handle(Request $request): Generator
    {
        $locations = $request->array('locations');

        foreach ($locations as $index => $location) {
            yield Response::notification('processing/progress', [
                'current' => $index + 1,
                'total' => count($locations),
                'location' => $location,
            ]);

            yield Response::text($this->forecastFor($location));
        }
    }
}

Використовуючи вебсервери, потокові відповіді автоматично відкривають SSE-потік (Server-Sent Events), надсилаючи кожне видане повідомлення клієнту як подію.

Промпти

Промпти дозволяють вашому серверу ділитися багаторазовими шаблонами промптів, які AI-клієнти можуть використовувати для взаємодії з мовними моделями. Вони дають стандартизований спосіб структурувати типові запити й взаємодії.

Створення промптів

Щоб створити промпт, виконайте артизан-команду 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
{
    /**
     * The prompts registered with this MCP server.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>>
     */
    protected array $prompts = [
        DescribeWeatherPrompt::class,
    ];
}

Ім'я, заголовок і опис промпта

За замовчуванням ім'я та заголовок промпта виводяться з імені класу. Наприклад, DescribeWeatherPrompt матиме ім'я describe-weather і заголовок Describe Weather Prompt. Ви можете змінити ці значення атрибутами Name і Title:

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

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

Описи промптів не генеруються автоматично. Вам слід завжди надавати змістовний опис через атрибут Description:

use Laravel\Mcp\Server\Attributes\Description;

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

Опис - критично важлива частина метаданих промпта, адже він допомагає AI-моделям зрозуміти, коли і як найкраще скористатися промптом.

Аргументи промпта

Промпти можуть визначати аргументи, які дозволяють AI-клієнтам налаштовувати шаблон промпта конкретними значеннями. Скористайтеся методом arguments, щоб визначити, які аргументи приймає ваш промпт:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Get the prompt's arguments.
     *
     * @return array<int, \Laravel\Mcp\Server\Prompts\Argument>
     */
    public function arguments(): array
    {
        return [
            new Argument(
                name: 'tone',
                description: 'The tone to use in the weather description (e.g., formal, casual, humorous).',
                required: true,
            ),
        ];
    }
}

Валідація аргументів промпта

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

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

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Handle the prompt request.
     */
    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'tone' => 'required|string|max:50',
        ]);

        $tone = $validated['tone'];

        // Generate the prompt response using the given tone...
    }
}

У разі невдалої валідації AI-клієнти діятимуть на основі наданих вами повідомлень про помилки. Тому критично важливо надавати зрозумілі повідомлення, з яких випливає, що робити:

$validated = $request->validate([
    'tone' => ['required','string','max:50'],
],[
    'tone.*' => 'You must specify a tone for the weather description. Examples include "formal", "casual", or "humorous".',
]);

Впровадження залежностей у промпти

Сервіс-контейнер Laravel використовується для створення всіх промптів. Тому ви можете вказати типи будь-яких залежностей, потрібних вашому промпту, у його конструкторі. Оголошені залежності будуть автоматично отримані й впроваджені в екземпляр промпта:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Create a new prompt instance.
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    //
}

Окрім впровадження через конструктор, ви також можете вказати типи залежностей у методі handle свого промпта. Сервіс-контейнер автоматично отримає й впровадить залежності під час виклику методу:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Handle the prompt request.
     */
    public function handle(Request $request, WeatherRepository $weather): Response
    {
        $isAvailable = $weather->isServiceAvailable();

        // ...
    }
}

Умовна реєстрація промптів

Ви можете умовно реєструвати промпти під час виконання, реалізувавши метод shouldRegister у класі промпта. Цей метод дозволяє визначити, чи має промпт бути доступним, залежно від стану застосунку, конфігурації чи параметрів запиту:

<?php

namespace App\Mcp\Prompts;

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

class CurrentWeatherPrompt extends Prompt
{
    /**
     * Determine if the prompt should be registered.
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

Коли метод shouldRegister промпта повертає false, той не з'явиться у списку доступних промптів і не може бути викликаний AI-клієнтами.

Відповіді промптів

Промпти можуть повертати один Laravel\Mcp\Response або ітерований набір екземплярів Laravel\Mcp\Response. Ці відповіді інкапсулюють вміст, який буде надіслано AI-клієнту:

<?php

namespace App\Mcp\Prompts;

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

class DescribeWeatherPrompt extends Prompt
{
    /**
     * Handle the prompt request.
     *
     * @return array<int, \Laravel\Mcp\Response>
     */
    public function handle(Request $request): array
    {
        $tone = $request->string('tone');

        $systemMessage = "You are a helpful weather assistant. Please provide a weather description in a {$tone} tone.";

        $userMessage = "What is the current weather like in New York City?";

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

Ви можете скористатися методом asAssistant(), щоб позначити, що повідомлення-відповідь слід вважати таким, що надійшло від AI-асистента, тоді як звичайні повідомлення вважаються введенням користувача.

Ресурси

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

Створення ресурсів

Щоб створити ресурс, виконайте артизан-команду 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
{
    /**
     * The resources registered with this MCP server.
     *
     * @var array<int, class-string<\Laravel\Mcp\Server\Resource>>
     */
    protected array $resources = [
        WeatherGuidelinesResource::class,
    ];
}

Ім'я, заголовок і опис ресурсу

За замовчуванням ім'я та заголовок ресурсу виводяться з імені класу. Наприклад, WeatherGuidelinesResource матиме ім'я weather-guidelines і заголовок Weather Guidelines Resource. Ви можете змінити ці значення атрибутами Name і Title:

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

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

Описи ресурсів не генеруються автоматично. Вам слід завжди надавати змістовний опис через атрибут Description:

use Laravel\Mcp\Server\Attributes\Description;

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

Опис - критично важлива частина метаданих ресурсу, адже він допомагає AI-моделям зрозуміти, коли і як ефективно використовувати ресурс.

Шаблони ресурсів

Шаблони ресурсів дозволяють вашому серверу надавати динамічні ресурси, що відповідають URI-шаблонам зі змінними. Замість визначати статичний URI для кожного ресурсу, ви можете створити один ресурс, який обробляє кілька URI за шаблоном.

Створення шаблонів ресурсів

Щоб створити шаблон ресурсу, реалізуйте інтерфейс HasUriTemplate у класі свого ресурсу й визначте метод uriTemplate, що повертає екземпляр UriTemplate:

<?php

namespace App\Mcp\Resources;

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

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

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

        // Fetch and return the file content...

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

Коли ресурс реалізує інтерфейс HasUriTemplate, його буде зареєстровано як шаблон ресурсу, а не як статичний ресурс. AI-клієнти зможуть запитувати ресурси за URI, що відповідають шаблону, а змінні з URI будуть автоматично витягнуті й доступні в методі handle вашого ресурсу.

Синтаксис URI-шаблонів

URI-шаблони використовують плейсхолдери у фігурних дужках, щоб визначити змінні сегменти URI:

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

Доступ до змінних шаблону

Коли URI відповідає вашому шаблону ресурсу, витягнуті змінні автоматично додаються до запиту, і до них можна звернутися методом get:

<?php

namespace App\Mcp\Resources;

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

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

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

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

        // Fetch user profile...

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

Об'єкт Request надає і витягнуті змінні, і початковий URI, який було запитано, даючи вам повний контекст для обробки запиту ресурсу.

URI та MIME-тип ресурсу

Кожен ресурс ідентифікується унікальним URI і має пов'язаний 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
{
    /**
     * Handle the resource request.
     */
    public function handle(Request $request): Response
    {
        // ...
    }
}

Впровадження залежностей у ресурси

Сервіс-контейнер Laravel використовується для створення всіх ресурсів. Тому ви можете вказати типи будь-яких залежностей, потрібних вашому ресурсу, у його конструкторі. Оголошені залежності будуть автоматично отримані й впроваджені в екземпляр ресурсу:

<?php

namespace App\Mcp\Resources;

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

class WeatherGuidelinesResource extends Resource
{
    /**
     * Create a new resource instance.
     */
    public function __construct(
        protected WeatherRepository $weather,
    ) {}

    // ...
}

Окрім впровадження через конструктор, ви також можете вказати типи залежностей у методі handle свого ресурсу. Сервіс-контейнер автоматично отримає й впровадить залежності під час виклику методу:

<?php

namespace App\Mcp\Resources;

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

class WeatherGuidelinesResource extends Resource
{
    /**
     * Handle the resource request.
     */
    public function handle(WeatherRepository $weather): Response
    {
        $guidelines = $weather->guidelines();

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

Анотації ресурсів

Ви можете збагатити свої ресурси анотаціями, щоб надати 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 Вказує цільову аудиторію (Role::User, Role::Assistant або обидві).
#[Priority] float Числова оцінка від 0.0 до 1.0, що вказує на важливість ресурсу.
#[LastModified] string Позначка часу ISO 8601, що показує, коли ресурс востаннє оновлювався.

Умовна реєстрація ресурсів

Ви можете умовно реєструвати ресурси під час виконання, реалізувавши метод shouldRegister у класі ресурсу. Цей метод дозволяє визначити, чи має ресурс бути доступним, залежно від стану застосунку, конфігурації чи параметрів запиту:

<?php

namespace App\Mcp\Resources;

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

class WeatherGuidelinesResource extends Resource
{
    /**
     * Determine if the resource should be registered.
     */
    public function shouldRegister(Request $request): bool
    {
        return $request?->user()?->subscribed() ?? false;
    }
}

Коли метод shouldRegister ресурсу повертає false, той не з'явиться у списку доступних ресурсів і буде недоступним для AI-клієнтів.

Відповіді ресурсів

Ресурси мають повертати екземпляр Laravel\Mcp\Response. Клас Response надає кілька зручних методів для створення різних типів відповідей:

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

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

/**
 * Handle the resource request.
 */
public function handle(Request $request): Response
{
    // ...

    return Response::text($weatherData);
}

Щоб повернути посилання на ресурс, скористайтеся методом resourceLink, указавши URI та ім'я. На відміну від вбудованого ресурсу, посилання на ресурс повертає вказівник URI, який AI-клієнт завантажує самостійно:

return Response::resourceLink(
    uri: 'file:///data/report.json',
    name: 'monthly-report',
    mimeType: 'application/json',
);

Ви також можете передати зареєстрований клас чи екземпляр ресурсу, який автоматично успадкує URI, ім'я, заголовок, опис і MIME-тип ресурсу:

return Response::resourceLink(new WeatherForecastResource);

Blob-відповіді

Щоб повернути blob-вміст, скористайтеся методом blob, передавши цей вміст:

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

Повертаючи blob-вміст, MIME-тип буде визначено налаштованим MIME-типом вашого ресурсу:

<?php

namespace App\Mcp\Resources;

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

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

Відповіді з помилкою

Щоб позначити, що під час отримання ресурсу сталася помилка, скористайтеся методом error():

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

Застосунки

Laravel MCP підтримує MCP Apps - розширення Model Context Protocol, яке дозволяє інструментам рендерити інтерактивні HTML-застосунки всередині ізольованих iframe у підтримуваних хостах. Це дає змогу створювати панелі, форми, візуалізації та інші багаті інтерфейси, що виходять за межі простих текстових відповідей.

MCP-застосунок складається з двох частин, які працюють разом:

  • Ресурс застосунку, який повертає самодостатній HTML вашого застосунку.
  • Інструмент, пов'язаний з ресурсом застосунку через атрибут #[RendersApp]. Коли інструмент викликається, хост завантажує й рендерить пов'язаний ресурс.

Створення ресурсів застосунку

Створити ресурс застосунку можна артизан-командою make:mcp-app-resource:

php artisan make:mcp-app-resource WeatherDashboardApp

Ця команда створює два файли: PHP-клас у app/Mcp/Resources і Blade-представлення в resources/views/mcp. Ім'я представлення виводиться з імені класу автоматично. Наприклад, WeatherDashboardApp відповідає mcp.weather-dashboard-app:

<?php

namespace App\Mcp\Resources;

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

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

AppResource розширює базовий клас Resource і автоматично налаштовує схему URI ui:// та MIME-тип text/html;profile=mcp-app, які вимагає специфікація MCP Apps. Як і будь-який інший ресурс, ви маєте зареєструвати його в масиві $resources свого сервера.

Згенероване Blade-представлення використовує компонент <x-mcp::app>, який рендерить повний HTML-документ із вбудованим клієнтським MCP SDK, готовим до використання:

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

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

Глобальна функція createMcpApp надається вбудованим SDK і бере на себе підключення iframe до сервера, застосування теми хоста та надання хелперів на кшталт callServerTool, sendMessage, openLink і колбеків подій. Повний клієнтський API дивіться в специфікації MCP Apps.

Рендеринг застосунків з інструментів

Щоб показати ресурс застосунку, пов'яжіть з ним інструмент через атрибут #[RendersApp]. Коли інструмент викликається, Laravel MCP додає URI ресурсу до метаданих інструмента, щоб хост міг відрендерити застосунок в ізольованому iframe:

<?php

namespace App\Mcp\Tools;

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

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

Laravel MCP автоматично оголошує можливість io.modelcontextprotocol/ui, щойно зареєстровано будь-який AppResource, тож додаткова конфігурація сервера не потрібна.

Видимість інструментів застосунку

Кожен інструмент з #[RendersApp] може обмежити, хто може його викликати, через аргумент visibility. Це корисно, щоб надавати приватні інструменти лише для застосунку, які UI викликає для завантаження чи оновлення даних, не роблячи їх видимими для моделі:

use Laravel\Mcp\Server\Attributes\RendersApp;
use Laravel\Mcp\Server\Ui\Enums\Visibility;

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

Enum Visibility має два випадки, Model і App, і за замовчуванням охоплює обидва. Використовуйте [Visibility::App] для бекенд-дій, які UI викликає безпосередньо, або [Visibility::Model], щоб зробити інструмент недоступним для UI.

Конфігурація застосунку

Атрибут #[AppMeta] на ресурсі вашого застосунку налаштовує Content Security Policy для iframe, дозволи браузера та будь-які бібліотечні скрипти, які слід додати до <head> представлення:

use Laravel\Mcp\Server\Attributes\AppMeta;
use Laravel\Mcp\Server\Ui\Enums\Library;
use Laravel\Mcp\Server\Ui\Enums\Permission;

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

Enum Library містить заздалегідь налаштовані CDN-скрипти для поширених фронтенд-бібліотек, як-от Library::Tailwind і Library::Alpine, і їхні CDN-джерела автоматично додаються до CSP. Enum Permission охоплює дозволи браузера, як-от Camera, Microphone, Geolocation та ClipboardWrite.

Для обчислюваної чи динамічної конфігурації перевизначте метод appMeta на своєму ресурсі, скориставшись плавними білдерами AppMeta, Csp і Permissions з простору імен Laravel\Mcp\Server\Ui.

Створення застосунків за допомогою Boost

Laravel MCP містить окремий довідник скіла Boost для створення MCP Apps. Якщо у вас встановлено Laravel Boost, ваш AI-агент для програмування може викликати скіл mcp-development і попросити його згенерувати ресурс застосунку, Blade-представлення й пов'язаний інструмент.

Повний довідник протоколу, включно з повним клієнтським API та деталями схеми, дивіться в офіційній документації MCP Apps.

Метадані

Laravel MCP також підтримує поле _meta, визначене в специфікації MCP, яке потрібне деяким MCP-клієнтам чи інтеграціям. Метадані можна застосувати до всіх примітивів MCP, включно з інструментами, ресурсами й промптами, а також до їхніх відповідей.

Ви можете прикріпити метадані до окремого вмісту відповіді методом withMeta:

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

/**
 * Handle the tool request.
 */
public function handle(Request $request): Response
{
    return Response::text('The weather is sunny.')
        ->withMeta(['source' => 'weather-api', 'cached' => true]);
}

Для метаданих рівня результату, що стосуються всієї оболонки відповіді, загорніть свої відповіді в Response::make і викличте withMeta на отриманому екземплярі фабрики відповідей:

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

/**
 * Handle the tool request.
 */
public function handle(Request $request): ResponseFactory
{
    return Response::make(
        Response::text('The weather is sunny.')
    )->withMeta(['request_id' => '12345']);
}

Щоб прикріпити метадані до самого інструмента, ресурсу чи промпта, визначте на класі властивість $meta:

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

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

    // ...
}

Іконки

MCP-клієнти можуть показувати іконки для вашого сервера та його примітивів. Ви можете оголосити іконки на сервері, інструменті, ресурсі чи промпті атрибутом Icon:

use Laravel\Mcp\Enums\IconTheme;
use Laravel\Mcp\Server\Attributes\Icon;

#[Icon('mcp/server.png', mimeType: 'image/png', sizes: ['48x48'])]
#[Icon('mcp/server-dark.svg', theme: IconTheme::Dark)]
class WeatherServer extends Server
{
    // ...
}

Атрибут Icon можна повторювати, тож ви можете оголосити кілька іконок, щоб надати різні розміри чи варіанти для світлої й темної теми.

Як альтернативу ви можете визначити іконки програмно, перевизначивши метод icons, що корисно, коли іконка залежить від умов виконання:

use Laravel\Mcp\Schema\Icon;

class CurrentWeatherTool extends Tool
{
    /**
     * Get the tool's icons.
     *
     * @return array<int, Icon>
     */
    public function icons(): array
    {
        return [
            Icon::from('mcp/tool.png', mimeType: 'image/png'),
        ];
    }
}

Іконки, визначені через атрибут і через метод icons, об'єднуються автоматично. Шляхи до іконок резолвляться так:

  • Шляхи зі схемою URI, як-от https: чи data:, використовуються як є.
  • Відносні шляхи перетворюються на URL за допомогою хелпера asset з Laravel.

Автентифікація

Так само як і маршрути, ви можете автентифікувати вебсервери 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 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, новий гард автентифікації й ключі passport.

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

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

Потім вкажіть Passport використовувати це представлення методом Passport::authorizationView. Зазвичай цей метод слід викликати в методі boot AppServiceProvider вашого застосунку:

use Laravel\Passport\Passport;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Passport::authorizationView(function ($parameters) {
        return view('mcp.authorize', $parameters);
    });
}

Це представлення буде показано кінцевому користувачеві під час автентифікації, щоб відхилити чи схвалити спробу автентифікації AI-агента.

Приклад екрана авторизації

У цьому сценарії ми просто використовуємо OAuth як шар перетворення до моделі автентифікації, що лежить в основі. Ми ігноруємо багато аспектів OAuth, як-от скопи.

Використання наявного встановлення Passport

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

Laravel MCP через метод Mcp::oauthRoutes, згаданий вище, додає, оголошує й використовує єдиний скоп mcp:use.

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

Авторизація

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

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

/**
 * Handle the tool request.
 */
public function handle(Request $request): Response
{
    if (! $request->user()->can('read-weather')) {
        return Response::error('Permission denied.');
    }

    // ...
}

MCP-клієнт

Окрім створення серверів, Laravel MCP містить клієнт для підключення до інших MCP-серверів - як власних, так і сторонніх. Клієнт дозволяє вашому застосунку виявляти й викликати інструменти, які надає MCP-сервер, що особливо корисно, щоб дати вашим AI-агентам доступ до можливостей зовнішніх MCP-серверів.

Підключення до серверів

Підключитися до MCP-сервера, доступного через HTTP, можна методом Client::web, передавши URL сервера:

use Laravel\Mcp\Client;

$client = Client::web('https://mcp.example.com');

Щоб підключитися до локального MCP-сервера, який працює як команда, скористайтеся методом Client::local, указавши команду й будь-які аргументи, потрібні для запуску сервера:

use Laravel\Mcp\Client;

$client = Client::local('php', ['artisan', 'mcp:start']);

Клієнт підключається ліниво, автоматично встановлюючи з'єднання під час першого переліку чи виклику інструментів. Якщо вам потрібно керувати з'єднанням вручну, скористайтеся методами connect, connected, ping і disconnect:

$client->connect();

$client->ping();

if ($client->connected()) {
    // ...
}

$client->disconnect();

Ви можете змінити тайм-аут запиту методом withTimeout:

$client = Client::web('https://mcp.example.com')->withTimeout(30);

Іменовані клієнти

Замість створювати клієнта щоразу, коли він вам потрібен, ви можете зареєструвати багаторазові іменовані клієнти. Зазвичай це роблять у методі boot сервіс-провайдера за допомогою фасада Mcp:

use Laravel\Mcp\Client;
use Laravel\Mcp\Facades\Mcp;

Mcp::registerClient('github', fn () => Client::web('https://mcp.example.com'));

Щойно клієнта зареєстровано, ви можете отримати його будь-де у своєму застосунку за іменем:

use Laravel\Mcp\Facades\Mcp;

$client = Mcp::client('github');

Іменовані клієнти створюються один раз на запит і автоматично від'єднуються наприкінці життєвого циклу запиту.

Автентифікація клієнта

Щоб підключитися до вебсервера MCP, захищеного bearer-токеном, скористайтеся методом withToken. Ви можете передати рядок токена або замикання, яке ліниво його поверне:

use Illuminate\Support\Facades\Auth;
use Laravel\Mcp\Client;

$client = Client::web('https://mcp.example.com')->withToken($token);

$client = Client::web('https://mcp.example.com')->withToken(
    fn () => Auth::user()->mcpToken(),
);

Для серверів, захищених OAuth 2.1, налаштуйте клієнта методом withOAuth. Це клієнтський відповідник захисту ваших власних серверів через OAuth:

use Laravel\Mcp\Client;
use Laravel\Mcp\Facades\Mcp;

Mcp::registerClient('github', fn () => Client::web('https://mcp.example.com')->withOAuth(
    clientId: config('services.github_mcp.client_id'),
    clientSecret: config('services.github_mcp.client_secret'),
));

Аргументи clientId і clientSecret можна опустити, коли MCP-сервер підтримує динамічну реєстрацію клієнтів - у цьому разі клієнт реєструється сам автоматично.

Далі зареєструйте OAuth-маршрути для іменованого клієнта у файлі routes/ai.php методом oAuthRoutesFor. Замикання, яке ви надаєте, отримує ім'я клієнта й отриманий TokenSet після обміну коду авторизації на токен доступу:

use Illuminate\Support\Facades\Auth;
use Laravel\Mcp\Client\OAuth\TokenSet;
use Laravel\Mcp\Facades\Mcp;

Mcp::oAuthRoutesFor('github', function (string $client, TokenSet $token) {
    Auth::user()->update([
        'github_mcp_token' => $token->accessToken,
    ]);

    return redirect('/dashboard');
});

Це реєструє два іменовані маршрути: маршрут підключення (mcp.oauth.{client}.connect), який перенаправляє користувача на сервер авторизації, і маршрут зворотного виклику (mcp.oauth.{client}.callback), який обмінює код авторизації й викликає ваш обробник. Обидва маршрути за замовчуванням використовують групу middleware web, яку ви можете перевизначити аргументом middleware.

Щоб розпочати потік авторизації, перенаправте користувача на маршрут підключення:

return redirect()->route('mcp.oauth.github.connect');

Інструменти

Отримати інструменти, які надає MCP-сервер, можна методом tools, що повертає колекцію інструментів з ключами за іменами:

use Laravel\Mcp\Facades\Mcp;

$tools = Mcp::client('github')->tools();

foreach ($tools as $tool) {
    $tool->name;
    $tool->title;
    $tool->description;
    $tool->inputSchema;
}

Клієнт автоматично проходить сторінками всіх доступних інструментів. Ви можете обмежити кількість повернутих інструментів аргументом limit:

$tools = Mcp::client('github')->tools(limit: 10);

Щоб викликати інструмент, скористайтеся методом callTool, передавши ім'я інструмента й масив аргументів. Повернутий екземпляр ToolResult надає відповідь інструмента:

use Laravel\Mcp\Facades\Mcp;

$result = Mcp::client('github')->callTool('current-weather', [
    'location' => 'New York',
]);

$result->text(); // The text content of the response...
(string) $result; // Equivalent to calling text()...
$result->isError; // Whether the tool reported an error...
$result->structuredContent;  // Structured content, if any...

Як альтернативу ви можете викликати інструмент безпосередньо з екземпляра переліченого інструмента:

$tools = Mcp::client('github')->tools();

$result = $tools['current-weather']->call([
    'location' => 'New York',
]);

Якщо ви створюєте агентів за допомогою Laravel AI SDK, ви також можете передати інструменти з MCP-клієнта безпосередньо агенту, дозволивши моделі викликати їх під час відповіді на промпт. Докладніше дивіться в розділі MCP Tools документації AI SDK.

Промпти

Отримати промпти, які надає MCP-сервер, можна методом prompts, що повертає колекцію промптів з ключами за іменами:

use Laravel\Mcp\Facades\Mcp;

$prompts = Mcp::client('github')->prompts();

foreach ($prompts as $prompt) {
    $prompt->name;
    $prompt->title;
    $prompt->description;
    $prompt->arguments;
}

Клієнт автоматично проходить сторінками всіх доступних промптів. Ви можете обмежити кількість повернутих промптів аргументом limit:

$prompts = Mcp::client('github')->prompts(limit: 10);

Щоб отримати промпт, скористайтеся методом getPrompt, передавши ім'я промпта й масив аргументів. Повернутий екземпляр PromptResult надає згенеровані повідомлення:

use Laravel\Mcp\Facades\Mcp;

$result = Mcp::client('github')->getPrompt('describe-weather', [
    'location' => 'New York',
]);

$result->text(); // The text content of the messages...
(string) $result; // Equivalent to calling text()...
$result->messages; // The raw messages returned by the prompt...
$result->description; // The prompt description, if any...

Ресурси

Отримати ресурси, які надає MCP-сервер, можна методом resources, що повертає колекцію ресурсів з ключами за URI:

use Laravel\Mcp\Facades\Mcp;

$resources = Mcp::client('github')->resources();

foreach ($resources as $resource) {
    $resource->uri;
    $resource->name;
    $resource->title;
    $resource->description;
    $resource->mimeType;
    $resource->size;
}

Клієнт автоматично проходить сторінками всіх доступних ресурсів. Ви можете обмежити кількість повернутих ресурсів аргументом limit:

$resources = Mcp::client('github')->resources(limit: 10);

Щоб прочитати ресурс, скористайтеся методом readResource, передавши URI ресурсу. Повернутий екземпляр ResourceReadResult надає вміст ресурсу:

use Laravel\Mcp\Facades\Mcp;

$result = Mcp::client('github')->readResource('weather://guidelines');

$result->content(); // The content of the resource, decoding base64 blobs as needed...
(string) $result; // Equivalent to calling content()...
$result->mimeType(); // The MIME type of the resource, if any...
$result->contents; // The raw contents returned by the resource...

Тестування серверів

Ви можете тестувати свої MCP-сервери за допомогою вбудованого MCP Inspector або пишучи юніт-тести.

MCP Inspector

MCP Inspector - це інтерактивний інструмент для тестування й налагодження ваших MCP-серверів. Використовуйте його, щоб підключитися до сервера, перевірити автентифікацію й випробувати інструменти, ресурси та промпти.

Ви можете запустити інспектор для будь-якого зареєстрованого сервера:

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

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

Ця команда запускає MCP Inspector і надає налаштування клієнта, які ви можете скопіювати до свого MCP-клієнта, щоб переконатися, що все налаштовано правильно. Якщо ваш вебсервер захищено middleware автентифікації, обов'язково додайте потрібні заголовки, як-от bearer-токен Authorization, під час підключення.

Юніт-тести

Ви можете писати юніт-тести для своїх MCP-серверів, інструментів, ресурсів і промптів.

Для початку створіть новий тест-кейс і викличте потрібний примітив на сервері, який його реєструє. Наприклад, щоб протестувати інструмент на WeatherServer:

test('tool', function () {
    $response = WeatherServer::tool(CurrentWeatherTool::class, [
        'location' => 'New York City',
        'units' => 'fahrenheit',
    ]);

    $response
        ->assertOk()
        ->assertSee('The current weather in New York City is 72°F and sunny.');
});
/**
 * Test a tool.
 */
public function test_tool(): void
{
    $response = WeatherServer::tool(CurrentWeatherTool::class, [
        'location' => 'New York City',
        'units' => 'fahrenheit',
    ]);

    $response
        ->assertOk()
        ->assertSee('The current weather in New York City is 72°F and sunny.');
}

Так само ви можете тестувати промпти й ресурси:

$response = WeatherServer::prompt(...);
$response = WeatherServer::resource(...);

Ви також можете діяти від імені автентифікованого користувача, додавши метод actingAs ланцюжком перед викликом примітива:

$response = WeatherServer::actingAs($user)->tool(...);

Отримавши відповідь, ви можете скористатися різними методами тверджень, щоб перевірити її вміст і статус.

Ви можете стверджувати, що відповідь успішна, методом assertOk. Він перевіряє, що відповідь не містить помилок:

$response->assertOk();

Ви можете стверджувати, що відповідь містить певний текст, методом assertSee:

$response->assertSee('The current weather in New York City is 72°F and sunny.');

Ви можете стверджувати, що відповідь містить помилку, методом assertHasErrors:

$response->assertHasErrors();

$response->assertHasErrors([
    'Something went wrong.',
]);

Ви можете стверджувати, що відповідь не містить помилки, методом assertHasNoErrors:

$response->assertHasNoErrors();

Ви можете стверджувати, що відповідь містить певні метадані, методами assertName(), assertTitle() та assertDescription():

$response->assertName('current-weather');
$response->assertTitle('Current Weather Tool');
$response->assertDescription('Fetches the current weather forecast for a specified location.');

Ви можете стверджувати, що сповіщення були надіслані, методами assertSentNotification і assertNotificationCount:

$response->assertSentNotification('processing/progress', [
    'step' => 1,
    'total' => 5,
]);

$response->assertSentNotification('processing/progress', [
    'step' => 2,
    'total' => 5,
]);

$response->assertNotificationCount(5);

Насамкінець, якщо ви хочете оглянути сирий вміст відповіді, скористайтеся методами dd чи dump, щоб вивести відповідь для налагодження:

$response->dd();
$response->dump();