Skip to main content
Glama
search-drive.ts•4.22 kB
import type { OAuth2Client } from "google-auth-library"; import { google } from "googleapis"; import { z } from "zod"; export const tool = { name: "gdrive_search_drive", description: "Search for files and documents across Google Drive using text query. Returns matching files with their names, IDs, types, and links.", inputSchema: z.object({ query: z .string() .describe( "Search query text. Supports Google Drive search syntax (e.g., 'type:document', 'name:report', or simple text search)", ), max_results: z .number() .min(1) .max(100) .default(10) .describe("Maximum number of results to return (default: 10, max: 100)"), }), annotations: { readOnlyHint: true, idempotentHint: true, }, } as const; export const handler = async ( args: z.infer<typeof tool.inputSchema>, auth: OAuth2Client, ) => { const { query, max_results } = args; try { const results = await searchDrive(auth, query, max_results); return { content: [ { type: "text" as const, text: results, }, ], }; } catch (error: unknown) { if (error instanceof Error) { return { content: [ { type: "text" as const, text: `Error: ${error.message}`, }, ], isError: true, }; } throw error; } }; const searchDrive = async ( auth: OAuth2Client, query: string, maxResults: number, ): Promise<string> => { const drive = google.drive({ version: "v3", auth }); try { // Build the search query // If the query doesn't contain Drive-specific operators, search in name and fullText const searchQuery = query.includes(":") ? query : `fullText contains '${query}' or name contains '${query}'`; const response = await drive.files.list({ q: searchQuery, pageSize: maxResults, fields: "files(id, name, mimeType, webViewLink, modifiedTime, owners, size)", orderBy: "modifiedTime desc", }); const files = response.data.files; if (!files || files.length === 0) { return "No files found matching your query."; } // Format the results let output = `Found ${files.length} file(s):\n\n`; for (const file of files) { const fileType = getMimeTypeLabel(file.mimeType || "unknown"); const modifiedDate = file.modifiedTime ? new Date(file.modifiedTime).toLocaleDateString() : "Unknown"; const owner = file.owners?.[0]?.displayName || "Unknown"; const size = file.size ? formatFileSize(Number.parseInt(file.size, 10)) : "N/A"; output += `đź“„ ${file.name}\n`; output += ` Type: ${fileType}\n`; output += ` ID: ${file.id}\n`; output += ` Modified: ${modifiedDate}\n`; output += ` Owner: ${owner}\n`; output += ` Size: ${size}\n`; output += ` Link: ${file.webViewLink}\n\n`; } return output; } catch (error: unknown) { if (error instanceof Error) { throw new Error(`Failed to search Drive: ${error.message}`); } throw error; } }; const getMimeTypeLabel = (mimeType: string): string => { const mimeTypeMap: Record<string, string> = { "application/vnd.google-apps.document": "Google Doc", "application/vnd.google-apps.spreadsheet": "Google Sheet", "application/vnd.google-apps.presentation": "Google Slides", "application/vnd.google-apps.form": "Google Form", "application/vnd.google-apps.folder": "Folder", "application/pdf": "PDF", "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "Word Document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "Excel Spreadsheet", "text/plain": "Text File", "image/jpeg": "JPEG Image", "image/png": "PNG Image", }; return mimeTypeMap[mimeType] || mimeType; }; const formatFileSize = (bytes: number): string => { if (bytes === 0) return "0 Bytes"; const k = 1024; const sizes = ["Bytes", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${Math.round((bytes / k ** i) * 100) / 100} ${sizes[i]}`; };

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/benjamine/gdrive-mcp'

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