@parabolicfamily/mcp
v0.2.2
Published
MCP server for Parabolic, a bonding-curve token launchpad: discover coins, quote curve trades and build unsigned transactions. Never holds keys.
Downloads
1,991
Maintainers
Readme
Parabolic MCP server
A small Model Context Protocol server for Parabolic, a bonding-curve token launchpad on Arc and Robinhood Chain. It lets AI agents (Claude Code, Cursor, custom ERC-8004 agents) discover coins, quote curve trades with the contract's exact math, and build unsigned transactions, without a browser.
What it never does: hold keys, sign, send or broadcast transactions, custody funds, or accept private keys, seed phrases or session tokens as input. Every build_* tool returns { to, data, value, chainId } for the caller's own wallet to sign. Quotes are read from chain at call time and can move before a transaction lands.
Install
Requires Node 22+. Nothing to build: point your MCP client at it with npx.
npx -y @parabolicfamily/mcp # starts the server on stdioThe ABIs ship with the package, so it works offline against any Arc RPC you point it at.
What changed in 0.1.8
One tool, parabolic.check_ticker, and nothing else moved: every call that worked in 0.1.7 works unchanged.
Given a ticker it asks the Parabolic site whether a coin already carries it on any chain the site serves
and whether <ticker>.parabolic.family is free. It is advice and not a gate (nothing on chain enforces a
unique symbol), and the hostname is the one exclusive thing, held by the oldest coin with that ticker. The
ticker is normalised the way the site normalises it, so an impossible one is refused before a request is spent.
What changed in 0.2.2
Coins on other launchpads read as ours do. list_coins pages by cursor (after, answering next), through the
indexer or the site's API. get_coin answers a venue ref (rhc:pons:0x…), and list_venue_coins lists from
the site's own index of that launchpad when no subgraph is set. A new tool, parabolic.venue_history, reads a
launchpad coin's candles, tape, holders and positions from the site (19 tools in all). A venue coin's price is
taken from its own supply, an unnamed quote asset is published as such (never as fiat), a missing creator is
null, and the fee split respects a coin whose buyback is off.
What changed in 0.2.1
No tool changed. The dependency tree is refreshed (@modelcontextprotocol/sdk 1.32.1, and the patched
proxy-addr, ip-address and fast-uri under it), so npm audit on an install reads clean, and a failed RPC
call now writes the endpoint's host to stderr rather than its whole URL, so a keyed endpoint's key stays out of
the server's own log as well as out of the answer.
What changed in 0.2.0
Five tools for coins made on other launchpads (pons on Robinhood Chain, SolonPad on Arc), traded through Parabolic's aggregator router; every call that worked in 0.1.9 works unchanged.
parabolic.list_venue_coinsreads that launchpad's subgraph whenPARABOLIC_SUBGRAPH_URL_PONS_RHC(or..._SOLONPAD_ARC) is set.parabolic.quote_routed_buy/quote_routed_sellandbuild_routed_buy_tx/build_routed_sell_txencodeParabolicAggregatorRouter.buy/sellbyte for byte as the site does, with no fee voucher and, for an ERC-20 input, an exact-amount approval of the router in place of the site's Permit2 signature. The coin lives on the other launchpad's contracts; the router charges Parabolic's routed fee (itsdefaultFeeBps, 60 bps at deploy) on top of that launchpad's own, and every answer shows both.- They refuse, by name, until the chain's deployment record carries the router under
aggregator, when the router has the launchpad switched off, when the coin is not that launchpad's, and when any read fails.
What changed in 0.1.9
0.1.9 makes Robinhood Chain (4663) a chain this server serves. Every call that worked before works unchanged and means the same chain it meant: an unqualified address is still Arc, permanently.
- Set
PARABOLIC_CHAIN_ID=4663and nothing else. The chain's public RPC, its factory and its start block ship with the package, read from the deploy's own record rather than typed in. Until 0.1.9 the server answeredchain: "rhc"with "Parabolic is not deployed on Robinhood Chain yet", which had been false since 19 September 2026, and an operator who set the chain id got Arc's RPC and no factory. list_coinsreaches that board. One site serves both, and it answers for its own chain when nothing names one, so the listing now names the chain (?chain=rhc) the way the Telegram bot does. Arc's URLs are byte-identical to what they have always been, because Arc's prefix is empty.- No routed buy there yet. The chain deploys
ParabolicRouter, which takes the referral code and the note as arguments;ParabolicMemoRouteris Arc's and the two share no function selector, so this package encodes no routed call on chain 4663.build_buy_txgoes straight to the curve andbuild_launch_txto the factory, which is the same call on every chain. The referral share itself is paid on that chain, credited by the indexer through the same ledger as Arc's memo, so what is missing here is the encoder and not the payout:parabolic.docsand the buy payload both say so, and passingmemois refused by name rather than by asking for a variable that must stay unset. parabolic.docsstates Arc mainnet as live. It described chain 5042 as "unofficial until Circle publishes it" and Arc's launch fee as 1e18; mainnet has been public since 16 September 2026 and the fee has been 0 since the 19th. The fee is read from the factory and never written down.
What changed in 0.1.7 (for an existing consumer: nothing has to)
0.1.7 makes the server chain-aware. Every call that worked in 0.1.6 works unchanged and means the same
chain it meant, because an unqualified identifier means Arc, permanently (docs/20-multichain.md §3).
- Added, optional, on every tool:
chain. A chain key ("arc") or an id (5042). Left out, it is the chain the server is configured for: Arc with no configuration at all. Arguments are strict, so this had to be declared rather than tolerated; passing nothing is what every existing caller does. - Added:
addressaccepts a reference.0x…is still a coin on this server's chain.rhc:0x…names a coin on another one and is refused by name ("…is on Robinhood Chain (chain 4663); this server is configured for Arc"), never looked up here: the same address is a different token on every chain. - Added to answers:
chain: { id, key, name }onget_coin,list_coins, both quotes, all three builders andprotocol_stats, plusrefonget_coinand on each listed coin. Nothing was renamed, nothing changed type:addressis the address,tx.chainIdis the same scalar a wallet reads. - One server still serves one chain. A second chain is a second server with its own
PARABOLIC_CHAIN_ID, RPC and factory.
Configure
Nothing is required. Out of the box the server talks to the newest Arc chain it has addresses for,
with those addresses already built in, so npx -y @parabolicfamily/mcp is a working install. Since
0.1.6 that is Arc mainnet (5042), live since 16 September 2026; set PARABOLIC_CHAIN_ID=5042002
for Arc Testnet.
Set PARABOLIC_CHAIN_ID and the RPC and contract addresses for that chain follow it. Every unsigned
transaction the server builds carries its chainId, so a wallet cannot sign a testnet launch onto
mainnet by mistake, and protocol_stats reports the chain and RPC host the server is actually using.
| Variable | Meaning | Default |
|---|---|---|
| PARABOLIC_CHAIN_ID | 5042 Arc mainnet, 5042002 Arc Testnet, 4663 Robinhood Chain | 5042 |
| PARABOLIC_RPC_URL | JSON-RPC endpoint | the public endpoint for the chain id |
| PARABOLIC_FACTORY | ParabolicLaunchFactory: coin lookups and launch transactions | the deployment for the chain id |
| PARABOLIC_MEMO_ROUTER | ParabolicMemoRouter: the atomic launch-and-buy and the referral-carrying buy. Refused on a chain whose record deploys ParabolicRouter and no memo router, because the two share no function selector and a routed build against that address would revert | the deployment for the chain id |
| PARABOLIC_EURC | EURC address, only for EURC-quoted coins | the deployment for the chain id |
| PARABOLIC_SUBGRAPH_URL | Subgraph endpoint: richer listings, holders, 24h volume, protocol stats | unset (the public API is used instead) |
| PARABOLIC_API_URL | Parabolic's public read API: listings, check_ticker, referral_status, venue_history and another launchpad's coins when no venue subgraph is set; "" turns it off | the site that serves the chain (see below) |
| PARABOLIC_SUBGRAPH_URL_<VENUE>_<CHAIN> | Another launchpad's subgraph for list_venue_coins: PARABOLIC_SUBGRAPH_URL_PONS_RHC, PARABOLIC_SUBGRAPH_URL_SOLONPAD_ARC, PARABOLIC_SUBGRAPH_URL_AKA_ARC | unset (the site's own index of that launchpad is read instead) |
| PARABOLIC_AGGREGATOR_ROUTER | ParabolicAggregatorRouter for the four routed tools. Honoured only on Anvil (31337) and the testnets, and only where the chain's deployment record names no router; ignored on Arc (5042) and Robinhood Chain (4663), where the record's router is the only one | the router in the chain's deployment record (aggregator), none until it is deployed |
| PARABOLIC_EXPLORER_URL | Block explorer the address and transaction links are built from | the explorer for the chain id |
| PARABOLIC_HOOK | ParabolicHook address | read from factory.memeHook() |
| PARABOLIC_ARC_MEMO | Arc Memo system contract | 0x5294E9927c3306DcBaDb03fe70b92e01cCede505 |
| PARABOLIC_AGENT_REGISTRY | Arc's ERC-8004 IdentityRegistry: agent_status, build_register_agent_tx and the pair: "Agents" listing filter | the registry Arc publishes for the chain id (Arc Testnet only, today) |
| PARABOLIC_LAUNCH_CONFIG_ID | Factory launch-config index (0 = the $5K open / $8,000 graduation curve) | 0 |
| PARABOLIC_FACTORY_START_BLOCK | First block of the TokenLaunched scan, used only when neither a subgraph nor the API is available | the factory's deployment block |
The API default follows the chain: Arc Testnet reads the testnet site (https://parabolic-testnet.vercel.app/api/v1,
live testnet data), Arc and Robinhood Chain both read https://www.parabolic.family/api/v1, which serves
both boards and is asked for the right one by name. Running against a fork or your own
factory: the server skips the site's API automatically whenever PARABOLIC_FACTORY differs from the
built-in address for the chain or PARABOLIC_RPC_URL points anywhere but the chain's own endpoint, and
reads the chain instead. To force that for any other reason, set PARABOLIC_API_URL="".
Call parabolic.docs to print the exact addresses this server is using, including the memo router
every launch with an opening buy is sent to, and check each one before you sign anything. The Arc
Testnet contracts below are on Arc's testnet explorer; the mainnet and Robinhood Chain contracts match
their source on Sourcify (graded match), because Arc's mainnet explorer was behind a login when they deployed:
| Contract | Arc Testnet (5042002) |
|---|---|
| ParabolicLaunchFactory | 0x2E06eD99bD7D164458847D186B282B23700b2C63 |
| ParabolicMemoRouter | 0x1381567ea31a094e64f6B39Bd880d0b59c48e08F |
| EURC (test token) | 0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a |
| Arc Memo (system) | 0x5294E9927c3306DcBaDb03fe70b92e01cCede505 |
| ERC-8004 IdentityRegistry (Arc's) | 0x8004A818BFB912233c491871b3d84c89A494BD9e |
The identity registry is Arc's contract, not ours: Arc deploys it, documents it and can change it. It is an ERC-1967 proxy, so the implementation behind that address is upgradeable by Arc. Parabolic only reads it (and builds the registration for your wallet to sign); nothing on the launchpad depends on it.
Arc mainnet (5042), deployed 16 September 2026 at block 21,105,294: factory
0x27EAeC564fd049E6920C73323ffA7eb6a32A4B1e, memo router 0x7d642150A222D0F6c98e2fC6bBe86E8Bb6DC90d0,
both matching their source on Sourcify. Arc has published no identity registry for mainnet, so on chain 5042
agent_status says there is no registry rather than reporting a wallet as unregistered.
Robinhood Chain (4663), deployed 19 September 2026: factory
0x25c9cFa179256A29f84b9Fd0DcF7cB2ff24b473d, quoted in USDG (0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168,
six decimals, Paxos), gas paid in ETH, the factory matching its source on Sourcify. Gas there is not a dollar, so a launch
fee or a balance on that chain is never a figure in dollars, and no identity registry exists. The chain's
ParabolicRouter is deliberately not configured here; see 0.1.9 above.
Claude Code
claude mcp add parabolic -- npx -y @parabolicfamily/mcpThat is enough to launch, quote and trade on Arc mainnet (5042), the default: get_coin, quote_buy,
quote_sell and every build_* tool read the chain directly, and list_coins reads Parabolic's public
read API. Only when neither a subgraph nor that API is available does list_coins fall back to scanning
TokenLaunched logs, which public Arc RPCs cap, so it then marks its result partial and names the range
it covered. Point it at a subgraph for holders, 24h volume and 24h change:
claude mcp add parabolic \
-e PARABOLIC_CHAIN_ID=5042 \
-e PARABOLIC_SUBGRAPH_URL=https://your-subgraph/gn \
-- npx -y @parabolicfamily/mcpGeneric JSON (Cursor, Claude Desktop, other MCP clients)
{
"mcpServers": {
"parabolic": {
"command": "npx",
"args": ["-y", "@parabolicfamily/mcp"],
"env": {
"PARABOLIC_CHAIN_ID": "5042002"
}
}
}
}Hosting over HTTP later
createServer() (the package's main export) builds the McpServer without a transport, so the same tools can be served over Streamable HTTP:
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { createServer } from "@parabolicfamily/mcp";
const server = createServer(); // reads PARABOLIC_* from process.env
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
await server.connect(transport);
// then hand transport.handleRequest(req, res, body) to your HTTP frameworkcreateServer({ config, env, rpc, fetch }) also accepts overrides, which is how the tests inject an in-memory RPC and a fake subgraph.
Tools
Arguments are strict: a key a tool does not know fails with Unrecognized key instead of being dropped (a top-level referral on build_buy_tx would otherwise build a plain buy; it belongs in memo: { referral }). Amounts go in as whole units ("25" or 25 = 25 USDC; tokens likewise) and come back as { amount, raw } pairs (whole units and raw 18-decimal, or 6-decimal for EURC, integers). Addresses are checksummed. Every tool returns JSON text plus structuredContent; errors come back as isError results with a plain message.
| Tool | Purpose |
|---|---|
| parabolic.list_coins | { status?: "climbing" \| "graduated", sort?: "trending" \| "new" \| "near_graduation" \| "market_cap", limit?, after?, pair?: "USDC" \| "EURC" \| "Agents" }. Pages by cursor: pass an earlier answer's next as after (or "" to start at the newest coin); next is null on the last page. Subgraph when configured, otherwise Parabolic's public read API; a TokenLaunched log scan only when both are unavailable. pair is the quote asset, except "Agents", which means the coin's creator holds an ERC-8004 identity: that is read from Arc's registry (one balanceOf per creator, over the top 100 of the sort) whatever the listing source is. Without a registry for the chain the result sets pairFilterApplied: false and the source line says the filter did not run. |
| parabolic.get_coin | { address } (token or curve). Name, ticker, creator, curve, status/phase, raised/threshold/progress, price, market cap, holders, pool id, fee terms and the coin's own split (creator / protocol / buyback as the curve snapshotted them at launch, the buyback leg only while the creator's buybackEnabled switch is on), snipe-tax window and currentSnipeTaxBps(). |
| parabolic.quote_buy | { address, quoteIn, buyer?, slippageBps? }. Exact curve math on live reserves: fee, creator tax and snipe tax legs, spot vs effective price, price impact, whether the buy graduates the coin, suggested minTokensOut. buyer checks the snipe-tax exemption. |
| parabolic.quote_sell | { address, tokensIn, slippageBps? }. Gross, fee, creator tax, effective price, price impact, suggested minQuoteOut. |
| parabolic.build_buy_tx | { address, quoteIn, minTokensOut?, recipient, buyer?, slippageBps?, memo? } → unsigned curve.buy(...) (value = quote on native-USDC curves; an approval step for EURC pairs). memo: { referral, note? } returns the memo-routed variant instead (see below). |
| parabolic.build_sell_tx | { address, tokensIn, minQuoteOut?, recipient, slippageBps? } → unsigned ERC-20 approval + curve.sell(...). |
| parabolic.build_launch_tx | { name, ticker, image?, description?, socials?, pair?, devBuy?, creatorTaxBps?, creator, buybackEnabled? } (creatorTaxBps 0 to 500, the factories' maxCreatorTaxBps()). The TokenParams are built exactly like the web Create form (economics pinned with previewLaunchEconomics, random salt). With devBuy and PARABOLIC_MEMO_ROUTER set: one unsigned ParabolicMemoRouter.launchAndBuy (value = launch fee + dev buy, creatorFeeRecipient zero, minTokensOut from the curve math on the launch config; launchAndBuyWithToken plus an approval for EURC). Otherwise: unsigned factory.launchToken(...) with the launch fee as value and, for a devBuy, the follow-up buy calldata to send to the curve from the TokenLaunched event. |
| parabolic.agent_status | { address }. Whether the wallet holds an ERC-8004 agent identity on Arc's IdentityRegistry (balanceOf), how many it holds, and the registry address and chain. On a chain where Arc has published no registry the answer is that fact, with registered and identities null. |
| parabolic.build_register_agent_tx | { from, metadataURI? } → unsigned IdentityRegistry.register(metadataURI) (no value). The registry mints the ERC-721 identity to the signer, so from is the wallet that sends it, and returns the agent id; read it from the Transfer log in the receipt. metadataURI is a pointer to the agent's metadata stored as tokenURI and may be empty. Warns when the wallet already holds an identity. |
| parabolic.protocol_stats | Subgraph totals (launches, graduations, trades, volume, fees, daily series) plus the factory's live launch fee, curve preset, snipe-tax terms and contract addresses. |
| parabolic.check_ticker | { ticker }. Whether a Parabolic coin already carries the ticker on any chain the site serves, and whether <ticker>.parabolic.family is free, read from the site's own route (/api/v1/studio/ticker on PARABOLIC_API_URL's site). Advice, not a gate: nothing on chain enforces a unique symbol, so free: false lists what exists (taken[], each with a ref for get_coin) and does not stop a launch. The hostname is the one exclusive thing and belongs to the oldest coin carrying the ticker (hostFree). A name on the site's reserved list comes back as reserved and is not a coin. The ticker is normalised the way the site does it (A-Z and 0-9, case and punctuation ignored, 2 to 10 characters); one outside that is refused before the site is asked. Call it before build_launch_tx. |
| parabolic.referral_status | { account }. One wallet's referral payouts on this server's chain, read from the site (GET /api/v1/referrals/{account}): per asset, what the indexer has credited, what the latest weekly root publishes, what the referral distributor has paid and what is claimable now, with the claim(asset, account, cumulative, proof) arguments when there is a leaf. Read-only; figures are never summed across assets. On a chain with no distributor recorded, referrals are paid by hand and the answer says so. |
| parabolic.list_venue_coins | { venue: "pons" \| "solonpad" \| "aka", status?, sort?, limit? }. Coins made on another launchpad (pons on Robinhood Chain; SolonPad and aka.fun on Arc), read from that launchpad's subgraph when PARABOLIC_SUBGRAPH_URL_<VENUE>_<CHAIN> is set and otherwise from the site's own index of it, with the figures list_coins returns plus venue, the site's ref and whether they can be routed here (routedHere). They live on that launchpad's contracts, not Parabolic's. aka is known and listed, and the four routed tools refuse it by name: the router is proved on aka.fun's pools, but this server does not build that trade. |
| parabolic.venue_history | { part: "chart" \| "holders" \| "claimable" \| "position", coin?, wallet?, tf?, limit? }. Another launchpad's coin as the Parabolic site reads it from the chain's logs: its candles from every fill read and its newest fills, its holders folded from its transfers since launch, its fee recipient's balance on that launchpad's own escrow (claimed there), or a wallet's positions across the launchpads the site indexes itself. Every answer says how far back it reaches. Read from the site (PARABOLIC_API_URL), never from a chain. |
| parabolic.quote_routed_buy | { venue, address, quoteIn, from?, slippageBps? }. Tokens received for quoteIn of the coin's own quote asset, bought through ParabolicAggregatorRouter on the launchpad's curve (the router's quote view) or its graduated v4 pool (the chain's V4Quoter), read now, with the launchpad's fee and Parabolic's routed fee (the router's defaultFeeBps) both shown. |
| parabolic.quote_routed_sell | { venue, address, tokensIn, from?, slippageBps? }. Money received, after Parabolic's routed fee, for tokensIn sold through the router, read now. |
| parabolic.build_routed_buy_tx | { venue, address, quoteIn, from, slippageBps?, maxSnipeTaxBps? } → unsigned ParabolicAggregatorRouter.buy(trade, noVoucher, "0x", noPermit), encoded as the site encodes it: minOut from a fresh quote less slippage, recipient = from, a five-minute deadline; an ETH-quoted coin sends quoteIn as value, a USDG-quoted one returns an exact-amount approval of the router first. Inside a launch window the build is refused and names the tax unless maxSnipeTaxBps accepts it. |
| parabolic.build_routed_sell_tx | { venue, address, tokensIn, from, slippageBps? } → unsigned exact-amount approval of the router plus ParabolicAggregatorRouter.sell(...); minOut is the money after Parabolic's fee. The four routed tools refuse, by name, until the chain's record carries the router (aggregator), when the router has the launchpad off, when the coin is not that launchpad's, and when any read fails. |
| parabolic.docs | The adopted parameters, curve mechanics, confirmed Arc facts and this server's configuration, as text. |
Every tool above also takes an optional chain (see "What changed in 0.1.7"), and every coin argument
takes a reference: 0x… for a coin on this server's chain, rhc:0x… for one elsewhere. A wallet argument
(recipient, buyer, creator, from, agent_status's address) stays a plain address: a wallet is
the same person on every EVM chain. check_ticker accepts chain like the others and its verdict still
covers every chain the site serves, because a ticker taken elsewhere is a collision the moment a link is shared.
Resources: parabolic://docs/parameters (same text as parabolic.docs) and parabolic://coins/{address} (same JSON as parabolic.get_coin; the address may be a reference).
Examples
Quote a $50 buy on a freshly opened curve (result abbreviated; the numbers are what the ported math returns for the adopted parameters):
{ "name": "parabolic.quote_buy", "arguments": { "address": "0x1000…0001", "quoteIn": "50" } }{
"side": "buy", "pair": "USDC",
"quoteIn": { "amount": "50", "raw": "50000000000000000000" },
"tokensOut": { "amount": "9802950.787206654124170709", "raw": "9802950787206654124170709" },
"minTokensOut": { "amount": "9704921.279334587582929001", "raw": "9704921279334587582929001", "slippageBps": 100 },
"fees": { "totalBps": 100, "fee": { "bps": 100, "amount": "0.5" }, "creatorTax": { "bps": 0, "amount": "0" }, "snipeTax": { "bps": 0, "amount": "0", "windowOpen": false, "buyerExempt": false } },
"spotPrice": 0.000005, "effectivePrice": 0.0000051005, "priceImpactPct": 2.0101, "graduatesCoin": false
}Build the same buy for a wallet to sign:
{ "name": "parabolic.build_buy_tx", "arguments": { "address": "0x1000…0001", "quoteIn": "50", "recipient": "0xYourWallet" } }{
"kind": "buy",
"tx": { "to": "0x2000…0002", "data": "0x…", "value": "0x2b5e3af16b1880000", "valueWei": "50000000000000000000", "chainId": 5042002 },
"quote": { "expectedTokensOut": { "…": "…" }, "minTokensOut": { "…": "…" }, "graduatesCoin": false },
"gas": { "note": "estimate then multiply by 1.25 …" }
}Launch a coin with a $200 dev buy:
{ "name": "parabolic.build_launch_tx", "arguments": { "name": "Orange Pill", "ticker": "PILL", "image": "ipfs://…", "description": "a frog", "socials": { "twitter": "@robin" }, "creatorTaxBps": 250, "devBuy": "200", "creator": "0xYourWallet" } }With PARABOLIC_MEMO_ROUTER set the result is kind: "launch_and_buy": one tx to the router (value = the factory's launchFee(), 0 on both chains today, + $200), the encoded params (creatorFeeRecipient zero, as the router requires), the curve terms (opening and fully diluted graduation market caps, reserved / pool-seed / locked token shares, snipe-tax window) and devBuy (expected and minimum tokens, snipe-tax exempt). Without the router it is kind: "launch": tx to the factory (value = the launch fee) and devBuy with the calldata for the second, snipe-tax-exempt transaction to the new curve. There is no exemption list: only the creator's own address is exempt from the snipe tax.
Check whether a wallet is a registered agent, then register it:
{ "name": "parabolic.agent_status", "arguments": { "address": "0xYourWallet" } }{
"address": "0xYourWallet",
"chain": { "id": 5042002, "name": "Arc Testnet" },
"registry": { "address": "0x8004A818BFB912233c491871b3d84c89A494BD9e", "contract": "ERC-8004 IdentityRegistry", "operator": "Arc" },
"registered": false, "identities": 0
}{ "name": "parabolic.build_register_agent_tx", "arguments": { "from": "0xYourWallet", "metadataURI": "ipfs://…/agent-card.json" } }The result is kind: "register_agent": one unsigned tx to the registry carrying no value, the
metadataURI as encoded, and currentIdentities for the wallet. Send it from from, because the
registry mints to msg.sender. Once it lands, parabolic.list_coins with pair: "Agents" keeps the
coins launched from that wallet, and the site tags them [ Agent ].
Check a ticker before launching under it:
{ "name": "parabolic.check_ticker", "arguments": { "ticker": "$para" } }{
"ticker": "PARA", "asked": "$para",
"chain": { "id": 5042, "key": "arc", "name": "Arc" },
"scope": "every chain the Parabolic site serves, not only this server's chain",
"free": false,
"taken": [{ "chain": { "id": 5042, "key": "arc", "name": "Arc" }, "name": "Parabolic", "address": "0x552F…4073", "ref": "0x552F…4073", "page": "https://www.parabolic.family/coin/0x552F…4073" }],
"reserved": null,
"host": "para.parabolic.family", "hostFree": false,
"message": "$PARA already trades on Arc as \"Parabolic\". Nothing on chain stops a second coin using it; para.parabolic.family belongs to the oldest coin carrying the ticker.",
"notes": ["Advice, not a gate: …", "…"]
}free: true comes back with taken: [] and hostFree: true, and a name on the site's reserved list as
reserved: { name }. Nothing here is a lock: the verdict is what the site's board holds at the moment of
asking, and it lags the site's indexer by however far that is behind.
Notes on the mechanics
- Curve math is a port of
ParabolicBondingCurve/ParabolicBondingCurveMath(and ofweb/lib/curve.ts): fee legs are taken off the buy input separately, the constant product is priced ongetReserves(), and a buy that would take more thansellableTokens()is clamped to the last sellable tokens, charged the grossed-up price and refunded the rest; that buy graduates the coin, so give it extra gas. Sells take the fee off the gross quote output and close once the curve is ready to graduate. minTokensOuton the curve is a price bound (spent × minTokensOut ≤ received × tokensOut), so a clamped fill still honours the caller's terms.- The snipe tax decays per second along
remaining² / window²; a quote in the launch window overstates the tax a later block charges. Passbuyerto have the exemption checked. - At graduation the curve still holds the reserved 38.46% of supply: ≈ 23.7% seeds the Uniswap v4 full-range position with the $8,000 raised at the same terminal price, and ≈ 14.8% is permanently locked. Fully diluted graduation market cap: $33,800.
- Fair launch:
ParabolicMemoRouter.launchAndBuy/launchAndBuyWithTokenput the creator's opening buy inside the launch transaction (snipe-tax exempt, before anyone else can trade). Called directly they work from any wallet; the router forwards no exemption list and rejects acreatorFeeRecipientother than zero or the signer. - A memo-routed buy (
memo: { referral }) wrapsParabolicMemoRouter.buyinside Arc'sMemo.memo(...)so the referral code is attributed on-chain. It is EOA-only (the Memo contract's caller must betx.origin) and forwards no value, so the router pulls whole 6-decimal USDC units through the ERC-20 view (0x3600…0000) and needs a one-time approval; smart-account wallets should use the direct buy. Memo-wrapped launches (referral on a launch) are not built here. - Agent identity is ERC-8004 on Arc's own
IdentityRegistry(an ERC-721 namedAgentIdentity, symbolAGENT):register(metadataURI)mints one to the caller,balanceOfanswers whether a wallet holds any. The registry is not ERC-721 Enumerable, so there is no way to list a wallet's agent ids without scanningTransferlogs, which public Arc RPCs cap and rate-limit; this server does not try. Arc can upgrade the registry behind its address (ERC-1967 proxy). Holding an identity is not an endorsement: registration is open to anyone. pair: "Agents"is a property of the creator, not of the coin, so it is read at call time: onebalanceOfper distinct creator over the top 100 coins of the sort, deduplicated and batched. A creator the registry will not answer for is left out rather than counted either way, and thesourceline reports how many. When the registry answers for nobody the list comes back empty and says so, because an unreachable registry and a board with no agent launches are not the same answer.- The factory has no enumeration function (only
getLaunchedToken(address)), so listing comes from an indexer:PARABOLIC_SUBGRAPH_URLwhen set, otherwise Parabolic's public read API. Only if both are unavailable does it scanTokenLaunchedlogs, which public Arc RPCs rate-limit hard.
Development
src/
index.ts stdio entry point (bin: parabolic-mcp)
server.ts createServer(): the 19 tools + resources on @modelcontextprotocol/sdk McpServer
parabolic.ts the service: reads (RPC + subgraph + API) and unsigned tx builders
curve.ts ported curve math
tx.ts viem encodeFunctionData builders (buy, sell, approve, launchToken, memo buy)
agents.ts ERC-8004 identity registry: balanceOf / ownerOf / tokenURI reads, register builder
chain.ts viem RPC wrapper (batched HTTP) behind a small Rpc interface
chains.ts the chain registry and chain-qualified references (`rhc:0x…`)
deployed.ts the shipped deployment records (abi/deployments.json): addresses, start blocks, routers
subgraph.ts GraphQL client and Coin/Protocol shapes
restapi.ts Parabolic's public read API client (listings when no subgraph is set)
coins.ts coin summaries, sorting
quote-unit.ts the money a coin is counted in, so no figure reads as dollars when it is not
format.ts JSON with bigints as decimal strings, short addresses
ticker.ts check_ticker's rule: the site's normalisation, its verdict shape, the sentence
referrals.ts referral_status, read from the site's /api/v1/referrals route
venues.ts the other launchpads: factories, hooks, proofs, venue subgraph variables
routed.ts list_venue_coins and the four routed tools through ParabolicAggregatorRouter
venue-history.ts venue_history, read from the site's /api/v1/coins views
config.ts PARABOLIC_* environment
abi.ts loads abi/*.json
docs.ts parameters + Arc facts text
test/ vitest (curve parity, calldata decode, tools over an in-memory MCP transport)
scripts/ sync-abis.mjs, smoke.mjsScripts: npm run build, npm test, npm start (stdio), npm run smoke, npm run sync-abis, npm run typecheck.
Working on the server itself
The source lives in a private repository; the published package ships src/ alongside dist/ so the
code is readable from node_modules. If you have the repository checked out:
npm install
npm run build # -> dist/
npm test # vitest: curve math, tx builders, tools against a mocked subgraph and RPC
npm run smoke # starts dist/index.js over stdio, initialize + tools/list
npm run sync-abis # re-copy abi/*.json from ../contracts/out after a forge buildLinks
- Parabolic: https://www.parabolic.family
- Protocol parameters, deployed addresses and the public read API: https://www.parabolic.family/docs
- Questions and bug reports: [email protected]
