Model Context Protocol(MCP) 은 AI 클라이언트(Claude, Cursor, GitHub Copilot 등)와 애플리케이션이 표준화된 프로토콜로 통신하기 위한 사양입니다. MCP 서버를 구현함으로써 AI 에이전트는 여러분의 Laravel 애플리케이션의 데이터에 접근하거나 액션을 실행할 수 있게 됩니다.
Laravel MCP는 Laravel 13에서 추가된 공식 패키지입니다. laravel/mcp로 제공되며, MCP 서버의 구축에 필요한 일련의 기능을 제공합니다.
<?phpnamespace 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{ public function handle(Request $request): Response { $location = $request->get('location'); // 날씨 데이터를 취득... return Response::text('The weather is sunny, 22°C.'); } public function schema(JsonSchema $schema): array { return [ 'location' => $schema->string() ->description('The location to get the weather for.') ->required(), ]; }}
schema 메서드로 입력 파라미터의 스키마를 정의합니다. Laravel의 JSON 스키마 빌더를 사용해 타입이나 제약을 지정할 수 있습니다.
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'), ];}
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. For example, "New York City" or "Tokyo".', 'units.in' => 'You must specify either "celsius" or "fahrenheit" for the units.', ]); // 밸리데이션 완료된 데이터를 사용해 처리...}
밸리데이션 실패 시에 AI 클라이언트는 에러 메시지를 참고해 재시도합니다. 구체적이고 실행 가능한 에러 메시지를 제공해 주십시오.
<?phpnamespace App\Mcp\Prompts;use Laravel\Mcp\Server\Prompt;use Laravel\Mcp\Server\Prompts\Argument;class DescribeWeatherPrompt extends Prompt{ 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, ), ]; }}
프롬프트의 handle 메서드에서는 사용자 메시지와 어시스턴트 메시지를 반환할 수 있습니다. asAssistant()로 어시스턴트 측 메시지로서 취급합니다.
<?phpnamespace 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 Tokyo?'; return [ Response::text($systemMessage)->asAssistant(), Response::text($userMessage), ]; }}
<?phpnamespace App\Mcp\Resources;use Laravel\Mcp\Request;use Laravel\Mcp\Response;use Laravel\Mcp\Server\Attributes\Description;use Laravel\Mcp\Server\Resource;#[Description('Comprehensive guidelines for using the Weather API.')]class WeatherGuidelinesResource extends Resource{ public function handle(Request $request): Response { $guidelines = "# Weather API Guidelines\n\n- Always specify a location..."; return Response::text($guidelines); }}
URI 변수를 가진 동적 리소스를 정의하려면 HasUriTemplate 인터페이스를 구현합니다.
<?phpnamespace 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{ 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("File {$fileId} for user {$userId}"); }}
Laravel MCP는 MCP Apps를 지원합니다. 이것은 Model Context Protocol의 확장 기능으로, 도구가 지원된 호스트 내의 샌드박스 iframe 상에서 인터랙티브한 HTML 애플리케이션을 렌더링할 수 있게 합니다. 이에 따라 플레인 텍스트 응답을 넘어선 대시보드, 폼, 시각화, 그 외의 리치한 경험을 구축할 수 있습니다.MCP 앱은 다음 2개의 파트가 연계되어 동작합니다.
이 명령어는 2개의 파일을 작성합니다. app/Mcp/Resources 내의 PHP 클래스와 resources/views/mcp 내의 Blade 뷰입니다. 뷰 이름은 클래스 이름에서 자동으로 추측됩니다. 예를 들어 WeatherDashboardApp은 mcp.weather-dashboard-app으로 매핑됩니다.
AppResource는 베이스의 Resource 클래스를 상속하며, MCP Apps 사양에서 요구되는 ui:// URI 스킴과 text/html;profile=mcp-app MIME 타입을 자동으로 설정합니다. 다른 리소스와 마찬가지로 서버의 $resources 배열에 등록해야 합니다.생성된 Blade 뷰는 <x-mcp::app> 컴포넌트를 사용합니다. 이 컴포넌트는 클라이언트 사이드의 MCP SDK가 번들된 완전한 HTML 문서를 렌더링합니다.
createMcpApp 글로벌 함수는 번들된 SDK가 제공합니다. iframe의 서버에의 접속, 호스트 테마의 적용, callServerTool·sendMessage·openLink 등의 헬퍼나 이벤트 콜백의 공개를 처리합니다. 완전한 클라이언트 사이드 API에 대해서는 MCP Apps 사양을 참조해 주십시오.
Library enum에는 Library::Tailwind나 Library::Alpine 등 일반적인 프런트엔드 라이브러리의 CDN 스크립트가 사전 설정되어 있으며, CDN 오리진은 자동으로 CSP에 머지됩니다. Permission enum은 Camera·Microphone·Geolocation·ClipboardWrite 등의 브라우저 권한을 커버합니다.
동적인 설정이 필요한 경우, Laravel\Mcp\Server\Ui 네임스페이스의 AppMeta·Csp·Permissions 플루언트 빌더를 사용해 리소스의 appMeta 메서드를 오버라이드합니다.
Laravel MCP에는 MCP Apps를 구축하기 위한 전용 Boost 스킬 레퍼런스가 포함되어 있습니다. Laravel Boost가 설치되어 있다면, AI 코딩 에이전트가 mcp-development 스킬을 호출해 앱 리소스, Blade 뷰, 링크된 도구를 자동 생성할 수 있습니다.프로토콜의 완전한 레퍼런스(클라이언트 사이드 API나 스키마의 상세 포함)에 대해서는 공식의 MCP Apps 문서를 참조해 주십시오.
Icon 속성은 반복 사용 가능하므로, 서로 다른 사이즈나 라이트·다크 테마의 배리언트를 제공하기 위해 여러 아이콘을 선언할 수 있습니다.또는 icons 메서드를 오버라이드해 프로그램으로 아이콘을 정의할 수도 있습니다. 이것은 아이콘이 런타임의 조건에 의존하는 경우에 편리합니다.
use Laravel\Mcp\Schema\Icon;class CurrentWeatherTool extends Tool{ /** * 도구의 아이콘을 취득합니다. * * @return array<int, Icon> */ public function icons(): array { return [ Icon::from('mcp/tool.png', mimeType: 'image/png'), ]; }}
속성과 icons 메서드로 정의된 아이콘은 자동으로 결합됩니다. 아이콘 경로는 다음과 같이 해결됩니다.
use App\Mcp\Servers\WeatherServer;use Laravel\Mcp\Facades\Mcp;Mcp::oauthRoutes();Mcp::web('/mcp/weather', WeatherServer::class) ->middleware('auth:api');
OAuth 인증을 사용하는 경우, Passport의 인가 뷰를 공개해 서비스 프로바이더에 설정합니다.
$request->user()로 인증된 사용자를 취득해, 도구나 리소스 내에서 인가 체크를 할 수 있습니다.
public function handle(Request $request): Response{ if (! $request->user()->can('read-weather')) { return Response::error('Permission denied.'); } // 처리를 계속...}
Laravel MCP는 서버의 구축뿐 아니라, 다른 MCP 서버로 접속하기 위한 클라이언트도 제공하고 있습니다. 클라이언트를 사용함으로써 외부 MCP 서버가 공개하는 도구를 발견·호출할 수 있습니다. AI 에이전트에 외부 MCP 서버의 기능을 제공할 때 특히 유용합니다.
MCP 서버가 동적 클라이언트 등록을 지원하고 있는 경우, clientId와 clientSecret은 생략할 수 있습니다. 클라이언트가 자동 등록합니다.
다음으로, routes/ai.php 파일에서 이름 있는 클라이언트의 OAuth 라우트를 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');});
이에 따라 2개의 이름이 있는 라우트가 등록됩니다. 사용자를 인가 서버로 리다이렉트하는 connect 라우트(mcp.oauth.{client}.connect)와, 인가 코드를 교환해 핸들러를 호출하는 callback 라우트(mcp.oauth.{client}.callback)입니다. 어느 쪽도 web 미들웨어 그룹을 사용합니다(middleware 인수로 덮어쓰기 가능).인가 플로우를 개시하려면 사용자를 connect 라우트로 리다이렉트합니다.
test('tool', function () { $response = WeatherServer::tool(CurrentWeatherTool::class, [ 'location' => 'Tokyo', 'units' => 'celsius', ]); $response ->assertOk() ->assertSee('The current weather in Tokyo is 22°C and sunny.');});
public function test_tool(): void{ $response = WeatherServer::tool(CurrentWeatherTool::class, [ 'location' => 'Tokyo', 'units' => 'celsius', ]); $response ->assertOk() ->assertSee('The current weather in Tokyo is 22°C and sunny.');}
$response->assertHasErrors();$response->assertHasErrors([ 'Something went wrong.',]);$response->assertHasNoErrors();
도구·리소스·프롬프트의 이름이나 타이틀, 설명을 검증할 수 있습니다.
$response->assertName('current-weather');$response->assertTitle('Current Weather Tool');$response->assertDescription('Fetches the current weather forecast for a specified location.');