obyte-mcp 0.1.2 → 0.2.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/README.md +76 -4
- package/dist/amounts.d.ts +43 -0
- package/dist/amounts.js +117 -0
- package/dist/amounts.js.map +1 -0
- package/dist/constants.d.ts +3 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/doctor.js +12 -0
- package/dist/doctor.js.map +1 -1
- package/dist/explorerClient.d.ts +39 -0
- package/dist/explorerClient.js +115 -0
- package/dist/explorerClient.js.map +1 -0
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/install.js +31 -11
- package/dist/install.js.map +1 -1
- package/dist/prompts.js +26 -18
- package/dist/prompts.js.map +1 -1
- package/dist/resources.js +8 -2
- package/dist/resources.js.map +1 -1
- package/dist/schemas.d.ts +8 -0
- package/dist/schemas.js +7 -0
- package/dist/schemas.js.map +1 -1
- package/dist/server.js +32 -1
- package/dist/server.js.map +1 -1
- package/dist/symbols.js +2 -1
- package/dist/symbols.js.map +1 -1
- package/dist/tools.js +101 -32
- package/dist/tools.js.map +1 -1
- package/dist/updateCheck.d.ts +16 -0
- package/dist/updateCheck.js +80 -0
- package/dist/updateCheck.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -179,6 +179,59 @@ it per call.
|
|
|
179
179
|
|
|
180
180
|
Inspect the live configuration for both networks any time with `obyte_get_network_info`.
|
|
181
181
|
|
|
182
|
+
## Amounts And Decimals
|
|
183
|
+
|
|
184
|
+
Raw hub data (balances, AA state vars, payment outputs, AA responses) carries amounts as
|
|
185
|
+
**integers in the asset's smallest units**. The base asset has 9 decimals: `2500000000` bytes
|
|
186
|
+
= `2.5 GBYTE`. Agents that skip this step report wrong numbers, so the server enforces it in
|
|
187
|
+
three ways:
|
|
188
|
+
|
|
189
|
+
- **Composite tools convert for you.** `obyte_analyze_address`, `obyte_analyze_aa`, and
|
|
190
|
+
`obyte_get_portfolio_summary` return a `totals_by_asset` / `balance_summary` block with
|
|
191
|
+
`symbol`, `decimals`, `raw_total`, and `display_total` (already divided by `10^decimals`).
|
|
192
|
+
Assets that cannot be resolved (e.g. no registry on testnet) are listed in
|
|
193
|
+
`unresolved_assets` with `display_total: null` — never presented as converted.
|
|
194
|
+
- **Server instructions and tool descriptions** tell agents to never show raw integers and to
|
|
195
|
+
resolve decimals via `obyte_resolve_asset` / `obyte_get_decimals_by_symbol_or_asset` first,
|
|
196
|
+
and to convert user-facing amounts *into* smallest units when building AA triggers.
|
|
197
|
+
- **Base aliases work without a registry**: decimals for `base`/`GBYTE`/`MBYTE`/`KBYTE`/`BYTE`
|
|
198
|
+
are answered locally, even on testnet with no registry configured.
|
|
199
|
+
|
|
200
|
+
### Asset holders
|
|
201
|
+
|
|
202
|
+
`obyte_get_asset_holders` returns the **top holders** of any asset (by symbol or asset id),
|
|
203
|
+
sorted by balance descending, with raw and display amounts plus total supply — up to 100
|
|
204
|
+
holders per call. The data comes from the Obyte explorer (a centralized convenience service,
|
|
205
|
+
separate from the hub) and may lag the ledger slightly.
|
|
206
|
+
|
|
207
|
+
For a human-browsable view, asset tools also return `explorer_asset_url`:
|
|
208
|
+
`https://explorer.obyte.org/asset/<symbol|asset>` (testnet:
|
|
209
|
+
`https://testnetexplorer.obyte.org/asset/<symbol|asset>`). Note: amounts on explorer web pages
|
|
210
|
+
are **already in display units** — only hub tool outputs need decimals conversion.
|
|
211
|
+
|
|
212
|
+
## Making Agents Use It Automatically
|
|
213
|
+
|
|
214
|
+
You should not have to tell your agent to use this server. Two mechanisms make it proactive:
|
|
215
|
+
|
|
216
|
+
1. **MCP server instructions.** At `initialize` the server sends instructions that hosts
|
|
217
|
+
(Claude Desktop, Claude Code, and others) inject into the agent's context: use `obyte_*`
|
|
218
|
+
tools whenever the user mentions Obyte, GBYTE/bytes, autonomous agents, or pastes an Obyte
|
|
219
|
+
identifier (addresses are 32-character base32 strings; unit hashes and asset ids are
|
|
220
|
+
44-character base64 strings usually ending in `=`), plus the network and decimals rules.
|
|
221
|
+
2. **Trigger-rich tool descriptions.** Each tool description states when to reach for it, so
|
|
222
|
+
hosts that only surface descriptions still route correctly.
|
|
223
|
+
|
|
224
|
+
For hosts that ignore server instructions (or to make it extra reliable in a specific project),
|
|
225
|
+
add a line to your project memory file — `CLAUDE.md` (Claude Code) or `AGENTS.md` (Codex):
|
|
226
|
+
|
|
227
|
+
```markdown
|
|
228
|
+
For anything involving Obyte, GBYTE, bytes, autonomous agents (AAs), Obyte units/addresses,
|
|
229
|
+
or Obyte token symbols, use the obyte MCP server tools (obyte_analyze_address,
|
|
230
|
+
obyte_analyze_unit, obyte_analyze_aa, obyte_resolve_asset, obyte_get_portfolio_summary,
|
|
231
|
+
obyte_prepare_aa_dry_run) without being asked. Pass network:"testnet" for testnet questions.
|
|
232
|
+
Never show raw smallest-unit amounts: use display_total fields or resolve decimals first.
|
|
233
|
+
```
|
|
234
|
+
|
|
182
235
|
## Configuration
|
|
183
236
|
|
|
184
237
|
Precedence, highest first:
|
|
@@ -200,6 +253,7 @@ Precedence, highest first:
|
|
|
200
253
|
| `OBYTE_REQUEST_TIMEOUT_MS` | `--timeout-ms` | both | `20000` | Hub request timeout, `1000..120000` |
|
|
201
254
|
| `OBYTE_MAX_CONCURRENCY` | `--max-concurrency` | both | `4` | Concurrent hub requests, `1..10` |
|
|
202
255
|
| `OBYTE_MAX_OUTPUT_BYTES` | `--max-output-bytes` | both | `262144` | Max tool output bytes, `16384..1048576` |
|
|
256
|
+
| `OBYTE_NO_UPDATE_CHECK` | — | — | unset | Set to disable the npm version check (`NO_UPDATE_NOTIFIER` also respected) |
|
|
203
257
|
|
|
204
258
|
Default hubs:
|
|
205
259
|
|
|
@@ -215,6 +269,22 @@ Custom hub URL policy (applies to any hub override):
|
|
|
215
269
|
|
|
216
270
|
## Updating
|
|
217
271
|
|
|
272
|
+
### How users learn about updates
|
|
273
|
+
|
|
274
|
+
The server checks the npm registry once per process (3s timeout, fail-silent, disable with
|
|
275
|
+
`OBYTE_NO_UPDATE_CHECK=1`) and surfaces the result in three places:
|
|
276
|
+
|
|
277
|
+
- `obyte_get_network_info` returns an `update` block (`current`, `latest`, `update_available`)
|
|
278
|
+
— agents are instructed to mention available updates to the user.
|
|
279
|
+
- `obyte-mcp doctor` prints an `update` check line (informational, never fails doctor).
|
|
280
|
+
- On startup an `update_available` diagnostic is written to stderr (visible in client MCP logs).
|
|
281
|
+
|
|
282
|
+
Users who keep the default unpinned `npx -y obyte-mcp` config get new versions automatically on
|
|
283
|
+
the next client restart — the notification mostly matters for pinned versions, `.mcpb` bundles,
|
|
284
|
+
and global installs. Watch the GitHub repo (Releases) for changelogs.
|
|
285
|
+
|
|
286
|
+
### How to update
|
|
287
|
+
|
|
218
288
|
The server runs through `npx`, which resolves the latest published version. How to move to a
|
|
219
289
|
newer release depends on how it is registered:
|
|
220
290
|
|
|
@@ -248,12 +318,13 @@ Check what you are running with `npx -y obyte-mcp --version` and `npx -y obyte-m
|
|
|
248
318
|
|
|
249
319
|
Use these first for agent-facing tasks. All accept an optional `network`.
|
|
250
320
|
|
|
251
|
-
- `obyte_analyze_address`: balances
|
|
321
|
+
- `obyte_analyze_address`: balances with decimals-aware `balance_summary`, profile units, definition, attestations, optional history.
|
|
252
322
|
- `obyte_analyze_unit`: joint plus optional AA response chain.
|
|
253
|
-
- `obyte_analyze_aa`: AA balances
|
|
254
|
-
- `obyte_resolve_asset`: resolves asset/symbol/decimals in one call.
|
|
323
|
+
- `obyte_analyze_aa`: AA balances with `balance_summary`, selected state vars, optional responses.
|
|
324
|
+
- `obyte_resolve_asset`: resolves asset/symbol/decimals in one call, returns `explorer_asset_url` (holders page).
|
|
325
|
+
- `obyte_get_asset_holders`: top holders of an asset (explorer-sourced), raw + display amounts, supply, up to 100 per call.
|
|
255
326
|
- `obyte_prepare_aa_dry_run`: validates and dry-runs an AA trigger.
|
|
256
|
-
- `obyte_get_portfolio_summary`: balances for up to 20 addresses.
|
|
327
|
+
- `obyte_get_portfolio_summary`: balances for up to 20 addresses with `totals_by_asset` display totals.
|
|
257
328
|
|
|
258
329
|
## Raw Hub Tools
|
|
259
330
|
|
|
@@ -491,6 +562,7 @@ Ask your MCP client:
|
|
|
491
562
|
|
|
492
563
|
- "Check this Obyte address balances on testnet and explain the assets."
|
|
493
564
|
- "Resolve this asset id to symbol and decimals on mainnet."
|
|
565
|
+
- "Who holds this asset?" (resolves it and links the explorer holders page)
|
|
494
566
|
- "Inspect why this AA trigger failed."
|
|
495
567
|
- "Dry-run this AA trigger on testnet."
|
|
496
568
|
- "Summarize AA state vars with this prefix."
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AaStateVarsReader, SymbolOptions } from "./symbols.js";
|
|
2
|
+
import type { Network } from "./types.js";
|
|
3
|
+
export declare const BASE_DECIMALS = 9;
|
|
4
|
+
export declare const AMOUNTS_NOTE = "Raw on-ledger amounts are integers in the asset's smallest units. display_total is already divided by 10^decimals; present display values to users, never raw integers. base is GBYTE with 9 decimals. explorer_asset_url lists the asset's description and holders (explorer amounts are already in display units).";
|
|
5
|
+
/** Explorer page listing an asset's description and holders. */
|
|
6
|
+
export declare function assetExplorerUrl(network: Network, symbolOrAsset: string): string;
|
|
7
|
+
export interface AssetAmountSummary {
|
|
8
|
+
asset: string;
|
|
9
|
+
symbol: string | null;
|
|
10
|
+
decimals: number | null;
|
|
11
|
+
raw_total: number;
|
|
12
|
+
display_total: string | null;
|
|
13
|
+
explorer_asset_url?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface BalanceAmountSummary {
|
|
16
|
+
totals_by_asset: Record<string, AssetAmountSummary>;
|
|
17
|
+
amounts_note: string;
|
|
18
|
+
unresolved_assets?: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Converts a raw smallest-units integer into a human display string without
|
|
22
|
+
* floating point artifacts, e.g. formatAmount(2500000000, 9) === "2.5".
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatAmount(rawAmount: number, decimals: number): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Sums raw amounts per asset from either hub balance shape:
|
|
27
|
+
* - get_balances: { address: { asset: { stable, pending } } }
|
|
28
|
+
* - AA balances: { asset: number }
|
|
29
|
+
*/
|
|
30
|
+
export declare function collectAssetTotals(balances: unknown): Record<string, number>;
|
|
31
|
+
export interface SummarizeOptions extends SymbolOptions {
|
|
32
|
+
resolve?: boolean;
|
|
33
|
+
maxResolvedAssets?: number;
|
|
34
|
+
/** When set, each asset summary gets an explorer_asset_url for that network. */
|
|
35
|
+
network?: Network;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds a per-asset totals summary with symbols, decimals, and display amounts.
|
|
39
|
+
* base always resolves to GBYTE/9 without touching the registry; custom assets
|
|
40
|
+
* are resolved through the registry when available, failures degrade to nulls
|
|
41
|
+
* and are listed in unresolved_assets so agents know to resolve before display.
|
|
42
|
+
*/
|
|
43
|
+
export declare function summarizeBalanceAmounts(reader: AaStateVarsReader, balances: unknown, options?: SummarizeOptions): Promise<BalanceAmountSummary>;
|
package/dist/amounts.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { MAINNET_EXPLORER, TESTNET_EXPLORER } from "./constants.js";
|
|
2
|
+
import { isPlainObject } from "./jsonUtils.js";
|
|
3
|
+
import { getDecimalsBySymbolOrAsset, getSymbolByAsset } from "./symbols.js";
|
|
4
|
+
export const BASE_DECIMALS = 9;
|
|
5
|
+
export const AMOUNTS_NOTE = "Raw on-ledger amounts are integers in the asset's smallest units. display_total is already divided by 10^decimals; present display values to users, never raw integers. base is GBYTE with 9 decimals. explorer_asset_url lists the asset's description and holders (explorer amounts are already in display units).";
|
|
6
|
+
/** Explorer page listing an asset's description and holders. */
|
|
7
|
+
export function assetExplorerUrl(network, symbolOrAsset) {
|
|
8
|
+
const base = network === "testnet" ? TESTNET_EXPLORER : MAINNET_EXPLORER;
|
|
9
|
+
return `${base}/asset/${encodeURIComponent(symbolOrAsset)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Converts a raw smallest-units integer into a human display string without
|
|
13
|
+
* floating point artifacts, e.g. formatAmount(2500000000, 9) === "2.5".
|
|
14
|
+
*/
|
|
15
|
+
export function formatAmount(rawAmount, decimals) {
|
|
16
|
+
if (typeof rawAmount !== "number" || !Number.isFinite(rawAmount))
|
|
17
|
+
return null;
|
|
18
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 30)
|
|
19
|
+
return null;
|
|
20
|
+
if (decimals === 0)
|
|
21
|
+
return String(rawAmount);
|
|
22
|
+
if (!Number.isSafeInteger(rawAmount))
|
|
23
|
+
return String(rawAmount / 10 ** decimals);
|
|
24
|
+
const negative = rawAmount < 0;
|
|
25
|
+
const digits = String(Math.abs(rawAmount)).padStart(decimals + 1, "0");
|
|
26
|
+
const whole = digits.slice(0, -decimals);
|
|
27
|
+
const frac = digits.slice(-decimals).replace(/0+$/, "");
|
|
28
|
+
return `${negative ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sums raw amounts per asset from either hub balance shape:
|
|
32
|
+
* - get_balances: { address: { asset: { stable, pending } } }
|
|
33
|
+
* - AA balances: { asset: number }
|
|
34
|
+
*/
|
|
35
|
+
export function collectAssetTotals(balances) {
|
|
36
|
+
const totals = {};
|
|
37
|
+
if (!isPlainObject(balances))
|
|
38
|
+
return totals;
|
|
39
|
+
const add = (asset, value) => {
|
|
40
|
+
let raw;
|
|
41
|
+
if (typeof value === "number") {
|
|
42
|
+
raw = value;
|
|
43
|
+
}
|
|
44
|
+
else if (isPlainObject(value)) {
|
|
45
|
+
const stable = typeof value.stable === "number" ? value.stable : 0;
|
|
46
|
+
const pending = typeof value.pending === "number" ? value.pending : 0;
|
|
47
|
+
raw = stable + pending;
|
|
48
|
+
}
|
|
49
|
+
if (raw !== undefined)
|
|
50
|
+
totals[asset] = (totals[asset] ?? 0) + raw;
|
|
51
|
+
};
|
|
52
|
+
for (const [key, entry] of Object.entries(balances)) {
|
|
53
|
+
const values = isPlainObject(entry) ? Object.values(entry) : [];
|
|
54
|
+
if (values.length > 0 && values.every((value) => isPlainObject(value))) {
|
|
55
|
+
// Address -> asset map (get_balances shape); sum across addresses.
|
|
56
|
+
for (const [asset, value] of Object.entries(entry))
|
|
57
|
+
add(asset, value);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
add(key, entry);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return totals;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Builds a per-asset totals summary with symbols, decimals, and display amounts.
|
|
67
|
+
* base always resolves to GBYTE/9 without touching the registry; custom assets
|
|
68
|
+
* are resolved through the registry when available, failures degrade to nulls
|
|
69
|
+
* and are listed in unresolved_assets so agents know to resolve before display.
|
|
70
|
+
*/
|
|
71
|
+
export async function summarizeBalanceAmounts(reader, balances, options = {}) {
|
|
72
|
+
const totals = collectAssetTotals(balances);
|
|
73
|
+
const customAssets = Object.keys(totals).filter((asset) => asset !== "base");
|
|
74
|
+
const maxResolved = options.maxResolvedAssets ?? 10;
|
|
75
|
+
const toResolve = options.resolve === false ? [] : customAssets.slice(0, maxResolved);
|
|
76
|
+
const resolved = new Map(await Promise.all(toResolve.map(async (asset) => {
|
|
77
|
+
const [symbol, decimals] = await Promise.all([
|
|
78
|
+
getSymbolByAsset(reader, asset, options).catch(() => null),
|
|
79
|
+
getDecimalsBySymbolOrAsset(reader, asset, options).catch(() => null)
|
|
80
|
+
]);
|
|
81
|
+
return [asset, { symbol, decimals }];
|
|
82
|
+
})));
|
|
83
|
+
const totalsByAsset = {};
|
|
84
|
+
const unresolved = [];
|
|
85
|
+
for (const [asset, rawTotal] of Object.entries(totals)) {
|
|
86
|
+
if (asset === "base") {
|
|
87
|
+
totalsByAsset[asset] = {
|
|
88
|
+
asset,
|
|
89
|
+
symbol: "GBYTE",
|
|
90
|
+
decimals: BASE_DECIMALS,
|
|
91
|
+
raw_total: rawTotal,
|
|
92
|
+
display_total: formatAmount(rawTotal, BASE_DECIMALS),
|
|
93
|
+
...(options.network ? { explorer_asset_url: assetExplorerUrl(options.network, "GBYTE") } : {})
|
|
94
|
+
};
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const info = resolved.get(asset);
|
|
98
|
+
const decimals = info?.decimals ?? null;
|
|
99
|
+
const symbol = info?.symbol ?? null;
|
|
100
|
+
totalsByAsset[asset] = {
|
|
101
|
+
asset,
|
|
102
|
+
symbol,
|
|
103
|
+
decimals,
|
|
104
|
+
raw_total: rawTotal,
|
|
105
|
+
display_total: decimals === null ? null : formatAmount(rawTotal, decimals),
|
|
106
|
+
// Unknown assets get a prefix fallback "symbol"; only registry-confirmed symbols make clean explorer URLs.
|
|
107
|
+
...(options.network ? { explorer_asset_url: assetExplorerUrl(options.network, decimals !== null && symbol ? symbol : asset) } : {})
|
|
108
|
+
};
|
|
109
|
+
if (decimals === null)
|
|
110
|
+
unresolved.push(asset);
|
|
111
|
+
}
|
|
112
|
+
const summary = { totals_by_asset: totalsByAsset, amounts_note: AMOUNTS_NOTE };
|
|
113
|
+
if (unresolved.length > 0)
|
|
114
|
+
summary.unresolved_assets = unresolved;
|
|
115
|
+
return summary;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=amounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amounts.js","sourceRoot":"","sources":["../src/amounts.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export declare const PACKAGE_NAME = "obyte-mcp";
|
|
2
|
-
export declare const PACKAGE_VERSION = "0.1
|
|
2
|
+
export declare const PACKAGE_VERSION = "0.2.1";
|
|
3
3
|
export declare const MAINNET_HUB = "https://obyte.org/api";
|
|
4
4
|
export declare const TESTNET_HUB = "https://testnet.obyte.org/api";
|
|
5
5
|
export declare const MAINNET_TOKEN_REGISTRY_ADDRESS = "O6H6ZIFI57X3PLTYHOCVYPP5A553CYFQ";
|
|
6
|
+
export declare const MAINNET_EXPLORER = "https://explorer.obyte.org";
|
|
7
|
+
export declare const TESTNET_EXPLORER = "https://testnetexplorer.obyte.org";
|
|
6
8
|
export declare const DEFAULT_TIMEOUT_MS = 20000;
|
|
7
9
|
export declare const MIN_TIMEOUT_MS = 1000;
|
|
8
10
|
export declare const MAX_TIMEOUT_MS = 120000;
|
package/dist/constants.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export const PACKAGE_NAME = "obyte-mcp";
|
|
2
|
-
export const PACKAGE_VERSION = "0.1
|
|
2
|
+
export const PACKAGE_VERSION = "0.2.1";
|
|
3
3
|
export const MAINNET_HUB = "https://obyte.org/api";
|
|
4
4
|
export const TESTNET_HUB = "https://testnet.obyte.org/api";
|
|
5
5
|
export const MAINNET_TOKEN_REGISTRY_ADDRESS = "O6H6ZIFI57X3PLTYHOCVYPP5A553CYFQ";
|
|
6
|
+
export const MAINNET_EXPLORER = "https://explorer.obyte.org";
|
|
7
|
+
export const TESTNET_EXPLORER = "https://testnetexplorer.obyte.org";
|
|
6
8
|
export const DEFAULT_TIMEOUT_MS = 20_000;
|
|
7
9
|
export const MIN_TIMEOUT_MS = 1_000;
|
|
8
10
|
export const MAX_TIMEOUT_MS = 120_000;
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,MAAM,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,+BAA+B,CAAC;AAC3D,MAAM,CAAC,MAAM,8BAA8B,GAAG,kCAAkC,CAAC;AAEjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAChD,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,MAAM,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,+BAA+B,CAAC;AAC3D,MAAM,CAAC,MAAM,8BAA8B,GAAG,kCAAkC,CAAC;AAEjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,mCAAmC,CAAC;AAEpE,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAChD,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI,CAAC"}
|
package/dist/doctor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildRuntimeConfig } from "./config.js";
|
|
2
2
|
import { PACKAGE_NAME, PACKAGE_VERSION } from "./constants.js";
|
|
3
3
|
import { ObyteMcpError } from "./errors.js";
|
|
4
|
+
import { checkForUpdate } from "./updateCheck.js";
|
|
4
5
|
export async function runDoctor(cliOptions, options) {
|
|
5
6
|
const checks = [];
|
|
6
7
|
let config;
|
|
@@ -16,6 +17,17 @@ export async function runDoctor(cliOptions, options) {
|
|
|
16
17
|
message: error instanceof ObyteMcpError ? error.message : String(error)
|
|
17
18
|
});
|
|
18
19
|
}
|
|
20
|
+
// Informational only: an available update never fails doctor.
|
|
21
|
+
const update = await checkForUpdate();
|
|
22
|
+
checks.push({
|
|
23
|
+
name: "update",
|
|
24
|
+
ok: true,
|
|
25
|
+
message: update.update_available === true
|
|
26
|
+
? `Update available: ${update.latest} (running ${update.current})`
|
|
27
|
+
: update.update_available === false
|
|
28
|
+
? `Up to date (${update.current})`
|
|
29
|
+
: (update.note ?? "Update check skipped")
|
|
30
|
+
});
|
|
19
31
|
const result = {
|
|
20
32
|
package: PACKAGE_NAME,
|
|
21
33
|
version: PACKAGE_VERSION,
|
package/dist/doctor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Network } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Reads top asset holders from the Obyte explorer's Nuxt payload endpoint
|
|
4
|
+
* (/asset/<symbol|asset>/_payload.json). The explorer is a centralized
|
|
5
|
+
* convenience service separate from the hub; treat its data accordingly.
|
|
6
|
+
*/
|
|
7
|
+
export interface AssetHolder {
|
|
8
|
+
address: string;
|
|
9
|
+
raw_balance: number;
|
|
10
|
+
display_balance: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface AssetHoldersResult {
|
|
13
|
+
input: string;
|
|
14
|
+
network: Network;
|
|
15
|
+
asset: string | null;
|
|
16
|
+
name: string | null;
|
|
17
|
+
decimals: number | null;
|
|
18
|
+
supply_raw: number | null;
|
|
19
|
+
supply_display: string | null;
|
|
20
|
+
holders: AssetHolder[];
|
|
21
|
+
holders_returned: number;
|
|
22
|
+
more_holders_available: boolean;
|
|
23
|
+
explorer_asset_url: string;
|
|
24
|
+
source_note: string;
|
|
25
|
+
}
|
|
26
|
+
export interface FetchHoldersOptions {
|
|
27
|
+
network: Network;
|
|
28
|
+
value: string;
|
|
29
|
+
limit: number;
|
|
30
|
+
timeoutMs: number;
|
|
31
|
+
fetchImpl?: typeof fetch;
|
|
32
|
+
}
|
|
33
|
+
export declare function fetchAssetHolders(options: FetchHoldersOptions): Promise<AssetHoldersResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Resolves Nuxt's devalue payload: a flat array where object values and array
|
|
36
|
+
* items are indices into the same array. Known reactive wrappers are unwrapped;
|
|
37
|
+
* devalue's negative sentinels map to undefined.
|
|
38
|
+
*/
|
|
39
|
+
export declare function decodeNuxtPayload(payload: unknown): unknown;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { BASE_DECIMALS, assetExplorerUrl, formatAmount } from "./amounts.js";
|
|
2
|
+
import { MAINNET_EXPLORER, TESTNET_EXPLORER } from "./constants.js";
|
|
3
|
+
import { ObyteMcpError } from "./errors.js";
|
|
4
|
+
import { isPlainObject } from "./jsonUtils.js";
|
|
5
|
+
const SOURCE_NOTE = "Data from the Obyte explorer (a centralized convenience service, not the hub), sorted by balance descending and may lag the ledger slightly. raw amounts are smallest units; display values are already divided by 10^decimals.";
|
|
6
|
+
export async function fetchAssetHolders(options) {
|
|
7
|
+
const value = normalizeAlias(options.value);
|
|
8
|
+
const base = options.network === "testnet" ? TESTNET_EXPLORER : MAINNET_EXPLORER;
|
|
9
|
+
const url = `${base}/asset/${encodeURIComponent(value)}/_payload.json`;
|
|
10
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
11
|
+
const controller = new AbortController();
|
|
12
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
13
|
+
let response;
|
|
14
|
+
try {
|
|
15
|
+
response = await fetchImpl(url, { headers: { Accept: "application/json" }, signal: controller.signal });
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
19
|
+
throw new ObyteMcpError("TIMEOUT", `Explorer request timed out after ${options.timeoutMs}ms`, { url });
|
|
20
|
+
}
|
|
21
|
+
throw new ObyteMcpError("NETWORK_ERROR", "Explorer request failed", { url });
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
}
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
throw new ObyteMcpError("NETWORK_ERROR", `Explorer responded with HTTP ${response.status}`, { url });
|
|
28
|
+
}
|
|
29
|
+
const payload = (await response.json());
|
|
30
|
+
const entry = extractAssetEntry(decodeNuxtPayload(payload), value);
|
|
31
|
+
if (entry.notFound === true) {
|
|
32
|
+
throw new ObyteMcpError("HUB_ERROR", `Asset "${options.value}" was not found on the ${options.network} explorer`, { url });
|
|
33
|
+
}
|
|
34
|
+
const holdersRaw = Array.isArray(entry.holders) ? entry.holders : [];
|
|
35
|
+
const isBase = entry.assetUnit === "bytes" || value === "GBYTE";
|
|
36
|
+
const decimals = isBase ? BASE_DECIMALS : typeof entry.decimals === "number" ? entry.decimals : null;
|
|
37
|
+
const name = isBase ? "GBYTE" : typeof entry.name === "string" ? entry.name : null;
|
|
38
|
+
const supplyRaw = typeof entry.supply === "number" ? entry.supply : null;
|
|
39
|
+
const holders = [];
|
|
40
|
+
let assetId = null;
|
|
41
|
+
for (const item of holdersRaw.slice(0, options.limit)) {
|
|
42
|
+
if (!isPlainObject(item) || typeof item.address !== "string" || typeof item.balance !== "number")
|
|
43
|
+
continue;
|
|
44
|
+
if (assetId === null && typeof item.asset === "string")
|
|
45
|
+
assetId = item.asset === "bytes" ? "base" : item.asset;
|
|
46
|
+
holders.push({
|
|
47
|
+
address: item.address,
|
|
48
|
+
raw_balance: item.balance,
|
|
49
|
+
display_balance: decimals === null ? null : formatAmount(item.balance, decimals)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
input: options.value,
|
|
54
|
+
network: options.network,
|
|
55
|
+
asset: assetId,
|
|
56
|
+
name,
|
|
57
|
+
decimals,
|
|
58
|
+
supply_raw: supplyRaw,
|
|
59
|
+
supply_display: supplyRaw !== null && decimals !== null ? formatAmount(supplyRaw, decimals) : null,
|
|
60
|
+
holders,
|
|
61
|
+
holders_returned: holders.length,
|
|
62
|
+
more_holders_available: entry.endHolders === false || holdersRaw.length > holders.length,
|
|
63
|
+
explorer_asset_url: assetExplorerUrl(options.network, value),
|
|
64
|
+
source_note: SOURCE_NOTE
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function normalizeAlias(value) {
|
|
68
|
+
const trimmed = value.trim();
|
|
69
|
+
return trimmed === "base" || trimmed === "bytes" ? "GBYTE" : trimmed;
|
|
70
|
+
}
|
|
71
|
+
function extractAssetEntry(decoded, value) {
|
|
72
|
+
const data = isPlainObject(decoded) ? decoded.data : undefined;
|
|
73
|
+
if (isPlainObject(data)) {
|
|
74
|
+
const exact = data[`asset:${value}`];
|
|
75
|
+
if (isPlainObject(exact))
|
|
76
|
+
return exact;
|
|
77
|
+
for (const [key, entry] of Object.entries(data)) {
|
|
78
|
+
if (key.startsWith("asset:") && isPlainObject(entry))
|
|
79
|
+
return entry;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw new ObyteMcpError("INTERNAL_ERROR", "Unexpected explorer payload shape", { value });
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolves Nuxt's devalue payload: a flat array where object values and array
|
|
86
|
+
* items are indices into the same array. Known reactive wrappers are unwrapped;
|
|
87
|
+
* devalue's negative sentinels map to undefined.
|
|
88
|
+
*/
|
|
89
|
+
export function decodeNuxtPayload(payload) {
|
|
90
|
+
if (!Array.isArray(payload) || payload.length === 0) {
|
|
91
|
+
throw new ObyteMcpError("INTERNAL_ERROR", "Explorer payload is not a Nuxt data array");
|
|
92
|
+
}
|
|
93
|
+
const wrappers = new Set(["ShallowReactive", "Reactive", "Ref", "ShallowRef"]);
|
|
94
|
+
const resolve = (index, depth) => {
|
|
95
|
+
if (depth > 16 || index < 0 || index >= payload.length)
|
|
96
|
+
return undefined;
|
|
97
|
+
const value = payload[index];
|
|
98
|
+
if (isPlainObject(value)) {
|
|
99
|
+
const result = {};
|
|
100
|
+
for (const [key, ref] of Object.entries(value)) {
|
|
101
|
+
result[key] = typeof ref === "number" ? resolve(ref, depth + 1) : ref;
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(value)) {
|
|
106
|
+
if (value.length === 2 && typeof value[0] === "string" && wrappers.has(value[0]) && typeof value[1] === "number") {
|
|
107
|
+
return resolve(value[1], depth + 1);
|
|
108
|
+
}
|
|
109
|
+
return value.map((ref) => (typeof ref === "number" ? resolve(ref, depth + 1) : ref));
|
|
110
|
+
}
|
|
111
|
+
return value;
|
|
112
|
+
};
|
|
113
|
+
return resolve(0, 0);
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=explorerClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explorerClient.js","sourceRoot":"","sources":["../src/explorerClient.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { PACKAGE_NAME, PACKAGE_VERSION } from "./constants.js";
|
|
3
3
|
import { parseCliArgs } from "./cliArgs.js";
|
|
4
4
|
import { buildRuntimeConfig } from "./config.js";
|
|
5
|
-
import {
|
|
5
|
+
import { toObyteMcpError } from "./errors.js";
|
|
6
6
|
import { runDoctor } from "./doctor.js";
|
|
7
7
|
import { runInstall } from "./install.js";
|
|
8
8
|
import { runServer } from "./server.js";
|
|
@@ -74,8 +74,7 @@ The default command starts MCP stdio. Do not print logs to stdout in this mode.
|
|
|
74
74
|
}
|
|
75
75
|
main().catch((error) => {
|
|
76
76
|
const normalized = toObyteMcpError(error);
|
|
77
|
-
|
|
78
|
-
process.stderr.write(`${body.code}: ${body.message}\n`);
|
|
77
|
+
process.stderr.write(`${normalized.code}: ${normalized.message}\n`);
|
|
79
78
|
process.exitCode = 1;
|
|
80
79
|
});
|
|
81
80
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnD,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,eAAe,IAAI,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/D,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,GAAG,YAAY,IAAI,eAAe;;;;;;;;IAQvC,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;;;;;;;;;;;;;;;;;;;;;;;;CAwBf,CAAC;AACF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;IACpE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/dist/install.js
CHANGED
|
@@ -99,19 +99,39 @@ function failWithSnippet(client, config, serverName, detail) {
|
|
|
99
99
|
return { client, status: "failed", detail };
|
|
100
100
|
}
|
|
101
101
|
function runCli(command, args) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return { ok: false, missing: false, message: result.error.message };
|
|
102
|
+
if (process.platform === "win32")
|
|
103
|
+
return runCliWindows(command, args);
|
|
104
|
+
const result = spawnSync(command, args, { stdio: "inherit" });
|
|
105
|
+
if (result.error) {
|
|
106
|
+
if (result.error.code === "ENOENT") {
|
|
107
|
+
return { ok: false, missing: true, message: `${command} not found on PATH` };
|
|
109
108
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
return { ok: false, missing: false, message: result.error.message };
|
|
110
|
+
}
|
|
111
|
+
if (result.status === 0)
|
|
112
|
+
return { ok: true, missing: false, message: "ok" };
|
|
113
|
+
return { ok: false, missing: false, message: `exited with code ${result.status ?? "unknown"}` };
|
|
114
|
+
}
|
|
115
|
+
function runCliWindows(command, args) {
|
|
116
|
+
// npm-installed CLIs (claude, code, codex) are .cmd shims on Windows; modern Node
|
|
117
|
+
// refuses to spawn them without a shell (CVE-2024-27980). Probe with where.exe,
|
|
118
|
+
// then run through the shell with cmd-style quoting.
|
|
119
|
+
const probe = spawnSync("where", [command], { stdio: "ignore" });
|
|
120
|
+
if (probe.error || probe.status !== 0) {
|
|
121
|
+
return { ok: false, missing: true, message: `${command} not found on PATH` };
|
|
113
122
|
}
|
|
114
|
-
|
|
123
|
+
const line = [command, ...args.map(quoteForCmd)].join(" ");
|
|
124
|
+
const result = spawnSync(line, { stdio: "inherit", shell: true });
|
|
125
|
+
if (result.error)
|
|
126
|
+
return { ok: false, missing: false, message: result.error.message };
|
|
127
|
+
if (result.status === 0)
|
|
128
|
+
return { ok: true, missing: false, message: "ok" };
|
|
129
|
+
return { ok: false, missing: false, message: `exited with code ${result.status ?? "unknown"}` };
|
|
130
|
+
}
|
|
131
|
+
function quoteForCmd(value) {
|
|
132
|
+
if (/^[A-Za-z0-9._:\\/=-]+$/.test(value))
|
|
133
|
+
return value;
|
|
134
|
+
return `"${value.replace(/"/g, '\\"')}"`;
|
|
115
135
|
}
|
|
116
136
|
export function claudeDesktopConfigPath() {
|
|
117
137
|
const home = homedir();
|