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

@ripplesdotrun/mcp

v0.18.0

Published

Exposes Ripples on Robinhood Chain to AI agents over stdio, signing with keys from your environment: launch, trade, collect and leave wakes. Does not run the agent: the model loop, memory and policy are yours.

Downloads

2,855

Readme

@ripplesdotrun/mcp

This exposes Ripples actions on Robinhood Chain to an AI agent over stdio: it signs with keys from your environment when a tool is called. It does not run the agent. The model loop, memory and policy are still yours; this server only signs what that loop asks for and reports what happened.

A model can launch a token and its collection with an agent's contract as the creator, run that agent inside its charter's limits, collect what this server's wallet is owed, and leave a market's income to whoever holds an NFT. New launches run on Robinhood Chain. A Crosscurrent already open is still read, joined and settled with the tools under "Crosscurrents already open".

An agent's operator key can spend at most a day's limits, only on the agent's own market and the published addresses. Treat it like the funds it controls.

Use it

{
  "mcpServers": {
    "ripples": {
      "command": "npx",
      "args": ["-y", "@ripplesdotrun/mcp"],
      "env": {
        "RIPPLES_NETWORK": "mainnet",
        "RIPPLES_ALLOW_MAINNET": "1",
        "RIPPLES_MAX_PER_CALL": "0.02",
        "RIPPLES_PRIVATE_KEY": "0x…"
      }
    }
  }
}

| Variable | What it does | |---|---| | RIPPLES_NETWORK | mainnet for Robinhood Chain (4663), or testnet for its test network (46630); a Crosscurrent already open is on the same network's Solana and Arc. robinhood and robinhood-testnet are accepted as aliases for the same two. Any letter case is read the same. | | RIPPLES_ALLOW_MAINNET | 1 or true, in any letter case, lets tools sign on mainnet. Left out, or 0 or false, every signing tool is refused before a chain or the API is asked anything, and the read tools still answer. | | RIPPLES_PRIVATE_KEY | The EVM wallet this server signs with on either chain: 64 hexadecimal characters, with or without 0x. | | RIPPLES_SOLANA_KEYPAIR | The absolute path of a Solana keypair file, or one that starts with ~/, as solana-keygen writes it, readable only by its owner (chmod 600). | | RIPPLES_SOLANA_SECRET_KEY | The Solana secret key in base58 or as a JSON array, when there is no keypair file. Set beside one, the file is the key the server uses, and a secret that cannot be a key still stops it at startup. | | RIPPLES_API_BASE, RIPPLES_SITE | The Ripples API and site, each an http or https address. On mainnet they default to https://api.ripples.run and https://ripples.run. Testnet has no public API, so set both to your own. The sign-in message must name the site. | | RIPPLES_RPC_URL, RIPPLES_ARC_RPC_URL, RIPPLES_BASE_RPC_URL, RIPPLES_SOLANA_RPC_URL | Your own Robinhood Chain, Arc, Base and Solana endpoints, in place of the public ones, each an http or https address. The public Robinhood Chain endpoint limits how often a client may ask; set your own for anything that reads often. | | RIPPLES_MEDIA_DIR | The only folder a tool may read an image from: an absolute path, or one that starts with ~/. | | RIPPLES_TREASURY | The treasury address of a single-chain agent that already exists, all lowercase or checksummed. With it, ripples_agent_status and ripples_agent_activity need no key. | | RIPPLES_MAX_PER_CALL | The most this server signs away in one call, per chain, in that chain's own asset (ETH on Robinhood Chain, WETH on its testnet and for a single-chain agent, USDC on Arc, SOL on Solana). Required on mainnet before any tool that moves value runs. See "Spending limits". | | RIPPLES_MAX_PER_DAY | The most this server signs away in any rolling 24 hours, per chain, in that chain's own asset, with ETH and WETH one tally on Robinhood Chain. Optional on both networks. Kept in memory; forgotten on restart. |

The server runs on mainnet when RIPPLES_NETWORK is unset. The SDK is stricter: its clients take the network by name, so code moving from this server to the SDK passes network: "mainnet" where the server config left it out.

The server checks its settings before it answers the handshake. A network it does not know, a RIPPLES_TREASURY that is not a valid address, a key that cannot be used (a malformed private key, a Solana secret that is not one, even beside a keypair file, a keypair path that is not absolute or ~/…, or a keypair file that is missing, unreadable, open to other users or not a keypair), a RIPPLES_ALLOW_MAINNET other than 1, true, 0 or false, a RIPPLES_MAX_PER_CALL or RIPPLES_MAX_PER_DAY that is not a positive decimal number, an endpoint setting that is not an http or https address, or a RIPPLES_MEDIA_DIR that is not an absolute path (or ~/…) naming a folder this server can read stops it with one line on stderr naming the variable and the fix.

The line never repeats an endpoint's value, which may hold a key. Your MCP client shows that line in its server log. The read tools never need a key, so a key problem never comes back as a failed read.

Run npx @ripplesdotrun/mcp --pins (or node dist/server.js --pins from a checkout) to print the exact contract and program addresses, Solana code hashes and upgrade authorities this build pins for RIPPLES_NETWORK, without starting the server. --help prints a short usage and --version the version, each without starting the server; any other flag, such as -v or a mistyped --pin, prints the usage on stderr and exits with code 2. --pins also lists the bridged releases the one-wallet tools recognise on the network (on the testnet, its v4 release), and on mainnet the wake contracts on Robinhood Chain and Base. SECURITY.md explains what those pins are for and how to check one yourself.

With no keys the server still reads: ripples_agent_status and ripples_agent_activity with RIPPLES_TREASURY, on mainnet ripples_wake and ripples_wake_split, and for a Crosscurrent already open ripples_dual_fill_status, ripples_dual_fill_positions for the evm and solana addresses you pass it, ripples_dual_fill_agent_remaining and ripples_crosscurrent_progress.

ESM only, Node 20.18 or newer.

From a checkout, npm test installs and builds the SDK beside this package, links it, builds this package and runs the tests; npm install alone resolves @ripplesdotrun/agent-sdk from the registry.

Answers and refusals

Every answer starts with statusLabel and summary, a Crosscurrent tool's in the words ripples.run shows for the same Crosscurrent. A refusal has statusLabel Refused, a summary to quote, a stable code, and a detail where there is one. No answer and nothing on stderr carries a key, a Solana secret or a configured RPC address.

Each single-chain agent write answers the same way: once its transaction landed, statusLabel (Bought, Sold, Minted, Paid, Noted, Claimed, Launched), a summary saying what the transaction did, read back from its receipt, and transaction with transactionUrl. Where that read fails the transaction still landed, and the summary says what it did could not be read. ripples_agent_status answers Agent, or No agent with how to name or launch one.

ripples_agent_activity answers Activity, with the entries newest first under activity; ripples_collect answers Collected or Nothing collected; and each wake tool answers Bound, Pinned, Wake or No wake, Released or Nothing released, Shared or Split. So every tool's answer, a refusal included, leads with statusLabel and summary, the same in structuredContent as in the text, and every tool lists an outputSchema naming the two.

A refusal the SDK words in its own names is said in this server's: the SDK's client is this server's wallet, its methods are this server's tools (ripples_share_wake, ripples_agent_status, ripples_agent_claim_vested), and a plan_invalid from ripples_launch_agent names the argument at fault as field (perCallSpend, operator, image, and so on) and by that name in its summary.

A call whose arguments do not fit the tool's schema, that passes an argument the tool does not take, or that sends its arguments as a string rather than an object, is refused as arguments_invalid with the field at fault, or as id_invalid for a Crosscurrent id. Its summary says what the argument must be, for example The side argument must be robinhood, arc or solana. A tool whose act cannot be undone lists acknowledge as a required argument whose only value is "permanent"; a call without it is refused as arguments_invalid on acknowledge, its summary saying what is permanent.

A text limit given in bytes is counted in bytes: ripples_launch_agent's image (512), description (2,048), and website and x (256 each). A longer value, however few its characters, is refused as arguments_invalid on that argument, its summary giving the limit in bytes. An argument a tool took under an older name is refused naming the one that replaced it, for example This tool takes no twitter argument. Pass twitter as x.

Amounts are decimal strings in their own asset's places: 18 in ETH, WETH or a token, 6 in USDC on Arc, 9 in SOL, and on a Solana side priced in another asset that asset's own, which the SDK holds the amount to once it has read the Crosscurrent's record. Trailing zeros are not counted as places, so "1.0000000" is a USDC amount. An amount with a digit past its places is refused in one wording, for example amount can have at most 6 decimal places in USDC on Arc. minTokensOut on ripples_dual_fill_agent_buy is a token amount: 18 places on Robinhood Chain and Arc, 9 on Solana. A wake tool's tokenId is text, such as "2", as an amount is; a number is refused.

An address argument is refused as address_invalid, naming the field, for example operator, payees.1, charter.robinhood.operator or for.evm. A 0x address is all lowercase or carries its checksum capitals, so capitals that do not match the checksum, all capitals included, are refused rather than corrected; a Solana address is base58.

A signing tool checks its wallet first: without the key it needs it is refused as signer_missing, naming the variable to set, and only then as mainnet_not_allowed.

A transaction the node turned away for its funds, nonce, fees or gas carries no transaction in any tool, whatever code the SDK filed it under, and its summary says nothing was sent, or, after earlier transactions in the same call landed, that it was not sent and what landed is in completed. It counts nothing against the spending limits. A transaction_refused from a single-chain, wake or collect tool carries no transaction either: what was refused never landed.

A Crosscurrent transaction that reverted on chain is refused with its hash. insufficient_funds names the chain the call signed on, Base or Robinhood Chain for a wake tool. A call that sends several transactions and fails after one of them landed carries those in completed, each without its receipt: what a Crosscurrent claim, refund or take-back did on the sides before it, a launch's approval, ripples_collect's claims or a wake's steps.

A chain endpoint that turns this server away (HTTP 401 or 403) is refused as endpoint_refused, and one limiting how often it may ask (HTTP 429) as chain_unavailable; both say to set that chain's endpoint setting (RIPPLES_RPC_URL, RIPPLES_ARC_RPC_URL, RIPPLES_BASE_RPC_URL or RIPPLES_SOLANA_RPC_URL) to your own and restart. The public Robinhood Chain endpoint limits how often a client may ask, so a server that reads often should name its own. ripples_dual_fill_positions says the same for a chain whose endpoint turned it away or is limiting it.

When any signing call finishes after its client stopped waiting (a cancel, or a timeout that sends one), the server keeps what it answered. The next signing call from any wallet it used is refused once with previous_unanswered, carrying that answer under previous, a list of { tool, answer }. Read it before calling again: the earlier call may already have done what this one asks. Reads are never held back this way.

The codes a tool can answer with:

  • Arguments and setup: arguments_invalid, id_invalid, argument_invalid, address_invalid, plan_invalid, tool_unknown, signer_missing, wallet_missing, mainnet_not_allowed, api_missing, treasury_missing, not_a_ripples_agent, media_dir_missing, media_dir_unreadable, image_choice, image_missing, image_outside_folder, image_unreadable, image_invalid.
  • This server's own guards: call_cancelled, previous_unanswered, create_running, create_unfinished, launch_running, launch_unacknowledged, spend_cap_required, over_spend_cap.
  • New launches: robinhood_only. A tool that prices or creates a Crosscurrent, called by name: new launches run on Robinhood Chain, and this server lists none of them.
  • One-wallet Crosscurrents: artwork_missing, artwork_order, artwork_too_many, crosscurrent_closed, crosscurrent_refused, launch_not_found, launch_interrupted, launch_sent, launch_unconfirmed, launch_reverted.
  • Chains and transactions: chain_unavailable, endpoint_refused, insufficient_funds, transaction_refused, transaction_reverted, transaction_unconfirmed, receipt_unexpected, wrong_chain, deployment_mismatch, pin_mismatch, program_mutable, fill_unverified, side_missing, not_on_network, launch_unknown, failed.
  • The Solana quote: quote_not_admitted, quote_paused, quote_frozen. The asset is not one the launch program admits, or its issuer holds transfers or an account the call needs. A hold leaves the Crosscurrent standing; the call can be tried again once it lifts.
  • Agents and their limits: over_daily_spend, over_call_spend, over_daily_sell, over_daily_mint, not_payee, not_operator, capability_unsupported, spend_window_exists, spend_window_invalid, spend_window_migration_required, spend_window_not_ready, spend_window_upgrade_required, not_an_agent, agent_stopped, agent_not_opened, agent_not_offered, agent_not_on_network, snipe_window, curve_ended, nothing_to_receive, runway_too_small, runway_too_large, charter_creator_wallet, charter_invalid.
  • Wakes: not_holder, nft_not_on_chain, not_fee_recipient, already_routed, split_unknown. The wallet does not hold the token, a piece has no holder on the chain named, the launch cannot be pointed at the pieces by this wallet, or the address named is not a split.
  • Crosscurrent state: not_filling, withdrawals_frozen, below_minimum, more_than_held, wallet_limit, nothing_held, nothing_to_claim, nothing_to_refund, deposit_held, deposit_settled, create_stopped, setup_closing, receipt_mismatch, reservation_mismatch.
  • The Ripples API: api_error, api_unavailable, bridged_unavailable, rate_limited (with retryAfter in seconds), sign_in_mismatch, artwork_draft_full, artwork_drafts_open, artwork_mismatch, artwork_not_found, artwork_quota_exceeded, artwork_sealed, artwork_storage_full, bad_signature, challenge_expired, unauthorized, invalid_request, dual_fill_not_found, dual_fill_conflict, dual_fills_not_enabled, kind_not_offered, fill_not_offered, collection_not_offered, fill_over_cap, fill_too_small, identity_invalid, collection_invalid, image_too_large, image_type_mismatch, unsupported_image, launch_media_quota_exceeded, metadata_storage_unavailable, leg_mismatch, leg_not_confirmed, not_setting_up, not_the_creator, price_out_of_tolerance, price_stale, price_unavailable, setup_expired, tax_invalid, terms_unreachable, too_many_pending, window_invalid.

Single-chain agent tools

| Tool | What it does | |---|---| | ripples_launch_agent | Creates the token, the market, the collection and the agent's contract, in one transaction, and moves the runway in | | ripples_agent_buy | Buys its own token on its own market | | ripples_agent_sell | Sells it back, inside the charter's daily ceiling | | ripples_agent_mint | Mints from its own collection | | ripples_agent_pay | Pays one of the published addresses | | ripples_agent_note | Writes to the public run log | | ripples_agent_claim | Takes in the trade fees and the collection's share of every mint | | ripples_agent_claim_vested | Takes in the token slice the agent's own mints earned it; with tokenIds only when its launch keyed its vest to pieces, as ripples_agent_status says in capabilities.vestKeyedToPieces | | ripples_agent_status | The charter, what is left of today's limits, what the treasury holds in WETH and in its own token, what its market and collection owe it now, how its vest is keyed, and the launch's addresses | | ripples_agent_activity | Everything the agent has done, newest first | | ripples_collect | Takes in everything this server's wallet is owed on Robinhood Chain, in one pass |

ripples_collect is for the server's own wallet rather than an agent's treasury: the creator fee of each launch it created, per asset; the proceeds of each collection it created; the token slice its mints vested, whether the vest belongs to the wallet or to the pieces it holds; holder periods the publisher could not push to it; and a paired launch's stock rewards. Each claim is read first and sent only with something to pay, so a wallet owed nothing sends nothing. The answer's summary says what was sent, or why nothing was: nothing is owed now, or this wallet is not the launch's fee recipient, minter or collection creator (an agent's launch pays its creator fee to the agent's treasury, which ripples_agent_claim collects); sent lists each claim with its transaction and skipped what was found and not sent, with the reason.

The wallet's launches and the rewards published for it come from the Ripples API; on the testnet, which has none unless RIPPLES_API_BASE names yours, launches names the launches and the rewards are skipped, saying so. A launch named that is not one on this network is refused as launch_unknown. The server's network decides which Robinhood Chain it collects on.

ripples_agent_status and ripples_agent_activity read with RIPPLES_TREASURY alone. The first read checks that the address is a treasury a Ripples agent factory deployed on this network; a wallet address, or an agent launched on the other network, is refused as not_a_ripples_agent, saying which setting to change. A tool that needs an agent, on a server whose RIPPLES_TREASURY names none, is refused as treasury_missing, saying to set RIPPLES_TREASURY to the agent's treasury and restart, or to launch one with ripples_launch_agent.

With no agent named, ripples_agent_status answers No agent with how to name or launch one, key or no key. Its answer's budget.balance is what the treasury holds in WETH, which every spend comes out of whatever is left of the day, and budget.tokens is the agent's own tokens it holds, the most a sell can take. owed, { quote, tokens }, is what its market and collection owe it now, which ripples_agent_claim takes in. capabilities.vestKeyedToPieces says how its launch keyed its vest: true, so ripples_agent_claim_vested takes tokenIds; false, so it takes none; null when that cannot be told. capabilities.objectVesting says whether the treasury's contract can claim a vest keyed to pieces at all. The summary says each of them. A read of owed or capabilities that fails just then leaves that field out, and the rest of the status still answers. This server's launches key the vest to the agent's wallet. ripples_agent_activity answers Activity with its entries under activity, and reads back to fromBlock 10,000 blocks a request, the last 50,000 blocks by default; fromBlock: 0 reads back to the agent's launch and stops there, and a call that is cancelled stops the read.

Every other tool here signs with RIPPLES_PRIVATE_KEY, pays its network fee in ETH from that wallet, and on mainnet needs RIPPLES_ALLOW_MAINNET. Signing calls from one wallet run one at a time, across both sets of tools, so two cannot take the same nonce; reads do not wait.

ripples_launch_agent spends the runway, in WETH, from this server's wallet. No tool here wraps or fetches WETH: on mainnet wrap ETH into WETH first, and on the testnet the WETH contract's faucet() gives a wallet 1 a day. A wallet short of the runway is refused as insufficient_funds, naming the chain, before anything is signed. Its operator is required: it is the only key that can ever spend from the agent's contract, and it cannot be changed. The server's own wallet is allowed, but it is also the wallet that funds the runway, so give the agent a key that holds nothing else, run from its own server with RIPPLES_TREASURY set.

The ticker follows the Crosscurrent rule: 1 to 10 letters or digits. Its X link is x, as on every other tool, and its per-call limit is perCallSpend, the name ripples_agent_status answers with. A call that still passes twitter or perTransactionSpend is refused as arguments_invalid, naming x or perCallSpend. creatorChargePercent, from 0 to 10 in steps of 0.01, adds a charge on every trade in the agent's market that is paid in full to its contract, on top of the 1% trade fee; it is fixed at launch and defaults to 0. dailySpend and perCallSpend may both be 0, for an agent that only sells or writes notes. ripples_agent_note's uri is at most 200 bytes, written on chain and paid for by this wallet.

A client that asks for progress is sent a note as each step starts: the runway's approval, where one is needed, then the launch. A call that is cancelled or times out stops before its next signature and answers call_cancelled, carrying in completed the approval where that landed; the answer reaches the wallet's next signing call as previous_unanswered, and a launch sent again uses that approval. An approval moves nothing, so a launch that stops after it, cancelled or refused before its launch transaction was sent, gives the runway it counted back to the day, and the launch sent again fits RIPPLES_MAX_PER_DAY as the first did. A launch answers Launched, with a summary of what moved and a note saying how to keep working the agent: with RIPPLES_TREASURY unset, this server works it until it restarts.

The launch is permanent: the charter's limits and payees can never change afterward, there is no pause, and losing the operator key ends the agent for good. ripples_launch_agent takes acknowledge: "permanent" as a required argument. An operator named as one of its own payees is refused too, as plan_invalid, before anything is signed.

Leave RIPPLES_TREASURY out and ripples_launch_agent sets it for the rest of the session. It is held in memory, so copy the treasury address it returns into the config before you restart: nothing else can find it for you. A later launch, once previousLaunch names the last, goes through a client of its own, and the session then works the agent it created; the earlier one is reached again only through RIPPLES_TREASURY. With RIPPLES_TREASURY set, the launch goes through a client of its own and this server goes on working the configured agent; the answer's note names the new treasury to set in RIPPLES_TREASURY to work it after a restart.

One launch runs at a time. The server keeps what the last launch did, so an answer the client never received is not lost: until a call names that launch as previousLaunch, a repeat launch sends nothing and is refused with launch_unacknowledged, carrying the launch's treasury, or its transaction when it was sent and not seen to confirm. A launch sent without an answer is refused as transaction_unconfirmed with its transaction.

ripples_agent_buy and ripples_agent_sell take minReceived, and ripples_agent_mint takes minRouted, the least the trade must return or route. Leave it out and the SDK sets it to 99% of what the market quotes when the call is made.

An agent launched without dailySell can never sell. A sell from it, or one above what is left of today's ceiling, is refused as over_daily_sell before anything is signed or sent. Any other call the charter forbids is refused before it is signed, under the limit's own code (over_call_spend, over_daily_spend, over_daily_sell, over_daily_mint, not_payee), its summary saying the limit and the call in WETH, tokens or pieces. A sell above the agent's own tokens the treasury holds is refused as more_than_held, and a buy or payment above the WETH it holds as insufficient_funds, each naming both figures, before anything is signed. A key that is not the agent's operator is refused as not_operator before anything else is asked. On ripples_agent_buy and ripples_agent_pay the server reads the operator itself, once for each treasury, so that refusal comes before the call is counted against RIPPLES_MAX_PER_CALL or RIPPLES_MAX_PER_DAY; of the spending checks, only a missing RIPPLES_MAX_PER_CALL on mainnet is said before it. A call refused this way gives back what it counted against the day's spending limits.

ripples_agent_claim reads what is owed first; with nothing owed it is refused as nothing_to_claim before anything is sent, and so is ripples_agent_claim_vested with nothing vested. A vest claimed the other way from how its launch keyed it, with tokenIds for a vest keyed to the wallet or without them for one keyed to pieces, is refused before anything is sent, as transaction_refused (or capability_unsupported for a treasury that cannot claim by piece at all), saying to call again without or with tokenIds.

Wake tools

A piece leaves a wake when a market is launched from it: the market's creator income goes to whoever holds the piece, and when the piece is sold, the income goes with it. These tools work on Robinhood Chain mainnet, named by chain; on a testnet server they are refused as not_on_network. New launches run on Robinhood Chain, so ripples_bind_token, ripples_pin_wake and ripples_share_wake take chain: "robinhood" alone, while the reads and releases also take chain: "base" for a wake on Base.

| Tool | What it does | |---|---| | ripples_bind_token | Makes a token this server's wallet holds an ERC-8004 agent, and answers the ripples.run link that launches a market from it | | ripples_pin_wake | Points the creator income of a launch this server's wallet made at a piece, for good | | ripples_wake | What a piece is owed now, what it has paid and its last payout | | ripples_release_wake | Pays everything a piece is owed to whoever holds it now | | ripples_share_wake | Shares the creator income of a launch this server's wallet made between up to 256 pieces, for good | | ripples_wake_split | What each piece of a split is owed now and has been paid, and who holds it | | ripples_release_split | Pays each piece of a split its part, at most 64 pieces a transaction |

ripples_pin_wake and ripples_share_wake cannot be undone and take acknowledge: "permanent" as a required argument. Every wake tool takes tokenId as text, such as "2". Anyone may send ripples_release_wake or ripples_release_split, and neither pays anyone but a piece's holder. The tools that sign spend the network fee and nothing else, so neither spending limit applies to them, and insufficient_funds from one names the chain it signed on. A release answers what it sent and, under skipped, each step the chain refused before anything was signed for it, such as a currency the holder cannot take; the rest goes ahead.

Each wake tool's answer leads with statusLabel and summary: Bound, Pinned, Wake or No wake, Released or Nothing released, Shared, Split. A pin or share the launch already has answers Pinned or Shared with nothing sent, and a release with nothing owed answers Nothing released, saying why.

ripples_wake and ripples_wake_split read with no key: what is owed comes from the chain when it is asked, and what has been paid from the Ripples API for a piece, or from the split itself. ripples_wake names a piece's part of a split in split where the Ripples API lists it; where it does not, split is null, and a piece paid only through a split answers wake: null. Read a split you know with ripples_wake_split. Where the API lists more markets than one call reads (256), the answer carries marketsOmitted; name any of them in launches.

Crosscurrents already open

New launches on Ripples run on Robinhood Chain, so this server lists no tool that prices or creates a Crosscurrent, and answers a call to one by name as robinhood_only. A Crosscurrent already open, on any of its chains, is read, joined and settled with these:

| Tool | What it does | |---|---| | ripples_dual_fill_join | Adds money to one side's opening buy | | ripples_dual_fill_withdraw | Takes money back from a side that is still filling | | ripples_dual_fill_status | Where a Crosscurrent stands, each side checked against its chain | | ripples_dual_fill_positions | Every side this server's wallets, or the addresses given, have money in | | ripples_dual_fill_claim | Claims tokens on each opened side, or on the one chain named | | ripples_dual_fill_refund | Sends money back from each side that did not open, or from the one chain named | | ripples_dual_fill_take_back_deposit | Sends the launch deposit back to the fill's creator (the wallet that created the Crosscurrent, or an agent's treasury) from each side that has opened or can no longer open, or from the one chain named; any wallet may send it | | ripples_dual_fill_agent_buy | The agent buys its own token on one chain | | ripples_dual_fill_agent_pay | The agent pays one of its fixed payees | | ripples_dual_fill_agent_note | The agent writes to its public log | | ripples_dual_fill_agent_remaining | What the agent may still spend and sell on each chain, and its Solana spending window's version and state | | ripples_dual_fill_agent_migrate_spend_window | Starts an agent's Solana spending window and its 24-hour wait; refused on both networks in this release | | ripples_crosscurrent_resume | Finishes a launch this server's wallet reserved, after a call_cancelled, launch_interrupted or launch_reverted answer. Signs; on mainnet the same settings as the launch | | ripples_crosscurrent_progress | Where a launch stands: each market's phase as Ripples last observed it, the token on each chain, its page. Reads only | | ripples_crosscurrent_name_solana_payout | Names this server's Solana wallet as where the creator's share of the Solana market's fees goes, with one message signed by it, after signing in with RIPPLES_PRIVATE_KEY, the wallet that reserved the launch. Permanent, so it needs acknowledge: "permanent"; on mainnet it needs RIPPLES_ALLOW_MAINNET=1 |

Every tool here that signs pays the network fee on the chain it signs on: with RIPPLES_PRIVATE_KEY on Robinhood Chain and Arc, and with RIPPLES_SOLANA_KEYPAIR or RIPPLES_SOLANA_SECRET_KEY on Solana. A side names one chain of the Crosscurrent's set: robinhood, arc or solana. A claim, refund or take-back with no side, or with all, walks every chain the Crosscurrent has a side on; when it fails after one side went through, the refusal carries completed with what that side did. ripples_dual_fill_take_back_deposit refuses a side whose deposit is not due back yet as deposit_held, and one already back as deposit_settled.

The agent tools run from a server holding the operator's key. Each is refused before signing when that key is not the charter's operator, when the agent is stopped, when its market has reached its funding target (curve_ended), or when its limits would refuse it. A Solana ripples_dual_fill_agent_buy or ripples_dual_fill_agent_pay, and ripples_dual_fill_agent_migrate_spend_window, are refused as spend_window_upgrade_required. ripples_dual_fill_agent_note records the keccak256 hash of the entry's UTF-8 text beside a link to it: pass text and the server hashes it, the same hash ripples_agent_note writes, or pass the hash yourself as digest.

ripples_crosscurrent_resume, ripples_crosscurrent_progress and ripples_crosscurrent_name_solana_payout take launch, the 0x id at the end of the launch page's address (64 lowercase hex characters); an unknown id, the all-zero id included, is refused as launch_not_found. A resume answers Launched once the launch went through, and launch_unconfirmed for a transaction signed and not seen to confirm: follow it with ripples_crosscurrent_progress before anything else.

Spending limits

RIPPLES_MAX_PER_CALL and RIPPLES_MAX_PER_DAY bound every tool that moves value, checked before anything is signed and independent of any charter an agent may later have: ripples_launch_agent (its runway), ripples_agent_buy, ripples_agent_pay, and on a Crosscurrent already open ripples_dual_fill_join, ripples_dual_fill_agent_buy, ripples_dual_fill_agent_pay and ripples_crosscurrent_resume. Both figures are per chain, in that chain's own asset: ETH on Robinhood Chain (WETH on its testnet), with a single-chain agent's WETH counted in the same day's tally, USDC on Arc, SOL on Solana. Figures are counted exactly, to 18 decimal places. RIPPLES_MAX_PER_DAY counts a rolling 24 hours and is kept in memory only, so it resets to nothing when the server restarts.

On mainnet, a tool that moves value is refused with spend_cap_required unless RIPPLES_MAX_PER_CALL is set; on testnet both are optional. A call above either limit is refused with over_spend_cap, naming the limit, the asset the call spends and the variable to raise:

{
  "statusLabel": "Refused",
  "summary": "RIPPLES_MAX_PER_CALL allows at most 0.02 ETH in one call on Robinhood Chain; this call is 0.05 ETH, so no transaction was sent. Raise RIPPLES_MAX_PER_CALL, or sign less.",
  "code": "over_spend_cap",
  "side": "robinhood",
  "field": "RIPPLES_MAX_PER_CALL"
}

A day refusal on Robinhood Chain says "ETH and WETH counted together". A worked config for a server that should never sign away more than 0.02 ETH in one call, or more than 0.1 ETH in a day:

{
  "mcpServers": {
    "ripples": {
      "command": "npx",
      "args": ["-y", "@ripplesdotrun/mcp"],
      "env": {
        "RIPPLES_NETWORK": "mainnet",
        "RIPPLES_ALLOW_MAINNET": "1",
        "RIPPLES_PRIVATE_KEY": "0x…",
        "RIPPLES_MAX_PER_CALL": "0.02",
        "RIPPLES_MAX_PER_DAY": "0.1"
      }
    }
  }
}

RIPPLES_MAX_PER_CALL and RIPPLES_MAX_PER_DAY are one number each, not one per chain: on a Crosscurrent already open, 0.02 means 0.02 ETH on Robinhood Chain and, separately, 0.02 SOL on Solana, tracked on their own. A join on a Solana side priced in another asset counts in that asset, as written, in a day's tally of its own: the same 0.02 bounds it at 0.02 DKNGx. With a cap set, the server reads the Crosscurrent's status before it counts a Solana join, and the refusal names the asset, for example "this call is 0.5 DKNGx". A one-wallet resume counts everything it takes together in the home chain's own asset, a token at its dollar value at the launch's prices. Run separate servers with different keys and settings if two chains need different limits.

A call refused before anything was signed, by this server or by the SDK with no transaction sent and nothing completed, takes its amount back out of the day's tally, and so does one whose transaction the node turned away. So does a ripples_launch_agent stopped after its runway's approval landed and before its launch transaction was sent, since an approval moves nothing. One that sent a transaction stays counted, even if it failed afterward. A launch refused with launch_running or launch_unacknowledged counts nothing.

ripples_agent_sell, ripples_agent_mint and ripples_dual_fill_agent_note are not checked against either limit: a sell is counted in the launch's own token, not its settlement asset; a mint's cost is fixed per piece on chain rather than passed to this server; and a note moves nothing beyond the network fee. All three, once an agent exists, are still bounded by its own on-chain charter. Withdrawals, claims, refunds, take-backs, notes, ripples_agent_claim, ripples_agent_claim_vested, ripples_collect, ripples_crosscurrent_name_solana_payout and the wake tools move nothing out of this server's wallets but the network fee, and ripples_dual_fill_agent_migrate_spend_window the rent of the window's account besides, so they sign on mainnet without either limit.

The keys

Give the server keys that hold nothing else. A charter bounds what an operator key can do with the agent's funds and bounds nothing about the rest of that wallet. RIPPLES_MAX_PER_CALL and RIPPLES_MAX_PER_DAY bound what this server signs away before any such charter exists; see "Spending limits" above.

Licence

MIT