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

@4pay.online/mcp-server

v1.0.0

Published

MCP server for 4pay.online platform operators

Readme

@4pay.online/mcp-server

MCP (Model Context Protocol) server for Surelle payment processing platform. Enables AI assistants (Claude, GPT) to interact with Surelle via standardized tools.

Two servers, not one

The platform ships two MCP servers, and they are different programs on purpose:

| Server | Who runs it | What it exposes | |---|---|---| | @4pay.online/mcp-server (this package) | the platform operator — the client who owns the organization | the platform itself: terminals, routing, limits, FX, organizations, partners, plus the payment counter | | @4pay.online/payments-mcp (its own repository) | the merchant — the partner who takes payments | payments, payouts, refunds, payment links, saved cards. Nothing else |

A merchant's agent has no business seeing terminals and routing rules: given them, an agent working through a declined payment will eventually try to "fix" the live routing. That is not a prompt problem — a tool absent from the list cannot be called, whatever anyone types. So the partner package lives in its own repository and contains no operator code at all: not disabled, not filtered, absent.

Hand partners @4pay.online/payments-mcp. Keep this one for the people who run the platform.

Quick Start

Install from npm:

npm install -g @4pay.online/mcp-server

The package contains its compiled distribution, so installation needs neither the repository nor development dependencies.

Claude Code

Add to .mcp.json in your project root. Credentials come from the environment, so no secrets live in the file:

{
  "mcpServers": {
    "surelle": {
      "command": "npx",
      "args": ["-y", "@4pay.online/mcp-server"],
      "env": {
        "SURELLE_API_URL": "${SURELLE_API_URL}",
        "SURELLE_LOGIN": "${SURELLE_LOGIN}",
        "SURELLE_PASSWORD": "${SURELLE_PASSWORD}",
        "SURELLE_ORGANIZATION_ID": "${SURELLE_ORGANIZATION_ID}"
      }
    }
  }
}

Export the variables before starting the client:

export SURELLE_API_URL=https://sandbox.4pay.online
export [email protected]
export SURELLE_PASSWORD=...
# Organization is optional — see Multi-tenancy
export SURELLE_ORGANIZATION_ID=...

Then install the agent skill into the project the agent works from — the server ships with it:

npx -y @4pay.online/mcp-server install-skill /path/to/your/project

The server logs in on its own — give it a login and password, not a token. It obtains the session token, renews it before expiry, and logs in again when the server rejects a stale session, retrying the request. A session token lasts a week, so a hand-copied SURELLE_BEARER_TOKEN stops working silently — use it only for one-off runs or when there is no password (SSO).

Two-factor authentication is required by default; see below.

Updating

npm install -g fails with ENOTEMPTY while the server is running — npm renames the package directory, and a live process holds it. Stop the MCP server in your client first (or close the session), then update:

npm install -g @4pay.online/mcp-server

A running client keeps the old build in memory regardless: restart the MCP server to pick up a new version.

Building from source

git clone [email protected]:heth_project/surelle-mcp.git && cd surelle-mcp
npm install
npm run build          # dist/ is committed, but rebuild after editing src/
npm test

Point .mcp.json at node /abs/path/to/surelle-mcp/dist/index.js instead of npx.

The catalog, typed tools and wizard registry are committed, so a fresh clone works without the neighbouring repositories. Regenerating them (npm run generate:all) does need surelle and admin_area checked out next to this one — see Generated artifacts.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json — same shape, but write the values literally, since Desktop does not read your shell environment:

{
  "mcpServers": {
    "surelle": {
      "command": "node",
      "args": ["/path/to/surelle-mcp/dist/index.js"],
      "env": {
        "SURELLE_API_URL": "https://sandbox.4pay.online",
        "SURELLE_API_KEY": "your-api-key"
      }
    }
  }
}

Configuration

| Environment Variable | Required | Default | Description | |---------------------|----------|---------|-------------| | SURELLE_API_URL | No | http://localhost:4000 | Surelle API base URL | | SURELLE_API_KEY | Yes* | — | Partner API key (X-API-Key header) | | SURELLE_LOGIN | Yes* | — | Login for automatic sign-in | | SURELLE_PASSWORD | Yes* | — | Password, paired with SURELLE_LOGIN | | SURELLE_ACCOUNT_TYPE | No | client | Role to sign in as: client / partner / admin / person | | SURELLE_TOTP | No | — | One-time code when 2FA is enabled | | SURELLE_BEARER_TOKEN | Yes* | — | Ready session token; the server cannot renew it | | SURELLE_ORGANIZATION_ID | No | — | Default tenant → x-organization-id header. Required for admin tokens | | SURELLE_TIMEOUT | No | 30000 | Request timeout (ms) | | SURELLE_RETRY_COUNT | No | 2 | Retry count for 5xx errors |

*At least one way to authenticate: SURELLE_LOGIN + SURELLE_PASSWORD (preferred), SURELLE_BEARER_TOKEN, or SURELLE_API_KEY.

SURELLE_API_KEY authenticates a partner, not a client: it opens the payment surface (transactions, links, products, recurring payments) and nothing of the organization's settings. The two can be set together — the server sends both, so payment calls go as the partner while settings go as the client.

Tools

The API exposes 1283 operations. Registering one flat tool per operation would make tools/list weigh ~580 KB and crowd out the actual task, so coverage is split in two: typed tools for the hot path, a catalog for everything else. Total footprint: 22 tools, ~15 KB.

Catalog — all 1283 operations

| Tool | Description | |------|-------------| | surelle_list_domains | 82 domains with operation counts — start here when you don't know where a setting lives | | surelle_search_operations | Find operations by keywords, domain, method, read-vs-write | | surelle_describe_operation | Full parameter and body schema for one operation | | surelle_call_operation | Execute any operation. State-changing ones require confirm=true |

Operator handbook

| Tool | Description | |------|-------------| | surelle_search_help | Search 224 handbook articles (ru/en) — what a thing is for and when it is used | | surelle_get_help | One article in full: concepts, worked example, pitfalls |

Pass locale: "en" for English; Russian is the default. Both translations are complete — 224 articles each. Wizard titles inside an English article stay Russian: the wizard registry is extracted in one language only.

The API catalog answers "how do I call this"; the handbook answers "when and why". Articles that share a route with a wizard point at it.

Setup wizards

| Tool | Description | |------|-------------| | surelle_list_wizards | 64 guided setup flows mirrored from admin_area, all with their API operations resolved | | surelle_get_wizard | Prerequisites, steps, required permissions and the operations behind one wizard |

Typed tools — hot path

49 generated tools cover the settings domains an operator touches constantly: terminals and providers, routing rules and health, limits and blacklists, FX rates and currencies, organizations and members, clients, partners, marketplace modules, pricing plans. Generated from the spec — the operation list lives in CURATED in scripts/build-typed-tools.ts.

16 hand-written tools cover transactions, wallets, ledger, cards, invoices and audit log.

All of them accept an optional organization_id — see Multi-tenancy below. State-changing ones take confirm, which the dispatcher requires before it will send the request.

Platform AI tools — discovered, not hard-coded

The platform runs its own tool registry inside Elixir (Surelle.AI.ToolRegistry): permissions, denylist, input schema, tenant scoping, audit and tier-3 confirmation all live there. This server does not keep a copy of that list — it asks for it.

| Tool | Description | |------|-------------| | surelle_ai_tools | Fetch GET /api/v1/ai/tools and re-register the ai_* set. page_domain narrows the catalog | | surelle_ai_invoke | Call a platform tool by its own name — the fallback when the catalog did not load at startup |

Every catalog entry is also registered as a real MCP tool named ai_<platform name>, whose handler is a thin proxy onto POST /api/v1/ai/tools/{name}/invoke. The prefix is not decoration: seven platform names (get_transaction, get_wallet_balance, get_ledger_entries, get_partner, get_terminal, get_af_aggregates, get_routing_health) collide with tools this server already ships, and registering over them would break clients that are already configured.

The catalog is fetched once after connect and refreshed by surelle_ai_tools. A failure is never fatal — the server starts without ai_* tools and says why on stderr. The contour sits behind the copilot_ai marketplace module and is served only to client roles under a session: a partner API key gets nothing, so discovery is skipped when no login or bearer token is configured.

Tier 3 (actions). A tool marked confirmation_required refuses to run without confirm=true — nothing reaches the platform until the operator has seen what would change. With confirm=true the server passes the two-factor elevation window, takes a one-time token from POST /api/v1/ai/tools/{name}/confirmations and only then invokes. If the platform still answers confirmation_required (expired token, arguments changed since it was issued), that comes back as an error saying the action was not performed — never as an empty success.

Amounts

Amounts cross the API as integer minor units. How many of them make one major unit is a property of the currency and the environment, not of its symbol: USDT is 6 decimals on mainnet and 18 on sepolia, ETH is 18, BTC 8, and the platform moved IDR from 2 to 0 by migration on live data. So this server keeps no currency table. It asks the platform — GET /api/v1/currencies (exponent) and GET /api/v1/crypto/currencies?env= (decimals) — caches the answer per environment, and does the arithmetic in BigInt (1 ETH is 10¹⁸ minor units, past Number.MAX_SAFE_INTEGER).

When the scale is unknown the amount is printed as an integer with a minor units marker rather than divided by 100. Both reference endpoints require a client or admin session, so a server configured with only SURELLE_API_KEY will see amounts in that unformatted form — honest, and preferable to a number that is wrong by 10¹⁶.

Client role

The server runs under a client token — an organization owner, not a platform admin. That shapes what is reachable: of 1283 operations, roughly 430 are open to a client, ~370 open up by activating a marketplace module, ~180 depend on a BaaS capability of the organization, and ~150 are admin-only.

The server logs in on its own — give it a login and password, not a token:

export [email protected]
export SURELLE_PASSWORD=...
export SURELLE_ACCOUNT_TYPE=client   # default; the endpoint itself defaults to 'partner'

It obtains the session token, renews it before expiry, and logs in again when the server rejects a stale session, retrying the request. A session token lasts a week, so a hand-copied SURELLE_BEARER_TOKEN stops working silently — use it only for one-off runs or when there is no password (SSO).

Every operation in the catalog carries its access state, so the agent sees the obstacle before spending a call: open, needs a module (activatable by the client), needs a BaaS capability, or admin-only. surelle_search_operations hides admin-only operations by default; pass include_admin_only: true to see them.

The access map lives in data/access-probe.json and was produced by probing the sandbox with a real client token. Direct observations are authoritative; states inferred for neighbouring routes are labelled as such and never block a call — that inference is right about 88% of the time.

Two-factor authentication

The server acts as an organization owner and can change production settings, so it requires a second factor by default:

  • It refuses to start if the account has 2FA disabled. Set SURELLE_REQUIRE_2FA=false to work without it, accepting the risk.
  • Sign-in asks for a code. Surelle answers 428 with totp_required, and the server asks the operator through the MCP client — the code comes from a phone, never from a config file.
  • Writes need an elevation window. The first state-changing operation asks for a code; after that, changes go through without further prompts for SURELLE_ELEVATION_MINUTES (default 15). Reads never ask for anything.

The TOTP secret is deliberately not accepted as configuration. A secret sitting next to the password in the same .env is reachable by the same access to the machine — that is a second password, not a second factor.

The client must be able to prompt the user (MCP elicitation). Where it cannot — cron, CI — the server says so plainly instead of silently proceeding without the second factor.

Multi-tenancy

Surelle isolates every tenant and resolves the organization from the x-organization-id header. A token does not carry one on its own.

You usually do not need to look the id up. If the account belongs to exactly one organization, the server resolves it on the first call and says which one it picked. With several, it refuses to guess and lists them with their ids — pass organization_id per call, or set SURELLE_ORGANIZATION_ID. surelle_my_organizations shows the same list on demand.

Working through a partner API key needs none of this: the key itself carries the organization.

Operations whose path already contains {organization_id} take it as a path parameter instead — surelle_describe_operation says which case applies.

Generated artifacts

Two artifacts are snapshots of other repositories and must be regenerated when those change:

| Artifact | Source | Command | |----------|--------|---------| | src/generated/catalog.json | surelle/openapi.yaml | npm run generate | | src/generated/typed-tools.ts | the catalog + CURATED list | npm run generate:typed | | wizards/*.yaml | admin_area routes, pages, hooks, services, i18n | npm run generate:wizards | | src/generated/help.json | admin_area help registry + ru/en locales | npm run generate:help |

The wizard extractor resolves a wizard's page through the routes in App.tsx (names alone are unreliable), then follows its calls through hooks, service objects, named service functions and shared components down to concrete endpoints, matching them against the catalog.

npm run generate:all does all three. npm run check:drift verifies they still match their sources and fails if not — run it in CI, otherwise the server keeps answering, just untruthfully.

Paths default to ../surelle/openapi.yaml and ../../3ds/admin_area; override with arguments or the SURELLE_OPENAPI / ADMIN_AREA_PATH environment variables.

Forward-router paths

282 of the 1283 operations arrive from the spec with a truncated path: OpenApiSpex writes the path inside a forward-mounted router without its prefix, so /standing-orders really means /api/v1/baas/standing-orders. The generator restores the prefix from the controller namespace. Any new forward in the router needs an entry in FORWARD_PREFIXES in scripts/build-catalog.ts, otherwise its operations will 404.

Skill

skills/surelle-settings/ holds the agent skill that drives this server: the working order, money and environment rules, the confirmation protocol for state-changing calls, and how to walk an operator through a wizard step by step.

Install it into a project the agent works from:

npm run install:skill -- /path/to/project

Development

npm install
npm run generate:all   # Rebuild catalog + wizard registry from sources
npm run build          # TypeScript compilation (+ copies the catalog into dist)
npm test               # Run tests
npm run check:drift    # Verify generated artifacts match their sources
npm run dev            # Watch mode (tsx)

Security

  • PCI DSS compliant: card data is tokenized, never exposed as PAN/CVV
  • Amounts in minor currency units (kopecks/cents)
  • API keys transmitted via secure headers only
  • All requests over HTTPS in production

License

MIT