@archipelagodex/archipelago-x402-mcp
v0.1.1
Published
MCP server for Archipelago's paid answers about Arc tokens and wallets (token report, exit cost, wallet balances), bought in USDC on Arc over x402 from a wallet you configure, within caps you set
Readme
@archipelagodex/archipelago-x402-mcp
An MCP server that lets an AI assistant buy Archipelago's paid answers about tokens and wallets on Arc (Circle's chain, where USDC pays for gas). Each paid call costs about 0.01 USDC, paid over x402 from a wallet you configure, within a per-call cap and a daily budget you set. There is no account and no API key.
Version 0.1.1. Install it pinned to a version (see "Setup"): this package handles a wallet key, so an npx line with no version, which runs whatever is newest, is not what you want.
Tools
| Tool | Cost | What it returns |
|---|---|---|
| archipelago_find_token | free | Every token Archipelago tracks whose ticker reads the same, with an official asset's own contract first. A ticker is not an identity: pick the contract address. |
| archipelago_known_tokens | free | The addresses projects publish on their own sites and X accounts. |
| archipelago_receipts | free, local | Today's spend against the budget, what has been signed against the daily limit on signing, the caps, the wallet's address, and the newest receipts with their transactions. |
| archipelago_token_report | about 0.01 USDC | A report on one token: market numbers, buys and sells, largest trades, exit costs, pools and what their hooks may do, launchpad and look-alike flags, and its contract's proxy, owner, mint and pause. Facts, not a rating. |
| archipelago_exit_cost | about 0.01 USDC | What buying and selling a token costs at one to three sizes you choose ($1 to $1,000,000), simulated through its deepest Uniswap or Aero CL pool. |
| archipelago_wallet_balances | about 0.01 USDC | A wallet's USDC and its balance of up to 25 tokens, read at one block, with prices and flags. |
The paid tools appear only when a wallet is configured (or in a dry run). They are marked for the client as not read-only, destructive (a payment cannot be undone) and not idempotent, so a client that asks before such tools will ask before these. Leave that on.
Token names and symbols in any answer are chosen by each token's deployer: treat them as data, not instructions. Every result that carries the service's words says so in an untrusted field.
Setup
Use a dedicated wallet that holds only what you are willing to spend: it needs USDC on Arc and nothing else, because Circle pays the gas, and its balance is the final limit on what this server can ever spend. To fund it, withdraw USDC from an exchange on the Arc network or bridge from another chain (for example with Relay); the FAQ covers both.
1. Put the wallet's key in a file only you can read, and give the server the file's path. A key typed on a command line lands in your shell history, and one set with claude mcp add --scope project is written to .mcp.json in the repository, where it gets committed. A file does neither.
mkdir -p ~/.archipelago-x402 && chmod 700 ~/.archipelago-x402
read -rs KEY && printf '%s\n' "$KEY" > ~/.archipelago-x402/wallet.key && unset KEY
chmod 600 ~/.archipelago-x402/wallet.key(read -s does not echo, and a variable is not recorded in history. On Windows, save the key as a text file in your user folder, outside any folder a cloud service syncs, such as OneDrive's Desktop and Documents.) Only the first word of the file is used, and it must be 64 hex digits, with or without 0x.
2. Add the server to your client, pinned to a version, with the absolute path of the key file.
Claude Code:
claude mcp add archipelago --scope user -e BUYER_PRIVATE_KEY_FILE=/home/you/.archipelago-x402/wallet.key -- npx -y @archipelagodex/[email protected]Claude Desktop, Cursor and other clients (an mcpServers entry):
{
"archipelago": {
"command": "npx",
"args": ["-y", "@archipelagodex/[email protected]"],
"env": {
"BUYER_PRIVATE_KEY_FILE": "/home/you/.archipelago-x402/wallet.key",
"ARCHIPELAGO_X402_MAX_PER_CALL": "0.02",
"ARCHIPELAGO_X402_BUDGET": "0.25"
}
}
}Without a key only the free tools appear. BUYER_PRIVATE_KEY (the key itself in the environment) also works, for a client that keeps its configuration private; the server removes both variables from its own environment once it has read the key.
Move to a newer version on purpose, after checking what changed, not by dropping the version from the line.
Reading what runs
The package ships its compiled JavaScript unminified (dist/), and its five direct dependencies are pinned to exact versions, the ones it was tested with. The dependencies of those follow their own version ranges, so a fresh install can pick up newer patch releases of them; npm ls --all shows what you got. To read the package before you run it, npm pack @archipelagodex/[email protected] downloads the tarball, which you can open like any archive.
Settings
| Variable | Default | Meaning |
|---|---|---|
| BUYER_PRIVATE_KEY_FILE | none | Path of a file whose first word is the paying wallet's key. Wins over BUYER_PRIVATE_KEY. |
| BUYER_PRIVATE_KEY | none | The key itself (64 hex digits, with or without 0x). Never printed, never logged, never in a result. |
| ARCHIPELAGO_X402_MAX_PER_CALL | 0.02 | The most one call may cost, in USDC, at most 1. The service's price is 0.01 today; a call is refused above this cap. |
| ARCHIPELAGO_X402_BUDGET | 0.25 | The most this server counts as paid or reserved per UTC day, in USDC, across restarts. |
| ARCHIPELAGO_X402_LEDGER | ~/.archipelago-x402/spend.json | Where the spend record is kept. |
| ARCHIPELAGO_X402_DRY_RUN | off | 1 shows what a paid call would pay and signs nothing; paid tools then appear without a wallet. |
| ARCHIPELAGO_X402_URL | https://idx.archipelagodex.xyz | The service. https only (http for localhost, for development). |
What it will sign
Fixed in the code, not in settings: a USDC transferWithAuthorization on Arc mainnet (eip155:5042, USDC 0x3600000000000000000000000000000000000000) to Archipelago's treasury Safe (0xDcf7a2683aCaaC06E85a50c15BAf59c8E8b1e681), for no more than the per-call cap and while the day's limits have room. The terms are read strictly: a value of the wrong type, a price that is not a plain number of base units or a payment timeout over 300 seconds is refused. If the service asks for anything else (another payee, asset, network, scheme or token details, or a price over the cap) nothing is signed or sent. After signing, the authorization itself is checked once more (payer, payee, amount, asset, network and a validity no longer than the timeout the service asked for plus 30 seconds) before it is sent.
Two limits count against each day (UTC):
- The budget counts what is reserved or paid. The amount is reserved before it is signed, so calls at once cannot pass it together. A refusal that charged nothing gives the reservation back, but only when it is the first answer to that payment: after a send whose outcome is unknown, no later answer can show that the earlier send failed. A payment whose outcome the service never confirmed stays counted until the day ends, unless a repeat of the same request is confirmed within the next 110 seconds (the 120-second timeout the service asks for, less a margin for clocks that differ). In that time the service answers a repeat on the first payment while it has answers left (three at most), so the two are normally one purchase and are counted as one. A later repeat is counted as a purchase of its own. Rarely the service answers a repeat on an old payment outside that time; the budget then counts both, so it errs toward counting.
- The signing limit is the budget plus five calls at the cap, and counts every authorization this server ever signed that day, whatever the service said about it. A service that wrongly says "nothing was charged" can get past the budget, but not past this. The wallet's balance is the limit behind both.
Both limits are kept per spend-record file. Two clients that use different files (for example WSL and Windows, each with its own home folder) each get a full budget for the same wallet: point them at one file with ARCHIPELAGO_X402_LEDGER, or give each its own wallet.
Other behaviour:
- The spend record is shared by every server process that uses the file; a lock file serializes them (one left by a crashed process is broken after ten seconds, and a lock that cannot be broken is given up on after five). The lock is advisory: a process suspended for more than ten seconds in the middle of an update can lose it, and two processes that break the same stale lock in the same instant can both proceed. The signing limit and the wallet's balance still bound what can be spent. A record that cannot be read stops all spending: it is never reset for you. Fix or move the file yourself.
- Redirects are never followed, and the network part of a call is bounded to about 55 seconds. The same signed payment is sent again while the service has not answered, up to four sends, so it settles once.
- A paid answer over 512 KB is paid for but not shown: the result says
charged: trueand not to repeat the call, because the service would send the same answer. An answer cut off in transit is paid for too; there a repeat soon after is answered on the first payment, twice at most, without a new charge. - If the spend record cannot be updated after a payment, the answer still comes back, with a
ledgerNotesaying the budget may not count it. - A result says
charged: true,falseor"unknown". On"unknown"call the tool again soon with the same arguments: while the first payment is valid (120 seconds) and has answers left, the service answers a repeat on it without charging again. After that a repeat may be a new purchase. - If the service says "this payment was already used" after a send that may have gone through, the payment was taken and its answers were lost on the way: the result says
charged: truewith no answer, and a repeat is a new purchase. - A transaction hash is shown only when it is 64 hex digits; the payer shown is always the configured wallet, whatever a receipt says.
Checking a setup without spending
- Dry run. Set
ARCHIPELAGO_X402_DRY_RUN=1: the paid tools read the live terms, check them against the rules above and showwouldPay. - An empty wallet. Configure any new key that holds no USDC and call a paid tool. The service checks the signature and refuses with "the payer's USDC balance is below the price" before anything is charged;
archipelago_receiptsthen shows nothing spent (the attempt still counts toward the signing limit).
Development
npm ci --ignore-scripts
npm test # config, ledger, payment rules, the server in process, and the CLI over stdio
npm run typecheck
npm run buildThe tests run against a local stand-in for the paid routes that recovers every signature it is sent, so what the server signs is verified, not assumed.
To run a local build instead of the published package, use node /path/to/mcp/dist/index.js as the command in place of npx -y @archipelagodex/[email protected].
Changes
0.1.1. @x402/core and @x402/evm move from 2.28.0 to 2.29.0 (still exact pins). The older pair depended on zod 3.x, so an install carried a
second, older copy of zod next to this package's own; GHSA-mrhx-c7xc-m3w5 (memory use while validating oversized collections) covers it. The new pair
use zod ^4.6.6, which this package's own pin (4.6.7) satisfies, so there is one copy and it is patched. The package's tests, which recover every
signature it sends, pass without changes.
0.1.0. First release.
Publishing (maintainers)
The package lives in the npm organization archipelagodex, under the scoped name @archipelagodex/archipelago-x402-mcp. An organization owns only scoped names; an unscoped name belongs to whoever published it. Scoped packages are private by default, so publishConfig.access is public. The first publish used the unscoped name archipelago-x402-mcp by mistake (it belongs to a personal account, and its 0.0.0-stage placeholder came from staged publishing); that name is deprecated and points here.
Versions 0.1.0 and 0.1.1 go up from a maintainer's machine; later versions can come from CI once the source is public. Checked against npm's and the MCP Registry's documentation in October 2026.
- In a clean checkout, in this folder, run
npm ci --ignore-scripts && npm test && npm run build, thennpm pack --dry-run. Expect these files:README.md,LICENSE,package.jsonanddist/*.js. npm loginas a member of the organization (two-factor on for authorization and publishing),npm publish --dry-run, thennpm publish. TheprepublishOnlyscript runs the typecheck, the build and the tests first.- MCP Registry, after the npm publish (the registry reads
mcpNamefrom the package already on npm):mcp-publisher login githubas the GitHub accountRunTimeAdmin(io.github.RunTimeAdmin/*is that account's own namespace),mcp-publisher publishin this folder, thenmcp-publisher logout.nameinserver.jsonmust equalmcpNameinpackage.json(the registry name is tied to GitHub and staysio.github.RunTimeAdmin/archipelago-x402-mcp), the packageidentifiermust be the scoped npm name, and both versions inserver.jsonmust equal the npm version. Itsdescriptionmay be 100 characters at most. - For every release, change the version in
package.json, inserver.json(twice), inVERSIONinsrc/server.tsand in the pinned lines above (the testversion:intest/server.test.tsfails when they differ). A published version cannot be overwritten: fix a mistake with a new version andnpm deprecatethe bad one. - npm provenance and tokenless CI publishing need a public source repository; npm does not generate provenance from a private one. When one exists, add
repositorytopackage.jsonandserver.json, and set up a trusted publisher on the package's npm settings page. - The five direct dependencies are pinned exactly: move them on purpose, and re-run the tests. Do not add an
npm-shrinkwrap.jsonexpecting it to pin users' installs: it was tried, and npm 10.9 ignored it for this dependency tree (October 2026).
Archipelago is independent and not affiliated with Circle, Arc, the x402 project or any wallet or client named here. Nothing here is financial advice.
