api-platform-mcp Skill
Stellt API Platform Ressourcen über PHP-Attribute als Model Context Protocol Tools und Resources für AI Agents bereit.
- GitHub Stars
- 29
- Dateien
- 1
- Letzter Commit
- 22. Okt. 2026
- Lizenz
- —
- Erlaubte Tools
- —
Was macht der api-platform-mcp Skill?
api-platform-mcp ist ein Agent Skill. Stellt API Platform Ressourcen über PHP-Attribute als Model Context Protocol Tools und Resources für AI Agents bereit.
Zusammenfassung erzeugt aus der SKILL.md des Skills.
Über den api-platform-mcp skill
Dieses Skill ermöglicht es Entwicklern, die API Platform zu nutzen, um PHP-basierte API-Ressourcen als Model Context Protocol Tools und Resources bereitzustellen. Es erlaubt AI Agents, deine bestehende Backend-Logik zu entdecken und mit ihr zu interagieren, indem PHP-Klassen in aufrufbare Tools oder Read-only Resources transformiert werden. Dies geschieht durch spezialisierte Attribute wie #[McpTool] für die Befehlsausführung und #[McpResource] zum Abrufen von Inhalten wie Dokumentationen oder Konfigurationen.
Entwickler können dies in Symfony- oder Laravel-Anwendungen integrieren, um strukturierte Daten oder benutzerdefinierte Responses bereitzustellen. Das System nutzt deinen bestehenden Metadata-Stack, einschließlich State Processors, Providern und Validierung. Du kannst spezifische Input-Schemas über DTOs definieren, Collections mit McpToolCollection handhaben oder die Standard-JSON-Serialisierung umgehen, indem du ein CallToolResult zurückgibst. Dies stellt sicher, dass ein LLM mit deiner API über standardmäßige tools/call und resources/read Operationen interagieren kann, ohne dass traditionelle HTTP-Routes benötigt werden.
Was ein agent damit machen kann
- 1Backend-Logik als Tools bereitstellenVerwandle eine spezifische PHP-Klasse in ein aufrufbares Tool, das ein AI Agent zur Datenverarbeitung nutzen kann.
- 2Business Rules für Agent-Inputs erzwingenStelle sicher, dass die von einem AI Agent gesendeten Daten spezifischen Validierungsregeln wie E-Mail-Formaten oder String-Längen entsprechen.
Geschrieben basierend auf dem SKILL.md des skills. Jeder use case wurde gegen ein zitat daraus geprüft.
So installierst du den api-platform-mcp Skill
Jeder Befehl kopiert den Skill-Ordner in das Skills-Verzeichnis des Clients. Starte den Client neu oder beginne eine neue Session, um ihn zu laden.Den api-platform-mcp Skill in Plugin installieren
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Den api-platform-mcp Skill in Claude Code installieren
~/.claude/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp ~/.claude/skills/api-platform-mcpDen api-platform-mcp Skill in Claude Code (project) installieren
.claude/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp .claude/skills/api-platform-mcpDen api-platform-mcp Skill in Codex installieren
~/.agents/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp ~/.agents/skills/api-platform-mcpDen api-platform-mcp Skill in Gemini CLI installieren
~/.gemini/skills/api-platform-mcp/SKILL.md
$ npx degit api-platform/skillset/skills/api-platform-mcp ~/.gemini/skills/api-platform-mcpDen api-platform-mcp Skill in Claude.ai installieren
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
Auf GitHub ansehenMCP: 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://
Dateien in diesem Skill
1api-platform-mcp Skill-Fragen
Wie installiere ich den api-platform-mcp Skill in Claude Code?
Führe npx degit api-platform/skillset/skills/api-platform-mcp ~/.claude/skills/api-platform-mcp aus. Claude Code lädt Skills aus ~/.claude/skills (alle Projekte) oder .claude/skills (ein Projekt) und nutzt einen Skill, wenn seine Beschreibung zur Aufgabe passt.
Welche Clients können den api-platform-mcp Skill nutzen?
Jeder Client, der das Agent Skills-Format liest: Claude Code, Codex, Gemini CLI und claude.ai (als ZIP hochladen). Skripte im Skill laufen nur dort, wo der Client Codeausführung erlaubt.
Wie kann ich eine Liste von Items an einen AI Agent zurückgeben?
Verwende die Klasse McpToolCollection anstelle von McpTool, wenn ein Tool eine Collection von Items zurückgeben soll.
Führt API Platform die Standard-Validierung für MCP Tools aus?
Nein, die Validierungs-Pipeline von API Platform ist für MCP Tools standardmäßig deaktiviert; du musst validate: true explizit setzen, um Business Constraints auszuführen.
Wie gehe ich mit Nullable-Properties um, die von LLMs abgelehnt werden könnten?
Du kannst das JSON-Schema für spezifische Properties mithilfe des #[ApiProperty(schema: [...])] Attributes überschreiben.