@alanse/mcp-server-google-workspace 0.2.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +250 -17
  2. package/dist/auth.js +6 -0
  3. package/dist/index.js +1 -1
  4. package/dist/lib/calendar-helpers.js +197 -0
  5. package/dist/lib/document-id-resolver.js +76 -0
  6. package/dist/lib/drive-helpers.js +263 -0
  7. package/dist/lib/gmail-helpers.js +204 -0
  8. package/dist/lib/response-formatter.js +82 -0
  9. package/dist/lib/validation.js +112 -0
  10. package/dist/tools/calendar/acl/calendar_acl_insert.js +80 -0
  11. package/dist/tools/calendar/acl/calendar_acl_list.js +82 -0
  12. package/dist/tools/calendar/basic/calendar_create_event.js +113 -0
  13. package/dist/tools/calendar/basic/calendar_delete_event.js +52 -0
  14. package/dist/tools/calendar/basic/calendar_get_event.js +52 -0
  15. package/dist/tools/calendar/basic/calendar_list_events.js +86 -0
  16. package/dist/tools/calendar/basic/calendar_update_event.js +116 -0
  17. package/dist/tools/calendar/calendarlist/calendar_calendarlist_get.js +73 -0
  18. package/dist/tools/calendar/calendarlist/calendar_calendarlist_list.js +87 -0
  19. package/dist/tools/calendar/calendars/calendar_calendars_get.js +52 -0
  20. package/dist/tools/calendar/calendars/calendar_calendars_insert.js +66 -0
  21. package/dist/tools/calendar/calendars/calendar_calendars_update.js +85 -0
  22. package/dist/tools/calendar/colors/calendar_colors_get.js +46 -0
  23. package/dist/tools/calendar/events_advanced/calendar_events_instances.js +81 -0
  24. package/dist/tools/calendar/events_advanced/calendar_events_move.js +63 -0
  25. package/dist/tools/calendar/events_advanced/calendar_events_quickadd.js +52 -0
  26. package/dist/tools/calendar/freebusy/calendar_freebusy_query.js +69 -0
  27. package/dist/tools/calendar/settings/calendar_settings_list.js +81 -0
  28. package/dist/tools/docs/basic/gdocs_create.js +37 -0
  29. package/dist/tools/docs/basic/gdocs_get_metadata.js +45 -0
  30. package/dist/tools/docs/basic/gdocs_list_documents.js +59 -0
  31. package/dist/tools/docs/basic/gdocs_read.js +62 -0
  32. package/dist/tools/docs/content/gdocs_append_text.js +57 -0
  33. package/dist/tools/docs/content/gdocs_apply_style.js +86 -0
  34. package/dist/tools/docs/content/gdocs_create_heading.js +89 -0
  35. package/dist/tools/docs/content/gdocs_create_list.js +86 -0
  36. package/dist/tools/docs/content/gdocs_delete_text.js +64 -0
  37. package/dist/tools/docs/content/gdocs_format_text.js +137 -0
  38. package/dist/tools/docs/content/gdocs_insert_text.js +62 -0
  39. package/dist/tools/docs/content/gdocs_replace_text.js +64 -0
  40. package/dist/tools/docs/content/gdocs_set_alignment.js +76 -0
  41. package/dist/tools/docs/content/gdocs_update_text.js +78 -0
  42. package/dist/tools/docs/elements/gdocs_batch_update.js +108 -0
  43. package/dist/tools/docs/elements/gdocs_create_table.js +73 -0
  44. package/dist/tools/docs/elements/gdocs_export.js +62 -0
  45. package/dist/tools/docs/elements/gdocs_insert_image.js +96 -0
  46. package/dist/tools/docs/elements/gdocs_insert_link.js +77 -0
  47. package/dist/tools/docs/elements/gdocs_insert_page_break.js +55 -0
  48. package/dist/tools/docs/elements/gdocs_insert_toc.js +71 -0
  49. package/dist/tools/docs/elements/gdocs_merge_documents.js +104 -0
  50. package/dist/tools/docs/elements/gdocs_suggest_mode.js +41 -0
  51. package/dist/tools/drive/advanced/drive_empty_trash.js +56 -0
  52. package/dist/tools/drive/advanced/drive_export_file.js +158 -0
  53. package/dist/tools/drive/advanced/drive_list_revisions.js +80 -0
  54. package/dist/tools/drive/basic/drive_get_metadata.js +49 -0
  55. package/dist/tools/drive/basic/drive_list_files.js +76 -0
  56. package/dist/tools/drive/file/drive_copy_file.js +79 -0
  57. package/dist/tools/drive/file/drive_create_file.js +72 -0
  58. package/dist/tools/drive/file/drive_delete_file.js +48 -0
  59. package/dist/tools/drive/file/drive_move_file.js +79 -0
  60. package/dist/tools/drive/file/drive_rename_file.js +58 -0
  61. package/dist/tools/drive/file/drive_update_file.js +106 -0
  62. package/dist/tools/drive/file/drive_upload_file.js +80 -0
  63. package/dist/tools/drive/folder/drive_create_folder.js +67 -0
  64. package/dist/tools/drive/folder/drive_list_folder_contents.js +68 -0
  65. package/dist/tools/drive/folder/drive_move_to_folder.js +59 -0
  66. package/dist/tools/drive/permissions/drive_list_permissions.js +115 -0
  67. package/dist/tools/drive/permissions/drive_remove_permission.js +71 -0
  68. package/dist/tools/drive/permissions/drive_share_file.js +116 -0
  69. package/dist/tools/drive/permissions/drive_update_permission.js +79 -0
  70. package/dist/tools/gmail/basic/gmail_get_message.js +95 -0
  71. package/dist/tools/gmail/basic/gmail_get_thread.js +46 -0
  72. package/dist/tools/gmail/basic/gmail_list_labels.js +54 -0
  73. package/dist/tools/gmail/basic/gmail_search_messages.js +59 -0
  74. package/dist/tools/gmail/batch/gmail_batch_modify_labels.js +74 -0
  75. package/dist/tools/gmail/batch/gmail_get_messages_batch.js +120 -0
  76. package/dist/tools/gmail/batch/gmail_get_threads_batch.js +102 -0
  77. package/dist/tools/gmail/labels/gmail_manage_label.js +131 -0
  78. package/dist/tools/gmail/labels/gmail_modify_labels.js +65 -0
  79. package/dist/tools/gmail/send/gmail_draft_message.js +117 -0
  80. package/dist/tools/gmail/send/gmail_send_message.js +109 -0
  81. package/dist/tools/index.js +386 -3
  82. package/package.json +8 -3
  83. package/dist/tools/basic/gsheets_add_sheet.js +0 -65
  84. package/dist/tools/basic/gsheets_copy_sheet.js +0 -56
  85. package/dist/tools/basic/gsheets_copy_to.js +0 -113
  86. package/dist/tools/basic/gsheets_create_spreadsheet.js +0 -88
  87. package/dist/tools/basic/gsheets_delete_columns.js +0 -69
  88. package/dist/tools/basic/gsheets_delete_rows.js +0 -69
  89. package/dist/tools/basic/gsheets_delete_sheet.js +0 -56
  90. package/dist/tools/basic/gsheets_duplicate_sheet.js +0 -72
  91. package/dist/tools/basic/gsheets_insert_columns.js +0 -69
  92. package/dist/tools/basic/gsheets_insert_rows.js +0 -69
  93. package/dist/tools/basic/gsheets_list_sheets.js +0 -53
  94. package/dist/tools/basic/gsheets_read.js +0 -120
  95. package/dist/tools/basic/gsheets_rename_sheet.js +0 -64
  96. package/dist/tools/charts/gsheets_add_bubble.js +0 -176
  97. package/dist/tools/charts/gsheets_add_candlestick.js +0 -192
  98. package/dist/tools/charts/gsheets_add_chart.js +0 -162
  99. package/dist/tools/charts/gsheets_add_combo.js +0 -169
  100. package/dist/tools/charts/gsheets_add_histogram.js +0 -143
  101. package/dist/tools/charts/gsheets_add_org_chart.js +0 -160
  102. package/dist/tools/charts/gsheets_add_treemap.js +0 -177
  103. package/dist/tools/charts/gsheets_add_waterfall.js +0 -155
  104. package/dist/tools/charts/gsheets_delete_chart.js +0 -56
  105. package/dist/tools/charts/gsheets_update_chart.js +0 -118
  106. package/dist/tools/data/gsheets_append_data.js +0 -68
  107. package/dist/tools/data/gsheets_batch_clear.js +0 -53
  108. package/dist/tools/data/gsheets_batch_update.js +0 -81
  109. package/dist/tools/data/gsheets_clear_data.js +0 -53
  110. package/dist/tools/data/gsheets_create_filter.js +0 -81
  111. package/dist/tools/data/gsheets_find_replace.js +0 -124
  112. package/dist/tools/data/gsheets_set_data_validation.js +0 -153
  113. package/dist/tools/data/gsheets_sort_range.js +0 -102
  114. package/dist/tools/data/gsheets_update_cell.js +0 -44
  115. package/dist/tools/formatting/gsheets_auto_resize.js +0 -75
  116. package/dist/tools/formatting/gsheets_format_cells.js +0 -161
  117. package/dist/tools/formatting/gsheets_freeze_columns.js +0 -67
  118. package/dist/tools/formatting/gsheets_freeze_rows.js +0 -67
  119. package/dist/tools/formatting/gsheets_merge_cells.js +0 -85
  120. package/dist/tools/formatting/gsheets_set_number_format.js +0 -116
  121. package/dist/tools/formatting/gsheets_unmerge_cells.js +0 -79
  122. package/dist/tools/formatting/gsheets_update_borders.js +0 -212
  123. package/dist/tools/gdrive/gdrive_read_file.js +0 -77
  124. package/dist/tools/gdrive/gdrive_search.js +0 -71
  125. package/dist/tools/gdrive_read_file.js +0 -77
  126. package/dist/tools/gdrive_search.js +0 -71
  127. package/dist/tools/gsheets_add_bubble.js +0 -176
  128. package/dist/tools/gsheets_add_candlestick.js +0 -192
  129. package/dist/tools/gsheets_add_chart.js +0 -162
  130. package/dist/tools/gsheets_add_combo.js +0 -169
  131. package/dist/tools/gsheets_add_conditional_format.js +0 -175
  132. package/dist/tools/gsheets_add_histogram.js +0 -143
  133. package/dist/tools/gsheets_add_named_range.js +0 -87
  134. package/dist/tools/gsheets_add_org_chart.js +0 -160
  135. package/dist/tools/gsheets_add_protected_range.js +0 -127
  136. package/dist/tools/gsheets_add_sheet.js +0 -65
  137. package/dist/tools/gsheets_add_treemap.js +0 -177
  138. package/dist/tools/gsheets_add_waterfall.js +0 -155
  139. package/dist/tools/gsheets_append_data.js +0 -68
  140. package/dist/tools/gsheets_auto_resize.js +0 -75
  141. package/dist/tools/gsheets_batch_clear.js +0 -53
  142. package/dist/tools/gsheets_batch_update.js +0 -81
  143. package/dist/tools/gsheets_clear_data.js +0 -53
  144. package/dist/tools/gsheets_copy_sheet.js +0 -56
  145. package/dist/tools/gsheets_copy_to.js +0 -113
  146. package/dist/tools/gsheets_create_filter.js +0 -81
  147. package/dist/tools/gsheets_create_spreadsheet.js +0 -88
  148. package/dist/tools/gsheets_delete_chart.js +0 -56
  149. package/dist/tools/gsheets_delete_columns.js +0 -69
  150. package/dist/tools/gsheets_delete_named_range.js +0 -56
  151. package/dist/tools/gsheets_delete_protected_range.js +0 -56
  152. package/dist/tools/gsheets_delete_rows.js +0 -69
  153. package/dist/tools/gsheets_delete_sheet.js +0 -56
  154. package/dist/tools/gsheets_duplicate_sheet.js +0 -72
  155. package/dist/tools/gsheets_find_replace.js +0 -124
  156. package/dist/tools/gsheets_format_cells.js +0 -161
  157. package/dist/tools/gsheets_freeze_columns.js +0 -67
  158. package/dist/tools/gsheets_freeze_rows.js +0 -67
  159. package/dist/tools/gsheets_insert_columns.js +0 -69
  160. package/dist/tools/gsheets_insert_rows.js +0 -69
  161. package/dist/tools/gsheets_list_sheets.js +0 -53
  162. package/dist/tools/gsheets_merge_cells.js +0 -85
  163. package/dist/tools/gsheets_read.js +0 -120
  164. package/dist/tools/gsheets_rename_sheet.js +0 -64
  165. package/dist/tools/gsheets_set_data_validation.js +0 -153
  166. package/dist/tools/gsheets_set_number_format.js +0 -116
  167. package/dist/tools/gsheets_sort_range.js +0 -102
  168. package/dist/tools/gsheets_unmerge_cells.js +0 -79
  169. package/dist/tools/gsheets_update_borders.js +0 -212
  170. package/dist/tools/gsheets_update_cell.js +0 -44
  171. package/dist/tools/gsheets_update_chart.js +0 -118
  172. package/dist/tools/gsheets_update_named_range.js +0 -112
  173. package/dist/tools/gsheets_update_protected_range.js +0 -110
  174. package/dist/tools/protection/gsheets_add_conditional_format.js +0 -175
  175. package/dist/tools/protection/gsheets_add_named_range.js +0 -87
  176. package/dist/tools/protection/gsheets_add_protected_range.js +0 -127
  177. package/dist/tools/protection/gsheets_delete_named_range.js +0 -56
  178. package/dist/tools/protection/gsheets_delete_protected_range.js +0 -56
  179. package/dist/tools/protection/gsheets_update_named_range.js +0 -112
  180. package/dist/tools/protection/gsheets_update_protected_range.js +0 -110
  181. /package/dist/tools/drive/{drive_read_file.js → basic/drive_read_file.js} +0 -0
  182. /package/dist/tools/drive/{drive_search.js → basic/drive_search.js} +0 -0
@@ -0,0 +1,80 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatRevisionList, } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_list_revisions",
6
+ description: "List all revisions of a file in Google Drive. Shows revision history with timestamps and modification details. Supports pagination.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ fileId: {
11
+ type: "string",
12
+ description: "ID of the file to list revisions for",
13
+ },
14
+ pageSize: {
15
+ type: "number",
16
+ description: "Maximum number of revisions to return per page (default: 10, max: 1000)",
17
+ optional: true,
18
+ },
19
+ pageToken: {
20
+ type: "string",
21
+ description: "Token for pagination to get the next page of results",
22
+ optional: true,
23
+ },
24
+ },
25
+ required: ["fileId"],
26
+ },
27
+ };
28
+ export async function listRevisions(args) {
29
+ try {
30
+ const drive = google.drive("v3");
31
+ const { fileId, pageSize = 10, pageToken } = args;
32
+ // Get file metadata
33
+ const fileResponse = await drive.files.get({
34
+ fileId,
35
+ fields: "id, name, mimeType, size, modifiedTime, createdTime",
36
+ });
37
+ const file = fileResponse.data;
38
+ // List revisions
39
+ const revisionsResponse = await drive.revisions.list({
40
+ fileId,
41
+ pageSize: Math.min(pageSize, 1000), // Cap at 1000
42
+ pageToken: pageToken || undefined,
43
+ fields: "revisions(id, modifiedTime, lastModifyingUser, size, keepForever, originalFilename, mimeType), nextPageToken",
44
+ });
45
+ const revisions = revisionsResponse.data.revisions || [];
46
+ const nextPageToken = revisionsResponse.data.nextPageToken;
47
+ // Format output
48
+ let output = `šŸ“„ Revision History for "${file.name}"\n`;
49
+ output += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
50
+ output += `Total Revisions: ${revisions.length}\n`;
51
+ if (nextPageToken) {
52
+ output += `(More revisions available - use nextPageToken for pagination)\n`;
53
+ }
54
+ output += `\n${formatRevisionList(revisions)}\n`;
55
+ // Format detailed output for each revision
56
+ let detailedRevisions = revisions.map((revision, index) => ({
57
+ index: index + 1,
58
+ revisionId: revision.id || "",
59
+ modifiedTime: revision.modifiedTime || "Unknown",
60
+ modifiedBy: revision.lastModifyingUser?.displayName || "Unknown",
61
+ modifiedByEmail: revision.lastModifyingUser?.emailAddress || "Unknown",
62
+ size: revision.size ? parseInt(revision.size) : 0,
63
+ mimeType: revision.mimeType || "Unknown",
64
+ keepForever: revision.keepForever || false,
65
+ originalFilename: revision.originalFilename || file.name,
66
+ }));
67
+ return ResponseFormatter.success({
68
+ fileId,
69
+ fileName: file.name,
70
+ totalRevisions: revisions.length,
71
+ revisions: detailedRevisions,
72
+ nextPageToken: nextPageToken || null,
73
+ hasMoreResults: !!nextPageToken,
74
+ pageSize,
75
+ }, output);
76
+ }
77
+ catch (error) {
78
+ return ResponseFormatter.error(error);
79
+ }
80
+ }
@@ -0,0 +1,49 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileMetadata } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_get_metadata",
6
+ description: "Get detailed metadata for a specific file in Google Drive. Returns file ID, name, MIME type, size, created/modified times, sharing settings, and more.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ fileId: {
11
+ type: "string",
12
+ description: "ID of the file to get metadata for",
13
+ },
14
+ fields: {
15
+ type: "string",
16
+ description: "Comma-separated list of fields to include (default: all common fields)",
17
+ optional: true,
18
+ },
19
+ },
20
+ required: ["fileId"],
21
+ },
22
+ };
23
+ export async function getMetadata(args) {
24
+ try {
25
+ const drive = google.drive("v3");
26
+ const { fileId, fields } = args;
27
+ const defaultFields = "id, name, mimeType, size, createdTime, modifiedTime, modifiedByMe, owners, lastModifyingUser, shared, sharingUser, permissions, parents, webViewLink, webContentLink, iconLink, thumbnailLink, description, starred, trashed, explicitlyTrashed, properties, appProperties, spaces, version, teamDriveId, driveId, hasAugmentedPermissions, hasVersions, headRevisionId, copyRequiresWriterPermission, writersCanShare, folderColorRgb, originalFilename, fullFileExtension, fileExtension, md5Checksum, sha1Checksum, sha256Checksum";
28
+ const response = await drive.files.get({
29
+ fileId,
30
+ fields: fields || defaultFields,
31
+ supportsAllDrives: true,
32
+ });
33
+ const file = response.data;
34
+ const output = formatFileMetadata(file, true);
35
+ return ResponseFormatter.success({
36
+ fileId: file.id,
37
+ name: file.name,
38
+ mimeType: file.mimeType,
39
+ size: file.size,
40
+ createdTime: file.createdTime,
41
+ modifiedTime: file.modifiedTime,
42
+ webViewLink: file.webViewLink,
43
+ metadata: file,
44
+ }, output);
45
+ }
46
+ catch (error) {
47
+ return ResponseFormatter.error(error);
48
+ }
49
+ }
@@ -0,0 +1,76 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileList } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_list_files",
6
+ description: "List files in Google Drive. Supports filtering by query, folder, pagination, and sorting. Returns file IDs, names, types, and sizes.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ query: {
11
+ type: "string",
12
+ description: "Search query using Google Drive query syntax (e.g., \"name contains 'report'\")",
13
+ optional: true,
14
+ },
15
+ folderId: {
16
+ type: "string",
17
+ description: "Folder ID to list files from (limits search to specific folder)",
18
+ optional: true,
19
+ },
20
+ pageSize: {
21
+ type: "number",
22
+ description: "Number of files to return per page (max 1000, default 100)",
23
+ optional: true,
24
+ },
25
+ pageToken: {
26
+ type: "string",
27
+ description: "Page token for pagination",
28
+ optional: true,
29
+ },
30
+ orderBy: {
31
+ type: "string",
32
+ description: "Sort order (e.g., 'name', 'modifiedTime desc', 'createdTime')",
33
+ optional: true,
34
+ },
35
+ },
36
+ required: [],
37
+ },
38
+ };
39
+ export async function listFiles(args) {
40
+ try {
41
+ const drive = google.drive("v3");
42
+ const { query, folderId, pageSize = 100, pageToken, orderBy } = args;
43
+ // Build query
44
+ let q = "trashed = false";
45
+ if (query) {
46
+ q += ` and (${query})`;
47
+ }
48
+ if (folderId) {
49
+ q += ` and '${folderId}' in parents`;
50
+ }
51
+ const response = await drive.files.list({
52
+ q,
53
+ pageSize: Math.min(pageSize, 1000),
54
+ pageToken,
55
+ orderBy: orderBy || "modifiedTime desc",
56
+ fields: "nextPageToken, files(id, name, mimeType, size, modifiedTime, createdTime, webViewLink, parents, iconLink)",
57
+ });
58
+ const files = response.data.files || [];
59
+ const nextPageToken = response.data.nextPageToken;
60
+ const output = formatFileList(files, nextPageToken);
61
+ return ResponseFormatter.success({
62
+ count: files.length,
63
+ files: files.map((f) => ({
64
+ id: f.id,
65
+ name: f.name,
66
+ mimeType: f.mimeType,
67
+ size: f.size,
68
+ modifiedTime: f.modifiedTime,
69
+ })),
70
+ nextPageToken,
71
+ }, output);
72
+ }
73
+ catch (error) {
74
+ return ResponseFormatter.error(error);
75
+ }
76
+ }
@@ -0,0 +1,79 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileMetadata, generateDriveWebUrl, } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_copy_file",
6
+ description: "Copy a file in Google Drive. Creates a duplicate of the file with optional new name and parent folder(s). Requires file ID.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ fileId: {
11
+ type: "string",
12
+ description: "ID of the file to copy",
13
+ },
14
+ name: {
15
+ type: "string",
16
+ description: "Name for the copied file (optional, defaults to 'Copy of [original name]')",
17
+ optional: true,
18
+ },
19
+ parents: {
20
+ type: "array",
21
+ items: {
22
+ type: "string",
23
+ },
24
+ description: "Parent folder ID(s) for the copied file (optional, defaults to same location as original)",
25
+ optional: true,
26
+ },
27
+ },
28
+ required: ["fileId"],
29
+ },
30
+ };
31
+ export async function copyFile(args) {
32
+ try {
33
+ const drive = google.drive("v3");
34
+ const { fileId, name, parents } = args;
35
+ // Get original file metadata
36
+ const originalFile = await drive.files.get({
37
+ fileId,
38
+ fields: "id, name, mimeType",
39
+ });
40
+ const originalName = originalFile.data.name || "Unknown";
41
+ // Create copy metadata
42
+ const copyMetadata = {};
43
+ if (name) {
44
+ copyMetadata.name = name;
45
+ }
46
+ else {
47
+ copyMetadata.name = `Copy of ${originalName}`;
48
+ }
49
+ if (parents && parents.length > 0) {
50
+ copyMetadata.parents = parents;
51
+ }
52
+ // Copy the file
53
+ const response = await drive.files.copy({
54
+ fileId,
55
+ requestBody: copyMetadata,
56
+ fields: "id, name, mimeType, size, modifiedTime, webViewLink, parents",
57
+ });
58
+ const copiedFile = response.data;
59
+ const copiedFileId = copiedFile.id || "";
60
+ let output = `āœ… File copied successfully!\n\n`;
61
+ output += `šŸ“„ Original: ${originalName} (${fileId})\n`;
62
+ output += `šŸ“„ Copy: ${copiedFile.name} (${copiedFileId})\n\n`;
63
+ output += formatFileMetadata(copiedFile, true);
64
+ output += `\nšŸ“Ž Web URL: ${generateDriveWebUrl(copiedFileId)}\n`;
65
+ return ResponseFormatter.success({
66
+ originalFileId: fileId,
67
+ originalName,
68
+ copiedFileId,
69
+ copiedName: copiedFile.name,
70
+ mimeType: copiedFile.mimeType,
71
+ size: copiedFile.size,
72
+ webViewLink: copiedFile.webViewLink,
73
+ parents: copiedFile.parents,
74
+ }, output);
75
+ }
76
+ catch (error) {
77
+ return ResponseFormatter.error(error);
78
+ }
79
+ }
@@ -0,0 +1,72 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileMetadata, generateDriveWebUrl, } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_create_file",
6
+ description: "Create an empty file or Google Workspace document in Google Drive. Creates a file with metadata only (no content). Use drive_upload_file if you need to include content.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ name: {
11
+ type: "string",
12
+ description: "File name",
13
+ },
14
+ mimeType: {
15
+ type: "string",
16
+ description: "MIME type of the file (e.g., 'application/vnd.google-apps.document' for Google Docs, 'application/vnd.google-apps.spreadsheet' for Sheets)",
17
+ },
18
+ parents: {
19
+ type: "array",
20
+ items: {
21
+ type: "string",
22
+ },
23
+ description: "Parent folder ID(s) where the file should be created",
24
+ optional: true,
25
+ },
26
+ description: {
27
+ type: "string",
28
+ description: "File description",
29
+ optional: true,
30
+ },
31
+ },
32
+ required: ["name", "mimeType"],
33
+ },
34
+ };
35
+ export async function createFile(args) {
36
+ try {
37
+ const drive = google.drive("v3");
38
+ const { name, mimeType, parents, description } = args;
39
+ // Create file metadata
40
+ const fileMetadata = {
41
+ name,
42
+ mimeType,
43
+ };
44
+ if (parents && parents.length > 0) {
45
+ fileMetadata.parents = parents;
46
+ }
47
+ if (description) {
48
+ fileMetadata.description = description;
49
+ }
50
+ // Create empty file
51
+ const response = await drive.files.create({
52
+ requestBody: fileMetadata,
53
+ fields: "id, name, mimeType, size, modifiedTime, webViewLink, parents",
54
+ });
55
+ const file = response.data;
56
+ const fileId = file.id || "";
57
+ let output = `āœ… File created successfully!\n\n`;
58
+ output += formatFileMetadata(file, true);
59
+ output += `\nšŸ“Ž Web URL: ${generateDriveWebUrl(fileId)}\n`;
60
+ return ResponseFormatter.success({
61
+ fileId,
62
+ name: file.name,
63
+ mimeType: file.mimeType,
64
+ size: file.size,
65
+ webViewLink: file.webViewLink,
66
+ parents: file.parents,
67
+ }, output);
68
+ }
69
+ catch (error) {
70
+ return ResponseFormatter.error(error);
71
+ }
72
+ }
@@ -0,0 +1,48 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "drive_delete_file",
5
+ description: "Delete a file from Google Drive. Moves the file to trash. To permanently delete, use drive_empty_trash. Requires file ID.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ fileId: {
10
+ type: "string",
11
+ description: "ID of the file to delete",
12
+ },
13
+ },
14
+ required: ["fileId"],
15
+ },
16
+ };
17
+ export async function deleteFile(args) {
18
+ try {
19
+ const drive = google.drive("v3");
20
+ const { fileId } = args;
21
+ // Get file metadata before deleting
22
+ const fileResponse = await drive.files.get({
23
+ fileId,
24
+ fields: "id, name, mimeType",
25
+ });
26
+ const fileName = fileResponse.data.name || "Unknown";
27
+ const mimeType = fileResponse.data.mimeType || "unknown";
28
+ // Delete the file (moves to trash)
29
+ await drive.files.delete({
30
+ fileId,
31
+ });
32
+ let output = `āœ… File deleted successfully!\n\n`;
33
+ output += `šŸ“„ File Details:\n`;
34
+ output += ` Name: ${fileName}\n`;
35
+ output += ` ID: ${fileId}\n`;
36
+ output += ` MIME Type: ${mimeType}\n`;
37
+ output += `\nNote: File moved to trash. Use drive_empty_trash to permanently delete.`;
38
+ return ResponseFormatter.success({
39
+ fileId,
40
+ name: fileName,
41
+ mimeType,
42
+ deleted: true,
43
+ }, output);
44
+ }
45
+ catch (error) {
46
+ return ResponseFormatter.error(error);
47
+ }
48
+ }
@@ -0,0 +1,79 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileMetadata, generateDriveWebUrl, } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_move_file",
6
+ description: "Move a file to a different folder in Google Drive. Updates the file's parent folder(s). Can optionally remove from existing parent folders. Requires file ID and new parent folder ID(s).",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ fileId: {
11
+ type: "string",
12
+ description: "ID of the file to move",
13
+ },
14
+ newParents: {
15
+ type: "array",
16
+ items: {
17
+ type: "string",
18
+ },
19
+ description: "New parent folder ID(s) to move the file to",
20
+ },
21
+ removeParents: {
22
+ type: "array",
23
+ items: {
24
+ type: "string",
25
+ },
26
+ description: "Parent folder ID(s) to remove the file from (optional, if not specified, removes from all current parents)",
27
+ optional: true,
28
+ },
29
+ },
30
+ required: ["fileId", "newParents"],
31
+ },
32
+ };
33
+ export async function moveFile(args) {
34
+ try {
35
+ const drive = google.drive("v3");
36
+ const { fileId, newParents, removeParents } = args;
37
+ // Get current file metadata
38
+ const fileResponse = await drive.files.get({
39
+ fileId,
40
+ fields: "id, name, parents",
41
+ });
42
+ const fileName = fileResponse.data.name || "Unknown";
43
+ const currentParents = fileResponse.data.parents || [];
44
+ // Determine which parents to remove
45
+ let parentsToRemove;
46
+ if (removeParents && removeParents.length > 0) {
47
+ parentsToRemove = removeParents;
48
+ }
49
+ else {
50
+ // Remove from all current parents if not specified
51
+ parentsToRemove = currentParents;
52
+ }
53
+ // Move the file
54
+ const response = await drive.files.update({
55
+ fileId,
56
+ addParents: newParents.join(","),
57
+ removeParents: parentsToRemove.join(","),
58
+ fields: "id, name, mimeType, size, modifiedTime, webViewLink, parents",
59
+ });
60
+ const movedFile = response.data;
61
+ let output = `āœ… File moved successfully!\n\n`;
62
+ output += `šŸ“„ File: ${fileName}\n`;
63
+ output += ` From: ${currentParents.join(", ") || "Root"}\n`;
64
+ output += ` To: ${newParents.join(", ")}\n\n`;
65
+ output += formatFileMetadata(movedFile, true);
66
+ output += `\nšŸ“Ž Web URL: ${generateDriveWebUrl(fileId)}\n`;
67
+ return ResponseFormatter.success({
68
+ fileId,
69
+ name: movedFile.name,
70
+ previousParents: currentParents,
71
+ newParents: movedFile.parents,
72
+ mimeType: movedFile.mimeType,
73
+ webViewLink: movedFile.webViewLink,
74
+ }, output);
75
+ }
76
+ catch (error) {
77
+ return ResponseFormatter.error(error);
78
+ }
79
+ }
@@ -0,0 +1,58 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileMetadata, generateDriveWebUrl, } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_rename_file",
6
+ description: "Rename a file in Google Drive. Updates the file's name while keeping all other properties unchanged. Requires file ID and new name.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ fileId: {
11
+ type: "string",
12
+ description: "ID of the file to rename",
13
+ },
14
+ newName: {
15
+ type: "string",
16
+ description: "New name for the file",
17
+ },
18
+ },
19
+ required: ["fileId", "newName"],
20
+ },
21
+ };
22
+ export async function renameFile(args) {
23
+ try {
24
+ const drive = google.drive("v3");
25
+ const { fileId, newName } = args;
26
+ // Get current file metadata
27
+ const fileResponse = await drive.files.get({
28
+ fileId,
29
+ fields: "id, name, mimeType",
30
+ });
31
+ const oldName = fileResponse.data.name || "Unknown";
32
+ // Rename the file
33
+ const response = await drive.files.update({
34
+ fileId,
35
+ requestBody: {
36
+ name: newName,
37
+ },
38
+ fields: "id, name, mimeType, size, modifiedTime, webViewLink, parents",
39
+ });
40
+ const renamedFile = response.data;
41
+ let output = `āœ… File renamed successfully!\n\n`;
42
+ output += `šŸ“„ Old Name: ${oldName}\n`;
43
+ output += `šŸ“„ New Name: ${newName}\n\n`;
44
+ output += formatFileMetadata(renamedFile, true);
45
+ output += `\nšŸ“Ž Web URL: ${generateDriveWebUrl(fileId)}\n`;
46
+ return ResponseFormatter.success({
47
+ fileId,
48
+ oldName,
49
+ newName: renamedFile.name,
50
+ mimeType: renamedFile.mimeType,
51
+ size: renamedFile.size,
52
+ webViewLink: renamedFile.webViewLink,
53
+ }, output);
54
+ }
55
+ catch (error) {
56
+ return ResponseFormatter.error(error);
57
+ }
58
+ }
@@ -0,0 +1,106 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFileMetadata, generateDriveWebUrl, } from "../../../lib/drive-helpers.js";
4
+ export const schema = {
5
+ name: "drive_update_file",
6
+ description: "Update a file's metadata and/or content in Google Drive. Can update name, description, MIME type, and content. All update fields are optional - only provide the fields you want to update.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ fileId: {
11
+ type: "string",
12
+ description: "ID of the file to update",
13
+ },
14
+ name: {
15
+ type: "string",
16
+ description: "New file name (optional)",
17
+ optional: true,
18
+ },
19
+ description: {
20
+ type: "string",
21
+ description: "New file description (optional)",
22
+ optional: true,
23
+ },
24
+ mimeType: {
25
+ type: "string",
26
+ description: "New MIME type (optional)",
27
+ optional: true,
28
+ },
29
+ content: {
30
+ type: "string",
31
+ description: "New file content (base64 encoded for binary files, plain text for text files) (optional)",
32
+ optional: true,
33
+ },
34
+ },
35
+ required: ["fileId"],
36
+ },
37
+ };
38
+ export async function updateFile(args) {
39
+ try {
40
+ const drive = google.drive("v3");
41
+ const { fileId, name, description, mimeType, content } = args;
42
+ // Get current file metadata
43
+ const fileResponse = await drive.files.get({
44
+ fileId,
45
+ fields: "id, name, description, mimeType",
46
+ });
47
+ const oldName = fileResponse.data.name || "Unknown";
48
+ const oldDescription = fileResponse.data.description || "";
49
+ const oldMimeType = fileResponse.data.mimeType || "unknown";
50
+ // Build update metadata
51
+ const updateMetadata = {};
52
+ const changes = [];
53
+ if (name !== undefined) {
54
+ updateMetadata.name = name;
55
+ changes.push(`Name: ${oldName} → ${name}`);
56
+ }
57
+ if (description !== undefined) {
58
+ updateMetadata.description = description;
59
+ changes.push(`Description: ${oldDescription || "(empty)"} → ${description}`);
60
+ }
61
+ if (mimeType !== undefined) {
62
+ updateMetadata.mimeType = mimeType;
63
+ changes.push(`MIME Type: ${oldMimeType} → ${mimeType}`);
64
+ }
65
+ // Update the file
66
+ const updateParams = {
67
+ fileId,
68
+ fields: "id, name, description, mimeType, size, modifiedTime, webViewLink, parents",
69
+ };
70
+ if (Object.keys(updateMetadata).length > 0) {
71
+ updateParams.requestBody = updateMetadata;
72
+ }
73
+ if (content !== undefined) {
74
+ updateParams.media = {
75
+ mimeType: mimeType || oldMimeType,
76
+ body: content,
77
+ };
78
+ changes.push("Content: Updated");
79
+ }
80
+ const response = await drive.files.update(updateParams);
81
+ const updatedFile = response.data;
82
+ let output = `āœ… File updated successfully!\n\n`;
83
+ if (changes.length > 0) {
84
+ output += `šŸ“ Changes:\n`;
85
+ changes.forEach((change) => {
86
+ output += ` • ${change}\n`;
87
+ });
88
+ output += `\n`;
89
+ }
90
+ output += formatFileMetadata(updatedFile, true);
91
+ output += `\nšŸ“Ž Web URL: ${generateDriveWebUrl(fileId)}\n`;
92
+ return ResponseFormatter.success({
93
+ fileId,
94
+ name: updatedFile.name,
95
+ description: updatedFile.description,
96
+ mimeType: updatedFile.mimeType,
97
+ size: updatedFile.size,
98
+ modifiedTime: updatedFile.modifiedTime,
99
+ webViewLink: updatedFile.webViewLink,
100
+ changes,
101
+ }, output);
102
+ }
103
+ catch (error) {
104
+ return ResponseFormatter.error(error);
105
+ }
106
+ }