solana-nft-mcp 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 p1xel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,237 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/banner.png" alt="solana-nft-mcp" width="100%" />
4
+
5
+ # solana-nft-mcp
6
+
7
+ **The NFT APIs I tried return an empty ownership history for a Metaplex Core asset, and an AI reading that empty answer tells you the card has never traded.** solana-nft-mcp reads the chain itself: who owned it, who can freeze it, what sold and for how much, and where the deals are. Read-only, no sign-up, nothing collected, runs on your machine.
8
+
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6)](https://github.com/p1xelapp/solana-nft-mcp/blob/main/tsconfig.json)
10
+ [![MCP](https://img.shields.io/badge/MCP-official%20SDK-8b5cf6)](https://modelcontextprotocol.io)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-22c55e)](https://github.com/p1xelapp/solana-nft-mcp/blob/main/LICENSE)
12
+ [![Sign-up](https://img.shields.io/badge/sign--up-none-f59e0b)](#what-it-reads)
13
+
14
+ </div>
15
+
16
+ ---
17
+
18
+ ## Why
19
+
20
+ Ask an assistant about a Solana card today and it answers from memory. It will say a card
21
+ "never traded", because the mainstream NFT APIs return an empty history for Metaplex Core
22
+ assets while the transfers sit on chain the whole time. It will compare two floors quoted in
23
+ two currencies as if they were one.
24
+
25
+ solana-nft-mcp hands the same assistant live, labelled data instead: the chain for supply,
26
+ ownership, provenance and custody rules, Magic Eden without a key, and OpenSea through a free
27
+ key the server issues itself. Each number comes back with its marketplace, its currency, its
28
+ read time, and what the source could not see.
29
+
30
+ <img src="assets/architecture.svg" alt="Your AI app talks to solana-nft-mcp over stdio; the server reads the Solana chain, the asset index, Magic Eden and OpenSea" width="100%" />
31
+
32
+ The server runs on your machine and your AI app starts it. There is no hosted service and no
33
+ account between you and the data. The picture is generated from the running server, so the
34
+ counts cannot drift from the code: `npm test` fails if they do.
35
+
36
+ ## Install
37
+
38
+ Node 22 or newer. Two ways to run it.
39
+
40
+ **From npm, no clone.** Wherever a client asks for a command, give it `npx` with the arguments
41
+ `-y solana-nft-mcp`. The first start downloads the package; later starts reuse it.
42
+
43
+ ```bash
44
+ claude mcp add solana-nft -- npx -y solana-nft-mcp
45
+ ```
46
+
47
+ **From source.** Build once, then point the client at `dist/index.js`:
48
+
49
+ ```bash
50
+ git clone https://github.com/p1xelapp/solana-nft-mcp.git
51
+ cd solana-nft-mcp && npm install && npm run build
52
+ ```
53
+
54
+ **Claude Code**
55
+
56
+ ```bash
57
+ claude mcp add solana-nft -- node /absolute/path/to/solana-nft-mcp/dist/index.js
58
+ ```
59
+
60
+ **Claude Desktop.** Settings -> Developer -> Edit Config, add the block below, then quit the
61
+ app fully and reopen it. Or install the `.mcpb` bundle from the latest release by dragging it
62
+ onto Settings -> Extensions.
63
+
64
+ ```json
65
+ {
66
+ "mcpServers": {
67
+ "solana-nft": {
68
+ "command": "node",
69
+ "args": ["/absolute/path/to/solana-nft-mcp/dist/index.js"]
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ **Other clients.** Tested: Claude Desktop, Claude Code, Codex CLI 0.153.4
76
+ (`codex exec -c 'mcp_servers.solana-nft.command="node"' -c 'mcp_servers.solana-nft.args=["/absolute/path/to/dist/index.js"]'`).
77
+ Cursor, Windsurf, Gemini CLI, Zed, Cline and VS Code take the same `command` / `args` pair in
78
+ their own config; the server is plain stdio with no client-specific code, but those have not
79
+ been tested here. ChatGPT on the web and Grok cannot run a local process.
80
+
81
+ **Did it work?** Your app lists the tools near the message box (Claude Code: `/mcp`). You should
82
+ see 21, starting with `identify`. If none: the path must be absolute and end in `dist/index.js`,
83
+ `npm run build` must have run, and the app must be fully quit and reopened.
84
+
85
+ **OpenSea** is on without any setup. The first question that needs it makes the server ask
86
+ OpenSea for a free agent key, stored at `~/.solana-nft-mcp/opensea-key.json` and renewed before it
87
+ expires. The key is never logged or printed into an answer. A collection's OpenSea slug is found
88
+ from its on-chain address, or by name and then proved against that address; pass `openseaSlug`
89
+ to override. Options, set in the config's `env` block (clients launch the server with a clean
90
+ environment):
91
+
92
+ - `OPENSEA_API_KEY` - your own key, overrides the self-issued one.
93
+ - `SOLANA_NFT_MCP_NO_AUTO_KEYS=1` - never request a key; OpenSea is off unless you set one.
94
+ - `SOLANA_RPC_URL`, `DAS_RPC_URL` - a private endpoint, neither required. A key in the URL is
95
+ registered and redacted from every answer (details in [docs/FAQ.md](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/FAQ.md)).
96
+ - `SOLANA_NFT_MCP_NO_UPDATE_CHECK=1` - skip the one startup request to npm for a newer version.
97
+
98
+ ## Ask it anything
99
+
100
+ Nobody types a tool name. These are asked in plain words and the assistant picks the calls.
101
+
102
+ - Who has owned this card since it was minted, with dates and the marketplaces involved?
103
+ - Is it true this card has never traded?
104
+ - Can the project still freeze, move or burn what is in my wallet?
105
+ - What is in wallet 7HHs3..., and does that wallet flip or hold?
106
+ - What is the cheapest Legendary listing in that DC collection right now?
107
+ - Any Superman or Batman DC comic #1 or #100 for sale, and are any close to floor?
108
+ - What did Shohei Ohtani cards sell for this week, and how many changed hands?
109
+ - Are the Magic Eden and OpenSea floors for this collection even comparable?
110
+ - What would it take to build a sales bot on this, and where would it fail quietly?
111
+
112
+ A collection name, a player name, a card number or a trait is enough to start. Names resolve
113
+ against a bundled snapshot of the Magic Eden directory, against OpenSea's Solana index, and
114
+ against the marketplace itself, and a fuzzy match is offered as a candidate with the mismatch
115
+ stated, never presented as the answer. Long answers are sized to arrive whole: a client that
116
+ caps a tool result gets fewer per-row details before it gets fewer rows, and the answer says
117
+ what it left out.
118
+
119
+ ## What it reads
120
+
121
+ | Source | Answers | Key |
122
+ |---|---|---|
123
+ | Solana RPC (three public endpoints, rotated) | supply, current owner from decoded Core account bytes, transfer history, wallet age | none |
124
+ | Asset index (DAS) on the public RPC | a second, independent opinion on ownership and wallet contents | none |
125
+ | Magic Eden v2 | floors, listings, sales, activity, top traders, trending | none |
126
+ | OpenSea v2 | second-marketplace floors, sales, supply, royalty, wallet transfers | self-issued |
127
+
128
+ No account, no sign-in, no telemetry, no log of your questions, and no signing code anywhere in
129
+ the repository; every tool declares `readOnlyHint`. What leaves the machine: the public address,
130
+ symbol or name you asked about, sent to the source that can answer it; one startup request to
131
+ npm for the latest version number; one request to OpenSea for a free key, the first time a
132
+ question needs it. One file is written, the key file above, at permissions 600. Nothing else
133
+ touches disk. To remove everything: uninstall or delete the clone, then delete
134
+ `~/.solana-nft-mcp/`.
135
+
136
+ ## Tools
137
+
138
+ 21 tools. Names are frozen: agents reference them in prompts, and a rename breaks integrations
139
+ without raising an error.
140
+
141
+ | Tool | Back |
142
+ |---|---|
143
+ | `identify` | what an address or name is, where it trades, which tool to call next |
144
+ | `verify_claim` | confirmed, contradicted or unverifiable, with the numbers seen and how to re-check |
145
+ | `get_asset_trust` | Core plugins decoded from bytes: delegates, frozen state, enforced vs advisory royalties, mutable metadata, editions |
146
+ | `get_integration_recipe` | endpoints, pacing, running cost, skeleton and the silent failure modes for a given build |
147
+ | `search_collections` | name lookup across the Magic Eden directory and the OpenSea Solana index, saying which layers were read |
148
+ | `get_collection_stats` | chain supply, floors per marketplace, and a reconciliation that refuses to rank SOL against USDC |
149
+ | `get_collection_holders` | census of a Core collection from the chain's asset index, each holder with a role (issuer, marketplace escrow, wallet), capped and saying so |
150
+ | `get_floor_prices` | current floor and listed count for up to 10 collections, Magic Eden only |
151
+ | `get_recent_sales` | latest completed fills with buyer, seller, price, mint and signature |
152
+ | `get_asset` | three readers for one item: the marketplace, a byte-level decode, and the chain's asset index, with owner agreement reported |
153
+ | `get_asset_provenance` | bounded ownership history of a Core asset, dated, marketplaces named, every unread hole marked in place. `historyComplete` says every transaction was read; `mintObserved` says the mint itself was decoded. They are different claims |
154
+ | `get_wallet_holdings` | holdings from two independent readers, with the gap between them named |
155
+ | `get_wallet_profile` | holdings by collection, share of wallet and of supply, listed and compressed counts, floor ceiling with assumptions, wallet age |
156
+ | `get_wallet_activity` | buys and sells, net flow, marketplace split, every flip with hold time and P&L, a behaviour label with its reason |
157
+ | `get_collection_sales` | sales over a window: count, volume, median, buyers, sellers, per-day series, per-name breakdown, how far back the feed was read |
158
+ | `find_in_group` | one edition number hunted across a whole family of collections, each match against its own floor |
159
+ | `find_listings` | cheapest-first listings, trait filters, a name filter that says what it matched, a lowest-serials mode, each ask against its trait floor on both marketplaces |
160
+ | `get_top_traders` | the largest wallets in a collection by Magic Eden volume |
161
+ | `get_trending` | Magic Eden's trending list, with an explicit note when the marketplace publishes nothing |
162
+ | `explain_mechanics` | escrow, freezing, delegates, royalties, wash trades and migrations, per standard and marketplace, each entry citing its source |
163
+ | `get_source_status` | every source pinged live: tier, fallback, what it cannot see, credential state |
164
+
165
+ Three prompts: `getting_started`, `collection_report`, `wallet_report`. No MCP resources, on
166
+ purpose: everything they would carry is reachable by a tool the assistant calls itself.
167
+
168
+ ## Trust and limits
169
+
170
+ - Buying, selling, listing and signing are absent. No code exists for them.
171
+ - Provenance and trust decoding cover Metaplex Core only. Legacy SPL and compressed NFTs are
172
+ reported as named gaps, never as empty lists. Holdings and activity cover both.
173
+ - Magic Eden and OpenSea only. Tensor has no self-serve keys; Rarible's Solana coverage is
174
+ unconfirmed. Both are catalogued with the condition that would add them.
175
+ - Every money figure names its currency and the API it came from, on the summary and on every
176
+ priced row, and counts keep their coverage flags beside them (`truncated`, `stale`,
177
+ `historyComplete`). A program should refuse to act on a row whose flag says the read was partial.
178
+ - Two error surfaces. Input that fails a tool's schema is refused before the handler runs:
179
+ `isError: true`, no `structuredContent`. Every failure inside a handler carries
180
+ `structuredContent.error`, a stable category (`not-found`, `wrong-kind`, `escrow`,
181
+ `source-unsupported`, `bad-input`, `upstream-unavailable`, `upstream-rate-limit`, `error`).
182
+ - No valuations and no currency conversion. Solana only.
183
+
184
+ Full detail: [docs/TRUST-AND-LIMITS.md](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/TRUST-AND-LIMITS.md).
185
+
186
+ ## Security
187
+
188
+ Minting is permissionless, so a collection name is attacker-controlled text. Every name and every
189
+ field from a chain or a marketplace is checked against the shape it claims to have before a model
190
+ sees it, and every credential this process has sent is redacted from every answer. Covered by the
191
+ offline suite. Reporting: [SECURITY.md](https://github.com/p1xelapp/solana-nft-mcp/blob/main/SECURITY.md).
192
+
193
+ ## Development
194
+
195
+ ```bash
196
+ npm test # offline: every tool, prompt, validation, wallet and market logic,
197
+ # the OpenSea contract, the prompt-injection defence. No network.
198
+ npm run test:live # live: floors, a real provenance trace, source status, name lookup
199
+ npm run snapshot # refresh the bundled Magic Eden collection directory
200
+ npm run inspect # open the MCP Inspector against a local build
201
+ ```
202
+
203
+ CI runs a full-history secrets scan on every push to every branch; the offline suite, lint, the
204
+ tarball check and `npm audit` on `main`, pull requests and release tags; and the live check weekly.
205
+
206
+ ## Docs
207
+
208
+ - [Under the hood: why it exists, how it works, what was tested](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/DEEP-DIVE.md)
209
+ - [Every data source, tiered](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/SOURCES.md)
210
+ - [Questions people ask, and which ones it can answer](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/QUESTIONS.md)
211
+ - [Fifteen ways people use it](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/HOW-PEOPLE-USE-IT.md) and [things people build with it](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/BUILD-IDEAS.md)
212
+ - [What can change under this server](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/MAINTENANCE.md), [FAQ](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/FAQ.md), [Contributing](https://github.com/p1xelapp/solana-nft-mcp/blob/main/CONTRIBUTING.md)
213
+
214
+ ## About
215
+
216
+ Built and maintained by P1xel ([p1xel.app](https://p1xel.app),
217
+ [@P1xelCollector](https://x.com/P1xelCollector)), a long-time Solana collector. The story of why it
218
+ exists is in [docs/DEEP-DIVE.md](https://github.com/p1xelapp/solana-nft-mcp/blob/main/docs/DEEP-DIVE.md).
219
+
220
+ ### Running on the same decoding
221
+
222
+ <a href="https://candyscan.p1xel.app"><img src="assets/using/candyscan.png" width="86" alt="CandyScan" /></a>
223
+
224
+ **[CandyScan](https://candyscan.p1xel.app)** tracks the Candy Digital collections on Solana:
225
+ supply, holders, migrations and sales, kept current. It is where the Core decoding was written
226
+ first, and this repository is the keyless half of that pipeline. Each project shaped the other.
227
+
228
+ Shipped something on top of solana-nft-mcp? Open an issue and it goes here.
229
+
230
+ **Independent project, not affiliated with the Solana Foundation.** SOLANA and SOL are trademarks
231
+ of the Solana Foundation. They appear in this project's name and documentation for one reason
232
+ only: to say which chain the server reads. Nothing here is endorsed, sponsored or reviewed by the
233
+ Solana Foundation, and no affiliation is claimed or implied.
234
+
235
+ ## License
236
+
237
+ MIT. See [LICENSE](https://github.com/p1xelapp/solana-nft-mcp/blob/main/LICENSE).