cd /news/ai-agents/deprecating-my-symfony-profiler-mcp-… · home topics ai-agents article
[ARTICLE · art-131955] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Deprecating My Symfony Profiler MCP Bundle: Right About the Problem, Half-Wrong About the Solution

A developer deprecated their mcp-profiler-bundle, a Symfony bundle that exposed the Symfony Profiler to AI coding agents via the Model Context Protocol, after Symfony shipped its own official solution, Symfony AI Mate. The bundle, which reached roughly 5,900 Packagist installs, was superseded by Mate, which later removed its MCP server in version 0.13 in favor of plain CLI commands paired with Agent Skills; contributor Johannes Wachter measured that the bare CLI was invoked in 0 of 20 agent runs, versus 5 of 20 with MCP and 10 of 10 on one task with Skills and project instructions.

by read6 min views1 publishedSep 16, 2026

In March 2025 I built mcp-profiler-bundle, a Symfony bundle that let AI coding agents read the Symfony Profiler: the requests your app just served, the queries they ran, the exceptions they threw. The bet was simple. An agent that can see what the app actually did should debug it better than one that can only read the source.

This week I deprecated it. Symfony now ships the official version of that idea, and rereading my code for the deprecation notice left me with an uncomfortable verdict: I was right about the problem, and half-wrong about the solution.

MCP, the Model Context Protocol, is a JSON-RPC protocol that lets a client like Claude Desktop, Cursor or Cline call tools on a local server. My bundle added a bin/console mcp:server:run command that spoke it over stdio and exposed four tools: profiler:list, profiler:get_by_token, profiler:get_collectors and profiler:get_collector.

There was no official PHP SDK back then. My first commit leaned on a community library, james2037/mcp-php-server, which only existed as dev-master. By the 0.1.0 tag on 31 March 2025 it was gone, and the whole protocol fit in one match:

// Command/RunMCPServerCommand.php
$payload = json_decode($line, true, JSON_THROW_ON_ERROR);
$method = $payload['method'] ?? null;

$response = match ($method) {
    'initialize' => $this->sendInitialize(),
    'tools/list' => $this->sendToolsList(),
    'tools/call' => $this->callTool($payload['params'] ?? []),
    'notifications/initialized' => null,
    default => $this->sendProtocolError(\sprintf('Method "%s" not found', $method)),
};

Hold on to that first line. It comes back later.

It found some users: 11 stars, 2 forks and roughly 5,900 Packagist installs. Version 0.2.0 added multi-kernel (APP_ID) support a week after launch, and in February 2026 an outside contributor, Rhodri Pugh, sent a PHP 8.4 fix.

The idea is official now. In September 2025, Symfony announced the official PHP MCP SDK, built with The PHP Foundation and Anthropic's MCP team. On 23 December 2025, Symfony AI Mate shipped its first release, about nine months after my 0.1.0: an MCP dev server giving coding agents access to a Symfony app's internals. The container came first, profiler access landed in 0.3 in January 2026, and it handles multi-kernel apps too.

Symfony's spotlight on Mate opens on the same premise: an agent can read all your code and still not know what happened on the last request. Mate is past 100,000 installs a month.

In August 2026, Mate 0.13 deleted its MCP server (PR #2380). It no longer depends on mcp/sdk, and the agent runs plain commands instead, like these from Mate's docs and its profiler skill:

vendor/bin/mate tools:list
vendor/bin/mate tools:call symfony-profiler-list --statusCode=500 --limit=5
vendor/bin/mate resources:read symfony-profiler://profile/<token>

A bare CLI has a problem an MCP server doesn't: nothing tells the agent it exists. Mate's answer is Agent Skills — SKILL.md files installed into .agents/skills/ (mirrored into .claude/skills/) that say when to reach for which tool. The profiler skill reads like a triage procedure: filter for the failing request instead of scrolling, check which collectors it has, then read them in symptom order. exception first for a 5xx; time, db, then memory for a slow request.

Johannes Wachter, who made that change, then measured it: Claude Haiku, two tasks with injected performance bugs, ten runs per setup, counting whether the agent touched Mate at all. The bare CLI: 0 runs out of 20. The MCP server: 5 out of 20. The CLI with Skills and project instructions: 10 out of 10 on one task, 5 out of 10 on the harder one. He calls it a pattern from a small sample, not a proven effect, and concludes that "transport alone wasn't the deciding variable. Visibility was."

That's the half I got wrong. I treated exposing the data as the product. Tools give the agent eyes; skills tell it where to look. My bundle handed over four tools with one-line descriptions ("Lists available profiler tokens.") and left the agent to work out the rest.

mcp-profiler-bundle (2025) Symfony AI Mate 0.13 (2026)
How the agent calls it MCP over stdio, hand-written JSON-RPC plain CLI, no server process
Needs the app to boot yes, it's a bin/console command no, reads the profiler and the dumped container from disk
Finding a profile the last N ( limit ) method, URL, IP, status, date range, kernel context
Collector output raw collector data or VarDumper dumps formatters for Doctrine, exceptions, logs, mail, memory, requests, timing and translations
Secrets no redaction cookies, session data, auth headers and secret env vars redacted
Prompt injection nothing output wrapped and marked as untrusted data
Telling the agent what to do four one-line tool descriptions Agent Skills plus AGENTS.md /CLAUDE.md
Beyond the profiler nothing service container, Monolog logs

Rereading the code was humbling. PHPStan flags the first two of these problems in CI, on a step I'd marked continue-on-error: true the day I set up CI:

 ------ -----------------------------------------------------------------------
  Line   Command/RunMCPServerCommand.php
 ------ -----------------------------------------------------------------------
  40     While loop condition is always true.
         🪪  while.alwaysTrue
  61     Unreachable statement - code above always terminates.
         🪪  deadCode.unreachable
  68     Constant JSON_THROW_ON_ERROR is not allowed for parameter #3 $depth
         of function json_decode.
         🪪  argument.invalidConstant

fgets() returns false, and the loop sleeps a millisecond and tries again, forever.JSON_THROW_ON_ERROR sits in json_decode()'s $depth parameter, not $flags, so bad input decodes to null. Instead of a -32700 parse error with a -32601 Method "" not found with id 0. And any other notification, like notifications/cancelled, gets an error reply, which JSON-RPC 2.0 forbids. profilerlist and profilerget_by_token, and the README documented different names altogether. ip, url, method and status_code. The rewrite kept them in ProfilerList::execute() but put only limit in the tool schema..env values into $_SERVER, that includes APP_SECRET and DATABASE_URL. profiler:get_collector dumped whatever the agent asked for, unfiltered, and the optional bin/run-mcp.sh wrapper (adapted from var/mcp/stdout.log. bin/console didn't start, and neither did the server. Mate reads everything from disk, so it still answers when the app won't boot. The protocol has moved on, too. MCP's 2026-07-28 revision removed the initialize handshake my match is built around and made a new server/discover method mandatory.

None of this is a verdict against MCP, by the way. symfony/mcp-bundle, for building your own MCP servers, does over 600,000 installs a month. The shift is narrower: for a dev tool the agent runs on your machine, a CLI plus skills got picked up at least as reliably, without a server process to babysit.

So I retired it properly. PR #14 puts a deprecation notice at the top of the README, with the migration:

composer require --dev symfony/ai-mate
vendor/bin/mate init
composer require --dev symfony/ai-symfony-mate-extension symfony/ai-monolog-mate-extension
vendor/bin/mate discover

mate discover also installs the skills. For frontend work, Simon André's Symfony UX skills cover Stimulus, Turbo, Twig Components and Live Components.

Even deprecating it took a fix. CI had been red since June, failing on the PHP CS Fixer step, and the log on the deprecation PR showed the culprit: with no config file, PHP CS Fixer 3.95 opens an interactive init wizard, which crashes in CI with Failed to read template file. A .php-cs-fixer.dist.php turned it green.

0.2.1 is the final release, Rhodri's fix included, and the repository stays public. The lesson I'm keeping: access was the easy half. The half that makes it useful is deciding what the agent should look at, in what order, and what it must never see.

── more in #ai-agents 4 stories · sorted by recency
── more on @symfony 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/deprecating-my-symfo…] indexed:0 read:6min 2026-09-16 ·