Skip to main content
Glama

fetch-with-payment

Fetch data from websites or APIs and automatically handle required payments (402 status) using Solana payment processing.

Instructions

Fetch data from a website or API. Automatically handles payment if required (402 status).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesThe URL to fetch data from
methodNoHTTP method (default: GET)
bodyNoRequest body for POST requests (JSON string)

Implementation Reference

  • The handler function that executes the 'fetch-with-payment' tool logic, including payment client creation, fetch execution, payment tracking, limit enforcement, and response formatting.
    async ({ url, method = "GET", body }) => { try { const signer = await createSigner("solana-devnet", process.env.SOLANA_PRIVATE_KEY || " "); const paymentClient = new ServerPaymentClient({ network: 'solana-devnet', signer }); const options: RequestInit = { method, headers: { "Content-Type": "application/json" }, }; if (method === "POST" && body) { options.body = body; } const response = await paymentClient.fetch(url, options); // Track payment if one was made const paymentInfo = (paymentClient as any).extractPaymentInfo?.(response); if (paymentInfo) { const amountInSol = paymentInfo.amount / LAMPORTS_PER_SOL; // Check payment limit if (paymentLimit !== null && amountInSol > paymentLimit) { throw new Error(`Payment amount (${amountInSol} SOL) exceeds limit (${paymentLimit} SOL)`); } paymentHistory.push({ url, amount: amountInSol, recipient: paymentInfo.recipient, timestamp: new Date().toISOString(), signature: paymentInfo.signature }); } const data = await response.json(); return { content: [{ type: "text", text: JSON.stringify({ success: true, data, payment_made: !!paymentInfo, payment_amount: paymentInfo ? paymentInfo.amount / LAMPORTS_PER_SOL : 0 }) }] }; } catch (err: any) { return { content: [{ type: "text", text: `Error: ${err.message || "Request failed"}` }], isError: true }; } }
  • Zod input schema defining parameters for the 'fetch-with-payment' tool: url (required), method (optional), body (optional).
    inputSchema: { url: z.string().describe("The URL to fetch data from"), method: z.enum(["GET", "POST"]).optional().describe("HTTP method (default: GET)"), body: z.string().optional().describe("Request body for POST requests (JSON string)") },
  • src/index.ts:153-163 (registration)
    MCP server registration of the 'fetch-with-payment' tool, specifying name, title, description, and input schema.
    server.registerTool( "fetch-with-payment", { title: "Fetch Data", description: "Fetch data from a website or API. Automatically handles payment if required (402 status).", inputSchema: { url: z.string().describe("The URL to fetch data from"), method: z.enum(["GET", "POST"]).optional().describe("HTTP method (default: GET)"), body: z.string().optional().describe("Request body for POST requests (JSON string)") }, },
  • ServerPaymentClient class providing the core fetch functionality with X402 payment handling using wrapFetchWithPayment from x402-fetch library.
    export class ServerPaymentClient extends BasePaymentClient { private fetchWithPayment!: (input: RequestInfo, init?: RequestInit) => Promise<Response>; private initPromise: Promise<void>; constructor(config: ServerPaymentConfig) { super(); if (!config.signer) { throw new Error( 'PAYMENT_FAILED' ); } this.initPromise = this.initialize(config); } private async initialize(config: ServerPaymentConfig): Promise<void> { try { this.fetchWithPayment = wrapFetchWithPayment(fetch, config.signer); } catch (error: any) { this.handleError(error, 'Failed to initialize server payment client'); } } async fetch(url: string, options?: RequestInit): Promise<Response> { await this.initPromise; try { return await this.fetchWithPayment(url, options); } catch (error: any) { this.handleError(error, 'Server payment fetch failed'); } } }
  • extractPaymentInfo method to parse payment details from response headers, used by the handler to track payments.
    protected extractPaymentInfo(response: Response): PaymentInfo | null { const paymentHeader = response.headers.get('x-payment-response'); if (!paymentHeader) { return null; } try { const decoded = JSON.parse(atob(paymentHeader)); return { amount: decoded.amount, recipient: decoded.recipient, signature: decoded.signature, wallet: decoded.wallet, }; } catch (error: any) { throw new Error( 'PAYMENT_FAILED', error ); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Kishore-MK/ai42-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server