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

@reevit/mcp

v0.2.0

Published

Reevit MCP server — let AI agents create payment links, check payments, and issue refunds through your Reevit account

Readme

@reevit/mcp

MCP server for Reevit — lets AI agents create payment links, look up payments, issue refunds, and read analytics through your Reevit account, using a scoped API key you control.

📖 Full documentation: docs.reevit.io/docs/reevit/mcp

Tools

| Tool | What it does | Scope needed | | --- | --- | --- | | reevit_create_payment_link | Shareable pay link (fixed or open amount) | payment_links:write | | reevit_list_payment_links | Links with filters and use counts, paged | payment_links:read | | reevit_get_payment_link | One link by id (plink_…) | payment_links:read | | reevit_get_payment | One payment by id, with status + route | payments:read | | reevit_list_payments | Recent payments with filters, paged | payments:read | | reevit_get_payment_failures | Why a payment failed: provider error, fault party, retriable | payments:read | | reevit_get_payment_status_history | Ordered status transitions and what triggered each | payments:read + a plan with audit logs | | reevit_create_refund | Full/partial refund — live mode requires human approval | payments:write | | reevit_get_refund | One refund by id — did it actually settle? | payments:read | | reevit_list_refunds | Refunds account-wide, or every refund on one payment | payments:read | | reevit_get_payment_analytics | Volume, counts, success rate | payments:read |

Scopes are enforced by the Reevit backend on every call: a payments:read-only key cannot refund, no matter what the model asks for.

reevit_get_payment_status_history carries a second gate on top of scopes — a plan-feature check for audit logs. It answers 402, not 403, when the account plan does not include it. The two are distinct on purpose: 403 is about the key and 402 is about the account, so no amount of re-keying clears a 402.

Renamed in 0.2.0. Tool names are now prefixed reevit_, and get_analytics_summary became reevit_get_payment_analytics. Tool names share one flat namespace across every server in a session, so the old names collided with any other server exposing a get_payment or get_analytics_summary — and told the model nothing about which product they queried. Nothing needs changing in your config; if you have prompts or agent instructions that name tools explicitly, update them.

Results are typed in 0.2.0. Every tool now declares an outputSchema and returns structuredContent alongside the JSON text, so clients get typed data rather than a blob to re-parse. Two results changed shape to make room for it: reevit_get_payment returns { payment: … } and reevit_create_payment_link returns { payment_link: … }, matching the wrapping reevit_list_payments and reevit_create_refund already used.

The schemas are deliberately permissive — every field optional and nullable, unknown fields passed through. The SDK turns a schema mismatch into a failed call, so a schema stricter than the API would break a working read rather than report a data problem. Treat them as documentation of the common fields, not as a guarantee that a field is present.

Setup

Create an API key in the Reevit dashboard (Developers → API keys) with only the scopes you want the agent to have.

Claude Code

claude mcp add reevit -e REEVIT_API_KEY=pfk_test_... -- npx -y @reevit/mcp

Claude Desktop

Add to claude_desktop_config.json (Settings → Developer → Edit Config):

{
  "mcpServers": {
    "reevit": {
      "command": "npx",
      "args": ["-y", "@reevit/mcp"],
      "env": { "REEVIT_API_KEY": "pfk_test_..." }
    }
  }
}

Cursor

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

{
  "mcpServers": {
    "reevit": {
      "command": "npx",
      "args": ["-y", "@reevit/mcp"],
      "env": { "REEVIT_API_KEY": "pfk_test_..." }
    }
  }
}

VS Code (Copilot agent mode)

Add to .vscode/mcp.json in your workspace:

{
  "servers": {
    "reevit": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@reevit/mcp"],
      "env": { "REEVIT_API_KEY": "pfk_test_..." }
    }
  }
}

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "reevit": {
      "command": "npx",
      "args": ["-y", "@reevit/mcp"],
      "env": { "REEVIT_API_KEY": "pfk_test_..." }
    }
  }
}

Cline

Open Cline → MCP Servers → Configure, and add the same mcpServers entry as Cursor/Windsurf above to cline_mcp_settings.json.

Zed

Add to Zed settings.json:

{
  "context_servers": {
    "reevit": {
      "command": { "path": "npx", "args": ["-y", "@reevit/mcp"] },
      "settings": {}
    }
  }
}

Set REEVIT_API_KEY in the environment Zed is launched from.

Codex CLI

Add to ~/.codex/config.toml:

[mcp_servers.reevit]
command = "npx"
args = ["-y", "@reevit/mcp"]
env = { REEVIT_API_KEY = "pfk_test_..." }

Gemini CLI

Add to ~/.gemini/settings.json:

{
  "mcpServers": {
    "reevit": {
      "command": "npx",
      "args": ["-y", "@reevit/mcp"],
      "env": { "REEVIT_API_KEY": "pfk_test_..." }
    }
  }
}

Configuration

| Env var | Default | Notes | | --- | --- | --- | | REEVIT_API_KEY | — (required) | Scoped API key from the dashboard. Must start pfk_test_ or pfk_live_ | | REEVIT_API_URL | https://api.reevit.io | Point at a self-hosted / local API | | REEVIT_MCP_HTTP_TOKEN | — | Bearer token required by --http. See Streamable HTTP mode | | REEVIT_MODE | derived from the key | Optional. If set it must agree with the key, or the server refuses to start |

Mode comes from the key

Test vs live is a property of the API key (pfk_test_… / pfk_live_…), not of the environment. The backend derives it from the key prefix and ignores any mode header on API-key requests, so REEVIT_MODE cannot put a live key into test mode — it can only misdescribe one. The server therefore derives mode from the key, and treats a contradicting REEVIT_MODE as a startup error.

A key with an unrecognized prefix is rejected at startup rather than assumed to be test — that also catches a truncated or mispasted key immediately instead of on the first API call.

Safety model

  • Scopes, not trust: authorization lives in the backend key scopes.
  • Live-money gate: reevit_create_refund in live mode will not proceed without human approval of that specific refund. Live mode is determined by the key, so this cannot be bypassed by omitting or mis-setting REEVIT_MODE. There are two mechanisms, and which one applies depends on the client:
    • The client supports elicitation — the server sends an elicitation/create request naming the payment, the amount and the reason, and the client puts it to the user. This supersedes confirm entirely: the refund proceeds only on an explicit approval, and setting confirm: true does not skip the prompt. It fails closed — a decline, a dismissal, a submitted-but-unticked form, or an error reaching the client all refuse the refund without calling the API.
    • The client does not — the server falls back to requiring confirm: true on the call. This is weaker on purpose-of-necessity: confirm is a tool input, so the model writes it, and the gate is only as good as the agent's honesty. Prefer a client that can elicit for live keys.
  • Credentials never enter the transcript: a payment's client_secret (and any *_secret field, at any depth, including inside the opaque next_action provider blob) is replaced with a [redacted …] marker before the result leaves the server. These are bearer tokens for a single payment — holding one is enough to drive that payment to completion without an API key — and reevit_get_payment previously returned them verbatim, so an ordinary read-only lookup wrote a live credential into the model's context and into whatever transcript or log the client keeps. The marker replaces the value rather than dropping the key, so an agent is told the field is withheld instead of concluding it was empty.
  • Raw API keys are caught by shape, not just by name: any string anywhere in a result matching a full pfk_test_…/pfk_live_… key (id and secret half) is replaced before the result leaves the server. This backstops the field-name sweep above, which is blind to a credential that turns up somewhere nobody expected — and one did: api_key_id on payment links held whole raw keys until migration 000139 scrubbed them. A bare key id with no secret half is left alone, because that is a reference the field is meant to carry. Only the key itself is replaced, not the string around it, so an error message quoting one stays readable.
  • Provider response bodies are truncated, not trusted: response_body on a failure event is whatever the PSP returned — usually a short JSON error, sometimes a gateway's HTML page. It is swept for keys and then cut at 2000 characters with an explicit marker, so one oversized body cannot crowd the other failures out of the result.
  • Idempotency: money-moving calls send an Idempotency-Key derived from the request itself — a SHA-256 of the method, path and canonicalised body. So a retry of the same logical operation carries the same key, whether the retry comes from this client's own backoff or from an agent re-issuing a tool call that timed out. The backend deduplicates it and no second refund is created. (Before 0.2.0 the key was a fresh UUID per invocation, which could not deduplicate anything; the backend's over-refund check was the only thing standing between a retried tool call and a double refund.)
  • Deduplication is visible, not silent: the flip side of stable keys is that a deliberate repeat with identical parameters inside the backend's idempotency window (24h by default) also collapses. When that happens the result says "replayed": true and explains that no new refund was created, rather than returning the older refund as if it were new. Pass a distinct idempotency_key to force a genuinely separate second refund.
  • Bounded work: each request gets a 30s deadline and the whole call, retries included, gets 60s. Retries are capped at 3 attempts with jittered backoff, honour Retry-After, and only ever replay a GET or a request carrying an idempotency key.
  • Amounts are minor units everywhere (GHS 50.00 = 5000).

Streamable HTTP mode

For remote/agent-platform use, run the same server over streamable HTTP (stateless; each request gets a fresh server, no session leakage):

REEVIT_API_KEY=pfk_test_... \
REEVIT_MCP_HTTP_TOKEN="$(openssl rand -hex 32)" \
  npx -y @reevit/mcp --http --port 8788
# endpoint: http://127.0.0.1:8788/mcp
# every request needs:  Authorization: Bearer $REEVIT_MCP_HTTP_TOKEN

REEVIT_MCP_HTTP_TOKEN is required — the server refuses to start without it. Anyone who can reach this endpoint can drive every tool with your key, including reevit_create_refund, so it is not an optional hardening step.

Three guards apply in HTTP mode:

  • Loopback bind. It listens on 127.0.0.1, not 0.0.0.0, so it is not reachable from the rest of your network by default. Override with host only behind a boundary you control.
  • Bearer token. Compared in constant time; a missing or wrong token is a 401.
  • DNS-rebinding guard. Requests whose Host is not a loopback name get a 403, so a website you visit cannot script your local server.

Bodies over 1 MB are rejected with 413.

For local-only experiments you can pass --allow-insecure-no-auth to skip the token. It logs a warning and should never be used anywhere but your own machine.

Development

npm install
npm test        # vitest — gate + request-shaping tests
npm run build   # tsc → dist/
REEVIT_API_KEY=pfk_test_... npm run dev