api-platform / api-platform/core
[MCP] Container fails to compile with symfony/mcp-bundle 0.13: non-existent service `mcp.registry`
- 主要語言
- PHP
- 星號
- 2.6k
- 分支
- 980
- 平均合併
- 2 天 5 小時
- 30 天內合併 PR
- 48
描述
## Summary
`symfony/mcp-bundle` **0.13.0** replaced its single, global `mcp.registry` service with one
registry **per configured server** (`mcp.server..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
```json
"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:
```bash
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.:
```yaml
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:
```php
$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:
```php
$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"](https://github.com/symfony/ai/blob/main/UPGRADE.md#upgrade-from-012-to-013):
> 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..registry`, … Autowire a specific server with `Mcp\Server $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..registry` is not sufficient, because
tagged request handlers are added to **every** server's builder:
```php
->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:
```php
$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:
```json
"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.
貢獻指南
評估
這個 Issue 還沒有評估資料。