Skip to main content
Glama

upload_file

Attach files to MantisBT issues by uploading local files or providing Base64-encoded content with optional MIME type specification.

Instructions

Upload a file as an attachment to a MantisBT issue via multipart/form-data.

Two input modes (exactly one must be provided):

  • file_path: absolute path to a local file — filename is derived from the path automatically

  • content: Base64-encoded file content — filename must be supplied explicitly via the filename parameter

The optional content_type parameter sets the MIME type (e.g. "image/png"). If omitted, "application/octet-stream" is used.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The handler implementation for the 'upload_file' tool, which processes either a file path or base64 content and uploads it to a MantisBT issue via multipart/form-data.
      async ({ issue_id, file_path, content, filename, content_type, description }) => {
        try {
          if (!file_path && !content) {
            return { content: [{ type: 'text', text: 'Error: Either file_path or content must be provided' }], isError: true };
          }
          if (file_path && content) {
            return { content: [{ type: 'text', text: 'Error: Only one of file_path or content may be provided' }], isError: true };
          }
    
          let fileBuffer: Buffer;
          let fileName: string;
    
          if (file_path) {
            if (normalizedUploadDir) {
              const normalizedPath = resolve(file_path);
              if (!normalizedPath.startsWith(normalizedUploadDir)) {
                return { content: [{ type: 'text', text: errorText('file_path is not allowed — access restricted to the designated upload directory') }], isError: true };
              }
            }
            fileBuffer = await readFile(file_path);
            fileName = filename ?? basename(file_path);
          } else {
            if (!filename) {
              return { content: [{ type: 'text', text: 'Error: filename is required when using content' }], isError: true };
            }
            fileBuffer = Buffer.from(content!, 'base64');
            fileName = filename;
          }
    
          const blob = new Blob([new Uint8Array(fileBuffer)], { type: content_type ?? 'application/octet-stream' });
          const formData = new FormData();
          formData.append('file', blob, fileName);
          if (description) {
            formData.append('description', description);
          }
          const result = await client.postFormData<unknown>(`issues/${issue_id}/files`, formData);
          return {
            content: [{ type: 'text', text: JSON.stringify(result ?? { success: true }, null, 2) }],
          };
        } catch (error) {
          const msg = error instanceof Error ? error.message : String(error);
          return { content: [{ type: 'text', text: errorText(msg) }], isError: true };
        }
      }
    );
  • Input schema definition for 'upload_file' using Zod, including validation for file_path vs content exclusivity.
    inputSchema: z.object({
      issue_id: z.coerce.number().int().positive().describe('Numeric issue ID'),
      file_path: z.string().min(1).optional().describe('Absolute path to the local file to upload (mutually exclusive with content)'),
      content: z.string().min(1).optional().describe('Base64-encoded file content (mutually exclusive with file_path)'),
      filename: z.string().min(1).optional().describe('File name for the attachment (required when using content; overrides the derived name when using file_path)'),
      content_type: z.string().optional().describe('MIME type of the file, e.g. "image/png" (default: "application/octet-stream")'),
      description: z.string().optional().describe('Optional description for the attachment'),
    }).refine(d => !!(d.file_path ?? d.content), {
      message: 'Either file_path or content must be provided',
    }).refine(d => !(d.file_path && d.content), {
      message: 'Only one of file_path or content may be provided',
    }).refine(d => !d.content || !!d.filename, {
      message: 'filename is required when using content',
    }),
  • Registration of the 'upload_file' tool within the McpServer.
      server.registerTool(
        'upload_file',
        {
          title: 'Upload File Attachment',
          description: `Upload a file as an attachment to a MantisBT issue via multipart/form-data.
    
    Two input modes (exactly one must be provided):
    - file_path: absolute path to a local file — filename is derived from the path automatically
    - content: Base64-encoded file content — filename must be supplied explicitly via the filename parameter
    
    The optional content_type parameter sets the MIME type (e.g. "image/png"). If omitted, "application/octet-stream" is used.`,
          inputSchema: z.object({
            issue_id: z.coerce.number().int().positive().describe('Numeric issue ID'),
            file_path: z.string().min(1).optional().describe('Absolute path to the local file to upload (mutually exclusive with content)'),
            content: z.string().min(1).optional().describe('Base64-encoded file content (mutually exclusive with file_path)'),
            filename: z.string().min(1).optional().describe('File name for the attachment (required when using content; overrides the derived name when using file_path)'),
            content_type: z.string().optional().describe('MIME type of the file, e.g. "image/png" (default: "application/octet-stream")'),
            description: z.string().optional().describe('Optional description for the attachment'),
          }).refine(d => !!(d.file_path ?? d.content), {
            message: 'Either file_path or content must be provided',
          }).refine(d => !(d.file_path && d.content), {
            message: 'Only one of file_path or content may be provided',
          }).refine(d => !d.content || !!d.filename, {
            message: 'filename is required when using content',
          }),
          annotations: {
            readOnlyHint: false,
            destructiveHint: false,
            idempotentHint: false,
          },
        },

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/dpesch/mantisbt-mcp-server'

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