agents
Version:
A home for your AI agents
260 lines (259 loc) • 7.83 kB
JavaScript
import { t as bindMcpClient } from "../client-invoker-VNZ7X0nn.js";
import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server";
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/server";
import { registerExactEvmScheme as registerExactEvmScheme$1 } from "@x402/evm/exact/client";
//#region src/mcp/x402.ts
/**
* Map of legacy v1 network names to CAIP-2 identifiers.
* Allows backward compatibility with v1 config.
*/
const LEGACY_NETWORK_MAP = {
"base-sepolia": "eip155:84532",
base: "eip155:8453",
ethereum: "eip155:1",
sepolia: "eip155:11155111"
};
/**
* Normalize a network identifier to CAIP-2 format.
* Accepts both legacy v1 names ("base-sepolia") and CAIP-2 ("eip155:84532").
*/
function normalizeNetwork(network) {
return LEGACY_NETWORK_MAP[network] ?? network;
}
function withX402(server, cfg) {
const network = normalizeNetwork(cfg.network);
const resourceServer = new x402ResourceServer(new HTTPFacilitatorClient(cfg.facilitator ?? { url: "https://x402.org/facilitator" }));
registerExactEvmScheme(resourceServer);
let initPromise = null;
function ensureInitialized() {
if (!initPromise) initPromise = resourceServer.initialize().catch((err) => {
initPromise = null;
throw err;
});
return initPromise;
}
function paidTool(name, description, priceUSD, paramsSchema, annotations, cb) {
return server.registerTool(name, {
description,
inputSchema: paramsSchema,
annotations,
_meta: {
"agents-x402/paymentRequired": true,
"agents-x402/priceUSD": priceUSD
}
}, (async (args, extra) => {
await ensureInitialized();
const resourceConfig = {
scheme: "exact",
payTo: cfg.recipient,
price: priceUSD,
network,
maxTimeoutSeconds: 300
};
let requirements;
try {
requirements = await resourceServer.buildPaymentRequirements(resourceConfig);
} catch {
const payload = {
x402Version: 2,
error: "PRICE_COMPUTE_FAILED"
};
return {
isError: true,
_meta: { "x402/error": payload },
content: [{
type: "text",
text: JSON.stringify(payload)
}]
};
}
const resourceInfo = {
url: `x402://${name}`,
description,
mimeType: "application/json"
};
const headers = extra?.requestInfo?.headers ?? {};
const token = extra?._meta?.["x402/payment"] ?? headers["PAYMENT-SIGNATURE"] ?? headers["X-PAYMENT"];
const paymentRequired = (reason = "PAYMENT_REQUIRED", extraFields = {}) => {
const payload = {
x402Version: 2,
error: reason,
resource: resourceInfo,
accepts: requirements,
...extraFields
};
return {
isError: true,
_meta: { "x402/error": payload },
content: [{
type: "text",
text: JSON.stringify(payload)
}]
};
};
if (!token || typeof token !== "string") return paymentRequired();
let paymentPayload;
try {
paymentPayload = JSON.parse(atob(token));
} catch {
return paymentRequired("INVALID_PAYMENT");
}
const matchingReq = resourceServer.findMatchingRequirements(requirements, paymentPayload);
if (!matchingReq) return paymentRequired("INVALID_PAYMENT");
try {
const vr = await resourceServer.verifyPayment(paymentPayload, matchingReq);
if (!vr.isValid) return paymentRequired(vr.invalidReason ?? "INVALID_PAYMENT", { payer: vr.payer });
} catch {
return paymentRequired("INVALID_PAYMENT");
}
let result;
let failed = false;
try {
result = await cb(args, extra);
if (result && typeof result === "object" && "isError" in result && result.isError) failed = true;
} catch (e) {
failed = true;
result = {
isError: true,
content: [{
type: "text",
text: `Tool execution failed: ${String(e)}`
}]
};
}
if (!failed) try {
const s = await resourceServer.settlePayment(paymentPayload, matchingReq);
if (s.success) {
result._meta ??= {};
result._meta["x402/payment-response"] = {
success: true,
transaction: s.transaction,
network: s.network,
payer: s.payer
};
} else return paymentRequired(s.errorReason ?? "SETTLEMENT_FAILED");
} catch {
return paymentRequired("SETTLEMENT_FAILED");
}
return result;
}));
}
Object.defineProperty(server, "paidTool", {
value: paidTool,
writable: false,
enumerable: false,
configurable: true
});
return server;
}
function withX402Client(client, x402Config) {
const invoker = bindMcpClient(client);
const { account } = x402Config;
const maxPaymentValue = x402Config.maxPaymentValue ?? BigInt(1e5);
const paymentClient = new x402Client();
registerExactEvmScheme$1(paymentClient, { signer: account });
if (x402Config.network) {
const preferredNetwork = normalizeNetwork(x402Config.network);
paymentClient.registerPolicy((_version, reqs) => {
const matching = reqs.filter((r) => r.network === preferredNetwork);
return matching.length > 0 ? matching : reqs;
});
}
const listTools = async (params, options) => {
const toolsRes = await invoker.listTools(params, options);
return {
...toolsRes,
tools: toolsRes.tools.map((tool) => {
let description = tool.description;
if (tool._meta?.["agents-x402/paymentRequired"]) {
const cost = tool._meta?.["agents-x402/priceUSD"] ? `$${tool._meta?.["agents-x402/priceUSD"]}` : "an unknown amount";
description += ` (This is a paid tool, you will be charged ${cost} for its execution)`;
}
return {
...tool,
description
};
})
};
};
const callToolWithPayment = async (x402ConfirmationCallback, params, schemaOrOptions, options) => {
const invoke = (callParams) => invoker.callTool(callParams, schemaOrOptions, options);
const res = await invoke(params);
const maybeX402Error = res._meta?.["x402/error"];
if (res.isError && maybeX402Error && maybeX402Error.accepts && Array.isArray(maybeX402Error.accepts) && maybeX402Error.accepts.length > 0) {
const accepts = maybeX402Error.accepts;
const confirmationCallback = x402ConfirmationCallback ?? x402Config.confirmationCallback;
if (confirmationCallback && !await confirmationCallback(accepts)) return {
isError: true,
content: [{
type: "text",
text: "User declined payment"
}]
};
const selectedReq = accepts[0];
if (!selectedReq || selectedReq.scheme !== "exact") return res;
let amount;
try {
amount = BigInt(selectedReq.amount);
} catch {
return res;
}
if (amount > maxPaymentValue) return {
isError: true,
content: [{
type: "text",
text: `Payment exceeds client cap: ${amount} > ${maxPaymentValue}`
}]
};
const paymentRequiredResponse = {
x402Version: maybeX402Error.x402Version ?? 2,
resource: maybeX402Error.resource ?? {
url: "",
description: "",
mimeType: "application/json"
},
accepts,
extensions: maybeX402Error.extensions
};
let paymentPayload;
try {
paymentPayload = await paymentClient.createPaymentPayload(paymentRequiredResponse);
} catch {
return {
isError: true,
content: [{
type: "text",
text: "Failed to create payment payload"
}]
};
}
const token = btoa(JSON.stringify(paymentPayload));
return invoke({
...params,
_meta: {
...params._meta,
"x402/payment": token
}
});
}
return res;
};
const _client = client;
Object.defineProperty(_client, "listTools", {
value: listTools,
writable: false,
enumerable: false,
configurable: true
});
Object.defineProperty(_client, "callTool", {
value: callToolWithPayment,
writable: false,
enumerable: false,
configurable: true
});
return _client;
}
//#endregion
export { normalizeNetwork, withX402, withX402Client };
//# sourceMappingURL=x402.js.map