{"_id":"@4pay.online/mcp-server","name":"@4pay.online/mcp-server","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@4pay.online/mcp-server","version":"1.0.0","description":"MCP server for 4pay.online platform operators","type":"module","main":"dist/index.js","bin":{"surelle-mcp":"dist/index.js"},"scripts":{"build":"tsc && node scripts/copy-generated.mjs","dev":"tsx watch src/index.ts","start":"node dist/index.js","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build && npm test","generate":"tsx scripts/build-catalog.ts","generate:wizards":"tsx scripts/build-wizards.ts","generate:all":"npm run generate && npm run generate:typed && npm run generate:wizards && npm run generate:help","install:skill":"node dist/index.js install-skill","check:drift":"node scripts/check-drift.mjs","generate:typed":"tsx scripts/build-typed-tools.ts","generate:help":"tsx scripts/build-help.ts"},"dependencies":{"@modelcontextprotocol/sdk":"^1.26.0","zod":"^3.24.0","yaml":"^2.9.0"},"devDependencies":{"@types/node":"^22.0.0","tsx":"^4.19.0","typescript":"^5.7.0","vitest":"^3.0.0"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public","provenance":true},"overrides":{"esbuild":"^0.28.1"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/surelle/surelle-mcp.git"},"homepage":"https://4pay.online","bugs":{"url":"https://github.com/surelle/surelle-mcp/issues"},"keywords":["mcp","surelle","payments","model-context-protocol"],"_id":"@4pay.online/mcp-server@1.0.0","gitHead":"4c6b0cd1606e4020836da7e5a655c48e6c8a2ba6","types":"./dist/index.d.ts","_nodeVersion":"23.11.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-zdL1cprKexW3hCFZpgp66I3Xkjie5/8/q0qunWhrxT0TI/bmJHKPCov9D1b36UgzRX0Y8isyN70MLC3fk1WBoA==","shasum":"4161cbcd54f2aaf00f1256ba53d4406e391f43ef","tarball":"https://registry.npmjs.org/@4pay.online/mcp-server/-/mcp-server-1.0.0.tgz","fileCount":177,"unpackedSize":3894363,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDjUNRm+JfzHjJhwSCwL9A7Wj2nkAP8aYL5z6KOFJ//eAIgfqxn2nin0wxO00hDUqJboS3Yv9BjSzE21E9il/mkE/k="}]},"_npmUser":{"name":"spiridonovmv","email":"support@4pay.online"},"directories":{},"maintainers":[{"name":"spiridonovmv","email":"support@4pay.online"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-server_1.0.0_1788544637269_0.8379459547322379"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-04T17:57:17.103Z","1.0.0":"2026-09-04T17:57:17.461Z","modified":"2026-09-04T17:57:17.684Z"},"maintainers":[{"name":"spiridonovmv","email":"support@4pay.online"}],"description":"MCP server for 4pay.online platform operators","homepage":"https://4pay.online","keywords":["mcp","surelle","payments","model-context-protocol"],"repository":{"type":"git","url":"git+https://github.com/surelle/surelle-mcp.git"},"bugs":{"url":"https://github.com/surelle/surelle-mcp/issues"},"license":"MIT","readme":"# @4pay.online/mcp-server\n\nMCP (Model Context Protocol) server for [Surelle](https://surelle.io) payment processing platform. Enables AI assistants (Claude, GPT) to interact with Surelle via standardized tools.\n\n## Two servers, not one\n\nThe platform ships two MCP servers, and they are different programs on purpose:\n\n| Server | Who runs it | What it exposes |\n|---|---|---|\n| **`@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 |\n| **`@4pay.online/payments-mcp`** ([its own repository](https://git.gaml.store/heth_project/4pay-payments-mcp)) | the merchant — the partner who takes payments | payments, payouts, refunds, payment links, saved cards. Nothing else |\n\nA merchant's agent has no business seeing terminals and routing rules: given them, an agent\nworking through a declined payment will eventually try to \"fix\" the live routing. That is not a\nprompt problem — a tool absent from the list cannot be called, whatever anyone types. So the\npartner package lives in its own repository and contains no operator code at all: not\ndisabled, not filtered, absent.\n\nHand partners `@4pay.online/payments-mcp`. Keep this one for the people who run the platform.\n\n## Quick Start\n\nInstall from npm:\n\n```bash\nnpm install -g @4pay.online/mcp-server\n```\n\nThe package contains its compiled distribution, so installation needs neither the repository nor\ndevelopment dependencies.\n\n### Claude Code\n\nAdd to `.mcp.json` in your project root. Credentials come from the environment, so no secrets\nlive in the file:\n\n```json\n{\n  \"mcpServers\": {\n    \"surelle\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@4pay.online/mcp-server\"],\n      \"env\": {\n        \"SURELLE_API_URL\": \"${SURELLE_API_URL}\",\n        \"SURELLE_LOGIN\": \"${SURELLE_LOGIN}\",\n        \"SURELLE_PASSWORD\": \"${SURELLE_PASSWORD}\",\n        \"SURELLE_ORGANIZATION_ID\": \"${SURELLE_ORGANIZATION_ID}\"\n      }\n    }\n  }\n}\n```\n\nExport the variables before starting the client:\n\n```bash\nexport SURELLE_API_URL=https://sandbox.4pay.online\nexport SURELLE_LOGIN=owner@example.com\nexport SURELLE_PASSWORD=...\n# Organization is optional — see Multi-tenancy\nexport SURELLE_ORGANIZATION_ID=...\n```\n\nThen install the agent skill into the project the agent works from — the server ships with it:\n\n```bash\nnpx -y @4pay.online/mcp-server install-skill /path/to/your/project\n```\n\nThe server logs in on its own — give it a login and password, not a token. It obtains the session\ntoken, renews it before expiry, and logs in again when the server rejects a stale session,\nretrying the request. A session token lasts a week, so a hand-copied `SURELLE_BEARER_TOKEN` stops\nworking silently — use it only for one-off runs or when there is no password (SSO).\n\nTwo-factor authentication is required by default; see below.\n\n### Updating\n\n`npm install -g` fails with `ENOTEMPTY` while the server is running — npm renames the package\ndirectory, and a live process holds it. Stop the MCP server in your client first (or close the\nsession), then update:\n\n```bash\nnpm install -g @4pay.online/mcp-server\n```\n\nA running client keeps the old build in memory regardless: restart the MCP server to pick up a\nnew version.\n\n### Building from source\n\n```bash\ngit clone git@git.gaml.store:heth_project/surelle-mcp.git && cd surelle-mcp\nnpm install\nnpm run build          # dist/ is committed, but rebuild after editing src/\nnpm test\n```\n\nPoint `.mcp.json` at `node /abs/path/to/surelle-mcp/dist/index.js` instead of `npx`.\n\nThe catalog, typed tools and wizard registry are committed, so a fresh clone works without the\nneighbouring repositories. Regenerating them (`npm run generate:all`) does need `surelle` and\n`admin_area` checked out next to this one — see Generated artifacts.\n\n### Claude Desktop\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json` — same shape, but write\nthe values literally, since Desktop does not read your shell environment:\n\n```json\n{\n  \"mcpServers\": {\n    \"surelle\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/surelle-mcp/dist/index.js\"],\n      \"env\": {\n        \"SURELLE_API_URL\": \"https://sandbox.4pay.online\",\n        \"SURELLE_API_KEY\": \"your-api-key\"\n      }\n    }\n  }\n}\n```\n\n## Configuration\n\n| Environment Variable | Required | Default | Description |\n|---------------------|----------|---------|-------------|\n| `SURELLE_API_URL` | No | `http://localhost:4000` | Surelle API base URL |\n| `SURELLE_API_KEY` | Yes* | — | Partner API key (`X-API-Key` header) |\n| `SURELLE_LOGIN` | Yes* | — | Login for automatic sign-in |\n| `SURELLE_PASSWORD` | Yes* | — | Password, paired with `SURELLE_LOGIN` |\n| `SURELLE_ACCOUNT_TYPE` | No | `client` | Role to sign in as: client / partner / admin / person |\n| `SURELLE_TOTP` | No | — | One-time code when 2FA is enabled |\n| `SURELLE_BEARER_TOKEN` | Yes* | — | Ready session token; the server cannot renew it |\n| `SURELLE_ORGANIZATION_ID` | No | — | Default tenant → `x-organization-id` header. Required for admin tokens |\n| `SURELLE_TIMEOUT` | No | `30000` | Request timeout (ms) |\n| `SURELLE_RETRY_COUNT` | No | `2` | Retry count for 5xx errors |\n\n*At least one way to authenticate: `SURELLE_LOGIN` + `SURELLE_PASSWORD` (preferred),\n`SURELLE_BEARER_TOKEN`, or `SURELLE_API_KEY`.\n\n`SURELLE_API_KEY` authenticates a **partner**, not a client: it opens the payment surface\n(transactions, links, products, recurring payments) and nothing of the organization's settings.\nThe two can be set together — the server sends both, so payment calls go as the partner while\nsettings go as the client.\n\n## Tools\n\nThe API exposes 1283 operations. Registering one flat tool per operation would make `tools/list`\nweigh ~580 KB and crowd out the actual task, so coverage is split in two: typed tools for the\nhot path, a catalog for everything else. Total footprint: 22 tools, ~15 KB.\n\n### Catalog — all 1283 operations\n\n| Tool | Description |\n|------|-------------|\n| `surelle_list_domains` | 82 domains with operation counts — start here when you don't know where a setting lives |\n| `surelle_search_operations` | Find operations by keywords, domain, method, read-vs-write |\n| `surelle_describe_operation` | Full parameter and body schema for one operation |\n| `surelle_call_operation` | Execute any operation. State-changing ones require `confirm=true` |\n\n### Operator handbook\n\n| Tool | Description |\n|------|-------------|\n| `surelle_search_help` | Search 224 handbook articles (ru/en) — what a thing is for and when it is used |\n| `surelle_get_help` | One article in full: concepts, worked example, pitfalls |\n\nPass `locale: \"en\"` for English; Russian is the default. Both translations are complete — 224\narticles each. Wizard titles inside an English article stay Russian: the wizard registry is\nextracted in one language only.\n\nThe API catalog answers \"how do I call this\"; the handbook answers \"when and why\". Articles that\nshare a route with a wizard point at it.\n\n### Setup wizards\n\n| Tool | Description |\n|------|-------------|\n| `surelle_list_wizards` | 64 guided setup flows mirrored from admin_area, all with their API operations resolved |\n| `surelle_get_wizard` | Prerequisites, steps, required permissions and the operations behind one wizard |\n\n### Typed tools — hot path\n\n49 generated tools cover the settings domains an operator touches constantly: terminals and\nproviders, routing rules and health, limits and blacklists, FX rates and currencies,\norganizations and members, clients, partners, marketplace modules, pricing plans. Generated from\nthe spec — the operation list lives in `CURATED` in `scripts/build-typed-tools.ts`.\n\n16 hand-written tools cover transactions, wallets, ledger, cards, invoices and audit log.\n\nAll of them accept an optional `organization_id` — see Multi-tenancy below. State-changing ones\ntake `confirm`, which the dispatcher requires before it will send the request.\n\n### Platform AI tools — discovered, not hard-coded\n\nThe platform runs its own tool registry inside Elixir (`Surelle.AI.ToolRegistry`): permissions,\ndenylist, input schema, tenant scoping, audit and tier-3 confirmation all live there. This server\ndoes **not** keep a copy of that list — it asks for it.\n\n| Tool | Description |\n|------|-------------|\n| `surelle_ai_tools` | Fetch `GET /api/v1/ai/tools` and re-register the `ai_*` set. `page_domain` narrows the catalog |\n| `surelle_ai_invoke` | Call a platform tool by its own name — the fallback when the catalog did not load at startup |\n\nEvery catalog entry is also registered as a real MCP tool named `ai_<platform name>`, whose\nhandler is a thin proxy onto `POST /api/v1/ai/tools/{name}/invoke`. The prefix is not decoration:\nseven platform names (`get_transaction`, `get_wallet_balance`, `get_ledger_entries`,\n`get_partner`, `get_terminal`, `get_af_aggregates`, `get_routing_health`) collide with tools this\nserver already ships, and registering over them would break clients that are already configured.\n\nThe catalog is fetched once after connect and refreshed by `surelle_ai_tools`. A failure is never\nfatal — the server starts without `ai_*` tools and says why on stderr. The contour sits behind\nthe `copilot_ai` marketplace module and is served **only to client roles under a session**: a\npartner API key gets nothing, so discovery is skipped when no login or bearer token is configured.\n\n**Tier 3 (actions).** A tool marked `confirmation_required` refuses to run without `confirm=true`\n— nothing reaches the platform until the operator has seen what would change. With `confirm=true`\nthe server passes the two-factor elevation window, takes a one-time token from\n`POST /api/v1/ai/tools/{name}/confirmations` and only then invokes. If the platform still answers\n`confirmation_required` (expired token, arguments changed since it was issued), that comes back as\nan error saying the action was **not** performed — never as an empty success.\n\n## Amounts\n\nAmounts cross the API as integer minor units. How many of them make one major unit is a property\nof the currency *and* the environment, not of its symbol: `USDT` is 6 decimals on mainnet and 18\non sepolia, `ETH` is 18, `BTC` 8, and the platform moved `IDR` from 2 to 0 by migration on live\ndata. So this server keeps no currency table. It asks the platform — `GET /api/v1/currencies`\n(`exponent`) and `GET /api/v1/crypto/currencies?env=` (`decimals`) — caches the answer per\nenvironment, and does the arithmetic in `BigInt` (1 ETH is 10¹⁸ minor units, past\n`Number.MAX_SAFE_INTEGER`).\n\nWhen the scale is unknown the amount is printed as an integer with a `minor units` marker rather\nthan divided by 100. Both reference endpoints require a client or admin session, so a server\nconfigured with only `SURELLE_API_KEY` will see amounts in that unformatted form — honest, and\npreferable to a number that is wrong by 10¹⁶.\n\n## Client role\n\nThe server runs under a **client** token — an organization owner, not a platform admin. That\nshapes what is reachable: of 1283 operations, roughly 430 are open to a client, ~370 open up by\nactivating a marketplace module, ~180 depend on a BaaS capability of the organization, and ~150\nare admin-only.\n\nThe server logs in on its own — give it a login and password, not a token:\n\n```bash\nexport SURELLE_LOGIN=owner@example.com\nexport SURELLE_PASSWORD=...\nexport SURELLE_ACCOUNT_TYPE=client   # default; the endpoint itself defaults to 'partner'\n```\n\nIt obtains the session token, renews it before expiry, and logs in again when the server rejects\na stale session, retrying the request. A session token lasts a week, so a hand-copied\n`SURELLE_BEARER_TOKEN` stops working silently — use it only for one-off runs or when there is no\npassword (SSO).\n\nEvery operation in the catalog carries its access state, so the agent sees the obstacle before\nspending a call: open, needs a module (activatable by the client), needs a BaaS capability, or\nadmin-only. `surelle_search_operations` hides admin-only operations by default; pass\n`include_admin_only: true` to see them.\n\nThe access map lives in `data/access-probe.json` and was produced by probing the sandbox with a\nreal client token. Direct observations are authoritative; states inferred for neighbouring routes\nare labelled as such and never block a call — that inference is right about 88% of the time.\n\n## Two-factor authentication\n\nThe server acts as an organization owner and can change production settings, so it requires a\nsecond factor by default:\n\n- **It refuses to start** if the account has 2FA disabled. Set `SURELLE_REQUIRE_2FA=false` to\n  work without it, accepting the risk.\n- **Sign-in asks for a code.** Surelle answers `428` with `totp_required`, and the server asks the\n  operator through the MCP client — the code comes from a phone, never from a config file.\n- **Writes need an elevation window.** The first state-changing operation asks for a code; after\n  that, changes go through without further prompts for `SURELLE_ELEVATION_MINUTES` (default 15).\n  Reads never ask for anything.\n\nThe TOTP secret is deliberately not accepted as configuration. A secret sitting next to the\npassword in the same `.env` is reachable by the same access to the machine — that is a second\npassword, not a second factor.\n\nThe client must be able to prompt the user (MCP elicitation). Where it cannot — cron, CI — the\nserver says so plainly instead of silently proceeding without the second factor.\n\n## Multi-tenancy\n\nSurelle isolates every tenant and resolves the organization from the `x-organization-id` header.\nA token does not carry one on its own.\n\nYou usually do not need to look the id up. If the account belongs to exactly one organization,\nthe server resolves it on the first call and says which one it picked. With several, it refuses\nto guess and lists them with their ids — pass `organization_id` per call, or set\n`SURELLE_ORGANIZATION_ID`. `surelle_my_organizations` shows the same list on demand.\n\nWorking through a partner API key needs none of this: the key itself carries the organization.\n\nOperations whose path already contains `{organization_id}` take it as a path parameter instead —\n`surelle_describe_operation` says which case applies.\n\n## Generated artifacts\n\nTwo artifacts are snapshots of other repositories and must be regenerated when those change:\n\n| Artifact | Source | Command |\n|----------|--------|---------|\n| `src/generated/catalog.json` | `surelle/openapi.yaml` | `npm run generate` |\n| `src/generated/typed-tools.ts` | the catalog + `CURATED` list | `npm run generate:typed` |\n| `wizards/*.yaml` | `admin_area` routes, pages, hooks, services, i18n | `npm run generate:wizards` |\n| `src/generated/help.json` | `admin_area` help registry + `ru`/`en` locales | `npm run generate:help` |\n\nThe wizard extractor resolves a wizard's page through the routes in `App.tsx` (names alone are\nunreliable), then follows its calls through hooks, service objects, named service functions and\nshared components down to concrete endpoints, matching them against the catalog.\n\n`npm run generate:all` does all three. `npm run check:drift` verifies they still match their sources\nand fails if not — run it in CI, otherwise the server keeps answering, just untruthfully.\n\nPaths default to `../surelle/openapi.yaml` and `../../3ds/admin_area`; override with arguments or\nthe `SURELLE_OPENAPI` / `ADMIN_AREA_PATH` environment variables.\n\n### Forward-router paths\n\n282 of the 1283 operations arrive from the spec with a truncated path: OpenApiSpex writes the path\ninside a `forward`-mounted router without its prefix, so `/standing-orders` really means\n`/api/v1/baas/standing-orders`. The generator restores the prefix from the controller namespace.\nAny new `forward` in the router needs an entry in `FORWARD_PREFIXES` in `scripts/build-catalog.ts`,\notherwise its operations will 404.\n\n## Skill\n\n`skills/surelle-settings/` holds the agent skill that drives this server: the working order,\nmoney and environment rules, the confirmation protocol for state-changing calls, and how to walk\nan operator through a wizard step by step.\n\nInstall it into a project the agent works from:\n\n```bash\nnpm run install:skill -- /path/to/project\n```\n\n## Development\n\n```bash\nnpm install\nnpm run generate:all   # Rebuild catalog + wizard registry from sources\nnpm run build          # TypeScript compilation (+ copies the catalog into dist)\nnpm test               # Run tests\nnpm run check:drift    # Verify generated artifacts match their sources\nnpm run dev            # Watch mode (tsx)\n```\n\n## Security\n\n- PCI DSS compliant: card data is tokenized, never exposed as PAN/CVV\n- Amounts in minor currency units (kopecks/cents)\n- API keys transmitted via secure headers only\n- All requests over HTTPS in production\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-bee5ee82d54a759dd1aeb90ca33c41e9"}