dero-mcp-server 0.1.1 → 0.2.2

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.
Files changed (58) hide show
  1. package/README.md +79 -6
  2. package/data/docs-index.json +5702 -0
  3. package/dist/citations.d.ts +70 -0
  4. package/dist/citations.d.ts.map +1 -0
  5. package/dist/citations.js +162 -0
  6. package/dist/citations.js.map +1 -0
  7. package/dist/composites/_shared.d.ts +119 -0
  8. package/dist/composites/_shared.d.ts.map +1 -0
  9. package/dist/composites/_shared.js +152 -0
  10. package/dist/composites/_shared.js.map +1 -0
  11. package/dist/composites/diagnose-chain-health.d.ts +64 -0
  12. package/dist/composites/diagnose-chain-health.d.ts.map +1 -0
  13. package/dist/composites/diagnose-chain-health.js +144 -0
  14. package/dist/composites/diagnose-chain-health.js.map +1 -0
  15. package/dist/composites/estimate-deploy-cost.d.ts +83 -0
  16. package/dist/composites/estimate-deploy-cost.d.ts.map +1 -0
  17. package/dist/composites/estimate-deploy-cost.js +116 -0
  18. package/dist/composites/estimate-deploy-cost.js.map +1 -0
  19. package/dist/composites/explain-smart-contract.d.ts +64 -0
  20. package/dist/composites/explain-smart-contract.d.ts.map +1 -0
  21. package/dist/composites/explain-smart-contract.js +149 -0
  22. package/dist/composites/explain-smart-contract.js.map +1 -0
  23. package/dist/composites/recommend-docs-path.d.ts +97 -0
  24. package/dist/composites/recommend-docs-path.d.ts.map +1 -0
  25. package/dist/composites/recommend-docs-path.js +149 -0
  26. package/dist/composites/recommend-docs-path.js.map +1 -0
  27. package/dist/composites/trace-transaction-with-context.d.ts +107 -0
  28. package/dist/composites/trace-transaction-with-context.d.ts.map +1 -0
  29. package/dist/composites/trace-transaction-with-context.js +217 -0
  30. package/dist/composites/trace-transaction-with-context.js.map +1 -0
  31. package/dist/docs-parse.d.ts +30 -0
  32. package/dist/docs-parse.d.ts.map +1 -0
  33. package/dist/docs-parse.js +147 -0
  34. package/dist/docs-parse.js.map +1 -0
  35. package/dist/docs.d.ts +101 -0
  36. package/dist/docs.d.ts.map +1 -0
  37. package/dist/docs.js +172 -0
  38. package/dist/docs.js.map +1 -0
  39. package/dist/server.d.ts.map +1 -1
  40. package/dist/server.js +417 -100
  41. package/dist/server.js.map +1 -1
  42. package/dist/tool-descriptions.d.ts +50 -0
  43. package/dist/tool-descriptions.d.ts.map +1 -0
  44. package/dist/tool-descriptions.js +246 -0
  45. package/dist/tool-descriptions.js.map +1 -0
  46. package/package.json +15 -3
  47. package/.github/workflows/ci.yml +0 -62
  48. package/docs/example-agent-flows.md +0 -236
  49. package/docs/mcp-agent-ready-evidence.md +0 -108
  50. package/glama.json +0 -6
  51. package/scripts/doctor.sh +0 -85
  52. package/scripts/flow-test.ts +0 -257
  53. package/scripts/mcp-smoke-probes.ts +0 -168
  54. package/server.json +0 -23
  55. package/src/index.ts +0 -30
  56. package/src/rpc.ts +0 -60
  57. package/src/server.ts +0 -636
  58. package/tsconfig.json +0 -16
@@ -1,236 +0,0 @@
1
- # Example Agent Flows
2
-
3
- How to use DERO MCP tools in multi-step conversations. These examples work in Cursor, Claude Desktop, or any MCP client with `dero-mcp-server` configured.
4
-
5
- ---
6
-
7
- ## Flow 1: Network Health Check
8
-
9
- **User prompt:**
10
- > "Is my DERO node synced?"
11
-
12
- **Agent steps:**
13
-
14
- 1. `dero_daemon_ping` — confirm daemon is reachable
15
- 2. `dero_get_info` — get version, network, topoheight, difficulty
16
- 3. `dero_get_height` — get height, stableheight, topoheight
17
-
18
- **What to look for:**
19
- - Ping returns `"Pong"` → daemon is up
20
- - `topoheight` is increasing over time → node is syncing
21
- - `stableheight` close to `topoheight` → node is caught up
22
- - Compare `topoheight` to a block explorer to verify sync status
23
-
24
- **Example response:**
25
- > Your node is reachable and synced. Current topoheight: 4,521,307. Network: mainnet. Daemon version: 3.5.1-1.DERO.STARGATE+05.
26
-
27
- ---
28
-
29
- ## Flow 2: Smart Contract Inspection
30
-
31
- **User prompt:**
32
- > "Show me the stored variables for SCID abc123..."
33
-
34
- **Agent steps:**
35
-
36
- 1. `dero_get_sc` with `scid`, `variables: true`, `code: false`
37
- 2. Parse the `stringkeys` and `balances` from the response
38
- 3. Interpret Uint64/String values using DVM-BASIC conventions
39
-
40
- **What to look for:**
41
- - `stringkeys` contains stored state (key-value pairs)
42
- - Keys starting with lowercase are typically private state
43
- - `balances` shows token holdings if the contract manages assets
44
- - `code` field contains DVM-BASIC source if `code: true`
45
-
46
- **Example prompt:**
47
- > "What's stored in the name registry contract?"
48
-
49
- ```
50
- dero_get_sc({
51
- scid: "0000000000000000000000000000000000000000000000000000000000000001",
52
- variables: true,
53
- code: false
54
- })
55
- ```
56
-
57
- ---
58
-
59
- ## Flow 3: Transaction Lookup
60
-
61
- **User prompt:**
62
- > "What happened in transaction 7f3a...?"
63
-
64
- **Agent steps:**
65
-
66
- 1. `dero_get_transaction` with `txs_hashes: ["7f3a..."]`, `decode_as_json: 1`
67
- 2. Summarize transaction type, transfers, and SC invocations
68
- 3. Link to block height from response metadata
69
-
70
- **What to look for:**
71
- - `txs` array contains transaction details
72
- - `sc_args` shows smart contract function calls
73
- - `as_hex` is the raw transaction (skip unless debugging)
74
- - `block_height` and `in_pool` indicate confirmation status
75
-
76
- **Example:**
77
- > Transaction 7f3a... was confirmed at block 4,521,200. It invoked the "Register" function on the name registry with argument "myname".
78
-
79
- ---
80
-
81
- ## Flow 4: Name Resolution
82
-
83
- **User prompt:**
84
- > "What address owns the name 'dero'?"
85
-
86
- **Agent steps:**
87
-
88
- 1. `dero_name_to_address` with `name: "dero"`, `topoheight: -1`
89
- 2. Return the resolved address
90
-
91
- **What to look for:**
92
- - `address` field contains the DERO address (starts with `dero1` or `deto1`)
93
- - If name is not registered, the RPC returns an error
94
- - `topoheight: -1` means "latest chain state"
95
-
96
- **Example:**
97
- > The name "dero" resolves to `dero1qy...` (truncated). This is public on-chain data visible to anyone.
98
-
99
- ---
100
-
101
- ## Flow 5: Block Exploration
102
-
103
- **User prompt:**
104
- > "Show me block 4,500,000"
105
-
106
- **Agent steps:**
107
-
108
- 1. `dero_get_block` with `height: 4500000`
109
- 2. Summarize: timestamp, miner reward, transaction count, hash
110
-
111
- **Alternative — by hash:**
112
- 1. `dero_get_block_header_by_hash` with `hash: "abc123..."`
113
-
114
- **What to look for:**
115
- - `block_header.timestamp` — Unix timestamp of block
116
- - `block_header.reward` — miner reward in atomic units (divide by 100000 for DERO)
117
- - `txs` — list of transaction hashes in the block
118
-
119
- ---
120
-
121
- ## Flow 6: Contract Deploy Prep (Read-Only)
122
-
123
- **User prompt:**
124
- > "Estimate gas for deploying this contract"
125
-
126
- **Agent steps:**
127
-
128
- 1. Validate DVM-BASIC syntax (use `dvm-basic` Cursor skill if available)
129
- 2. `dero_get_gas_estimate` with `sc: "<contract source>"`
130
- 3. Report compute and storage costs
131
-
132
- **Important:** This MCP server is **read-only**. It cannot deploy contracts. After estimating gas, tell the user to deploy via:
133
- - DERO CLI wallet (`curl` to wallet RPC)
134
- - Engram wallet GUI
135
- - XSWD browser integration
136
-
137
- **Example:**
138
- > Gas estimate: 5,000 compute + 12,000 storage = 17,000 total. Deploy via your wallet — this MCP cannot submit transactions.
139
-
140
- ---
141
-
142
- ## Flow 7: Mempool Check
143
-
144
- **User prompt:**
145
- > "Are there pending transactions?"
146
-
147
- **Agent steps:**
148
-
149
- 1. `dero_get_tx_pool`
150
- 2. Report count of pending transaction hashes
151
-
152
- **What to look for:**
153
- - `tx_hashes` array — pending transactions waiting for blocks
154
- - Empty array means mempool is clear
155
- - Large mempool may indicate network congestion
156
-
157
- ---
158
-
159
- ## Flow 8: Encrypted Balance Lookup
160
-
161
- **User prompt:**
162
- > "Get the encrypted balance blob for address dero1qy..."
163
-
164
- **Agent steps:**
165
-
166
- 1. `dero_get_encrypted_balance` with `address`, `topoheight: -1`
167
- 2. Return the encrypted balance data
168
-
169
- **Important:** This returns **encrypted** balance data, not cleartext. Only the address owner can decrypt it with their private keys. This is useful for:
170
- - Building transactions (ring signatures need balance commitments)
171
- - Verifying an address exists on-chain
172
-
173
- ---
174
-
175
- ## Flow 9: Mining Template (Advanced)
176
-
177
- **User prompt:**
178
- > "Get a block template for mining"
179
-
180
- **Agent steps:**
181
-
182
- 1. `dero_get_block_template` with `wallet_address: "dero1qy..."`
183
- 2. Return the template blob for mining software
184
-
185
- **Note:** This is for miners integrating with pools or solo mining. Most users won't need this.
186
-
187
- ---
188
-
189
- ## Combining Flows
190
-
191
- Real conversations often combine multiple flows:
192
-
193
- **User:** "Check if my node is synced, then show me the latest block and any pending transactions."
194
-
195
- **Agent:**
196
- 1. `dero_daemon_ping` → confirm reachable
197
- 2. `dero_get_info` → get topoheight
198
- 3. `dero_get_last_block_header` → latest block details
199
- 4. `dero_get_tx_pool` → pending transactions
200
-
201
- ---
202
-
203
- ## Tips for Agents
204
-
205
- 1. **Always ping first** if unsure about daemon connectivity
206
- 2. **Use `topoheight: -1`** for latest state in queries that accept it
207
- 3. **SCIDs are 64-character hex** — validate format before calling
208
- 4. **Atomic units**: DERO amounts are in 1/100000 units (5 decimals)
209
- 5. **Read-only boundary**: This MCP cannot send transactions, deploy contracts, or modify state. Guide users to wallet tools for writes.
210
- 6. **Use structured errors**: failed tools return `_meta.error` with `code`, `hint`, and `retryable` for recovery logic.
211
-
212
- ---
213
-
214
- ## Related Skills
215
-
216
- If using Cursor, these skills complement the MCP tools:
217
-
218
- | Skill | Use for |
219
- |---|---|
220
- | `dero-rpc` | Direct curl commands, wallet RPC (transfers, scinvoke) |
221
- | `dvm-basic` | Writing and debugging smart contract code |
222
- | `smart-contracts` | Deployment workflows, ownership transfer |
223
- | `tela-publisher` | Deploying TELA web apps on-chain |
224
- | `gnomon-indexer` | Discovering contracts by stored variables |
225
-
226
- The MCP provides **live chain reads**. Skills provide **workflow guidance** and access to wallet operations the MCP intentionally excludes.
227
-
228
- ## Built-in MCP Prompts
229
-
230
- These prompts are available from `prompts/list`:
231
-
232
- - `network_health_check`
233
- - `inspect_smart_contract`
234
- - `trace_transaction`
235
-
236
- Use `prompts/get` with arguments, then execute the suggested tool sequence.
@@ -1,108 +0,0 @@
1
- # DERO MCP Agent-Ready Evidence
2
-
3
- **Last updated:** 2026-05-19
4
- **Repo:** `DHEBP/dero-mcp-server` @ `6630dee`
5
- **Mode:** Local stdio MCP (read-only daemon access)
6
-
7
- ---
8
-
9
- ## One-line verdict
10
-
11
- DERO MCP is **agent-ready for local stdio usage**: surface contract is stable, diagnostics pass, flow tests pass, and CI now includes MCP smoke probes.
12
-
13
- ---
14
-
15
- ## Verified surface
16
-
17
- | Primitive | Count | Notes |
18
- |---|---:|---|
19
- | Tools | 17 | Read-only daemon methods only |
20
- | Resources | 3 | Server info, safety boundary, example flows |
21
- | Prompts | 3 | Network health, SC inspection, tx tracing |
22
-
23
- ---
24
-
25
- ## Proof commands and outcomes
26
-
27
- ### 1) MCP smoke probes
28
-
29
- ```bash
30
- npm run smoke:mcp
31
- ```
32
-
33
- Result (latest run):
34
-
35
- - `tools/list` parity: **17**
36
- - `resources/list` parity: **3**
37
- - `prompts/list` parity: **3**
38
- - `prompts/get` check: **pass**
39
- - Structured error probe (`_meta.error`): **pass**
40
-
41
- ### 2) Flow tests
42
-
43
- ```bash
44
- npm run test:flows
45
- ```
46
-
47
- Result (latest run):
48
-
49
- - **10 passed**
50
- - **0 failed**
51
- - **0 skipped**
52
-
53
- ### 3) Daemon connectivity doctor
54
-
55
- ```bash
56
- npm run doctor
57
- ```
58
-
59
- Result (latest run):
60
-
61
- - TCP reachability: **pass**
62
- - `DERO.Ping`: **pass**
63
- - `DERO.GetInfo`: **pass**
64
-
65
- ### 4) Build and type safety
66
-
67
- ```bash
68
- npm run build
69
- npm run typecheck
70
- ```
71
-
72
- Result (latest run):
73
-
74
- - Build: **pass**
75
- - Typecheck: **pass**
76
-
77
- ---
78
-
79
- ## Security boundary (explicit)
80
-
81
- This MCP server remains **read-only** by design.
82
-
83
- Excluded methods include:
84
-
85
- - Wallet mutation calls (e.g., `transfer`, `scinvoke`)
86
- - `DERO.SendRawTransaction`
87
- - `DERO.SubmitBlock`
88
-
89
- Write operations must remain outside this server unless an explicit wallet-write gate policy is introduced.
90
-
91
- ---
92
-
93
- ## CI gate
94
-
95
- Current CI runs:
96
-
97
- 1. `npm run build`
98
- 2. `npm run smoke:mcp`
99
- 3. `npm run test:flows`
100
- 4. `tsc --noEmit`
101
-
102
- ---
103
-
104
- ## Deferred items
105
-
106
- - Wallet-write support (intentionally deferred)
107
- - Streamable HTTP/SSE transport (not required for current stdio-first strategy)
108
- - Domain DNS discovery artifacts (`.well-known`, `_mcp`, `_agentroot`, `_llms`) until remote transport exists
package/glama.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "$schema": "https://glama.ai/mcp/schemas/server.json",
3
- "maintainers": [
4
- "DHEBP"
5
- ]
6
- }
package/scripts/doctor.sh DELETED
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env bash
2
- # DERO MCP Server — connectivity doctor
3
- # Checks daemon reachability before using the MCP server.
4
- #
5
- # Usage:
6
- # ./scripts/doctor.sh # uses DERO_DAEMON_URL or default
7
- # ./scripts/doctor.sh http://127.0.0.1:10102 # explicit URL
8
- # DERO_DAEMON_URL=http://... ./scripts/doctor.sh
9
-
10
- set -euo pipefail
11
-
12
- # Default: public RPC (same as server default)
13
- DEFAULT_URL="http://82.65.143.182:10102"
14
-
15
- # Accept CLI arg or env var
16
- DAEMON_URL="${1:-${DERO_DAEMON_URL:-$DEFAULT_URL}}"
17
- DAEMON_URL="${DAEMON_URL%/}" # strip trailing slash
18
-
19
- echo "DERO MCP Doctor"
20
- echo "==============="
21
- echo "Daemon URL: ${DAEMON_URL}"
22
- echo ""
23
-
24
- fail=0
25
-
26
- # Check 1: Basic TCP reachability (extract host:port)
27
- host_port=$(echo "$DAEMON_URL" | sed -E 's|https?://||' | sed 's|/.*||')
28
- host=$(echo "$host_port" | cut -d: -f1)
29
- port=$(echo "$host_port" | cut -d: -f2)
30
- if [[ -z "$port" || "$port" == "$host" ]]; then
31
- port=10102
32
- fi
33
-
34
- echo "1. TCP connectivity to ${host}:${port}"
35
- if nc -z -w 5 "$host" "$port" 2>/dev/null; then
36
- echo " OK — port reachable"
37
- else
38
- echo " FAIL — cannot reach ${host}:${port}"
39
- echo " Hint: Is the daemon running? Is the port open?"
40
- fail=$((fail + 1))
41
- fi
42
-
43
- echo ""
44
-
45
- # Check 2: DERO.Ping RPC call
46
- echo "2. DERO.Ping RPC"
47
- ping_response=$(curl -sS -m 10 -X POST "${DAEMON_URL}/json_rpc" \
48
- -H "Content-Type: application/json" \
49
- -d '{"jsonrpc":"2.0","method":"DERO.Ping","id":1}' 2>/dev/null || echo '{"error":"curl_failed"}')
50
-
51
- if echo "$ping_response" | grep -Eq '"status":"OK"|"result":"Pong ?"' ; then
52
- echo " OK — daemon responded to ping"
53
- else
54
- echo " FAIL — DERO.Ping did not return a known success shape"
55
- echo " Response: $ping_response"
56
- fail=$((fail + 1))
57
- fi
58
-
59
- echo ""
60
-
61
- # Check 3: DERO.GetInfo (confirms chain sync)
62
- echo "3. DERO.GetInfo RPC"
63
- info_response=$(curl -sS -m 10 -X POST "${DAEMON_URL}/json_rpc" \
64
- -H "Content-Type: application/json" \
65
- -d '{"jsonrpc":"2.0","method":"DERO.GetInfo","id":1}' 2>/dev/null || echo '{"error":"curl_failed"}')
66
-
67
- if echo "$info_response" | grep -q '"topoheight"'; then
68
- topoheight=$(echo "$info_response" | grep -oE '"topoheight":[0-9]+' | grep -oE '[0-9]+')
69
- echo " OK — chain topoheight: ${topoheight:-unknown}"
70
- else
71
- echo " FAIL — DERO.GetInfo did not return chain data"
72
- echo " Response: $info_response"
73
- fail=$((fail + 1))
74
- fi
75
-
76
- echo ""
77
-
78
- # Summary
79
- if [[ "$fail" -eq 0 ]]; then
80
- echo "All checks passed. MCP server should work against this daemon."
81
- exit 0
82
- else
83
- echo "${fail} check(s) failed. Fix connectivity before using MCP."
84
- exit 1
85
- fi
@@ -1,257 +0,0 @@
1
- #!/usr/bin/env npx tsx
2
- /**
3
- * DERO MCP Server — Flow Test
4
- *
5
- * Tests the daemon RPC calls that the MCP tools wrap.
6
- * Run this against a live daemon (local or remote) to verify connectivity
7
- * and that the RPC methods return expected data shapes.
8
- *
9
- * Usage:
10
- * npx tsx scripts/flow-test.ts
11
- * npx tsx scripts/flow-test.ts http://127.0.0.1:10102
12
- * DERO_DAEMON_URL=http://... npx tsx scripts/flow-test.ts
13
- */
14
-
15
- const DEFAULT_URL = "http://82.65.143.182:10102";
16
-
17
- type FlowStatus = "pass" | "fail" | "skip";
18
- type FlowResult = {
19
- id: string;
20
- name: string;
21
- status: FlowStatus;
22
- message?: string;
23
- durationMs: number;
24
- };
25
-
26
- async function deroRpc<T = unknown>(
27
- endpoint: string,
28
- method: string,
29
- params?: unknown
30
- ): Promise<T> {
31
- const res = await fetch(`${endpoint}/json_rpc`, {
32
- method: "POST",
33
- headers: { "Content-Type": "application/json" },
34
- body: JSON.stringify({
35
- jsonrpc: "2.0",
36
- id: "1",
37
- method,
38
- params,
39
- }),
40
- });
41
-
42
- if (!res.ok) {
43
- throw new Error(`HTTP ${res.status} from daemon`);
44
- }
45
-
46
- const data = await res.json();
47
- if (data.error) {
48
- throw new Error(`RPC error: ${JSON.stringify(data.error)}`);
49
- }
50
- return data.result;
51
- }
52
-
53
- function assert(condition: unknown, message: string): void {
54
- if (!condition) throw new Error(message);
55
- }
56
-
57
- async function runFlow(
58
- id: string,
59
- name: string,
60
- fn: () => Promise<void>
61
- ): Promise<FlowResult> {
62
- const start = performance.now();
63
- try {
64
- await fn();
65
- return { id, name, status: "pass", durationMs: Math.round(performance.now() - start) };
66
- } catch (error) {
67
- return {
68
- id,
69
- name,
70
- status: "fail",
71
- message: error instanceof Error ? error.message : String(error),
72
- durationMs: Math.round(performance.now() - start),
73
- };
74
- }
75
- }
76
-
77
- async function runAllFlows(daemonUrl: string): Promise<FlowResult[]> {
78
- const results: FlowResult[] = [];
79
-
80
- // Flow 1: Ping
81
- results.push(
82
- await runFlow("ping", "DERO.Ping — daemon reachable", async () => {
83
- const result = await deroRpc<string>(daemonUrl, "DERO.Ping");
84
- assert(result === "Pong " || result === "Pong", `Expected 'Pong', got '${result}'`);
85
- })
86
- );
87
-
88
- // Flow 2: Echo
89
- results.push(
90
- await runFlow("echo", "DERO.Echo — roundtrip strings", async () => {
91
- const words = ["hello", "dero", "mcp"];
92
- const result = await deroRpc<string>(daemonUrl, "DERO.Echo", words);
93
- assert(typeof result === "string", "Expected string response");
94
- assert(result.includes("DERO") || words.some(w => result.includes(w)), "Echo should contain input or DERO");
95
- })
96
- );
97
-
98
- // Flow 3: GetInfo
99
- let topoheight: number | undefined;
100
- results.push(
101
- await runFlow("get-info", "DERO.GetInfo — chain metadata", async () => {
102
- const result = await deroRpc<{
103
- topoheight?: number;
104
- height?: number;
105
- network?: string;
106
- version?: string;
107
- }>(daemonUrl, "DERO.GetInfo");
108
- assert(typeof result.topoheight === "number", "Missing topoheight");
109
- assert(typeof result.height === "number", "Missing height");
110
- topoheight = result.topoheight;
111
- })
112
- );
113
-
114
- // Flow 4: GetHeight
115
- results.push(
116
- await runFlow("get-height", "DERO.GetHeight — block heights", async () => {
117
- const result = await deroRpc<{
118
- height?: number;
119
- stableheight?: number;
120
- topoheight?: number;
121
- }>(daemonUrl, "DERO.GetHeight");
122
- assert(typeof result.height === "number", "Missing height");
123
- assert(typeof result.topoheight === "number", "Missing topoheight");
124
- })
125
- );
126
-
127
- // Flow 5: GetBlockCount
128
- results.push(
129
- await runFlow("get-block-count", "DERO.GetBlockCount — total blocks", async () => {
130
- const result = await deroRpc<{ count?: number }>(daemonUrl, "DERO.GetBlockCount");
131
- assert(typeof result.count === "number", "Missing count");
132
- assert(result.count > 0, "Block count should be > 0");
133
- })
134
- );
135
-
136
- // Flow 6: GetLastBlockHeader
137
- results.push(
138
- await runFlow("get-last-block-header", "DERO.GetLastBlockHeader — tip block", async () => {
139
- const result = await deroRpc<{ block_header?: { height?: number; hash?: string } }>(
140
- daemonUrl,
141
- "DERO.GetLastBlockHeader"
142
- );
143
- assert(result.block_header, "Missing block_header");
144
- assert(typeof result.block_header.height === "number", "Missing height in header");
145
- })
146
- );
147
-
148
- // Flow 7: GetBlock by height (use topoheight - 10 for safety)
149
- results.push(
150
- await runFlow("get-block-by-height", "DERO.GetBlock — fetch by height", async () => {
151
- const testHeight = Math.max(1, (topoheight ?? 100) - 10);
152
- const result = await deroRpc<{ block_header?: unknown }>(daemonUrl, "DERO.GetBlock", {
153
- height: testHeight,
154
- });
155
- assert(result.block_header, "Missing block_header in response");
156
- })
157
- );
158
-
159
- // Flow 8: GetTxPool (may be empty, just check shape)
160
- results.push(
161
- await runFlow("get-tx-pool", "DERO.GetTxPool — mempool check", async () => {
162
- const result = await deroRpc<{ tx_hashes?: string[] }>(daemonUrl, "DERO.GetTxPool");
163
- // tx_hashes may be null/undefined if empty, which is fine
164
- assert(
165
- result.tx_hashes === undefined || result.tx_hashes === null || Array.isArray(result.tx_hashes),
166
- "tx_hashes should be array or null"
167
- );
168
- })
169
- );
170
-
171
- // Flow 9: NameToAddress (test known name "dero" — may not exist on all networks)
172
- results.push(
173
- await runFlow("name-to-address", "DERO.NameToAddress — resolve 'dero'", async () => {
174
- try {
175
- const result = await deroRpc<{ address?: string; name?: string }>(
176
- daemonUrl,
177
- "DERO.NameToAddress",
178
- { name: "dero", topoheight: -1 }
179
- );
180
- // Name may not be registered, that's okay
181
- if (result.address) {
182
- assert(result.address.startsWith("dero") || result.address.startsWith("deto"), "Invalid address format");
183
- }
184
- } catch (e) {
185
- // Name not found is acceptable
186
- if (String(e).includes("NOT FOUND") || String(e).includes("not found")) {
187
- return;
188
- }
189
- throw e;
190
- }
191
- })
192
- );
193
-
194
- // Flow 10: GetSC — test with the name registry SCID
195
- const NAME_REGISTRY_SCID = "0000000000000000000000000000000000000000000000000000000000000001";
196
- results.push(
197
- await runFlow("get-sc", "DERO.GetSC — name registry contract", async () => {
198
- const result = await deroRpc<{ code?: string; balances?: unknown }>(
199
- daemonUrl,
200
- "DERO.GetSC",
201
- { scid: NAME_REGISTRY_SCID, code: true, variables: false }
202
- );
203
- assert(result.code, "Missing contract code");
204
- assert(result.code.includes("Function"), "Code should contain Function keyword");
205
- })
206
- );
207
-
208
- return results;
209
- }
210
-
211
- function formatReport(results: FlowResult[]): string {
212
- const lines: string[] = [
213
- "",
214
- "DERO MCP Flow Test Results",
215
- "==========================",
216
- "",
217
- ];
218
-
219
- const passed = results.filter((r) => r.status === "pass").length;
220
- const failed = results.filter((r) => r.status === "fail").length;
221
- const skipped = results.filter((r) => r.status === "skip").length;
222
-
223
- for (const r of results) {
224
- const icon = r.status === "pass" ? "✓" : r.status === "fail" ? "✗" : "○";
225
- const status = r.status.toUpperCase().padEnd(4);
226
- lines.push(`${icon} ${status} ${r.name} (${r.durationMs}ms)`);
227
- if (r.message) {
228
- lines.push(` ${r.message}`);
229
- }
230
- }
231
-
232
- lines.push("");
233
- lines.push(`Summary: ${passed} passed, ${failed} failed, ${skipped} skipped`);
234
- lines.push("");
235
-
236
- return lines.join("\n");
237
- }
238
-
239
- async function main() {
240
- const daemonUrl = (process.argv[2] || process.env.DERO_DAEMON_URL || DEFAULT_URL).replace(/\/$/, "");
241
-
242
- console.log(`Testing daemon at: ${daemonUrl}`);
243
- console.log("");
244
-
245
- try {
246
- const results = await runAllFlows(daemonUrl);
247
- console.log(formatReport(results));
248
-
249
- const failed = results.filter((r) => r.status === "fail").length;
250
- process.exit(failed > 0 ? 1 : 0);
251
- } catch (error) {
252
- console.error("Fatal error:", error instanceof Error ? error.message : error);
253
- process.exit(1);
254
- }
255
- }
256
-
257
- main();