@xrpl-utilities/mcp 0.1.6
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 +109 -0
- package/dist/dispatch.d.ts +53 -0
- package/dist/dispatch.js +158 -0
- package/dist/dispatch.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/jsonschema.d.ts +19 -0
- package/dist/jsonschema.js +7 -0
- package/dist/jsonschema.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +93 -0
- package/dist/server.js.map +1 -0
- package/dist/services/index.d.ts +28 -0
- package/dist/services/index.js +25 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/pulse.d.ts +12 -0
- package/dist/services/pulse.js +66 -0
- package/dist/services/pulse.js.map +1 -0
- package/dist/services/sentinel.d.ts +11 -0
- package/dist/services/sentinel.js +84 -0
- package/dist/services/sentinel.js.map +1 -0
- package/dist/services/telemetry.d.ts +21 -0
- package/dist/services/telemetry.js +118 -0
- package/dist/services/telemetry.js.map +1 -0
- package/dist/services/trust.d.ts +11 -0
- package/dist/services/trust.js +140 -0
- package/dist/services/trust.js.map +1 -0
- package/dist/transport/http.d.ts +18 -0
- package/dist/transport/http.js +106 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/stdio.d.ts +17 -0
- package/dist/transport/stdio.js +28 -0
- package/dist/transport/stdio.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +29 -0
- package/dist/validate.js +88 -0
- package/dist/validate.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @xrpl-utilities/mcp
|
|
2
|
+
|
|
3
|
+
[Model Context Protocol](https://modelcontextprotocol.io) server for the
|
|
4
|
+
XRPL-Utilities™ portfolio. Exposes the read endpoints of all four
|
|
5
|
+
services as MCP tools so AI agents can discover and use them — either
|
|
6
|
+
locally via stdio (Claude Desktop, MCP Inspector, etc.) or remotely
|
|
7
|
+
via the hosted endpoint at `mcp.xrpl-utilities.io`.
|
|
8
|
+
|
|
9
|
+
## Services covered
|
|
10
|
+
|
|
11
|
+
| Service | What it does | Tools |
|
|
12
|
+
|---------------|---------------------------------------------------------|-------|
|
|
13
|
+
| **XR-Sentinel** | XRPL wallet activity-pattern classifier (0-100 score, 22-signal catalog, AI narrative) | `xrpl_sentinel_scan`, `xrpl_sentinel_scan_history` |
|
|
14
|
+
| **XR-Pulse** | Normalized XRPL signal feed — public-source news + on-chain whale activity + XLS-70/80/81 lifecycle | `xrpl_pulse_recent_events` |
|
|
15
|
+
| **XR-Telemetry** | XRPL macro snapshot — supply, liquidity, AMM, Active Float, Burst Math utility floor | `xrpl_telemetry_snapshot`, `xrpl_telemetry_get_quote`, `xrpl_telemetry_get_status`, `xrpl_telemetry_get_results` |
|
|
16
|
+
| **XR-Trust** | Directory + drill-down for XRPL permissioned-asset stack (XLS-70/80/81 + XLS-40 DID) | `xrpl_trust_list_domains`, `xrpl_trust_get_domain`, `xrpl_trust_credential_issuers`, `xrpl_trust_recent_events` |
|
|
17
|
+
|
|
18
|
+
11 tools total, all read-only. Every paid call is settled via x402 v2
|
|
19
|
+
on the XRPL mainnet through the t54 facilitator.
|
|
20
|
+
|
|
21
|
+
## Auth model
|
|
22
|
+
|
|
23
|
+
The MCP server is a **stateless passthrough proxy**. It does not hold
|
|
24
|
+
wallets, manage user accounts, or subsidize calls.
|
|
25
|
+
|
|
26
|
+
For paid tools (every endpoint at $0.10 USD), the caller supplies a
|
|
27
|
+
`payment_signature` argument: a base64-JSON-encoded x402 v2 payment
|
|
28
|
+
header signing an XRPL Payment that matches one of the requirements
|
|
29
|
+
returned by an unauthenticated probe. The server forwards it as the
|
|
30
|
+
`PAYMENT-SIGNATURE` header on the underlying call.
|
|
31
|
+
|
|
32
|
+
If you don't supply `payment_signature`, the underlying service
|
|
33
|
+
returns its real `402 Payment Required` challenge with the XRP +
|
|
34
|
+
RLUSD requirements. The MCP server passes that back to the LLM as
|
|
35
|
+
a structured error so it can sign and retry.
|
|
36
|
+
|
|
37
|
+
Operators can set `MCP_BYPASS_KEY` on the server to enable an opt-in
|
|
38
|
+
bypass for friendlies / demos. The caller passes the matching key as
|
|
39
|
+
`_bypass_key` in the tool args. Rate-limited at the proxy layer.
|
|
40
|
+
|
|
41
|
+
## Use it
|
|
42
|
+
|
|
43
|
+
### Locally via Claude Desktop (stdio)
|
|
44
|
+
|
|
45
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"xrpl-utilities": {
|
|
51
|
+
"command": "npx",
|
|
52
|
+
"args": ["-y", "@xrpl-utilities/mcp", "--transport", "stdio"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Restart Claude Desktop. The 11 tools should appear with the prefix
|
|
59
|
+
`xrpl_`. Ask Claude to "scan the wallet rXXX with XR-Sentinel" or
|
|
60
|
+
"list permissioned domains on XRPL" and the tool calls flow through.
|
|
61
|
+
|
|
62
|
+
### Remotely (HTTP/SSE)
|
|
63
|
+
|
|
64
|
+
Point any MCP client at `https://mcp.xrpl-utilities.io/mcp`. Same
|
|
65
|
+
tool list, same auth model.
|
|
66
|
+
|
|
67
|
+
## What you need to actually pay
|
|
68
|
+
|
|
69
|
+
To avoid 402 challenges on every call, your client needs to:
|
|
70
|
+
|
|
71
|
+
1. Hold a funded XRPL wallet (XRP + optional RLUSD trustline).
|
|
72
|
+
2. On each paid tool call, sign a Payment matching one of the
|
|
73
|
+
`accepts` entries from a prior probe.
|
|
74
|
+
3. Pass the base64-JSON-encoded header as `payment_signature`.
|
|
75
|
+
|
|
76
|
+
The Python reference implementation is
|
|
77
|
+
[`x402-xrpl`](https://pypi.org/project/x402-xrpl/) — useful as a
|
|
78
|
+
template even if you're using a different language.
|
|
79
|
+
|
|
80
|
+
## Local dev
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install
|
|
84
|
+
npm run build
|
|
85
|
+
node dist/index.js --transport http --port 8080
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Point MCP Inspector at `http://localhost:8080/mcp` to walk through
|
|
89
|
+
tool definitions interactively.
|
|
90
|
+
|
|
91
|
+
## Releases
|
|
92
|
+
|
|
93
|
+
Releases are cut by tag push. The `Release` workflow builds, validates
|
|
94
|
+
that `package.json` version matches the tag, then publishes to npm
|
|
95
|
+
with sigstore provenance.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm version patch # or minor / major
|
|
99
|
+
git push --follow-tags # pushes commit + tag, CI does the rest
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The published artifact appears at
|
|
103
|
+
[npmjs.com/package/@xrpl-utilities/mcp](https://www.npmjs.com/package/@xrpl-utilities/mcp)
|
|
104
|
+
within ~90 seconds. Provenance attestation is visible on the package
|
|
105
|
+
page as a green check.
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT. Full portfolio at [xrpl-utilities.com](https://xrpl-utilities.com).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool dispatcher: receives an MCP tool call, looks up the owning
|
|
3
|
+
* service + tool, builds the underlying HTTP request, forwards the
|
|
4
|
+
* response.
|
|
5
|
+
*
|
|
6
|
+
* Auth model (per-tool, see ToolDef.authMode):
|
|
7
|
+
*
|
|
8
|
+
* inline_x402 - caller passes payment_signature in tool args; the
|
|
9
|
+
* dispatcher forwards it as the PAYMENT-SIGNATURE
|
|
10
|
+
* header. Standard x402 v2; \$0.10 USD settled inline
|
|
11
|
+
* via the t54 facilitator on every successful call.
|
|
12
|
+
*
|
|
13
|
+
* async_invoice - MCP wrapper around one step of Telemetry's three-
|
|
14
|
+
* step flow (quote -> pay -> status -> results). The
|
|
15
|
+
* wrapper itself doesn't carry a payment header; the
|
|
16
|
+
* actual XRPL Payment happens out-of-band when the
|
|
17
|
+
* caller pays the deeplink returned by quote.
|
|
18
|
+
*
|
|
19
|
+
* free - no payment ever. Reserved for future pure-metadata
|
|
20
|
+
* wrappers; not used by any current tool.
|
|
21
|
+
*
|
|
22
|
+
* Operator-issued bypass: if MCP_BYPASS_KEY is set on the MCP process
|
|
23
|
+
* AND an inline_x402 tool call includes a matching `_bypass_key` in
|
|
24
|
+
* args, the dispatcher forwards it as the dev-bypass header on the
|
|
25
|
+
* underlying service (rate-limited at the MCP transport layer).
|
|
26
|
+
*
|
|
27
|
+
* The web-origin bypass that the marketing site uses is deliberately
|
|
28
|
+
* NOT honored here: that bypass is meant for the human-facing site,
|
|
29
|
+
* not for agent traffic. Otherwise the MCP server would silently turn
|
|
30
|
+
* a paid agent API into a free one.
|
|
31
|
+
*/
|
|
32
|
+
export interface DispatchOptions {
|
|
33
|
+
/**
|
|
34
|
+
* Global bypass key from the MCP_BYPASS_KEY env var. When the caller
|
|
35
|
+
* also presents this key (via the `_bypass_key` reserved tool arg),
|
|
36
|
+
* the dispatcher uses it as the dev-bypass header on the underlying
|
|
37
|
+
* service. Rate-limited by the caller (see transport-http).
|
|
38
|
+
*/
|
|
39
|
+
bypassKey?: string;
|
|
40
|
+
/** Override base URLs (useful for tests pointing at localhost). */
|
|
41
|
+
baseUrlOverride?: (serviceId: string) => string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Identity string put on the User-Agent header so service-side logs
|
|
44
|
+
* can distinguish MCP traffic from direct API users.
|
|
45
|
+
*/
|
|
46
|
+
userAgent?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Run a single tool call. Throws on missing tool / network error /
|
|
50
|
+
* non-2xx upstream response. Caller (the MCP server adapter) is
|
|
51
|
+
* responsible for catching and converting to an MCP-shaped error.
|
|
52
|
+
*/
|
|
53
|
+
export declare function dispatchTool(toolName: string, args: Record<string, unknown>, opts?: DispatchOptions): Promise<unknown>;
|
package/dist/dispatch.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool dispatcher: receives an MCP tool call, looks up the owning
|
|
3
|
+
* service + tool, builds the underlying HTTP request, forwards the
|
|
4
|
+
* response.
|
|
5
|
+
*
|
|
6
|
+
* Auth model (per-tool, see ToolDef.authMode):
|
|
7
|
+
*
|
|
8
|
+
* inline_x402 - caller passes payment_signature in tool args; the
|
|
9
|
+
* dispatcher forwards it as the PAYMENT-SIGNATURE
|
|
10
|
+
* header. Standard x402 v2; \$0.10 USD settled inline
|
|
11
|
+
* via the t54 facilitator on every successful call.
|
|
12
|
+
*
|
|
13
|
+
* async_invoice - MCP wrapper around one step of Telemetry's three-
|
|
14
|
+
* step flow (quote -> pay -> status -> results). The
|
|
15
|
+
* wrapper itself doesn't carry a payment header; the
|
|
16
|
+
* actual XRPL Payment happens out-of-band when the
|
|
17
|
+
* caller pays the deeplink returned by quote.
|
|
18
|
+
*
|
|
19
|
+
* free - no payment ever. Reserved for future pure-metadata
|
|
20
|
+
* wrappers; not used by any current tool.
|
|
21
|
+
*
|
|
22
|
+
* Operator-issued bypass: if MCP_BYPASS_KEY is set on the MCP process
|
|
23
|
+
* AND an inline_x402 tool call includes a matching `_bypass_key` in
|
|
24
|
+
* args, the dispatcher forwards it as the dev-bypass header on the
|
|
25
|
+
* underlying service (rate-limited at the MCP transport layer).
|
|
26
|
+
*
|
|
27
|
+
* The web-origin bypass that the marketing site uses is deliberately
|
|
28
|
+
* NOT honored here: that bypass is meant for the human-facing site,
|
|
29
|
+
* not for agent traffic. Otherwise the MCP server would silently turn
|
|
30
|
+
* a paid agent API into a free one.
|
|
31
|
+
*/
|
|
32
|
+
import { findToolOwner } from "./services/index.js";
|
|
33
|
+
/**
|
|
34
|
+
* Run a single tool call. Throws on missing tool / network error /
|
|
35
|
+
* non-2xx upstream response. Caller (the MCP server adapter) is
|
|
36
|
+
* responsible for catching and converting to an MCP-shaped error.
|
|
37
|
+
*/
|
|
38
|
+
export async function dispatchTool(toolName, args, opts = {}) {
|
|
39
|
+
const owner = findToolOwner(toolName);
|
|
40
|
+
if (!owner) {
|
|
41
|
+
throw new Error(`unknown tool: ${toolName}`);
|
|
42
|
+
}
|
|
43
|
+
const { service, tool } = owner;
|
|
44
|
+
const baseUrl = opts.baseUrlOverride?.(service.id) ?? service.baseUrl;
|
|
45
|
+
// Substitute path params (e.g. /domain/{domain_id}) from args.
|
|
46
|
+
let path = tool.path;
|
|
47
|
+
const consumedPathArgs = new Set();
|
|
48
|
+
path = path.replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (_, key) => {
|
|
49
|
+
if (!(key in args)) {
|
|
50
|
+
throw new Error(`tool ${toolName} requires path parameter ${key}, missing from args`);
|
|
51
|
+
}
|
|
52
|
+
consumedPathArgs.add(key);
|
|
53
|
+
return encodeURIComponent(String(args[key]));
|
|
54
|
+
});
|
|
55
|
+
// Strip args reserved for transport-level concerns (payment_signature,
|
|
56
|
+
// _bypass_key) AND args already consumed by path params. What remains
|
|
57
|
+
// is the actual API payload.
|
|
58
|
+
const stripSet = new Set([
|
|
59
|
+
...(tool.stripArgs ?? []),
|
|
60
|
+
"_bypass_key",
|
|
61
|
+
"payment_signature",
|
|
62
|
+
]);
|
|
63
|
+
const apiArgs = {};
|
|
64
|
+
for (const [k, v] of Object.entries(args)) {
|
|
65
|
+
if (consumedPathArgs.has(k))
|
|
66
|
+
continue;
|
|
67
|
+
if (stripSet.has(k))
|
|
68
|
+
continue;
|
|
69
|
+
apiArgs[k] = v;
|
|
70
|
+
}
|
|
71
|
+
// Auth resolution. The caller can either supply payment_signature
|
|
72
|
+
// (which we forward as PAYMENT-SIGNATURE) or _bypass_key (which we
|
|
73
|
+
// verify against MCP_BYPASS_KEY before forwarding to the underlying
|
|
74
|
+
// service as its dev-bypass header).
|
|
75
|
+
const headers = {
|
|
76
|
+
Accept: "application/json",
|
|
77
|
+
"User-Agent": opts.userAgent ?? "xrpl-utilities-mcp/0.1.6",
|
|
78
|
+
};
|
|
79
|
+
const callerPaymentSig = stringArg(args.payment_signature);
|
|
80
|
+
const callerBypassKey = stringArg(args._bypass_key);
|
|
81
|
+
if (tool.authMode === "inline_x402") {
|
|
82
|
+
if (callerPaymentSig) {
|
|
83
|
+
headers["PAYMENT-SIGNATURE"] = callerPaymentSig;
|
|
84
|
+
}
|
|
85
|
+
else if (callerBypassKey && opts.bypassKey && callerBypassKey === opts.bypassKey) {
|
|
86
|
+
// Operator-issued bypass. Forward as the dev-bypass header that
|
|
87
|
+
// the underlying services accept (D_BYPASS_KEY pattern).
|
|
88
|
+
headers["PAYMENT-SIGNATURE"] = callerBypassKey;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// No auth supplied. Fire the request anyway so the caller gets
|
|
92
|
+
// the real 402 challenge back from the underlying service - that
|
|
93
|
+
// tells them what payment_signature shape to send next time. The
|
|
94
|
+
// MCP server is a transparent proxy here, not an enforcer.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// async_invoice + free both fall through with no PAYMENT-SIGNATURE
|
|
98
|
+
// header. async_invoice tools wrap the Telemetry quote/status/results
|
|
99
|
+
// flow where payment happens out-of-band; free is reserved for
|
|
100
|
+
// future pure-metadata wrappers.
|
|
101
|
+
// Build the request URL (query for GET, body for POST).
|
|
102
|
+
let url = baseUrl + path;
|
|
103
|
+
let body;
|
|
104
|
+
if (tool.method === "GET") {
|
|
105
|
+
const params = new URLSearchParams();
|
|
106
|
+
for (const [k, v] of Object.entries(apiArgs)) {
|
|
107
|
+
if (v === undefined || v === null)
|
|
108
|
+
continue;
|
|
109
|
+
params.append(k, String(v));
|
|
110
|
+
}
|
|
111
|
+
const qs = params.toString();
|
|
112
|
+
if (qs)
|
|
113
|
+
url += "?" + qs;
|
|
114
|
+
}
|
|
115
|
+
else if (tool.method === "POST") {
|
|
116
|
+
if (tool.bodyFromArgs) {
|
|
117
|
+
headers["Content-Type"] = "application/json";
|
|
118
|
+
body = JSON.stringify(apiArgs);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Run the request. The MCP SDK gives us 30+ seconds of headroom on
|
|
122
|
+
// most clients; we cap at 60s here so an upstream stall surfaces as
|
|
123
|
+
// a timeout error instead of hanging the MCP session forever.
|
|
124
|
+
const ctl = new AbortController();
|
|
125
|
+
const timeoutId = setTimeout(() => ctl.abort(), 60_000);
|
|
126
|
+
let res;
|
|
127
|
+
try {
|
|
128
|
+
res = await fetch(url, { method: tool.method, headers, body, signal: ctl.signal });
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
clearTimeout(timeoutId);
|
|
132
|
+
}
|
|
133
|
+
const text = await res.text();
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = JSON.parse(text);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
parsed = text;
|
|
140
|
+
}
|
|
141
|
+
// Surface 402 challenges + 4xx/5xx errors as structured errors so
|
|
142
|
+
// the LLM can reason over them and retry with a payment_signature.
|
|
143
|
+
if (!res.ok) {
|
|
144
|
+
return {
|
|
145
|
+
_error: true,
|
|
146
|
+
status: res.status,
|
|
147
|
+
response: parsed,
|
|
148
|
+
hint: res.status === 402
|
|
149
|
+
? "This endpoint requires x402 payment. Sign an XRPL Payment matching one of the entries in 'accepts', base64-JSON-encode it, and pass as payment_signature."
|
|
150
|
+
: undefined,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return parsed;
|
|
154
|
+
}
|
|
155
|
+
function stringArg(v) {
|
|
156
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Entry point. Dispatches to stdio or HTTP transport based on a
|
|
4
|
+
* --transport flag (or the MCP_TRANSPORT env var).
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* xrpl-utilities-mcp --transport stdio # for Claude Desktop config
|
|
8
|
+
* xrpl-utilities-mcp --transport http # for hosted Railway deploy
|
|
9
|
+
*
|
|
10
|
+
* Default is stdio so the npm-published entry-point Just Works when
|
|
11
|
+
* Claude Desktop launches it.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Entry point. Dispatches to stdio or HTTP transport based on a
|
|
4
|
+
* --transport flag (or the MCP_TRANSPORT env var).
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* xrpl-utilities-mcp --transport stdio # for Claude Desktop config
|
|
8
|
+
* xrpl-utilities-mcp --transport http # for hosted Railway deploy
|
|
9
|
+
*
|
|
10
|
+
* Default is stdio so the npm-published entry-point Just Works when
|
|
11
|
+
* Claude Desktop launches it.
|
|
12
|
+
*/
|
|
13
|
+
import { runStdio } from "./transport/stdio.js";
|
|
14
|
+
import { runHttp } from "./transport/http.js";
|
|
15
|
+
import { validateAllServices } from "./validate.js";
|
|
16
|
+
function parseArgs(argv) {
|
|
17
|
+
let transport = (process.env["MCP_TRANSPORT"] === "http" ? "http" : "stdio");
|
|
18
|
+
let port = Number(process.env["PORT"] ?? "8080");
|
|
19
|
+
let skipValidate = process.env["MCP_SKIP_VALIDATE"] === "1";
|
|
20
|
+
for (let i = 0; i < argv.length; i++) {
|
|
21
|
+
const a = argv[i];
|
|
22
|
+
if (a === "--transport" || a === "-t") {
|
|
23
|
+
const v = argv[++i];
|
|
24
|
+
if (v === "stdio" || v === "http")
|
|
25
|
+
transport = v;
|
|
26
|
+
}
|
|
27
|
+
else if (a === "--port" || a === "-p") {
|
|
28
|
+
port = Number(argv[++i] ?? port);
|
|
29
|
+
}
|
|
30
|
+
else if (a === "--skip-validate") {
|
|
31
|
+
skipValidate = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { transport, port, skipValidate };
|
|
35
|
+
}
|
|
36
|
+
async function main() {
|
|
37
|
+
const { transport, port, skipValidate } = parseArgs(process.argv.slice(2));
|
|
38
|
+
// Schema-discipline check. On stdio we run silently and only complain
|
|
39
|
+
// on stderr (Claude Desktop captures stdout for the JSON-RPC stream).
|
|
40
|
+
// On HTTP we log normally.
|
|
41
|
+
if (!skipValidate) {
|
|
42
|
+
const results = await validateAllServices({ strict: false });
|
|
43
|
+
const log = transport === "stdio" ? console.error : console.log;
|
|
44
|
+
for (const r of results) {
|
|
45
|
+
if (r.errors.length) {
|
|
46
|
+
log(`[validate] ${r.service}: ERRORS`);
|
|
47
|
+
r.errors.forEach((e) => log(` ${e}`));
|
|
48
|
+
}
|
|
49
|
+
if (r.warnings.length) {
|
|
50
|
+
log(`[validate] ${r.service}: warnings`);
|
|
51
|
+
r.warnings.forEach((w) => log(` ${w}`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const anyError = results.some((r) => r.errors.length);
|
|
55
|
+
if (anyError && process.env["MCP_FAIL_ON_DRIFT"] === "1") {
|
|
56
|
+
process.exit(2);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (transport === "stdio") {
|
|
60
|
+
await runStdio();
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
await runHttp(port);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
main().catch((e) => {
|
|
67
|
+
console.error("xrpl-utilities-mcp fatal:", e);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal JSON Schema typing. The MCP SDK accepts plain objects as
|
|
3
|
+
* tool input schemas; we only need a small subset of Draft 7 to
|
|
4
|
+
* describe the args we care about (string / number / object / etc.).
|
|
5
|
+
*/
|
|
6
|
+
export interface JSONSchema7 {
|
|
7
|
+
type?: "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
|
|
8
|
+
description?: string;
|
|
9
|
+
properties?: Record<string, JSONSchema7>;
|
|
10
|
+
required?: string[];
|
|
11
|
+
enum?: unknown[];
|
|
12
|
+
minimum?: number;
|
|
13
|
+
maximum?: number;
|
|
14
|
+
pattern?: string;
|
|
15
|
+
items?: JSONSchema7;
|
|
16
|
+
additionalProperties?: boolean | JSONSchema7;
|
|
17
|
+
default?: unknown;
|
|
18
|
+
examples?: unknown[];
|
|
19
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal JSON Schema typing. The MCP SDK accepts plain objects as
|
|
3
|
+
* tool input schemas; we only need a small subset of Draft 7 to
|
|
4
|
+
* describe the args we care about (string / number / object / etc.).
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=jsonschema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonschema.js","sourceRoot":"","sources":["../src/jsonschema.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server core. Wires the registered tools into the MCP SDK's
|
|
3
|
+
* Server abstraction and routes incoming tool calls through the
|
|
4
|
+
* dispatcher. Transport-agnostic — the same Server object is later
|
|
5
|
+
* connected via stdio (transport-stdio) or HTTP/SSE (transport-http).
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { type DispatchOptions } from "./dispatch.js";
|
|
9
|
+
export declare function buildServer(opts?: DispatchOptions): Server;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server core. Wires the registered tools into the MCP SDK's
|
|
3
|
+
* Server abstraction and routes incoming tool calls through the
|
|
4
|
+
* dispatcher. Transport-agnostic — the same Server object is later
|
|
5
|
+
* connected via stdio (transport-stdio) or HTTP/SSE (transport-http).
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { ALL_TOOLS, SERVICES } from "./services/index.js";
|
|
10
|
+
import { dispatchTool } from "./dispatch.js";
|
|
11
|
+
const SERVER_NAME = "xrpl-utilities";
|
|
12
|
+
const SERVER_VERSION = "0.1.6";
|
|
13
|
+
export function buildServer(opts = {}) {
|
|
14
|
+
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, { capabilities: { tools: {}, resources: {} } });
|
|
15
|
+
// ---- Tools ---------------------------------------------------------------
|
|
16
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
17
|
+
tools: ALL_TOOLS.map((t) => ({
|
|
18
|
+
name: t.name,
|
|
19
|
+
description: t.description,
|
|
20
|
+
inputSchema: t.inputSchema,
|
|
21
|
+
})),
|
|
22
|
+
}));
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
24
|
+
const args = (req.params.arguments ?? {});
|
|
25
|
+
try {
|
|
26
|
+
const result = await dispatchTool(req.params.name, args, opts);
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
type: "text",
|
|
31
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2),
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return {
|
|
38
|
+
isError: true,
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `xrpl-utilities-mcp dispatch error: ${e.message}`,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
// ---- Resources -----------------------------------------------------------
|
|
49
|
+
// Each service's live agents.json + /schema is exposed as a resource
|
|
50
|
+
// so the LLM can fetch the full manifest / output-shape detail without
|
|
51
|
+
// a tool call. This is the MCP-native way to surface "static-ish"
|
|
52
|
+
// documentation alongside the actionable tools.
|
|
53
|
+
const resources = SERVICES.flatMap((s) => [
|
|
54
|
+
{
|
|
55
|
+
uri: `${s.baseUrl}/agents.json`,
|
|
56
|
+
mimeType: "application/json",
|
|
57
|
+
name: `${s.label} agents.json`,
|
|
58
|
+
description: `Live agent-discovery manifest for ${s.label}: schema_version, capabilities, endpoint catalog, payment requirements.`,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
uri: `${s.baseUrl}/schema`,
|
|
62
|
+
mimeType: "application/json",
|
|
63
|
+
name: `${s.label} /schema`,
|
|
64
|
+
description: `Field-level output shape for ${s.label} responses. Source of truth for what each tool returns.`,
|
|
65
|
+
},
|
|
66
|
+
]);
|
|
67
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
68
|
+
resources,
|
|
69
|
+
}));
|
|
70
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
|
|
71
|
+
const uri = req.params.uri;
|
|
72
|
+
const ctl = new AbortController();
|
|
73
|
+
const tId = setTimeout(() => ctl.abort(), 10_000);
|
|
74
|
+
try {
|
|
75
|
+
const r = await fetch(uri, { signal: ctl.signal });
|
|
76
|
+
const text = await r.text();
|
|
77
|
+
return {
|
|
78
|
+
contents: [
|
|
79
|
+
{
|
|
80
|
+
uri,
|
|
81
|
+
mimeType: r.headers.get("content-type") ?? "application/json",
|
|
82
|
+
text,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
clearTimeout(tId);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return server;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Master service registry. Adding a new XR-* service is a single line:
|
|
3
|
+
* import the new module + push it onto SERVICES.
|
|
4
|
+
*
|
|
5
|
+
* Tool names are globally namespaced (xrpl_<service>_<verb>) so cross-
|
|
6
|
+
* service calls in one MCP session don't collide with each other or
|
|
7
|
+
* with any other MCP server the user may have connected.
|
|
8
|
+
*/
|
|
9
|
+
import type { ServiceDef } from "../types.js";
|
|
10
|
+
export declare const SERVICES: ServiceDef[];
|
|
11
|
+
/** Flat list of every tool across every registered service. */
|
|
12
|
+
export declare const ALL_TOOLS: {
|
|
13
|
+
_serviceId: string;
|
|
14
|
+
_baseUrl: string;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
inputSchema: import("../jsonschema.js").JSONSchema7;
|
|
18
|
+
method: import("../types.js").HttpMethod;
|
|
19
|
+
path: string;
|
|
20
|
+
authMode: import("../types.js").AuthMode;
|
|
21
|
+
bodyFromArgs?: boolean;
|
|
22
|
+
stripArgs?: string[];
|
|
23
|
+
}[];
|
|
24
|
+
/** Look up the owning service for a given tool name. */
|
|
25
|
+
export declare function findToolOwner(toolName: string): {
|
|
26
|
+
service: ServiceDef;
|
|
27
|
+
tool: ServiceDef["tools"][number];
|
|
28
|
+
} | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Master service registry. Adding a new XR-* service is a single line:
|
|
3
|
+
* import the new module + push it onto SERVICES.
|
|
4
|
+
*
|
|
5
|
+
* Tool names are globally namespaced (xrpl_<service>_<verb>) so cross-
|
|
6
|
+
* service calls in one MCP session don't collide with each other or
|
|
7
|
+
* with any other MCP server the user may have connected.
|
|
8
|
+
*/
|
|
9
|
+
import { sentinel } from "./sentinel.js";
|
|
10
|
+
import { pulse } from "./pulse.js";
|
|
11
|
+
import { telemetry } from "./telemetry.js";
|
|
12
|
+
import { trust } from "./trust.js";
|
|
13
|
+
export const SERVICES = [sentinel, pulse, telemetry, trust];
|
|
14
|
+
/** Flat list of every tool across every registered service. */
|
|
15
|
+
export const ALL_TOOLS = SERVICES.flatMap((s) => s.tools.map((t) => ({ ...t, _serviceId: s.id, _baseUrl: s.baseUrl })));
|
|
16
|
+
/** Look up the owning service for a given tool name. */
|
|
17
|
+
export function findToolOwner(toolName) {
|
|
18
|
+
for (const service of SERVICES) {
|
|
19
|
+
const tool = service.tools.find((t) => t.name === toolName);
|
|
20
|
+
if (tool)
|
|
21
|
+
return { service, tool };
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,CAAC,MAAM,QAAQ,GAAiB,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAE1E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9C,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CACtE,CAAC;AAEF,wDAAwD;AACxD,MAAM,UAAU,aAAa,CAAC,QAAgB;IAG5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAC5D,IAAI,IAAI;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XR-Pulse: normalized XRPL signal feed bridging public-source news,
|
|
3
|
+
* on-chain whale activity, and XLS-70/80/81 permissioned-domain
|
|
4
|
+
* lifecycle events into one time-ordered stream.
|
|
5
|
+
*
|
|
6
|
+
* News carries a four-hour XRPL price-window correlation. Whale rows
|
|
7
|
+
* carry sender + receiver addresses with XRPScan institutional
|
|
8
|
+
* labels. Permissioned-domain rows mirror XR-Trust's /events with
|
|
9
|
+
* cross-product enrichment. Paid via x402 ($0.10 USD per query).
|
|
10
|
+
*/
|
|
11
|
+
import type { ServiceDef } from "../types.js";
|
|
12
|
+
export declare const pulse: ServiceDef;
|