Skip to content
Agents

MCP server

A local MCP server that lets your coding agent read your Squally data: which CI runs happened, which tests are flaky, and why a test failed.

squally-mcp is a local MCP server. It runs on your machine over stdio, started by your coding agent, and reads your Squally data through the read API over HTTPS - the same requests a curl would make, answered with the same JSON.

Read-only by construction. The server issues HTTP GET requests and nothing else: there is no code path that writes. Every tool is annotated readOnlyHint: true, so a client can run them without asking you to confirm each one. It cannot reach past your organization either: the key is scoped to one organization, and scoping, plan checks and secret exclusion are enforced by the API, not by this client.

The package is squally-mcp on npm, MIT-licensed, with its source on GitHub.

  • A Standard or Pro plan. The read API is part of both; on Free, every call is answered tier_too_low.
  • An organization read key. An organization admin creates it under Settings → API keys → Create read key. It starts with sqly_ro_ and is shown once. It is not the project ingest key your Playwright reporter uses - the server refuses that one by name. More in Read keys.
  • Node 22 or newer. Your agent starts the server with npx.

Worth knowing before you hand a key to an assistant. Through this server an agent can read:

  • your projects, their names and stable branches;
  • your CI runs - commit SHA and message, branch, author, pull request, timing, pass/fail counts;
  • per-test results for a run, including which shard ran what;
  • for a failing attempt: the error message and stack, the error snippet - verbatim source lines from your test file - and the page snapshot at the moment of failure: an ARIA snapshot of your application, whatever was on screen, truncated to 3000 characters. Both are part of the Copy-for-AI prompt, which the agent gets too;
  • flakiness verdicts and how much time each flaky test has cost;
  • error signatures: failures grouped across runs and branches.

It cannot see screenshots, videos or traces - artifacts are deliberately out of scope - and it cannot see any key, secret or webhook URL.

Each client starts the server with npx -y squally-mcp and hands it your key as SQUALLY_API_KEY. Replace sqly_ro_your_key_here with your read key. If the client’s config file already has an mcpServers section, add the squally entry to it.

claude mcp add squally --scope user \
--env SQUALLY_API_KEY=sqly_ro_your_key_here \
-- npx -y squally-mcp

--scope user makes the server available in all your projects and keeps it in ~/.claude.json - not in a project’s .mcp.json, which is shared through version control. claude mcp list shows whether it connected; /mcp shows it inside a session.

In ~/.codex/config.toml - the Codex CLI and the IDE extension read the same file:

[mcp_servers.squally]
command = "npx"
args = ["-y", "squally-mcp"]
[mcp_servers.squally.env]
SQUALLY_API_KEY = "sqly_ro_your_key_here"

Or the same from the command line:

codex mcp add squally \
--env SQUALLY_API_KEY=sqly_ro_your_key_here \
-- npx -y squally-mcp

codex mcp list shows the configured servers; /mcp in the Codex TUI shows the active ones.

In ~/.cursor/mcp.json, for all your projects:

{
"mcpServers": {
"squally": {
"type": "stdio",
"command": "npx",
"args": ["-y", "squally-mcp"],
"env": { "SQUALLY_API_KEY": "sqly_ro_your_key_here" }
}
}
}

A project’s .cursor/mcp.json works too, but it is meant to be committed - so write "SQUALLY_API_KEY": "${env:SQUALLY_API_KEY}" there instead of the key, and set the variable in the environment Cursor starts from. Save the file and restart Cursor; the server appears under Customize → MCPs, where it can be switched on and off. The Cursor CLI reads the same files.

In Claude Desktop, open Settings → Developer and click Edit Config. It opens claude_desktop_config.json - on macOS in ~/Library/Application Support/Claude/, on Windows in %APPDATA%\Claude\:

{
"mcpServers": {
"squally": {
"command": "npx",
"args": ["-y", "squally-mcp"],
"env": { "SQUALLY_API_KEY": "sqly_ro_your_key_here" }
}
}
}

Then quit Claude Desktop completely and start it again - it needs a restart to load the new configuration.

On Windows, npx can fail to start when npm is not installed globally. If %APPDATA%\npm does not exist, run npm install -g npm once.

Read from squally-mcp 0.1.2 when these docs were built. Each tool is one call on the read API; the path links to its reference.

ToolWhat it answersCost
squally-list-projectsGET /projects
Which projects exist. Start here — every other tool needs a projectId from it.cheap
Which runs happened — latest, or by branch, commit SHA or status. Counters only.cheap
One run with its per-test rows, across all shards. Which test is red.cheap
Every attempt of one test in one run: error, stack, Copy-for-AI prompt.cheap
The stored flakiness status of one test.cheap
squally-list-flaky-testsGET /projects/{projectId}/flaky
The ranked flaky/broken list with time lost.expensive
Error signatures in a period: what keeps failing, grouped.cheap
What the server tells your agent first
Start with squally-list-projects; every other tool needs a projectId from it. For one test, use squally-get-test-status (cheap), not squally-list-flaky-tests (expensive, one engine pass). If a test name is ambiguous, repeat with filePath from the error. Errors carry a code and an action; follow the action.

The server stops at start: SQUALLY_API_KEY is not set. Before anything else, the server checks for the key and, without one, exits with a single line naming the variable. Your client shows that line in the server’s log - Claude Desktop in mcp-server-squally.log (in ~/Library/Logs/Claude on macOS, %APPDATA%\Claude\logs on Windows), Cursor in the Output panel under MCP Logs. Add the key to the client’s config (Setup) and restart the server.

It refuses the key as an ingest key. A key that starts with sqly_ but not sqly_ro_ is a project ingest key - the one your Playwright reporter uses to upload results. The server refuses it at start, by name, before any request. Create an organization read key under Settings → API keys.

tier_too_low. The organization is on Free, and the read API is part of Standard and Pro. The agent gets the API’s sentence as a tool error and passes it on, rather than reporting Squally as unreachable. Keys are not revoked on a downgrade; they work again after an upgrade.

Rate limited. Over the limit, the tool answers: wait 60 seconds, then retry. The limit comes from the edge, which sends no body and no Retry-After - so waiting 60 seconds is the whole instruction. The numbers are on Rate limit.

A note that the key expires. From 7 days before your key expires, every successful tool result carries one extra line with the date. Keys are not renewed: create a new key, put it in the client’s config, and revoke the old one. After the date, calls are answered key_expired.

Every other error reaches the agent as the API’s sentence, its code and what to do about it. All codes: the error table on Conventions.

Set SQUALLY_API_URL next to SQUALLY_API_KEY to point the server at another Squally, such as a local one: http://localhost:3000. It takes the base only - the server appends /api/v1 itself, and tolerates a trailing / or /api/v1. Without it, the server talks to https://app.squally.dev. Use a read key created in that app: a key is only known to the app that issued it.

If the address is wrong, the tool answers that it could not reach the Squally API there.

The key stays on your machine, in your agent’s local config. The server reads it from its environment, sends it only to the Squally API as the Authorization header, and never prints it. Keep it out of anything you commit: the user-level configs above keep it out of the repository.

The key reaches every project in the organization. Create one per machine, so a single revocation does not lock out everything, and revoke it in Settings → API keys when you no longer need it. The list there shows when each key was created, last used, and when it expires.

Provenance. Every version from 0.1.1 on is published from the package’s GitHub Actions workflow with an npm provenance attestation: a signed statement linking the tarball to the workflow run and the commit it was built from. To check the latest version:

npm view squally-mcp dist.attestations

A version with provenance answers with the attestation’s url and predicateType: 'https://slsa.dev/provenance/v1'; one without answers nothing. 0.1.0, published by hand before trusted publishing was set up, is the only version without.