dero-mcp-server 0.4.0 → 0.4.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/data/docs-index.json +5 -5
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +15 -8
- package/dist/http-server.js.map +1 -1
- package/dist/server.js +2 -2
- package/package.json +2 -2
package/data/docs-index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"generated_at": "2026-05-
|
|
3
|
+
"generated_at": "2026-05-31T20:35:13.976Z",
|
|
4
4
|
"page_count": 146,
|
|
5
5
|
"pages": [
|
|
6
6
|
{
|
|
@@ -835,8 +835,8 @@
|
|
|
835
835
|
"Part 6: The Keystone Collapses",
|
|
836
836
|
"Related Pages"
|
|
837
837
|
],
|
|
838
|
-
"plainText": "The 2022 Inflation Claim: Claims vs. Evidence _Derolytics' \"irrefutable proof\" is a string anyone can forge — and even a genuine one describes a transfer the chain would have rejected._ **Scope:** This page tests **one** claim: that DERO minted ~2.2M coins in October 2022 by exploiting a bug in how transfers were validated. Laundering totals, dollar figures, and attribution to individuals all **derive from this single claim** — if it falls, they fall with it. Governance and wallet-holdings allegations are out of scope here. TL;DR Summary | Question | The Evidence | |----------|--------------| | **Did total supply increase by ~2.2M DERO?** | **No.** The exploit-block reward was **0.615 DERO** — normal scheduled emission, not millions. The report never shows a supply jump on chain. Part 4 | | Is negative-transfer wraparound possible on consensus? | **No.** Range proofs bind every transfer to a non-negative range; a negative/out-of-range amount cannot produce a verifying proof. Part 4 | | Is the circulated payload proof cryptographic evidence of a mint? | **No.** It is a user-supplied **display object**; \"Verified\" means its own math is consistent, not that consensus accepted it. Part 3 | | Can explorer **Verified** on inflated proofs be reproduced? | **Yes** on unpatched explorers (MAX_INT64_SAFE bypass). Part 3 | | Does the deanonymization support the ~2.2M? | **No — it refutes it.** The figure is the forgeable proof string, not a deanonymization output; a faithful deanonymization recovers an ordinary transfer of coins already held. Part 5 | | **Bottom line on the keystone?** | **The artifact at the center of every accusation is a display object anyone can forge — and consensus could not have accepted the transfer it depicts.** Part 6 | --- At the center of every inflation accusation is a string. About a hundred characters of base32, prefixed deroproof1..., pasted into an unpatched DERO explorer where it lights up as **Verified ✓** for an amount the explorer renders as 184,467,438,537,095.51434 DERO — roughly eleven million times the entire DERO supply. That string is the foundation of the Derolytics \"DERO Heist\" report and its follow-ups — the source of the **2.2-million-DERO** figure, the cited evidence for every downstream claim of laundering, theft, and attribution. It is also a *payload proof*: a wallet-side display object the protocol gives no third party any way to verify. By design. Ring signatures rely on exactly this ambiguity — if outsiders could verify payload proofs, plausible deniability would die with them. The technique that produced it became possible in **May 2024**, when a separate wallet-layer randomness-reuse bug (patched in Release 142) gave outside observers their first means of reading inside DERO's encrypted payloads. Pointed back at a transaction mined on **October 17, 2022** — accepted by every validating node, indistinguishable on-chain from any other transfer — that technique returned a value, paired it with a payload proof, and announced an inflation. The chain never said any such thing. The transaction is the same one it has always been: bounded by range proofs that pin every amount to a non-negative range, conserved by balance proofs that bind inputs to outputs, accepted unanimously. What changed in 2024 was the ability to *interpret* — and a misreading, intentional or otherwise, of what a payload proof is and does. The entire Derolytics narrative rests on that single misreading. Every chart, every accusation, every dollar figure. --- Part 1: The Claim and Its Foundation The report cites this **payload proof** as cryptographic evidence — readers paste it into an explorer, see **Verified**, and treat that as confirmation the on-chain transfer was negative (Proof Types; display-layer only, not consensus). As cited: **Category error:** **Verified** on a pasted payload proof means the display object's internal math is consistent — **not** that nodes accepted the transfer or minted coins. Payload proofs are user-supplied; explorers check math, not consensus. Proof Types **The technical claim** (as stated in public exploit reports) rests on a single assumption — that the payload proof above is cryptographic evidence, and what verifies on an explorer also represents what consensus accepted: 1. The transfer amount was **−2,200,000.00181 DERO** (fee included in the negative value). 2. Stored as uint64 (an unsigned 64-bit integer, no negatives), that negative value wraparound displays as **~184 trillion DERO** on explorers — roughly **14 million× total supply**. 3. Post-2024 deanonymization is cited to name a fresh wallet as the **sender** — and to read the wraparound as a **~2.2M DERO** credit to that sender, not the **~184 trillion** figure on screen. 4. **Conclusion:** consensus failed → **~2.2M DERO** minted from nothing. Each step is load-bearing. The rest of this page evaluates them on three independent grounds — the proof string (Parts 2–3), what consensus enforces (Part 4), and attribution limits (Part 5) — then synthesizes them (Part 6). Report claims vs. evidence | Report claim | What actually follows | |---|---| | *\"Protocol failed to validate transaction proofs\"* | They mean **payload proofs** (display layer). **Transaction proofs** are verified by every node. Proof Types | | *\"Verify yourself… proof string … on the official explorer\"* | **Verified** = pasted object math checks out, not node acceptance. The string decodes to exactly **−2,200,000.00181** and the explorer's display-layer consistency check passes — because that is all a display proof does. Part 3 | | *\"Sender actually received 2.2M DERO\"* | The ~2.2M is the forgeable proof string, not a deanonymization result; a faithful deanonymization reads a **conserved transfer of coins already held**. Part 5 | | *\"Both wallets freshly created and empty\"* | Ring members **always** show encrypted balance changes — including decoys who did not send. Ring Member Behavior | | *\"$8.34M laundered over 781 transactions\"* | **Assumes the mint happened.** No keystone → the graph is unmotivated. Out of scope here. | --- Part 2: The Explorer Wraparound — What It Actually Proves Paste the Part 1 **payload proof** into an unpatched explorer and it displays **184,467,438,537,095.51434 DERO** with **Verified ✓** — roughly **14 million× total supply** on screen. That figure is a display-layer reading of the embedded uint64 as a positive number. **Proves:** Unpatched explorers can mark inflated payload proofs **Verified** — including amounts that bypass MAX_INT64_SAFE and wrap to negatives. **Does not prove:** The on-chain transaction contained that amount. Remediation **The proof is authentic.** Decode the bech32 string as an integer (rpc.NewAddress → args.Value(RPC_VALUE_TRANSFER, DataUint64)) and the embedded value is 18,446,743,853,709,551,435 — exactly **−2,200,000.00181 DERO**, the report's own stated figure to the atom. The \"off-by-one\" in the display is the explorer's rounding, not a flaw in the proof: FormatMoneyPrecision parses the uint64 via big.ParseFloat(..., prec=0, ...), which Go's stdlib promotes to a **64-bit mantissa** before rounding (documented behavior — when prec=0, math/big.Float.Parse sets it to 64). At that precision the step size near 10¹⁴ (~0.0000153 DERO) is *just over* one atomic unit (0.00001 DERO), so rounding lands in the **last** place — …51435 renders as …51434. Authenticity is the page's point, not a problem for it. The misreading at the heart of the inflation claim isn't \"Derolytics produced a broken proof\" — it's that an authentic display object was treated as consensus state. A layer that cannot reliably render its own last digit is not consensus state. Decode it yourself The canonical path the callout cites — rpc.NewAddress → args.Value — runs in ~10 lines against any DEROHE checkout: On the cited TX with the Part 1 string: **Unpatched** (DEROFDN/derohe main — no proof/proof_validation.go) shows it as **Verified ✓**: Unpatched explorer displays the report proof as Verified — 184,467,438,537,095.51434 DERO **Patched** (DEROFDN/derohe community-dev, via PR #14 — ValidatePayloadProofAmount) rejects the wraparound before display: Same report proof rejected by the patched explorer Part 3 shows anyone can forge such proofs for arbitrary amounts. --- Part 3: Forge a Fake Proof Yourself **We forged one to show how trivial it is.** Below is a fake deroproof… built specifically for this page — accepts on unpatched explorers, shows an amount that never moved on-chain. It took minutes. No wallet, no private keys, no insider access. Everything needed is already public: the Part 1 transaction, its 16 ring slots, and the commitment math. The point isn't that forgery is *theoretically possible* — it's that **the report's \"Verified ✓\" evidence is the same kind of object, built the same way**. The trick, in plain English 1. **Pick the real transaction** everyone is looking at (5bbe1b7eecfe3447cb045b1197a07a214b456968eda8a3d5a90f5fae9ce57e55). 2. **Pick one of 16 ring slots** (positions 0–15) — each slot has a public address; you choose which slot the fake proof should attach to. 3. **Pick any amount** you want on screen — including **−1 DERO** or **~184 trillion DERO** wraparound values. 4. **Do the math.** Each ring slot has a published commitment of the form amount × G + blinder — public on chain. Pick any amount; rearrange to solve for the blinder that fits: blinder = C[slot] − amount × G. 5. **Paste the string** into an unpatched explorer with the same TX. If the display math fits → **Verified ✓** on an unpatched explorer. Nodes never saw the string; supply didn't change. The circulated report string (Part 1) is exactly one such pasted object. **Three ways to see it for yourself**, easiest first — paste ours, ask an agent, or build one from scratch with nothing but public data. Tier 0 — Paste the one we already made **Paste this forged demo** — built for this page, not from the report. | Field | Value | |---|---| | **TX** | 5bbe1b7eecfe3447cb045b1197a07a214b456968eda8a3d5a90f5fae9ce57e55 | | **Ring slot** | **0** (of 16) | | **Encoded amount** | **−1 DERO** → renders on screen as 184,467,440,737,094.51616 | **Unpatched** (DEROFDN/derohe main): Page-built −1 DERO forged proof accepted by unpatched explorer **Patched** (DEROFDN/derohe community-dev, PR #14): Same forged proof rejected — wraparound amount blocked Tier 1 — Ask your agent to forge one (no setup) No Go, no daemon, no keys, nothing to install. The DERO MCP server ships a dero_forge_demo_proof tool that finds a node for you automatically — your own if you're running one (the local-first default as of v0.4.0), a public node otherwise — so you don't have to run anything. Add it to any MCP client (Claude, Cursor, ChatGPT connectors) and ask: > *\"Forge a payload proof for TX 5bbe…e55, ring slot 7, for −5,000,000 DERO.\"* Back comes a deroproof… string. Paste it into an unpatched explorer — it lights up **Verified ✓**, rendering your −5M as a ~184-trillion-DERO \"mint.\" The chain never moved a coin. Change the slot, change the amount, go bigger; the \"evidence\" doesn't care what number you pick — *that's the whole point.* Needs the MCP server at **v0.4.0+** (the release with the forge tool and local-first node resolution). Until it lands on npm, install from source. Tier 2 — Build one from scratch (no DERO tooling) No wallet — public inputs, public math, one bech32 string. Nothing here comes from DERO, so a skeptic can re-run the whole thing from public data and trust the result. We're showing the work so it can be reproduced, not taken on faith. **What we chose:** ring slot **0**, target **−1 DERO** (= −100,000 atoms). Encoded as the uint64 wraparound **18446744073709451616**, the unpatched explorer renders it as a positive number → **184,467,440,737,094.51616 DERO** on screen — the −1 we picked never appears (same display-layer reading as Part 2). **The equation** (proof/proof.go): C[0] is **public** in the TX hex. Rearrange: **blinder = C[0] − amount×G**. That derived point — **not** the ring address — plus V (amount) and dummy H, bech32-encoded → demo string above. **Self-check:** Passes → unpatched explorer shows **Verified ✓**. **Nothing on-chain changed.** The circulated report string (Part 1) is the same kind of object. Steps 1–2 — fetch the cited TX and its **16 ring members** (public on-chain): The explorer checks commitment math against these public values — not whether the amount was consensus-valid. Step 3 only — wraparound uint64 math for a chosen amount. **Does not** output a pasteable deroproof… string. Step 4 — encode a complete deroproof… string. **Building** the proof needs only the TX bytes (to read C[slot]); the **ring** is used solely by the optional proof.Prove self-check at the end. The proof embeds a **derived blinder point** (C[slot] − amount×G) so the explorer math fits — not the ring address string itself. **Setup once.** This imports github.com/deroproject/derohe/..., so either drop forge_demo.go *inside* a DEROHE checkout, or make a folder beside one and wire a module to it: Change amount and slot to forge any display value for any ring position. If proof.Prove succeeds, an unpatched explorer would show **Verified ✓** for that amount. --- Part 4: The Chain's Account at the Exploit Block The proof asserts consensus accepted a negative-amount transfer — that the protocol minted ~2.2M DERO from nothing. The chain testifies otherwise on two independent counts. **First:** range proofs cannot verify a negative-amount transfer, so no validating node could have accepted one. **Second:** the block where it allegedly happened records a **0.615 DERO** reward — scheduled emission, not millions — and one transaction whose range proofs passed cleanly at every validator. Both counts hold. Negative transfers fail range-proof validation Could negative transfers pass consensus — separate from the submitted proof string? **No — and the guarantee is cryptographic, not a string-parsing quirk.** Every DERO transfer carries a **Bulletproof range proof**. The protocol packs the **transfer amount** and the sender's **remaining balance** into one 128-bit value and proves, in zero knowledge, that it lies in 0, 2^128) — i.e. that *both* the amount sent and the balance left over are valid **non-negative** 64-bit numbers (number := btransfer.Add(btransfer, bdiff.Lsh(bdiff, 64)) at cryptography/crypto/proof_generate.go:471). A \"negative\" transfer is the uint64 wraparound of a huge value, and it cannot satisfy that proof: - **As the amount** — a value near 2^64 exceeds the 64-bit range bound. - **As the consequence** — spending more than you hold drives the *remaining balance* negative, which wraps out of range too. By the **computational soundness** of Bulletproofs — under the discrete-log assumption on the bn256 curve, in the random oracle model (Fiat-Shamir) — no prover can construct a proof that *verifies* for an out-of-range committed value, except with negligible probability bounded by the underlying hardness. Combined with DERO's homomorphic accounting (inputs and outputs are bound to balance exactly), value cannot be created from nothing. Every node runs this verification independently before accepting a block, so a negative-transfer mint is rejected at **consensus** — not merely discouraged client-side. See [Cryptographic Assumptions for the full assumption stack. | Proves | Does not prove | |---|---| | The **specific** alleged mechanism cannot produce a verifying proof. | No inflation via *any* mechanism. | | Range proofs bind every node's acceptance. | Every historical tx has been audited. | Full derivation: Negative Transfer Protection. That closes the *mechanism* question. The *outcome* question is what the chain permanently recorded at topo 1,081,893 — not what a pasted deroproof displays. Verify supply at the exploit block The report's conclusion is that ~2.2M DERO was **minted from nothing** on October 17, 2022 (topoheight **1,081,893**). To support that, it would need to show abnormal coin creation at consensus — a multi-million DERO step in the block itself, or a supply audit against something other than the emission schedule. It publishes neither: only a payload proof string and an interpretation of the **corresponding transaction** (Part 1). Scheduled emission is **deterministic** from block height: premine plus block rewards that halve on a fixed schedule (CalcBlockReward in blockchain/transaction_execute.go). That formula estimates *expected* cumulative supply at any height. **DERO.GetInfo reports the same approximation** (cmd/derod/rpc/rpc_dero_getinfo.go:81-82: PREMINE + CalcBlockReward(topoheight) × topoheight, then divided by 100,000 to convert atomic units to whole DERO) — scheduled emission in whole DERO, **not** a UTXO census or balance sum across the ledger. **Burden of proof.** Supply conservation isn't audited — it's built in. Every accepted transaction is bound by range proofs (amounts must be non-negative) and balance proofs (inputs must equal outputs), so cumulative supply at any height is exactly **premine + scheduled block rewards**. GetInfo.total_supply reports that schedule, not a UTXO census — and it doesn't need to. To show a 2.2M mint, the report would need a deviation against an independent supply measure, or an accounting discrepancy in the block record. It shows neither. Per-block emission at this era was **0.615 DERO**, and the cited block records exactly that. The independent checks on this case: block-header **reward**, cited-TX **acceptance** (range proofs passed), and the **impossibility** of the alleged mechanism (above). Exploit block: what the chain records Independent on-chain checks at topoheight **1,081,893** — query any synced node: | Check | RPC / source | Result | |---|---|---| | Block timestamp | GetBlockHeaderByTopoHeight | 2022-10-17 07:58:09 UTC | | Block hash | GetBlockHeaderByTopoHeight | b6bd914f7fb1c79788fe8676c277e58e7bb5a904317afb096b1d2793af9aed13 | | Block reward | GetBlockHeaderByTopoHeight | **0.615 DERO** (61,500 atomic units) — normal scheduled emission, not a 2.2M mint | | TX count | GetBlockHeaderByTopoHeight | **1** (the cited transaction) | | Cited TX status | GetTransaction | **Accepted and mined** → all range proofs passed at every validating node | | Expected cumulative supply | Emission formula | **~12,946,618 DERO** at this height (schedule only — not a ledger audit) | For context, if a **+2.2M DERO** consensus mint had occurred at this block, expected cumulative supply under the schedule would be **~15,146,618 DERO** instead — but detecting that would require an **independent** supply measure the protocol does not expose via RPC. The report never publishes one. For **this alleged mechanism**, the block record is decisive anyway: a negative-transfer mint would require consensus to accept an impossible amount (range proofs). The TX **was** accepted — under normal protocol rules, with a **0.615 DERO** block reward, not millions. Steps 1–2 are the independent checks. Step 3 confirms GetInfo.total_supply implements the emission schedule (PREMINE + CalcBlockReward × height) — **not** a UTXO census. Matching the Python tab means the RPC uses the formula; it does not detect a surreptitious mint. Same RPC methods are available via the DERO MCP server (dero_get_info, dero_get_block_header_by_topo_height). Part 4 closes the consensus side: the alleged mechanism cannot pass range-proof validation. The exploit block records a **0.615 DERO** reward — not a multi-million mint — and the cited transaction in Part 1 was **accepted**, meaning range proofs passed at every validating node. The report never publishes a supply delta against an independent measure. --- Part 5: What Deanonymization Can and Cannot Establish Parts 2–4 closed the mint question. The report leans on one further capability — deanonymization — to name a beneficiary and trace funds. Applied honestly to this transaction, it does not support the inflation claim. It undercuts it. **The bug was real, and the fix mattered.** The deanonymization in public reports relies on a genuine wallet-layer randomness-reuse vulnerability (disclosed May 2024, fixed in Release 142): payloads were encrypted under a key derived from a **deterministic** blinding scalar feeding a zero-nonce stream cipher, which Release 142 replaced with a per-payload ephemeral key. This page neither disputes the vulnerability nor minimizes the fix. **The ~2.2M is not a deanonymization result.** It is the circulated proof string — a forgeable display object (Part 3) whose embedded uint64 reads as −2,200,000.00181 only if you take a wraparound as negative. The report sources the figure there itself: *\"use the proof string on the official explorer to confirm.\"* **A faithful deanonymization reads the chain — and the chain was constrained in advance.** Deanonymizing recovers the value actually committed in the transaction, not a pasted string. Whatever that value is, the range proof already pinned what it *can* be (Part 4): the sender provably **held** the amount and the balances **conserved**. A committed transfer of ~184 trillion DERO is impossible — the sender would have had to hold it, and the proof would not have verified. So a faithful deanonymization of this transaction recovers an **ordinary transfer of coins that already existed** — not a mint. The payload structure backs this up: in both pre-fix and post-fix wallet code (walletapi/transaction_build.go), the only address-bound byte serialized into the payload is the **receiver index** (witness_index[1]) — the sender is never written into the payload in either era. What Release 142 changed was the **key derivation**, from the global blinding scalar r to a per-payload ephemeral scalar an outside observer can't reconstruct. A faithful read of either era's payload surfaces a receiver index and the committed value — exactly what a deanonymization can return, and nothing more. Attribution to a named individual is the report's own conceded allegation, resting on timing, access, and behavior — not cryptography. The laundering graph inherits that dependency: with no minted 2.2M, there is nothing to launder. --- Part 6: The Keystone Collapses Every downstream claim in the public exploit narrative — dollar figures, laundering graphs, \"stolen funds,\" attribution arguments, the framing of a multi-year cover-up — is built on **one load-bearing artifact**: the payload proof pasted above, presented as cryptographic confirmation that the protocol minted 2.2M DERO from nothing. That artifact fails on four independent grounds — in the order established above: 1. **It is only a display object.** Part 3 — a payload proof is user-supplied; anyone can build a **Verified ✓** one for any amount and any ring slot. 2. **The mechanism is impossible.** Part 4 — a negative/wraparound transfer cannot produce a verifying range proof, so no node would accept it at the protocol layer. 3. **No consensus mint recorded.** Part 4 — block reward was **0.615 DERO**, not millions; the cited TX was **accepted** (range proofs passed). GetInfo reports scheduled emission, not a UTXO census — it cannot detect a surreptitious mint by itself. The report never publishes a supply delta against any independent measure. 4. **Deanonymization refutes the mint, it doesn't support it.** Part 5 — the ~2.2M is the forgeable proof string, not a deanonymization output. A faithful deanonymization reads the value committed on-chain, which the range proof guarantees was held and conserved — an ordinary transfer. Attribution to a person is the report's own conceded allegation. The display-layer bug that made this confusion possible was real. It is being remediated — DEROFDN/derohe community-dev (PR #14), HOLOGRAM, and patched explorers now reject proofs like this one; main and other unpatched explorers may still show **Verified**. That is a display-layer problem worth fixing. It is not evidence that the chain minted coins; the range proofs do not permit it. **\"Irrefutable\" is only as strong as its evidence.** Derolytics' executive summary calls the case *\"irrefutable\"* and invites readers to *\"verify yourself\"* by pasting the proof string into an explorer. But that string is a user-supplied display object — one anyone can forge for any amount, describing a transfer that consensus could never accept. The artifact at the center of every accusation is a display object anyone can forge. The chain neither records the event the report describes nor permits the mechanism it alleges. Every downstream claim — laundering, attribution, dollar figures — requires that artifact to function as cryptographic evidence. It does not. --- Related Pages Transaction vs payload proofs — the distinction at the center of this case Why decoy addresses see ciphertext changes without sending funds Mathematical proof that negative amounts cannot pass consensus Why third-party payload verification is ambiguous by design",
|
|
839
|
-
"lastUpdated": "2026-05-
|
|
838
|
+
"plainText": "The 2022 Inflation Claim: Claims vs. Evidence _Derolytics' \"irrefutable proof\" is a string anyone can forge — and even a genuine one describes a transfer the chain would have rejected._ **Scope:** This page tests **one** claim: that DERO minted ~2.2M coins in October 2022 by exploiting a bug in how transfers were validated. Laundering totals, dollar figures, and attribution to individuals all **derive from this single claim** — if it falls, they fall with it. Governance and wallet-holdings allegations are out of scope here. TL;DR Summary | Question | The Evidence | |----------|--------------| | **Did total supply increase by ~2.2M DERO?** | **No.** The exploit-block reward was **0.615 DERO** — normal scheduled emission, not millions. The report never shows a supply jump on chain. Part 4 | | Is negative-transfer wraparound possible on consensus? | **No.** Range proofs bind every transfer to a non-negative range; a negative/out-of-range amount cannot produce a verifying proof. Part 4 | | Is the circulated payload proof cryptographic evidence of a mint? | **No.** It is a user-supplied **display object**; \"Verified\" means its own math is consistent, not that consensus accepted it. Part 3 | | Can explorer **Verified** on inflated proofs be reproduced? | **Yes** on unpatched explorers (MAX_INT64_SAFE bypass). Part 3 | | Does the deanonymization support the ~2.2M? | **No — it refutes it.** The figure is the forgeable proof string, not a deanonymization output; a faithful deanonymization recovers an ordinary transfer of coins already held. Part 5 | | **Bottom line on the keystone?** | **The artifact at the center of every accusation is a display object anyone can forge — and consensus could not have accepted the transfer it depicts.** Part 6 | --- At the center of every inflation accusation is a string. About a hundred characters of base32, prefixed deroproof1..., pasted into an unpatched DERO explorer where it lights up as **Verified ✓** for an amount the explorer renders as 184,467,438,537,095.51434 DERO — roughly fourteen million times the entire DERO supply. That string is the foundation of the Derolytics \"DERO Heist\" report and its follow-ups — the source of the **2.2-million-DERO** figure, the cited evidence for every downstream claim of laundering, theft, and attribution. It is also a *payload proof*: a wallet-side display object the protocol gives no third party any way to verify. By design. Ring signatures rely on exactly this ambiguity — if outsiders could verify payload proofs, plausible deniability would die with them. The technique that produced it became possible in **May 2024**, when a separate wallet-layer randomness-reuse bug (patched in Release 142) gave outside observers their first means of reading inside DERO's encrypted payloads. Pointed back at a transaction mined on **October 17, 2022** — accepted by every validating node, indistinguishable on-chain from any other transfer — that technique returned a value, paired it with a payload proof, and announced an inflation. The chain never said any such thing. The transaction is the same one it has always been: bounded by range proofs that pin every amount to a non-negative range, conserved by balance proofs that bind inputs to outputs, accepted unanimously. What changed in 2024 was the ability to *interpret* — and a misreading, intentional or otherwise, of what a payload proof is and does. The entire Derolytics narrative rests on that single misreading. Every chart, every accusation, every dollar figure. --- Part 1: The Claim and Its Foundation The report cites this **payload proof** as cryptographic evidence — readers paste it into an explorer, see **Verified**, and treat that as confirmation the on-chain transfer was negative (Proof Types; display-layer only, not consensus). As cited: **Category error:** **Verified** on a pasted payload proof means the display object's internal math is consistent — **not** that nodes accepted the transfer or minted coins. Payload proofs are user-supplied; explorers check math, not consensus. Proof Types **The technical claim** (as stated in public exploit reports) rests on a single assumption — that the payload proof above is cryptographic evidence, and what verifies on an explorer also represents what consensus accepted: 1. The transfer amount was **−2,200,000.00181 DERO** — −220,000,000,181 atoms when the bech32 is decoded (Part 2). 2. Stored as uint64 (an unsigned 64-bit integer, no negatives), that negative value wraparound displays as **~184 trillion DERO** on explorers — roughly **14 million× total supply**. 3. Post-2024 deanonymization is cited to name a fresh wallet as the **sender** — and to read the wraparound as a **~2.2M DERO** credit to that sender, not the **~184 trillion** figure on screen. 4. **Conclusion:** consensus failed → **~2.2M DERO** minted from nothing. Each step is load-bearing. The rest of this page evaluates them on three independent grounds — the proof string (Parts 2–3), what consensus enforces (Part 4), and attribution limits (Part 5) — then synthesizes them (Part 6). Report claims vs. evidence | Report claim | What actually follows | |---|---| | *\"Protocol failed to validate transaction proofs\"* | They mean **payload proofs** (display layer). **Transaction proofs** are verified by every node. Proof Types | | *\"Verify yourself… proof string … on the official explorer\"* | **Verified** = pasted object math checks out, not node acceptance. The string decodes to exactly **−2,200,000.00181** and the explorer's display-layer consistency check passes — because that is all a display proof does. Part 3 | | *\"Sender actually received 2.2M DERO\"* | The ~2.2M is the forgeable proof string, not a deanonymization result; a faithful deanonymization reads a **conserved transfer of coins already held**. Part 5 | | *\"Both wallets freshly created and empty\"* | Ring members **always** show encrypted balance changes — including decoys who did not send. Ring Member Behavior | | *\"$8.34M laundered over 781 transactions\"* | **Assumes the mint happened.** No keystone → the graph is unmotivated. Out of scope here. | --- Part 2: The Explorer Wraparound — What It Actually Proves Paste the Part 1 **payload proof** into an unpatched explorer and it displays **184,467,438,537,095.51434 DERO** with **Verified ✓** — roughly **14 million× total supply** on screen. That figure is a display-layer reading of the embedded uint64 as a positive number. **Proves:** Unpatched explorers can mark inflated payload proofs **Verified** — including amounts that bypass MAX_INT64_SAFE and wrap to negatives. **Does not prove:** The on-chain transaction contained that amount. Remediation **The proof is authentic.** Decode the bech32 string as an integer (rpc.NewAddress → args.Value(RPC_VALUE_TRANSFER, DataUint64)) and the embedded value is 18,446,743,853,709,551,435 — exactly **−2,200,000.00181 DERO**, the report's own stated figure to the atom. The \"off-by-one\" in the display is the explorer's rounding, not a flaw in the proof: FormatMoneyPrecision parses the uint64 via big.ParseFloat(..., prec=0, ...), which Go's stdlib promotes to a **64-bit mantissa** before rounding (documented behavior — when prec=0, math/big.Float.Parse sets it to 64). At that precision the step size near 10¹⁴ (~0.0000153 DERO) is *just over* one atomic unit (0.00001 DERO), so rounding lands in the **last** place — …51435 renders as …51434. Authenticity is the page's point, not a problem for it. The misreading at the heart of the inflation claim isn't \"Derolytics produced a broken proof\" — it's that an authentic display object was treated as consensus state. A layer that cannot reliably render its own last digit is not consensus state. Decode it yourself The canonical path the callout cites — rpc.NewAddress → args.Value — runs in ~10 lines against any DEROHE checkout: On the cited TX with the Part 1 string: **Unpatched** (DEROFDN/derohe main — no proof/proof_validation.go) shows it as **Verified ✓**: Unpatched explorer displays the report proof as Verified — 184,467,438,537,095.51434 DERO **Patched** (DEROFDN/derohe community-dev, via PR #14 — ValidatePayloadProofAmount) rejects the wraparound before display: Same report proof rejected by the patched explorer Part 3 shows anyone can forge such proofs for arbitrary amounts. --- Part 3: Forge a Fake Proof Yourself **We forged one to show how trivial it is.** Below is a fake deroproof… built specifically for this page — accepts on unpatched explorers, shows an amount that never moved on-chain. It took minutes. No wallet, no private keys, no insider access. Everything needed is already public: the Part 1 transaction, its 16 ring slots, and the commitment math. The point isn't that forgery is *theoretically possible* — it's that **the report's \"Verified ✓\" evidence is the same kind of object, built the same way**. The trick, in plain English 1. **Pick the real transaction** everyone is looking at (5bbe1b7eecfe3447cb045b1197a07a214b456968eda8a3d5a90f5fae9ce57e55). 2. **Pick one of 16 ring slots** (positions 0–15) — each slot has a public address; you choose which slot the fake proof should attach to. 3. **Pick any amount** you want on screen — including **−1 DERO** or **~184 trillion DERO** wraparound values. 4. **Do the math.** Each ring slot has a published commitment of the form amount × G + blinder — public on chain. Pick any amount; rearrange to solve for the blinder that fits: blinder = C[slot] − amount × G. 5. **Paste the string** into an unpatched explorer with the same TX. If the display math fits → **Verified ✓** on an unpatched explorer. Nodes never saw the string; supply didn't change. The circulated report string (Part 1) is exactly one such pasted object. **Three ways to see it for yourself**, easiest first — paste ours, ask an agent, or build one from scratch with nothing but public data. Tier 0 — Paste the one we already made **Paste this forged demo** — built for this page, not from the report. | Field | Value | |---|---| | **TX** | 5bbe1b7eecfe3447cb045b1197a07a214b456968eda8a3d5a90f5fae9ce57e55 | | **Ring slot** | **0** (of 16) | | **Encoded amount** | **−1 DERO** → renders on screen as 184,467,440,737,094.51616 | **Unpatched** (DEROFDN/derohe main): Page-built −1 DERO forged proof accepted by unpatched explorer **Patched** (DEROFDN/derohe community-dev, PR #14): Same forged proof rejected — wraparound amount blocked Tier 1 — Ask your agent to forge one (no setup) No Go, no keys, no math. The DERO MCP server ships a dero_forge_demo_proof tool — connect once, then ask in plain language. Two ways in: - **Nothing to install** — point an HTTP MCP client (ChatGPT custom connectors, Cursor hosted mode) at https://mcp.derod.org/mcp. - **Run it yourself** — npx dero-mcp-server and add it to Claude or Cursor. Either way it finds a node automatically: your own if you're running one (the local-first default as of v0.4.0), a public node otherwise. Then ask: > *\"Forge a payload proof for TX 5bbe…e55, ring slot 7, for −5,000,000 DERO.\"* Back comes a deroproof… string. Paste it into an unpatched explorer — it lights up **Verified ✓**, rendering your −5M as a ~184-trillion-DERO \"mint.\" The chain never moved a coin. Change the slot, change the amount, go bigger; the \"evidence\" doesn't care what number you pick — *that's the whole point.* Live now — npx dero-mcp-server (v0.4.0+) or the hosted endpoint at mcp.derod.org, both shipping the forge tool and local-first node resolution (source). Tier 2 — Build one from scratch (no DERO tooling) No wallet — public inputs, public math, one bech32 string. Nothing here comes from DERO, so a skeptic can re-run the whole thing from public data and trust the result. We're showing the work so it can be reproduced, not taken on faith. **What we chose:** ring slot **0**, target **−1 DERO** (= −100,000 atoms). Encoded as the uint64 wraparound **18446744073709451616**, the unpatched explorer renders it as a positive number → **184,467,440,737,094.51616 DERO** on screen — the −1 we picked never appears (same display-layer reading as Part 2). **The equation** (proof/proof.go): C[0] is **public** in the TX hex. Rearrange: **blinder = C[0] − amount×G**. That derived point — **not** the ring address — plus V (amount) and dummy H, bech32-encoded → demo string above. **Self-check:** Passes → unpatched explorer shows **Verified ✓**. **Nothing on-chain changed.** The circulated report string (Part 1) is the same kind of object. Steps 1–2 — fetch the cited TX and its **16 ring members** (public on-chain): The explorer checks commitment math against these public values — not whether the amount was consensus-valid. Step 3 only — wraparound uint64 math for a chosen amount. **Does not** output a pasteable deroproof… string. Step 4 — encode a complete deroproof… string. **Building** the proof needs only the TX bytes (to read C[slot]); the **ring** is used solely by the optional proof.Prove self-check at the end. The proof embeds a **derived blinder point** (C[slot] − amount×G) so the explorer math fits — not the ring address string itself. **Setup once.** This imports github.com/deroproject/derohe/..., so either drop forge_demo.go *inside* a DEROHE checkout, or make a folder beside one and wire a module to it: Change amount and slot to forge any display value for any ring position. If proof.Prove succeeds, an unpatched explorer would show **Verified ✓** for that amount. --- Part 4: The Chain's Account at the Exploit Block The proof asserts consensus accepted a negative-amount transfer — that the protocol minted ~2.2M DERO from nothing. The chain testifies otherwise on two independent counts. **First:** range proofs cannot verify a negative-amount transfer, so no validating node could have accepted one. **Second:** the block where it allegedly happened records a **0.615 DERO** reward — scheduled emission, not millions — and one transaction whose range proofs passed cleanly at every validator. Both counts hold. Negative transfers fail range-proof validation Could negative transfers pass consensus — separate from the submitted proof string? **No — and the guarantee is cryptographic, not a string-parsing quirk.** Every DERO transfer carries a **Bulletproof range proof**. The protocol packs the **transfer amount** and the sender's **remaining balance** into one 128-bit value and proves, in zero knowledge, that it lies in 0, 2^128) — i.e. that *both* the amount sent and the balance left over are valid **non-negative** 64-bit numbers (number := btransfer.Add(btransfer, bdiff.Lsh(bdiff, 64)) at cryptography/crypto/proof_generate.go:471). A \"negative\" transfer is the uint64 wraparound of a huge value, and it cannot satisfy that proof: - **As the amount** — a value near 2^64 exceeds the 64-bit range bound. - **As the consequence** — spending more than you hold drives the *remaining balance* negative, which wraps out of range too. By the **computational soundness** of Bulletproofs — under the discrete-log assumption on the bn256 curve, in the random oracle model (Fiat-Shamir) — no prover can construct a proof that *verifies* for an out-of-range committed value, except with negligible probability bounded by the underlying hardness. Combined with DERO's homomorphic accounting (inputs and outputs are bound to balance exactly), value cannot be created from nothing. Every node runs this verification independently before accepting a block, so a negative-transfer mint is rejected at **consensus** — not merely discouraged client-side. See [Cryptographic Assumptions for the full assumption stack. | Proves | Does not prove | |---|---| | The **specific** alleged mechanism cannot produce a verifying proof. | No inflation via *any* mechanism. | | Range proofs bind every node's acceptance. | Every historical tx has been audited. | Full derivation: Negative Transfer Protection. That closes the *mechanism* question. The *outcome* question is what the chain permanently recorded at topo 1,081,893 — not what a pasted deroproof displays. Verify supply at the exploit block The report's conclusion is that ~2.2M DERO was **minted from nothing** on October 17, 2022 (topoheight **1,081,893**). To support that, it would need to show abnormal coin creation at consensus — a multi-million DERO step in the block itself, or a supply audit against something other than the emission schedule. It publishes neither: only a payload proof string and an interpretation of the **corresponding transaction** (Part 1). Scheduled emission is **deterministic** from block height: premine plus block rewards that halve on a fixed schedule (CalcBlockReward in blockchain/transaction_execute.go). That formula estimates *expected* cumulative supply at any height. **DERO.GetInfo reports the same approximation** (cmd/derod/rpc/rpc_dero_getinfo.go:81-82: PREMINE + CalcBlockReward(topoheight) × topoheight, then divided by 100,000 to convert atomic units to whole DERO) — scheduled emission in whole DERO, **not** a UTXO census or balance sum across the ledger. **Burden of proof.** Supply conservation isn't audited — it's built in. Every accepted transaction is bound by range proofs (amounts must be non-negative) and balance proofs (inputs must equal outputs), so cumulative supply at any height is exactly **premine + scheduled block rewards**. GetInfo.total_supply reports that schedule, not a UTXO census — and it doesn't need to. To show a 2.2M mint, the report would need a deviation against an independent supply measure, or an accounting discrepancy in the block record. It shows neither. Per-block emission at this era was **0.615 DERO**, and the cited block records exactly that. The independent checks on this case: block-header **reward**, cited-TX **acceptance** (range proofs passed), and the **impossibility** of the alleged mechanism (above). Exploit block: what the chain records Independent on-chain checks at topoheight **1,081,893** — query any synced node: | Check | RPC / source | Result | |---|---|---| | Block timestamp | GetBlockHeaderByTopoHeight | 2022-10-17 07:58:09 UTC | | Block hash | GetBlockHeaderByTopoHeight | b6bd914f7fb1c79788fe8676c277e58e7bb5a904317afb096b1d2793af9aed13 | | Block reward | GetBlockHeaderByTopoHeight | **0.615 DERO** (61,500 atomic units) — normal scheduled emission, not a 2.2M mint | | TX count | GetBlockHeaderByTopoHeight | **1** (the cited transaction) | | Cited TX status | GetTransaction | **Accepted and mined** → all range proofs passed at every validating node | | Expected cumulative supply | Emission formula | **~12,946,618 DERO** at this height (schedule only — not a ledger audit) | For context, if a **+2.2M DERO** consensus mint had occurred at this block, expected cumulative supply under the schedule would be **~15,146,618 DERO** instead — but detecting that would require an **independent** supply measure the protocol does not expose via RPC. The report never publishes one. For **this alleged mechanism**, the block record is decisive anyway: a negative-transfer mint would require consensus to accept an impossible amount (range proofs). The TX **was** accepted — under normal protocol rules, with a **0.615 DERO** block reward, not millions. Steps 1–2 are the independent checks. Step 3 confirms GetInfo.total_supply implements the emission schedule (PREMINE + CalcBlockReward × height) — **not** a UTXO census. Matching the Python tab means the RPC uses the formula; it does not detect a surreptitious mint. Same RPC methods are available via the DERO MCP server (dero_get_info, dero_get_block_header_by_topo_height). Part 4 closes the consensus side: the alleged mechanism cannot pass range-proof validation. The exploit block records a **0.615 DERO** reward — not a multi-million mint — and the cited transaction in Part 1 was **accepted**, meaning range proofs passed at every validating node. The report never publishes a supply delta against an independent measure. --- Part 5: What Deanonymization Can and Cannot Establish Parts 2–4 closed the mint question. The report leans on one further capability — deanonymization — to name a beneficiary and trace funds. Applied honestly to this transaction, it does not support the inflation claim. It undercuts it. **The bug was real, and the fix mattered.** The deanonymization in public reports relies on a genuine wallet-layer randomness-reuse vulnerability (disclosed May 2024, fixed in Release 142): payloads were encrypted under a key derived from a **deterministic** blinding scalar feeding a zero-nonce stream cipher, which Release 142 replaced with a per-payload ephemeral key. This page neither disputes the vulnerability nor minimizes the fix. **The ~2.2M is not a deanonymization result.** It is the circulated proof string — a forgeable display object (Part 3) whose embedded uint64 reads as −2,200,000.00181 only if you take a wraparound as negative. The report sources the figure there itself: *\"use the proof string on the official explorer to confirm.\"* **A faithful deanonymization reads the chain — and the chain was constrained in advance.** Deanonymizing recovers the value actually committed in the transaction, not a pasted string. Whatever that value is, the range proof already pinned what it *can* be (Part 4): the sender provably **held** the amount and the balances **conserved**. A committed transfer that wraps either way — the on-screen ~184 trillion DERO or the report's signed −2.2M read as a credit — is impossible: the first exceeds the 64-bit range bound, and the second requires the sender's remaining balance to go negative, which the range proof also forbids (Part 4). So a faithful deanonymization of this transaction recovers an **ordinary transfer of coins that already existed** — not a mint. The payload structure backs this up: in both pre-fix and post-fix wallet code (walletapi/transaction_build.go), the only address-bound byte serialized into the payload is the **receiver index** (witness_index[1]) — the sender is never written into the payload in either era. What Release 142 changed was the **key derivation**, from the global blinding scalar r to a per-payload ephemeral scalar an outside observer can't reconstruct. A faithful read of either era's payload surfaces a receiver index and the committed value — exactly what a deanonymization can return, and nothing more. Attribution to a named individual is the report's own conceded allegation, resting on timing, access, and behavior — not cryptography. The laundering graph inherits that dependency: with no minted 2.2M, there is nothing to launder. --- Part 6: The Keystone Collapses Every downstream claim in the public exploit narrative — dollar figures, laundering graphs, \"stolen funds,\" attribution arguments, the framing of a multi-year cover-up — is built on **one load-bearing artifact**: the payload proof pasted above, presented as cryptographic confirmation that the protocol minted 2.2M DERO from nothing. That artifact fails on four independent grounds — in the order established above: 1. **It is only a display object.** Part 3 — a payload proof is user-supplied; anyone can build a **Verified ✓** one for any amount and any ring slot. 2. **The mechanism is impossible.** Part 4 — a negative/wraparound transfer cannot produce a verifying range proof, so no node would accept it at the protocol layer. 3. **No consensus mint recorded.** Part 4 — block reward was **0.615 DERO**, not millions; the cited TX was **accepted** (range proofs passed). GetInfo reports scheduled emission, not a UTXO census — it cannot detect a surreptitious mint by itself. The report never publishes a supply delta against any independent measure. 4. **Deanonymization refutes the mint, it doesn't support it.** Part 5 — the ~2.2M is the forgeable proof string, not a deanonymization output. A faithful deanonymization reads the value committed on-chain, which the range proof guarantees was held and conserved — an ordinary transfer. Attribution to a person is the report's own conceded allegation. The display-layer bug that made this confusion possible was real. It is being remediated — DEROFDN/derohe community-dev (PR #14), HOLOGRAM, and patched explorers now reject proofs like this one; main and other unpatched explorers may still show **Verified**. That is a display-layer problem worth fixing. It is not evidence that the chain minted coins; the range proofs do not permit it. **\"Don't Trust, Verify\" — exactly. So verify the chain, not a string someone hands you.** Derolytics' executive summary calls the case *\"irrefutable\"* and tells you to *\"verify yourself\"* by pasting the proof into an explorer. But a payload proof's **Verified ✓** only confirms the display object's own math is self-consistent — it never touched consensus. That's not *Don't Trust, Verify* — it's *trust the checkmark.* The string is forgeable for any amount, describing a transfer consensus could never accept. **Verify the chain** — run a node, decode the transaction, check the range proofs — and the \"mint\" disappears. The artifact at the center of every accusation is a display object anyone can forge. The chain neither records the event the report describes nor permits the mechanism it alleges. Every downstream claim — laundering, attribution, dollar figures — requires that artifact to function as cryptographic evidence. It does not. --- Related Pages Transaction vs payload proofs — the distinction at the center of this case Why decoy addresses see ciphertext changes without sending funds Mathematical proof that negative amounts cannot pass consensus Why third-party payload verification is ambiguous by design",
|
|
839
|
+
"lastUpdated": "2026-05-30"
|
|
840
840
|
},
|
|
841
841
|
{
|
|
842
842
|
"product": "derod",
|
|
@@ -1614,8 +1614,8 @@
|
|
|
1614
1614
|
"Verify, Don't Trust",
|
|
1615
1615
|
"See Also"
|
|
1616
1616
|
],
|
|
1617
|
-
"plainText": "MCP Server Query the DERO blockchain — and the canonical DERO documentation — from AI assistants. No middlemen, no API keys, no surveillance. The DERO MCP server implements the Model Context Protocol, the open standard for connecting AI models to external tools. Run it as a local **stdio** process for Claude Desktop / Cursor / OpenCode, or as a **streamable-HTTP** server behind your own domain (e.g. mcp.derod.org) for ChatGPT Custom Connectors, Cursor hosted mode, and any agent that needs a remote URL instead of a subprocess. **AI discovery files:** llms.txt and /api/openapi.json are curated subsets for agents — not a full RPC catalog. Use the Daemon RPC API and Wallet RPC API for complete method reference. Examples assume a **local daemon** at http://127.0.0.1:10102. At a Glance | Surface | Count | Notes | |---|---:|---| | **Tools** | **28** | 18 daemon RPC wrappers + 3 docs-index tools + 7 composites | | ↳ Daemon primitives | 18 | One per common daemon read method, plus local bech32 proof/address decode | | ↳ Docs primitives | 3 | Search, fetch-by-slug, enumerate across derod / tela / hologram / deropay | | ↳ Composite tools | 7 | Multi-step intent-shaped flows that fan out into primitives + docs and return a narrative with curated citations | | **Resources** | 4 | server-info, safety-boundary, example-flows, composites | | **Prompts** | 5 | Composite-first guided flows | | **Structured error codes** | 11 | Every error carries a hint and a retryable flag for agent self-correction | | **Transports** | 2 | Local **stdio** (default) + **streamable-HTTP** (self-hosted) — both drive the same buildServer() factory, so the tool surface, response shapes, and error contract are identical | | **Bundled in the npm package** | 3 docs | README.md, SKILL.md (per-tool agent runbook), POSITIONING.md (audience boundary + comparison vs. ACP / Stripe / Crossmint / Skyfire) | Latest version, install commands, and per-release notes: see npm and the GitHub releases. Tool identifiers, schemas, and behavior are semantically stable — once a tool ships, its name, args, and response shape are preserved across minor and patch releases. Breaking changes only land in majors and are flagged in the release notes. Why This Matters AI assistants are powerful research and dev tools, but most blockchain integrations route through centralized APIs that log your queries. This server runs on **your machine**, talks to **your daemon** (or a public one you choose), and communicates with your AI over **local stdio**. No accounts, no analytics, no tracking — just code you can audit. The bundled DERO documentation index (145+ pages across derod, tela, hologram, and deropay) is shipped inside the package, so the AI can quote primary sources offline without a single network round-trip beyond the daemon you pointed it at. Install Requires Node.js 18+. Source code: github.com/DHEBP/dero-mcp-server · npm: dero-mcp-server Run Your Own Node The server defaults to a third-party public RPC. For real privacy, run your own daemon: Then point the MCP server at it via DERO_DAEMON_URL (see below). Configure Your MCP Client Claude Desktop Edit claude_desktop_config.json: | OS | Path | |----|------| | macOS | ~/Library/Application Support/Claude/claude_desktop_config.json | | Windows | %APPDATA%\\Claude\\claude_desktop_config.json | | Linux | ~/.config/claude/claude_desktop_config.json | Omit env to use the default public RPC. Cursor **Settings → MCP → Add Server** - Command: dero-mcp-server - Environment: DERO_DAEMON_URL=http://127.0.0.1:10102 (optional) OpenCode Or with a local node: Continue · Cline · Zed · others Any MCP-compatible client works. The server uses **stdio** transport: Consult your client's MCP documentation for the exact config format. Inspect interactively To explore the full surface without committing to a client config, use the official MCP Inspector: It opens a local web UI that lists every tool with its schema and annotations, lets you invoke any tool with form-filled args, and shows the structured response including _meta.error blocks. HTTP Mode (Self-Hosted) For clients that can't launch a local subprocess — ChatGPT Custom Connectors, Cursor hosted mode, n8n / Zapier integrations — run the server in streamable-HTTP mode and put it behind your own domain: | Variable | Default | Description | |---|---|---| | DERO_MCP_HTTP | unset | Set to 1 (or pass --http) to start in HTTP mode | | DERO_MCP_HTTP_PORT | 8787 | Listen port | | DERO_MCP_HTTP_HOST | 127.0.0.1 | Bind address. Use 0.0.0.0 to bind publicly (do not without auth + TLS upstream) | | DERO_MCP_AUTH_TOKEN | unset | If set, every /mcp request must carry Authorization: Bearer . Constant-time compared. | For a turnkey deploy with Caddy + auto-TLS + Docker Compose, see the deploy/ reference in the repo. Anyone can fork and run their own mcp.derod.org-style instance. The stdio transport and the HTTP transport share the same buildServer() factory, so the tool surface, response shapes, and error codes are identical across both. What You Can Ask Once connected, talk to your AI naturally — it will pick the right composite or primitive based on your intent: - *\"Is the DERO daemon healthy and synced?\"* → diagnose_chain_health - *\"What does the contract at SCID […] do?\"* → explain_smart_contract - *\"Look up transaction [txid] and tell me what it is.\"* → trace_transaction_with_context - *\"Which DERO docs page should I read to deploy a TELA app?\"* → recommend_docs_path - *\"Estimate the gas cost to deploy this DVM contract.\"* → estimate_deploy_cost - *\"Verify the claim that DERO's total supply has been correctly minted at the current tip.\"* → audit_chain_artifact_claim - *\"Generate a demo DERO proof string so I can exercise my SDK's decode path.\"* → dero_forge_demo_proof - *\"What's the current block height?\"* → dero_get_info / dero_get_height - *\"Show me the source code for contract [SCID].\"* → dero_get_sc - *\"Resolve the name dero to a wallet address.\"* → dero_name_to_address - *\"Decode this bech32 proof string and tell me what it represents.\"* → dero_decode_proof_string Composite Tools Each composite replaces a multi-step primitive chain with a single call, returns a plain-language narrative summary, and stitches the most relevant bundled docs pages as related_docs citations. | Composite | Replaces | When to call | |---|---|---| | diagnose_chain_health | Ping + GetInfo + GetHeight + GetTxPool | Any \"is the chain healthy / are we synced\" question | | explain_smart_contract | GetSC + manual DVM-BASIC parsing + docs lookup | \"What does this contract do\" — returns function surface + token/registry/minimal/generic classification + 1-4 curated DVM docs | | recommend_docs_path | 4× parallel dero_docs_search + manual ranking | Natural-language intent → ranked docs across all 4 DERO products; product_hint is a 1.5× score bias, not a filter | | estimate_deploy_cost | GetGasEstimate + manual surface extraction + manual gas interpretation | DVM deploy pre-flight — returns gas estimate + plain-text breakdown + parsed function surface | | trace_transaction_with_context | GetTransaction + (for SC installs) GetSC + manual classification | \"What is this tx\" — returns confirmation status, kind classification, ring stats, and parsed SC install surface inline | | audit_chain_artifact_claim | Multiple primitives + docs lookups + proof decode | End-to-end verifier for chain-related claims — returns narrative + cited daemon state + flagged-artifact analysis + optional bech32 proof round-trips. Backbone of the adversarial-context defense layer | | dero_forge_demo_proof | dero_get_random_address + dero_decode_proof_string | Generate a demo DERO proof string that round-trips through bech32 decode/encode — for exercising SDK proof-handling code paths in testing | Each composite is fully documented in docs/composites.md (design contract, accepted/rejected designs, failure modes), and every composite ships with a green flow test in CI that runs against a live public daemon. **Why composites matter for agents.** A generic JSON-RPC client can chain primitives, but it cannot stitch the right docs context or classify failure modes for free. Composites are the wedge: they deliver agent-ready answers from the canonical DERO data sources in one call. Primitive Tools The 21 primitives map 1:1 onto daemon RPC methods (18) plus the bundled docs index (3). Use them when a composite is unavailable or you need raw data. Daemon RPC | Tool | RPC Method | Purpose | |------|------------|---------| | dero_daemon_ping | DERO.Ping | Liveness check | | dero_daemon_echo | DERO.Echo | Roundtrip string echo | | dero_get_info | DERO.GetInfo | Network height, difficulty, version, hashrate, testnet flag | | dero_get_height | DERO.GetHeight | Height, stableheight, topoheight | | dero_get_block_count | DERO.GetBlockCount | Total block count | | dero_get_block | DERO.GetBlock | Full block by hash or height | | dero_get_block_header_by_hash | DERO.GetBlockHeaderByHash | Block header by hash | | dero_get_block_header_by_topo_height | DERO.GetBlockHeaderByTopoHeight | Block header by topoheight | | dero_get_last_block_header | DERO.GetLastBlockHeader | Tip block header | | dero_get_block_template | DERO.GetBlockTemplate | Mining block template | | dero_get_transaction | DERO.GetTransaction | Transaction record by hash | | dero_get_tx_pool | DERO.GetTxPool | Mempool transaction hashes | | dero_get_sc | DERO.GetSC | Smart contract code, variables, balances | | dero_get_gas_estimate | DERO.GetGasEstimate | Daemon-side gas estimate for a contract source or call | | dero_get_encrypted_balance | DERO.GetEncryptedBalance | Encrypted balance for an address | | dero_get_random_address | DERO.GetRandomAddress | Random registered wallet addresses | | dero_name_to_address | DERO.NameToAddress | Resolve a registered name to its address | | dero_decode_proof_string | _(local — no RPC)_ | Decode a DERO bech32 proof/address string locally. Powers the adversarial-context defense layer and the demo-proof composite | Bundled docs index | Tool | Purpose | |------|---------| | dero_docs_list | Enumerate available doc pages across derod, tela, hologram, deropay | | dero_docs_search | Full-text search across the bundled docs index — in-process, no network round-trip | | dero_docs_get_page | Fetch a single doc page by slug with full plain-text content and headings | Resources and Prompts Beyond tools, the server exposes 4 **resources** and 5 **prompts** so MCP-aware clients can surface them in their UI: Resources | URI | Content | |-----|---------| | dero://mcp/server-info | Server metadata, tool list, resource list, prompt names, daemon endpoint | | dero://mcp/safety-boundary | Read-only posture and excluded method list (transfer, scinvoke, etc.) | | dero://mcp/example-flows | Composite-first agent flow recipes for common DERO investigations | | dero://mcp/composites | Structured catalog of all 7 composites — what each replaces, when to call it, what it returns, and which _meta.error codes it can emit | Prompts | Prompt | What it scripts | |--------|----------------| | network_health_check | Drives diagnose_chain_health with optional reference_topoheight | | inspect_smart_contract | Drives explain_smart_contract for any SCID | | trace_transaction | Drives trace_transaction_with_context for any tx hash | | find_dero_docs_for_intent | Drives recommend_docs_path with a natural-language intent + optional product_hint | | estimate_deploy_for_contract | Drives estimate_deploy_cost with DVM-BASIC source | Structured Errors Every tool wraps failures in a structured _meta.error block so agents can react programmatically instead of parsing error strings: | Code | Emitted by | Meaning | Retryable | |------|------------|---------|:---------:| | INVALID_INPUT | estimate_deploy_cost + others | Tool input shape is wrong (wraps daemon -32098 for DVM compile errors); raw message preserved in _meta.error.raw | no — read the hint | | INVALID_BECH32 | dero_decode_proof_string, audit + forge composites | Bech32 proof/address string failed to decode | no — re-check input string | | NO_DOCS_MATCH | recommend_docs_path | Intent matched zero pages across all 4 products | no — rephrase intent (drop verbs) | | DOC_NOT_FOUND | dero_docs_get_page | Slug doesn't exist in the bundled index | no — use dero_docs_search to find valid slugs | | TX_NOT_FOUND | trace_transaction_with_context | Daemon returned an empty record for the hash | yes — verify hash + network; retryable if freshly broadcast | | RPC_UNREACHABLE | All daemon tools | Daemon not reachable on DERO_DAEMON_URL | yes — check daemon + run npm run doctor | | RPC_INVALID_PARAMS | Most daemon tools | Daemon rejected the request shape | no — check arg names and types | | RPC_METHOD_NOT_FOUND | All daemon tools | Daemon outdated or not Stargate | no — surface to user; they need to upgrade | | RPC_HTTP_ERROR | All daemon tools | HTTP-level error from the daemon | yes — check DERO_DAEMON_URL | | DOCS_UNAVAILABLE | All docs tools | Bundled docs index missing from the install | no — reinstall dero-mcp-server | | TOOL_EXECUTION_ERROR | All tools | Catch-all unexpected error | yes — retry once, then inspect daemon logs | Every error code carries a hint string with actionable next steps so the agent can recover or explain the failure cleanly to the user. Read-Only by Design Every one of the 28 tools carries the MCP read-only annotation block: This lets MCP hosts safely auto-approve any tool call from this server without prompting on every read. The server **cannot**: - Send transactions - Transfer funds - Invoke smart contracts (only **estimate** deploy cost via estimate_deploy_cost — nothing is submitted to chain) - Submit blocks - Hold wallet keys or talk to wallet RPC Wallet RPC methods (transfer, scinvoke, DERO.SendRawTransaction, DERO.SubmitBlock) are explicitly excluded. The full read-only posture, the six AND-gated conditions that would be required to expand the boundary, and the rationale for each are documented in docs/decision-boundary.md. If you need write capabilities in the future, they will be gated behind explicit flags **and** a separate wallet URL **and** a distinct annotation block (readOnlyHint: false) **and** documented escalation — never enabled by default. Environment | Variable | Default | Description | |----------|---------|-------------| | DERO_DAEMON_URL | http://82.65.143.182:10102 | Daemon base URL. Set to http://127.0.0.1:10102 for a local node. | | DERO_DOCS_ROOT | _(unset; uses bundled index)_ | Optional dev override pointing at a local docs source tree. Production deployments should leave this unset to use the bundled index. | | DERO_MCP_HTTP | unset | Set to 1 (or pass --http) to start in streamable-HTTP mode instead of stdio. | | DERO_MCP_HTTP_PORT | 8787 | HTTP listen port when running in HTTP mode. | | DERO_MCP_HTTP_HOST | 127.0.0.1 | HTTP bind address. Use 0.0.0.0 to bind publicly (only behind auth + TLS upstream). | | DERO_MCP_AUTH_TOKEN | unset | Bearer token for HTTP /mcp requests. If set, every request must carry Authorization: Bearer . Constant-time compared. | Verify, Don't Trust - Source code on GitHub — composite design contract in docs/composites.md, read-only posture in docs/decision-boundary.md, agent-ready evidence in docs/mcp-agent-ready-evidence.md - **Bundled with the npm package:** SKILL.md is the per-tool agent operating manual (composite-first rule, port reference, structured error contract, workflow recipes, safety rules); POSITIONING.md covers who this server is for vs. who it isn't, with a comparison vs. ACP / Stripe / Crossmint / Skyfire - Agent-discovery surfaces at /.well-known/agent-card.json (A2A v0.2-draft descriptor for the broader agent ecosystem) and /.well-known/mcp-server-card.json (MCP-specific descriptor) - Package on npm - Listed in the official MCP registry as io.github.DHEBP/dero-mcp-server - CI runs full smoke probes, composite flow tests, primitive flow tests, description / citation drift guards, and HTTP transport smoke tests on every push - MIT licensed — fork it, audit it, improve it See Also - DERO Daemon RPC API — full RPC reference for the methods the primitives wrap - Running a DERO Node — set up your own daemon - Smart Contract Fundamentals — DVM concepts the composites cite - XSWD — browser wallet integration (for write flows the MCP server intentionally excludes) - SKILL.md — agent operating manual served at the docs origin (mirror of the npm-bundled file) - agents.md — human-and-LLM-readable operating runbook for the whole DERO docs surface - llms.txt — curated agent map of the DERO docs corpus",
|
|
1618
|
-
"lastUpdated": "2026-05-
|
|
1617
|
+
"plainText": "MCP Server Query the DERO blockchain — and the canonical DERO documentation — from AI assistants. No middlemen, no API keys, no surveillance. The DERO MCP server implements the Model Context Protocol, the open standard for connecting AI models to external tools. Run it as a local **stdio** process for Claude Desktop / Cursor / OpenCode, or as a **streamable-HTTP** server behind your own domain (e.g. mcp.derod.org) for ChatGPT Custom Connectors, Cursor hosted mode, and any agent that needs a remote URL instead of a subprocess. **AI discovery files:** llms.txt and /api/openapi.json are curated subsets for agents — not a full RPC catalog. Use the Daemon RPC API and Wallet RPC API for complete method reference. Examples assume a **local daemon** at http://127.0.0.1:10102. At a Glance | Surface | Count | Notes | |---|---:|---| | **Tools** | **28** | 18 daemon RPC wrappers + 3 docs-index tools + 7 composites | | ↳ Daemon primitives | 18 | One per common daemon read method, plus local bech32 proof/address decode | | ↳ Docs primitives | 3 | Search, fetch-by-slug, enumerate across derod / tela / hologram / deropay | | ↳ Composite tools | 7 | Multi-step intent-shaped flows that fan out into primitives + docs and return a narrative with curated citations | | **Resources** | 4 | server-info, safety-boundary, example-flows, composites | | **Prompts** | 5 | Composite-first guided flows | | **Structured error codes** | 11 | Every error carries a hint and a retryable flag for agent self-correction | | **Transports** | 2 | Local **stdio** (default) + **streamable-HTTP** (self-hosted) — both drive the same buildServer() factory, so the tool surface, response shapes, and error contract are identical | | **Bundled in the npm package** | 3 docs | README.md, SKILL.md (per-tool agent runbook), POSITIONING.md (audience boundary + comparison vs. ACP / Stripe / Crossmint / Skyfire) | Latest version, install commands, and per-release notes: see npm and the GitHub releases. Tool identifiers, schemas, and behavior are semantically stable — once a tool ships, its name, args, and response shape are preserved across minor and patch releases. Breaking changes only land in majors and are flagged in the release notes. Why This Matters AI assistants are powerful research and dev tools, but most blockchain integrations route through centralized APIs that log your queries. This server runs on **your machine**, talks to **your daemon** (or a public one you choose), and communicates with your AI over **local stdio**. No accounts, no analytics, no tracking — just code you can audit. The bundled DERO documentation index (145+ pages across derod, tela, hologram, and deropay) is shipped inside the package, so the AI can quote primary sources offline without a single network round-trip beyond the daemon you pointed it at. Install Requires Node.js 18+. Source code: github.com/DHEBP/dero-mcp-server · npm: dero-mcp-server Run Your Own Node The server defaults to a third-party public RPC. For real privacy, run your own daemon: Then point the MCP server at it via DERO_DAEMON_URL (see below). Configure Your MCP Client Claude Desktop Edit claude_desktop_config.json: | OS | Path | |----|------| | macOS | ~/Library/Application Support/Claude/claude_desktop_config.json | | Windows | %APPDATA%\\Claude\\claude_desktop_config.json | | Linux | ~/.config/claude/claude_desktop_config.json | Omit env to use the default public RPC. Cursor **Settings → MCP → Add Server** - Command: dero-mcp-server - Environment: DERO_DAEMON_URL=http://127.0.0.1:10102 (optional) OpenCode Or with a local node: Continue · Cline · Zed · others Any MCP-compatible client works. The server uses **stdio** transport: Consult your client's MCP documentation for the exact config format. Inspect interactively To explore the full surface without committing to a client config, use the official MCP Inspector: It opens a local web UI that lists every tool with its schema and annotations, lets you invoke any tool with form-filled args, and shows the structured response including _meta.error blocks. HTTP Mode (Self-Hosted) For clients that can't launch a local subprocess — ChatGPT Custom Connectors, Cursor hosted mode, n8n / Zapier integrations — run the server in streamable-HTTP mode and put it behind your own domain: | Variable | Default | Description | |---|---|---| | DERO_MCP_HTTP | unset | Set to 1 (or pass --http) to start in HTTP mode | | DERO_MCP_HTTP_PORT | 8787 | Listen port | | DERO_MCP_HTTP_HOST | 127.0.0.1 | Bind address. Use 0.0.0.0 to bind publicly (do not without auth + TLS upstream) | | DERO_MCP_AUTH_TOKEN | unset | If set, every /mcp request must carry Authorization: Bearer . Constant-time compared. | For a turnkey deploy with Caddy + auto-TLS + Docker Compose, see the deploy/ reference in the repo. Anyone can fork and run their own mcp.derod.org-style instance. The stdio transport and the HTTP transport share the same buildServer() factory, so the tool surface, response shapes, and error codes are identical across both. What You Can Ask Once connected, talk to your AI naturally — it will pick the right composite or primitive based on your intent: - *\"Is the DERO daemon healthy and synced?\"* → diagnose_chain_health - *\"What does the contract at SCID […] do?\"* → explain_smart_contract - *\"Look up transaction [txid] and tell me what it is.\"* → trace_transaction_with_context - *\"Which DERO docs page should I read to deploy a TELA app?\"* → recommend_docs_path - *\"Estimate the gas cost to deploy this DVM contract.\"* → estimate_deploy_cost - *\"Verify the claim that DERO's total supply has been correctly minted at the current tip.\"* → audit_chain_artifact_claim - *\"Forge a payload proof showing any amount — to see why 'Verified ✓' on an explorer proves nothing.\"* → dero_forge_demo_proof - *\"What's the current block height?\"* → dero_get_info / dero_get_height - *\"Show me the source code for contract [SCID].\"* → dero_get_sc - *\"Resolve the name dero to a wallet address.\"* → dero_name_to_address - *\"Decode this bech32 proof string and tell me what it represents.\"* → dero_decode_proof_string Composite Tools Each composite replaces a multi-step primitive chain with a single call, returns a plain-language narrative summary, and stitches the most relevant bundled docs pages as related_docs citations. | Composite | Replaces | When to call | |---|---|---| | diagnose_chain_health | Ping + GetInfo + GetHeight + GetTxPool | Any \"is the chain healthy / are we synced\" question | | explain_smart_contract | GetSC + manual DVM-BASIC parsing + docs lookup | \"What does this contract do\" — returns function surface + token/registry/minimal/generic classification + 1-4 curated DVM docs | | recommend_docs_path | 4× parallel dero_docs_search + manual ranking | Natural-language intent → ranked docs across all 4 DERO products; product_hint is a 1.5× score bias, not a filter | | estimate_deploy_cost | GetGasEstimate + manual surface extraction + manual gas interpretation | DVM deploy pre-flight — returns gas estimate + plain-text breakdown + parsed function surface | | trace_transaction_with_context | GetTransaction + (for SC installs) GetSC + manual classification | \"What is this tx\" — returns confirmation status, kind classification, ring stats, and parsed SC install surface inline | | audit_chain_artifact_claim | Multiple primitives + docs lookups + proof decode | End-to-end verifier for chain-related claims — returns narrative + cited daemon state + flagged-artifact analysis + optional bech32 proof round-trips. Backbone of the adversarial-context defense layer | | dero_forge_demo_proof | dero_get_transaction + manual commitment math + bech32 encode | Forge a deroproof… display object for any tx / ring slot / amount — the one-call reproduction of the inflation-claim Part 3 demo that **Verified ✓ proves nothing**: payload proofs are user-forgeable. Also exercises SDK proof-decode paths. | Each composite is fully documented in docs/composites.md (design contract, accepted/rejected designs, failure modes), and every composite ships with a green flow test in CI that runs against a live public daemon. **Why composites matter for agents.** A generic JSON-RPC client can chain primitives, but it cannot stitch the right docs context or classify failure modes for free. Composites are the wedge: they deliver agent-ready answers from the canonical DERO data sources in one call. Primitive Tools The 21 primitives map 1:1 onto daemon RPC methods (18) plus the bundled docs index (3). Use them when a composite is unavailable or you need raw data. Daemon RPC | Tool | RPC Method | Purpose | |------|------------|---------| | dero_daemon_ping | DERO.Ping | Liveness check | | dero_daemon_echo | DERO.Echo | Roundtrip string echo | | dero_get_info | DERO.GetInfo | Network height, difficulty, version, hashrate, testnet flag | | dero_get_height | DERO.GetHeight | Height, stableheight, topoheight | | dero_get_block_count | DERO.GetBlockCount | Total block count | | dero_get_block | DERO.GetBlock | Full block by hash or height | | dero_get_block_header_by_hash | DERO.GetBlockHeaderByHash | Block header by hash | | dero_get_block_header_by_topo_height | DERO.GetBlockHeaderByTopoHeight | Block header by topoheight | | dero_get_last_block_header | DERO.GetLastBlockHeader | Tip block header | | dero_get_block_template | DERO.GetBlockTemplate | Mining block template | | dero_get_transaction | DERO.GetTransaction | Transaction record by hash | | dero_get_tx_pool | DERO.GetTxPool | Mempool transaction hashes | | dero_get_sc | DERO.GetSC | Smart contract code, variables, balances | | dero_get_gas_estimate | DERO.GetGasEstimate | Daemon-side gas estimate for a contract source or call | | dero_get_encrypted_balance | DERO.GetEncryptedBalance | Encrypted balance for an address | | dero_get_random_address | DERO.GetRandomAddress | Random registered wallet addresses | | dero_name_to_address | DERO.NameToAddress | Resolve a registered name to its address | | dero_decode_proof_string | _(local — no RPC)_ | Decode a DERO bech32 proof/address string locally. Powers the adversarial-context defense layer and the demo-proof composite | Bundled docs index | Tool | Purpose | |------|---------| | dero_docs_list | Enumerate available doc pages across derod, tela, hologram, deropay | | dero_docs_search | Full-text search across the bundled docs index — in-process, no network round-trip | | dero_docs_get_page | Fetch a single doc page by slug with full plain-text content and headings | Resources and Prompts Beyond tools, the server exposes 4 **resources** and 5 **prompts** so MCP-aware clients can surface them in their UI: Resources | URI | Content | |-----|---------| | dero://mcp/server-info | Server metadata, tool list, resource list, prompt names, daemon endpoint | | dero://mcp/safety-boundary | Read-only posture and excluded method list (transfer, scinvoke, etc.) | | dero://mcp/example-flows | Composite-first agent flow recipes for common DERO investigations | | dero://mcp/composites | Structured catalog of all 7 composites — what each replaces, when to call it, what it returns, and which _meta.error codes it can emit | Prompts | Prompt | What it scripts | |--------|----------------| | network_health_check | Drives diagnose_chain_health with optional reference_topoheight | | inspect_smart_contract | Drives explain_smart_contract for any SCID | | trace_transaction | Drives trace_transaction_with_context for any tx hash | | find_dero_docs_for_intent | Drives recommend_docs_path with a natural-language intent + optional product_hint | | estimate_deploy_for_contract | Drives estimate_deploy_cost with DVM-BASIC source | Structured Errors Every tool wraps failures in a structured _meta.error block so agents can react programmatically instead of parsing error strings: | Code | Emitted by | Meaning | Retryable | |------|------------|---------|:---------:| | INVALID_INPUT | estimate_deploy_cost + others | Tool input shape is wrong (wraps daemon -32098 for DVM compile errors); raw message preserved in _meta.error.raw | no — read the hint | | INVALID_BECH32 | dero_decode_proof_string, audit + forge composites | Bech32 proof/address string failed to decode | no — re-check input string | | NO_DOCS_MATCH | recommend_docs_path | Intent matched zero pages across all 4 products | no — rephrase intent (drop verbs) | | DOC_NOT_FOUND | dero_docs_get_page | Slug doesn't exist in the bundled index | no — use dero_docs_search to find valid slugs | | TX_NOT_FOUND | trace_transaction_with_context | Daemon returned an empty record for the hash | yes — verify hash + network; retryable if freshly broadcast | | RPC_UNREACHABLE | All daemon tools | Daemon not reachable on DERO_DAEMON_URL | yes — check daemon + run npm run doctor | | RPC_INVALID_PARAMS | Most daemon tools | Daemon rejected the request shape | no — check arg names and types | | RPC_METHOD_NOT_FOUND | All daemon tools | Daemon outdated or not Stargate | no — surface to user; they need to upgrade | | RPC_HTTP_ERROR | All daemon tools | HTTP-level error from the daemon | yes — check DERO_DAEMON_URL | | DOCS_UNAVAILABLE | All docs tools | Bundled docs index missing from the install | no — reinstall dero-mcp-server | | TOOL_EXECUTION_ERROR | All tools | Catch-all unexpected error | yes — retry once, then inspect daemon logs | Every error code carries a hint string with actionable next steps so the agent can recover or explain the failure cleanly to the user. Read-Only by Design Every one of the 28 tools carries the MCP read-only annotation block: This lets MCP hosts safely auto-approve any tool call from this server without prompting on every read. The server **cannot**: - Send transactions - Transfer funds - Invoke smart contracts (only **estimate** deploy cost via estimate_deploy_cost — nothing is submitted to chain) - Submit blocks - Hold wallet keys or talk to wallet RPC Wallet RPC methods (transfer, scinvoke, DERO.SendRawTransaction, DERO.SubmitBlock) are explicitly excluded. The full read-only posture, the six AND-gated conditions that would be required to expand the boundary, and the rationale for each are documented in docs/decision-boundary.md. If you need write capabilities in the future, they will be gated behind explicit flags **and** a separate wallet URL **and** a distinct annotation block (readOnlyHint: false) **and** documented escalation — never enabled by default. Environment | Variable | Default | Description | |----------|---------|-------------| | DERO_DAEMON_URL | http://82.65.143.182:10102 | Daemon base URL. Set to http://127.0.0.1:10102 for a local node. | | DERO_DOCS_ROOT | _(unset; uses bundled index)_ | Optional dev override pointing at a local docs source tree. Production deployments should leave this unset to use the bundled index. | | DERO_MCP_HTTP | unset | Set to 1 (or pass --http) to start in streamable-HTTP mode instead of stdio. | | DERO_MCP_HTTP_PORT | 8787 | HTTP listen port when running in HTTP mode. | | DERO_MCP_HTTP_HOST | 127.0.0.1 | HTTP bind address. Use 0.0.0.0 to bind publicly (only behind auth + TLS upstream). | | DERO_MCP_AUTH_TOKEN | unset | Bearer token for HTTP /mcp requests. If set, every request must carry Authorization: Bearer . Constant-time compared. | Verify, Don't Trust - Source code on GitHub — composite design contract in docs/composites.md, read-only posture in docs/decision-boundary.md, agent-ready evidence in docs/mcp-agent-ready-evidence.md - **Bundled with the npm package:** SKILL.md is the per-tool agent operating manual (composite-first rule, port reference, structured error contract, workflow recipes, safety rules); POSITIONING.md covers who this server is for vs. who it isn't, with a comparison vs. ACP / Stripe / Crossmint / Skyfire - Agent-discovery surfaces at /.well-known/agent-card.json (A2A v0.2-draft descriptor for the broader agent ecosystem) and /.well-known/mcp-server-card.json (MCP-specific descriptor) - Package on npm - Listed in the official MCP registry as io.github.DHEBP/dero-mcp-server - CI runs full smoke probes, composite flow tests, primitive flow tests, description / citation drift guards, and HTTP transport smoke tests on every push - MIT licensed — fork it, audit it, improve it See Also - DERO Daemon RPC API — full RPC reference for the methods the primitives wrap - Running a DERO Node — set up your own daemon - Smart Contract Fundamentals — DVM concepts the composites cite - XSWD — browser wallet integration (for write flows the MCP server intentionally excludes) - SKILL.md — agent operating manual served at the docs origin (mirror of the npm-bundled file) - agents.md — human-and-LLM-readable operating runbook for the whole DERO docs surface - llms.txt — curated agent map of the DERO docs corpus",
|
|
1618
|
+
"lastUpdated": "2026-05-29"
|
|
1619
1619
|
},
|
|
1620
1620
|
{
|
|
1621
1621
|
"product": "derod",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAsCH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAsCH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoFrD"}
|
package/dist/http-server.js
CHANGED
|
@@ -39,7 +39,7 @@ import { timingSafeEqual } from 'node:crypto';
|
|
|
39
39
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
40
40
|
import { createDeroMcpServer } from './server.js';
|
|
41
41
|
import { resolveDaemonBase, describeDaemonResolution } from './daemon-base.js';
|
|
42
|
-
const PACKAGE_VERSION = '0.4.
|
|
42
|
+
const PACKAGE_VERSION = '0.4.1';
|
|
43
43
|
function readEnv() {
|
|
44
44
|
const port = Number.parseInt(process.env.DERO_MCP_HTTP_PORT ?? '8787', 10);
|
|
45
45
|
const host = process.env.DERO_MCP_HTTP_HOST ?? '127.0.0.1';
|
|
@@ -71,13 +71,6 @@ export async function startHttpServer() {
|
|
|
71
71
|
const { port, host, authToken } = readEnv();
|
|
72
72
|
const resolution = await resolveDaemonBase();
|
|
73
73
|
const daemonUrl = resolution.base;
|
|
74
|
-
const mcpServer = createDeroMcpServer(daemonUrl);
|
|
75
|
-
// Stateless mode: no session IDs, no in-memory state across requests.
|
|
76
|
-
// Fits read-only semantics and minimizes the privacy surface.
|
|
77
|
-
const transport = new StreamableHTTPServerTransport({
|
|
78
|
-
sessionIdGenerator: undefined,
|
|
79
|
-
});
|
|
80
|
-
await mcpServer.connect(transport);
|
|
81
74
|
const httpServer = http.createServer(async (req, res) => {
|
|
82
75
|
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
83
76
|
if (url.pathname === '/health' && req.method === 'GET') {
|
|
@@ -102,7 +95,21 @@ export async function startHttpServer() {
|
|
|
102
95
|
send(res, 401, JSON.stringify({ error: 'unauthorized' }));
|
|
103
96
|
return;
|
|
104
97
|
}
|
|
98
|
+
// Stateless mode: fresh McpServer + transport per request. The SDK's
|
|
99
|
+
// StreamableHTTPServerTransport carries per-request state (the active
|
|
100
|
+
// response writer, SSE stream); reusing a single transport across
|
|
101
|
+
// requests wedges every request after the first. Per-request isolation
|
|
102
|
+
// also prevents request-ID collisions across concurrent clients.
|
|
103
|
+
const mcpServer = createDeroMcpServer(daemonUrl);
|
|
104
|
+
const transport = new StreamableHTTPServerTransport({
|
|
105
|
+
sessionIdGenerator: undefined,
|
|
106
|
+
});
|
|
107
|
+
res.on('close', () => {
|
|
108
|
+
transport.close().catch(() => { });
|
|
109
|
+
mcpServer.close().catch(() => { });
|
|
110
|
+
});
|
|
105
111
|
try {
|
|
112
|
+
await mcpServer.connect(transport);
|
|
106
113
|
await transport.handleRequest(req, res);
|
|
107
114
|
}
|
|
108
115
|
catch (err) {
|
package/dist/http-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAClG,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAE9E,MAAM,eAAe,GAAG,OAAO,CAAA;AAE/B,SAAS,OAAO;IACd,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,MAAM,EAAE,EAAE,CAAC,CAAA;IAC1E,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,WAAW,CAAA;IAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,SAAS,CAAA;IACtE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAClC,CAAC;AAED,SAAS,YAAY,CAAC,GAAyB,EAAE,aAAqB;IACpE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;IAC3C,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAClD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC1C,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACpB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAA;IAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IACpC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACvC,OAAO,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED,SAAS,IAAI,CAAC,GAAwB,EAAE,MAAc,EAAE,IAAY,EAAE,WAAW,GAAG,kBAAkB;IACpG,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,WAAW;QAC3B,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;KAC1C,CAAC,CAAA;IACF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,CAAA;IAC3C,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAA;IAC5C,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -230,7 +230,7 @@ export function createDeroMcpServer(daemonBaseUrl) {
|
|
|
230
230
|
const rpc = async (method, params) => deroJsonRpc(endpoint, method, params);
|
|
231
231
|
const server = new McpServer({
|
|
232
232
|
name: 'dero-daemon-mcp',
|
|
233
|
-
version: '0.4.
|
|
233
|
+
version: '0.4.1',
|
|
234
234
|
});
|
|
235
235
|
server.registerTool('dero_daemon_ping', readOnly({
|
|
236
236
|
description: TOOL_DESCRIPTIONS.dero_daemon_ping,
|
|
@@ -584,7 +584,7 @@ export function createDeroMcpServer(daemonBaseUrl) {
|
|
|
584
584
|
mimeType: 'application/json',
|
|
585
585
|
text: JSON.stringify({
|
|
586
586
|
name: 'dero-daemon-mcp',
|
|
587
|
-
version: '0.4.
|
|
587
|
+
version: '0.4.1',
|
|
588
588
|
mode: 'read-only',
|
|
589
589
|
endpoint: endpoint,
|
|
590
590
|
docs_products: DERO_DOC_PRODUCTS,
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dero-mcp-server",
|
|
3
3
|
"mcpName": "io.github.DHEBP/dero-mcp-server",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"description": "Model Context Protocol (MCP) server exposing DERO Stargate daemon JSON-RPC and bundled documentation to Claude and other MCP clients",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"engines": {
|
|
9
|
-
"node": ">=
|
|
9
|
+
"node": ">=22"
|
|
10
10
|
},
|
|
11
11
|
"main": "./dist/index.js",
|
|
12
12
|
"bin": {
|