UNPKG

mcp-gdrive-enhanced-markov

Version:

MCP server for Google Drive and Sheets with write capabilities, AI-powered PDF analysis, SQLite document indexing, and advanced directory exploration tools

162 lines (161 loc) 6.4 kB
import { google } from "googleapis"; export const schema = { name: "gdrive_search", description: "Search for files in Google Drive with advanced filtering options", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query - can be file name or content search", }, pageToken: { type: "string", description: "Token for the next page of results", optional: true, }, pageSize: { type: "number", description: "Number of results per page (max 100)", optional: true, }, fileType: { type: "string", description: "Filter by file type: 'spreadsheet', 'document', 'presentation', 'pdf', 'image', 'video', 'audio', 'folder'", optional: true, }, modifiedAfter: { type: "string", description: "Only return files modified after this date (ISO format: YYYY-MM-DD)", optional: true, }, modifiedBefore: { type: "string", description: "Only return files modified before this date (ISO format: YYYY-MM-DD)", optional: true, }, }, required: ["query"], }, }; export async function search(args) { const drive = google.drive("v3"); const userQuery = args.query.trim(); let searchQuery = "trashed = false"; // Helper function to map file types to mime types const getFileTypeMimeTypes = (fileType) => { switch (fileType.toLowerCase()) { case 'spreadsheet': return [ 'application/vnd.google-apps.spreadsheet', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel' ]; case 'document': return [ 'application/vnd.google-apps.document', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/msword' ]; case 'presentation': return [ 'application/vnd.google-apps.presentation', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.ms-powerpoint' ]; case 'pdf': return ['application/pdf']; case 'image': return ['image/']; case 'video': return ['video/']; case 'audio': return ['audio/']; case 'folder': return ['application/vnd.google-apps.folder']; default: return []; } }; // Build search query components const queryParts = []; // Add name/content search if provided if (userQuery) { if (userQuery.includes("=") || userQuery.includes(":") || userQuery.startsWith("mimeType") || userQuery.startsWith("trashed")) { // If the query looks like a Drive API query, use it directly (but still apply other filters) searchQuery = userQuery; } else { // Search by name and full text const escapedQuery = userQuery.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); queryParts.push(`(name contains '${escapedQuery}' or fullText contains '${escapedQuery}')`); } } // Add file type filter if (args.fileType) { const mimeTypes = getFileTypeMimeTypes(args.fileType); if (mimeTypes.length > 0) { if (args.fileType.toLowerCase() === 'image' || args.fileType.toLowerCase() === 'video' || args.fileType.toLowerCase() === 'audio') { // For media types, use startsWith const mimeTypeQueries = mimeTypes.map(mime => `mimeType contains '${mime}'`); queryParts.push(`(${mimeTypeQueries.join(' or ')})`); } else { // For specific types, use exact match const mimeTypeQueries = mimeTypes.map(mime => `mimeType = '${mime}'`); queryParts.push(`(${mimeTypeQueries.join(' or ')})`); } } } // Add date filters if (args.modifiedAfter) { queryParts.push(`modifiedTime > '${args.modifiedAfter}'`); } if (args.modifiedBefore) { queryParts.push(`modifiedTime < '${args.modifiedBefore}'`); } // Combine all query parts if (queryParts.length > 0) { if (searchQuery === "trashed = false") { searchQuery = `${queryParts.join(' and ')} and trashed = false`; } else { // If we already have a complex query, combine it carefully searchQuery = `(${searchQuery}) and ${queryParts.join(' and ')}`; } } const res = await drive.files.list({ q: searchQuery, pageSize: args.pageSize || 10, pageToken: args.pageToken, orderBy: "modifiedTime desc", fields: "nextPageToken, files(id, name, mimeType, modifiedTime, size, parents)", }); const files = res.data.files || []; // Format the file list with more detailed information const fileList = files .map((file) => { const modifiedTime = file.modifiedTime ? new Date(file.modifiedTime).toLocaleDateString() : 'Unknown'; const size = file.size ? `${Math.round(parseInt(file.size) / 1024)} KB` : ''; return `${file.id} ${file.name} - ${modifiedTime} ${size} (${file.mimeType})`; }) .join("\n"); let response = `Found ${files.length} files:\n${fileList}`; // Add search query info for debugging if (args.fileType || args.modifiedAfter || args.modifiedBefore) { response += `\n\n**Search Query:** ${searchQuery}`; } // Add pagination info if there are more results if (res.data.nextPageToken) { response += `\n\nMore results available. Use pageToken: ${res.data.nextPageToken}`; } return { content: [ { type: "text", text: response, }, ], isError: false, }; }