Skip to main content
Glama
upload-file-tool.ts3.74 kB
/** * Tool to upload a file to FileSearchStore */ import { z } from "zod"; import { basename } from "node:path"; import { BaseTool } from "../base/base-tool.js"; import type { MCPToolResponse, CustomMetadata, MetadataInput, } from "../../types/index.js"; import { convertMetadataInput } from "../../utils/metadata.js"; type UploadFileArgs = { filePath: string; mimeType?: string; displayName?: string; metadata?: MetadataInput; }; type UploadFileResult = { documentName: string; filePath: string; displayName: string; storeName: string; }; export class UploadFileTool extends BaseTool<UploadFileArgs> { readonly name = "upload_file"; readonly description = "Upload a file to the FileSearchStore for RAG indexing. The file will be processed and made searchable."; getInputSchema() { return z.object({ filePath: z .string() .describe( "Absolute path to the file to upload (e.g., /path/to/document.pdf)", ), mimeType: z .string() .optional() .describe( "MIME type of the file (e.g., application/pdf, text/markdown). Auto-detected if not provided.", ), displayName: z .string() .optional() .describe( "Display name for the file in the store. Uses filename if not provided.", ), metadata: z .record(z.union([z.string(), z.number()])) .optional() .describe( "Custom metadata as key-value pairs. Values can be strings or numbers. Maximum 20 entries per document. Example: {\"category\": \"guide\", \"year\": 2025}", ), }); } async execute(args: UploadFileArgs): Promise<MCPToolResponse<UploadFileResult>> { const { geminiClient, storeDisplayName } = this.context; // Ensure store exists const store = await geminiClient.ensureStore(storeDisplayName); // Determine display name const displayName = args.displayName ?? basename(args.filePath); // Auto-detect MIME type if not provided let mimeType = args.mimeType; if (!mimeType) { const ext = args.filePath.split(".").pop()?.toLowerCase(); mimeType = this.getMimeTypeFromExtension(ext ?? ""); } // Upload file const uploadArgs: { storeName: string; filePath: string; mimeType: string; displayName: string; metadata?: CustomMetadata[]; } = { storeName: store.name, filePath: args.filePath, mimeType, displayName, }; if (args.metadata) { uploadArgs.metadata = convertMetadataInput(args.metadata); } const result = await geminiClient.uploadFile(uploadArgs); return { success: true, message: `File uploaded successfully: ${displayName}`, data: { documentName: result.documentName, filePath: args.filePath, displayName, storeName: store.name, }, }; } /** * Simple MIME type mapping for common file types */ private getMimeTypeFromExtension(ext: string): string { const mimeTypes: Record<string, string> = { pdf: "application/pdf", txt: "text/plain", md: "text/markdown", html: "text/html", json: "application/json", xml: "application/xml", csv: "text/csv", doc: "application/msword", docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", xls: "application/vnd.ms-excel", xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ppt: "application/vnd.ms-powerpoint", pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation", }; return mimeTypes[ext] ?? "application/octet-stream"; } }

Implementation Reference

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/masseater/gemini-rag-mcp'

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