Your agent can read
your production traces.
PHPRay speaks the Model Context Protocol. Point Claude Code, Claude Desktop, Cursor or any other MCP client at one URL and it can answer "which page got slow after Tuesday's deploy" from real request data — not from guessing at your source code.
Add it in one line
claude mcp add --transport http phpray https://phpray.dev/mcp
Nothing to install and no account needed. Without a token you get the read-only demo account: a WooCommerce store with real recorded traffic, so you can see what the tools return before you decide anything. Rate-limited to 30 requests a minute per address.
Not using Claude Code?
Every MCP client takes the same server. Paste this into your client's MCP
configuration — mcp.json in Cursor, settings.json in the VS Code
MCP extension, claude_desktop_config.json in Claude Desktop:
{
"mcpServers": {
"phpray": {
"type": "http",
"url": "https://phpray.dev/mcp"
}
}
}Transport is streamable HTTP over POST; there is no SSE stream, and a
GET asking for one is answered with 405 on purpose, which is what
the specification asks for. If your client searches a registry instead, we are listed in the
official Model Context Protocol registry as
dev.phpray/phpray.
Then ask in plain language
- "Which pages on this site are slowest, and what is the p95?"
- "Which SQL fingerprint costs the most time, and who calls it?"
- "Which plugin eats the most time on profiled requests?"
- "Compare the last 24 hours with the previous 24 — did anything get worse?"
- "Show me the slowest request over 800 ms and break it down."
And this is what comes back
Unedited output of phpray_slow_queries, fetched from the endpoint above while this page was built. No key was used, so this is exactly what your agent gets on its first call:
62 slow query fingerprints, showing 5, ordered by total time in the window (avg x calls) — that is what costs the database. Literal values are masked as ?.
1. total 116 ms · avg 0.2 ms · max 0.7 ms · 501 calls
SELECT option_name, option_value FROM wp_options WHERE option_name IN (?)
2. total 107 ms · avg 0.4 ms · max 0.8 ms · 256 calls
SELECT option_name, option_value FROM wp_options WHERE autoload IN (?)
3. total 95 ms · avg 0.2 ms · max 0.4 ms · 457 calls
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (?) AND tr.object_id IN (?) ORDER B…
4. total 85 ms · avg 4.7 ms · max 7.6 ms · 18 calls
UPDATE `wp_options` SET `option_value` = ? WHERE `option_name` = ?
5. total 83 ms · avg 0.3 ms · max 1.1 ms · 317 calls
SELECT option_value FROM wp_options WHERE option_name = ? LIMIT ?Captured 2026-09-24 from the public demo account. The values inside the queries are already replaced with ? before anything leaves the site — that is the masking, shown rather than promised.
Your own sites
Pass a console token and the same tools see your sites instead of the demo, scoped exactly to what that token can read:
claude mcp add --transport http phpray https://phpray.dev/mcp \ --header "Authorization: Bearer <console token>"
The token comes from the console under Settings. It travels on each request and is never stored by the MCP service — the service holds no database and no credentials of its own. A read-only token cannot start profiling; the server refuses it rather than pretending.
What the tools do
phpray_sites | List the PHP sites this token can see, with requests, p95 latency and error rate. Start here: every other tool needs a site_id from this list. |
phpray_overview | Headline numbers for one site over a time window: requests, errors, p50/p95/p99 latency, database share and N+1 count. Use this before digging into anything else. |
phpray_slow_pages | The slowest URLs on a site, with request counts and p95, from the request timeseries. Answers "which page is slow". |
phpray_slow_queries | SQL fingerprints ordered by time spent, with call counts and the caller when known. Literals are already masked. Answers "which query is slow". |
phpray_components | Time attributed to each plugin, theme or vendor package on profiled requests. Answers "which plugin is slowing the site down". Empty when function profiling is off. |
phpray_errors | Recent PHP errors and warnings for a site, with file, line and the request they happened in. |
phpray_traces | Recent requests for a site. Filter with min_ms and status to find the bad ones, then pass an id to phpray_trace. |
phpray_trace | One request in full: wall time split into PHP, database and outbound HTTP, every query, every external call, errors, and the component breakdown when the request was profiled. |
phpray_compare | Two time ranges for one site side by side. Use it to check whether a deployment, a plugin update or a configuration change made things better or worse. |
phpray_alerts | Alerts currently firing across every site this token can see. |
This table is generated from the live endpoint, so it cannot drift away from
what the server actually offers. With your own token you also get
phpray_profile_url, which turns per-function profiling on for one URL prefix for
a few minutes — the only tool that changes anything, and it is hidden on the demo.
Prefer it local?
The same server runs as a binary next to your collector, over stdio, with no cloud at all:
claude mcp add phpray-local -- phpray-mcp
It reads the collector on 127.0.0.1:9191 and needs no account.
Binaries for Linux and macOS are in every
release; the source is in
src/mcp, Apache-2.0, with no third-party dependencies.
What it is not
- It does not read or write your code. It reads recorded request data, nothing else.
- It does not stream: the transport is plain POST with JSON-RPC, no SSE session.
- It cannot change your PHP configuration, restart anything or touch your server.
Get your own data in there
The demo shows the shape. Your own traffic takes one install: open source, Apache-2.0, no card. A free cloud account gives one site, 10,000 traces a day, 7 days of history.
Install PHPRay See the plansRead next
- Continuous profiling for PHP — what Datadog and Pyroscope require, and what we do instead.
- Xdebug alternative — what to keep Xdebug for, and where it stops.
- Profiling PHP in production — what the data behind these tools actually is.
- Blackfire alternative — an honest comparison, including where Blackfire wins.
- What always-on tracing costs — measured, with the raw numbers.