Skip to main content
Glama

createSignedUploadUrl

Generate secure URLs for client-side file uploads to Pinata IPFS while protecting API keys, with options to control expiration, file size, and allowed types.

Instructions

Create a signed URL for client-side file uploads without exposing your API key

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
expiresYesHow long the URL is valid in seconds after signing
max_file_sizeNoRestrict the max size of a file upload in bytes
allow_mime_typesNoArray of allowed MIME types (supports wildcards like 'image/*')
group_idNoID of the group that the file will be uploaded to
filenameNoName of the file that will be uploaded
keyvaluesNoMetadata key-value pairs for the file

Implementation Reference

  • Handler implementation for createSignedUploadUrl tool - makes a POST request to Pinata's upload signing endpoint to generate a time-limited signed URL for secure client-side file uploads
      async ({ expires, max_file_size, allow_mime_types, group_id, filename, keyvalues }) => {
        try {
          const url = "https://uploads.pinata.cloud/v3/files/sign";
          const date = Math.floor(Date.now() / 1000);
    
          const payload: {
            date: number;
            expires: number;
            max_file_size?: number;
            allow_mime_types?: string[];
            group_id?: string;
            filename?: string;
            keyvalues?: Record<string, string>;
          } = { date, expires };
    
          if (max_file_size) payload.max_file_size = max_file_size;
          if (allow_mime_types) payload.allow_mime_types = allow_mime_types;
          if (group_id) payload.group_id = group_id;
          if (filename) payload.filename = filename;
          if (keyvalues) payload.keyvalues = keyvalues;
    
          const response = await fetch(url, {
            method: "POST",
            headers: getHeaders(),
            body: JSON.stringify(payload),
          });
    
          if (!response.ok) {
            const errorText = await response.text();
            throw new Error(
              `Failed to create signed upload URL: ${response.status} ${response.statusText}\n${errorText}`
            );
          }
    
          const data = await response.json();
          return {
            content: [
              {
                type: "text",
                text: `✅ Signed upload URL created!\n\nURL: ${data.data}\n\nExpires in ${expires} seconds`,
              },
            ],
          };
        } catch (error) {
          return errorResponse(error);
        }
      }
    );
  • Zod schema defining input parameters for createSignedUploadUrl tool - validates expires (required), and optional max_file_size, allow_mime_types, group_id, filename, and keyvalues parameters
    {
      expires: z
        .number()
        .describe("How long the URL is valid in seconds after signing"),
      max_file_size: z
        .number()
        .optional()
        .describe("Restrict the max size of a file upload in bytes"),
      allow_mime_types: z
        .array(z.string())
        .optional()
        .describe("Array of allowed MIME types (supports wildcards like 'image/*')"),
      group_id: z
        .string()
        .optional()
        .describe("ID of the group that the file will be uploaded to"),
      filename: z
        .string()
        .optional()
        .describe("Name of the file that will be uploaded"),
      keyvalues: z
        .record(z.string())
        .optional()
        .describe("Metadata key-value pairs for the file"),
    },
  • src/index.ts:1474-1549 (registration)
    Tool registration for createSignedUploadUrl - registers the MCP tool with its name, description, input schema, and handler function
    server.tool(
      "createSignedUploadUrl",
      "Create a signed URL for client-side file uploads without exposing your API key",
      {
        expires: z
          .number()
          .describe("How long the URL is valid in seconds after signing"),
        max_file_size: z
          .number()
          .optional()
          .describe("Restrict the max size of a file upload in bytes"),
        allow_mime_types: z
          .array(z.string())
          .optional()
          .describe("Array of allowed MIME types (supports wildcards like 'image/*')"),
        group_id: z
          .string()
          .optional()
          .describe("ID of the group that the file will be uploaded to"),
        filename: z
          .string()
          .optional()
          .describe("Name of the file that will be uploaded"),
        keyvalues: z
          .record(z.string())
          .optional()
          .describe("Metadata key-value pairs for the file"),
      },
      async ({ expires, max_file_size, allow_mime_types, group_id, filename, keyvalues }) => {
        try {
          const url = "https://uploads.pinata.cloud/v3/files/sign";
          const date = Math.floor(Date.now() / 1000);
    
          const payload: {
            date: number;
            expires: number;
            max_file_size?: number;
            allow_mime_types?: string[];
            group_id?: string;
            filename?: string;
            keyvalues?: Record<string, string>;
          } = { date, expires };
    
          if (max_file_size) payload.max_file_size = max_file_size;
          if (allow_mime_types) payload.allow_mime_types = allow_mime_types;
          if (group_id) payload.group_id = group_id;
          if (filename) payload.filename = filename;
          if (keyvalues) payload.keyvalues = keyvalues;
    
          const response = await fetch(url, {
            method: "POST",
            headers: getHeaders(),
            body: JSON.stringify(payload),
          });
    
          if (!response.ok) {
            const errorText = await response.text();
            throw new Error(
              `Failed to create signed upload URL: ${response.status} ${response.statusText}\n${errorText}`
            );
          }
    
          const data = await response.json();
          return {
            content: [
              {
                type: "text",
                text: `✅ Signed upload URL created!\n\nURL: ${data.data}\n\nExpires in ${expires} seconds`,
              },
            ],
          };
        } catch (error) {
          return errorResponse(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/PinataCloud/pinata-mcp'

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