Summary
symfony/mcp-bundle 0.13.0 replaced its single, global mcp.registry service with one
registry per configured server (mcp.server.<name>.registry), as part of the new
multi-server support. API Platform's MCP integration still hard-references the old service id,
so with api_platform.mcp.enabled: true (the default) the container no longer compiles at all:
In CheckExceptionOnInvalidReferenceBehaviorPass.php line 116:
The service "api_platform.mcp.list_handler" has a dependency on a non-existent
service "mcp.registry". Did you mean this: "form.registry"?
Because this is a container-compile failure, it takes down cache:clear, cache:warmup and
every console command in any environment where McpBundle is registered — it is not limited to
requests actually reaching the MCP endpoint. And since mcp is declared with canBeDisabled(),
the integration is on by default, so no opt-in is needed to hit this.
Separately, and arguably the more important half of this report: nothing prevents the bad
combination from being installed. api-platform/core declares only
"require-dev": {
"mcp/sdk": "^0.6",
"symfony/mcp-bundle": "dev-main"
}
There is no runtime constraint and no conflict entry, so composer update happily installs
mcp-bundle 0.13 alongside API Platform and the application only breaks later, at
container-compile time, with an error that does not name either package.
Environment
|
|
| api-platform/core |
4.3.17 |
| symfony/mcp-bundle |
0.13.0 broken, 0.12.0 OK |
| mcp/sdk |
0.8.1 (required by mcp-bundle 0.13; API Platform's dev constraint is still ^0.6) |
| Symfony |
8.1.5 |
| PHP |
8.5.10 |
| api_platform.mcp |
enabled: true (default — not set explicitly) |
Reproduction
On any API Platform app with McpBundle registered:
composer require symfony/mcp-bundle:^0.13
php bin/console cache:clear
The 0.13 config schema also changed (app + client_transports became a servers map with a
required registry key), so config/packages/mcp.yaml needs migrating first, e.g.:
mcp:
servers:
app:
registry: '*'
transports: { stdio: false, http: true }
With valid config, the failure above is what you get next.
Root cause
src/Symfony/Bundle/Resources/config/mcp/mcp.php:46 injects the removed service:
$services->set('api_platform.mcp.list_handler', ListHandler::class)
->args([
service('mcp.registry'), // <- removed in mcp-bundle 0.13
service('api_platform.mcp.loader'),
])
->tag('mcp.request_handler');
In mcp-bundle 0.13, McpBundle::configureServer() registers one registry per server:
$registryId = \sprintf('mcp.server.%s.registry', $name);
$container->register($registryId, Registry::class)
This rename is documented in
symfony/ai UPGRADE.md, "Upgrade from 0.12 to 0.13":
The per-server services replace their singleton counterparts: mcp.registry, mcp.server.builder,
mcp.server, mcp.session.store, mcp.middleware_factory and mcp.server.controller became
mcp.server.<name>.registry, … Autowire a specific server with Mcp\Server $<name>Server.
The good news is that this is the only incompatibility I found. The
mcp.loader, mcp.request_handler and mcp.notification_handler tags all still exist in 0.13
and are still consumed globally, via TaggedIteratorArgument on each server's builder. So
mcp.php:37, events.php:44 and state.php:44 are unaffected.
Suggested fix
Worth noting that swapping in a hardcoded mcp.server.<name>.registry is not sufficient, because
tagged request handlers are added to every server's builder:
->addMethodCall('addRequestHandlers', [new TaggedIteratorArgument('mcp.request_handler')])
so a single ListHandler instance holding one registry reference would serve the wrong registry
as soon as a second server is configured. The upgrade notes give the one-to-one service rename but
don't cover this case, since it only arises for a shared, tagged request handler like this one.
mcp-bundle 0.13 does expose a service locator for it, mapping server name to registry:
$this->registerServerLocator('mcp.server_locator.registry', array_keys($servers), 'registry', $container);
So ListHandler probably wants to take mcp.server_locator.registry and resolve the registry for
the server handling the current request, rather than a single injected Registry.
I'm happy to open a PR if you can confirm the intended direction — in particular whether
ListHandler should become server-aware, or whether API Platform would rather register one
handler per configured server.
In the meantime, a conflict entry would turn this into a clear resolver error instead of a
container-compile failure:
"conflict": {
"symfony/mcp-bundle": ">=0.13"
}
Workaround
Pin symfony/mcp-bundle to ^0.12 (and mcp/sdk to ^0.7), keeping the pre-0.13
mcp.yaml schema. Everything else in the symfony/ai 0.13 release train — ai-platform,
ai-agent, ai-bundle and the platform bridges — upgrades cleanly alongside API Platform 4.3.17;
mcp-bundle is the only package that has to be held back.
For anyone who needs mcp-bundle 0.13 more than they need the API Platform MCP tools, setting
api_platform: mcp: { enabled: false } also unblocks the container, at the cost of dropping every
#[ApiResource(mcp: [...])] tool.
Summary
symfony/mcp-bundle0.13.0 replaced its single, globalmcp.registryservice with oneregistry per configured server (
mcp.server.<name>.registry), as part of the newmulti-server support. API Platform's MCP integration still hard-references the old service id,
so with
api_platform.mcp.enabled: true(the default) the container no longer compiles at all:Because this is a container-compile failure, it takes down
cache:clear,cache:warmupandevery console command in any environment where McpBundle is registered — it is not limited to
requests actually reaching the MCP endpoint. And since
mcpis declared withcanBeDisabled(),the integration is on by default, so no opt-in is needed to hit this.
Separately, and arguably the more important half of this report: nothing prevents the bad
combination from being installed.
api-platform/coredeclares onlyThere is no runtime constraint and no
conflictentry, socomposer updatehappily installsmcp-bundle 0.13 alongside API Platform and the application only breaks later, at
container-compile time, with an error that does not name either package.
Environment
^0.6)enabled: true(default — not set explicitly)Reproduction
On any API Platform app with McpBundle registered:
The 0.13 config schema also changed (
app+client_transportsbecame aserversmap with arequired
registrykey), soconfig/packages/mcp.yamlneeds migrating first, e.g.:With valid config, the failure above is what you get next.
Root cause
src/Symfony/Bundle/Resources/config/mcp/mcp.php:46injects the removed service:In mcp-bundle 0.13,
McpBundle::configureServer()registers one registry per server:This rename is documented in
symfony/ai UPGRADE.md, "Upgrade from 0.12 to 0.13":
The good news is that this is the only incompatibility I found. The
mcp.loader,mcp.request_handlerandmcp.notification_handlertags all still exist in 0.13and are still consumed globally, via
TaggedIteratorArgumenton each server's builder. Somcp.php:37,events.php:44andstate.php:44are unaffected.Suggested fix
Worth noting that swapping in a hardcoded
mcp.server.<name>.registryis not sufficient, becausetagged request handlers are added to every server's builder:
so a single
ListHandlerinstance holding one registry reference would serve the wrong registryas soon as a second server is configured. The upgrade notes give the one-to-one service rename but
don't cover this case, since it only arises for a shared, tagged request handler like this one.
mcp-bundle 0.13 does expose a service locator for it, mapping server name to registry:
So
ListHandlerprobably wants to takemcp.server_locator.registryand resolve the registry forthe server handling the current request, rather than a single injected
Registry.I'm happy to open a PR if you can confirm the intended direction — in particular whether
ListHandlershould become server-aware, or whether API Platform would rather register onehandler per configured server.
In the meantime, a
conflictentry would turn this into a clear resolver error instead of acontainer-compile failure:
Workaround
Pin
symfony/mcp-bundleto^0.12(andmcp/sdkto^0.7), keeping the pre-0.13mcp.yamlschema. Everything else in thesymfony/ai0.13 release train —ai-platform,ai-agent,ai-bundleand the platform bridges — upgrades cleanly alongside API Platform 4.3.17;mcp-bundleis the only package that has to be held back.For anyone who needs mcp-bundle 0.13 more than they need the API Platform MCP tools, setting
api_platform: mcp: { enabled: false }also unblocks the container, at the cost of dropping every#[ApiResource(mcp: [...])]tool.