A minimal Model Context Protocol (MCP) server implemented in pure PHP that exposes two tools:
phpstan_analyze: Runs PHPStan and returns a readable report.phpstan_pro: Runs PHPStan Pro JSON output (if available) for richer diagnostics.
No Composer dependencies. Designed to be copied into any project.
src/Domain: Tool contracts and resultssrc/Application: JSON-RPC MCP server and registrysrc/Infrastructure: Process runner, config, tool implementationsbin/mcp-phpstan: STDIO entrypoint
You can configure via environment variables or config/config.json:
MCP_PHPSTAN_PATH– path tophpstanbinary (default:vendor/bin/phpstanthenphpstanon PATH)MCP_PHPSTAN_CONFIG– path to a phpstan.neon or phpstan.neon.dist (optional; autodetected upward)MCP_PHPSTAN_LEVEL– level to pass to phpstan (e.g.maxor8) if not set in config
If no config is provided, the server searches upwards from the current working directory for one of:
phpstan.neon, phpstan.neon.dist.
Mark the script executable once:
chmod +x mcp/phpstan-server/bin/mcp-phpstanThen configure your MCP client to start the server via stdio using the command:
/absolute/path/to/mcp/phpstan-server/bin/mcp-phpstan{
"mcpServers": {
"phpstan": {
"command": "/absolute/path/to/mcp/phpstan-server/bin/mcp-phpstan",
"env": {
"MCP_PHPSTAN_PATH": "/usr/local/bin/phpstan",
"MCP_PHPSTAN_CONFIG": "/path/to/your/phpstan.neon",
"MCP_PHPSTAN_LEVEL": "max"
}
}
}
}The server speaks JSON-RPC 2.0 over STDIN/STDOUT and implements:
initializetools/listtools/call
Input schema:
{
"type": "object",
"properties": {
"paths": {"type": "array", "items": {"type": "string"}},
"level": {"type": ["string", "integer"], "description": "Override level"}
},
"required": ["paths"]
}Same input schema as phpstan_analyze, but returns JSON directly when possible.
- Output to STDOUT is strictly JSON-RPC messages. Logs go to STDERR.
- Non-zero exit codes from
phpstanmay indicate findings as well as failures; we parse output to determine error state.