@hpp-io/x402-mcp-bridge 0.0.2 → 0.0.3
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 +120 -122
- package/bin/hpp-x402.js +5 -0
- package/dist/a2a.d.ts +2 -2
- package/dist/a2a.js +4 -4
- package/dist/a2a.js.map +1 -1
- package/dist/autoTopup.d.ts +2 -1
- package/dist/autoTopup.js.map +1 -1
- package/dist/cli/channel.d.ts +1 -1
- package/dist/cli/channel.js +1 -8
- package/dist/cli/channel.js.map +1 -1
- package/dist/cli/hpp-x402.d.ts +2 -0
- package/dist/cli/hpp-x402.js +375 -0
- package/dist/cli/hpp-x402.js.map +1 -0
- package/dist/cli/install-claude-code.d.ts +24 -0
- package/dist/cli/install-claude-code.js +50 -0
- package/dist/cli/install-claude-code.js.map +1 -0
- package/dist/cli/install-cursor.d.ts +7 -0
- package/dist/cli/install-cursor.js +26 -0
- package/dist/cli/install-cursor.js.map +1 -0
- package/dist/cli/install-mcp-host.d.ts +2 -2
- package/dist/cli/install-mcp-host.js.map +1 -1
- package/dist/cli/install-windsurf.d.ts +7 -0
- package/dist/cli/install-windsurf.js +37 -0
- package/dist/cli/install-windsurf.js.map +1 -0
- package/dist/cli/policy.d.ts +1 -1
- package/dist/cli/policy.js +1 -8
- package/dist/cli/policy.js.map +1 -1
- package/dist/cli/revoke.d.ts +1 -1
- package/dist/cli/revoke.js +1 -5
- package/dist/cli/revoke.js.map +1 -1
- package/dist/cli/safe.d.ts +62 -62
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +1 -5
- package/dist/cli/setup.js.map +1 -1
- package/dist/client.d.ts +6 -2
- package/dist/client.js +34 -15
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +46 -7
- package/dist/config.js +39 -5
- package/dist/config.js.map +1 -1
- package/dist/discovery.d.ts +43 -0
- package/dist/discovery.js +62 -0
- package/dist/discovery.js.map +1 -0
- package/dist/discoveryTools.d.ts +75 -0
- package/dist/discoveryTools.js +101 -0
- package/dist/discoveryTools.js.map +1 -0
- package/dist/funds/direct-balance.d.ts +27 -0
- package/dist/funds/direct-balance.js +58 -0
- package/dist/funds/direct-balance.js.map +1 -0
- package/dist/funds.d.ts +26 -0
- package/dist/funds.js +2 -0
- package/dist/funds.js.map +1 -0
- package/dist/httpX402.d.ts +8 -2
- package/dist/httpX402.js +19 -13
- package/dist/httpX402.js.map +1 -1
- package/dist/index.js +27 -10
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +5 -2
- package/dist/server.js +30 -64
- package/dist/server.js.map +1 -1
- package/package.json +7 -11
- package/bin/hpp-x402-channel.js +0 -5
- package/bin/hpp-x402-keychain.js +0 -5
- package/bin/hpp-x402-policy.js +0 -5
- package/bin/hpp-x402-safe-revoke.js +0 -5
- package/bin/hpp-x402-safe-setup.js +0 -5
- package/dist/autoSettlePickup.d.ts +0 -69
- package/dist/autoSettlePickup.js +0 -150
- package/dist/autoSettlePickup.js.map +0 -1
- package/dist/cli/keychain.d.ts +0 -1
- package/dist/cli/keychain.js +0 -147
- package/dist/cli/keychain.js.map +0 -1
package/dist/config.d.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* loudly at startup rather than mid-call.
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
|
-
declare const Schema: z.ZodObject<{
|
|
8
|
+
declare const Schema: z.ZodEffects<z.ZodObject<{
|
|
9
9
|
DELEGATE_PRIVATE_KEY: z.ZodEffects<z.ZodString, string, string>;
|
|
10
|
-
SAFE_ADDRESS: z.ZodString
|
|
11
|
-
ALLOWANCE_MODULE_ADDRESS: z.ZodString
|
|
10
|
+
SAFE_ADDRESS: z.ZodOptional<z.ZodString>;
|
|
11
|
+
ALLOWANCE_MODULE_ADDRESS: z.ZodOptional<z.ZodString>;
|
|
12
12
|
USDCE_ADDRESS: z.ZodString;
|
|
13
13
|
RESOURCE_SERVER_URL: z.ZodOptional<z.ZodString>;
|
|
14
14
|
HPP_RPC_URL: z.ZodString;
|
|
@@ -16,31 +16,70 @@ declare const Schema: z.ZodObject<{
|
|
|
16
16
|
TOPUP_AMOUNT_ATOMIC: z.ZodOptional<z.ZodString>;
|
|
17
17
|
TOPUP_HEADROOM_X: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
18
18
|
LOG_LEVEL: z.ZodDefault<z.ZodOptional<z.ZodEnum<["off", "info", "debug"]>>>;
|
|
19
|
+
HPP_X402_DISCOVERY: z.ZodDefault<z.ZodOptional<z.ZodEnum<["on", "off"]>>>;
|
|
20
|
+
HPP_X402_DISCOVERY_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
19
21
|
}, "strip", z.ZodTypeAny, {
|
|
20
22
|
DELEGATE_PRIVATE_KEY: string;
|
|
21
|
-
SAFE_ADDRESS: string;
|
|
22
|
-
ALLOWANCE_MODULE_ADDRESS: string;
|
|
23
23
|
USDCE_ADDRESS: string;
|
|
24
24
|
HPP_RPC_URL: string;
|
|
25
25
|
HPP_NETWORK: string;
|
|
26
26
|
TOPUP_HEADROOM_X: string;
|
|
27
27
|
LOG_LEVEL: "off" | "info" | "debug";
|
|
28
|
+
HPP_X402_DISCOVERY: "off" | "on";
|
|
29
|
+
HPP_X402_DISCOVERY_URL: string;
|
|
30
|
+
SAFE_ADDRESS?: string | undefined;
|
|
31
|
+
ALLOWANCE_MODULE_ADDRESS?: string | undefined;
|
|
28
32
|
RESOURCE_SERVER_URL?: string | undefined;
|
|
29
33
|
TOPUP_AMOUNT_ATOMIC?: string | undefined;
|
|
30
34
|
}, {
|
|
31
35
|
DELEGATE_PRIVATE_KEY: string;
|
|
32
|
-
SAFE_ADDRESS: string;
|
|
33
|
-
ALLOWANCE_MODULE_ADDRESS: string;
|
|
34
36
|
USDCE_ADDRESS: string;
|
|
35
37
|
HPP_RPC_URL: string;
|
|
36
38
|
HPP_NETWORK: string;
|
|
39
|
+
SAFE_ADDRESS?: string | undefined;
|
|
40
|
+
ALLOWANCE_MODULE_ADDRESS?: string | undefined;
|
|
37
41
|
RESOURCE_SERVER_URL?: string | undefined;
|
|
38
42
|
TOPUP_AMOUNT_ATOMIC?: string | undefined;
|
|
39
43
|
TOPUP_HEADROOM_X?: string | undefined;
|
|
40
44
|
LOG_LEVEL?: "off" | "info" | "debug" | undefined;
|
|
45
|
+
HPP_X402_DISCOVERY?: "off" | "on" | undefined;
|
|
46
|
+
HPP_X402_DISCOVERY_URL?: string | undefined;
|
|
47
|
+
}>, {
|
|
48
|
+
DELEGATE_PRIVATE_KEY: string;
|
|
49
|
+
USDCE_ADDRESS: string;
|
|
50
|
+
HPP_RPC_URL: string;
|
|
51
|
+
HPP_NETWORK: string;
|
|
52
|
+
TOPUP_HEADROOM_X: string;
|
|
53
|
+
LOG_LEVEL: "off" | "info" | "debug";
|
|
54
|
+
HPP_X402_DISCOVERY: "off" | "on";
|
|
55
|
+
HPP_X402_DISCOVERY_URL: string;
|
|
56
|
+
SAFE_ADDRESS?: string | undefined;
|
|
57
|
+
ALLOWANCE_MODULE_ADDRESS?: string | undefined;
|
|
58
|
+
RESOURCE_SERVER_URL?: string | undefined;
|
|
59
|
+
TOPUP_AMOUNT_ATOMIC?: string | undefined;
|
|
60
|
+
}, {
|
|
61
|
+
DELEGATE_PRIVATE_KEY: string;
|
|
62
|
+
USDCE_ADDRESS: string;
|
|
63
|
+
HPP_RPC_URL: string;
|
|
64
|
+
HPP_NETWORK: string;
|
|
65
|
+
SAFE_ADDRESS?: string | undefined;
|
|
66
|
+
ALLOWANCE_MODULE_ADDRESS?: string | undefined;
|
|
67
|
+
RESOURCE_SERVER_URL?: string | undefined;
|
|
68
|
+
TOPUP_AMOUNT_ATOMIC?: string | undefined;
|
|
69
|
+
TOPUP_HEADROOM_X?: string | undefined;
|
|
70
|
+
LOG_LEVEL?: "off" | "info" | "debug" | undefined;
|
|
71
|
+
HPP_X402_DISCOVERY?: "off" | "on" | undefined;
|
|
72
|
+
HPP_X402_DISCOVERY_URL?: string | undefined;
|
|
41
73
|
}>;
|
|
42
74
|
export type Config = z.infer<typeof Schema> & {
|
|
43
75
|
chainId: number;
|
|
76
|
+
/** "safe" when SAFE_ADDRESS + ALLOWANCE_MODULE_ADDRESS are set (autoTopup
|
|
77
|
+
* from the Safe); "light" when both are omitted (delegate holds USDC.e). */
|
|
78
|
+
walletMode: "safe" | "light";
|
|
79
|
+
/** true when HPP_X402_DISCOVERY === "on" — register hpp_discover/hpp_call. */
|
|
80
|
+
discoveryEnabled: boolean;
|
|
81
|
+
/** Base URL of the discovery REST API. */
|
|
82
|
+
discoveryUrl: string;
|
|
44
83
|
};
|
|
45
84
|
export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
|
|
46
85
|
export {};
|
package/dist/config.js
CHANGED
|
@@ -16,10 +16,12 @@ const Schema = z.object({
|
|
|
16
16
|
DELEGATE_PRIVATE_KEY: z
|
|
17
17
|
.string()
|
|
18
18
|
.refine((v) => HEX_KEY.test(v) || KEYCHAIN_URI.test(v), "expected 0x + 64 hex chars OR keychain://hpp-x402/<account>"),
|
|
19
|
-
// Safe wallet that holds the user's USDC.e.
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
|
|
19
|
+
// Safe wallet that holds the user's USDC.e (Safe mode only). Omit for light
|
|
20
|
+
// mode, where the delegate EOA holds USDC.e directly. Must be set together
|
|
21
|
+
// with ALLOWANCE_MODULE_ADDRESS (both-or-neither, enforced below).
|
|
22
|
+
SAFE_ADDRESS: z.string().regex(HEX_ADDR).optional(),
|
|
23
|
+
// Deployed AllowanceModule (Safe mode only; pairs with SAFE_ADDRESS).
|
|
24
|
+
ALLOWANCE_MODULE_ADDRESS: z.string().regex(HEX_ADDR).optional(),
|
|
23
25
|
// Asset paid in (USDC.e on HPP).
|
|
24
26
|
USDCE_ADDRESS: z.string().regex(HEX_ADDR),
|
|
25
27
|
// Remote MCP server we proxy to (the seller). Optional: when unset the
|
|
@@ -49,6 +51,31 @@ const Schema = z.object({
|
|
|
49
51
|
.default("10"),
|
|
50
52
|
// Logging. "off" = silent (good for clean stdio), "debug" = verbose stderr.
|
|
51
53
|
LOG_LEVEL: z.enum(["off", "info", "debug"]).optional().default("info"),
|
|
54
|
+
// Curated service discovery (hpp-x402-discovery). "on" (default) registers
|
|
55
|
+
// the hpp_discover / hpp_call tools that query the HPP discovery directory —
|
|
56
|
+
// a facilitator-indexed, semi-curated list of paid x402 services. "off"
|
|
57
|
+
// disables them (manual RESOURCE_SERVER_URL only).
|
|
58
|
+
HPP_X402_DISCOVERY: z.enum(["on", "off"]).optional().default("on"),
|
|
59
|
+
HPP_X402_DISCOVERY_URL: z
|
|
60
|
+
.string()
|
|
61
|
+
.url()
|
|
62
|
+
.optional()
|
|
63
|
+
.default("https://x402-discovery.hpp.io"),
|
|
64
|
+
})
|
|
65
|
+
// Wallet mode is inferred from Safe config presence: both set = Safe mode
|
|
66
|
+
// (autoTopup from the Safe within an on-chain cap); both omitted = light mode
|
|
67
|
+
// (delegate EOA holds USDC.e directly). Setting one without the other is a
|
|
68
|
+
// config error.
|
|
69
|
+
.superRefine((v, ctx) => {
|
|
70
|
+
const hasSafe = !!v.SAFE_ADDRESS;
|
|
71
|
+
const hasModule = !!v.ALLOWANCE_MODULE_ADDRESS;
|
|
72
|
+
if (hasSafe !== hasModule) {
|
|
73
|
+
ctx.addIssue({
|
|
74
|
+
code: z.ZodIssueCode.custom,
|
|
75
|
+
path: [hasSafe ? "ALLOWANCE_MODULE_ADDRESS" : "SAFE_ADDRESS"],
|
|
76
|
+
message: "SAFE_ADDRESS and ALLOWANCE_MODULE_ADDRESS must be set together (Safe mode) or both omitted (light mode)",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
52
79
|
});
|
|
53
80
|
export function loadConfig(env = process.env) {
|
|
54
81
|
const parsed = Schema.safeParse(env);
|
|
@@ -60,6 +87,13 @@ export function loadConfig(env = process.env) {
|
|
|
60
87
|
}
|
|
61
88
|
const v = parsed.data;
|
|
62
89
|
const chainId = Number(v.HPP_NETWORK.split(":")[1]);
|
|
63
|
-
|
|
90
|
+
const walletMode = v.SAFE_ADDRESS && v.ALLOWANCE_MODULE_ADDRESS ? "safe" : "light";
|
|
91
|
+
return {
|
|
92
|
+
...v,
|
|
93
|
+
chainId,
|
|
94
|
+
walletMode,
|
|
95
|
+
discoveryEnabled: v.HPP_X402_DISCOVERY === "on",
|
|
96
|
+
discoveryUrl: v.HPP_X402_DISCOVERY_URL,
|
|
97
|
+
};
|
|
64
98
|
}
|
|
65
99
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,QAAQ,GAAG,qBAAqB,CAAC;AACvC,MAAM,OAAO,GAAG,qBAAqB,CAAC;AACtC,MAAM,YAAY,GAAG,wCAAwC,CAAC;AAE9D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,qEAAqE;IACrE,kBAAkB;IAClB,oDAAoD;IACpD,+EAA+E;IAC/E,oBAAoB,EAAE,CAAC;SACpB,MAAM,EAAE;SACR,MAAM,CACL,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAC9C,6DAA6D,CAC9D;IAEH,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface DiscoveredResource {
|
|
2
|
+
id: string;
|
|
3
|
+
type: "http" | "mcp" | "a2a";
|
|
4
|
+
resourceUrl: string;
|
|
5
|
+
routeTemplate?: string;
|
|
6
|
+
toolName?: string;
|
|
7
|
+
skillId?: string;
|
|
8
|
+
agentCardUrl?: string;
|
|
9
|
+
payTo: string;
|
|
10
|
+
network: string;
|
|
11
|
+
asset: string;
|
|
12
|
+
scheme: string;
|
|
13
|
+
priceAtomic: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
httpMethod?: string;
|
|
16
|
+
bodyType?: "json" | "form-data" | "text";
|
|
17
|
+
transport?: "streamable-http" | "sse";
|
|
18
|
+
x402Version: number;
|
|
19
|
+
}
|
|
20
|
+
export interface DiscoveredResourceDetail extends DiscoveredResource {
|
|
21
|
+
metadata?: {
|
|
22
|
+
info?: unknown;
|
|
23
|
+
schema?: unknown;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface DiscoverQuery {
|
|
27
|
+
/** Free-text semantic search; omit to browse the newest/highest-ranked. */
|
|
28
|
+
query?: string;
|
|
29
|
+
type?: "http" | "mcp" | "a2a" | "all";
|
|
30
|
+
/** CAIP-2 network filter, e.g. "eip155:190415". */
|
|
31
|
+
network?: string;
|
|
32
|
+
limit?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare class DiscoveryClient {
|
|
35
|
+
private readonly baseUrl;
|
|
36
|
+
private readonly timeoutMs;
|
|
37
|
+
constructor(baseUrl: string, timeoutMs?: number);
|
|
38
|
+
private get;
|
|
39
|
+
/** List or semantically search the directory. */
|
|
40
|
+
discover(q: DiscoverQuery): Promise<DiscoveredResource[]>;
|
|
41
|
+
/** Full detail for one resource (incl. metadata.schema when present). */
|
|
42
|
+
detail(id: string): Promise<DiscoveredResourceDetail>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the HPP x402-discovery REST API — a curated, facilitator-indexed
|
|
3
|
+
* directory of paid x402 services on the HPP chain.
|
|
4
|
+
*
|
|
5
|
+
* Read-only from the bridge's side: we query discovery to *find* services,
|
|
6
|
+
* then pay them directly with the bridge's own wallet. Discovery never holds
|
|
7
|
+
* funds or sees our keys (non-custodial).
|
|
8
|
+
*
|
|
9
|
+
* REST contract (hpp-x402-discovery/spec/openapi.yaml → routes/discovery.ts):
|
|
10
|
+
* GET /discovery/resources?type&network&limit&offset -> { items: [...] }
|
|
11
|
+
* GET /discovery/search?q&type&network&sort&limit -> { items: [...] }
|
|
12
|
+
* GET /discovery/resources/:id -> ResourceDetail
|
|
13
|
+
*/
|
|
14
|
+
import { log } from "./log.js";
|
|
15
|
+
export class DiscoveryClient {
|
|
16
|
+
baseUrl;
|
|
17
|
+
timeoutMs;
|
|
18
|
+
constructor(baseUrl, timeoutMs = 10_000) {
|
|
19
|
+
this.baseUrl = baseUrl;
|
|
20
|
+
this.timeoutMs = timeoutMs;
|
|
21
|
+
}
|
|
22
|
+
async get(path) {
|
|
23
|
+
const url = this.baseUrl.replace(/\/$/, "") + path;
|
|
24
|
+
const ac = new AbortController();
|
|
25
|
+
const t = setTimeout(() => ac.abort(), this.timeoutMs);
|
|
26
|
+
try {
|
|
27
|
+
const res = await fetch(url, {
|
|
28
|
+
signal: ac.signal,
|
|
29
|
+
headers: { accept: "application/json" },
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok)
|
|
32
|
+
throw new Error(`discovery ${res.status} for ${path}`);
|
|
33
|
+
return (await res.json());
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
clearTimeout(t);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** List or semantically search the directory. */
|
|
40
|
+
async discover(q) {
|
|
41
|
+
const type = q.type ?? "all";
|
|
42
|
+
const limit = Math.min(Math.max(q.limit ?? 20, 1), 50);
|
|
43
|
+
const params = new URLSearchParams();
|
|
44
|
+
params.set("type", type);
|
|
45
|
+
if (q.network)
|
|
46
|
+
params.set("network", q.network);
|
|
47
|
+
params.set("limit", String(limit));
|
|
48
|
+
const query = q.query?.trim();
|
|
49
|
+
const path = query
|
|
50
|
+
? `/discovery/search?q=${encodeURIComponent(query)}&${params.toString()}`
|
|
51
|
+
: `/discovery/resources?${params.toString()}`;
|
|
52
|
+
const out = await this.get(path);
|
|
53
|
+
const items = out.items ?? [];
|
|
54
|
+
log.debug("discovery.discover", { path, count: items.length });
|
|
55
|
+
return items;
|
|
56
|
+
}
|
|
57
|
+
/** Full detail for one resource (incl. metadata.schema when present). */
|
|
58
|
+
async detail(id) {
|
|
59
|
+
return this.get(`/discovery/resources/${encodeURIComponent(id)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAmC/B,MAAM,OAAO,eAAe;IAEP;IACA;IAFnB,YACmB,OAAe,EACf,YAAY,MAAM;QADlB,YAAO,GAAP,OAAO,CAAQ;QACf,cAAS,GAAT,SAAS,CAAS;IAClC,CAAC;IAEI,KAAK,CAAC,GAAG,CAAI,IAAY;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC;QACnD,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC3B,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;aACxC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,QAAQ,IAAI,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;QACjC,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,KAAK,CAAC,QAAQ,CAAC,CAAgB;QAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAEnC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,KAAK;YAChB,CAAC,CAAC,uBAAuB,kBAAkB,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE;YACzE,CAAC,CAAC,wBAAwB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QAEhD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAmC,IAAI,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9B,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,GAAG,CACb,wBAAwB,kBAAkB,CAAC,EAAE,CAAC,EAAE,CACjD,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery-backed local tools: hpp_discover + hpp_call.
|
|
3
|
+
*
|
|
4
|
+
* The multi-service UX decision (SERVICE_CONNECTION_DESIGN §멀티서비스 UX):
|
|
5
|
+
* instead of proxying every discovered service's tools (context explosion),
|
|
6
|
+
* expose two generic tools —
|
|
7
|
+
* - hpp_discover: list/search the curated directory (read-only, no payment)
|
|
8
|
+
* - hpp_call: call one discovered service by id (payment via our wallet)
|
|
9
|
+
*
|
|
10
|
+
* hpp_call routes HTTP-typed resources through the same x402 HTTP payment path
|
|
11
|
+
* as x402_http_call, but marks the call `trustedSource` so it skips the manual
|
|
12
|
+
* host allowlist — curated discovery is the trust boundary — while keeping the
|
|
13
|
+
* daily spend cap. MCP/A2A-typed resources return connection guidance.
|
|
14
|
+
*/
|
|
15
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
16
|
+
import type { DiscoveryClient } from "./discovery.js";
|
|
17
|
+
import { type HttpX402Deps } from "./httpX402.js";
|
|
18
|
+
export declare const HPP_DISCOVER_TOOL: {
|
|
19
|
+
readonly name: "hpp_discover";
|
|
20
|
+
readonly description: string;
|
|
21
|
+
readonly inputSchema: {
|
|
22
|
+
readonly type: "object";
|
|
23
|
+
readonly properties: {
|
|
24
|
+
readonly query: {
|
|
25
|
+
readonly type: "string";
|
|
26
|
+
readonly description: "Optional free-text search over the directory.";
|
|
27
|
+
};
|
|
28
|
+
readonly type: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
readonly enum: readonly ["http", "mcp", "a2a", "all"];
|
|
31
|
+
readonly description: "Filter by resource type (default all).";
|
|
32
|
+
};
|
|
33
|
+
readonly network: {
|
|
34
|
+
readonly type: "string";
|
|
35
|
+
readonly description: "Filter by CAIP-2 network, e.g. eip155:190415.";
|
|
36
|
+
};
|
|
37
|
+
readonly limit: {
|
|
38
|
+
readonly type: "number";
|
|
39
|
+
readonly description: "Max results (default 20, max 50).";
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
readonly additionalProperties: false;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export declare const HPP_CALL_TOOL: {
|
|
46
|
+
readonly name: "hpp_call";
|
|
47
|
+
readonly description: string;
|
|
48
|
+
readonly inputSchema: {
|
|
49
|
+
readonly type: "object";
|
|
50
|
+
readonly properties: {
|
|
51
|
+
readonly resourceId: {
|
|
52
|
+
readonly type: "string";
|
|
53
|
+
readonly description: "Service id returned by hpp_discover.";
|
|
54
|
+
};
|
|
55
|
+
readonly body: {
|
|
56
|
+
readonly type: "object";
|
|
57
|
+
readonly description: "Request body / input args for the service.";
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
readonly required: readonly ["resourceId"];
|
|
61
|
+
readonly additionalProperties: false;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export interface DiscoverArgs {
|
|
65
|
+
query?: string;
|
|
66
|
+
type?: "http" | "mcp" | "a2a" | "all";
|
|
67
|
+
network?: string;
|
|
68
|
+
limit?: number;
|
|
69
|
+
}
|
|
70
|
+
export interface HppCallArgs {
|
|
71
|
+
resourceId: string;
|
|
72
|
+
body?: unknown;
|
|
73
|
+
}
|
|
74
|
+
export declare function hppDiscover(client: DiscoveryClient, args: DiscoverArgs): Promise<CallToolResult>;
|
|
75
|
+
export declare function hppCall(deps: HttpX402Deps, client: DiscoveryClient, args: HppCallArgs): Promise<CallToolResult>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { x402HttpCall } from "./httpX402.js";
|
|
2
|
+
export const HPP_DISCOVER_TOOL = {
|
|
3
|
+
name: "hpp_discover",
|
|
4
|
+
description: "Discover paid x402 services on the HPP chain from the curated discovery " +
|
|
5
|
+
"directory. Returns services with their resourceId, description, price " +
|
|
6
|
+
"(USDC.e atomic units), network and type. Pass `query` for a semantic " +
|
|
7
|
+
"search (e.g. 'image generation'), or omit it to browse. Then invoke one " +
|
|
8
|
+
"with hpp_call({ resourceId, body }).",
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
query: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Optional free-text search over the directory.",
|
|
15
|
+
},
|
|
16
|
+
type: {
|
|
17
|
+
type: "string",
|
|
18
|
+
enum: ["http", "mcp", "a2a", "all"],
|
|
19
|
+
description: "Filter by resource type (default all).",
|
|
20
|
+
},
|
|
21
|
+
network: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Filter by CAIP-2 network, e.g. eip155:190415.",
|
|
24
|
+
},
|
|
25
|
+
limit: { type: "number", description: "Max results (default 20, max 50)." },
|
|
26
|
+
},
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export const HPP_CALL_TOOL = {
|
|
31
|
+
name: "hpp_call",
|
|
32
|
+
description: "Call a service found via hpp_discover. Pass its `resourceId` and a `body` " +
|
|
33
|
+
"(the service's input args). Payment (USDC.e) is handled automatically with " +
|
|
34
|
+
"your wallet, subject to the daily spend cap — you do not sign anything. " +
|
|
35
|
+
"HTTP-typed services are called directly; MCP/A2A-typed services return " +
|
|
36
|
+
"connection guidance.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
resourceId: {
|
|
41
|
+
type: "string",
|
|
42
|
+
description: "Service id returned by hpp_discover.",
|
|
43
|
+
},
|
|
44
|
+
body: {
|
|
45
|
+
type: "object",
|
|
46
|
+
description: "Request body / input args for the service.",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
required: ["resourceId"],
|
|
50
|
+
additionalProperties: false,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
function errorResult(text) {
|
|
54
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
55
|
+
}
|
|
56
|
+
export async function hppDiscover(client, args) {
|
|
57
|
+
const resources = await client.discover(args);
|
|
58
|
+
const services = resources.map((r) => ({
|
|
59
|
+
resourceId: r.id,
|
|
60
|
+
type: r.type,
|
|
61
|
+
description: r.description ?? r.toolName ?? r.resourceUrl,
|
|
62
|
+
priceAtomic: r.priceAtomic,
|
|
63
|
+
asset: r.asset,
|
|
64
|
+
network: r.network,
|
|
65
|
+
scheme: r.scheme,
|
|
66
|
+
...(r.toolName ? { toolName: r.toolName } : {}),
|
|
67
|
+
}));
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{ type: "text", text: JSON.stringify({ count: services.length, services }) },
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export async function hppCall(deps, client, args) {
|
|
75
|
+
if (!args.resourceId || typeof args.resourceId !== "string") {
|
|
76
|
+
return errorResult("resourceId required");
|
|
77
|
+
}
|
|
78
|
+
let detail;
|
|
79
|
+
try {
|
|
80
|
+
detail = await client.detail(args.resourceId);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
return errorResult(`discovery lookup failed: ${err.message}`);
|
|
84
|
+
}
|
|
85
|
+
if (detail.type !== "http") {
|
|
86
|
+
return errorResult(`resource "${args.resourceId}" is type "${detail.type}" — connect to it ` +
|
|
87
|
+
`directly at ${detail.resourceUrl}` +
|
|
88
|
+
(detail.type === "a2a"
|
|
89
|
+
? ` (use pay_a2a_agent with its skill id).`
|
|
90
|
+
: ` (MCP transport).`));
|
|
91
|
+
}
|
|
92
|
+
// Curated discovery is the trust boundary → skip the manual host allowlist
|
|
93
|
+
// (trustedSource) but keep the spend cap. Exact-scheme only today; upto/batch
|
|
94
|
+
// resources surface a clear "no exact accept" error (follow-up).
|
|
95
|
+
return x402HttpCall({ ...deps, trustedSource: true }, {
|
|
96
|
+
url: detail.resourceUrl,
|
|
97
|
+
method: detail.httpMethod ?? "POST",
|
|
98
|
+
body: args.body,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=discoveryTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoveryTools.js","sourceRoot":"","sources":["../src/discoveryTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DirectBalance — light wallet mode (Safe-less).
|
|
3
|
+
*
|
|
4
|
+
* The delegate EOA holds USDC.e directly (funded by sending USDC.e straight to
|
|
5
|
+
* its address). No Safe, no AllowanceModule, no autoTopup — and because x402
|
|
6
|
+
* settlement is gasless (the facilitator submits EIP-3009 / sponsors the upto
|
|
7
|
+
* Permit2 approval), the delegate needs no native gas either. So funding the
|
|
8
|
+
* wallet is a single USDC.e transfer.
|
|
9
|
+
*
|
|
10
|
+
* This `Funds` impl simply reads the delegate's balance before each payment and,
|
|
11
|
+
* when short, throws an error whose message doubles as a funding instruction the
|
|
12
|
+
* MCP host surfaces to the LLM/user.
|
|
13
|
+
*/
|
|
14
|
+
import { type Address, type Hex } from "viem";
|
|
15
|
+
import type { Funds } from "../funds.js";
|
|
16
|
+
export declare class DirectBalance implements Funds {
|
|
17
|
+
private readonly delegate;
|
|
18
|
+
private readonly token;
|
|
19
|
+
private readonly publicClient;
|
|
20
|
+
constructor(delegate: Address, token: Address, chainId: number, rpcUrl: string);
|
|
21
|
+
/**
|
|
22
|
+
* Light mode never performs an on-chain topup, so this either returns null
|
|
23
|
+
* (sufficient balance) or throws with a funding instruction. It never returns
|
|
24
|
+
* a tx hash.
|
|
25
|
+
*/
|
|
26
|
+
ensure(requiredAtomic: bigint): Promise<Hex | null>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DirectBalance — light wallet mode (Safe-less).
|
|
3
|
+
*
|
|
4
|
+
* The delegate EOA holds USDC.e directly (funded by sending USDC.e straight to
|
|
5
|
+
* its address). No Safe, no AllowanceModule, no autoTopup — and because x402
|
|
6
|
+
* settlement is gasless (the facilitator submits EIP-3009 / sponsors the upto
|
|
7
|
+
* Permit2 approval), the delegate needs no native gas either. So funding the
|
|
8
|
+
* wallet is a single USDC.e transfer.
|
|
9
|
+
*
|
|
10
|
+
* This `Funds` impl simply reads the delegate's balance before each payment and,
|
|
11
|
+
* when short, throws an error whose message doubles as a funding instruction the
|
|
12
|
+
* MCP host surfaces to the LLM/user.
|
|
13
|
+
*/
|
|
14
|
+
import { createPublicClient, http, defineChain, } from "viem";
|
|
15
|
+
const ERC20_BALANCE_ABI = [
|
|
16
|
+
{
|
|
17
|
+
type: "function",
|
|
18
|
+
name: "balanceOf",
|
|
19
|
+
inputs: [{ name: "account", type: "address" }],
|
|
20
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
21
|
+
stateMutability: "view",
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
export class DirectBalance {
|
|
25
|
+
delegate;
|
|
26
|
+
token;
|
|
27
|
+
publicClient;
|
|
28
|
+
constructor(delegate, token, chainId, rpcUrl) {
|
|
29
|
+
this.delegate = delegate;
|
|
30
|
+
this.token = token;
|
|
31
|
+
const chain = defineChain({
|
|
32
|
+
id: chainId,
|
|
33
|
+
name: `chain-${chainId}`,
|
|
34
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
35
|
+
rpcUrls: { default: { http: [rpcUrl] } },
|
|
36
|
+
});
|
|
37
|
+
this.publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Light mode never performs an on-chain topup, so this either returns null
|
|
41
|
+
* (sufficient balance) or throws with a funding instruction. It never returns
|
|
42
|
+
* a tx hash.
|
|
43
|
+
*/
|
|
44
|
+
async ensure(requiredAtomic) {
|
|
45
|
+
const balance = (await this.publicClient.readContract({
|
|
46
|
+
address: this.token,
|
|
47
|
+
abi: ERC20_BALANCE_ABI,
|
|
48
|
+
functionName: "balanceOf",
|
|
49
|
+
args: [this.delegate],
|
|
50
|
+
}));
|
|
51
|
+
if (balance >= requiredAtomic)
|
|
52
|
+
return null;
|
|
53
|
+
throw new Error(`insufficient USDC.e: need ${requiredAtomic}, have ${balance}. ` +
|
|
54
|
+
`Send USDC.e to ${this.delegate} on this network to top up ` +
|
|
55
|
+
`(no native gas required).`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=direct-balance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct-balance.js","sourceRoot":"","sources":["../../src/funds/direct-balance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,kBAAkB,EAClB,IAAI,EACJ,WAAW,GAIZ,MAAM,MAAM,CAAC;AAId,MAAM,iBAAiB,GAAG;IACxB;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC9C,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACxC,eAAe,EAAE,MAAM;KACxB;CACO,CAAC;AAEX,MAAM,OAAO,aAAa;IAIL;IACA;IAJF,YAAY,CAAe;IAE5C,YACmB,QAAiB,EACjB,KAAc,EAC/B,OAAe,EACf,MAAc;QAHG,aAAQ,GAAR,QAAQ,CAAS;QACjB,UAAK,GAAL,KAAK,CAAS;QAI/B,MAAM,KAAK,GAAG,WAAW,CAAC;YACxB,EAAE,EAAE,OAAO;YACX,IAAI,EAAE,SAAS,OAAO,EAAE;YACxB,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE;YAC9D,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE;SACzC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,kBAAkB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,cAAsB;QACjC,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC;YACpD,OAAO,EAAE,IAAI,CAAC,KAAK;YACnB,GAAG,EAAE,iBAAiB;YACtB,YAAY,EAAE,WAAW;YACzB,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;SACtB,CAAC,CAAW,CAAC;QAEd,IAAI,OAAO,IAAI,cAAc;YAAE,OAAO,IAAI,CAAC;QAE3C,MAAM,IAAI,KAAK,CACb,6BAA6B,cAAc,UAAU,OAAO,IAAI;YAC9D,kBAAkB,IAAI,CAAC,QAAQ,6BAA6B;YAC5D,2BAA2B,CAC9B,CAAC;IACJ,CAAC;CACF"}
|
package/dist/funds.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Funds — abstraction over "ensure the delegate can cover this payment".
|
|
3
|
+
*
|
|
4
|
+
* Two implementations back the two wallet modes:
|
|
5
|
+
* - AutoTopup (Safe mode): pulls USDC.e from the user's Safe to the delegate
|
|
6
|
+
* EOA via AllowanceModule.executeAllowanceTransfer, within the on-chain
|
|
7
|
+
* daily cap, when the delegate balance is short.
|
|
8
|
+
* - DirectBalance (light mode): the delegate EOA holds USDC.e directly; this
|
|
9
|
+
* impl only verifies the balance and surfaces a clear funding instruction
|
|
10
|
+
* when short — no Safe, no on-chain topup, no native gas.
|
|
11
|
+
*
|
|
12
|
+
* The payment path (client.ts onPaymentRequested) depends only on this
|
|
13
|
+
* interface, so the two modes share a single code path.
|
|
14
|
+
*/
|
|
15
|
+
import type { Hex } from "viem";
|
|
16
|
+
export interface Funds {
|
|
17
|
+
/**
|
|
18
|
+
* Ensure the delegate holds at least `requiredAtomic` of the payment asset
|
|
19
|
+
* before the x402 payment is signed.
|
|
20
|
+
*
|
|
21
|
+
* Returns the topup tx hash when an on-chain refill was performed (Safe mode),
|
|
22
|
+
* or `null` when no action was needed (already sufficient). Throws a clear,
|
|
23
|
+
* host-surfaceable error when funds are insufficient and cannot be topped up.
|
|
24
|
+
*/
|
|
25
|
+
ensure(requiredAtomic: bigint): Promise<Hex | null>;
|
|
26
|
+
}
|
package/dist/funds.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"funds.js","sourceRoot":"","sources":["../src/funds.ts"],"names":[],"mappings":""}
|
package/dist/httpX402.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type { Network } from "@x402/core/types";
|
|
2
2
|
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { Funds } from "./funds.js";
|
|
4
4
|
import type { RawEoaSigner } from "./signers/raw-eoa.js";
|
|
5
5
|
export interface HttpX402Deps {
|
|
6
6
|
signer: RawEoaSigner;
|
|
7
7
|
network: Network;
|
|
8
8
|
/** Ensure the delegate holds enough USDC.e before paying. */
|
|
9
|
-
|
|
9
|
+
funds?: Funds;
|
|
10
|
+
/**
|
|
11
|
+
* Set by hpp_call for curated-discovery resources: skip the manual host
|
|
12
|
+
* allowlist + local credential injection (discovery is the trust boundary).
|
|
13
|
+
* The spend cap (default limits, per-call amount, cooldown) still applies.
|
|
14
|
+
*/
|
|
15
|
+
trustedSource?: boolean;
|
|
10
16
|
}
|
|
11
17
|
export declare const X402_HTTP_TOOL: {
|
|
12
18
|
readonly name: "x402_http_call";
|