fetchFromGateway
Retrieve content from IPFS networks using Pinata's gateway by providing a CID, supporting both public and private file access.
Instructions
Fetch content from Public or Private IPFS via Pinata gateway and return it
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cid | Yes | The CID of the file to fetch | |
| network | No | Whether the file is on public or private IPFS | public |
Implementation Reference
- src/index.ts:583-673 (handler)Complete implementation of the fetchFromGateway tool that fetches content from Public or Private IPFS via Pinata gateway. The handler constructs the appropriate URL based on network type (public uses /ipfs/ endpoint, private creates a temporary download link first), fetches the content, and returns it as text or base64 depending on the content type and size.
server.tool( "fetchFromGateway", "Fetch content from Public or Private IPFS via Pinata gateway and return it", { cid: z.string().describe("The CID of the file to fetch"), network: z .enum(["public", "private"]) .default("public") .describe("Whether the file is on public or private IPFS"), }, async ({ cid, network }) => { try { if (!GATEWAY_URL) { throw new Error("GATEWAY_URL environment variable is not set"); } let fileUrl: string; if (network === "public") { fileUrl = `https://${GATEWAY_URL}/ipfs/${cid}`; } else { const filePath = `https://${GATEWAY_URL}/files/${cid}`; const apiUrl = `https://api.pinata.cloud/v3/files/private/download_link`; const date = Math.floor(new Date().getTime() / 1000); const expires = 600; const payload = { url: filePath, expires, date, method: "GET", }; const linkResponse = await fetch(apiUrl, { method: "POST", headers: getHeaders(), body: JSON.stringify(payload), }); if (!linkResponse.ok) { const errorText = await linkResponse.text(); throw new Error( `Failed to create download link: ${linkResponse.status} ${linkResponse.statusText}. Response: ${errorText}` ); } const linkData = await linkResponse.json(); fileUrl = linkData.data; } const response = await fetch(fileUrl); if (!response.ok) { throw new Error( `Failed to fetch file: ${response.status} ${response.statusText}` ); } const contentType = response.headers.get("content-type") || "application/octet-stream"; const arrayBuffer = await response.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); let resultText = `✅ Fetched ${buffer.length} bytes from ${network} IPFS (CID: ${cid})\nContent-Type: ${contentType}\n\n`; // Return text content directly, binary as base64 if ( contentType.startsWith("text/") || contentType.includes("json") || contentType.includes("javascript") || contentType.includes("xml") ) { if (buffer.length < 100000) { resultText += `Content:\n${buffer.toString("utf-8")}`; } else { resultText += `Content too large to display (${buffer.length} bytes). Use a smaller file or save to disk.`; } } else if (buffer.length < 50000) { resultText += `Base64 Content:\n${buffer.toString("base64")}`; } else { resultText += `Binary content too large to display (${buffer.length} bytes).`; } return { content: [{ type: "text", text: resultText }], }; } catch (error) { return errorResponse(error); } } ); - src/index.ts:111-124 (helper)Helper functions for consistent API responses. errorResponse creates a standardized error response with the error message, while successResponse formats successful JSON data responses.
const errorResponse = (error: unknown) => ({ content: [ { type: "text" as const, text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }); // Helper for consistent success responses const successResponse = (data: unknown) => ({ content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }); - src/index.ts:100-108 (helper)Helper function that generates authorization headers for API requests using the PINATA_JWT environment variable.
const getHeaders = () => { if (!PINATA_JWT) { throw new Error("PINATA_JWT environment variable is not set"); } return { Authorization: `Bearer ${PINATA_JWT}`, "Content-Type": "application/json", }; };