Skip to main content
Glama

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
NameRequiredDescriptionDefault
cidYesThe CID of the file to fetch
networkNoWhether the file is on public or private IPFSpublic

Implementation Reference

  • 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);
        }
      }
    );
  • 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) }],
    });
  • 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",
      };
    };

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/PinataCloud/pinata-mcp'

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