Welcome everyone. Today I want to show you Symfony Mate. The core idea is simple: AI coding assistants are powerful, but they're still blind to what your application is actually doing at runtime. Mate gives them access to the right runtime information, so they can stop guessing and start diagnosing.
My name is Johannes Wachter. I'm a core developer at Sulu CMS, I maintain symfony/ai-mate, and I've been working with Symfony since 2012. Father of two — so most of my open source contributions happen after 20:00, once the kids are asleep and my "bread" job is done. I care a lot about open source, developer experience, and lately about how we make AI tools actually useful for real PHP applications.
This talk started long before Mate existed. At SymfonyCon Vienna in 2024, I spoke about my own AI library, modelflow-ai. So when symfony/ai launched in mid 2025, I was honestly skeptical — another AI abstraction? I already had one, and I already had strong opinions. That changed in Amsterdam at SymfonyCon in November 2025. Fabien talked about how AI could improve developer experience — shaped by the community. Christopher Hertel was interested in bringing modelflow-ai ideas into symfony/ai. Tobias Nyholm got immediately excited when I told him about the MCP Development Server idea. At the conference I opened my first PR to symfony/ai, and Tobias and I started building the first Mate prototype, side by side, right there. That's how we got here.
Today AI assistants are everywhere: Claude Code, Codex, Copilot, Cursor, JetBrains AI. They can read code, search files, write patches. But there's still a hard limit — by default they don't know what your running application is doing. They don't see the profiler. They don't see your logs in a structured way. They don't know what your container actually resolved to, or what's in your cache files. So when we ask them to debug a real problem, they have to guess from static code alone.
Take a very normal prompt: "This page is slow, find the performance problem." Without runtime access, the assistant starts reading files — the controller, the entities, the template, maybe the Doctrine config, maybe some repositories. It's trying to reconstruct the execution path from code alone. Sometimes that works. Sometimes it finds the right thing after enough searching. But it might also suggest something completely unrelated. The process is noisy, expensive, and unreliable. And in a real project with hundreds of files, it gets worse — more files to read, more wrong turns to take.
So what's the actual cost of this approach? Every file the AI reads costs tokens. Most of those files turn out not to matter — they're noise. The results are non-deterministic: ask the same question twice, you might get two different answers. And worst of all, you can't optimize this process. More files in your project just means more guessing, more tokens, more wrong turns. What if there was a way to skip the guessing entirely? What if the AI could go straight to the answer?
There is an answer. MCP — the Model Context Protocol. Think of it as a standard interface: on one side your AI assistant, on the other side your tools, talking over a common protocol. The AI can discover which tools are available and call them when it needs them. People say tools cost tokens — and that's true. Tool descriptions, tool calls, and responses all cost tokens. But the real cost is not having a good tool. Without one, the AI burns thousands of tokens reading files that don't matter. A good tool is different: one focused call, compact structured output, deterministic behavior, and something you can improve over time. The PHP MCP SDK was built as a collaboration between Symfony, the PHP Foundation, and the MCP project. Tobias goes deep on MCP right after this talk — I won't steal his thunder. Today I want to focus on what we built with it.
You might think: "I already have a CLI for that." And you're right — CLIs are great. I use the Symfony CLI and Composer CLI myself for many tasks. But MCP adds something CLIs can't: interactive context. The AI knows from tool descriptions exactly what each tool does and when to call it — it doesn't have to guess, you don't have to script it. And when there's no CLI at all — say for your Graylog instance or an internal admin API — you can wrap any HTTP endpoint as an MCP tool. It's just a PHP class. MCP is not replacing CLIs. It's the layer that lets AI use them, and everything else, intelligently.
That's where Mate comes in. Mate is an MCP server built for PHP developers, with Symfony support as a first-class story. It doesn't replace your assistant — it lets your assistant see the parts of your app that matter for debugging and diagnosis.
Mate is a development-only MCP server for PHP and Symfony applications. It exposes profiler data, logs, container information, PHP environment details, and custom tools you define yourself. A lot of Symfony AI work is about letting your application use AI — the Platform, the Agent, the Store. Mate does the opposite: it lets AI use your application. It's the outside-in complement.
Let me show you the problem concretely. I have a small Symfony blog application — 100 posts, each with comments. Intentionally simple, but it has a classic performance problem. Mate is not installed yet, so from the assistant's view this is just a normal codebase. I ask the assistant to find the performance issue. Watch what it does — it starts reading files: the controller, the entity, maybe the repository, then the Twig template. It's trying to reconstruct at runtime what the application does, purely from static code. *(while the AI is working)* This is the blind search. Every file costs tokens. Most of it is noise. And the model has no way to know which file matters until it has already read the others. It might get there eventually — but think about a real project with hundreds of files. This doesn't scale.
Three commands. That's the full setup. *(run composer require)* While this installs — Composer picks up Mate and registers the MCP server entry point automatically via the Composer plugin. No manual wiring. *(run mate init)* This creates the local Mate configuration — where to find the running app, which extensions to load. *(run composer require extension)* And the Symfony extension adds the profiler, container, and log tools. From this point on the assistant has a runtime-aware path. It doesn't have to guess anymore — it can ask.
Same question, same app, same problem. Let's see what changes. *(while Claude is working)* Notice what it does first this time — it calls a tool. It doesn't start reading files. It goes straight to the profiler. *(while waiting for the result)* This is the key shift. The assistant isn't smarter. Same model, same knowledge. The difference is that it now has access to runtime data. Instead of inferring what might be slow, it can look at what actually ran. *(once the result is back)* And there it is. One tool call, and the shape of the problem is completely clear.
This is exactly what a good tool response looks like: compact, structured, actionable. The AI doesn't need to read your code — it gets the answer directly. One call, instant diagnosis. That's the point: the profiler always knows, guessing never does. And notice how human this feels: open the page, read the profiler output, spot the problem — then open only the one file you need to write the fix.
Mate isn't only about built-in tools. The more interesting part is that you can bake your own domain knowledge into tools. If there's a recurring debugging question in your company or project, you can turn that into a focused MCP tool. It's a PHP class with the McpTool attribute. Constructor injection works — full Symfony DI support inside Mate's own container. You control what comes back. You decide what matters, what's noise, and what shape helps the assistant reason correctly. Over time the tool gets better, and every assistant benefits. And if you want to share your tools, make it an extension. There's an extension template at github.com/MatesOfMate/extension-template. Declare your scan directories in composer.json, write an INSTRUCTIONS.md, publish on Packagist. That's it.
So far I've shown why this matters. Now I want to show how Mate is built, because some of the design decisions are the reason it works cleanly in real projects. Three decisions in particular: own container, extension discovery, and the extension pattern.
The first important decision is that Mate builds and uses its own Symfony DI container. It doesn't inject itself into your application's container, and it doesn't try to become part of your runtime. That separation matters. Mate is a separate process with its own lifecycle, configuration, and services. It keeps the integration clean and avoids surprises. And importantly: Mate doesn't need a working app container. If your application has DI issues — a broken service definition, a missing parameter — Mate still works. It's completely independent.
The second piece is extension discovery. Extensions describe themselves through Composer metadata — scan directories, includes, and instructions. That makes the setup familiar for PHP developers because it follows the same pattern as PHPStan or PHPUnit extensions. Mate scans installed.json to find all extensions. Since v0.7, the Composer plugin handles this automatically on install — no more manual mate discover step. The important thing is that tools are not hardcoded into one big package. The system is designed so capabilities can be added, shared, and evolved as separate extensions.
The third design decision is the extension pattern. Mate core isn't tied to Symfony. Symfony-specific features live in a Symfony extension, Monolog in a Monolog extension, Sulu in a Sulu extension, and so on. That gives you two things. First, the core stays reusable for other PHP applications — you can use Mate with Laravel, with plain PHP, with anything. Second, growing the ecosystem becomes much easier because framework-specific integrations don't have to live in the core. The extensions are optional add-ons.
Extensions can ship INSTRUCTIONS.md files that tell the assistant when a tool should be used and when it shouldn't. It's easy to underestimate, but important for token efficiency: if you don't teach the assistant when to use a tool, it may still waste tokens trying the wrong path. Good instructions make good tools cheaper — and the AI doesn't have to guess which tool fits.
Whenever you expose runtime data to an AI tool, security has to be part of the design, not an afterthought. Mate automatically redacts sensitive data from profiler output — cookies, auth headers, session data, and sensitive environment values. That gives you a safe default for development use without asking you to build your own filtering first. And new extensions are automatically discovered when you install them via Composer — and you can disable any extension at any time if you don't need it.
Mate isn't only a package — it's becoming an ecosystem. That matters because no single team can think of every useful debugging or inspection tool. The stronger the extension story becomes, the more useful Mate becomes in real projects.
There are official extensions, and there are community extensions for things like PHPUnit, PHPStan, and Composer. We also have the Sulu Mate extension for Sulu CMS and the database extension by ineersa for database schema access. The shared idea is always the same: don't dump raw terminal output if you can return structured, high-signal information instead. Extension authors aren't just exposing commands. They're curating context.
Let me be honest about strengths and weaknesses. Strengths first: Mate is framework-agnostic at the core — it works with any PHP app. It's security-conscious by default with auto-redaction. It supports a wide range of Symfony versions — from the LTS releases all the way to current. And the developer tooling is solid — a debug CLI, tool inspection, and the Composer plugin for auto-discovery.
Now the drawbacks — because this keeps the talk credible. MCP does add tokens, and a badly designed tool that returns too much data wastes more than it saves. There are dependency conflicts, since Mate shares your Composer dependencies — a PHAR distribution is planned to fix that. Stdio is the only transport, but that's by design — it's the standard MCP transport that all clients support. And it's pre-1.0, so the API is still evolving. Mate is not magic. It only helps if the tool design is good. The quality of the tool determines whether you save tokens or waste them.
MCP tools are an investment. If the tool is vague, noisy, or badly scoped, it's a tax. If the tool is focused and shaped around the actual question, it saves time, tokens, and wrong turns. Your domain knowledge, baked into a good tool, is usually more valuable than asking the model to reverse-engineer your application from files. That's why extension quality matters — and why INSTRUCTIONS.md exists.
Nicolas this morning — "the cost of statelessness." Every request starts from zero: Redis Sentinel failover? Poll. Feature flags? Evaluate. Weather data? Fetch. PHP can't listen, it can only ask. Sounds familiar? AI assistants work exactly the same way. Each conversation starts from zero. They have no memory of the last request. They can only ask. The question is — what are they asking, and who is answering? Without Mate, they ask your files. With Mate, they can ask the profiler, the container, the logs — things that actually know.
Dave Liddament earlier today showed this loop — AI agents don't just generate code, they plan first, then generate, then iterate. It's a real workflow now. But here's the thing. That plan is built on context the agent gathered. If the context came from reading ten files and guessing, the plan is a guess. If the context came from the profiler — deterministic, structured, true — the plan is grounded. Better context doesn't just change the answer. It changes the entire plan upstream of the answer.
Dave's pyramid — I loved this. Reliable AI-assisted development stacks up like this: code review at the top, plan mode below that, then CLAUDE.md, Skills, Agents, and at the very base — deterministic checks. Tests. Static analysis. Mate lives at that base. The profiler, the container, the logs — they're deterministic. They don't guess. They know. And everything above this base only works because the base is solid. That's the whole argument in one picture: if you want AI agents to help with real work, give them a base they can stand on.
Pivot from present value to future direction. Where we are today, where we're headed: better packaging, less friction, and a bigger ecosystem. Don't overpromise — just show a credible path.
Two recent releases worth mentioning. v0.7 landed two weeks ago with four key improvements. The Composer plugin auto-runs mate discover on install — no more manual step. Codex wrappers for OpenAI integration. Agent instruction materialization — extension INSTRUCTIONS.md files are automatically merged into your agent configuration, so the AI always has the right guidance without you wiring it up manually. And we unified 16 tools down to 9, cutting about 500 tokens from every request. v0.8 dropped two days ago. More about the broader symfony/ai ecosystem than Mate itself, but worth mentioning it's fresh. Up next: PHAR distribution to eliminate dependency conflicts completely. We're also experimenting with knowledge extensions — project and framework-specific knowledge bases, richer context beyond just tools. And growing the extension ecosystem with more MatesOfMate packages.
Open source momentum usually starts with a specific idea, a few conversations, and one first contribution. Thanks to Christopher Hertel for leading Symfony AI and welcoming contributions. Tobias Nyholm for his energy, his MCP expertise, and for building that first Mate prototype together. Oskar for his contributions and feedback. Fabien for the vision that brought everyone together. And the entire community. Mate didn't appear fully formed. It came from discussions, shared curiosity, and people willing to build in public. That's still how most good things in this community happen. So if you have an idea — for a tool, an extension, a component — find the people who share your excitement. Talk to them. Open that first PR. You don't need permission. The Symfony community is built on people who just did it. So go do it.
Final message, keep it simple — no new information. If you want AI assistants to help with real software problems, don't just give them more context. Give them better context. That's what Mate is for.
I'm happy to take your questions. You can also find me on Twitter/X at @wachterjohannes, or catch me in the hallway afterwards.
Leave this one on screen during Q&A so people can scan the QR and follow the links. Mate docs on symfony.com, the symfony/ai repository, MatesOfMate for community extensions, and the MCP spec itself. Slides and the full demo are on my GitHub. Tobias Nyholm is up next at 16:45 with "Make your AI useful with MCP". Christopher Hertel tomorrow morning with "Symfony AI in Action".