symfony/ai-mate
MCP server that lets AI assistants interact with PHP and Symfony applications through standardized tools. A development-only tool: install with composer require --dev symfony/ai-mate, then run vendor/bin/mate init. An optional Composer plugin keeps extension discovery fresh.
Add the package as a dev dependency and bootstrap it from the project root:
composer require --dev symfony/ai-mate
vendor/bin/mate init
init rewrites composer.json (adding the script/autoload wiring it needs), so run it once, review the diff, then commit. If your composer.json contains non-ASCII (author names, descriptions), 0.14 fixes the rewriting bug that mangled those bytes — worth upgrading before running init for the first time.
Where to look first:
vendor/bin/mate list — the full command surface.vendor/bin/mate tools:list — as of 0.14 this now prints each tool's arguments, so it doubles as a quick reference card.vendor/bin/mate skills:install --help — skills are the fastest thing to get value from.First use case: install a skill bundle, then exercise one tool end-to-end from the CLI before wiring any agent to it:
vendor/bin/mate skills:install
vendor/bin/mate tools:inspect some_tool
vendor/bin/mate tools:call some_tool '{"id": 1}'
If that loop works, the config, env file, and API keys are all sane — which is exactly the set of things that go wrong later.
Debug loop: list → inspect → call. tools:list gives you names plus argument signatures; tools:inspect gives the full schema; tools:call executes. When a call fails, read the error — since 0.14 tools:call failures explicitly point you at tools:inspect, which is almost always telling you the argument shape is wrong, not the values.
Treat tools:call output as human-format, not machine-format. In 0.14 the pretty renderer stops padding to the widest column (cosmetic) and auto-falls back to JSON rendering for large results. That fallback is content-dependent, so don't build parsers or snapshot assertions on top of the pretty table. If you need stable output in scripts, request JSON explicitly where the flag exists, or accept that large payloads arrive as JSON.
Keep tool results small. The pretty renderer is genuinely nicer for scanning, and it's what you get under the auto-fallback threshold. A Laravel tool that wraps Artisan::call() should return a trimmed summary, not raw command output — both for token economy in agent contexts and to stay in the readable render path.
Laravel integration shape. Expose artisan commands and a few read-only Eloquent queries as tools; avoid tools that mutate state without an explicit confirmation argument. Skills are prose + frontmatter, so a project-specific skill ("how we run migrations here", "our queue convention") is often more valuable than another tool. The demo Mate skills synced in 0.14 are the canonical examples to copy structure from.
Per-environment env files. Set mate.env_file=.env.local (or similar) rather than relying on defaults. Since 0.14 symfony/dotenv is a real dependency, so this works without you adding it manually — but note mate loads its own env file, independent of Laravel's bootstrap.
CI usage. skills:install now emits a per-skill status table, which makes partial failures visible in CI logs without parsing exit codes. Good place to fail the build if a skill didn't land.
Debug logging. Set MATE_DEBUG_LOG_FILE=storage/logs/mate.log. Relative paths now resolve against the project root (and absolute paths are accepted), so the Laravel-conventional path works regardless of which subdirectory you invoke mate from.
has_api_key false positives (fixed in 0.14). Prior versions reported true for unset env vars. If you previously chased phantom auth failures, upgrade and re-verify — the tool was lying about configuration state.mate.env_file needed symfony/dotenv before 0.14. The setting existed but the dependency wasn't required, so it silently did nothing in a clean install. On 0.14+ it's required; if you're pinned below that, add the dependency yourself.MATE_DEBUG_LOG_FILE resolution changed. Relative paths used to resolve against the working directory, so invoking mate from a subdirectory scattered logs. Absolute paths are now supported — prefer them if you have any wrapper scripts or Docker entrypoints that cd around.tools:call table output in tests, the removal of column padding will fail those assertions. Regenerate fixtures on upgrade.init mutates a tracked file. Always inspect the composer.json diff; it's the most common source of "why did my PR touch composer.json" noise.^0.14 and re-run your scripts after each bump, especially the ones that scrape terminal output.tools:inspect on your own tool to see how the schema is presented to agents. If the generated schema looks wrong to you, it looks wrong to the model too. That feedback loop is the single highest-value habit with this package.How can I help you explore Laravel packages today?