@verusidx/chain-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/build/discovery.d.ts +39 -0
- package/build/discovery.d.ts.map +1 -0
- package/build/discovery.js +336 -0
- package/build/discovery.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +16 -0
- package/build/index.js.map +1 -0
- package/build/tools.d.ts +3 -0
- package/build/tools.d.ts.map +1 -0
- package/build/tools.js +422 -0
- package/build/tools.js.map +1 -0
- package/package.json +30 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VerusIDX Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @verusidx/chain-mcp
|
|
2
|
+
|
|
3
|
+
Foundation MCP server for the Verus blockchain. Handles chain discovery, daemon management, health checks, and raw transaction operations. All other verusidx MCP servers depend on this one.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Add to your MCP client config (e.g., Claude Code `claude_desktop_config.json`):
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"verusidx-chain": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["@verusidx/chain-mcp"],
|
|
15
|
+
"env": {}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Alternative: local install.** If you prefer a pinned version or offline use, install into a project directory with `npm install @verusidx/chain-mcp` (or `pnpm add` / `yarn add`) and point your config at the local path instead of using `npx`.
|
|
22
|
+
|
|
23
|
+
### Environment Variables
|
|
24
|
+
|
|
25
|
+
| Variable | Default | Description |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `VERUSIDX_READ_ONLY` | `false` | Set to `true` to disable write tools (`verusd`, `stop`, `sendrawtransaction`, `signrawtransaction`). Read tools and `refresh_chains` remain available. |
|
|
28
|
+
| `VERUSIDX_DATA_DIR` | OS default | Override the chain data directory for discovery. Defaults to `~/Library/Application Support/Komodo` (macOS), `~/.komodo` (Linux), `%AppData%\Komodo` (Windows). |
|
|
29
|
+
| `VERUSIDX_EXTRA_CHAINS` | — | Add remote daemons. Format: `name:host:port:user:pass`, comma-separated. Example: `remote-vrsc:192.168.1.50:27486:rpcuser:rpcpass` |
|
|
30
|
+
| `VERUSIDX_BIN_PATH` | — | Directory containing the `verusd` binary. If not set, searches PATH then OS-specific default locations. |
|
|
31
|
+
| `VERUSIDX_AUDIT_LOG` | `true` | Set to `false` to disable audit logging of write operations. |
|
|
32
|
+
| `VERUSIDX_AUDIT_DIR` | OS default | Custom directory for audit log files. Defaults to `~/.config/verusidx-mcp/audit` (Linux), `~/Library/Application Support/verusidx-mcp/audit` (macOS). |
|
|
33
|
+
|
|
34
|
+
### Read-Only Mode
|
|
35
|
+
|
|
36
|
+
Set `VERUSIDX_READ_ONLY=true` to run in read-only mode. This is useful for monitoring, research, or exploration — no blockchain state can be modified. Write tools are not registered (they won't appear in the tool list). If a stale client attempts to call a write tool anyway, it receives a `WRITE_DISABLED` error.
|
|
37
|
+
|
|
38
|
+
You can set read-only mode independently per MCP server. For example, keep chain-mcp read-write (for `refresh_chains` and daemon management) while running send-mcp in read-only mode.
|
|
39
|
+
|
|
40
|
+
## Tools
|
|
41
|
+
|
|
42
|
+
### Always available
|
|
43
|
+
|
|
44
|
+
| Tool | Description |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `getinfo` | Get blockchain and node info (version, block height, connections, sync status) |
|
|
47
|
+
| `getwalletinfo` | Get wallet balances (confirmed, unconfirmed, immature, reserve currencies) |
|
|
48
|
+
| `help` | Get daemon documentation for any RPC command |
|
|
49
|
+
| `getblockcount` | Get current block height (lightweight) |
|
|
50
|
+
| `getcurrency` | Get full definition and state of a currency (reserves, weights, prices, fees) |
|
|
51
|
+
| `getnewaddress` | Generate a new transparent R-address for receiving payments |
|
|
52
|
+
| `z_getnewaddress` | Generate a new shielded Sapling address (zs-address) for private transactions |
|
|
53
|
+
| `status` | Check registry freshness and daemon reachability |
|
|
54
|
+
| `refresh_chains` | Re-run chain discovery and rewrite the registry file |
|
|
55
|
+
|
|
56
|
+
### Write tools (disabled in read-only mode)
|
|
57
|
+
|
|
58
|
+
| Tool | Description |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `stop` | Stop a running daemon (terminates the process for ALL clients) |
|
|
61
|
+
| `verusd` | Start a Verus daemon instance (spawns detached process) |
|
|
62
|
+
| `sendrawtransaction` | Broadcast a signed raw transaction to the network |
|
|
63
|
+
| `signrawtransaction` | Sign inputs of a raw transaction (for multisig workflows) |
|
|
64
|
+
|
|
65
|
+
## Chain Registry
|
|
66
|
+
|
|
67
|
+
On first run, call `refresh_chains` to discover local chains. The server scans for `.conf` files in the chain data directory and PBaaS directory, checks which daemons are running, and writes a registry file (`chains.json`). All other verusidx MCP servers read this file to know what chains are available.
|
|
68
|
+
|
|
69
|
+
Every tool that talks to a daemon requires a `chain` parameter (e.g., `"VRSC"`, `"vrsctest"`). There is no default chain — the agent or user always specifies which chain to operate on.
|
|
70
|
+
|
|
71
|
+
## Audit Logging
|
|
72
|
+
|
|
73
|
+
All write operations (`stop`, `verusd`, `sendrawtransaction`, `signrawtransaction`, `refresh_chains`) are logged to date-stamped JSONL files in the audit directory. Each entry records the tool name, chain, parameters, result, and success status. Logs are append-only with `0600` permissions.
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Node.js >= 18.0.0
|
|
78
|
+
- At least one Verus daemon installed (for `verusd` tool) or already running (for RPC tools)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type RpcCredentials, type ChainRegistry } from '@verusidx/shared';
|
|
2
|
+
export type PingResult = {
|
|
3
|
+
running: true;
|
|
4
|
+
getinfo: Record<string, unknown>;
|
|
5
|
+
} | {
|
|
6
|
+
running: false;
|
|
7
|
+
error: string;
|
|
8
|
+
};
|
|
9
|
+
export interface DiscoveryResult {
|
|
10
|
+
registry: ChainRegistry;
|
|
11
|
+
reachability: Record<string, {
|
|
12
|
+
running: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Ping a daemon with a `getinfo` call using a short timeout.
|
|
18
|
+
*
|
|
19
|
+
* Does NOT use the shared rpcCall() because:
|
|
20
|
+
* - During first discovery, the registry doesn't exist yet
|
|
21
|
+
* - We need configurable timeout (6s default vs 30s in shared)
|
|
22
|
+
*/
|
|
23
|
+
export declare function pingChain(creds: RpcCredentials, timeoutMs?: number): Promise<PingResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Discover all chains (local + PBaaS + remote) and write the registry.
|
|
26
|
+
*
|
|
27
|
+
* This is the core logic behind the `refresh_chains` tool.
|
|
28
|
+
*/
|
|
29
|
+
export declare function discoverChains(): Promise<DiscoveryResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Find the verusd binary path.
|
|
32
|
+
*
|
|
33
|
+
* Checks in order:
|
|
34
|
+
* 1. VERUSIDX_BIN_PATH env var (directory containing verusd)
|
|
35
|
+
* 2. PATH lookup via `which verusd`
|
|
36
|
+
* 3. OS-specific default locations from getVerusdDefaultPaths()
|
|
37
|
+
*/
|
|
38
|
+
export declare function findVerusdBinary(): string | null;
|
|
39
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,cAAc,EAInB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,GAAG;IACF,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAMD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,cAAc,EACrB,SAAS,SAAO,GACf,OAAO,CAAC,UAAU,CAAC,CAkCrB;AA6MD;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CA2E/D;AAMD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAmChD"}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { readdirSync, accessSync, existsSync, constants } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { parseConfFile, getChainDataDir, getPbaasDir, getVerusdDefaultPaths, writeRegistry, } from '@verusidx/shared';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Ping — lightweight getinfo with short timeout
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
/**
|
|
9
|
+
* Ping a daemon with a `getinfo` call using a short timeout.
|
|
10
|
+
*
|
|
11
|
+
* Does NOT use the shared rpcCall() because:
|
|
12
|
+
* - During first discovery, the registry doesn't exist yet
|
|
13
|
+
* - We need configurable timeout (6s default vs 30s in shared)
|
|
14
|
+
*/
|
|
15
|
+
export async function pingChain(creds, timeoutMs = 6000) {
|
|
16
|
+
const url = `http://${creds.host}:${creds.port}`;
|
|
17
|
+
const credentials = Buffer.from(`${creds.user}:${creds.password}`).toString('base64');
|
|
18
|
+
try {
|
|
19
|
+
const response = await fetch(url, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'text/plain',
|
|
23
|
+
'Authorization': `Basic ${credentials}`,
|
|
24
|
+
},
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
jsonrpc: '1.0',
|
|
27
|
+
id: 'ping',
|
|
28
|
+
method: 'getinfo',
|
|
29
|
+
params: [],
|
|
30
|
+
}),
|
|
31
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
return { running: false, error: `HTTP ${response.status}` };
|
|
35
|
+
}
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
if (data.error || !data.result) {
|
|
38
|
+
return { running: false, error: 'getinfo returned error' };
|
|
39
|
+
}
|
|
40
|
+
return { running: true, getinfo: data.result };
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
44
|
+
return { running: false, error: msg };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Scan the Komodo data directory for chains with .conf files.
|
|
49
|
+
* Respects VERUSIDX_DATA_DIR override.
|
|
50
|
+
*/
|
|
51
|
+
function scanKomodoDir() {
|
|
52
|
+
const dataDir = process.env.VERUSIDX_DATA_DIR || getChainDataDir();
|
|
53
|
+
const results = [];
|
|
54
|
+
let dirs;
|
|
55
|
+
try {
|
|
56
|
+
dirs = readdirSync(dataDir, { withFileTypes: true })
|
|
57
|
+
.filter(d => d.isDirectory())
|
|
58
|
+
.map(d => d.name);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return results;
|
|
62
|
+
}
|
|
63
|
+
for (const dir of dirs) {
|
|
64
|
+
const confPath = join(dataDir, dir, `${dir}.conf`);
|
|
65
|
+
if (!existsSync(confPath))
|
|
66
|
+
continue;
|
|
67
|
+
const conf = parseConfFile(confPath);
|
|
68
|
+
if (!conf?.rpcuser || !conf?.rpcpassword)
|
|
69
|
+
continue;
|
|
70
|
+
const port = conf.rpcport ? parseInt(conf.rpcport, 10) : undefined;
|
|
71
|
+
if (!port || isNaN(port))
|
|
72
|
+
continue;
|
|
73
|
+
const host = conf.rpchost || '127.0.0.1';
|
|
74
|
+
const entry = { confPath, host, port };
|
|
75
|
+
const creds = { host, port, user: conf.rpcuser, password: conf.rpcpassword };
|
|
76
|
+
results.push({ name: dir, entry, creds });
|
|
77
|
+
}
|
|
78
|
+
return results;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Scan the PBaaS directory for chains with hex-encoded folder names.
|
|
82
|
+
* Returns a map of hex folder name → scanned chain data.
|
|
83
|
+
*/
|
|
84
|
+
function scanPbaasDir() {
|
|
85
|
+
const pbaasDir = getPbaasDir();
|
|
86
|
+
const results = new Map();
|
|
87
|
+
let dirs;
|
|
88
|
+
try {
|
|
89
|
+
dirs = readdirSync(pbaasDir, { withFileTypes: true })
|
|
90
|
+
.filter(d => d.isDirectory())
|
|
91
|
+
.map(d => d.name);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
for (const dir of dirs) {
|
|
97
|
+
// PBaaS dirs may have a .conf file with a different name pattern
|
|
98
|
+
// Look for any .conf file in the directory
|
|
99
|
+
let confFiles;
|
|
100
|
+
try {
|
|
101
|
+
confFiles = readdirSync(join(pbaasDir, dir))
|
|
102
|
+
.filter(f => f.endsWith('.conf'));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (confFiles.length === 0)
|
|
108
|
+
continue;
|
|
109
|
+
const confPath = join(pbaasDir, dir, confFiles[0]);
|
|
110
|
+
const conf = parseConfFile(confPath);
|
|
111
|
+
if (!conf?.rpcuser || !conf?.rpcpassword)
|
|
112
|
+
continue;
|
|
113
|
+
const port = conf.rpcport ? parseInt(conf.rpcport, 10) : undefined;
|
|
114
|
+
if (!port || isNaN(port))
|
|
115
|
+
continue;
|
|
116
|
+
const host = conf.rpchost || '127.0.0.1';
|
|
117
|
+
const entry = { confPath, host, port };
|
|
118
|
+
const creds = { host, port, user: conf.rpcuser, password: conf.rpcpassword };
|
|
119
|
+
results.set(dir, { name: dir, entry, creds });
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve PBaaS hex folder names to friendly names via the VRSC daemon.
|
|
125
|
+
*
|
|
126
|
+
* Calls `listcurrencies {"systemtype":"pbaas"}` on VRSC and matches
|
|
127
|
+
* `currencyidhex` to hex folder names. Unresolved hex names are kept as-is.
|
|
128
|
+
*
|
|
129
|
+
* Best-effort — if VRSC isn't running, returns entries with hex names.
|
|
130
|
+
*/
|
|
131
|
+
async function resolvePbaasNames(hexEntries, vrscCreds) {
|
|
132
|
+
if (hexEntries.size === 0)
|
|
133
|
+
return [];
|
|
134
|
+
const resolved = [];
|
|
135
|
+
const unresolved = new Map(hexEntries);
|
|
136
|
+
if (vrscCreds) {
|
|
137
|
+
try {
|
|
138
|
+
const pingResult = await pingChain(vrscCreds);
|
|
139
|
+
if (pingResult.running) {
|
|
140
|
+
// Make a direct RPC call to listcurrencies on VRSC
|
|
141
|
+
const url = `http://${vrscCreds.host}:${vrscCreds.port}`;
|
|
142
|
+
const credentials = Buffer.from(`${vrscCreds.user}:${vrscCreds.password}`).toString('base64');
|
|
143
|
+
const response = await fetch(url, {
|
|
144
|
+
method: 'POST',
|
|
145
|
+
headers: {
|
|
146
|
+
'Content-Type': 'text/plain',
|
|
147
|
+
'Authorization': `Basic ${credentials}`,
|
|
148
|
+
},
|
|
149
|
+
body: JSON.stringify({
|
|
150
|
+
jsonrpc: '1.0',
|
|
151
|
+
id: 'listcurrencies',
|
|
152
|
+
method: 'listcurrencies',
|
|
153
|
+
params: [{ systemtype: 'pbaas' }],
|
|
154
|
+
}),
|
|
155
|
+
signal: AbortSignal.timeout(15000),
|
|
156
|
+
});
|
|
157
|
+
if (response.ok) {
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
if (data.result) {
|
|
160
|
+
for (const currency of data.result) {
|
|
161
|
+
const hex = currency.currencydefinition?.currencyidhex;
|
|
162
|
+
const name = currency.currencydefinition?.fullyqualifiedname;
|
|
163
|
+
if (hex && name && unresolved.has(hex)) {
|
|
164
|
+
const scanned = unresolved.get(hex);
|
|
165
|
+
resolved.push({ ...scanned, name });
|
|
166
|
+
unresolved.delete(hex);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Best-effort — keep hex names
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Add unresolved entries with their hex folder names
|
|
178
|
+
for (const [, scanned] of unresolved) {
|
|
179
|
+
resolved.push(scanned);
|
|
180
|
+
}
|
|
181
|
+
return resolved;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Parse VERUSIDX_EXTRA_CHAINS env var for remote daemons.
|
|
185
|
+
* Format: name:host:port:user:pass, comma-separated
|
|
186
|
+
*/
|
|
187
|
+
function parseExtraChains() {
|
|
188
|
+
const envVal = process.env.VERUSIDX_EXTRA_CHAINS;
|
|
189
|
+
if (!envVal)
|
|
190
|
+
return [];
|
|
191
|
+
const results = [];
|
|
192
|
+
for (const part of envVal.split(',')) {
|
|
193
|
+
const trimmed = part.trim();
|
|
194
|
+
if (!trimmed)
|
|
195
|
+
continue;
|
|
196
|
+
const segments = trimmed.split(':');
|
|
197
|
+
if (segments.length < 5)
|
|
198
|
+
continue;
|
|
199
|
+
const [name, host, portStr, user, ...passwordParts] = segments;
|
|
200
|
+
const port = parseInt(portStr, 10);
|
|
201
|
+
if (!name || !host || isNaN(port) || !user)
|
|
202
|
+
continue;
|
|
203
|
+
// Password may contain colons, rejoin remaining segments
|
|
204
|
+
const password = passwordParts.join(':');
|
|
205
|
+
if (!password)
|
|
206
|
+
continue;
|
|
207
|
+
results.push({
|
|
208
|
+
name,
|
|
209
|
+
entry: { host, port, user, password },
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return results;
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// Main discovery
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
/**
|
|
218
|
+
* Discover all chains (local + PBaaS + remote) and write the registry.
|
|
219
|
+
*
|
|
220
|
+
* This is the core logic behind the `refresh_chains` tool.
|
|
221
|
+
*/
|
|
222
|
+
export async function discoverChains() {
|
|
223
|
+
// 1. Scan Komodo data dir
|
|
224
|
+
const komodoChains = scanKomodoDir();
|
|
225
|
+
// 2. Scan PBaaS dir
|
|
226
|
+
const pbaasHexEntries = scanPbaasDir();
|
|
227
|
+
// 3. Find VRSC credentials for PBaaS name resolution
|
|
228
|
+
const vrscChain = komodoChains.find(c => c.name === 'VRSC');
|
|
229
|
+
const vrscCreds = vrscChain?.creds ?? null;
|
|
230
|
+
// 4. Resolve PBaaS hex names
|
|
231
|
+
const pbaasChains = await resolvePbaasNames(pbaasHexEntries, vrscCreds);
|
|
232
|
+
// 5. Parse extra chains
|
|
233
|
+
const extraChains = parseExtraChains();
|
|
234
|
+
// 6. Build chains record (deduplicate: Komodo wins over PBaaS for same name)
|
|
235
|
+
const chains = {};
|
|
236
|
+
for (const c of komodoChains) {
|
|
237
|
+
chains[c.name] = c.entry;
|
|
238
|
+
}
|
|
239
|
+
for (const c of pbaasChains) {
|
|
240
|
+
if (!chains[c.name]) {
|
|
241
|
+
chains[c.name] = c.entry;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
for (const c of extraChains) {
|
|
245
|
+
chains[c.name] = c.entry;
|
|
246
|
+
}
|
|
247
|
+
// 7. Check reachability for all chains
|
|
248
|
+
const reachability = {};
|
|
249
|
+
// Build a creds map for pinging
|
|
250
|
+
const credsMap = new Map();
|
|
251
|
+
for (const c of komodoChains) {
|
|
252
|
+
if (c.creds)
|
|
253
|
+
credsMap.set(c.name, c.creds);
|
|
254
|
+
}
|
|
255
|
+
for (const c of pbaasChains) {
|
|
256
|
+
if (c.creds)
|
|
257
|
+
credsMap.set(c.name, c.creds);
|
|
258
|
+
}
|
|
259
|
+
for (const c of extraChains) {
|
|
260
|
+
credsMap.set(c.name, {
|
|
261
|
+
host: c.entry.host,
|
|
262
|
+
port: c.entry.port,
|
|
263
|
+
user: c.entry.user,
|
|
264
|
+
password: c.entry.password,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
const pingPromises = Object.keys(chains).map(async (name) => {
|
|
268
|
+
const creds = credsMap.get(name);
|
|
269
|
+
if (!creds) {
|
|
270
|
+
reachability[name] = { running: false, error: 'No credentials' };
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const result = await pingChain(creds);
|
|
274
|
+
reachability[name] = result.running
|
|
275
|
+
? { running: true }
|
|
276
|
+
: { running: false, error: result.error };
|
|
277
|
+
});
|
|
278
|
+
await Promise.allSettled(pingPromises);
|
|
279
|
+
// 8. Build and write registry
|
|
280
|
+
const registry = {
|
|
281
|
+
version: 1,
|
|
282
|
+
discoveredAt: new Date().toISOString(),
|
|
283
|
+
chains,
|
|
284
|
+
};
|
|
285
|
+
writeRegistry(registry);
|
|
286
|
+
return { registry, reachability };
|
|
287
|
+
}
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
// verusd binary discovery
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
/**
|
|
292
|
+
* Find the verusd binary path.
|
|
293
|
+
*
|
|
294
|
+
* Checks in order:
|
|
295
|
+
* 1. VERUSIDX_BIN_PATH env var (directory containing verusd)
|
|
296
|
+
* 2. PATH lookup via `which verusd`
|
|
297
|
+
* 3. OS-specific default locations from getVerusdDefaultPaths()
|
|
298
|
+
*/
|
|
299
|
+
export function findVerusdBinary() {
|
|
300
|
+
// 1. Env var — directory containing verusd
|
|
301
|
+
const binPath = process.env.VERUSIDX_BIN_PATH;
|
|
302
|
+
if (binPath) {
|
|
303
|
+
const candidate = join(binPath, 'verusd');
|
|
304
|
+
try {
|
|
305
|
+
accessSync(candidate, constants.X_OK);
|
|
306
|
+
return candidate;
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
// Env var set but binary not found at that path
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// 2. PATH lookup
|
|
313
|
+
try {
|
|
314
|
+
const result = execFileSync('which', ['verusd'], {
|
|
315
|
+
encoding: 'utf-8',
|
|
316
|
+
timeout: 5000,
|
|
317
|
+
}).trim();
|
|
318
|
+
if (result)
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// Not on PATH
|
|
323
|
+
}
|
|
324
|
+
// 3. OS-specific defaults
|
|
325
|
+
for (const candidate of getVerusdDefaultPaths()) {
|
|
326
|
+
try {
|
|
327
|
+
accessSync(candidate, constants.X_OK);
|
|
328
|
+
return candidate;
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { registerTools } from './tools.js';
|
|
5
|
+
const server = new McpServer({
|
|
6
|
+
name: 'verusidx-chain-mcp',
|
|
7
|
+
version: '0.1.0',
|
|
8
|
+
});
|
|
9
|
+
registerTools(server);
|
|
10
|
+
const transport = new StdioServerTransport();
|
|
11
|
+
await server.connect(transport);
|
|
12
|
+
process.on('SIGINT', async () => {
|
|
13
|
+
await server.close();
|
|
14
|
+
process.exit(0);
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,oBAAoB;IAC1B,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/build/tools.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqEzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAudrD"}
|
package/build/tools.js
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { rpcCall, RegistryReader, auditLog, isReadOnly, assertWriteEnabled, VerusError, getRegistryPath, parseConfFile, getChainConfPath, } from '@verusidx/shared';
|
|
4
|
+
import { discoverChains, findVerusdBinary, pingChain } from './discovery.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Response helpers
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
function ok(data) {
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function fail(category, message) {
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: 'text', text: JSON.stringify({ error: category, message }, null, 2) }],
|
|
16
|
+
isError: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function handleError(err) {
|
|
20
|
+
if (err instanceof VerusError) {
|
|
21
|
+
return fail(err.category, err.message);
|
|
22
|
+
}
|
|
23
|
+
return fail('INTERNAL_ERROR', err instanceof Error ? err.message : 'Unknown error');
|
|
24
|
+
}
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Utilities
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
function relativeTime(isoDate) {
|
|
29
|
+
const then = new Date(isoDate).getTime();
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const diffMs = now - then;
|
|
32
|
+
if (diffMs < 0)
|
|
33
|
+
return 'just now';
|
|
34
|
+
const seconds = Math.floor(diffMs / 1000);
|
|
35
|
+
if (seconds < 60)
|
|
36
|
+
return `${seconds} seconds ago`;
|
|
37
|
+
const minutes = Math.floor(seconds / 60);
|
|
38
|
+
if (minutes < 60)
|
|
39
|
+
return `${minutes} minute${minutes === 1 ? '' : 's'} ago`;
|
|
40
|
+
const hours = Math.floor(minutes / 60);
|
|
41
|
+
if (hours < 24)
|
|
42
|
+
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
|
|
43
|
+
const days = Math.floor(hours / 24);
|
|
44
|
+
return `${days} day${days === 1 ? '' : 's'} ago`;
|
|
45
|
+
}
|
|
46
|
+
const SERVER_NAME = 'verusidx-chain-mcp';
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Tool registration
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
export function registerTools(server) {
|
|
51
|
+
// ------ Read-only tools (always registered) ------
|
|
52
|
+
server.tool('getinfo', 'Get blockchain and node information for a running chain. Returns version, block height, connections, difficulty, sync status, and fee configuration. Use this to check whether a daemon is running and synced before performing operations on that chain.', { chain: z.string().describe('Chain to query (e.g., "VRSC", "vrsctest")') }, async ({ chain }) => {
|
|
53
|
+
try {
|
|
54
|
+
const result = await rpcCall(chain, 'getinfo', []);
|
|
55
|
+
return ok(result);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
return handleError(err);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
server.tool('getwalletinfo', 'Get wallet state for a running chain. Returns balances (confirmed, unconfirmed, immature, staking-eligible), reserve currency balances, transaction count, and key pool status. Use this for a quick overview of wallet health and native + reserve currency holdings. Note: reserve_balance is an object keyed by currency name, showing all non-native currencies held in the wallet.', { chain: z.string().describe('Chain to query (e.g., "VRSC", "vrsctest")') }, async ({ chain }) => {
|
|
62
|
+
try {
|
|
63
|
+
const result = await rpcCall(chain, 'getwalletinfo', []);
|
|
64
|
+
return ok(result);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return handleError(err);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
server.tool('help', 'Get daemon documentation for any RPC command. With no command argument, returns a list of all available RPCs grouped by category. With a command name, returns detailed usage including parameters, types, and examples. Use this when an agent needs to understand an RPC that isn\'t exposed as an MCP tool, or to check exact parameter formats before constructing a complex call.', {
|
|
71
|
+
chain: z.string().describe('Chain to query (e.g., "VRSC", "vrsctest")'),
|
|
72
|
+
command: z.string().optional().describe('RPC command name to get help for (e.g., "sendcurrency", "getidentity"). Omit to list all commands.'),
|
|
73
|
+
}, async ({ chain, command }) => {
|
|
74
|
+
try {
|
|
75
|
+
const params = command ? [command] : [];
|
|
76
|
+
const result = await rpcCall(chain, 'help', params);
|
|
77
|
+
// help returns a plain string from the daemon
|
|
78
|
+
const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
79
|
+
return { content: [{ type: 'text', text }] };
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
return handleError(err);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
server.tool('getblockcount', 'Get the current block count (height of the longest chain). Returns a single number — the most lightweight way to check the current block height. Use this for polling block progress, such as waiting for a name commitment to confirm before calling registeridentity.', { chain: z.string().describe('Chain to query (e.g., "VRSC", "vrsctest")') }, async ({ chain }) => {
|
|
86
|
+
try {
|
|
87
|
+
const result = await rpcCall(chain, 'getblockcount', []);
|
|
88
|
+
return ok(result);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return handleError(err);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
server.tool('getcurrency', 'Get the full definition and current state of a currency. Returns the currency\'s configuration (reserves, weights, fees, preallocations, eras) and its latest on-chain state (supply, reserve balances, conversion prices). Use this to check if a currency exists, understand its structure (simple token vs. fractional basket), read current reserve ratios and conversion prices before performing conversions, or look up registration fees before registering identities or defining currencies on a specific chain. Fee interpretation: idregistrationfees is the fee amount. For basket currencies, if idimportfees is a satoshi-scale value it encodes which reserve currency the fee is denominated in: 0.00000000 = first reserve (index 0), 0.00000001 = second reserve (index 1), etc. Default idimportfees (e.g., 0.02) means the fee is in the basket currency itself, but defaults may differ per chain.', {
|
|
95
|
+
chain: z.string().describe('Chain to query (e.g., "VRSC", "vrsctest")'),
|
|
96
|
+
currencyname: z.string().describe('Currency name (e.g., "bitcoins", "NATI🦉") or i-address. Also accepts "hex:<currencyidhex>" format.'),
|
|
97
|
+
}, async ({ chain, currencyname }) => {
|
|
98
|
+
try {
|
|
99
|
+
const result = await rpcCall(chain, 'getcurrency', [currencyname]);
|
|
100
|
+
return ok(result);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return handleError(err);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
server.tool('getnewaddress', 'Generate a new transparent (R-address) for receiving payments. Use this to create fresh addresses for identity primaryaddresses, change addresses, or destination addresses. Each call generates a unique address from the wallet\'s keypool.', { chain: z.string().describe('Chain to generate address on (e.g., "VRSC", "vrsctest")') }, async ({ chain }) => {
|
|
107
|
+
try {
|
|
108
|
+
const result = await rpcCall(chain, 'getnewaddress', []);
|
|
109
|
+
return ok(result);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
return handleError(err);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
server.tool('z_getnewaddress', 'Generate a new shielded Sapling address (zs-address) for private transactions. Use this to create addresses for identity privateaddress fields or private sends. Each call generates a unique shielded address.', { chain: z.string().describe('Chain to generate address on (e.g., "VRSC", "vrsctest")') }, async ({ chain }) => {
|
|
116
|
+
try {
|
|
117
|
+
const result = await rpcCall(chain, 'z_getnewaddress', ['sapling']);
|
|
118
|
+
return ok(result);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
return handleError(err);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
server.tool('status', 'Check registry freshness and daemon reachability. Use this to verify chain health before starting a workflow, or to debug why calls to other MCPs are failing. Without a chain parameter, returns an overview of all registered chains. With a chain parameter, returns detailed status for that specific chain.', {
|
|
125
|
+
chain: z.string().optional().describe('Specific chain to check. Omit for an overview of all registered chains.'),
|
|
126
|
+
}, async ({ chain }) => {
|
|
127
|
+
try {
|
|
128
|
+
const reader = new RegistryReader();
|
|
129
|
+
const registry = reader.read();
|
|
130
|
+
if (!registry) {
|
|
131
|
+
return fail('CONNECTION_FAILED', 'No chain registry found. Run refresh_chains to discover chains.');
|
|
132
|
+
}
|
|
133
|
+
const discoveredAt = registry.discoveredAt;
|
|
134
|
+
const registryAge = relativeTime(discoveredAt);
|
|
135
|
+
if (chain) {
|
|
136
|
+
// Single chain status
|
|
137
|
+
const entry = registry.chains[chain];
|
|
138
|
+
if (!entry) {
|
|
139
|
+
return fail('CONNECTION_FAILED', `Chain "${chain}" not found in registry. Run refresh_chains to update.`);
|
|
140
|
+
}
|
|
141
|
+
const creds = reader.resolveCredentials(entry);
|
|
142
|
+
if (!creds) {
|
|
143
|
+
return ok({
|
|
144
|
+
chain,
|
|
145
|
+
reachable: false,
|
|
146
|
+
error: 'Cannot resolve credentials',
|
|
147
|
+
registry_age: registryAge,
|
|
148
|
+
registry_discovered_at: discoveredAt,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const pingResult = await pingChain(creds);
|
|
152
|
+
if (pingResult.running) {
|
|
153
|
+
const info = pingResult.getinfo;
|
|
154
|
+
return ok({
|
|
155
|
+
chain,
|
|
156
|
+
reachable: true,
|
|
157
|
+
blocks: info.blocks,
|
|
158
|
+
connections: info.connections,
|
|
159
|
+
synced: typeof info.longestchain === 'number' && info.blocks === info.longestchain,
|
|
160
|
+
version: info.version,
|
|
161
|
+
testnet: info.testnet,
|
|
162
|
+
registry_age: registryAge,
|
|
163
|
+
registry_discovered_at: discoveredAt,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return ok({
|
|
167
|
+
chain,
|
|
168
|
+
reachable: false,
|
|
169
|
+
error: pingResult.error,
|
|
170
|
+
registry_age: registryAge,
|
|
171
|
+
registry_discovered_at: discoveredAt,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// All chains overview
|
|
175
|
+
const chainsStatus = {};
|
|
176
|
+
const chainNames = Object.keys(registry.chains);
|
|
177
|
+
const pingPromises = chainNames.map(async (name) => {
|
|
178
|
+
const entry = registry.chains[name];
|
|
179
|
+
const creds = reader.resolveCredentials(entry);
|
|
180
|
+
if (!creds) {
|
|
181
|
+
chainsStatus[name] = { reachable: false, error: 'Cannot resolve credentials' };
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const pingResult = await pingChain(creds);
|
|
185
|
+
if (pingResult.running) {
|
|
186
|
+
const info = pingResult.getinfo;
|
|
187
|
+
chainsStatus[name] = {
|
|
188
|
+
reachable: true,
|
|
189
|
+
blocks: info.blocks,
|
|
190
|
+
connections: info.connections,
|
|
191
|
+
synced: typeof info.longestchain === 'number' && info.blocks === info.longestchain,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
chainsStatus[name] = {
|
|
196
|
+
reachable: false,
|
|
197
|
+
error: pingResult.error,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
await Promise.allSettled(pingPromises);
|
|
202
|
+
return ok({
|
|
203
|
+
registry_age: registryAge,
|
|
204
|
+
registry_discovered_at: discoveredAt,
|
|
205
|
+
chains: chainsStatus,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
return handleError(err);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
server.tool('refresh_chains', 'Re-run chain discovery and rewrite the chain registry file. Call this after starting a new daemon, stopping a daemon, or when the registry appears stale. Discovery scans OS-appropriate data directories for .conf files, parses them, and calls getinfo on each discovered chain to confirm it\'s running. PBaaS chains with hex-encoded folder names are resolved to friendly names via the VRSC daemon. The updated registry is written atomically. Available in read-only mode.', {}, async () => {
|
|
213
|
+
try {
|
|
214
|
+
const result = await discoverChains();
|
|
215
|
+
const chainsSummary = {};
|
|
216
|
+
let runningCount = 0;
|
|
217
|
+
for (const [name, entry] of Object.entries(result.registry.chains)) {
|
|
218
|
+
const reachable = result.reachability[name];
|
|
219
|
+
const running = reachable?.running ?? false;
|
|
220
|
+
if (running)
|
|
221
|
+
runningCount++;
|
|
222
|
+
chainsSummary[name] = {
|
|
223
|
+
host: entry.host,
|
|
224
|
+
port: entry.port,
|
|
225
|
+
running,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const discovered = Object.keys(chainsSummary).length;
|
|
229
|
+
auditLog({
|
|
230
|
+
server: SERVER_NAME,
|
|
231
|
+
tool: 'refresh_chains',
|
|
232
|
+
chain: '*',
|
|
233
|
+
params: {},
|
|
234
|
+
result: { discovered, running: runningCount },
|
|
235
|
+
success: true,
|
|
236
|
+
});
|
|
237
|
+
return ok({
|
|
238
|
+
discovered,
|
|
239
|
+
chains: chainsSummary,
|
|
240
|
+
registry_path: getRegistryPath(),
|
|
241
|
+
message: `Registry updated. ${runningCount} of ${discovered} discovered chains are running.`,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
return handleError(err);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
// ------ Write tools (registered only when not read-only) ------
|
|
249
|
+
if (!isReadOnly()) {
|
|
250
|
+
server.tool('stop', 'Stop a running daemon. This shuts down the daemon process for the specified chain entirely — ALL connected clients, MCP servers, CLI users, and applications connected to this daemon will lose connectivity. This is not a per-session disconnect; it terminates the daemon. After stopping, the chain will no longer be reachable. Consider calling refresh_chains after stopping so other MCPs see the updated state.', {
|
|
251
|
+
chain: z.string().describe('Chain whose daemon to stop (e.g., "VRSC", "vrsctest")'),
|
|
252
|
+
reason: z.string().optional().describe('Reason for stopping. Not sent to the daemon — recorded only in the local audit log for accountability.'),
|
|
253
|
+
}, async ({ chain, reason }) => {
|
|
254
|
+
try {
|
|
255
|
+
assertWriteEnabled();
|
|
256
|
+
const result = await rpcCall(chain, 'stop', []);
|
|
257
|
+
auditLog({
|
|
258
|
+
server: SERVER_NAME,
|
|
259
|
+
tool: 'stop',
|
|
260
|
+
chain,
|
|
261
|
+
params: { reason },
|
|
262
|
+
result,
|
|
263
|
+
success: true,
|
|
264
|
+
});
|
|
265
|
+
return ok(result);
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
return handleError(err);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
server.tool('verusd', 'Start a Verus daemon instance. This is a system command that spawns a new process — it is NOT an RPC call to an existing daemon. The daemon runs independently of this MCP server (detached process). After starting, the tool waits briefly and verifies the daemon launched successfully via getinfo. Call refresh_chains after a successful start so other MCPs can discover the new daemon.', {
|
|
272
|
+
chain: z.string().optional().describe('Chain to start. Omit for VRSC mainnet. For other chains, provide the chain name (e.g., "vrsctest"). Maps to the -chain= flag.'),
|
|
273
|
+
bootstrap: z.boolean().optional().describe('Start with -bootstrap flag for faster initial sync. Only useful on first start or after a long time offline. Default: false.'),
|
|
274
|
+
extra_args: z.array(z.string()).optional().describe('Additional command-line arguments passed to verusd (e.g., ["-reindex"]).'),
|
|
275
|
+
}, async ({ chain, bootstrap, extra_args }) => {
|
|
276
|
+
try {
|
|
277
|
+
assertWriteEnabled();
|
|
278
|
+
const binaryPath = findVerusdBinary();
|
|
279
|
+
if (!binaryPath) {
|
|
280
|
+
return fail('RPC_ERROR', 'verusd binary not found — set VERUSIDX_BIN_PATH or add verusd to your PATH');
|
|
281
|
+
}
|
|
282
|
+
const effectiveChain = chain || 'VRSC';
|
|
283
|
+
// Check if daemon is already running
|
|
284
|
+
const confPath = getChainConfPath(effectiveChain);
|
|
285
|
+
const conf = parseConfFile(confPath);
|
|
286
|
+
if (conf?.rpcuser && conf?.rpcpassword && conf?.rpcport) {
|
|
287
|
+
const port = parseInt(conf.rpcport, 10);
|
|
288
|
+
if (!isNaN(port)) {
|
|
289
|
+
const creds = {
|
|
290
|
+
host: conf.rpchost || '127.0.0.1',
|
|
291
|
+
port,
|
|
292
|
+
user: conf.rpcuser,
|
|
293
|
+
password: conf.rpcpassword,
|
|
294
|
+
};
|
|
295
|
+
const alreadyRunning = await pingChain(creds);
|
|
296
|
+
if (alreadyRunning.running) {
|
|
297
|
+
return fail('RPC_ERROR', `Daemon for ${effectiveChain} appears to already be running (getinfo responded on port ${port})`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Build args
|
|
302
|
+
const args = ['-daemon'];
|
|
303
|
+
if (chain) {
|
|
304
|
+
args.push(`-chain=${chain}`);
|
|
305
|
+
}
|
|
306
|
+
if (bootstrap) {
|
|
307
|
+
args.push('-bootstrap');
|
|
308
|
+
}
|
|
309
|
+
if (extra_args) {
|
|
310
|
+
args.push(...extra_args);
|
|
311
|
+
}
|
|
312
|
+
// Spawn detached
|
|
313
|
+
const child = spawn(binaryPath, args, {
|
|
314
|
+
detached: true,
|
|
315
|
+
stdio: 'ignore',
|
|
316
|
+
});
|
|
317
|
+
const pid = child.pid;
|
|
318
|
+
child.unref();
|
|
319
|
+
// Wait for daemon to start
|
|
320
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
321
|
+
// Verify it started — re-read conf in case it was just created
|
|
322
|
+
let started = false;
|
|
323
|
+
const freshConf = parseConfFile(confPath);
|
|
324
|
+
if (freshConf?.rpcuser && freshConf?.rpcpassword && freshConf?.rpcport) {
|
|
325
|
+
const port = parseInt(freshConf.rpcport, 10);
|
|
326
|
+
if (!isNaN(port)) {
|
|
327
|
+
const creds = {
|
|
328
|
+
host: freshConf.rpchost || '127.0.0.1',
|
|
329
|
+
port,
|
|
330
|
+
user: freshConf.rpcuser,
|
|
331
|
+
password: freshConf.rpcpassword,
|
|
332
|
+
};
|
|
333
|
+
const verifyResult = await pingChain(creds);
|
|
334
|
+
started = verifyResult.running;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const resultData = started
|
|
338
|
+
? { started: true, chain: effectiveChain, pid, message: 'Daemon started. Run refresh_chains to update the chain registry.' }
|
|
339
|
+
: { started: false, chain: effectiveChain, pid, message: 'Daemon process spawned but getinfo did not respond yet. It may still be starting — try status in a few seconds.' };
|
|
340
|
+
auditLog({
|
|
341
|
+
server: SERVER_NAME,
|
|
342
|
+
tool: 'verusd',
|
|
343
|
+
chain: effectiveChain,
|
|
344
|
+
params: { chain, bootstrap, extra_args },
|
|
345
|
+
result: resultData,
|
|
346
|
+
success: started,
|
|
347
|
+
});
|
|
348
|
+
return ok(resultData);
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
return handleError(err);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
server.tool('sendrawtransaction', 'Broadcast a signed raw transaction to the network. Takes a hex-encoded signed transaction and submits it to the local node, which relays it to the network. Returns the transaction hash (txid) on success. This is the companion to definecurrency — definecurrency returns a signed hex that must be broadcast here. Also used for any pre-signed transaction hex.', {
|
|
355
|
+
chain: z.string().describe('Chain to broadcast on (e.g., "VRSC", "vrsctest")'),
|
|
356
|
+
hexstring: z.string().describe('The hex-encoded signed raw transaction'),
|
|
357
|
+
allowhighfees: z.boolean().optional().describe('Allow transactions with unusually high fees. Default: false.'),
|
|
358
|
+
}, async ({ chain, hexstring, allowhighfees }) => {
|
|
359
|
+
try {
|
|
360
|
+
assertWriteEnabled();
|
|
361
|
+
const params = [hexstring];
|
|
362
|
+
if (allowhighfees !== undefined)
|
|
363
|
+
params.push(allowhighfees);
|
|
364
|
+
const result = await rpcCall(chain, 'sendrawtransaction', params);
|
|
365
|
+
auditLog({
|
|
366
|
+
server: SERVER_NAME,
|
|
367
|
+
tool: 'sendrawtransaction',
|
|
368
|
+
chain,
|
|
369
|
+
params: { hexstring: hexstring.slice(0, 20) + '...', allowhighfees },
|
|
370
|
+
result,
|
|
371
|
+
success: true,
|
|
372
|
+
});
|
|
373
|
+
return ok(result);
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
return handleError(err);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
server.tool('signrawtransaction', 'Sign inputs of a raw transaction. Takes a hex-encoded transaction and signs it with keys available in the wallet (or with explicitly provided private keys). Returns the signed hex and whether all inputs are fully signed. Use this for multisig workflows where multiple parties need to sign. For definecurrency in the normal single-signer case, the hex is returned already signed — signrawtransaction is not needed.', {
|
|
380
|
+
chain: z.string().describe('Chain to sign for (e.g., "VRSC", "vrsctest")'),
|
|
381
|
+
hexstring: z.string().describe('The hex-encoded raw transaction to sign'),
|
|
382
|
+
prevtxs: z.array(z.object({
|
|
383
|
+
txid: z.string(),
|
|
384
|
+
vout: z.number(),
|
|
385
|
+
scriptPubKey: z.string(),
|
|
386
|
+
redeemScript: z.string().optional(),
|
|
387
|
+
amount: z.number(),
|
|
388
|
+
})).optional().describe('Array of previous dependent transaction outputs not yet in the blockchain.'),
|
|
389
|
+
privatekeys: z.array(z.string()).optional().describe('Array of base58-encoded private keys to use for signing. If provided, only these keys are used.'),
|
|
390
|
+
sighashtype: z.string().optional().describe('Signature hash type. Default: "ALL". Options: "ALL", "NONE", "SINGLE", "ALL|ANYONECANPAY", "NONE|ANYONECANPAY", "SINGLE|ANYONECANPAY".'),
|
|
391
|
+
}, async ({ chain, hexstring, prevtxs, privatekeys, sighashtype }) => {
|
|
392
|
+
try {
|
|
393
|
+
assertWriteEnabled();
|
|
394
|
+
// Build positional params — daemon expects: hexstring [prevtxs] [privatekeys] [sighashtype]
|
|
395
|
+
const params = [hexstring];
|
|
396
|
+
if (prevtxs !== undefined || privatekeys !== undefined || sighashtype !== undefined) {
|
|
397
|
+
params.push(prevtxs ?? null);
|
|
398
|
+
}
|
|
399
|
+
if (privatekeys !== undefined || sighashtype !== undefined) {
|
|
400
|
+
params.push(privatekeys ?? null);
|
|
401
|
+
}
|
|
402
|
+
if (sighashtype !== undefined) {
|
|
403
|
+
params.push(sighashtype);
|
|
404
|
+
}
|
|
405
|
+
const result = await rpcCall(chain, 'signrawtransaction', params);
|
|
406
|
+
auditLog({
|
|
407
|
+
server: SERVER_NAME,
|
|
408
|
+
tool: 'signrawtransaction',
|
|
409
|
+
chain,
|
|
410
|
+
params: { hexstring: hexstring.slice(0, 20) + '...', prevtxs: !!prevtxs, privatekeys: !!privatekeys, sighashtype },
|
|
411
|
+
result,
|
|
412
|
+
success: true,
|
|
413
|
+
});
|
|
414
|
+
return ok(result);
|
|
415
|
+
}
|
|
416
|
+
catch (err) {
|
|
417
|
+
return handleError(err);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@verusidx/chain-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Foundation MCP server — chain discovery, daemon management, health checks, raw transactions",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"verusidx-chain-mcp": "./build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18.0.0"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
18
|
+
"zod": "^3.23.0",
|
|
19
|
+
"@verusidx/shared": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.0.0",
|
|
23
|
+
"typescript": "^5.7.0",
|
|
24
|
+
"vitest": "^3.0.0"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"test": "vitest run"
|
|
29
|
+
}
|
|
30
|
+
}
|