joyride-cli package and speaks
MCP over stdio.
It is a reading and requesting surface, not a full trading surface. Read
The server holds no signing key before
planning anything around it.
Connect a client
Install the CLI, sign in, then register the server with a client:--client accepts claude, codex, or cursor. Pass --force to overwrite
an existing entry, and joyride mcp uninstall --client <client> to remove it.
To register it by hand, the server entry is the joyride binary with the
mcp serve arguments:
joyride login wrote and sends it as a bearer for every downstream call. It
never runs Sign-In with Solana itself and never opens the keystore. If the
session has expired, every tool reports that and points back at
joyride login. A wallet selected on the command line that does not match the
stored session is a fatal startup error, so one wallet’s session can never be
used to act as another.
What the RFQ tools expose
Package legs are ordered and their quantities are signed decimal strings:
positive buys the leg, negative sells it. Submitted order is canonical and is
never sorted.
request_rfq_quote takes an optional client_ref idempotency key. When a
request’s outcome comes back unknown, re-sending the same key retries that
request rather than opening a second one.
Market data and account reads are available through the server’s other tools
and resources. Order-book trading tools also exist from the exchange’s earlier
shape; the venue these pages document is RFQ, and nothing here teaches the
order book.
Three maker tools — watch_rfq_requests, respond_rfq_quote, and
decline_rfq_request — exist behind an operator switch and are absent from the
tool listing unless it is on. Quoting from MCP is limited by the same missing
key described below, so a desk should read TypeScript Maker SDK
instead.
The server holds no signing key
This is a design decision, not a gap to configure around. The MCP server is a pure auth client. It resumes a session token; it never opens the keystore and never produces an ed25519 signature. Accepting a quote and responding to a request are both signing operations, so in production:accept_rfq_quotecannot sign an acceptance.respond_rfq_quotecannot sign a maker quote. Its refusal says so in those words and points at the CLI.
joyride CLI, which holds the keystore, or in the
Joyride app. A workable division of labour is: let the agent find the package
and request the quote through MCP, then accept from the CLI with
joyride rfq accept.
A refused accept consumes nothing. No nonce is spent, no request state changes,
and the account’s other live requests are unaffected.
The spend ceiling
accept_rfq_quote is gated by two environment variables before it touches
anything, and the gate is a safety requirement rather than an optional tweak.
They are required together: with neither set, or with only one set, every
accept refuses. A half-configured operator would otherwise believe spend is
capped while a whole dimension stayed open.
JOYRIDE_RFQ_MAX_PREMIUM_USDC caps the total cash one accept may cost.
JOYRIDE_RFQ_MAX_LOCKED_USDC caps the collateral one accept may lock.
Set both in the env object of the server entry in your client’s
configuration, or export them in the shell that launches the server. Values are
plain USDC decimals, for example 250.00.
Total cash, not premium alone
That first cap is a cost ceiling, not a premium ceiling. It bounds the premium plus the trading fee maximum the signature authorizes, compared as one number. The fee is real money leaving the account, and it is charged and capped per leg rather than per package, so it grows with the number of legs while the premium does not have to. A package can therefore owe far more in fees than its premium suggests; the worked example on Fees and Limits shows one. A credit package is not automatically under the ceiling. A credit pays the taker, so its premium contributes nothing to the cost — but the fee is still owed, and it is the whole cost. Those are exactly the structures a premium-only ceiling never bounded at all. The same two caps bound the maker tools when they are switched on, with the worst-case package outflow standing in for the premium: a quote is refused when that outflow plus themax_maker_fee it signs for is above the cost ceiling.
The refusal names the bound, the limit, the figure and the overshoot.
Three properties are deliberate:
- The ceilings are the operator’s, and
accept_rfq_quoteexposes no arguments for them. A model cannot pass what it cannot name, so it cannot raise them. - They are read at call time, not at startup, so there is no stale captured copy to disagree with the environment.
- They are handed to the SDK, which evaluates them against the same read the signature is built from. A pre-check would test one read and sign against another.
What an agent can and cannot do
There is no cancel and no replace
A quote delivered to the venue is firm until itsexpires_at. Nothing pulls it
back, amends it, or replaces it, and the quote’s TTL is the only control over
how long that commitment stands.
For an agent on the taking side, the consequence is on the clock: a quote that
is read and reasoned about for too long expires, and the venue refuses an
accept that arrives with under two seconds of life left. Treat expires_at as
a deadline, not a hint, and re-request rather than accepting stale state.