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

@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

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 stdio

The 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_coins reads that launchpad's subgraph when PARABOLIC_SUBGRAPH_URL_PONS_RHC (or ..._SOLONPAD_ARC) is set.
  • parabolic.quote_routed_buy / quote_routed_sell and build_routed_buy_tx / build_routed_sell_tx encode ParabolicAggregatorRouter.buy / sell byte 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 (its defaultFeeBps, 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=4663 and 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 answered chain: "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_coins reaches 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; ParabolicMemoRouter is Arc's and the two share no function selector, so this package encodes no routed call on chain 4663. build_buy_tx goes straight to the curve and build_launch_tx to 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.docs and the buy payload both say so, and passing memo is refused by name rather than by asking for a variable that must stay unset.
  • parabolic.docs states 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: address accepts 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 } on get_coin, list_coins, both quotes, all three builders and protocol_stats, plus ref on get_coin and on each listed coin. Nothing was renamed, nothing changed type: address is the address, tx.chainId is 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/mcp

That 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/mcp

Generic 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 framework

createServer({ 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 of web/lib/curve.ts): fee legs are taken off the buy input separately, the constant product is priced on getReserves(), and a buy that would take more than sellableTokens() 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.
  • minTokensOut on 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. Pass buyer to 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 / launchAndBuyWithToken put 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 a creatorFeeRecipient other than zero or the signer.
  • A memo-routed buy (memo: { referral }) wraps ParabolicMemoRouter.buy inside Arc's Memo.memo(...) so the referral code is attributed on-chain. It is EOA-only (the Memo contract's caller must be tx.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 named AgentIdentity, symbol AGENT): register(metadataURI) mints one to the caller, balanceOf answers 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 scanning Transfer logs, 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: one balanceOf per 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 the source line 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_URL when set, otherwise Parabolic's public read API. Only if both are unavailable does it scan TokenLaunched logs, 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.mjs

Scripts: 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 build

Links