@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,87 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_calendarlist_list",
5
+ description: "List all calendars in the user's calendar list. Returns information about each calendar including ID, summary, description, and access role. Supports pagination and filtering by access level.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ maxResults: {
10
+ type: "number",
11
+ description: "Maximum number of calendars to return per page (default: 100, max: 250)",
12
+ },
13
+ minAccessRole: {
14
+ type: "string",
15
+ description: "Minimum access role filter: 'freeBusyReader', 'owner', 'reader', or 'writer'",
16
+ },
17
+ pageToken: {
18
+ type: "string",
19
+ description: "Token for accessing subsequent result pages",
20
+ },
21
+ showDeleted: {
22
+ type: "boolean",
23
+ description: "Include deleted calendar entries (default: false)",
24
+ },
25
+ showHidden: {
26
+ type: "boolean",
27
+ description: "Include hidden entries (default: false)",
28
+ },
29
+ },
30
+ required: [],
31
+ },
32
+ };
33
+ export async function listCalendarList(args) {
34
+ try {
35
+ const calendar = google.calendar("v3");
36
+ const { maxResults, minAccessRole, pageToken, showDeleted, showHidden, } = args;
37
+ const response = await calendar.calendarList.list({
38
+ maxResults,
39
+ minAccessRole,
40
+ pageToken,
41
+ showDeleted,
42
+ showHidden,
43
+ });
44
+ const calendars = response.data.items || [];
45
+ const totalCalendars = calendars.length;
46
+ if (totalCalendars === 0) {
47
+ return ResponseFormatter.success({ calendars: [], count: 0 }, "No calendars found in the calendar list.");
48
+ }
49
+ // Format calendar list
50
+ const calendarList = calendars.map((cal) => ({
51
+ id: cal.id,
52
+ summary: cal.summary,
53
+ description: cal.description || null,
54
+ timeZone: cal.timeZone,
55
+ accessRole: cal.accessRole,
56
+ primary: cal.primary || false,
57
+ backgroundColor: cal.backgroundColor,
58
+ foregroundColor: cal.foregroundColor,
59
+ }));
60
+ let message = `📅 Calendar List (${totalCalendars} calendar${totalCalendars > 1 ? "s" : ""})\n\n`;
61
+ calendars.forEach((cal, index) => {
62
+ const isPrimary = cal.primary ? " [PRIMARY]" : "";
63
+ message += `${index + 1}. ${cal.summary}${isPrimary}\n`;
64
+ message += ` ID: ${cal.id}\n`;
65
+ message += ` Access Role: ${cal.accessRole}\n`;
66
+ if (cal.description) {
67
+ message += ` Description: ${cal.description}\n`;
68
+ }
69
+ message += ` Time Zone: ${cal.timeZone}\n`;
70
+ if (cal.backgroundColor) {
71
+ message += ` Colors: BG ${cal.backgroundColor}, FG ${cal.foregroundColor}\n`;
72
+ }
73
+ message += "\n";
74
+ });
75
+ if (response.data.nextPageToken) {
76
+ message += `\n📄 Next Page Token: ${response.data.nextPageToken}`;
77
+ }
78
+ return ResponseFormatter.success({
79
+ calendars: calendarList,
80
+ count: totalCalendars,
81
+ nextPageToken: response.data.nextPageToken || null,
82
+ }, message);
83
+ }
84
+ catch (error) {
85
+ return ResponseFormatter.error(error);
86
+ }
87
+ }
@@ -0,0 +1,52 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_calendars_get",
5
+ description: "Get metadata for a specific calendar. Returns calendar information including title, description, location, and timezone. Use 'primary' to access the currently logged-in user's main calendar, or provide a specific calendar ID.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ calendarId: {
10
+ type: "string",
11
+ description: "Calendar identifier. Use 'primary' for the user's primary calendar.",
12
+ },
13
+ },
14
+ required: ["calendarId"],
15
+ },
16
+ };
17
+ export async function getCalendar(args) {
18
+ try {
19
+ const calendar = google.calendar("v3");
20
+ const { calendarId } = args;
21
+ const response = await calendar.calendars.get({
22
+ calendarId,
23
+ });
24
+ const cal = response.data;
25
+ let message = `📅 Calendar: ${cal.summary}\n\n`;
26
+ message += `ID: ${cal.id}\n`;
27
+ if (cal.description) {
28
+ message += `Description: ${cal.description}\n`;
29
+ }
30
+ if (cal.location) {
31
+ message += `Location: ${cal.location}\n`;
32
+ }
33
+ if (cal.timeZone) {
34
+ message += `Time Zone: ${cal.timeZone}\n`;
35
+ }
36
+ if (cal.conferenceProperties) {
37
+ message += `\n📞 Conference Properties:\n`;
38
+ message += ` Allowed Conference Solution Types: ${cal.conferenceProperties.allowedConferenceSolutionTypes?.join(", ") || "None"}\n`;
39
+ }
40
+ return ResponseFormatter.success({
41
+ calendarId: cal.id,
42
+ summary: cal.summary,
43
+ description: cal.description || null,
44
+ location: cal.location || null,
45
+ timeZone: cal.timeZone || null,
46
+ etag: cal.etag,
47
+ }, message);
48
+ }
49
+ catch (error) {
50
+ return ResponseFormatter.error(error);
51
+ }
52
+ }
@@ -0,0 +1,66 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_calendars_insert",
5
+ description: "Create a new secondary calendar. The authenticated user becomes the owner of the new calendar. You can specify the calendar's title, description, location, and timezone. This is different from the primary calendar which is created automatically with the user account.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ summary: {
10
+ type: "string",
11
+ description: "Title of the calendar (required)",
12
+ },
13
+ description: {
14
+ type: "string",
15
+ description: "Description of the calendar",
16
+ },
17
+ location: {
18
+ type: "string",
19
+ description: "Geographic location as free-form text",
20
+ },
21
+ timeZone: {
22
+ type: "string",
23
+ description: "IANA Time Zone Database name (e.g., 'America/New_York', 'Europe/London')",
24
+ },
25
+ },
26
+ required: ["summary"],
27
+ },
28
+ };
29
+ export async function insertCalendar(args) {
30
+ try {
31
+ const calendar = google.calendar("v3");
32
+ const { summary, description, location, timeZone, } = args;
33
+ const response = await calendar.calendars.insert({
34
+ requestBody: {
35
+ summary,
36
+ description,
37
+ location,
38
+ timeZone,
39
+ },
40
+ });
41
+ const cal = response.data;
42
+ let message = `✅ Calendar created successfully\n\n`;
43
+ message += `📅 ${cal.summary}\n`;
44
+ message += `ID: ${cal.id}\n`;
45
+ if (cal.description) {
46
+ message += `Description: ${cal.description}\n`;
47
+ }
48
+ if (cal.location) {
49
+ message += `Location: ${cal.location}\n`;
50
+ }
51
+ if (cal.timeZone) {
52
+ message += `Time Zone: ${cal.timeZone}\n`;
53
+ }
54
+ message += `\n💡 You are now the owner of this calendar.`;
55
+ return ResponseFormatter.success({
56
+ calendarId: cal.id,
57
+ summary: cal.summary,
58
+ description: cal.description || null,
59
+ location: cal.location || null,
60
+ timeZone: cal.timeZone || null,
61
+ }, message);
62
+ }
63
+ catch (error) {
64
+ return ResponseFormatter.error(error);
65
+ }
66
+ }
@@ -0,0 +1,85 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_calendars_update",
5
+ description: "Update metadata for an existing calendar. You can modify the calendar's title, description, location, and timezone. All fields are optional - only provide the fields you want to update. Use 'primary' to update the user's primary calendar.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ calendarId: {
10
+ type: "string",
11
+ description: "Calendar identifier. Use 'primary' for the user's primary calendar.",
12
+ },
13
+ summary: {
14
+ type: "string",
15
+ description: "New title for the calendar",
16
+ },
17
+ description: {
18
+ type: "string",
19
+ description: "New description for the calendar",
20
+ },
21
+ location: {
22
+ type: "string",
23
+ description: "New geographic location as free-form text",
24
+ },
25
+ timeZone: {
26
+ type: "string",
27
+ description: "New IANA Time Zone Database name (e.g., 'America/New_York')",
28
+ },
29
+ },
30
+ required: ["calendarId"],
31
+ },
32
+ };
33
+ export async function updateCalendar(args) {
34
+ try {
35
+ const calendar = google.calendar("v3");
36
+ const { calendarId, summary, description, location, timeZone, } = args;
37
+ // Get current calendar data
38
+ const currentCalendar = await calendar.calendars.get({
39
+ calendarId,
40
+ });
41
+ if (!currentCalendar.data) {
42
+ return ResponseFormatter.error(new Error(`Calendar with ID '${calendarId}' not found.`));
43
+ }
44
+ // Prepare update payload with only provided fields
45
+ const updatePayload = {};
46
+ if (summary !== undefined)
47
+ updatePayload.summary = summary;
48
+ if (description !== undefined)
49
+ updatePayload.description = description;
50
+ if (location !== undefined)
51
+ updatePayload.location = location;
52
+ if (timeZone !== undefined)
53
+ updatePayload.timeZone = timeZone;
54
+ if (Object.keys(updatePayload).length === 0) {
55
+ return ResponseFormatter.error(new Error("No fields provided to update. Specify at least one field: summary, description, location, or timeZone."));
56
+ }
57
+ const response = await calendar.calendars.update({
58
+ calendarId,
59
+ requestBody: updatePayload,
60
+ });
61
+ const cal = response.data;
62
+ let message = `✅ Calendar updated successfully\n\n`;
63
+ message += `📅 ${cal.summary}\n`;
64
+ message += `ID: ${cal.id}\n`;
65
+ if (cal.description) {
66
+ message += `Description: ${cal.description}\n`;
67
+ }
68
+ if (cal.location) {
69
+ message += `Location: ${cal.location}\n`;
70
+ }
71
+ if (cal.timeZone) {
72
+ message += `Time Zone: ${cal.timeZone}\n`;
73
+ }
74
+ return ResponseFormatter.success({
75
+ calendarId: cal.id,
76
+ summary: cal.summary,
77
+ description: cal.description || null,
78
+ location: cal.location || null,
79
+ timeZone: cal.timeZone || null,
80
+ }, message);
81
+ }
82
+ catch (error) {
83
+ return ResponseFormatter.error(error);
84
+ }
85
+ }
@@ -0,0 +1,46 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_colors_get",
5
+ description: "Get the color definitions available for calendars and events. Returns a palette of colors with their IDs and hex values that can be used when creating or updating calendars and events. Useful for UI display and color selection.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {},
9
+ required: [],
10
+ },
11
+ };
12
+ export async function getColors() {
13
+ try {
14
+ const calendar = google.calendar("v3");
15
+ const response = await calendar.colors.get();
16
+ const data = response.data;
17
+ const calendarColors = data.calendar || {};
18
+ const eventColors = data.event || {};
19
+ let message = `🎨 Google Calendar Color Palette\n\n`;
20
+ // Calendar Colors
21
+ message += `📅 Calendar Colors:\n`;
22
+ Object.entries(calendarColors).forEach(([id, colorData]) => {
23
+ message += ` ${id}: Background ${colorData.background}, Foreground ${colorData.foreground}\n`;
24
+ });
25
+ message += `\n📌 Event Colors:\n`;
26
+ Object.entries(eventColors).forEach(([id, colorData]) => {
27
+ message += ` ${id}: Background ${colorData.background}, Foreground ${colorData.foreground}\n`;
28
+ });
29
+ message += `\n💡 Usage: Use these color IDs when creating or updating calendars and events.`;
30
+ return ResponseFormatter.success({
31
+ calendarColors: Object.entries(calendarColors).map(([id, data]) => ({
32
+ id,
33
+ background: data.background,
34
+ foreground: data.foreground,
35
+ })),
36
+ eventColors: Object.entries(eventColors).map(([id, data]) => ({
37
+ id,
38
+ background: data.background,
39
+ foreground: data.foreground,
40
+ })),
41
+ }, message);
42
+ }
43
+ catch (error) {
44
+ return ResponseFormatter.error(error);
45
+ }
46
+ }
@@ -0,0 +1,81 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatEventList } from "../../../lib/calendar-helpers.js";
4
+ export const schema = {
5
+ name: "calendar_events_instances",
6
+ description: "Get all instances of a recurring event within a specified time range. Returns individual occurrences of repeating events, allowing you to see each instance's specific date and time. Useful for viewing or managing individual occurrences of a recurring meeting or appointment.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ calendarId: {
11
+ type: "string",
12
+ description: "Calendar identifier (default: 'primary' for user's main calendar)",
13
+ },
14
+ eventId: {
15
+ type: "string",
16
+ description: "Recurring event identifier",
17
+ },
18
+ timeMin: {
19
+ type: "string",
20
+ description: "Lower bound (inclusive) for instances (RFC3339 format, e.g., '2024-01-15T00:00:00Z')",
21
+ },
22
+ timeMax: {
23
+ type: "string",
24
+ description: "Upper bound (exclusive) for instances (RFC3339 format, e.g., '2024-01-31T23:59:59Z')",
25
+ },
26
+ maxResults: {
27
+ type: "number",
28
+ description: "Maximum number of instances to return (default: 250, max: 2500)",
29
+ },
30
+ pageToken: {
31
+ type: "string",
32
+ description: "Token for accessing subsequent result pages",
33
+ },
34
+ showDeleted: {
35
+ type: "boolean",
36
+ description: "Include cancelled instances (default: false)",
37
+ },
38
+ },
39
+ required: ["eventId"],
40
+ },
41
+ };
42
+ export async function listEventInstances(args) {
43
+ try {
44
+ const calendar = google.calendar("v3");
45
+ const { calendarId = "primary", eventId, timeMin, timeMax, maxResults, pageToken, showDeleted, } = args;
46
+ const response = await calendar.events.instances({
47
+ calendarId,
48
+ eventId,
49
+ timeMin,
50
+ timeMax,
51
+ maxResults,
52
+ pageToken,
53
+ showDeleted,
54
+ });
55
+ const instances = response.data.items || [];
56
+ const totalInstances = instances.length;
57
+ if (totalInstances === 0) {
58
+ return ResponseFormatter.success({ instances: [], count: 0 }, "No instances found for this recurring event in the specified time range.");
59
+ }
60
+ const message = formatEventList(instances, calendarId);
61
+ let resultMessage = `🔁 Recurring Event Instances (${totalInstances} instance${totalInstances > 1 ? "s" : ""})\n\n`;
62
+ resultMessage += message;
63
+ if (response.data.nextPageToken) {
64
+ resultMessage += `\n\n📄 Next Page Token: ${response.data.nextPageToken}`;
65
+ }
66
+ return ResponseFormatter.success({
67
+ instances: instances.map((inst) => ({
68
+ id: inst.id,
69
+ summary: inst.summary,
70
+ start: inst.start,
71
+ end: inst.end,
72
+ status: inst.status,
73
+ })),
74
+ count: totalInstances,
75
+ nextPageToken: response.data.nextPageToken || null,
76
+ }, resultMessage);
77
+ }
78
+ catch (error) {
79
+ return ResponseFormatter.error(error);
80
+ }
81
+ }
@@ -0,0 +1,63 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatEvent } from "../../../lib/calendar-helpers.js";
4
+ export const schema = {
5
+ name: "calendar_events_move",
6
+ description: "Move an event from one calendar to another. This changes the event's organizer to the destination calendar owner. Only works with default events (not recurring event instances). The event is removed from the source calendar and appears in the destination calendar.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ calendarId: {
11
+ type: "string",
12
+ description: "Source calendar identifier where the event currently exists",
13
+ },
14
+ eventId: {
15
+ type: "string",
16
+ description: "Event identifier to move",
17
+ },
18
+ destination: {
19
+ type: "string",
20
+ description: "Destination calendar identifier where the event will be moved to",
21
+ },
22
+ sendUpdates: {
23
+ type: "string",
24
+ description: "Whether to send event notifications: 'all', 'externalOnly', 'none'. Default: 'none'",
25
+ },
26
+ },
27
+ required: ["calendarId", "eventId", "destination"],
28
+ },
29
+ };
30
+ export async function moveEvent(args) {
31
+ try {
32
+ const calendar = google.calendar("v3");
33
+ const { calendarId, eventId, destination, sendUpdates = "none", } = args;
34
+ // Get event details before moving
35
+ const originalEvent = await calendar.events.get({
36
+ calendarId,
37
+ eventId,
38
+ });
39
+ const response = await calendar.events.move({
40
+ calendarId,
41
+ eventId,
42
+ destination,
43
+ sendUpdates,
44
+ });
45
+ const event = response.data;
46
+ let message = `✅ Event moved successfully\n\n`;
47
+ message += `From Calendar: ${calendarId}\n`;
48
+ message += `To Calendar: ${destination}\n\n`;
49
+ message += formatEvent(event, destination);
50
+ return ResponseFormatter.success({
51
+ eventId: event.id,
52
+ sourceCalendar: calendarId,
53
+ destinationCalendar: destination,
54
+ summary: event.summary,
55
+ start: event.start,
56
+ end: event.end,
57
+ htmlLink: event.htmlLink,
58
+ }, message);
59
+ }
60
+ catch (error) {
61
+ return ResponseFormatter.error(error);
62
+ }
63
+ }
@@ -0,0 +1,52 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatEvent } from "../../../lib/calendar-helpers.js";
4
+ export const schema = {
5
+ name: "calendar_events_quickadd",
6
+ description: "Create a calendar event from a simple text description using natural language processing. Examples: 'Meeting with John tomorrow at 2pm', 'Lunch at noon on Friday', 'Conference call next Monday 10-11am'. The system automatically parses the text to extract event details.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ calendarId: {
11
+ type: "string",
12
+ description: "Calendar identifier (default: 'primary' for user's main calendar)",
13
+ },
14
+ text: {
15
+ type: "string",
16
+ description: "Natural language text describing the event (e.g., 'Dinner with Sarah tomorrow at 7pm')",
17
+ },
18
+ sendUpdates: {
19
+ type: "string",
20
+ description: "Whether to send event notifications: 'all', 'externalOnly', 'none'. Default: 'none'",
21
+ },
22
+ },
23
+ required: ["text"],
24
+ },
25
+ };
26
+ export async function quickAddEvent(args) {
27
+ try {
28
+ const calendar = google.calendar("v3");
29
+ const { calendarId = "primary", text, sendUpdates = "none", } = args;
30
+ const response = await calendar.events.quickAdd({
31
+ calendarId,
32
+ text,
33
+ sendUpdates,
34
+ });
35
+ const event = response.data;
36
+ let message = `✅ Event created via QuickAdd\n\n`;
37
+ message += `Input Text: "${text}"\n\n`;
38
+ message += formatEvent(event, calendarId);
39
+ return ResponseFormatter.success({
40
+ eventId: event.id,
41
+ calendarId,
42
+ summary: event.summary,
43
+ start: event.start,
44
+ end: event.end,
45
+ htmlLink: event.htmlLink,
46
+ inputText: text,
47
+ }, message);
48
+ }
49
+ catch (error) {
50
+ return ResponseFormatter.error(error);
51
+ }
52
+ }
@@ -0,0 +1,69 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatFreeBusyResponse } from "../../../lib/calendar-helpers.js";
4
+ export const schema = {
5
+ name: "calendar_freebusy_query",
6
+ description: "Query free/busy information for one or more calendars within a specified time range. Returns busy time periods to help schedule meetings or check availability. Useful for finding meeting slots that work for multiple attendees.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ timeMin: {
11
+ type: "string",
12
+ description: "Start of the time range to query (ISO 8601 format, e.g., '2024-01-01T00:00:00Z')",
13
+ },
14
+ timeMax: {
15
+ type: "string",
16
+ description: "End of the time range to query (ISO 8601 format)",
17
+ },
18
+ calendars: {
19
+ type: "array",
20
+ items: {
21
+ type: "string",
22
+ },
23
+ description: "List of calendar IDs to query (default: ['primary'])",
24
+ },
25
+ timeZone: {
26
+ type: "string",
27
+ description: "Time zone for the query (e.g., 'America/New_York', 'UTC'). Default: UTC",
28
+ },
29
+ },
30
+ required: ["timeMin", "timeMax"],
31
+ },
32
+ };
33
+ export async function queryFreeBusy(args) {
34
+ try {
35
+ const calendar = google.calendar("v3");
36
+ const { timeMin, timeMax, calendars = ["primary"], timeZone = "UTC", } = args;
37
+ const response = await calendar.freebusy.query({
38
+ requestBody: {
39
+ timeMin,
40
+ timeMax,
41
+ timeZone,
42
+ items: calendars.map((id) => ({ id })),
43
+ },
44
+ });
45
+ const freeBusyData = response.data;
46
+ if (!freeBusyData) {
47
+ return ResponseFormatter.error(new Error("Failed to query free/busy information"));
48
+ }
49
+ const formattedOutput = formatFreeBusyResponse(freeBusyData);
50
+ // Calculate total busy periods across all calendars
51
+ let totalBusyPeriods = 0;
52
+ if (freeBusyData.calendars) {
53
+ Object.values(freeBusyData.calendars).forEach((cal) => {
54
+ if (cal.busy) {
55
+ totalBusyPeriods += cal.busy.length;
56
+ }
57
+ });
58
+ }
59
+ return ResponseFormatter.success({
60
+ timeMin: freeBusyData.timeMin,
61
+ timeMax: freeBusyData.timeMax,
62
+ calendars: freeBusyData.calendars,
63
+ totalBusyPeriods,
64
+ }, `Free/Busy query results:\n\n${formattedOutput}`);
65
+ }
66
+ catch (error) {
67
+ return ResponseFormatter.error(error);
68
+ }
69
+ }