noisebynorthwest / php-spx-mcp
MCP server for php-spx profiler
Package info
github.com/NoiseByNorthwest/php-spx-mcp
Type:project
pkg:composer/noisebynorthwest/php-spx-mcp
Requires
- php: >=8.3
- ext-zlib: *
- php-mcp/server: ^3.3
- psr/clock: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.65
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.0
- squizlabs/php_codesniffer: ^3.10
Suggests
- ext-zstd: Required to read .txt.zst reports
This package is not auto-updated.
Last update: 2026-06-02 20:36:20 UTC
README
An MCP server that exposes php-spx profiling reports to LLM agents.
It gives an assistant read access to those profiles so it can list them, read a report's metadata, and walk its call graph directly from the conversation, instead of through the SPX web UI.
Important
Only the SPX v0.5 report format is supported.
How it works
php-spx writes one report per profiled request/command to a data directory: a
<key>.json metadata sidecar plus a compressed body (<key>.txt.gz or
<key>.txt.zst). This server reads that directory and serves the reports over
MCP's stdio transport. It reads the reports; it does not modify them.
Requirements
- PHP >= 8.3
ext-zlib(to read.txt.gzreports)ext-zstd(optional, only to read.txt.zstreports)- A directory of php-spx reports to read
Installation
Install a standalone, runnable copy with Composer:
composer create-project noisebynorthwest/php-spx-mcp
This creates a php-spx-mcp/ directory with dependencies installed; its
bin/server.php is the entry point referenced below.
Alternatively, clone the repository:
git clone https://github.com/NoiseByNorthwest/php-spx-mcp.git
cd php-spx-mcp
composer install --no-dev
Configuration
The server reads reports from the directory given by the SPX_DATA_DIR
environment variable, defaulting to /tmp/spx. Point it at the directory where
php-spx stores its reports.
Register the server with your MCP client (stdio transport). For example:
{
"mcpServers": {
"php-spx": {
"command": "php",
"args": ["/absolute/path/to/php-spx-mcp/bin/server.php"],
"env": {
"SPX_DATA_DIR": "/tmp/spx"
}
}
}
}
Tools
find_reports
Find reports with server-side filters, returning their essential metadata so a
follow-up get_report_metadata call is usually unnecessary.
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string | n/a | Matched case-insensitively against the request URI and CLI command line. Plain text matches as a substring; *, ?, [] enable wildcards. |
within_last_seconds |
int >= 0 | n/a | Only reports whose execution started within the last N seconds. |
since_timestamp |
int | n/a | Only reports whose execution started at or after this Unix time (seconds). |
min_wall_time_ms |
int >= 0 | n/a | Only reports whose recorded wall time is at least this value. |
limit |
int 1-200 | 50 | Maximum number of reports to return, most recent first. |
Returns a list of { key, timestamp, descriptor, wall_time_ms }, most recent
first. descriptor is the request URI or CLI command line, depending on the
report.
get_report_metadata
Get the full metadata for a report (enabled metrics, URL/command, duration, memory, etc.).
| Parameter | Type | Description |
|---|---|---|
report_key |
string | The report key, as returned by find_reports. |
get_aggregated_call_graph
Get the aggregated, pruned call graph for a report.
| Parameter | Type | Default | Description |
|---|---|---|---|
report_key |
string | n/a | The report key. |
metric |
enum | wt |
Metric to aggregate: wt, ct, zm, zmmu, zmc, ze, zr, zo, zgc, zgr, io, ior, iow. |
pruning_relative_threshold |
number 0-1 | 0.005 | Nodes below this fraction of the (sub)tree's total metric are dropped. |
root_stack |
string[] | [] |
Optional call path to zoom into, from the outermost frame inward (see below). |
Children are sorted by value descending, and every non-root node carries its
source location (file, lineNumber).
Zooming with root_stack
The full graph can be large. To focus on a subtree, pass root_stack, the path
of calls from the root down to the call you want to re-root on. Each entry is a
function name as shown in the graph, optionally prefixed with <lineNumber>: to
disambiguate homonyms:
[ "/usr/local/bin/composer", "1:phar:///usr/local/bin/composer/bin/composer", "423:Composer\\Autoload\\ClassLoader::loadClass" ]
The result is re-rooted on the call the path lands on, and pruning then applies
relative to that subtree's own value, so pruning_relative_threshold: 0.01
after zooming means "drop calls below 1% of the focused call".
Dev
Install dependencies
composer install
Apply CS Fixer fixes
composer cs-fix
QA
composer phpcs && composer cs-check && composer phpstan && ./vendor/bin/phpunit
License
MIT