MCP server
pump.fun runs a hosted Model Context Protocol server at https://mcp.pump.fun/mcp (Streamable HTTP). It exposes the same read-only data as the API as 28 tools, authenticated with the same pf_live_ key. Each tool call is exactly one API request and counts against your key’s limits like any other call.
The server is stateless: every request is a POST /mcp with a JSON-RPC body and a JSON response. There are no sessions and no server-sent event streams; GET /mcp answers 405.
Connect
Section titled “Connect”Pass your key as a bearer header. The MCP server only accepts Authorization: Bearer pf_live_...: the x-api-key alias is refused (400), and so is any request that carries a browser Origin header (403), including browser-hosted MCP inspectors.
claude mcp add --transport http pump https://mcp.pump.fun/mcp \ --header "Authorization: Bearer pf_live_..."Add to claude_desktop_config.json (Settings → Developer → Edit Config):
{ "mcpServers": { "pump": { "url": "https://mcp.pump.fun/mcp", "headers": { "Authorization": "Bearer pf_live_..." } } }}Add to .cursor/mcp.json in your project (or the global one):
{ "mcpServers": { "pump": { "url": "https://mcp.pump.fun/mcp", "headers": { "Authorization": "Bearer pf_live_..." } } }}Clients that cannot speak HTTP directly can bridge through mcp-remote:
{ "mcpServers": { "pump": { "command": "npx", "args": [ "-y", "mcp-remote", "https://mcp.pump.fun/mcp", "--header", "Authorization: Bearer ${PUMP_API_KEY}" ] } }}All tools are read-only (readOnlyHint: true) and map to one API route each. Page sizes are small by default and differ per tool (for example 5 rows for user search, 10 for callout lists, 20 for followers, 25 for trades); each tool’s input schema states its default and maximum, and a larger value is clamped to the maximum rather than rejected.
| Tool | Scope | API route | Returns |
|---|---|---|---|
get_user_profile | profiles.read | GET /users/{id} | Public profile of one pump.fun account by wallet address, pump.fun user id or username. |
search_users | profiles.read | GET /users/search-v2 | Search pump.fun accounts by username or wallet fragment. |
lookup_wallets | profiles.read | POST /users/batch | Resolve up to 50 wallet addresses to pump.fun profile rows in one call (a read served over POST). |
resolve_identifiers | profiles.read | GET /search/resolve | Classify 1 to 5 identifiers in one hop. |
get_followers | graph.read | GET /following/v3/followers/{userId} | One page of a user's followers as plain profile rows. |
get_following | graph.read | GET /following/v3/following/{userId} | One page of the accounts a user follows as plain profile rows. |
check_follows | graph.read | GET /following/single/{id} | Whether one account follows another. |
get_group_members | graph.read | GET /groups/{groupId}/members | A page of a squad's (group's) active members, owner first. |
get_callout | content.read | GET /callout/{calloutId} | One callout by id with its author identity, thesis, market-cap-at-callout, current multiple, like/reply/quote counts and author updates. |
list_user_callouts | content.read | GET /callout/list/{userId} | A user's callout history with tail cohorts, newest first by default. |
get_coin_callouts | content.read | GET /callout/coin/{coin} | Top callouts on one coin with author identity. |
get_callout_replies | content.read | GET /callout/{calloutId}/replies | One tree level of replies on a callout, newest first. |
get_callout_quotes | content.read | GET /callout/{calloutId}/quotes | Quote posts of a callout (both reply-shaped and callout-shaped quotes), newest first. |
get_callout_tailers | content.read | GET /callout/{calloutId}/tailers | The wallets that tailed a callout, oldest tail first, with their profile and position outcome. |
list_user_replies | content.read | GET /callout/replies/list/{userId} | A user's callout replies and quotes with thread context, newest first. |
get_recent_callouts | content.read | GET /home-feed/new | The global "new callouts" feed: every live-position-backed callout across all users, newest first, no ranking. |
get_posts | content.read | GET /posts | Posts by id (1 to 25) with one-level embeds. |
get_post_replies | content.read | GET /posts/{postId}/replies | Direct live replies to a post, newest first. |
get_pnl_leaderboard | leaderboards.read | GET /pnl-leaderboard | The trader PnL leaderboard for a period with each entry's top positions. |
get_squad_leaderboard | leaderboards.read | GET /pnl-leaderboard/groups | The squad (group) PnL leaderboard for a period. |
get_top_positions | leaderboards.read | GET /pnl-leaderboard/positions | The best single positions for a period (daily or weekly). |
get_competitions | leaderboards.read | GET /competitions | Every trading competition in three buckets: upcoming, live (with the current top board) and past (the 50 latest, with winners). |
get_creator_payouts_leaderboard | leaderboards.read | GET /payouts/leaderboard | The confirmed creator-payout leaderboard (top 500), all-time or a rolling 1d/1w/1m window, plus the earner count. |
get_user_positions | positions.read | GET /user-positions/{userId} | A user's position (PnL plus callout) in each of up to 50 given mints. |
get_user_trades | positions.read | GET /user-trades/{id} | One page of an account's trades, newest first, with the trader and coin identities behind the rows. |
get_user_portfolio | positions.read | GET /user-portfolio/{userId} | A user's whole-portfolio positions (open, closed or all) with net PnL and a summary. |
get_coin_holder_positions | positions.read | GET /mint-positions/{mint} | The users holding a position in a coin, with their position and callout thesis when present. |
check_address_banned | moderation.read | GET /moderation/ban/address/{address} | Whether a wallet address is banned on pump.fun: banned true/false, or null when unknown. |
The table above is the complete tool list; the other routes of the API are reachable only through the API itself. Not exposed as tools: bulk user listing (GET /users), the username-exists check, follow suggestions, the video feed, the Mayhem top-traders board and the verified-profile, generated-media and badge batch reads. (POST /users/batch is exposed as lookup_wallets, capped at 50 addresses.) Narrower reads such as follower counts, searches within a follow list, likers and reposters, reply chains, competition detail and the portfolio summary have no tool either.
Tool results
Section titled “Tool results”Every successful result has a content[0].text that starts with one fixed line explaining the untrusted wrapper, followed by the JSON, and a structuredContent with data and meta:
meta key |
Contents |
|---|---|
fun.pump/untrustedFields |
Paths of user-generated strings; each is { "untrusted": true, "text": "..." } in place. |
fun.pump/strippedFields |
Viewer-relative fields removed before shaping. |
fun.pump/upstream |
The API’s X-Request-Id, X-RateLimit-*, Retry-After and, on a deprecated route, Sunset / Deprecation. Quote the request id in support requests. |
fun.pump/page |
The page size actually sent, and clampedFrom when you asked for more. |
Tool errors
Section titled “Tool errors”Tool errors (isError: true) carry structuredContent.error, derived from the API’s error envelope. Every upstream failure also carries status (the API’s HTTP status), code (the API’s error code, when it sent one) and requestId.
| Tool error | API code |
|---|---|
invalid_key |
API_KEY_REQUIRED, API_KEY_INVALID |
key_revoked |
API_KEY_REVOKED, API_ORG_SUSPENDED |
key_not_approved |
API_ORG_NOT_APPROVED |
insufficient_scope |
API_SCOPE_FORBIDDEN (carries requiredScope) |
rate_limited |
API_KEY_RATE_LIMITED (carries retryAfterSeconds and rateLimit.limit/remaining/reset/window) |
upstream_unavailable |
any 503 |
upstream_error |
anything else; status: 404 is “no such record”, status: 400 is “the API rejected the input” |
timeout |
the API did not answer within the server’s deadline (no API code) |
disabled |
the tool is switched off on the server (no API code) |
Untrusted content
Section titled “Untrusted content”Callout text, replies, bios, usernames and group names are written by pump.fun users. The MCP server marks these fields as untrusted in every tool result (an explicit untrusted: true wrapper on the text, with the paths listed in meta["fun.pump/untrustedFields"]) so that an agent does not follow instructions hidden in them, and it never turns URLs found in user content into links or instructions. Viewer-relative fields (isFollowing, viewerFollows, mute state) are stripped: the server has no viewer.
Later: OAuth
Section titled “Later: OAuth”The server has an RFC 9728 protected-resource metadata endpoint at /.well-known/oauth-protected-resource so an OAuth 2.1 flow can be added without changing the endpoint. Today the metadata is not advertised and the bearer key is the only credential.