@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
+ export const schema = {
4
+ name: "calendar_acl_insert",
5
+ description: "Add a new access control rule to share a calendar with a user, group, or domain. Specify the access level (owner, writer, reader, freeBusyReader) and the scope (who gets access). Use this to grant calendar permissions to others. The system can optionally send notification emails to inform users about the new sharing.",
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
+ role: {
14
+ type: "string",
15
+ description: "Access level: 'owner', 'writer', 'reader', 'freeBusyReader', or 'none'",
16
+ },
17
+ scopeType: {
18
+ type: "string",
19
+ description: "Scope type: 'user' (individual), 'group' (Google group), 'domain' (entire domain), or 'default' (public)",
20
+ },
21
+ scopeValue: {
22
+ type: "string",
23
+ description: "Email address (for user/group) or domain name (for domain). Omit for 'default' scope type.",
24
+ },
25
+ sendNotifications: {
26
+ type: "boolean",
27
+ description: "Whether to send email notifications about the sharing change (default: true)",
28
+ },
29
+ },
30
+ required: ["calendarId", "role", "scopeType"],
31
+ },
32
+ };
33
+ export async function insertAcl(args) {
34
+ try {
35
+ const calendar = google.calendar("v3");
36
+ const { calendarId, role, scopeType, scopeValue, sendNotifications = true, } = args;
37
+ // Validate scope
38
+ if ((scopeType === "user" || scopeType === "group" || scopeType === "domain") && !scopeValue) {
39
+ return ResponseFormatter.error(new Error(`scopeValue is required for scopeType '${scopeType}'. Provide an email address or domain name.`));
40
+ }
41
+ if (scopeType === "default" && scopeValue) {
42
+ return ResponseFormatter.error(new Error("scopeValue should not be provided for scopeType 'default' (public access)."));
43
+ }
44
+ const response = await calendar.acl.insert({
45
+ calendarId,
46
+ sendNotifications,
47
+ requestBody: {
48
+ role,
49
+ scope: {
50
+ type: scopeType,
51
+ value: scopeValue,
52
+ },
53
+ },
54
+ });
55
+ const rule = response.data;
56
+ let message = `āœ… Access control rule added successfully\n\n`;
57
+ message += `šŸ“… Calendar: ${calendarId}\n`;
58
+ message += `Role: ${rule.role?.toUpperCase()}\n`;
59
+ message += `Scope: ${rule.scope?.type}`;
60
+ if (rule.scope?.value) {
61
+ message += ` (${rule.scope.value})`;
62
+ }
63
+ message += `\n`;
64
+ message += `Rule ID: ${rule.id}\n`;
65
+ if (sendNotifications && rule.scope?.value) {
66
+ message += `\nšŸ“§ Notification email sent to ${rule.scope.value}`;
67
+ }
68
+ message += `\n\nšŸ’” The specified user/group now has ${role} access to this calendar.`;
69
+ return ResponseFormatter.success({
70
+ ruleId: rule.id,
71
+ calendarId,
72
+ role: rule.role,
73
+ scopeType: rule.scope?.type,
74
+ scopeValue: rule.scope?.value || null,
75
+ }, message);
76
+ }
77
+ catch (error) {
78
+ return ResponseFormatter.error(error);
79
+ }
80
+ }
@@ -0,0 +1,82 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_acl_list",
5
+ description: "List all access control rules (sharing settings) for a calendar. Shows who has access to the calendar and their permission levels (owner, writer, reader, freeBusyReader). Use this to view current sharing configuration before adding or removing permissions.",
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
+ maxResults: {
14
+ type: "number",
15
+ description: "Maximum number of ACL entries to return per page (default: 100, max: 250)",
16
+ },
17
+ pageToken: {
18
+ type: "string",
19
+ description: "Token for accessing subsequent result pages",
20
+ },
21
+ showDeleted: {
22
+ type: "boolean",
23
+ description: "Include deleted ACL entries (default: false)",
24
+ },
25
+ },
26
+ required: ["calendarId"],
27
+ },
28
+ };
29
+ export async function listAcl(args) {
30
+ try {
31
+ const calendar = google.calendar("v3");
32
+ const { calendarId, maxResults, pageToken, showDeleted, } = args;
33
+ const response = await calendar.acl.list({
34
+ calendarId,
35
+ maxResults,
36
+ pageToken,
37
+ showDeleted,
38
+ });
39
+ const rules = response.data.items || [];
40
+ const totalRules = rules.length;
41
+ if (totalRules === 0) {
42
+ return ResponseFormatter.success({ rules: [], count: 0 }, "No access control rules found for this calendar.");
43
+ }
44
+ let message = `šŸ” Calendar Access Control List (${totalRules} rule${totalRules > 1 ? "s" : ""})\n\n`;
45
+ rules.forEach((rule, index) => {
46
+ message += `${index + 1}. ${rule.role?.toUpperCase()}\n`;
47
+ message += ` Scope: ${rule.scope?.type}`;
48
+ if (rule.scope?.value) {
49
+ message += ` (${rule.scope.value})`;
50
+ }
51
+ message += `\n`;
52
+ message += ` Rule ID: ${rule.id}\n`;
53
+ if (rule.scope?.type === "user" || rule.scope?.type === "group") {
54
+ message += ` Email: ${rule.scope.value}\n`;
55
+ }
56
+ else if (rule.scope?.type === "domain") {
57
+ message += ` Domain: ${rule.scope.value}\n`;
58
+ }
59
+ else if (rule.scope?.type === "default") {
60
+ message += ` Public Access\n`;
61
+ }
62
+ message += `\n`;
63
+ });
64
+ if (response.data.nextPageToken) {
65
+ message += `šŸ“„ Next Page Token: ${response.data.nextPageToken}\n`;
66
+ }
67
+ message += `\nšŸ’” Role levels: owner > writer > reader > freeBusyReader`;
68
+ return ResponseFormatter.success({
69
+ rules: rules.map((rule) => ({
70
+ id: rule.id,
71
+ role: rule.role,
72
+ scopeType: rule.scope?.type,
73
+ scopeValue: rule.scope?.value || null,
74
+ })),
75
+ count: totalRules,
76
+ nextPageToken: response.data.nextPageToken || null,
77
+ }, message);
78
+ }
79
+ catch (error) {
80
+ return ResponseFormatter.error(error);
81
+ }
82
+ }
@@ -0,0 +1,113 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatEvent, parseDateTime, formatAttendees, validateTimeRange } from "../../../lib/calendar-helpers.js";
4
+ export const schema = {
5
+ name: "calendar_create_event",
6
+ description: "Create a new event in Google Calendar with specified details. Supports setting title, time, location, description, attendees, and conference data (Google Meet). Can create all-day events or timed events with specific start/end times.",
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
+ summary: {
15
+ type: "string",
16
+ description: "Event title/summary",
17
+ },
18
+ startTime: {
19
+ type: "string",
20
+ description: "Event start time (ISO 8601 format: '2024-01-15T10:00:00Z' or date only: '2024-01-15' for all-day)",
21
+ },
22
+ endTime: {
23
+ type: "string",
24
+ description: "Event end time (ISO 8601 format: '2024-01-15T11:00:00Z' or date only: '2024-01-16' for all-day)",
25
+ },
26
+ location: {
27
+ type: "string",
28
+ description: "Event location (address or place name)",
29
+ },
30
+ description: {
31
+ type: "string",
32
+ description: "Event description (supports plain text and HTML)",
33
+ },
34
+ attendees: {
35
+ type: "array",
36
+ items: {
37
+ type: "string",
38
+ },
39
+ description: "List of attendee email addresses",
40
+ },
41
+ sendUpdates: {
42
+ type: "string",
43
+ description: "Whether to send event notifications: 'all' (send to all attendees), 'externalOnly' (external only), 'none' (no notifications). Default: 'none'",
44
+ },
45
+ conferenceData: {
46
+ type: "boolean",
47
+ description: "Whether to create a Google Meet conference link (default: false)",
48
+ },
49
+ },
50
+ required: ["summary", "startTime", "endTime"],
51
+ },
52
+ };
53
+ export async function createEvent(args) {
54
+ try {
55
+ const calendar = google.calendar("v3");
56
+ const { calendarId = "primary", summary, startTime, endTime, location, description, attendees, sendUpdates = "none", conferenceData = false, } = args;
57
+ // Validate time range
58
+ const validation = validateTimeRange(startTime, endTime);
59
+ if (!validation.valid) {
60
+ return ResponseFormatter.error(new Error(validation.error));
61
+ }
62
+ // Parse start and end times
63
+ const start = parseDateTime(startTime);
64
+ const end = parseDateTime(endTime);
65
+ // Build event resource
66
+ const eventResource = {
67
+ summary,
68
+ start,
69
+ end,
70
+ };
71
+ if (location) {
72
+ eventResource.location = location;
73
+ }
74
+ if (description) {
75
+ eventResource.description = description;
76
+ }
77
+ if (attendees && attendees.length > 0) {
78
+ eventResource.attendees = formatAttendees(attendees);
79
+ }
80
+ if (conferenceData) {
81
+ eventResource.conferenceData = {
82
+ createRequest: {
83
+ requestId: `meet-${Date.now()}`,
84
+ conferenceSolutionKey: {
85
+ type: "hangoutsMeet",
86
+ },
87
+ },
88
+ };
89
+ }
90
+ const response = await calendar.events.insert({
91
+ calendarId,
92
+ requestBody: eventResource,
93
+ sendUpdates,
94
+ conferenceDataVersion: conferenceData ? 1 : undefined,
95
+ });
96
+ const event = response.data;
97
+ if (!event) {
98
+ return ResponseFormatter.error(new Error("Failed to create event"));
99
+ }
100
+ const formattedOutput = formatEvent(event, calendarId);
101
+ return ResponseFormatter.success({
102
+ id: event.id,
103
+ summary: event.summary,
104
+ start: event.start,
105
+ end: event.end,
106
+ htmlLink: event.htmlLink,
107
+ conferenceData: event.conferenceData,
108
+ }, `Event created successfully:\n\n${formattedOutput}`);
109
+ }
110
+ catch (error) {
111
+ return ResponseFormatter.error(error);
112
+ }
113
+ }
@@ -0,0 +1,52 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_delete_event",
5
+ description: "Delete a calendar event permanently. This action cannot be undone. Optionally send notifications to attendees about the event cancellation.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ calendarId: {
10
+ type: "string",
11
+ description: "Calendar identifier (default: 'primary' for user's main calendar)",
12
+ },
13
+ eventId: {
14
+ type: "string",
15
+ description: "Event identifier to delete",
16
+ },
17
+ sendUpdates: {
18
+ type: "string",
19
+ description: "Whether to send event cancellation notifications: 'all', 'externalOnly', 'none'. Default: 'all'",
20
+ },
21
+ },
22
+ required: ["eventId"],
23
+ },
24
+ };
25
+ export async function deleteEvent(args) {
26
+ try {
27
+ const calendar = google.calendar("v3");
28
+ const { calendarId = "primary", eventId, sendUpdates = "all", } = args;
29
+ // Get event details before deletion for confirmation message
30
+ const eventResponse = await calendar.events.get({
31
+ calendarId,
32
+ eventId,
33
+ });
34
+ const event = eventResponse.data;
35
+ const eventTitle = event.summary || "(No title)";
36
+ // Delete the event
37
+ await calendar.events.delete({
38
+ calendarId,
39
+ eventId,
40
+ sendUpdates,
41
+ });
42
+ return ResponseFormatter.success({
43
+ deleted: true,
44
+ eventId,
45
+ calendarId,
46
+ summary: eventTitle,
47
+ }, `Event "${eventTitle}" (ID: ${eventId}) has been deleted successfully.`);
48
+ }
49
+ catch (error) {
50
+ return ResponseFormatter.error(error);
51
+ }
52
+ }
@@ -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_get_event",
6
+ description: "Get detailed information about a specific calendar event by its ID. Returns comprehensive event details including title, time, location, description, attendees, recurrence rules, and conference data (Google Meet links).",
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: "Event identifier to retrieve",
17
+ },
18
+ },
19
+ required: ["eventId"],
20
+ },
21
+ };
22
+ export async function getEvent(args) {
23
+ try {
24
+ const calendar = google.calendar("v3");
25
+ const { calendarId = "primary", eventId } = args;
26
+ const response = await calendar.events.get({
27
+ calendarId,
28
+ eventId,
29
+ });
30
+ const event = response.data;
31
+ if (!event) {
32
+ return ResponseFormatter.error(new Error(`Event not found: ${eventId}`));
33
+ }
34
+ const formattedOutput = formatEvent(event, calendarId);
35
+ return ResponseFormatter.success({
36
+ id: event.id,
37
+ summary: event.summary,
38
+ start: event.start,
39
+ end: event.end,
40
+ location: event.location,
41
+ description: event.description,
42
+ attendees: event.attendees,
43
+ htmlLink: event.htmlLink,
44
+ conferenceData: event.conferenceData,
45
+ recurrence: event.recurrence,
46
+ status: event.status,
47
+ }, `Event details:\n\n${formattedOutput}`);
48
+ }
49
+ catch (error) {
50
+ return ResponseFormatter.error(error);
51
+ }
52
+ }
@@ -0,0 +1,86 @@
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_list_events",
6
+ description: "List events from a Google Calendar. Returns upcoming events with details including title, time, location, attendees, and meeting links. Supports filtering by time range, search query, and pagination.",
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
+ timeMin: {
15
+ type: "string",
16
+ description: "Lower bound (inclusive) for event start time (ISO 8601 format, e.g., '2024-01-01T00:00:00Z')",
17
+ },
18
+ timeMax: {
19
+ type: "string",
20
+ description: "Upper bound (exclusive) for event end time (ISO 8601 format)",
21
+ },
22
+ q: {
23
+ type: "string",
24
+ description: "Free text search terms to find events matching title, description, location, attendee emails, etc.",
25
+ },
26
+ maxResults: {
27
+ type: "number",
28
+ description: "Maximum number of events to return (default: 10, max: 250)",
29
+ },
30
+ pageToken: {
31
+ type: "string",
32
+ description: "Token for pagination to get the next page of results",
33
+ },
34
+ singleEvents: {
35
+ type: "boolean",
36
+ description: "Whether to expand recurring events into instances (default: true)",
37
+ },
38
+ orderBy: {
39
+ type: "string",
40
+ description: "Order of events: 'startTime' (chronological) or 'updated' (modification time). Requires singleEvents=true for 'startTime'",
41
+ },
42
+ },
43
+ required: [],
44
+ },
45
+ };
46
+ export async function listEvents(args) {
47
+ try {
48
+ const calendar = google.calendar("v3");
49
+ const { calendarId = "primary", timeMin, timeMax, q, maxResults = 10, pageToken, singleEvents = true, orderBy = "startTime", } = args;
50
+ const response = await calendar.events.list({
51
+ calendarId,
52
+ timeMin,
53
+ timeMax,
54
+ q,
55
+ maxResults: Math.min(maxResults, 250),
56
+ pageToken,
57
+ singleEvents,
58
+ orderBy: singleEvents ? orderBy : undefined,
59
+ });
60
+ const events = response.data.items || [];
61
+ const nextPageToken = response.data.nextPageToken;
62
+ if (events.length === 0) {
63
+ return ResponseFormatter.success({
64
+ count: 0,
65
+ events: [],
66
+ calendarId,
67
+ }, `No events found in calendar: ${calendarId}`);
68
+ }
69
+ const formattedOutput = formatEventList(events, calendarId);
70
+ return ResponseFormatter.success({
71
+ count: events.length,
72
+ calendarId,
73
+ events: events.map((e) => ({
74
+ id: e.id,
75
+ summary: e.summary,
76
+ start: e.start,
77
+ end: e.end,
78
+ htmlLink: e.htmlLink,
79
+ })),
80
+ nextPageToken,
81
+ }, `Events from ${calendarId}:\n\n${formattedOutput}`);
82
+ }
83
+ catch (error) {
84
+ return ResponseFormatter.error(error);
85
+ }
86
+ }
@@ -0,0 +1,116 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ import { formatEvent, parseDateTime, formatAttendees, validateTimeRange } from "../../../lib/calendar-helpers.js";
4
+ export const schema = {
5
+ name: "calendar_update_event",
6
+ description: "Update an existing calendar event. Can modify title, time, location, description, attendees, and other event properties. Only specified fields will be updated; unspecified fields remain unchanged.",
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: "Event identifier to update",
17
+ },
18
+ summary: {
19
+ type: "string",
20
+ description: "New event title/summary",
21
+ },
22
+ startTime: {
23
+ type: "string",
24
+ description: "New event start time (ISO 8601 format: '2024-01-15T10:00:00Z' or date only: '2024-01-15' for all-day)",
25
+ },
26
+ endTime: {
27
+ type: "string",
28
+ description: "New event end time (ISO 8601 format: '2024-01-15T11:00:00Z' or date only: '2024-01-16' for all-day)",
29
+ },
30
+ location: {
31
+ type: "string",
32
+ description: "New event location",
33
+ },
34
+ description: {
35
+ type: "string",
36
+ description: "New event description",
37
+ },
38
+ attendees: {
39
+ type: "array",
40
+ items: {
41
+ type: "string",
42
+ },
43
+ description: "New list of attendee email addresses (replaces existing attendees)",
44
+ },
45
+ sendUpdates: {
46
+ type: "string",
47
+ description: "Whether to send event notifications: 'all', 'externalOnly', 'none'. Default: 'all'",
48
+ },
49
+ },
50
+ required: ["eventId"],
51
+ },
52
+ };
53
+ export async function updateEvent(args) {
54
+ try {
55
+ const calendar = google.calendar("v3");
56
+ const { calendarId = "primary", eventId, summary, startTime, endTime, location, description, attendees, sendUpdates = "all", } = args;
57
+ // First, get the existing event
58
+ const existingResponse = await calendar.events.get({
59
+ calendarId,
60
+ eventId,
61
+ });
62
+ const existingEvent = existingResponse.data;
63
+ if (!existingEvent) {
64
+ return ResponseFormatter.error(new Error(`Event not found: ${eventId}`));
65
+ }
66
+ // Build update resource with only specified fields
67
+ const eventResource = {
68
+ ...existingEvent,
69
+ };
70
+ if (summary !== undefined) {
71
+ eventResource.summary = summary;
72
+ }
73
+ if (startTime !== undefined && endTime !== undefined) {
74
+ // Validate time range if both are provided
75
+ const validation = validateTimeRange(startTime, endTime);
76
+ if (!validation.valid) {
77
+ return ResponseFormatter.error(new Error(validation.error));
78
+ }
79
+ eventResource.start = parseDateTime(startTime);
80
+ eventResource.end = parseDateTime(endTime);
81
+ }
82
+ else if (startTime !== undefined || endTime !== undefined) {
83
+ return ResponseFormatter.error(new Error("Both startTime and endTime must be provided together"));
84
+ }
85
+ if (location !== undefined) {
86
+ eventResource.location = location;
87
+ }
88
+ if (description !== undefined) {
89
+ eventResource.description = description;
90
+ }
91
+ if (attendees !== undefined) {
92
+ eventResource.attendees = formatAttendees(attendees);
93
+ }
94
+ const response = await calendar.events.update({
95
+ calendarId,
96
+ eventId,
97
+ requestBody: eventResource,
98
+ sendUpdates,
99
+ });
100
+ const event = response.data;
101
+ if (!event) {
102
+ return ResponseFormatter.error(new Error("Failed to update event"));
103
+ }
104
+ const formattedOutput = formatEvent(event, calendarId);
105
+ return ResponseFormatter.success({
106
+ id: event.id,
107
+ summary: event.summary,
108
+ start: event.start,
109
+ end: event.end,
110
+ htmlLink: event.htmlLink,
111
+ }, `Event updated successfully:\n\n${formattedOutput}`);
112
+ }
113
+ catch (error) {
114
+ return ResponseFormatter.error(error);
115
+ }
116
+ }
@@ -0,0 +1,73 @@
1
+ import { google } from "googleapis";
2
+ import { ResponseFormatter } from "../../../lib/response-formatter.js";
3
+ export const schema = {
4
+ name: "calendar_calendarlist_get",
5
+ description: "Get detailed information about a specific calendar from the user's calendar list. Returns calendar metadata including access role, notifications, and display settings.",
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 getCalendarListEntry(args) {
18
+ try {
19
+ const calendar = google.calendar("v3");
20
+ const { calendarId } = args;
21
+ const response = await calendar.calendarList.get({
22
+ calendarId,
23
+ });
24
+ const cal = response.data;
25
+ let message = `šŸ“… Calendar: ${cal.summary}\n\n`;
26
+ message += `ID: ${cal.id}\n`;
27
+ message += `Access Role: ${cal.accessRole}\n`;
28
+ message += `Time Zone: ${cal.timeZone}\n`;
29
+ if (cal.description) {
30
+ message += `Description: ${cal.description}\n`;
31
+ }
32
+ if (cal.location) {
33
+ message += `Location: ${cal.location}\n`;
34
+ }
35
+ if (cal.primary) {
36
+ message += `Primary Calendar: Yes\n`;
37
+ }
38
+ if (cal.backgroundColor) {
39
+ message += `\nšŸŽØ Display Colors:\n`;
40
+ message += ` Background: ${cal.backgroundColor}\n`;
41
+ message += ` Foreground: ${cal.foregroundColor}\n`;
42
+ }
43
+ if (cal.defaultReminders && cal.defaultReminders.length > 0) {
44
+ message += `\nā° Default Reminders:\n`;
45
+ cal.defaultReminders.forEach((reminder) => {
46
+ message += ` - ${reminder.method}: ${reminder.minutes} minutes before\n`;
47
+ });
48
+ }
49
+ if (cal.notificationSettings) {
50
+ message += `\nšŸ”” Notification Settings:\n`;
51
+ cal.notificationSettings.notifications?.forEach((notif) => {
52
+ message += ` - ${notif.type}: ${notif.method}\n`;
53
+ });
54
+ }
55
+ return ResponseFormatter.success({
56
+ calendar: {
57
+ id: cal.id,
58
+ summary: cal.summary,
59
+ description: cal.description || null,
60
+ location: cal.location || null,
61
+ timeZone: cal.timeZone,
62
+ accessRole: cal.accessRole,
63
+ primary: cal.primary || false,
64
+ backgroundColor: cal.backgroundColor,
65
+ foregroundColor: cal.foregroundColor,
66
+ defaultReminders: cal.defaultReminders || [],
67
+ },
68
+ }, message);
69
+ }
70
+ catch (error) {
71
+ return ResponseFormatter.error(error);
72
+ }
73
+ }