Laravel MCP

번역일: 2026년 6월 25일

Laravel MCP

소개

Laravel MCP는 AI 클라이언트가 Model Context Protocol을 통해 Laravel 애플리케이션과 상호작용할 수 있도록 해주는 패키지입니다. 서버, Tool, Resource, Prompt를 유창하고 표현력 있는 인터페이스로 정의하여 AI 기반의 애플리케이션 연동을 손쉽게 구현할 수 있습니다.

설치

Composer로 Laravel MCP를 설치합니다:

composer require laravel/mcp

라우트 퍼블리시

설치 후 vendor:publish Artisan 명령어로 routes/ai.php 파일을 게시합니다. MCP 서버는 이 파일에서 등록합니다:

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

이 명령어를 실행하면 애플리케이션의 routes 디렉터리에 routes/ai.php 파일이 생성됩니다.

서버 생성

make:mcp-server Artisan 명령어로 MCP 서버를 생성합니다. 서버는 Tool, Resource, Prompt 등의 MCP 기능을 AI 클라이언트에 노출하는 중심 허브 역할을 합니다:

php artisan make:mcp-server WeatherServer

이 명령어는 app/Mcp/Servers 디렉터리에 서버 클래스를 생성합니다. 생성된 클래스는 Laravel\Mcp\Server를 상속하며, PHP 어트리뷰트(attribute)와 속성(property)을 통해 서버를 구성하고 Tool, Resource, Prompt를 등록합니다:

<?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('이 서버는 날씨 정보와 예보를 제공합니다.')] class WeatherServer extends Server { /** * 이 MCP 서버에 등록된 Tool 목록 * * @var array<int, class-string<\Laravel\Mcp\Server\Tool>> */ protected array $tools = [ // GetCurrentWeatherTool::class, ]; /** * 이 MCP 서버에 등록된 Resource 목록 * * @var array<int, class-string<\Laravel\Mcp\Server\Resource>> */ protected array $resources = [ // WeatherGuidelinesResource::class, ]; /** * 이 MCP 서버에 등록된 Prompt 목록 * * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>> */ protected array $prompts = [ // DescribeWeatherPrompt::class, ]; }

서버 등록

서버를 생성했다면 routes/ai.php 파일에 등록해야 외부에서 접근할 수 있습니다. Laravel MCP는 HTTP로 접근 가능한 web 방식과 커맨드라인 기반의 local 방식을 제공합니다.

웹 서버

웹 서버는 HTTP POST 요청으로 접근하는 가장 일반적인 방식으로, 원격 AI 클라이언트나 웹 기반 연동에 적합합니다. web 메서드로 등록합니다:

use App\Mcp\Servers\WeatherServer; use Laravel\Mcp\Facades\Mcp; Mcp::web('/mcp/weather', WeatherServer::class);

일반 라우트와 마찬가지로 미들웨어를 적용해 서버를 보호할 수 있습니다:

Mcp::web('/mcp/weather', WeatherServer::class) ->middleware(['throttle:mcp']);

로컬 서버

로컬 서버는 Artisan 명령어로 실행되며, Laravel Boost와 같은 로컬 AI 어시스턴트 연동에 적합합니다. local 메서드로 등록합니다:

use App\Mcp\Servers\WeatherServer; use Laravel\Mcp\Facades\Mcp; Mcp::local('weather', WeatherServer::class);

등록 후에는 일반적으로 mcp:start Artisan 명령어를 직접 실행할 필요가 없습니다. MCP 클라이언트(AI 에이전트)가 서버를 시작하도록 설정하거나 MCP Inspector를 활용하세요.

Tools

Tool은 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 { /** * Tool 요청을 처리합니다. */ public function handle(Request $request): Response { $location = $request->get('location'); // 날씨 정보 조회... return Response::text('현재 날씨는...'); } /** * Tool의 입력 스키마를 반환합니다. * * @return array<string, \Illuminate\JsonSchema\Types\Type> */ public function schema(JsonSchema $schema): array { return [ 'location' => $schema->string() ->description('날씨를 조회할 위치') ->required(), ]; } }

Tool 생성

make:mcp-tool Artisan 명령어로 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 서버에 등록된 Tool 목록 * * @var array<int, class-string<\Laravel\Mcp\Server\Tool>> */ protected array $tools = [ CurrentWeatherTool::class, ]; }

Tool 이름, 제목, 설명

기본적으로 Tool의 이름과 제목은 클래스명에서 자동으로 생성됩니다. 예를 들어 CurrentWeatherTool은 이름이 current-weather, 제목이 Current Weather Tool이 됩니다. NameTitle 어트리뷰트로 이를 변경할 수 있습니다:

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 { // ... }

Tool 설명은 자동으로 생성되지 않습니다. 반드시 Description 어트리뷰트로 의미 있는 설명을 제공하세요:

use Laravel\Mcp\Server\Attributes\Description; #[Description('지정된 위치의 현재 날씨 예보를 가져옵니다.')] class CurrentWeatherTool extends Tool { // }

NOTE

설명은 AI 모델이 Tool을 언제, 어떻게 사용할지 판단하는 데 핵심적인 메타데이터입니다. 명확하고 구체적으로 작성하세요.

Tool 입력 스키마

Tool은 AI 클라이언트로부터 받을 인자의 구조를 입력 스키마로 정의할 수 있습니다. Laravel의 Illuminate\Contracts\JsonSchema\JsonSchema 빌더를 사용합니다:

<?php namespace App\Mcp\Tools; use Illuminate\Contracts\JsonSchema\JsonSchema; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * 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('온도 단위') ->default('celsius'), ]; } }

Tool 출력 스키마

Tool은 출력 스키마를 정의하여 응답의 구조를 명시할 수 있습니다. 파싱 가능한 결과가 필요한 AI 클라이언트와의 통합에 유용합니다. outputSchema 메서드를 사용합니다:

<?php namespace App\Mcp\Tools; use Illuminate\Contracts\JsonSchema\JsonSchema; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * 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(), ]; } }

Tool 인자 유효성 검사

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 { /** * 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' => '날씨를 조회할 위치를 지정해야 합니다. 예: "서울" 또는 "부산".', 'units.in' => '온도 단위는 "celsius" 또는 "fahrenheit"여야 합니다.', ]);

Tool 의존성 주입

모든 Tool은 Laravel 서비스 컨테이너를 통해 리졸브됩니다. 생성자에 타입 힌트를 선언하면 의존성이 자동으로 주입됩니다:

<?php namespace App\Mcp\Tools; use App\Repositories\WeatherRepository; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * 새 Tool 인스턴스를 생성합니다. */ 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 { /** * Tool 요청을 처리합니다. */ public function handle(Request $request, WeatherRepository $weather): Response { $location = $request->get('location'); $forecast = $weather->getForecastFor($location); // ... } }

Tool 어노테이션

어노테이션을 사용해 AI 클라이언트에 Tool의 동작 특성에 관한 추가 메타데이터를 제공할 수 있습니다. 어트리뷰트를 통해 추가합니다:

<?php namespace App\Mcp\Tools; use Laravel\Mcp\Server\Tools\Annotations\IsIdempotent; use Laravel\Mcp\Server\Tools\Annotations\IsReadOnly; use Laravel\Mcp\Server\Tool; #[IsIdempotent] #[IsReadOnly] class CurrentWeatherTool extends Tool { // }

사용 가능한 어노테이션:

어노테이션타입설명
#[IsReadOnly]booleanTool이 환경을 변경하지 않음을 나타냅니다.
#[IsDestructive]booleanTool이 파괴적인 변경을 수행할 수 있음을 나타냅니다(읽기 전용이 아닐 때만 유효).
#[IsIdempotent]boolean동일한 인자로 반복 호출해도 추가 효과가 없음을 나타냅니다(읽기 전용이 아닐 때).
#[IsOpenWorld]booleanTool이 외부 엔티티와 상호작용할 수 있음을 나타냅니다.

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 { // }

조건부 Tool 등록

shouldRegister 메서드를 구현하면 런타임에 Tool 등록 여부를 동적으로 결정할 수 있습니다. 애플리케이션 상태, 설정, 또는 요청 파라미터에 따라 Tool 사용 가능 여부를 제어할 때 유용합니다:

<?php namespace App\Mcp\Tools; use Laravel\Mcp\Request; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * Tool 등록 여부를 결정합니다. */ public function shouldRegister(Request $request): bool { return $request?->user()?->subscribed() ?? false; } }

shouldRegisterfalse를 반환하면 해당 Tool은 사용 가능한 목록에 노출되지 않으며 AI 클라이언트가 호출할 수 없습니다.

Tool 응답

Tool은 Laravel\Mcp\Response 인스턴스를 반환해야 합니다. Response 클래스는 다양한 유형의 응답을 생성하는 편의 메서드를 제공합니다.

단순 텍스트 응답은 text 메서드를 사용합니다:

use Laravel\Mcp\Request; use Laravel\Mcp\Response; /** * Tool 요청을 처리합니다. */ public function handle(Request $request): Response { // ... return Response::text('날씨 요약: 맑음, 22°C'); }

Tool 실행 중 오류가 발생했음을 나타내려면 error 메서드를 사용합니다:

return Response::error('날씨 데이터를 가져올 수 없습니다. 다시 시도해 주세요.');

이미지나 오디오 콘텐츠를 반환하려면 imageaudio 메서드를 사용합니다:

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');

다중 콘텐츠 응답

Tool은 Response 인스턴스 배열을 반환해 여러 개의 콘텐츠를 한 번에 전달할 수 있습니다:

use Laravel\Mcp\Request; use Laravel\Mcp\Response; /** * Tool 요청을 처리합니다. * * @return array<int, \Laravel\Mcp\Response> */ public function handle(Request $request): array { // ... return [ Response::text('날씨 요약: 맑음, 22°C'), Response::text('**상세 예보**\n- 오전: 18°C\n- 오후: 26°C\n- 저녁: 21°C'), ]; }

구조화된 응답

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 메서드에서 Generator를 반환하면 최종 응답 이전에 중간 업데이트를 클라이언트에 전달할 수 있습니다:

<?php namespace App\Mcp\Tools; use Generator; use Laravel\Mcp\Request; use Laravel\Mcp\Response; use Laravel\Mcp\Server\Tool; class CurrentWeatherTool extends Tool { /** * 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) 스트림이 열리며, yield된 각 메시지가 이벤트로 클라이언트에 전송됩니다.

Prompts

Prompt는 AI 클라이언트가 언어 모델과 상호작용할 때 사용할 수 있는 재사용 가능한 프롬프트 템플릿을 서버에 공유합니다. 일반적인 쿼리와 상호작용을 표준화된 방식으로 구조화할 수 있습니다.

Prompt 생성

make:mcp-prompt Artisan 명령어로 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 서버에 등록된 Prompt 목록 * * @var array<int, class-string<\Laravel\Mcp\Server\Prompt>> */ protected array $prompts = [ DescribeWeatherPrompt::class, ]; }

Prompt 이름, 제목, 설명

기본적으로 Prompt의 이름과 제목은 클래스명에서 자동으로 생성됩니다. 예를 들어 DescribeWeatherPrompt는 이름이 describe-weather, 제목이 Describe Weather Prompt가 됩니다. NameTitle 어트리뷰트로 변경할 수 있습니다:

use Laravel\Mcp\Server\Attributes\Name; use Laravel\Mcp\Server\Attributes\Title; #[Name('weather-assistant')] #[Title('Weather Assistant Prompt')] class DescribeWeatherPrompt extends Prompt { // ... }

Prompt 설명은 자동으로 생성되지 않습니다. 반드시 Description 어트리뷰트로 의미 있는 설명을 제공하세요:

use Laravel\Mcp\Server\Attributes\Description; #[Description('주어진 위치의 날씨를 자연어로 설명하는 프롬프트를 생성합니다.')] class DescribeWeatherPrompt extends Prompt { // }

NOTE

설명은 AI 모델이 Prompt를 언제, 어떻게 활용할지 이해하는 데 핵심적인 메타데이터입니다.

Prompt 인자

Prompt는 AI 클라이언트가 템플릿을 커스터마이즈할 수 있도록 인자를 정의할 수 있습니다.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 25일