run402-mcp
Version:
MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.
109 lines • 4.82 kB
JavaScript
/**
* Single audit surface for the optional paid-fetch dependency stack.
*
* Every `viem` / `@x402/*` / `mppx` import the SDK performs flows through
* this file. Concentrating the imports here lets a reviewer enumerate the
* SDK's direct attack surface to those packages from one place, and lets
* the package.json declare them as `optionalPeerDependencies` — consumers
* who never make on-chain paid requests do not need to install them.
*
* Adding a new import here is the only way to grow the surface; doing so
* also widens what consumers must install to enable paid fetch. Keep this
* list minimal. When a symbol is small enough to inline (e.g. the
* `viem/chains` constants are ~5-line objects), prefer inlining over
* adding a new dependency edge.
*/
export class PaidStackUnavailable extends Error {
missingPackages;
constructor(missing) {
super(`run402: paid requests require optional peer dependencies that are not installed: ${missing.join(", ")}. ` +
`Install them with: npm install ${missing.join(" ")}`);
this.name = "PaidStackUnavailable";
this.missingPackages = missing;
}
}
function isModuleNotFound(err) {
if (!(err instanceof Error))
return false;
const code = err.code;
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND")
return true;
return /Cannot find (package|module)/.test(err.message);
}
class LoadCollector {
missing = new Set();
firstOtherError = null;
async load(pkg, load) {
try {
return await load();
}
catch (err) {
if (isModuleNotFound(err))
this.missing.add(pkg);
else if (this.firstOtherError === null)
this.firstOtherError = err;
return undefined;
}
}
throwIfFailed() {
if (this.missing.size > 0) {
throw new PaidStackUnavailable([...this.missing].sort());
}
// eslint-disable-next-line @typescript-eslint/only-throw-error -- rethrows the import failure unchanged
if (this.firstOtherError !== null)
throw this.firstOtherError;
}
}
export async function loadX402Stack() {
const c = new LoadCollector();
const accounts = await c.load("viem", () => import("viem/accounts"));
const viemMod = await c.load("viem", () => import("viem"));
const chains = await c.load("viem", () => import("viem/chains"));
const x402Fetch = await c.load("@x402/fetch", () => import("@x402/fetch"));
const x402EvmClient = await c.load("@x402/evm", () => import("@x402/evm/exact/client"));
const x402Evm = await c.load("@x402/evm", () => import("@x402/evm"));
const offerReceipt = await c.load("@x402/extensions", () => import("@x402/extensions/offer-receipt"));
c.throwIfFailed();
return {
privateKeyToAccount: accounts.privateKeyToAccount,
createPublicClient: viemMod.createPublicClient,
http: viemMod.http,
base: chains.base,
baseSepolia: chains.baseSepolia,
x402Client: x402Fetch.x402Client,
wrapFetchWithPayment: x402Fetch.wrapFetchWithPayment,
ExactEvmScheme: x402EvmClient.ExactEvmScheme,
toClientEvmSigner: x402Evm.toClientEvmSigner,
offerReceipt: {
extractOffersFromPaymentRequired: offerReceipt.extractOffersFromPaymentRequired,
decodeSignedOffers: offerReceipt.decodeSignedOffers,
findAcceptsObjectFromSignedOffer: offerReceipt.findAcceptsObjectFromSignedOffer,
isEIP712SignedOffer: offerReceipt.isEIP712SignedOffer,
isEIP712SignedReceipt: offerReceipt.isEIP712SignedReceipt,
verifyOfferSignatureEIP712: offerReceipt.verifyOfferSignatureEIP712,
verifyReceiptSignatureEIP712: offerReceipt.verifyReceiptSignatureEIP712,
extractReceiptFromResponse: offerReceipt.extractReceiptFromResponse,
},
};
}
/** The MPP challenge/credential codecs the Lightning rail needs (no Tempo, no viem). */
export async function loadLightningStack() {
const c = new LoadCollector();
const mppxSpecifier = "mppx";
const mppx = await c.load("mppx", () => import(/* webpackIgnore: true */ mppxSpecifier));
c.throwIfFailed();
return { Challenge: mppx.Challenge, Credential: mppx.Credential };
}
export async function loadMppStack() {
const c = new LoadCollector();
const mppxSpecifier = "mppx/client";
const mppx = await c.load("mppx", () => import(/* webpackIgnore: true */ mppxSpecifier));
const accounts = await c.load("viem", () => import("viem/accounts"));
c.throwIfFailed();
return {
privateKeyToAccount: accounts.privateKeyToAccount,
Mppx: mppx.Mppx,
tempo: mppx.tempo,
};
}
//# sourceMappingURL=_paid-stack.js.map