AI agents: read this page as markdown at /docs/agents/mcp-server.md, or start from the full AI-readable index at /llms.txt.

MCP server for agents

The Meticulous MCP server provides tools which enable agents to interface with Meticulous: get test run diffs, replay details, coverage, and more. It's a hosted Model Context Protocol endpoint, hosted at https://app.meticulous.ai/api/mcp. We furthermore provide agent skills which compose these tools into higher-level workflows, like a skill to review a PR test run.


What it's for

Meticulous records real user sessions in your app and replays them against every commit to catch visual regressions before they ship. This server lets an agent — reviewing a PR, debugging a failing check, or investigating coverage — pull that data directly: which screenshots changed and why, whether a diff is a real regression or noise, which lines of a change are covered by a test, and (for CI/build agents) trigger a new run against a build.


Connecting a client

The server is an OAuth 2.1 protected resource — it supports dynamic client registration and standard discovery (/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server), so clients connect with just the endpoint URL above. There is no client id, secret, scope, or authorization-server URL to configure by hand. Login happens in your browser on first connect and tokens refresh automatically.

Claude Code

Run the following in your terminal:

claude mcp add --transport http Meticulous https://app.meticulous.ai/api/mcp

Then, in Claude Code, type /mcp and choose "Authenticate" for the Meticulous MCP.

Cursor

Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (per project):

{
  "mcpServers": {
    "Meticulous": { "url": "https://app.meticulous.ai/api/mcp" }
  }
}

Codex/ChatGPT

Add a server with name "Meticulous" and URL https://app.meticulous.ai/api/mcp, then click "Authenticate".

Calls are scoped to your default project. If you only have access to a single project, that one is used automatically; otherwise set a default in your user settings in the web app, or via the CLI: meticulous auth set-project.


Authenticating with a token instead

Any MCP client can also authenticate with a static bearer token instead of the browser OAuth flow — useful in CI, or wherever an interactive login isn't possible. The token is a Meticulous OAuth token or a project API token (see Setup > Org-wide setup for how to obtain one). A project API token scopes every call to that one project.

{
  "url": "https://app.meticulous.ai/api/mcp",
  "headers": { "Authorization": "Bearer <token>" }
}

Available tools

Every tool takes broadly the same arguments as its matching CLI command and returns the same data as that command's --json output — with minor differences inherent to a hosted endpoint rather than a local CLI (for example, no git-inferred commitSha, since the server has no checkout to infer it from). "Access" below reflects each tool's MCP annotations, which determine whether a client can call it without per-call confirmation.

Identity and project selection

ToolAccessWhat it does
whoamiReadShow the identity the connection is authenticated as, and the project it resolves to.
list_projectsReadList the projects the authenticated user can access.
get_projectReadShow the project project-scoped tools use when not given a project argument, and where that came from.
set_projectWriteChange the default project for the user account — every session and machine, not just this connection.

Test runs and diffs

ToolAccessWhat it does
get_test_run_for_commitReadLook up the latest test run for a commit; returns its ID and status.
get_test_run_diffsReadGet the (curated or full) list of screenshot diffs for a test run.
get_test_run_diffs_countsReadGet aggregate diff counts for a test run, including the six-way review-decision breakdown.
get_image_urlsReadGet signed URLs for a screenshot diff's before/after/diff images.
get_dom_diffReadGet the structural DOM diff for one screenshot diff, as unified-diff-style hunks.
get_timeline_diffReadGet the list of timeline event differences (e.g. network requests, DOM mutations) for a replay diff.
get_test_run_checkReadGet the Markdown report for a builtin or custom non-visual check.
get_test_run_check_available_idsReadList the check IDs available for a test run, for the checks that have reported results so far.

Computing a test run's diffs is asynchronous — the tool returns { status: 'processing' } until done. A poll can itself start the underlying compute workflow; that lazy compute does not make the tool a write. A failed result (with a reason) means nothing is still computing — stop polling; a test-run-not-ready reason can be retried by calling again a minute or more later, the others cannot.

get_test_run_check is also asynchronous: it returns { status: 'processing' } until the separately computed results arrive. Poll every 10s for at most 3 minutes — the same budget the CLI gives itself — and treat still-processing after that as "not reported yet" rather than polling on. A completed response is { status: 'complete', text }, or { status: 'complete', text, url } when the report is too large to return inline — text is then a short notice and the full report is downloadable from url. A failed result (with a reason) is final — there is no way to retry. With checkType: 'custom', an error saying the run is not expecting custom check results can be transient shortly after the run completes, since your CI registers its checks separately from the run itself — retry for a minute or so before concluding the run has none. Use get_test_run_check_available_ids to find a valid checkId instead of guessing one.

Reviewing diffs

ToolAccessWhat it does
get_diff_commentsReadGet the review comments (with replies) for a screenshot diff, oldest first.
reject_diffWriteAgent-reject a screenshot diff and comment why.
ignore_diffWriteAgent-ignore a screenshot diff and comment why.
create_diff_commentWriteStart a review comment thread at approximate image coordinates.
reply_to_diff_commentWriteReply to an existing review comment thread.

JS coverage

ToolAccessWhat it does
get_test_run_js_coverageReadGet per-file JavaScript coverage for a test run.
get_project_js_coverageReadGet per-file JavaScript coverage for a project's latest successful test run.
get_replay_js_coverageReadGet per-file JavaScript coverage for a single replay, or one screenshot of it.
get_replay_diff_js_coverage_diffReadGet per-file JavaScript coverage differences (base vs. head) for a replay diff.

Sessions

ToolAccessWhat it does
get_sessionsReadList a project's most recently created recorded sessions, newest first.
get_session_dataReadGet the recorded user-flow and network summary for a session — useful for understanding what a replay exercises.

Triggering a test run

ToolAccessWhat it does
request_asset_uploadWriteRequest a signed URL to upload a zipped static-asset build.
register_asset_buildWriteRegister an uploaded zipped asset build as a reusable deployment.
request_container_uploadWriteRequest registry credentials to push a Docker container build.
register_container_buildWriteRegister a pushed container build as a reusable deployment.
trigger_test_runWriteTrigger a test run against a registered deployment (or one already uploaded for a commit).
complete_base_runWriteReplay the selected sessions a base run has not run yet.

Feedback

ToolAccessWhat it does
submit_feedbackWriteSend free-form feedback about Meticulous to the Meticulous team.

What this connector can access

  • Reads: your identity and the projects you can access; test runs and their status; screenshot diffs, outcomes, and images; DOM and timeline diffs; JavaScript coverage; and recorded session data (the user flow and network requests a session exercises).
  • Writes (only when the corresponding tool is called): uploads a build's assets or container image, registers it as a deployment, triggers a new test run against it, changes your account's default project, and submits feedback to the Meticulous team.
  • Never accesses: your repository's source code, or PR titles/descriptions — Meticulous's diffs and coverage are computed from screenshots, DOM snapshots, and instrumented JS execution, not from reading your code.
  • Scope: every call is scoped to the projects the authenticated user (or, for a project API token, the single owning project) has access to.

Troubleshooting

  • 401/403 on every call: your token has expired or was revoked — reconnect via /mcp (Claude Code) or your client's equivalent to re-authenticate.
  • "No default project" errors: call set_project (list_projects shows the options), set one from your user settings in the web app, or run meticulous auth set-project — or, for a one-off call, pass the optional project argument most tools accept (id, org/proj, or simply proj; only honored for an OAuth user token, not a project or test-run API token).
  • A lookup returns nothing when you expected results: it may have run against a different project. The default project is stored against your user account, so it is shared with the CLI and every other session, and changing it anywhere changes it everywhere. Call get_project to see which project is in play — an empty test-run or session result already names it for you.
  • SSO-only organizations: if your organization enforces a specific identity provider, a token issued outside that flow is rejected; log in again through your organization's SSO entry point.
  • Anything else: contact us (see below).

Support and policies