A starter template for building MatesOfMate extensions that follow the current Symfony AI Mate workflow.
- Use this template on GitHub.
- Replace all
exampleandExampleExtensionplaceholders with your framework name. - Run
composer install. - Add your tools and resources in
src/Capability/. - Run
composer testandcomposer lint.
This template is aligned with the current symfony/ai-mate 0.8.x workflow and the current core Mate response encoding behavior:
- initialize projects with
vendor/bin/mate init - extension discovery is handled automatically on Composer install and update in current Mate setups
mate/extensions.phpcontrols which discovered extensions are enabledvendor/bin/mate discoverstill refreshes discovery state and regenerates agent instruction artifacts- Codex should be started via
./bin/codexorbin/codex.bat
Useful Mate commands while developing:
vendor/bin/mate debug:capabilities
vendor/bin/mate debug:extensions
vendor/bin/mate mcp:tools:list
vendor/bin/mate mcp:tools:inspect example-helloextension-template/
├── .github/
├── composer.json
├── README.md
├── LICENSE
├── .gitignore
├── phpunit.xml.dist
├── phpstan.dist.neon
├── rector.php
├── .php-cs-fixer.php
├── src/
│ └── Capability/
│ ├── ExampleTool.php
│ └── ExampleResource.php
├── config/
│ └── config.php
└── tests/
└── Capability/
├── ExampleToolTest.php
└── ExampleResourceTest.php
composer require --dev matesofmate/your-extension
vendor/bin/mate initIn current AI Mate setups, extension discovery is handled automatically after install and update. Run vendor/bin/mate discover when you want to refresh generated instruction artifacts or re-scan the project manually.
For Codex, use the generated wrapper instead of relying on mcp.json alone:
./bin/codexTools are PHP classes with methods marked with #[McpTool].
<?php
namespace MatesOfMate\ExampleExtension\Capability;
use Mcp\Capability\Attribute\McpTool;
use Symfony\AI\Mate\Encoding\ResponseEncoder;
/**
* Example tool showing the default MatesOfMate style.
*
* @author Johannes Wachter <[email protected]>
*/
class ListEntitiesTool
{
public function __construct(
private readonly SomeService $service,
) {
}
/**
* @param string|null $scope Optional scope used to narrow the entities that are returned.
*/
#[McpTool(
name: 'example-list-entities',
description: 'List available entities. Use when the user asks which entities, models, or tables exist.'
)]
public function execute(?string $scope = null): string
{
$entities = $this->service->getEntities($scope);
return ResponseEncoder::encode([
'entities' => $entities,
'count' => count($entities),
]);
}
}Tool guidance:
- Use
{framework}-{action}for tool names. - Prefer one flexible tool with clear parameters over several near-duplicate tool names.
- Write descriptions that say when the AI should call the tool.
- Add
@paramdocblocks so generated schemas include parameter descriptions. - For encoded string payloads, use Mate's built-in
ResponseEncoderso TOON is used when available and JSON is used as a fallback. - Current AI Mate also supports array and scalar tool returns. Use encoded strings when you want stable structured output across environments.
- Register tool classes in
config/config.php.
Resources provide static or semi-static context to the AI.
<?php
namespace MatesOfMate\ExampleExtension\Capability;
use Mcp\Capability\Attribute\McpResource;
use Symfony\AI\Mate\Encoding\ResponseEncoder;
/**
* Example resource showing the default MatesOfMate style.
*
* @author Johannes Wachter <[email protected]>
*/
class ConfigurationResource
{
#[McpResource(
uri: 'example://config',
name: 'example_config',
mimeType: 'text/plain'
)]
public function getConfiguration(): array
{
return [
'uri' => 'example://config',
'mimeType' => 'text/plain',
'text' => ResponseEncoder::encode([
'version' => '1.0.0',
'features' => ['feature_a' => true],
]),
];
}
}Resource guidance:
- Use a custom URI scheme such as
example://config. - Return
uri,mimeType, andtext. - Use
text/plainfor encoder-backed resource text because the payload may be TOON or JSON depending on the installed environment. - Prefer the core Mate
ResponseEncoderinstead of maintaining a package-local encoding helper.
Register capabilities in config/config.php:
<?php
use MatesOfMate\ExampleExtension\Capability\ListEntitiesTool;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $container): void {
$services = $container->services()
->defaults()
->autowire()
->autoconfigure();
$services->set(ListEntitiesTool::class);
};INSTRUCTIONS.md should help AI agents map common user intents to your MCP capabilities. Keep it short, concrete, and focused on when to use your tools instead of CLI commands.
Current Mate workflows also materialize aggregated instructions into mate/AGENT_INSTRUCTIONS.md and maintain a managed AI Mate block in the project AGENTS.md when discovery is refreshed.
composer test
composer lint
composer fixUseful direct commands:
vendor/bin/phpunit
vendor/bin/phpstan analyse
vendor/bin/rector process --dry-run
vendor/bin/php-cs-fixer fix --dry-run --diff- Replace all
exampleandExampleExtensionplaceholders - Update
composer.jsonpackage name and description - Update
.github/CODEOWNERS - Update
LICENSE - Replace example tool and resource names, URIs, and descriptions
- Update README install and usage docs for your framework
- Make sure
composer testpasses - Make sure
composer lintpasses - Tag a release and submit to Packagist
"Because every Mate needs Mates"