api-platform-mcp skill
PHP 어트리뷰트를 사용하여 API Platform 리소스를 AI 에이전트용 Model Context Protocol 도구 및 리소스로 노출합니다.
- GitHub 스타
- 29
- 파일
- 1
- 마지막 커밋
- 2026년 10월 22일
- 라이선스
- —
- 허용된 도구
- —
api-platform-mcp skill은 무엇을 하나요?
api-platform-mcp은(는) agent skill입니다. PHP 어트리뷰트를 사용하여 API Platform 리소스를 AI 에이전트용 Model Context Protocol 도구 및 리소스로 노출합니다.
skill의 SKILL.md에서 생성된 요약입니다.
api-platform-mcp skill 정보
이 SKILL은 API Platform을 사용하는 개발자가 PHP 기반 API 리소스를 Model Context Protocol 도구 및 리소스로 노출할 수 있게 해줍니다. PHP 클래스를 호출 가능한 도구 또는 읽기 전용 리소스로 변환하여 AI 에이전트가 기존 백엔드 로직을 탐색하고 상호작용할 수 있도록 지원합니다. 이는 명령 실행을 위한 #[McpTool] 및 문서나 설정 같은 콘텐츠를 가져오기 위한 #[McpResource]와 같은 특수 어트리뷰트를 통해 구현됩니다.
개발자는 이를 Symfony 또는 Laravel 애플리케이션에 통합하여 구조화된 데이터나 커스텀 응답을 제공할 수 있습니다. 이 시스템은 state processor, provider, validation을 포함한 기존 메타데이터 스택을 재사용합니다. DTO를 사용하여 특정 입력 스키마를 정의하거나, McpToolCollection으로 컬렉션을 처리하거나, CallToolResult를 반환하여 표준 JSON 직렬화를 우회할 수 있습니다. 이를 통해 LLM은 전통적인 HTTP 라우트 없이도 표준 tools/call 및 resources/read 작업을 통해 API와 상호작용할 수 있습니다.
agent가 수행할 수 있는 작업
- 1백엔드 로직을 도구로 노출특정 PHP 클래스를 AI 에이전트가 데이터를 처리하는 데 사용할 수 있는 호출 가능한 도구로 변환합니다.
- 2에이전트 입력에 비즈니스 규칙 적용AI 에이전트가 전송하는 데이터가 이메일 형식이나 문자열 길이와 같은 특정 검증 제약 조건을 준수하도록 보장합니다.
skill의 SKILL.md를 기반으로 작성되었습니다. 모든 사용 사례는 해당 문서의 인용구와 대조 확인되었습니다.
api-platform-mcp skill 설치 방법
각 명령은 skill 폴더를 클라이언트의 skills 디렉터리에 복사합니다. 클라이언트를 재시작하거나 새 세션을 시작하여 로드하세요.플러그인에 api-platform-mcp skill 설치
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Claude Code에 api-platform-mcp skill 설치
~/.claude/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp ~/.claude/skills/api-platform-mcpClaude Code (project)에 api-platform-mcp skill 설치
.claude/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp .claude/skills/api-platform-mcpCodex에 api-platform-mcp skill 설치
~/.agents/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp ~/.agents/skills/api-platform-mcpGemini CLI에 api-platform-mcp skill 설치
~/.gemini/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp ~/.gemini/skills/api-platform-mcpClaude.ai에 api-platform-mcp skill 설치
npx degit api-platform/skillset/skills/api-platform-mcp api-platform-mcp && zip -r api-platform-mcp.zip api-platform-mcp # claude.ai → Customize → Skills → + → Create skill → Upload a skill → api-platform-mcp.zip
SKILL.md
GitHub에서 보기MCP: Exposing Your API to AI Agents
API Platform turns PHP classes into Model Context Protocol tools and resources. It reuses the existing metadata stack — state processors/providers, validation, serialization, JSON Schema — so an MCP tool is just an operation with no HTTP route.
@experimental. API may change between minor releases.
Install & enable
Symfony — composer require api-platform/mcp symfony/mcp-bundle (bundle namespace is
Symfony\AI\McpBundle, composer name symfony/mcp-bundle):
# config/packages/mcp.yaml
mcp:
client_transports:
http: true
stdio: false
http:
path: "/mcp"
session: { store: "file", directory: "%kernel.cache_dir%/mcp", ttl: 3600 }
# config/packages/api_platform.yaml
api_platform:
mcp:
enabled: true # default: true
format: jsonld # default; must be a registered api_platform.format (json, jsonapi, …)
format sets the serialization format for structured content. jsonld emits @context,
@id, @type. Laravel — enabled by default, endpoint auto-registered at /mcp:
// config/api-platform.php
return [ /* … */ 'mcp' => ['enabled' => true] ];
API Platform registers its own SDK Handler; supports() returns true only for tools/resources
in its registry, otherwise the SDK's own handler chain runs. API Platform tools and native
mcp/sdk tools coexist on the same server.
Two ways to declare a tool
Standalone #[McpTool] class attribute — convenient for a one-off tool. Class properties
become the inputSchema; a state processor handles the command
(CQRS-style — the agent's input is processed through your logic):
use ApiPlatform\Metadata\McpTool;
#[McpTool(
name: 'process_message',
description: 'Process a message with priority',
processor: [self::class, 'process'],
)]
class ProcessMessage
{
public function __construct(
private string $message,
private int $priority = 1,
) {}
// getters + setters drive (de)serialization
public static function process($data): mixed
{
$data->setMessage('Processed: '.$data->getMessage());
return $data;
}
}
The agent's arguments are deserialized into a ProcessMessage, passed to the processor; the
returned object is serialized back as structured content. processor is any callable or a
ProcessorInterface service.
mcp: array on #[ApiResource] — use when the class exposes no HTTP endpoints
(operations: []), combines several MCP operations, or needs resource-level control. Keys are
the tool names, so omit name: inside each new McpTool(...):
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\McpTool;
use App\State\ReadHydraResourceProcessor;
#[ApiResource(
operations: [],
mcp: [
'read_hydra_resource' => new McpTool(
description: 'Navigate to a Hydra API resource by URI.',
processor: ReadHydraResourceProcessor::class,
structuredContent: false,
),
],
)]
class ReadHydraResource
{
public string $uri;
}
Separate input DTO
When the input schema must differ from the result class, point input: at a DTO. That DTO drives
inputSchema; the host class describes the output:
#[McpTool(
name: 'search_books',
description: 'Search books by keyword',
input: SearchQuery::class, // what the agent sends
processor: SearchBooksProcessor::class,
)]
class BookSearchResult
{
public int $id;
public string $title;
public string $isbn;
}
The processor receives a SearchQuery instance and returns the result(s).
Collections — McpToolCollection
Use McpToolCollection (extends McpTool, implements CollectionOperationInterface) when a tool
returns a list — the serializer and schema factory emit collection-shaped output:
use ApiPlatform\Metadata\McpToolCollection;
#[ApiResource(operations: [], mcp: [
'list_books' => new McpToolCollection(
description: 'List Books',
input: SearchQuery::class,
processor: SearchBooksProcessor::class,
structuredContent: true,
),
])]
class Book { public ?int $id = null; public ?string $title = null; public ?string $isbn = null; }
With structuredContent: true and the default jsonld format, the response carries @context,
hydra:totalItems, and a hydra:member array of serialized items; the published outputSchema
reflects that shape. Output schemas are flattened for MCP compliance — no $ref, allOf,
$schema, or definitions.
Custom responses — CallToolResult
Default: results serialize through API Platform's serialization
as structured JSON. For full control, set structuredContent: false and return a CallToolResult:
use Mcp\Schema\Content\TextContent;
use Mcp\Schema\Result\CallToolResult;
#[McpTool(name: 'generate_report', description: 'Generate a markdown report',
processor: [self::class, 'process'], structuredContent: false)]
class Report
{
public function __construct(private string $title, private string $content) {}
// getters/setters …
public static function process($data): CallToolResult
{
return new CallToolResult(
[new TextContent("# {$data->getTitle()}\n\n{$data->getContent()}")],
false, // isError
// 3rd arg: optional _meta array
);
}
}
structuredContent: false disables automatic JSON serialization; the CallToolResult is sent
as-is, with no structuredContent / _meta key in the response.
Schema overrides — the nullable-union gotcha
PHP nullable types generate union schemas like {"type": ["array", "null"]}. Some LLM providers
reject these. Override per property with #[ApiProperty(schema: [...])]:
use ApiPlatform\Metadata\ApiProperty;
class InvokeHydraOperation
{
public string $uri;
public string $method;
#[ApiProperty(schema: ['type' => 'object', 'description' => 'JSON payload for the request'])]
public ?array $payload = null; // without override: {"type": ["array","null"]}
}
Validation — off by default
The MCP SDK validates inputs against the JSON Schema at transport level (types, required fields).
API Platform's own validation pipeline is disabled for MCP tools. Set validate: true to
run business constraints (email format, length, custom rules):
use Symfony\Component\Validator\Constraints as Assert;
#[McpTool(name: 'submit_contact', description: 'Submit a contact form',
processor: [self::class, 'process'], validate: true)]
class ContactForm
{
#[Assert\NotBlank] #[Assert\Length(min: 3, max: 50)]
private ?string $name = null;
#[Assert\NotNull] #[Assert\Email]
private ?string $email = null;
}
Laravel — same validate: true, plus rules: instead of constraints:
#[McpTool(name: 'submit_contact', description: '…', processor: [self::class, 'process'],
validate: true, rules: ['name' => 'required|min:3|max:50', 'email' => 'required|email'])]
Read-only resources — #[McpResource]
Expose retrievable content (docs, config, reference data) backed by a
state provider. uri must be unique and use the resource:// scheme:
use ApiPlatform\Metadata\McpResource;
#[ApiResource(operations: [], mcp: [
'api_docs' => new McpResource(
uri: 'resource://my-app/documentation',
name: 'App-Documentation',
description: 'Application API documentation',
mimeType: 'text/markdown',
provider: [self::class, 'provide'],
),
])]
class Documentation
{
public function __construct(private string $content, private string $uri) {}
public static function provide(): self
{
return new self('# My API Documentation\n\nWelcome.', 'resource://my-app/documentation');
}
}
Options
McpTool and McpResource extend HttpOperation, so they accept all standard
operation options. MCP-specific / notable ones:
| Option | Tool | Res | Notes |
|---|---|---|---|
name |
✓ | ✓ | exposed to agents; defaults to class short name. Omit in mcp: array (key wins) |
description |
✓ | ✓ | defaults to class DocBlock |
structuredContent |
✓ | ✓ | include JSON structured content (default true) |
input / output |
✓ | separate DTO for input schema / output representation | |
inputFormats / outputFormats |
✓ | (de)serialization formats, e.g. ['json'], ['jsonld'] |
|
contentNegotiation |
✓ | ✓ | default false for MCP |
validate |
✓ | run validation pipeline (default false for MCP) |
|
rules |
✓ | Laravel validation rules (Laravel only) | |
annotations/icons/meta |
✓ | ✓ | behavior hints / icon URLs / arbitrary metadata |
uri |
✓ | required, resource:// scheme, unique across server |
|
mimeType / size |
✓ | content MIME type / byte size if known |
Wire protocol (for testing)
Everything is JSON-RPC 2.0 POSTed to /mcp with
Accept: application/json, text/event-stream. initialize returns an mcp-session-id header;
send it back on every subsequent call. tools/list / resources/list enumerate; tools/call
(params: {name, arguments}) and resources/read (params: {uri}) invoke. The handler overrides
Accept to the operation's output format, so a jsonld tool always responds JSON-LD regardless
of use_symfony_listeners.
Laravel
- Config under
mcpinconfig/api-platform.php; endpoint auto-registered at/mcp. - Validation uses
rules:(string/array/closure/FormRequest), not Symfony constraints. - MongoDB is not supported for MCP.
Checklist
-
api-platform/mcp+symfony/mcp-bundleinstalled,/mcptransport configured (Symfony) - Tool class has a
processor(write) orMcpResourcehas aprovider(read) -
operations: []when the class is MCP-only (no HTTP routes) -
name:omitted insidemcp:array entries (the array key is the name) -
McpToolCollection(notMcpTool) for list-returning tools -
structuredContent: false+CallToolResultwhen bypassing JSON serialization - Nullable/union properties overridden with
#[ApiProperty(schema: …)]if the LLM rejects them -
validate: trueset explicitly where business constraints must run -
McpResourceuriis unique and usesresource://
이 스킬의 파일
1api-platform-mcp skill 질문
Claude Code에 api-platform-mcp skill을 어떻게 설치하나요?
npx degit api-platform/skillset/skills/api-platform-mcp ~/.claude/skills/api-platform-mcp를 실행합니다. Claude Code는 ~/.claude/skills(모든 프로젝트) 또는 .claude/skills(한 프로젝트)에서 skills를 로드하며, 설명이 작업과 일치할 때 skill을 사용합니다.
api-platform-mcp skill을 사용할 수 있는 클라이언트는 무엇인가요?
Agent Skills 형식을 읽는 모든 클라이언트(Claude Code, Codex, Gemini CLI, claude.ai(ZIP으로 업로드))가 사용할 수 있습니다. skill 내 스크립트는 클라이언트가 코드 실행을 허용하는 경우에만 실행됩니다.
AI 에이전트에게 아이템 목록을 반환하려면 어떻게 해야 하나요?
도구가 아이템 컬렉션을 반환해야 하는 경우 McpTool 대신 McpToolCollection 클래스를 사용하십시오.
MCP 도구에 대해 API Platform의 표준 검증이 실행되나요?
아니요, MCP 도구의 경우 API Platform의 검증 파이프라인이 기본적으로 비활성화되어 있습니다. 비즈니스 제약 조건을 실행하려면 validate: true를 명시적으로 설정해야 합니다.
LLM이 거부할 수 있는 nullable 속성은 어떻게 처리하나요?
#[ApiProperty(schema: [...])] 어트리뷰트를 사용하여 특정 속성에 대한 JSON-Schema를 재정의할 수 있습니다.