npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@percio/mcp

v5.0.0

Published

Model Context Protocol server for Percio — define a usability test, Percio runs it

Readme

@percio/mcp

Use Percio from your AI assistant.

Percio helps you run AI-guided usability tests on real sites: you describe what to check and which user mindset matters, and Percio walks through the flow and reports findings.

This package is an MCP server (Model Context Protocol): assistants that support MCP can call Percio on your behalf — drafting the test from your repository and your request, launching it on your Percio account, and reporting the findings back in chat.

v5 changes who drives the browser. Percio's own runner now executes the run, in character as the persona, with every evidence pipeline attached. Your assistant defines the test and watches; it no longer clicks through the flow itself, so a run costs you almost no tokens.

Local targets run on Percio's motor too, with nothing to install. localhost:3000 is invisible to a browser in the cloud, so percio_start_test opens a short-lived HTTPS tunnel in front of that one origin and the run executes normally against it. The tunnel binary ships with this package — no account, no login, no port forwarding, no firewall change; the connection is outbound, from your machine. It exposes nothing but the origin you approved, you are told which one before it happens, it closes when the run finishes or when the MCP process exits, and the run is filed under your local URL rather than the ephemeral tunnel hostname.

If a tunnel cannot be opened — or the target is unreachable for some other reason — percio_start_test hands the browser back to your assistant and it drives locally, exactly as in v4. That fallback path is unchanged, and it is reported honestly: a run executed that way cannot claim high score confidence.

Upgrading from v4? Nothing in your config changes. What changes is the flow: percio_start_test returns an execution_id and a live_url, and Percio executes the run on its own motor. The thirteen browser tools (percio_navigate, percio_get_state, percio_click, percio_type, percio_scroll, percio_go_back, percio_screenshot, percio_extract_content, percio_step_result, percio_complete, percio_save_result, percio_list_sessions, percio_close_session) are gone, together with the host-driven fallback they belonged to — calling one returns a removal notice. Follow percio_run_status for progress and results.


What you need

  • Node.js (a current LTS version is fine).
  • A Percio account and API key from percio.app (account settings / Integrations).
  • Nothing for local targets. The cloudflared binary that makes your dev server reachable is installed with this package and managed for you.
  • No browser for a run. Percio executes the flow on its own infrastructure; nothing in a test run opens a browser here. The one exception is scrape_url against a localhost URL, which reads that page with a local headless browser — if you use it, install one once with npx playwright install chromium.

You do not need to npm install this package globally; your assistant runs it via npx (see below).


Configure your assistant

Every MCP client needs three things: run the server with npx, pass -y and @percio/mcp, and set your API key in the server environment.

Cursor

  1. Open Settings → MCP (or your project’s MCP config file, e.g. .mcp.json).
  2. Add a server (any name you like, e.g. percio).
  3. Command: npx
  4. Arguments: -y, @percio/mcp
  5. Environment: PERCIO_API_KEY = your key from Percio.

Example:

{
  "mcpServers": {
    "percio": {
      "command": "npx",
      "args": ["-y", "@percio/mcp"],
      "env": {
        "PERCIO_API_KEY": "$API_KEY"
      }
    }
  }
}

Save, reload MCP if the app asks you to, and confirm Percio appears in the MCP server list.

Claude Desktop

  1. Open Developer settings and edit the MCP JSON config.
  2. Under mcpServers, add an entry with the same shape as above (npx, args -y + @percio/mcp, PERCIO_API_KEY in env).
  3. Restart Claude Desktop.

Other MCP clients

If the client supports stdio servers with command, args, and env, use the same pattern: npx + -y + @percio/mcp + PERCIO_API_KEY.


What Percio measures

Percio is an instrument for observing how one specific person experiences a flow. Its findings are friction, hesitation, doubt, discoverability failure and abandonment.

It is not a regression suite — verifying that features still work is not the task. A flow where every control functions and the persona still cannot accomplish what they came for is a bad result, and reporting it is the job. Abandoning where a real user would abandon is a valid outcome, not a failed test. success: false is evidence, never a failed assertion. Never re-run a step to confirm behaviour — the first encounter is the only honest one. There is no pass/fail vocabulary in the output.

Who narrates

Percio's runner does. It carries the persona in its system prompt, decides each step in character, and writes the first-person rationale the analysis reads — which is why the findings describe hesitation and doubt rather than restating a click log.

Before 5.0.0 a host driving the fallback wrote that text itself, and the quality of a run depended on how well the host followed a narration contract. That contract is gone from this package along with the tools it governed.

The persona briefing still arrives in band on percio_start_test (persona_briefing) so the assistant knows who the run is about, whether or not the host fetches the optional usability_test prompt.

Severity

Severity describes what the persona did, not how bad the pixel looked:

| Severity | The persona… | | --- | --- | | critical | abandoned the task here, or completed it wrongly without noticing | | high | got through, but only after a wrong turn, a retry, or help they would not normally have had | | medium | hesitated and had to reason it out — the cost is time and confidence, not completion | | low | noticed it and was mildly annoyed; completion and confidence unaffected |

abandoned vs failed

abandoned = the run could not proceed for reasons outside the product's design (too little test data or variety, environment unavailable, budget exhausted) — persisted as not scorable, charged no penalty. failed = the product itself failed the persona. A run stopped by missing test data is abandoned, never failed.

percio_run_status returns the usability_score, its score_confidence (high/medium/low — how much the run earned the right to claim, never moving the score) and a score_breakdown naming every deduction, so the number can be reconciled with the findings instead of taken on trust.

How to use

  1. In chat, say which site (URL) you want tested and type the scenario yourself in plain language (≥ 20 chars). The assistant won't author the scenario from URL/persona alone — Percio's contract is that the user owns the scope.
  2. The assistant will ask whether the flow needs runtime credentials (login email/password, API tokens, …). Paste them in chat if so; they're forwarded only to this run and discarded after.
  3. Confirm when you're ready — the assistant calls percio_confirm_scenario(confirmed:true, scenario, credentials_asked:true) and then percio_start_test.
  4. Open the live_url the assistant shares. That's your run executing in real time — the transcript, the screenshots, the cursor. When it finishes, the same page becomes the report.

If something fails, check: the API key is correct, the target is reachable from the internet (or is a local URL this package can tunnel), and your Percio plan allows the action you requested.

Tool order (canonical Path A)

The host model must follow this order; the server returns structured errors for skipped steps.

  1. list_projects (the human picks) and list_personas (and optionally create_persona for a custom one).
  2. The assistant drafts the mission, stop condition and scenario; the human approves them. The assistant asks about runtime credentials.
  3. percio_confirm_scenario({ confirmed: true, project_id, mission, stop_condition, scenario, credentials_asked: true, url }). For a local url the response carries a tunnel_notice; state the exposed origin and its lifetime to the human before step 4.
  4. percio_start_test({ url, persona_id, project_id, mission, stop_condition, scenario, credentials? }).
  5. Branch on the returned execution_mode:
    • server_side — Percio runs it. Share live_url with the human, then poll percio_run_status({ execution_id }) when you want progress or the result. The browser tools are rejected for this run. When it also carries via: "local_target_tunnel", the run reaches your machine through a tunnel owned by this MCP process: relay tunnel.exposed_origin, keep the session open until the run finishes, and pass on any fidelity_warnings (they are configuration notes about running a dev server behind a changed origin, not findings about the product).
    • tunnel_refused — not a run. The tunnel opened but what answers through it would not be your product (typically a Next dev server rejecting the tunnel host). Nothing was created, nothing billed; show the blocking condition, let the human fix it, call again.
    • refused — neither reachable nor tunnellable, and the response says why (reason_code, plus tunnel_unavailable for a local target). No run was created and no credit was spent. Relay the reason and next_step; there is no host-driven mode to fall back to, because a run the host drove itself would measure a different motor and could not mean the same thing.

A target the runner cannot reach costs no credit — reachability is checked before anything is created or billed. A run whose tunnel drops mid-flight is recorded as abandoned, not failed: no usability score is charged to the product and the credit is refunded.

create_persona (session-based)

BREAKING (v2.1.0): create_persona no longer accepts { name } only. It runs the same multi-turn guided conversation as the web app (POST /api/agent/persona-chat), then saves via POST /api/agent/personas when the chat signals completion.

  1. First call: omit persona_session_id. Optionally pass user_message if the user already gave a short description.
  2. Response: JSON includes persona_session_id, assistant_message, and phase: "conversation" until done.
  3. Follow-ups: pass persona_session_id and user_message (the user’s exact reply — never fabricated).
  4. Done: when phase is "complete", the persona row is created; the payload includes the persisted persona.

Sessions expire after 1 hour; the server keeps at most 200 active sessions (oldest evicted when over capacity).

Runtime credentials

percio_start_test accepts an optional credentials array of { name, value } objects (≤ 20 entries, name 1–120 chars, value 1–4000 chars — same limits as the Test Lab modal in the web app). Forward only the values the user just gave you in chat; never source credentials from .env, host secrets, or staging defaults.

On a server-side run they travel to Percio, encrypted. The runner is the thing that has to type them, so they are stored on the run with AES-256-GCM, decrypted in-flight by the runner only, never logged, never sent to a model, and wiped when the run reaches a terminal status.

There is no longer a path where they stay on your machine: with the host-driven fallback gone, the runner is always the thing that types them.

Credentials are never echoed in any MCP tool response.

What leaves your machine

Percio receives the target URL, the mission, the stop condition, the scenario, the persona id, the project id, and any credentials the human supplied. Your repository is not read and no file contents are sent.

Local targets: the tunnel

The binary ships with the package, so there is nothing to install. Two things worth knowing:

  • Keep the session open. The tunnel lives in this MCP process. Closing it closes the tunnel, and the run is recorded as abandoned with its credit refunded — never charged to the product as a failure.
  • Cloudflare rate-limits account-less tunnels per IP. Several local runs back to back can hit HTTP 429 / error 1015. It clears by itself in a few minutes; the tool says so explicitly rather than reporting a generic failure, and the run is refused rather than downgraded — try again shortly.

PERCIO_TUNNEL=0 skips the tunnel entirely, which means local targets are simply refused. PERCIO_CLOUDFLARED_BIN points at your own cloudflared if you would rather use it than the bundled one.

PERCIO_MCP_SKIP_CREDENTIALS_GATE (CI only)

Mirrors PERCIO_MCP_SKIP_PERSONA_TOKEN. Set to 1 / true / yes to make credentials_asked:true implicit on percio_confirm_scenario. Use this in scripted automation where there is no human to ask; never enable it in a host that talks to a real user.


Help

Product site and account: percio.app