更新日:2025/10/15
Laravel Model Context Protocol (MCP)

Laravel MCP (Model Context Protocol) is a specialized Laravel package that provides a simple and elegant method for AI clients to interact with your Laravel application. It implements the Model Context Protocol (MCP) and offers an expressive, fluent interface for defining the elements—servers, tools, resources, and prompts—that enable these AI-powered interactions.
To begin using Laravel MCP, you must install it using Composer
composer require laravel/mcpAfter installation, the routes must be published using the Artisan command
php artisan vendor:publish --tag=ai-routesThis creates the routes/ai.php file, which is used to register MCP servers
Servers act as the central communication point, exposing all MCP capabilities (tools, resources, and prompts) to AI clients
Servers are created using the make:mcp-server Artisan command
php artisan make:mcp-server WeatherServerThe resulting class extends Laravel\Mcp\Server and includes properties for defining the server's metadata (e.g., $name, $version, $instructions) and arrays for registering its components ( $tools, $resources, $prompts).
<?php
namespace App\Mcp\Servers;
use Laravel\Mcp\Server;
class WeatherServer extends Server
{
protected string $name = 'Weather Server';
protected string $version = '1.0.0';
protected string $instructions = 'This server provides weather information and forecasts.';
protected array $tools = [
// GetCurrentWeatherTool::class,
];
protected array $resources = [
// WeatherGuidelinesResource::class,
];
protected array $prompts = [
// DescribeWeatherPrompt::class,
];
}Servers must be registered in the routes/ai.php file using two available methods:
These are the most common type, accessible via HTTP POST requests, and are ideal for remote AI clients. They are registered using the Mcp::web facade method and can be protected by applying middleware:
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::web('/mcp/weather', WeatherServer::class)
->middleware(['throttle:mcp']);These run as Artisan commands, designed for local AI assistant integrations (like Laravel Boost). They are registered using the Mcp::local facade method.
use App\Mcp\Servers\WeatherServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::local('weather', WeatherServer::class);Laravel MCP applications are primarily defined by three types of components: Tools, Prompts, and Resources
Tools enable the MCP server to expose functionality that AI clients can call. They allow language models to perform actions, run code, or interact with external systems
Tools are created via make:mcp-tool and registered in the server's $tools property.
php artisan make:mcp-tool CurrentWeatherToolThe tool's $description is critical metadata that helps AI models understand when and how to use it
class CurrentWeatherTool extends Tool
{
protected string $name = 'get-optimistic-weather';
protected string $title = 'Get Optimistic Weather Forecast';
protected string $description = 'Fetches the current weather forecast for a specified location.';
}Tools define arguments using Laravel's Illuminate\JsonSchema\JsonSchema builder within the schema() method. This specifies the required input arguments (e.g., location, units)
<?php
namespace App\Mcp\Tools;
use Illuminate\JsonSchema\JsonSchema;
use Laravel\Mcp\Server\Tool;
class CurrentWeatherTool extends Tool
{
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'),
];
}
}Complex validation can be enforced within the tool's handle() method using Laravel's validation features ($request->validate(...)). Clear, actionable error messages must be provided for AI clients
<?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',
],[
'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.',
]);
}
}Tools must return a Laravel\Mcp\Response instance. Responses can be simple text (Response::text()), an error message (Response::error()), or multiple content responses (array of Response instances)
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
public function handle(Request $request): Response
{
// ...
return Response::text('Weather Summary: Sunny, 72°F');
}Tools can return a PHP Generator from the handle method for long-running operations or real-time data streaming. When used with web servers, this automatically opens an SSE (Server-Sent Events) stream
<?php
namespace App\Mcp\Tools;
use Generator;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;
class CurrentWeatherTool extends Tool
{
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));
}
}
}Tools can include attributes (annotations) like #[IsIdempotent] or #[IsReadOnly] to provide additional metadata about their capabilities and behavior to AI clients
<?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
{
//
}Tools can be registered conditionally at runtime by implementing the shouldRegister() method, based on application state or request parameters (e.g., checking if a user is subscribed)
<?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;
}
}The Laravel service container resolves all tools, allowing dependencies to be type-hinted in the constructor or the 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();
// ...
}
}Prompts enable the server to share reusable prompt templates that AI clients can utilize to interact with language models, providing a standardized way to structure common queries
Prompts are created via make:mcp-prompt and registered in the server's $prompts property.
php artisan make:mcp-prompt DescribeWeatherPromptA meaningful $description helps AI models understand prompt utility
class DescribeWeatherPrompt extends Prompt
{
protected string $name = 'weather-assistant';
protected string $title = 'Weather Assistant Prompt';
protected string $description = 'Generates a natural-language explanation of the weather for a given location.';
// ...
}Prompts define arguments using the arguments() method, returning \Laravel\Mcp\Server\Prompts\Argument instances. Validation is done within the handle method, similar to tools
<?php
namespace App\Mcp\Prompts;
use Laravel\Mcp\Server\Prompt;
use Laravel\Mcp\Server\Prompts\Argument;
class DescribeWeatherPrompt extends Prompt
{
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...
}
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,
),
];
}
}Prompts may return a single or an iterable set of Laravel\Mcp\Response instances. The asAssistant() method can indicate that a message should be treated as coming from the AI assistant
<?php
namespace App\Mcp\Prompts;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Prompt;
class DescribeWeatherPrompt extends Prompt
{
public function handle(Request $request): array
{
$tone = $request->string('tone');
$systemMessage = "You are a helpful weather assistant. Please provide a weather description in a {$tone} tone.";
$userMessage = "What is the current weather like in New York City?";
return [
Response::text($systemMessage)->asAssistant(),
Response::text($userMessage),
];
}
}Like tools, prompts support dependency injection in constructors and the handle method, and conditional registration using 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;
}
}Resources expose data and content that AI clients can read and use as context when interacting with language models, such as documentation or configuration. Unlike tools and prompts, resources cannot define input schemas or arguments
Resources are created via make:mcp-resource and registered in the server's $resources property.
php artisan make:mcp-resource WeatherGuidelinesResourceA $description is essential metadata
class WeatherGuidelinesResource extends Resource
{
protected string $name = 'weather-api-docs';
protected string $title = 'Weather API Documentation';
protected string $description = 'Comprehensive guidelines for using the Weather API.';
// ...
}Resources are identified by a unique URI (e.g., weather://resources/weather-guidelines) and an associated MIME type (defaulting to text/plain). These can be customized using the $uri and $mimeType properties
<?php
namespace App\Mcp\Resources;
use Laravel\Mcp\Server\Resource;
class WeatherGuidelinesResource extends Resource
{
protected string $uri = 'weather://resources/guidelines';
protected string $mimeType = 'application/pdf';
}Resources must return a Laravel\Mcp\Response. For simple content, use Response::text(). To return binary content, use Response::blob(), where the MIME type is determined by the resource's $mimeType property. Error responses use Response::error()
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
/**
* Handle the resource request.
*/
public function handle(Request $request): Response
{
// ...
return Response::text($weatherData);
}Resources also support dependency injection and conditional registration via 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;
}
}Web MCP servers can be protected using standard Laravel middleware
Two primary authentication methods are supported:
This is the documented authentication mechanism in the Model Context Protocol specification and is widely supported by MCP clients. It is implemented using Laravel Passport. This requires invoking Mcp::oauthRoutes() to register discovery and client registration routes, and then applying Passport’s auth:api middleware to the Mcp::web route. Laravel MCP advertises and uses a single mcp:use scope.
use App\Mcp\Servers\WeatherExample;
use Laravel\Mcp\Facades\Mcp;
Mcp::oauthRoutes();
Mcp::web('/mcp/weather', WeatherExample::class)
->middleware('auth:api');If integrating Passport is cumbersome, Sanctum can be used by applying the auth:sanctum middleware, requiring clients to provide an Authorization: Bearer <token> header
use App\Mcp\Servers\WeatherExample;
use Laravel\Mcp\Facades\Mcp;
Mcp::web('/mcp/demo', WeatherExample::class)
->middleware('auth:sanctum');Within tools and resources, the currently authenticated user can be accessed via $request->user(). This allows for authorization checks (e.g., using Laravel's permission system) and returning a Response::error() if permission is denied
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
public function handle(Request $request): Response
{
if (! $request->user()->can('read-weather')) {
return Response::error('Permission denied.');
}
// ...
}Laravel MCP provides both an interactive debugging tool and methods for comprehensive unit testing
The MCP Inspector is an interactive tool used for testing and debugging registered servers. It can be launched via Artisan (php artisan mcp:inspector [server]) for both web and local servers.
# Web server...
php artisan mcp:inspector mcp/weather
# Local server named "weather"...
php artisan mcp:inspector weatherIt allows users to connect to the server, verify authentication, and test out tools, resources, and prompts
Unit tests can be written by invoking the primitive directly on the server class
$response = WeatherServer::tool(CurrentWeatherTool::class, [...])$response = WeatherServer::prompt(...)or
$response = WeatherServer::resource(...)$response = WeatherServer::actingAs($user)->tool(...)
Unit test assertions include assertOk() (checks for no errors), assertSee() (checks for specific text content), assertHasErrors(), assertHasNoErrors(), and assertions for metadata like assertName() or assertDescription(). For streaming responses, assertions like assertSentNotification() and assertNotificationCount() are available
/**
* 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.');
}
Laravel Model Context Protocol (MCP)
オフショア開発のご紹介資料