diff --git a/.claude/settings.json b/.claude/settings.json index 45010b39b..cec3b88c0 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -5,10 +5,12 @@ "playwright@claude-plugins-official": true }, "enabledMcpjsonServers": [ - "context7" + "context7", + "symfony-ai-mate" ], "permissions": { "allow": [ + "mcp__symfony-ai-mate", "Bash(docker compose:*)", "WebFetch(domain:api-platform.com)", "Bash(grep:*)", 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/.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..8154eb378 --- /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, symfony/ai-monolog-mate-extension. + diff --git a/CHANGELOG.md b/CHANGELOG.md index 3be471ab9..a85d609bd 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`. + Includes the Monolog bridge (`symfony/ai-monolog-mate-extension`) exposing log search/tail tools. - Sped up the Playwright CI job: it now runs in parallel (3 workers, sized to the 4-vCPU public GitHub runner) instead of the default 2, added `ipc: host` to the `playwright` Compose service so parallel Chromium does not exhaust Docker's default 64 MB `/dev/shm`, pulls the 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 a20f1f8a4..b4de8738a 100644 --- a/composer.json +++ b/composer.json @@ -63,6 +63,8 @@ "phpstan/phpstan-symfony": "^2.0", "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", @@ -91,7 +93,8 @@ "autoload-dev": { "psr-4": { "App\\PhpStan\\": "tools/phpstan/", - "App\\Tests\\": "tests/" + "App\\Tests\\": "tests/", + "Mate\\": "mate/src/" } }, "config": { @@ -110,6 +113,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 25850c08d..f9fc7f38c 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": "8a30d37314d093225e912c6a8eff1998", + "content-hash": "682da7e19e418d0e250b75fc72b8b90b", "packages": [ { "name": "api-platform/core", @@ -6139,16 +6139,16 @@ }, { "name": "symfony/console", - "version": "v6.4.39", + "version": "v6.4.41", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c132f1215fe4aa45b70173cc00ce9a755dd31ec5" + "reference": "d21b17ed158e79180fac3895ff751707970eeb57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c132f1215fe4aa45b70173cc00ce9a755dd31ec5", - "reference": "c132f1215fe4aa45b70173cc00ce9a755dd31ec5", + "url": "https://api.github.com/repos/symfony/console/zipball/d21b17ed158e79180fac3895ff751707970eeb57", + "reference": "d21b17ed158e79180fac3895ff751707970eeb57", "shasum": "" }, "require": { @@ -6213,7 +6213,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.39" + "source": "https://github.com/symfony/console/tree/v6.4.41" }, "funding": [ { @@ -6233,7 +6233,7 @@ "type": "tidelift" } ], - "time": "2026-05-12T06:50:03+00:00" + "time": "2026-05-24T08:48:41+00:00" }, { "name": "symfony/dependency-injection", @@ -8107,16 +8107,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.38.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "9c862df890f7c833b1101ac5578ec4dcf199efb5" + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/9c862df890f7c833b1101ac5578ec4dcf199efb5", - "reference": "9c862df890f7c833b1101ac5578ec4dcf199efb5", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", "shasum": "" }, "require": { @@ -8165,7 +8165,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" }, "funding": [ { @@ -8185,7 +8185,7 @@ "type": "tidelift" } ], - "time": "2026-05-25T12:39:52+00:00" + "time": "2026-05-26T05:58:03+00:00" }, { "name": "symfony/polyfill-intl-idn", @@ -8361,16 +8361,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.38.1", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92" + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92", - "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { @@ -8422,7 +8422,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { @@ -8442,7 +8442,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T12:51:13+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { "name": "symfony/polyfill-php56", @@ -8598,16 +8598,16 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.37.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/6bfb9c766cacffbc8e118cb87217d08ed84e5cd7", + "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7", "shasum": "" }, "require": { @@ -8654,7 +8654,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.38.1" }, "funding": [ { @@ -8674,7 +8674,7 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-05-26T12:45:58+00:00" }, { "name": "symfony/polyfill-php83", @@ -8921,16 +8921,16 @@ }, { "name": "symfony/process", - "version": "v6.4.39", + "version": "v6.4.41", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "6c93071cb8c91dce5a41960d125e019e64ef6cb5" + "reference": "c8fc09bdfe9fde9aaa89b415a4477feaccec16a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/6c93071cb8c91dce5a41960d125e019e64ef6cb5", - "reference": "6c93071cb8c91dce5a41960d125e019e64ef6cb5", + "url": "https://api.github.com/repos/symfony/process/zipball/c8fc09bdfe9fde9aaa89b415a4477feaccec16a7", + "reference": "c8fc09bdfe9fde9aaa89b415a4477feaccec16a7", "shasum": "" }, "require": { @@ -8962,7 +8962,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.39" + "source": "https://github.com/symfony/process/tree/v6.4.41" }, "funding": [ { @@ -8982,7 +8982,7 @@ "type": "tidelift" } ], - "time": "2026-05-11T16:53:15+00:00" + "time": "2026-05-23T13:47:21+00:00" }, { "name": "symfony/property-access", @@ -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,297 @@ ], "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/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/.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..770daa092 --- /dev/null +++ b/mate/AGENT_INSTRUCTIONS.md @@ -0,0 +1,52 @@ +## 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 + +--- + +### 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/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..6a41da102 --- /dev/null +++ b/mate/config.php @@ -0,0 +1,24 @@ +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..e42ccb7cb --- /dev/null +++ b/mate/extensions.php @@ -0,0 +1,11 @@ + ['enabled' => true], + 'symfony/ai-monolog-mate-extension' => ['enabled' => true], +]; diff --git a/mate/src/.gitignore b/mate/src/.gitignore new file mode 100644 index 000000000..e69de29bb