From 308f45007a0c736e4087068214ac89808659c4c2 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 5 Jun 2026 10:28:11 +0200 Subject: [PATCH 1/4] feat(dev): add Symfony AI Mate MCP server running through the phpfpm container Install symfony/ai-mate (dev-only) and wire its stdio MCP server into .mcp.json via 'docker compose exec -T phpfpm vendor/bin/mate serve' so it works without host PHP, matching the project's container-only tooling. Enable it in .claude/settings.json, document it in CLAUDE.md, and add project instructions (extra.ai-mate.instructions) telling agents to run mate through the container. Drop the mate-generated host-path mcp.json and Codex wrappers, which assume host PHP. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/settings.json | 3 +- .mcp.json | 13 + AGENTS.md | 6 + CHANGELOG.md | 3 + CLAUDE.md | 4 + composer.json | 14 +- composer.lock | 583 ++++++++++++++++++++++++++++++++++++- mate/.env | 0 mate/.gitignore | 1 + mate/AGENT_INSTRUCTIONS.md | 34 +++ mate/INSTRUCTIONS.md | 14 + mate/config.php | 22 ++ mate/extensions.php | 8 + mate/src/.gitignore | 0 14 files changed, 702 insertions(+), 3 deletions(-) create mode 100644 AGENTS.md create mode 100644 mate/.env create mode 100644 mate/.gitignore create mode 100644 mate/AGENT_INSTRUCTIONS.md create mode 100644 mate/INSTRUCTIONS.md create mode 100644 mate/config.php create mode 100644 mate/extensions.php create mode 100644 mate/src/.gitignore diff --git a/.claude/settings.json b/.claude/settings.json index 92845ee84..e0dceced7 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -5,7 +5,8 @@ "playwright@claude-plugins-official": true }, "enabledMcpjsonServers": [ - "context7" + "context7", + "symfony-ai-mate" ], "permissions": { "allow": [ diff --git a/.mcp.json b/.mcp.json index c5280c5f9..7b7e43a5b 100644 --- a/.mcp.json +++ b/.mcp.json @@ -3,6 +3,19 @@ "context7": { "type": "http", "url": "https://mcp.context7.com/mcp" + }, + "symfony-ai-mate": { + "type": "stdio", + "command": "docker", + "args": [ + "compose", + "exec", + "-T", + "phpfpm", + "vendor/bin/mate", + "serve", + "--force-keep-alive" + ] } } } diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..7cf114bfe --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,6 @@ + +AI Mate Summary: +- Role: MCP-powered, project-aware coding guidance and tools. +- Required action: Read and follow `mate/AGENT_INSTRUCTIONS.md` before taking any action in this project, and prefer MCP tools over raw CLI commands whenever possible. +- Installed extensions: symfony/ai-mate. + diff --git a/CHANGELOG.md b/CHANGELOG.md index aba4b7a67..389399aab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +- Added Symfony AI Mate (`symfony/ai-mate`, dev-only) as a project-aware MCP server for AI coding + agents; wired in `.mcp.json` to run inside the `phpfpm` container via `docker compose exec`. + ## [3.0.0-rc4] - 2026-06-04 - Tuned OPcache in the production image: enabled Symfony class preloading, inlined container diff --git a/CLAUDE.md b/CLAUDE.md index 84786ebd7..e1cf9ea36 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -45,6 +45,10 @@ A few things teammates install once on their host so the project's hooks, auto-e across the Entity ↔ DTO ↔ Provider/Processor chain. Static analyser only — does not need host PHP. - **context7 MCP** — auto-enabled via `.mcp.json` + `.claude/settings.json` `enabledMcpjsonServers`. No install step; Claude Code fetches it on first use. Used for live Symfony/API Platform/Doctrine docs lookup. +- **Symfony AI Mate MCP** — auto-enabled via `.mcp.json` + `enabledMcpjsonServers`. No host install; the + stdio server runs inside the `phpfpm` container, so it just needs the compose stack up. Project-aware PHP + tools (see `mate/AGENT_INSTRUCTIONS.md`); after changing Mate extensions, run + `task compose -- exec phpfpm vendor/bin/mate discover`. ## The `/v2/` API is versioned — no breaking changes allowed diff --git a/composer.json b/composer.json index cc6664309..d6b0a854c 100644 --- a/composer.json +++ b/composer.json @@ -63,6 +63,7 @@ "phpstan/phpstan-symfony": "^2.0", "phpunit/phpunit": "^9.5", "rector/rector": "^2.4", + "symfony/ai-mate": "^0.9.0", "symfony/browser-kit": "~6.4.0", "symfony/css-selector": "~6.4.0", "symfony/debug-bundle": "~6.4.0", @@ -91,7 +92,8 @@ "autoload-dev": { "psr-4": { "App\\PhpStan\\": "tools/phpstan/", - "App\\Tests\\": "tests/" + "App\\Tests\\": "tests/", + "Mate\\": "mate/src/" } }, "config": { @@ -110,6 +112,16 @@ "sort-packages": true }, "extra": { + "ai-mate": { + "extension": false, + "includes": [ + "mate/config.php" + ], + "instructions": "mate/INSTRUCTIONS.md", + "scan-dirs": [ + "mate/src" + ] + }, "symfony": { "allow-contrib": false, "require": "~6.4.0" diff --git a/composer.lock b/composer.lock index 2f7460767..c54f13615 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bdd63ae5b088abd9c17af1c7314d434e", + "content-hash": "b004b2b0ccd0d7da74cd6d0596c63ab5", "packages": [ { "name": "api-platform/core", @@ -11952,6 +11952,90 @@ }, "time": "2025-08-30T09:44:18+00:00" }, + { + "name": "mcp/sdk", + "version": "v0.5.0", + "source": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/php-sdk.git", + "reference": "fb2c8c2ee4ab2791239c5f534bb07bfb7589d4e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/modelcontextprotocol/php-sdk/zipball/fb2c8c2ee4ab2791239c5f534bb07bfb7589d4e8", + "reference": "fb2c8c2ee4ab2791239c5f534bb07bfb7589d4e8", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "opis/json-schema": "^2.4", + "php": "^8.1", + "php-http/discovery": "^1.20", + "phpdocumentor/reflection-docblock": "^5.6 || ^6.0", + "psr/clock": "^1.0", + "psr/container": "^1.0 || ^2.0", + "psr/event-dispatcher": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/uid": "^5.4 || ^6.4 || ^7.3 || ^8.0" + }, + "require-dev": { + "composer/semver": "^3.0", + "ext-openssl": "*", + "firebase/php-jwt": "^6.10 || ^7.0", + "laminas/laminas-httphandlerrunner": "^2.12", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phar-io/composer-distributor": "^1.0.2", + "php-cs-fixer/shim": "^3.91", + "phpdocumentor/shim": "^3", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^10.5", + "psr/simple-cache": "^2.0 || ^3.0", + "symfony/cache": "^5.4 || ^6.4 || ^7.3 || ^8.0", + "symfony/console": "^5.4 || ^6.4 || ^7.3 || ^8.0", + "symfony/finder": "^5.4 || ^6.4 || ^7.3 || ^8.0", + "symfony/http-client": "^5.4 || ^6.4 || ^7.3 || ^8.0", + "symfony/process": "^5.4 || ^6.4 || ^7.3 || ^8.0" + }, + "suggest": { + "symfony/finder": "Required for file-based discovery." + }, + "type": "library", + "autoload": { + "psr-4": { + "Mcp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Kyrian Obikwelu", + "email": "koshnawaza@gmail.com" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + } + ], + "description": "Model Context Protocol SDK for Client and Server applications in PHP", + "support": { + "issues": "https://github.com/modelcontextprotocol/php-sdk/issues", + "source": "https://github.com/modelcontextprotocol/php-sdk/tree/v0.5.0" + }, + "time": "2026-04-26T13:37:40+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.13.4", @@ -12165,6 +12249,196 @@ }, "time": "2025-12-06T11:56:16+00:00" }, + { + "name": "opis/json-schema", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/opis/json-schema.git", + "reference": "8458763e0dd0b6baa310e04f1829fc73da4e8c8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/json-schema/zipball/8458763e0dd0b6baa310e04f1829fc73da4e8c8a", + "reference": "8458763e0dd0b6baa310e04f1829fc73da4e8c8a", + "shasum": "" + }, + "require": { + "ext-json": "*", + "opis/string": "^2.1", + "opis/uri": "^1.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ext-bcmath": "*", + "ext-intl": "*", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\JsonSchema\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + }, + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + } + ], + "description": "Json Schema Validator for PHP", + "homepage": "https://opis.io/json-schema", + "keywords": [ + "json", + "json-schema", + "schema", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/opis/json-schema/issues", + "source": "https://github.com/opis/json-schema/tree/2.6.0" + }, + "time": "2025-10-17T12:46:48+00:00" + }, + { + "name": "opis/string", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/opis/string.git", + "reference": "3e4d2aaff518ac518530b89bb26ed40f4503635e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/string/zipball/3e4d2aaff518ac518530b89bb26ed40f4503635e", + "reference": "3e4d2aaff518ac518530b89bb26ed40f4503635e", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "ext-json": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\String\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "Multibyte strings as objects", + "homepage": "https://opis.io/string", + "keywords": [ + "multi-byte", + "opis", + "string", + "string manipulation", + "utf-8" + ], + "support": { + "issues": "https://github.com/opis/string/issues", + "source": "https://github.com/opis/string/tree/2.1.0" + }, + "time": "2025-10-17T12:38:41+00:00" + }, + { + "name": "opis/uri", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/opis/uri.git", + "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/uri/zipball/0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a", + "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a", + "shasum": "" + }, + "require": { + "opis/string": "^2.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Uri\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "Build, parse and validate URIs and URI-templates", + "homepage": "https://opis.io", + "keywords": [ + "URI Template", + "parse url", + "punycode", + "uri", + "uri components", + "url", + "validate uri" + ], + "support": { + "issues": "https://github.com/opis/uri/issues", + "source": "https://github.com/opis/uri/tree/1.1.0" + }, + "time": "2021-05-22T15:57:08+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.4", @@ -12965,6 +13239,119 @@ ], "time": "2026-01-27T05:45:00+00:00" }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, { "name": "rector/rector", "version": "2.4.4", @@ -13972,6 +14359,200 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "symfony/ai-mate", + "version": "v0.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ai-mate.git", + "reference": "e38aefde76cc60e226fa7abca1771733cc1a4557" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ai-mate/zipball/e38aefde76cc60e226fa7abca1771733cc1a4557", + "reference": "e38aefde76cc60e226fa7abca1771733cc1a4557", + "shasum": "" + }, + "require": { + "mcp/sdk": "^0.5", + "php": ">=8.2", + "psr/log": "^2.0|^3.0", + "symfony/ai-mate-composer-plugin": "^0.9", + "symfony/config": "^5.4|^6.4|^7.3|^8.0", + "symfony/console": "^5.4|^6.4|^7.3|^8.0", + "symfony/dependency-injection": "^5.4|^6.4|^7.3|^8.0", + "symfony/finder": "^5.4|^6.4|^7.3|^8.0" + }, + "require-dev": { + "ext-simplexml": "*", + "helgesverre/toon": "^3.1", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^11.5.53", + "symfony/dotenv": "^5.4|^6.4|^7.3|^8.0" + }, + "bin": [ + "bin/mate" + ], + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ai", + "name": "symfony/ai" + }, + "ai-mate": { + "scan-dirs": [ + "src/Capability" + ], + "instructions": "INSTRUCTIONS.md" + } + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Mate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes Wachter", + "email": "johannes@sulu.io" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "AI development assistant MCP server for Symfony projects", + "keywords": [ + "ai", + "debug", + "dev", + "development", + "mcp", + "model-context-protocol", + "symfony" + ], + "support": { + "source": "https://github.com/symfony/ai-mate/tree/v0.9.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-16T01:01:33+00:00" + }, + { + "name": "symfony/ai-mate-composer-plugin", + "version": "v0.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ai-mate-composer-plugin.git", + "reference": "0e449d57b71b0f6fd56fd2b9353d4bccb628c476" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ai-mate-composer-plugin/zipball/0e449d57b71b0f6fd56fd2b9353d4bccb628c476", + "reference": "0e449d57b71b0f6fd56fd2b9353d4bccb628c476", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.1", + "php": ">=8.2" + }, + "require-dev": { + "composer/composer": "^2.1", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^11.5.53", + "symfony/ai-mate": "^0.9" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\AI\\Mate\\ComposerPlugin\\MatePlugin", + "thanks": { + "url": "https://github.com/symfony/ai", + "name": "symfony/ai" + }, + "plugin-optional": true + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Mate\\ComposerPlugin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes Wachter", + "email": "johannes@sulu.io" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Composer plugin that automatically discovers AI Mate extensions on install/update", + "keywords": [ + "ai", + "auto-discovery", + "composer-plugin", + "mate", + "mcp" + ], + "support": { + "source": "https://github.com/symfony/ai-mate-composer-plugin/tree/v0.9.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-16T01:01:33+00:00" + }, { "name": "symfony/browser-kit", "version": "v6.4.32", diff --git a/mate/.env b/mate/.env new file mode 100644 index 000000000..e69de29bb diff --git a/mate/.gitignore b/mate/.gitignore new file mode 100644 index 000000000..11ee75815 --- /dev/null +++ b/mate/.gitignore @@ -0,0 +1 @@ +.env.local diff --git a/mate/AGENT_INSTRUCTIONS.md b/mate/AGENT_INSTRUCTIONS.md new file mode 100644 index 000000000..6180248c7 --- /dev/null +++ b/mate/AGENT_INSTRUCTIONS.md @@ -0,0 +1,34 @@ +## AI Mate Agent Instructions + +This MCP server provides specialized tools for PHP development. +The following extensions are installed and provide MCP tools that you should +prefer over running CLI commands directly. + +--- + +## Project: containerised PHP + +This project has no host PHP — all PHP tooling runs inside the `phpfpm` docker compose container. +The Mate MCP server is already wired accordingly in `.mcp.json` +(`docker compose exec -T phpfpm vendor/bin/mate serve`); it requires the compose stack to be up. + +When running Mate CLI commands, go through the container: + +```sh +task compose -- exec phpfpm vendor/bin/mate +``` + +e.g. `mate discover` after changing Mate extensions, or `mate mcp:tools:list` to debug. +Never invoke `vendor/bin/mate` (or any `php`/`composer` command) directly on the host. + +--- + +### Server Info + +| Instead of... | Use | +|---------------------|---------------| +| `php -v` | `server-info` | +| `php -m` | `server-info` | +| `uname -s` | `server-info` | + +- Returns PHP version, OS, OS family, and loaded extensions in a single call diff --git a/mate/INSTRUCTIONS.md b/mate/INSTRUCTIONS.md new file mode 100644 index 000000000..470632f8a --- /dev/null +++ b/mate/INSTRUCTIONS.md @@ -0,0 +1,14 @@ +# Project: containerised PHP + +This project has no host PHP — all PHP tooling runs inside the `phpfpm` docker compose container. +The Mate MCP server is already wired accordingly in `.mcp.json` +(`docker compose exec -T phpfpm vendor/bin/mate serve`); it requires the compose stack to be up. + +When running Mate CLI commands, go through the container: + +```sh +task compose -- exec phpfpm vendor/bin/mate +``` + +e.g. `mate discover` after changing Mate extensions, or `mate mcp:tools:list` to debug. +Never invoke `vendor/bin/mate` (or any `php`/`composer` command) directly on the host. diff --git a/mate/config.php b/mate/config.php new file mode 100644 index 000000000..30d0e3ad1 --- /dev/null +++ b/mate/config.php @@ -0,0 +1,22 @@ +parameters() + // Override default parameters here + // ->set('mate.cache_dir', sys_get_temp_dir().'/mate') + // ->set('mate.env_file', ['.env']) // This will load mate/.env and mate/.env.local + ; + + $container->services() + ->defaults() + ->autowire() + ->autoconfigure() + + // Register your custom services here + ; +}; diff --git a/mate/extensions.php b/mate/extensions.php new file mode 100644 index 000000000..964e7507e --- /dev/null +++ b/mate/extensions.php @@ -0,0 +1,8 @@ + ['enabled' => true], +]; diff --git a/mate/src/.gitignore b/mate/src/.gitignore new file mode 100644 index 000000000..e69de29bb From 356aa4b08ae34b9cc605470d8494cd27699d55fa Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 5 Jun 2026 10:31:36 +0200 Subject: [PATCH 2/4] feat(dev): pre-approve all symfony-ai-mate MCP tools in Claude settings Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.claude/settings.json b/.claude/settings.json index e0dceced7..441c802a4 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -10,6 +10,7 @@ ], "permissions": { "allow": [ + "mcp__symfony-ai-mate", "Bash(docker compose:*)", "WebFetch(domain:api-platform.com)", "Bash(grep:*)", From c9919401f0757d5632856ea849c169877630bde8 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 5 Jun 2026 10:35:35 +0200 Subject: [PATCH 3/4] feat(dev): add Mate Monolog bridge for log search/tail MCP tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds symfony/ai-monolog-mate-extension (PHP-only constraints, no Symfony 7 requirement) exposing monolog-search/-context-search/-tail/ -list-files/-list-channels against var/log inside the container. The Symfony bridge (container/profiler introspection) is skipped for now: it requires symfony/dependency-injection ^7.3, incompatible with this Symfony 6.4 app — revisit on the 7.x upgrade. Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 2 +- CHANGELOG.md | 1 + composer.json | 1 + composer.lock | 99 +++++++++++++++++++++++++++++++++++++- mate/AGENT_INSTRUCTIONS.md | 18 +++++++ mate/extensions.php | 1 + 6 files changed, 120 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7cf114bfe..8154eb378 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,5 +2,5 @@ AI Mate Summary: - Role: MCP-powered, project-aware coding guidance and tools. - Required action: Read and follow `mate/AGENT_INSTRUCTIONS.md` before taking any action in this project, and prefer MCP tools over raw CLI commands whenever possible. -- Installed extensions: symfony/ai-mate. +- Installed extensions: symfony/ai-mate, symfony/ai-monolog-mate-extension. diff --git a/CHANGELOG.md b/CHANGELOG.md index 389399aab..d42e4513f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. - Added Symfony AI Mate (`symfony/ai-mate`, dev-only) as a project-aware MCP server for AI coding agents; wired in `.mcp.json` to run inside the `phpfpm` container via `docker compose exec`. + Includes the Monolog bridge (`symfony/ai-monolog-mate-extension`) exposing log search/tail tools. ## [3.0.0-rc4] - 2026-06-04 diff --git a/composer.json b/composer.json index d6b0a854c..4ffb54640 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,7 @@ "phpunit/phpunit": "^9.5", "rector/rector": "^2.4", "symfony/ai-mate": "^0.9.0", + "symfony/ai-monolog-mate-extension": "^0.9.0", "symfony/browser-kit": "~6.4.0", "symfony/css-selector": "~6.4.0", "symfony/debug-bundle": "~6.4.0", diff --git a/composer.lock b/composer.lock index c54f13615..e151caf73 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b004b2b0ccd0d7da74cd6d0596c63ab5", + "content-hash": "c8bd0c1f3f711fbc08cf44f47d1654b8", "packages": [ { "name": "api-platform/core", @@ -14553,6 +14553,103 @@ ], "time": "2026-05-16T01:01:33+00:00" }, + { + "name": "symfony/ai-monolog-mate-extension", + "version": "v0.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ai-monolog-mate-extension.git", + "reference": "b72ab1202ce6813906d0f3af475111e3403d7c90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ai-monolog-mate-extension/zipball/b72ab1202ce6813906d0f3af475111e3403d7c90", + "reference": "b72ab1202ce6813906d0f3af475111e3403d7c90", + "shasum": "" + }, + "require": { + "monolog/monolog": "^2.0|^3.0", + "php": ">=8.2", + "symfony/ai-mate": "^0.9" + }, + "require-dev": { + "helgesverre/toon": "^3.1", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^11.5.53" + }, + "type": "symfony-ai-mate", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ai", + "name": "symfony/ai" + }, + "ai-mate": { + "includes": [ + "config/config.php" + ], + "scan-dirs": [ + "Capability" + ], + "instructions": "INSTRUCTIONS.md" + } + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Mate\\Bridge\\Monolog\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes Wachter", + "email": "johannes@sulu.io" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Monolog bridge for AI Mate - provides log search and analysis tools", + "keywords": [ + "Bridge", + "ai", + "dev", + "logs", + "mcp", + "monolog" + ], + "support": { + "source": "https://github.com/symfony/ai-monolog-mate-extension/tree/v0.9.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-16T01:01:33+00:00" + }, { "name": "symfony/browser-kit", "version": "v6.4.32", diff --git a/mate/AGENT_INSTRUCTIONS.md b/mate/AGENT_INSTRUCTIONS.md index 6180248c7..770daa092 100644 --- a/mate/AGENT_INSTRUCTIONS.md +++ b/mate/AGENT_INSTRUCTIONS.md @@ -32,3 +32,21 @@ Never invoke `vendor/bin/mate` (or any `php`/`composer` command) directly on the | `uname -s` | `server-info` | - Returns PHP version, OS, OS family, and loaded extensions in a single call + +--- + +### Monolog Bridge + +Use MCP tools instead of CLI for log analysis: + +| Instead of... | Use | +|-----------------------------------|--------------------------------------------------| +| `tail -f var/log/dev.log` | `monolog-tail` | +| `grep "error" var/log/*.log` | `monolog-search` with term "error" | +| `grep -E "pattern" var/log/*.log` | `monolog-search` with term "pattern", regex: true | + +#### Benefits + +- Structured output with parsed log entries +- Multi-file search across all logs at once +- Filter by environment, level, or channel diff --git a/mate/extensions.php b/mate/extensions.php index 964e7507e..37a0da594 100644 --- a/mate/extensions.php +++ b/mate/extensions.php @@ -5,4 +5,5 @@ return [ 'symfony/ai-mate' => ['enabled' => true], + 'symfony/ai-monolog-mate-extension' => ['enabled' => true], ]; From 26adcec7801e4231b84a709535d9256057dcf9d1 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 10 Jun 2026 08:40:46 +0200 Subject: [PATCH 4/4] fix(mate): satisfy php-cs-fixer and markdownlint for the Mate integration - php-cs-fixer: format mate/config.php and mate/extensions.php. - markdownlint: ignore the AI Mate docs (generated AGENTS.md + the mate/ directory), which follow Mate's own format rather than this project's Markdown conventions and are partly generated by the composer plugin. Co-Authored-By: Claude Opus 4.8 --- .markdownlintignore | 8 ++++++++ mate/config.php | 2 ++ mate/extensions.php | 2 ++ 3 files changed, 12 insertions(+) diff --git a/.markdownlintignore b/.markdownlintignore index a4bd9bdd5..eeb5174b6 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -4,3 +4,11 @@ # https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#ignoring-files vendor/ node_modules/ + +# AI Mate generates AGENTS.md (maintained between the AI_MATE_INSTRUCTIONS +# markers by the composer plugin) and ships its own agent docs under mate/. +# Both follow Mate's own format, not this project's Markdown conventions, so +# they are excluded from markdownlint rather than hand-fixed (the generated +# parts would be overwritten anyway). +AGENTS.md +mate/ diff --git a/mate/config.php b/mate/config.php index 30d0e3ad1..6a41da102 100644 --- a/mate/config.php +++ b/mate/config.php @@ -1,5 +1,7 @@