{
  "markdown": "# depix-mcp\n\n[![smithery badge](https://smithery.ai/badge/depixapp/depix-mcp)](https://smithery.ai/servers/depixapp/depix-mcp)\n\nThe MCP (Model Context Protocol) server for [DePix App](https://depixapp.com) —\nthe agent-facing interface of the non-custodial Pix↔DePix payment gateway **and**\nof a non-custodial Liquid wallet.\n\n**One MCP, two levels of access.** Same package, same registry entry; what works\ndepends only on whether the running instance has a seed:\n\n| | Level 1 — hosted | Level 2 — local |\n|---|---|---|\n| How | `https://mcp.depixapp.com/mcp` (Streamable HTTP) | `npx -y @depixapp/mcp` (stdio) |\n| Runs on | DePix App's servers | **your** machine |\n| Tools | **26** — receive Pix, status reads, onboarding/vault/webhook reads, support | **62** — the 26 **plus** 29 `wallet_*` and 7 account tools |\n| Seed | none, ever | yours, never leaves the machine |\n| Install | zero (claude.ai, ChatGPT) | Node.js ≥ 22.4 |\n\nCustody is decided by **who holds the seed, not by the transport**. Every spend\nmaterializes a signer **in-process**, and there is no remote-signing path — so\nDePix App cannot host working wallet tools without becoming custodial, and does\nnot. That is physics, not a product tier.\n\n## What it is (and isn't)\n\n**Both levels:**\n\n- **A pure client of the public DePix API** (`https://api.depixapp.com/api/*`) for\n  the 26 gateway tools. It holds **zero critical credentials** — no provider token,\n  no database, no webhook HMAC. Your `sk_` key is passed **verbatim** to the API\n  on each call and lives only in memory for that request.\n- **Same door as everyone.** No privileged path: the same auth, scopes and rate\n  limits as any external agent.\n\n**Level 1 (`mcp.depixapp.com`) only:** it never signs, never holds funds, never\nstores your key. It has no wallet code at all — the wallet engine is not merely\ndisabled there, it is **structurally absent** from that deployment's import graph,\nand a CI guard (`npm run guard:hosted`) fails the build if that ever changes.\n\n**Level 2 (`npx`) only:** the 29 `wallet_*` tools hold, send, convert and pay —\nsigning locally, inside your own process, under guardrails (per-transaction and\nrolling-24h BRL caps, optional allowlist) that no tool call can raise. There is\nno tool that exports the seed, edits guardrails, or pays a merchant checkout QR.\n\n## Related — `@depixapp/sdk`\n\nThe wallet engine started life as the standalone\n**[`@depixapp/sdk`](https://www.npmjs.com/package/@depixapp/sdk)**. It lives here\nnow (`src/wallet-engine/`), and this package is where it is developed and\nreleased. The 1.2.x line of `@depixapp/sdk` stays on npm and keeps working; it\nis frozen, not deprecated. If what you want is **an agent with a wallet**, you\nwant this package: it exposes the engine over MCP, so nothing has to be written.\n\n## Quickstart 1 — Connect Claude Code (remote, HTTP)\n\nPass your DePix API key as a Bearer header. Always start with a sandbox key.\n\n```bash\nclaude mcp add --transport http depix https://mcp.depixapp.com/mcp \\\n  --header \"Authorization: Bearer sk_test_YOUR_KEY\"\n```\n\nThen test the connection by asking Claude to run `get_account`. It should return\nyour merchant with `is_live: false` (sandbox).\n\n**Cursor** — add to `~/.cursor/mcp.json` (or a project `.cursor/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"depix\": {\n      \"url\": \"https://mcp.depixapp.com/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer sk_test_YOUR_KEY\" }\n    }\n  }\n}\n```\n\nOr use the one-click deeplink. The key placeholder lives INSIDE the base64\n`config=` value, so re-encode it with your real key first:\n\n```bash\nnode -e 'const cfg={url:\"https://mcp.depixapp.com/mcp\",headers:{Authorization:\"Bearer sk_test_YOUR_KEY\"}};console.log(Buffer.from(JSON.stringify(cfg)).toString(\"base64\"))'\n```\n\n```\ncursor://anysphere.cursor-deeplink/mcp/install?name=depix&config=<base64 from the command above>\n```\n\n> The claude.ai web UI custom-connector only supports OAuth (no custom header).\n> This server is an OAuth 2.1 Resource Server (WorkOS AuthKit): the web connector\n> signs you in, and the session forwards your verified login to the API as the\n> bearer. To operate you must first **link that login to your DePix account**\n> (dashboard → connector settings); until then the tools return a typed\n> \"not linked yet\" message. OAuth sessions are read + merchant only and can never\n> move money (`wallet_write`) — use an `sk_` key for withdrawals. The whole OAuth\n> surface is feature-flagged (`AUTHKIT_DOMAIN`): with it unset, only the `sk_`\n> header/stdio paths above are active. Terminal clients keep using `sk_` keys.\n\n## Quickstart 2 — Local stdio, 62 tools (Claude Desktop / Claude Code / Cursor)\n\nRequires **Node.js ≥ 22.4**. The only official npm package is `@depixapp/mcp` —\nthe `@depixapp` scope is organization-owned; do not install any similarly-named\nunscoped package. Secrets come from the environment, never from a flag.\n\n### 2a. Gateway only (no wallet)\n\nExactly the 26 tools of level 1, running locally:\n\n```json\n{\n  \"mcpServers\": {\n    \"depix\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@depixapp/mcp\"],\n      \"env\": { \"DEPIX_API_KEY\": \"sk_test_YOUR_KEY\" }\n    }\n  }\n}\n```\n\nAll 62 tools are still *listed* — the 29 `wallet_*` ones answer with a typed\n`wallet_not_configured` error telling the agent to ask you to run `init`. That is\ndeliberate: MCP hosts snapshot the tool list when they connect, so a catalog that\ngrew later would mean \"restart your client\".\n\n### 2b. First run — create the wallet\n\n**`init` is a human ceremony at a terminal, never an MCP tool.** It prints your\n12-word seed backup, so it refuses to run when stdin/stdout are not a real TTY,\nand no agent can invoke it:\n\n```bash\nnpx -y @depixapp/mcp init            # create a new wallet\nnpx -y @depixapp/mcp init --restore  # import an existing 12-word mnemonic\n```\n\nIt asks for (or generates) a passphrase — never echoed — walks you through the\nbackup ritual, asks for your spending limits, and then wires the AI hosts it\nfinds on the machine (Claude Code, Claude Desktop, Cursor) to this wallet by\nitself. The unlock key goes into the OS keychain, so the passphrase is never\nwritten into a host config. For a host it does not detect it prints the block to\npaste instead — and that block carries no secret:\n\n```json\n{\n  \"mcpServers\": {\n    \"depix\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@depixapp/mcp\"],\n      \"env\": {\n        \"DEPIX_WALLET_DIR\": \"/Users/you/.depix-wallet\",\n        \"DEPIX_GUARDRAIL_PER_TX_BRL_CENTS\": \"10000\",\n        \"DEPIX_GUARDRAIL_DAILY_BRL_CENTS\": \"50000\"\n      }\n    }\n  }\n}\n```\n\nClear your terminal scrollback afterwards. Restart your MCP client and ask it to\nrun `wallet_status`.\n\n### 2c. Reading the 12 words again\n\n```bash\nnpx -y @depixapp/mcp backup          # show this wallet's 12 words again\n```\n\nSame rules as `init`: a real terminal or nothing. It asks for your passphrase\n**every time**, even on a machine that unlocks the wallet by itself — the\nkeychain unlock key exists so the server can start, not so anyone at the keyboard\ncan read the seed. When you confirm you have copied the words, it wipes the\nscreen and the scrollback. Quit your MCP client first: the wallet dir takes an\nexclusive lock, and a running server holds it.\n\nRun the server directly to sanity-check:\n\n```bash\nDEPIX_API_KEY=sk_test_YOUR_KEY npx -y @depixapp/mcp\n```\n\n> **Self-hosting over HTTP is NOT trivially safe.** The wallet tools have no auth\n> of their own and the seed is loaded process-wide. Over local **stdio** that is\n> fine. Exposed over HTTP, anyone who reaches the port can drain the wallet — bind\n> to localhost and add your own bearer/mTLS + network isolation, or don't.\n\n## CLI subcommands\n\nOne bin, `depix-mcp`, with five subcommands — all of them acts for the human at\nthe keyboard. `npx -y @depixapp/mcp --help` prints the same list.\n\n**None of the five is an MCP tool, and that is deliberate.** Two of them (`init`,\n`backup`) display a 12-word seed, which must never transit model context or a\nconversation log. The other three choose *which account* the server acts as: as\ntools, an agent that read a poisoned web page could promote itself from its own\nsandbox account to yours.\n\n| Command | What it does | When you run it | The safety property |\n|---|---|---|---|\n| `init` | Creates the local wallet (`--restore` imports an existing 12-word mnemonic) and wires your AI host to it | Once, before any `wallet_*` tool can work | Refuses unless stdin **and** stdout are a real terminal; the passphrase is never echoed and never written into a host config |\n| `backup` | Shows this wallet's 12 words again | When you need to copy the seed onto paper again | A real terminal or nothing; your passphrase is typed **every time**, even on a machine that unlocks the wallet by itself; the screen is wiped afterwards |\n| `login` | Signs you in to your own DePix account in the browser (Google or GitHub) and seals the session on this machine | When you want the server to act as **you**, not as an account the agent registered for itself | The browser does the sign-in and the reply lands on this same computer; no token is ever printed, logged, or put in an error message |\n| `logout` | Removes that login from this machine | When you are done with it, or on a machine you no longer control | Undoes `login` completely — including an `account use owner` selection that would now point at nothing |\n| `account status` / `account use agent\\|owner` | Prints which account the server acts as and why / picks one | Whenever you are unsure who is spending, and after `login` on a machine that already has an agent account | Reading and choosing happen at your terminal, so no agent can switch identity; `status` names the winner instead of leaving it implicit |\n\n### Signing in as yourself — `login` / `logout`\n\n```bash\nnpx -y @depixapp/mcp login                    # choose Google or GitHub in the browser\nnpx -y @depixapp/mcp login --provider github  # skip the chooser\nnpx -y @depixapp/mcp logout\n```\n\n`login` opens your browser on the DePix App sign-in and waits for the answer at\n`http://127.0.0.1:47617/callback` — **this** computer, never a remote one. The\nlistener binds before the browser opens, so a second `login` running at the same\ntime fails right there instead of sending your sign-in to whatever else holds\nthat port. What comes back is exchanged for a session and sealed on disk with\nyour wallet passphrase; the terminal prints who you signed in as, never the\ncredential. On a headless or remote box there is no browser to open — use\n`DEPIX_API_KEY` there, or let the agent register its own account.\n\n> On **2.8.0** and **2.8.1**, `login` needs `DEPIX_WORKOS_CLIENT_ID` set to the\n> DePix App sign-in application — the id baked into those two versions points at\n> an older client. From **2.8.2** the right one ships baked in and the command\n> needs no configuration.\n\nIf an agent account is already registered on this machine, logging in changes\n**nothing** by default: the agent's account still wins, and `login` says so\nloudly. `account use owner` is what switches. `logout` removes the stored\nsession and, when you had selected `owner`, drops that selection too — it would\notherwise point at a login that no longer exists.\n\n### Which account acts — `account status` / `account use`\n\nTwo identities can live on one machine: the account the agent registered for\nitself (`register_account`) and your own login. Exactly one of them\nauthenticates each call, and the order is fixed:\n\n```\nDEPIX_API_KEY  >  an explicit `account use`  >  the agent's own account  >  your login\n```\n\nThe agent's own account carries two keys — sandbox (`sk_test_`) and the\nproduction starter (`sk_live_`) — and starts on the sandbox one. The agent\nswitches with **`activate_key`** (`{ \"mode\": \"live\" }`): the choice is saved in\nthe encrypted vault, survives restarts, and the wallet picks it up on its next\ncall. Under `live`, deposits are real Pix charges.\n\n```bash\nnpx -y @depixapp/mcp account status       # who is acting, and why\nnpx -y @depixapp/mcp account use owner    # act as your own DePix login\nnpx -y @depixapp/mcp account use agent    # act as the account the agent registered here\n```\n\n> **`DEPIX_API_KEY` in the server's environment beats everything below it.** With\n> that variable set, `account use` decides nothing — `account status` prints that\n> warning in place. Unset it (and restart the server) to let your selection win.\n\n`account status` prints labels only — a provider, an email, an expiry — never a\ntoken and never your passphrase.\n\n## Quickstart 3 — Sandbox testing (the full loop)\n\nAlways test with an `sk_test_` key before `sk_live_`. Sandbox QRs are\nnon-payable placeholders (`SANDBOX-…-DO-NOT-PAY`).\n\n1. **`create_checkout`** — `amount` is always required; on the default **Pix**\n   rail `payer_tax_number` is too (the CPF/CNPJ is required even in sandbox).\n   Use a test CPF like `52998224725`:\n\n   ```json\n   { \"amount\": 1500, \"payer_tax_number\": \"52998224725\" }\n   ```\n\n   Returns a `chk_…` id, a `payment_url`, a sandbox `pix.qr_code`, and\n   `is_live: false`.\n\n2. **`simulate_checkout_payment`** — `{ \"checkout_id\": \"chk_…\" }` marks the\n   sandbox checkout paid (sandbox-only; live checkouts return `sandbox_only`).\n\n3. **`wait_for_checkout`** — `{ \"checkout_id\": \"chk_…\" }`. The server polls\n   internally and streams progress; you make **one** call and it returns\n   `{ \"status\": \"completed\", \"terminal\": true }` — no client-side polling loop.\n\nYou can also read a synthetic deposit: **`get_deposit_status`** with a\n`sandbox_…` id returns `depix_sent`.\n\n### Charging on the DePix rail instead of Pix\n\n`create_checkout` takes `payment_method`. The default `\"pix\"` is the flow above.\nWith `\"depix\"` the payer sends DePix **wallet-to-wallet on Liquid** to the\nmerchant's dedicated address — there is no Pix QR and no payer document:\n\n```json\n{ \"amount\": 9990, \"payment_method\": \"depix\", \"expected_discount_pct\": 10 }\n```\n\nThe response carries `depix` instead of `pix`: `address`, the **exact**\n`amount_cents` to send (face amount minus the merchant's discount, minus a\nsub-cent-window adjustment that makes the value unique — that uniqueness is how\nthe payment is matched), the decimal `amount` a wallet signs, `asset_id` and a\nready-to-scan `uri`. Send any other amount or any other asset and the payment\ncannot be credited automatically, and an on-chain payment is irreversible.\n\nSettlement is observed on-chain: `approved` at the first confirmation (~1 min),\n`completed` at the second. `expires_in` accepts 300–3600 s here (default 1800)\ninstead of the Pix rail's 300–1200. The rail must be enabled by the merchant —\notherwise the API answers `depix_not_enabled`. On the local level, a registered\nagent account turns it on with **`configure_depix_rail`** (`{ \"enabled\": true }`):\nthe tool derives a dedicated address from your own wallet and registers it, so\nyou keep custody and the backend only gains a per-address viewing key. Sandbox\nDePix checkouts are deliberately unpayable (placeholder address, `uri: null`);\ndrive them with `simulate_checkout_payment`.\n\n## Tools\n\n**26 gateway tools** — available at both levels. Amounts are BRL cents.\n\n| Tool | API | Scope |\n|---|---|---|\n| `create_checkout` | POST /api/checkouts | `merchant_write` |\n| `get_checkout` | GET /api/checkouts/:id | `merchant_read` |\n| `list_checkouts` | GET /api/checkouts | `merchant_read` |\n| `simulate_checkout_payment` | POST /api/checkouts/:id/simulate-payment | `merchant_write` (sandbox-only) |\n| `wait_for_checkout` | GET /api/checkouts/:id (server-side loop) | `merchant_read` |\n| `create_product` | POST /api/products | `merchant_write` |\n| `list_products` | GET /api/products | `merchant_read` |\n| `get_product` | GET /api/products/:id | `merchant_read` |\n| `update_product` | PATCH /api/products/:id | `merchant_write` |\n| `activate_product` | POST /api/products/:id/activate | `merchant_write` |\n| `deactivate_product` | POST /api/products/:id/deactivate | `merchant_write` |\n| `set_featured_products` | POST /api/products/featured | `merchant_write` |\n| `list_product_checkouts` | GET /api/products/:id/checkouts | `merchant_read` |\n| `get_account` | GET /api/me | `merchant_read` |\n| `get_onboarding_status` | GET /api/verification + GET /api/me probe (self-heals via POST when every step is done) | `merchant_read` |\n| `update_merchant_profile` | PATCH /api/merchants/me | `merchant_write` |\n| `get_vault_status` | GET /api/vault/status | `wallet_read` (read-only) |\n| `list_webhook_logs` | GET /api/webhook-logs, /api/webhook-logs/:id | `merchant_read` |\n| `get_deposit_status` | GET /api/deposits/:id | `wallet_read` (read-only) |\n| `get_withdrawal_status` | GET /api/withdrawals/:id | `wallet_read` (read-only) |\n| `open_support_ticket` | POST /api/tickets | any key (scope-less) |\n| `get_support_ticket` | GET /api/tickets/:id | any key (scope-less) |\n| `list_support_tickets` | GET /api/tickets | any key (scope-less) |\n| `reply_support_ticket` | POST /api/tickets/:id/messages | any key (scope-less) |\n| `attach_support_ticket_file` | POST /api/tickets/:id/attachments | any key (scope-less) |\n| `close_support_ticket` | POST /api/tickets/:id/close | any key (scope-less) |\n\n**Charges (cobranças).** `create_product` with `kind: \"charge\"` creates a payment link with a **due date** and optional late fine/interest — rent, tuition, an instalment. It is served at `pay.depixapp.com/c/{id}`, never appears on the merchant's public store, and the amount is recomputed on each visit (base + fine + pro-rata interest for the current cycle). With `recurrence` the same link keeps working month after month, settling the oldest unpaid cycle first. `list_products` does **not** return charges unless you pass `kind: \"charge\"` (or `\"all\"`); charge rows then carry `charge_state` — current cycle, days late, today's total.\n\nDo not confuse it with `create_checkout`, which mints a **one-off** payment that is paid once and is short-lived. A charge is the standing one.\n\nThe last six are the support channel: open a ticket, poll for the human reply,\nreply back, attach a screenshot or diagnostic/log file (base64, ~3 MB), or close\nit (up to 5 open per account). Replies are not pushed —\npoll `get_support_ticket`. Amounts are BRL cents. A tool call whose key lacks the required scope returns an\n`insufficient_scope` tool error naming the missing scope — that is the only way\nto discover a missing scope (the API never lists a key's scopes).\n\n**29 `wallet_*` tools** — the local (`npx`) level only. They sign in-process with\nyour seed; without one they return `wallet_not_configured`.\n\n| Group | Tools |\n|---|---|\n| Status & reads | `wallet_status`, `wallet_get_address`, `wallet_get_balances`, `wallet_list_transactions`, `wallet_list_utxos`, `wallet_get_guardrails`, `wallet_diagnostics` |\n| Sync | `wallet_sync` (explicit refresh; `rescan` for a deep cold re-scan) |\n| Move money | `wallet_send`, `wallet_create_deposit`, `wallet_wait_deposit`, `wallet_create_withdrawal`, `wallet_wait_withdrawal` |\n| Convert | `wallet_quote`, `wallet_convert`, `wallet_swap_quote`, `wallet_swap_execute`, `wallet_to_stablecoin`, `wallet_shift_usdt` |\n| Lightning | `wallet_pay_lightning_invoice`, `wallet_receive_lightning` |\n| Gift cards | `wallet_list_giftcards`, `wallet_list_giftcard_products`, `wallet_giftcard_price`, `wallet_buy_giftcard`, `wallet_list_giftcard_orders`, `wallet_get_giftcard_order_status` |\n| Recovery | `wallet_recover`, `wallet_pending` |\n\n`wallet_convert` is the primary conversion surface (`wallet_quote` enumerates the\nroutes); the provider-level tools are the escape hatch. `wallet_shift_usdt` is the\none **custodial** route (SideShift) and says so. Amounts carry their unit in the\nfield name: `amount_cents` is BRL cents, `amount_sats` is the asset's base units.\n\nThere is deliberately **no** tool to export the seed, change guardrails, edit the\npayout addresses, or pay a merchant checkout QR — not even from a fully injected\nmodel.\n\n## Configuration (public, no secrets)\n\n| Env | Meaning | Default |\n|---|---|---|\n| `DEPIX_API_BASE` | API base URL (allowlisted origins only) | `https://api.depixapp.com` |\n| `MCP_MAX_WAIT_SECONDS` | Max `wait_for_checkout` budget; prod sets ~780 (Vercel Pro) | `290` (Hobby-safe) |\n| `MCP_SERVER_VERSION` | Version reported in the handshake | package version |\n| `MCP_ALLOWED_HOSTS` | Comma-separated Host allowlist (DNS-rebinding protection). Matched **exactly** — no wildcards. Vercel preview deploys add their own hostnames automatically, so this is normally unset | `mcp.depixapp.com` |\n| `DEPIX_API_KEY` | **stdio mode only** — your `sk_` key | — |\n\nLocal (`npx`) level only — the wallet half:\n\n| Env | Meaning | Default |\n|---|---|---|\n| `DEPIX_WALLET_PASSPHRASE` | Unlocks the encrypted local wallet, and seals the stored API keys and the `login` session. Optional: `init` puts the same passphrase in the OS keychain (or a `0600` file), and everything reads it there when this is unset | — |\n| `DEPIX_AGENT_PASSPHRASE` | Optional. When set it seals and opens the stored API keys and the `login` session instead of `DEPIX_WALLET_PASSPHRASE`; the wallet itself keeps using `DEPIX_WALLET_PASSPHRASE` | — |\n| `DEPIX_WALLET_DIR` | Where the encrypted wallet lives | `~/.depix-wallet` |\n| `DEPIX_GUARDRAIL_*` | Per-transaction / rolling-24h BRL caps and allowlist. Immutable at runtime: set here + restart | R$100/tx, R$500/day |\n| `DEPIX_MCP_MAX_WAIT_SECONDS` | Ceiling for the wallet wait tools | `900` |\n\nThere is deliberately **no** env for an API key, provider token, HMAC or DB\ncredential in the remote server. In HTTP mode the key arrives per-request in the\n`Authorization` header. The wallet passphrase and seed exist **only** on the\noperator's machine — the hosted deployment reads neither and has no code that\ncould.\n\n## Endpoints\n\n- `POST /mcp` — the MCP Streamable HTTP endpoint (`DELETE` ends a session;\n  `GET` returns 405 — this stateless server offers no standalone SSE stream).\n- `GET /.well-known/mcp.json` — minimal discovery document.\n- `GET /api/health` (also `/`) — service status.\n\n## Development\n\n```bash\nnpm install\nnpm test           # vitest\nnpm run typecheck  # tsc --noEmit\nnpm run lint       # eslint\nnpm run build      # compile src (incl. the wallet engine) → dist\nnpm run smoke      # run the compiled dist: wasm init, address goldens, seed roundtrip\nnpm run guard:hosted   # the hosted deployment has no path to the wallet engine\nnpm run licenses:check # THIRD_PARTY_LICENSES matches the prod dep tree\n```\n\nSet `DEPIX_TEST_KEY=sk_test_…` to run the real-sandbox e2e test\n(`test/e2e/sandbox.test.ts`), otherwise it is skipped. Set `DEPIX_SDK_OFFLINE=1`\n(CI does) to skip the one engine test that reads mainnet Esplora for real.\n\n### The wallet engine (`src/wallet-engine/`)\n\nThe 29 wallet tools come from the DePix App wallet engine. It used to be vendored\nhere from a pinned commit of a second repository; it is now simply part of this\npackage's source, developed and released with it. Its tests live in\n`test/wallet-engine/`, mirroring the layout.\n\nTwo settings the engine brings with it:\n\n- `tsconfig.wallet-engine.json` typechecks `src/wallet-engine/` +\n  `test/wallet-engine/` under the stricter options the engine was written with\n  (`noUncheckedIndexedAccess` and friends). `npm run typecheck` runs the\n  repo-wide pass and then this one; tsc has no per-directory options.\n- `floor-smoke` in CI runs the compiled artifact on Node **22.4** exactly — the\n  `engines` floor. The test matrix's \"22\" is whatever `latest-22` resolves to,\n  which never proves the floor.\n\n### Why the hosted deployment cannot sign\n\n`api/mcp.ts` → `src/http.ts` → `src/server.ts` has **zero** import path to\n`src/wallet-engine/**`. Neither this repo nor Vercel runs a tree-shaking bundler,\nso that import graph is the whole guarantee. `scripts/check-hosted-isolation.mjs`\nenforces it twice — a static walk of the TypeScript sources and a `@vercel/nft`\ntrace of the compiled entries — and its `--self-test` proves both checks reject a\npoisoned entry. Only `src/stdio.ts` → `src/unified.ts` may reach the engine.\n\n**CI** (`.github/workflows/ci.yml`) runs typecheck + lint + test + build + smoke +\nboth guards on every push to `main` and every PR, on Node 22 and 24, plus the\nNode 22.4 floor smoke — that is the correctness gate.\n\n## Releasing\n\nPublishing is automated via GitHub Actions using **npm Trusted Publishing\n(OIDC)** — no npm token, no 2FA prompt, and every release carries build\nprovenance. `.github/workflows/publish-mcp.yml` (on a `v*` tag) publishes the\n**npm package** and then the **MCP Registry** entry (`registry/server.json`).\n\nTo cut a release:\n\n1. Bump the version in **`package.json`**, **`registry/server.json`** (both the\n   top-level `version` and `packages[].version`) and the `resolveServerVersion`\n   fallback in **`src/config.ts`** — they must match, and CI fails the release if\n   the tag, `package.json` and the registry npm entry disagree (a unit test pins\n   the config fallback). The MCP Registry is **immutable per version**, so\n   anything that publishes from the tagged tree has to be right before the tag.\n2. Commit to `main`.\n3. Tag and push:\n   ```bash\n   git tag v2.0.0 && git push origin v2.0.0\n   ```\n\nThe workflow verifies the versions, re-runs typecheck + lint + tests + both\nguards (`ci.yml` is not triggered by tags), publishes to npm with provenance,\nthen publishes the registry entry (idempotent — re-running a tag is a safe\nno-op).\nRe-tagging an already-published version skips both publishes.\n\nOne-time setup (already done): the package is registered as an npm **Trusted\nPublisher** for this repo with workflow filename `publish-mcp.yml` (npmjs.com →\npackage → Settings → Trusted Publisher). No secrets are stored in the repo.\n\n## Release smoke test\n\nAfter a preview/production deploy:\n\n1. `claude mcp add --transport http depix <url>/mcp --header \"Authorization: Bearer sk_test_…\"`\n2. Ask Claude to run `get_account` → returns the merchant, `is_live: false`.\n3. `create_checkout` (sandbox) → `simulate_checkout_payment` → `wait_for_checkout`\n   → `completed`.\n\n> Pushing to `main` deploys to production (`mcp.depixapp.com`). Validate on a\n> Vercel preview deploy before merging. **Previews are reachable out of the box:**\n> a non-production deployment adds its own `VERCEL_URL` and `VERCEL_BRANCH_URL`\n> to the DNS-rebinding allowlist (`resolveAllowedHosts`), and production widens by\n> nothing. If you ever need to allow another host, set `MCP_ALLOWED_HOSTS` to the\n> **exact** hostname — the allowlist is an exact match, so `*.vercel.app` matches\n> nothing and would leave the preview unreachable.\n",
  "bytes": 26604,
  "sha": "7ed596515f743badf30f94ee9c8cf61d2890ceeba22712df9eca03746344a16f",
  "repo_slug": "depixapp/depix-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_depixapp_depix_mcp_1ccb7327/readme"
}