api-platform/mcp
Experimental API Platform MCP component. Integrates the Model Context Protocol (MCP) PHP SDK with API Platform and Symfony’s MCP Bundle. Read-only split from api-platform/core; report issues and PRs in the core repository.
Prerequisites
composer require api-platform/mcp
api-platform/core is installed (this package is a read-only split).First Configuration
Register the MCP bundle in config/bundles.php (Symfony) or equivalent Laravel service provider:
// For Symfony (if using API Platform)
return [
ApiPlatform\McpBundle\McpBundle::class => ['all' => true],
];
For Laravel, create a service provider to bootstrap MCP:
// app/Providers/McpServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use ApiPlatform\McpBundle\McpBundle;
class McpServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->register(McpBundle::class);
}
}
Register the provider in config/app.php:
'providers' => [
// ...
App\Providers\McpServiceProvider::class,
],
Enable MCP for a Resource Annotate an API resource class with MCP-specific metadata. Example:
// src/Entity/Book.php
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Mcp\Annotation\McpContext;
#[ApiResource]
#[McpContext(
context: "https://example.org/contexts/Book.jsonld",
types: ["Book"]
)]
class Book
{
// ...
}
Test the Integration
HTTP/1.1 200 OK
Content-Type: application/ld+json
Link: <https://example.org/contexts/Book.jsonld>; rel="http://www.w3.org/ns/hydra/context";
Model Annotation Pattern
#[McpContext] to define the JSON-LD context and types for each resource.#[McpContext(
context: "https://example.org/contexts/Author.jsonld",
types: ["Author"],
embedded: ["Book" => "https://example.org/contexts/Book.jsonld"]
)]
class Author { ... }
Context Resolution
@context URIs during serialization. Override resolution logic in a custom context resolver:
// src/Resolver/CustomContextResolver.php
use ApiPlatform\Mcp\ContextResolverInterface;
class CustomContextResolver implements ContextResolverInterface
{
public function resolve(string $contextUrl): string
{
// Custom logic (e.g., cache, remote fetch)
return file_get_contents($contextUrl);
}
}
$this->app->bind(ContextResolverInterface::class, CustomContextResolver::class);
Hybrid API Design
ApiResource class:
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Mcp\Annotation\McpOperation;
#[ApiResource(
operations: [
new Get(
uriTemplate: '/books/{id}',
output: Book::class,
name: 'get_book'
),
new McpOperation(
uriTemplate: '/books/{id}/mcp',
output: Book::class,
name: 'get_book_mcp',
formats: ['ld+json']
)
]
)]
class Book { ... }
Validation Layer
use Symfony\Component\Validator\Constraints as Assert;
use ApiPlatform\Mcp\Validator\Constraints\McpContext;
#[Assert\Valid]
#[McpContext(
context: "https://example.org/contexts/Book.jsonld",
types: ["Book"]
)]
class Book { ... }
Leverage API Platform’s Hydra Combine MCP with Hydra for richer API documentation:
# config/packages/api_platform.yaml
api_platform:
formats:
jsonld: ['application/ld+json']
mcp:
hydra_context: "https://api-platform.com/contexts/hydra.jsonld"
Caching Contexts Cache resolved contexts to improve performance:
use Symfony\Contracts\Cache\CacheInterface;
class CachedContextResolver implements ContextResolverInterface
{
public function __construct(private CacheInterface $cache) {}
public function resolve(string $contextUrl): string
{
return $this->cache->get($contextUrl, fn() => file_get_contents($contextUrl));
}
}
Laravel-Specific Adaptations
$this->app->bind(
\ApiPlatform\Mcp\ContextResolverInterface::class,
\App\Services\CustomContextResolver::class
);
// app/Http/Middleware/HandleMcpRequests.php
use ApiPlatform\Mcp\McpRequest;
class HandleMcpRequests
{
public function handle($request, \Closure $next)
{
if ($request->wantsJsonLd()) {
$request = new McpRequest($request->all());
}
return $next($request);
}
}
Experimental Status
api-platform/core. Issues/PRs must be submitted to the core repo.Annotation Overhead
#[McpContext]) are not backward compatible with standard API Platform resources. Refactoring existing models may be required.Context Resolution Failures
@context URIs are unreachable, MCP will throw exceptions. Always:
public function resolve(string $contextUrl): string
{
try {
return file_get_contents($contextUrl);
} catch (\Exception $e) {
// Fallback to a local context
return file_get_contents(__DIR__.'/fallback-context.jsonld');
}
}
Performance Bottlenecks
php -d memory_limit=-1 vendor/bin/debug:profiler
Tooling Gaps
@property annotations for hints.composer require digitalbazaar/jsonld
Symfony/Laravel Tensions
api_platform.route middleware to avoid conflicts:
Route::middleware(['api_platform.route'])->group(function () {
// MCP-enabled routes
});
Enable MCP Debugging
Add this to config/packages/dev/api_platform.yaml:
api_platform:
mcp:
debug: true
This logs context resolution and serialization steps.
Inspect Headers
Use telescope or laravel-debugbar to inspect MCP-specific headers:
Link: <https://example.org/contexts/Book.jsonld>; rel="http://www.w3.org/ns/hydra/context"
Content-Type: application/ld+json
Validate JSON-LD Use the JSON-LD Validator to check responses:
curl -H "Accept: application/ld+json" http://your-api/books/1 | \
jq -r . > response.jsonld
Common Errors
McpContextNotFoundException: The @context URL is invalid. VerifyHow can I help you explore Laravel packages today?