gmcp 0.4.0 → 0.5.0

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 (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +267 -164
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -148,7 +148,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
148
148
 
149
149
  ## Tools
150
150
 
151
- ### Gmail (16 tools)
151
+ ### Gmail (17 tools)
152
152
 
153
153
  | Tool | Description |
154
154
  |------|-------------|
@@ -161,6 +161,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
161
161
  | `gmcp_gmail_reply` | Reply to email in thread |
162
162
  | `gmcp_gmail_create_draft` | Create draft message |
163
163
  | `gmcp_gmail_delete_email` | Permanently delete email (bypasses trash) |
164
+ | `gmcp_gmail_archive_email` | Archive email (remove from inbox) |
164
165
  | `gmcp_gmail_list_labels` | List all labels |
165
166
  | `gmcp_gmail_get_label` | Get label details |
166
167
  | `gmcp_gmail_create_label` | Create custom label |
package/dist/index.js CHANGED
@@ -739,7 +739,7 @@ function registerTools(server, client, tools, logger) {
739
739
  }
740
740
  }
741
741
 
742
- // src/tools/batch-modify.ts
742
+ // src/tools/archive-email.ts
743
743
  import json2md from "json2md";
744
744
  import { z } from "zod";
745
745
 
@@ -775,13 +775,108 @@ function createErrorResponse(context, error, logger) {
775
775
  };
776
776
  }
777
777
 
778
- // src/tools/batch-modify.ts
779
- var BatchModifyInputSchema = z.object({
780
- message_ids: z.array(z.string()).min(1, "Must provide at least one message ID").max(1000, "Maximum 1000 messages per batch").describe("Array of Gmail message IDs to modify (max 1000)"),
781
- add_labels: z.array(z.string()).optional().describe("Label IDs to add to all messages (e.g., ['STARRED', 'IMPORTANT'])"),
782
- remove_labels: z.array(z.string()).optional().describe("Label IDs to remove from all messages (e.g., ['UNREAD', 'INBOX'])"),
778
+ // src/tools/archive-email.ts
779
+ var ArchiveEmailInputSchema = z.object({
780
+ message_id: z.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to archive"),
783
781
  output_format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
784
782
  });
783
+ function archiveToMarkdown(email) {
784
+ const sections = [
785
+ { h1: "Email Archived Successfully" },
786
+ { h2: "Message Details" },
787
+ {
788
+ ul: [
789
+ `**Subject:** ${email.subject}`,
790
+ `**From:** ${email.from}`,
791
+ `**Message ID:** ${email.id}`
792
+ ]
793
+ },
794
+ { h2: "Current Labels" },
795
+ {
796
+ p: email.labels.length > 0 ? email.labels.join(", ") : "*No labels on this message*"
797
+ },
798
+ { h2: "Notes" },
799
+ {
800
+ ul: [
801
+ "The email has been removed from your inbox",
802
+ "The email is still accessible in All Mail",
803
+ "To unarchive, add the INBOX label back to the message"
804
+ ]
805
+ }
806
+ ];
807
+ return json2md(sections);
808
+ }
809
+ async function archiveEmailTool(gmailClient, params) {
810
+ try {
811
+ const email = await gmailClient.modifyLabels(params.message_id, undefined, [
812
+ "INBOX"
813
+ ]);
814
+ const formattedEmail = formatEmailForOutput(email);
815
+ const output = {
816
+ message_id: params.message_id,
817
+ subject: email.subject,
818
+ archived: true,
819
+ removed_labels: ["INBOX"],
820
+ current_labels: email.labels || []
821
+ };
822
+ const textContent = params.output_format === "json" ? JSON.stringify(output, null, 2) : archiveToMarkdown({
823
+ ...formattedEmail,
824
+ labels: email.labels || []
825
+ });
826
+ return {
827
+ content: [{ type: "text", text: textContent }],
828
+ structuredContent: output
829
+ };
830
+ } catch (error) {
831
+ return createErrorResponse("archiving email", error);
832
+ }
833
+ }
834
+ var ARCHIVE_EMAIL_DESCRIPTION = `Archive a Gmail email by removing it from the inbox.
835
+
836
+ This tool archives an email message by removing the INBOX label. The email remains accessible in "All Mail" and can be unarchived by adding the INBOX label back.
837
+
838
+ **Parameters**:
839
+ - \`message_id\` (string, required): The Gmail message ID to archive
840
+ - \`output_format\` (string, optional): Output format: "markdown" (default) or "json"
841
+
842
+ **Returns**:
843
+ - \`message_id\`: The archived message ID
844
+ - \`subject\`: Email subject
845
+ - \`archived\`: Always true on success
846
+ - \`removed_labels\`: Labels that were removed (always ["INBOX"])
847
+ - \`current_labels\`: All current labels on the message after archiving
848
+
849
+ **Examples**:
850
+ - Archive email: \`{ "message_id": "18f3c5d4e8a2b1c0" }\`
851
+ - Archive with JSON output: \`{ "message_id": "18f3c5d4e8a2b1c0", "output_format": "json" }\`
852
+
853
+ **Important Notes**:
854
+ - This is a reversible operation - archived emails can be unarchived
855
+ - The email is moved out of the inbox but remains in "All Mail"
856
+ - To unarchive, use \`modify_labels\` with \`add_labels: ["INBOX"]\`
857
+ - This is different from \`delete_email\` which permanently removes the message
858
+
859
+ **Use Cases**:
860
+ - Clean up inbox without deleting emails
861
+ - Archive emails after reading/processing them
862
+ - Remove emails from inbox while keeping them for reference
863
+
864
+ **Error Handling**:
865
+ - Returns error if message ID doesn't exist
866
+ - Returns error if authentication lacks sufficient permissions
867
+
868
+ **Scope Requirements**:
869
+ - Requires \`gmail.modify\` or full \`mail.google.com\` scope`;
870
+
871
+ // src/tools/batch-modify.ts
872
+ import json2md2 from "json2md";
873
+ import { z as z2 } from "zod";
874
+ var BatchModifyInputSchema = z2.object({
875
+ message_ids: z2.array(z2.string()).min(1, "Must provide at least one message ID").max(1000, "Maximum 1000 messages per batch").describe("Array of Gmail message IDs to modify (max 1000)"),
876
+ add_labels: z2.array(z2.string()).optional().describe("Label IDs to add to all messages (e.g., ['STARRED', 'IMPORTANT'])"),
877
+ remove_labels: z2.array(z2.string()).optional().describe("Label IDs to remove from all messages (e.g., ['UNREAD', 'INBOX'])"),
878
+ output_format: z2.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
879
+ });
785
880
  function batchModificationToMarkdown(messageCount, addedLabels, removedLabels) {
786
881
  const sections = [
787
882
  { h1: "Batch Label Modification Successful" },
@@ -798,7 +893,7 @@ function batchModificationToMarkdown(messageCount, addedLabels, removedLabels) {
798
893
  sections.push({
799
894
  p: `All ${messageCount} messages have been updated successfully.`
800
895
  });
801
- return json2md(sections);
896
+ return json2md2(sections);
802
897
  }
803
898
  async function batchModifyTool(gmailClient, params) {
804
899
  try {
@@ -890,10 +985,10 @@ This tool allows you to efficiently add or remove labels from multiple Gmail mes
890
985
  - Recommended for operations affecting more than 5 messages`;
891
986
 
892
987
  // src/tools/calendar-create.ts
893
- import { z as z2 } from "zod";
988
+ import { z as z3 } from "zod";
894
989
 
895
990
  // src/utils/markdown.ts
896
- import json2md2 from "json2md";
991
+ import json2md3 from "json2md";
897
992
  function emailToJson2md(email) {
898
993
  const elements = [
899
994
  { h2: email.subject },
@@ -935,7 +1030,7 @@ function searchResultsToMarkdown(query, data) {
935
1030
  });
936
1031
  }
937
1032
  }
938
- return json2md2(elements);
1033
+ return json2md3(elements);
939
1034
  }
940
1035
  function calendarListToMarkdown(data) {
941
1036
  const sections = [
@@ -961,7 +1056,7 @@ function calendarListToMarkdown(data) {
961
1056
  sections.push({ ul: details });
962
1057
  }
963
1058
  }
964
- return json2md2(sections);
1059
+ return json2md3(sections);
965
1060
  }
966
1061
  function formatEventTime(time) {
967
1062
  if (time.date) {
@@ -1028,7 +1123,7 @@ function eventListToMarkdown(data) {
1028
1123
  sections.push({ hr: "" });
1029
1124
  }
1030
1125
  }
1031
- return json2md2(sections);
1126
+ return json2md3(sections);
1032
1127
  }
1033
1128
  function formatAttendeeDetailed(att) {
1034
1129
  const name = att.display_name || att.email;
@@ -1076,23 +1171,23 @@ function eventToMarkdown(event, successMessage) {
1076
1171
  sections.push({ ul: event.attendees.map(formatAttendeeDetailed) });
1077
1172
  }
1078
1173
  addEventMetadata(sections, event);
1079
- return json2md2(sections);
1174
+ return json2md3(sections);
1080
1175
  }
1081
1176
 
1082
1177
  // src/tools/calendar-create.ts
1083
- var CalendarCreateEventInputSchema = z2.object({
1084
- calendar_id: z2.string().default("primary").describe('Calendar ID to create event in (default: "primary")'),
1085
- summary: z2.string().min(1, "Event title is required").describe("Event title/summary (required)"),
1086
- start: z2.string().min(1, "Start time is required").describe('Start time: RFC3339 (e.g., "2024-01-15T09:00:00-08:00") or date for all-day (e.g., "2024-01-15")'),
1087
- end: z2.string().min(1, "End time is required").describe('End time: RFC3339 (e.g., "2024-01-15T10:00:00-08:00") or date for all-day (e.g., "2024-01-15")'),
1088
- description: z2.string().optional().describe("Event description (optional)"),
1089
- location: z2.string().optional().describe("Event location (optional)"),
1090
- attendees: z2.array(z2.string().email()).optional().describe("Array of attendee email addresses (optional)"),
1091
- timezone: z2.string().optional().describe('IANA timezone (e.g., "America/Los_Angeles", optional)'),
1092
- recurrence: z2.array(z2.string()).optional().describe('Recurrence rules as RRULE strings (e.g., ["RRULE:FREQ=WEEKLY;COUNT=10"], optional)'),
1093
- add_meet: z2.boolean().default(false).describe("Auto-create Google Meet conference link (default: false)"),
1094
- confirm: z2.boolean().default(false).describe("Must be true to create the event (safety check)"),
1095
- output_format: z2.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1178
+ var CalendarCreateEventInputSchema = z3.object({
1179
+ calendar_id: z3.string().default("primary").describe('Calendar ID to create event in (default: "primary")'),
1180
+ summary: z3.string().min(1, "Event title is required").describe("Event title/summary (required)"),
1181
+ start: z3.string().min(1, "Start time is required").describe('Start time: RFC3339 (e.g., "2024-01-15T09:00:00-08:00") or date for all-day (e.g., "2024-01-15")'),
1182
+ end: z3.string().min(1, "End time is required").describe('End time: RFC3339 (e.g., "2024-01-15T10:00:00-08:00") or date for all-day (e.g., "2024-01-15")'),
1183
+ description: z3.string().optional().describe("Event description (optional)"),
1184
+ location: z3.string().optional().describe("Event location (optional)"),
1185
+ attendees: z3.array(z3.string().email()).optional().describe("Array of attendee email addresses (optional)"),
1186
+ timezone: z3.string().optional().describe('IANA timezone (e.g., "America/Los_Angeles", optional)'),
1187
+ recurrence: z3.array(z3.string()).optional().describe('Recurrence rules as RRULE strings (e.g., ["RRULE:FREQ=WEEKLY;COUNT=10"], optional)'),
1188
+ add_meet: z3.boolean().default(false).describe("Auto-create Google Meet conference link (default: false)"),
1189
+ confirm: z3.boolean().default(false).describe("Must be true to create the event (safety check)"),
1190
+ output_format: z3.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1096
1191
  });
1097
1192
  async function calendarCreateEventTool(calendarClient, params) {
1098
1193
  if (!params.confirm) {
@@ -1243,16 +1338,16 @@ Created event object containing:
1243
1338
  - Returns error if Calendar API request fails`;
1244
1339
 
1245
1340
  // src/tools/calendar-events.ts
1246
- import { z as z3 } from "zod";
1247
- var CalendarEventsInputSchema = z3.object({
1248
- calendar_id: z3.string().default("primary").describe('Calendar ID to list events from (default: "primary")'),
1249
- time_min: z3.string().optional().describe("Lower bound for event start time (RFC3339, e.g., 2024-01-01T00:00:00Z)"),
1250
- time_max: z3.string().optional().describe("Upper bound for event start time (RFC3339, e.g., 2024-12-31T23:59:59Z)"),
1251
- max_results: z3.number().int().min(1).max(250).default(10).describe("Maximum number of events to return (default: 10, max: 250)"),
1252
- query: z3.string().optional().describe("Free text search query to filter events"),
1253
- single_events: z3.boolean().default(true).describe("Expand recurring events into individual instances (default: true)"),
1254
- order_by: z3.enum(["startTime", "updated"]).default("startTime").describe('Sort order: "startTime" (default) or "updated"'),
1255
- output_format: z3.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1341
+ import { z as z4 } from "zod";
1342
+ var CalendarEventsInputSchema = z4.object({
1343
+ calendar_id: z4.string().default("primary").describe('Calendar ID to list events from (default: "primary")'),
1344
+ time_min: z4.string().optional().describe("Lower bound for event start time (RFC3339, e.g., 2024-01-01T00:00:00Z)"),
1345
+ time_max: z4.string().optional().describe("Upper bound for event start time (RFC3339, e.g., 2024-12-31T23:59:59Z)"),
1346
+ max_results: z4.number().int().min(1).max(250).default(10).describe("Maximum number of events to return (default: 10, max: 250)"),
1347
+ query: z4.string().optional().describe("Free text search query to filter events"),
1348
+ single_events: z4.boolean().default(true).describe("Expand recurring events into individual instances (default: true)"),
1349
+ order_by: z4.enum(["startTime", "updated"]).default("startTime").describe('Sort order: "startTime" (default) or "updated"'),
1350
+ output_format: z4.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1256
1351
  });
1257
1352
  async function calendarEventsTool(calendarClient, params) {
1258
1353
  try {
@@ -1350,11 +1445,11 @@ This tool retrieves events from a specified calendar with support for time range
1350
1445
  - Returns empty array if no events match filters`;
1351
1446
 
1352
1447
  // src/tools/calendar-get-event.ts
1353
- import { z as z4 } from "zod";
1354
- var CalendarGetEventInputSchema = z4.object({
1355
- calendar_id: z4.string().default("primary").describe('Calendar ID (default: "primary")'),
1356
- event_id: z4.string().min(1, "Event ID is required").describe("Event ID to retrieve"),
1357
- output_format: z4.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1448
+ import { z as z5 } from "zod";
1449
+ var CalendarGetEventInputSchema = z5.object({
1450
+ calendar_id: z5.string().default("primary").describe('Calendar ID (default: "primary")'),
1451
+ event_id: z5.string().min(1, "Event ID is required").describe("Event ID to retrieve"),
1452
+ output_format: z5.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1358
1453
  });
1359
1454
  async function calendarGetEventTool(calendarClient, params) {
1360
1455
  try {
@@ -1446,10 +1541,10 @@ Complete event object containing:
1446
1541
  - Returns error if Calendar API request fails`;
1447
1542
 
1448
1543
  // src/tools/calendar-list.ts
1449
- import { z as z5 } from "zod";
1450
- var CalendarListInputSchema = z5.object({
1451
- show_hidden: z5.boolean().default(false).describe("Include hidden calendars in the results (default: false)"),
1452
- output_format: z5.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1544
+ import { z as z6 } from "zod";
1545
+ var CalendarListInputSchema = z6.object({
1546
+ show_hidden: z6.boolean().default(false).describe("Include hidden calendars in the results (default: false)"),
1547
+ output_format: z6.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1453
1548
  });
1454
1549
  async function calendarListTool(calendarClient, params) {
1455
1550
  try {
@@ -1511,16 +1606,16 @@ This tool retrieves all calendars accessible by the authenticated user, includin
1511
1606
  - Returns error if Calendar API request fails`;
1512
1607
 
1513
1608
  // src/tools/create-draft.ts
1514
- import json2md3 from "json2md";
1515
- import { z as z6 } from "zod";
1516
- var CreateDraftInputSchema = z6.object({
1517
- to: z6.email("Must be a valid email address").describe("Recipient email address"),
1518
- subject: z6.string().min(1, "Subject cannot be empty").describe("Email subject"),
1519
- body: z6.string().min(1, "Body cannot be empty").describe("Email body content"),
1520
- content_type: z6.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML emails"),
1521
- cc: z6.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
1522
- bcc: z6.email("BCC must be a valid email address").optional().describe("BCC (blind carbon copy) email address"),
1523
- output_format: z6.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1609
+ import json2md4 from "json2md";
1610
+ import { z as z7 } from "zod";
1611
+ var CreateDraftInputSchema = z7.object({
1612
+ to: z7.email("Must be a valid email address").describe("Recipient email address"),
1613
+ subject: z7.string().min(1, "Subject cannot be empty").describe("Email subject"),
1614
+ body: z7.string().min(1, "Body cannot be empty").describe("Email body content"),
1615
+ content_type: z7.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML emails"),
1616
+ cc: z7.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
1617
+ bcc: z7.email("BCC must be a valid email address").optional().describe("BCC (blind carbon copy) email address"),
1618
+ output_format: z7.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1524
1619
  });
1525
1620
  function draftCreatedToMarkdown(params, result) {
1526
1621
  const sections = [
@@ -1540,7 +1635,7 @@ function draftCreatedToMarkdown(params, result) {
1540
1635
  p: "The draft has been saved and will appear in your Drafts folder. You can edit and send it later from Gmail."
1541
1636
  }
1542
1637
  ];
1543
- return json2md3(sections);
1638
+ return json2md4(sections);
1544
1639
  }
1545
1640
  async function createDraftTool(gmailClient, params) {
1546
1641
  try {
@@ -1634,15 +1729,15 @@ This tool creates a draft email in your Gmail Drafts folder. Unlike sending an e
1634
1729
  - Collaborative: Others with access can review drafts`;
1635
1730
 
1636
1731
  // src/tools/create-label.ts
1637
- import json2md4 from "json2md";
1638
- import { z as z7 } from "zod";
1639
- var CreateLabelInputSchema = z7.object({
1640
- name: z7.string().min(1, "Label name cannot be empty").describe("The label name (e.g., 'Work', 'Personal/Family'). Use '/' for nested labels."),
1641
- message_list_visibility: z7.enum(["show", "hide"]).optional().describe("How label appears in message list. Default: 'show'. Use 'hide' to hide messages with this label from message list."),
1642
- label_list_visibility: z7.enum(["labelShow", "labelShowIfUnread", "labelHide"]).optional().describe("How label appears in label list. Default: 'labelShow'. Options: 'labelShow' (always visible), 'labelShowIfUnread' (only when unread), 'labelHide' (hidden)."),
1643
- background_color: z7.string().optional().describe("Background color in hex format (e.g., '#ff0000'). Must provide both background and text color together."),
1644
- text_color: z7.string().optional().describe("Text color in hex format (e.g., '#ffffff'). Must provide both background and text color together."),
1645
- output_format: z7.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1732
+ import json2md5 from "json2md";
1733
+ import { z as z8 } from "zod";
1734
+ var CreateLabelInputSchema = z8.object({
1735
+ name: z8.string().min(1, "Label name cannot be empty").describe("The label name (e.g., 'Work', 'Personal/Family'). Use '/' for nested labels."),
1736
+ message_list_visibility: z8.enum(["show", "hide"]).optional().describe("How label appears in message list. Default: 'show'. Use 'hide' to hide messages with this label from message list."),
1737
+ label_list_visibility: z8.enum(["labelShow", "labelShowIfUnread", "labelHide"]).optional().describe("How label appears in label list. Default: 'labelShow'. Options: 'labelShow' (always visible), 'labelShowIfUnread' (only when unread), 'labelHide' (hidden)."),
1738
+ background_color: z8.string().optional().describe("Background color in hex format (e.g., '#ff0000'). Must provide both background and text color together."),
1739
+ text_color: z8.string().optional().describe("Text color in hex format (e.g., '#ffffff'). Must provide both background and text color together."),
1740
+ output_format: z8.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1646
1741
  });
1647
1742
  function createdLabelToMarkdown(label) {
1648
1743
  const sections = [
@@ -1679,7 +1774,7 @@ function createdLabelToMarkdown(label) {
1679
1774
  sections.push({
1680
1775
  p: `You can now use this label ID (${label.id}) with other tools like modify_labels or batch_modify.`
1681
1776
  });
1682
- return json2md4(sections);
1777
+ return json2md5(sections);
1683
1778
  }
1684
1779
  async function createLabelTool(gmailClient, params) {
1685
1780
  try {
@@ -1771,11 +1866,11 @@ This tool creates a new label with customizable visibility and color settings. L
1771
1866
  - Requires \`gmail.labels\` or \`gmail.modify\` scope`;
1772
1867
 
1773
1868
  // src/tools/delete-email.ts
1774
- import json2md5 from "json2md";
1775
- import { z as z8 } from "zod";
1776
- var DeleteEmailInputSchema = z8.object({
1777
- message_id: z8.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to permanently delete"),
1778
- output_format: z8.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1869
+ import json2md6 from "json2md";
1870
+ import { z as z9 } from "zod";
1871
+ var DeleteEmailInputSchema = z9.object({
1872
+ message_id: z9.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to permanently delete"),
1873
+ output_format: z9.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1779
1874
  });
1780
1875
  function deletionToMarkdown(messageId) {
1781
1876
  const sections = [
@@ -1792,7 +1887,7 @@ function deletionToMarkdown(messageId) {
1792
1887
  ]
1793
1888
  }
1794
1889
  ];
1795
- return json2md5(sections);
1890
+ return json2md6(sections);
1796
1891
  }
1797
1892
  async function deleteEmailTool(gmailClient, params) {
1798
1893
  try {
@@ -1850,8 +1945,8 @@ This tool permanently deletes an email message from your Gmail account. Unlike m
1850
1945
  - Requires \`gmail.modify\` or full \`mail.google.com\` scope`;
1851
1946
 
1852
1947
  // src/tools/delete-label.ts
1853
- import json2md6 from "json2md";
1854
- import { z as z9 } from "zod";
1948
+ import json2md7 from "json2md";
1949
+ import { z as z10 } from "zod";
1855
1950
  var SYSTEM_LABELS = [
1856
1951
  "INBOX",
1857
1952
  "SENT",
@@ -1867,9 +1962,9 @@ var SYSTEM_LABELS = [
1867
1962
  "CATEGORY_UPDATES",
1868
1963
  "CATEGORY_FORUMS"
1869
1964
  ];
1870
- var DeleteLabelInputSchema = z9.object({
1871
- label_id: z9.string().min(1, "Label ID cannot be empty").describe("The label ID to delete (e.g., 'Label_123'). Cannot delete system labels."),
1872
- output_format: z9.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1965
+ var DeleteLabelInputSchema = z10.object({
1966
+ label_id: z10.string().min(1, "Label ID cannot be empty").describe("The label ID to delete (e.g., 'Label_123'). Cannot delete system labels."),
1967
+ output_format: z10.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
1873
1968
  });
1874
1969
  function deletionToMarkdown2(labelId) {
1875
1970
  const sections = [
@@ -1887,7 +1982,7 @@ function deletionToMarkdown2(labelId) {
1887
1982
  ]
1888
1983
  }
1889
1984
  ];
1890
- return json2md6(sections);
1985
+ return json2md7(sections);
1891
1986
  }
1892
1987
  async function deleteLabelTool(gmailClient, params) {
1893
1988
  try {
@@ -2009,11 +2104,11 @@ This tool permanently deletes a user-created label from your Gmail account. Syst
2009
2104
  If you want to hide a label instead of deleting it, consider using the \`update_label\` tool to set \`label_list_visibility\` to "labelHide" instead.`;
2010
2105
 
2011
2106
  // src/tools/get-attachment.ts
2012
- import { z as z10 } from "zod";
2013
- var GetAttachmentInputSchema = z10.object({
2014
- message_id: z10.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID containing the attachment"),
2015
- attachment_id: z10.string().min(1, "Attachment ID cannot be empty").describe("The attachment ID to download (from list_attachments)"),
2016
- output_format: z10.enum(["base64", "json"]).default("base64").describe("Output format: base64 (default, returns raw base64url string) or json (returns structured object)")
2107
+ import { z as z11 } from "zod";
2108
+ var GetAttachmentInputSchema = z11.object({
2109
+ message_id: z11.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID containing the attachment"),
2110
+ attachment_id: z11.string().min(1, "Attachment ID cannot be empty").describe("The attachment ID to download (from list_attachments)"),
2111
+ output_format: z11.enum(["base64", "json"]).default("base64").describe("Output format: base64 (default, returns raw base64url string) or json (returns structured object)")
2017
2112
  });
2018
2113
  async function getAttachmentTool(gmailClient, params) {
2019
2114
  try {
@@ -2080,12 +2175,12 @@ To decode:
2080
2175
  3. Decode base64url data to get original file content`;
2081
2176
 
2082
2177
  // src/tools/get-email.ts
2083
- import json2md7 from "json2md";
2084
- import { z as z11 } from "zod";
2085
- var GetEmailInputSchema = z11.object({
2086
- message_id: z11.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to retrieve"),
2087
- include_body: z11.boolean().default(true).describe("Whether to include full email body in results (default: true)"),
2088
- output_format: z11.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2178
+ import json2md8 from "json2md";
2179
+ import { z as z12 } from "zod";
2180
+ var GetEmailInputSchema = z12.object({
2181
+ message_id: z12.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to retrieve"),
2182
+ include_body: z12.boolean().default(true).describe("Whether to include full email body in results (default: true)"),
2183
+ output_format: z12.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2089
2184
  });
2090
2185
  function emailToMarkdown(email) {
2091
2186
  const sections = [
@@ -2112,7 +2207,7 @@ function emailToMarkdown(email) {
2112
2207
  sections.push({ h2: "Snippet" });
2113
2208
  sections.push({ p: email.snippet });
2114
2209
  }
2115
- return json2md7(sections);
2210
+ return json2md8(sections);
2116
2211
  }
2117
2212
  async function getEmailTool(gmailClient, params) {
2118
2213
  try {
@@ -2163,11 +2258,11 @@ This tool retrieves a specific email message from Gmail using its unique message
2163
2258
  - Retrieve email for further processing or analysis`;
2164
2259
 
2165
2260
  // src/tools/get-label.ts
2166
- import json2md8 from "json2md";
2167
- import { z as z12 } from "zod";
2168
- var GetLabelInputSchema = z12.object({
2169
- label_id: z12.string().min(1, "Label ID cannot be empty").describe("The label ID to retrieve (e.g., 'INBOX', 'Label_123')"),
2170
- output_format: z12.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2261
+ import json2md9 from "json2md";
2262
+ import { z as z13 } from "zod";
2263
+ var GetLabelInputSchema = z13.object({
2264
+ label_id: z13.string().min(1, "Label ID cannot be empty").describe("The label ID to retrieve (e.g., 'INBOX', 'Label_123')"),
2265
+ output_format: z13.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2171
2266
  });
2172
2267
  function labelToMarkdown(label) {
2173
2268
  const sections = [
@@ -2202,7 +2297,7 @@ function labelToMarkdown(label) {
2202
2297
  ]
2203
2298
  });
2204
2299
  }
2205
- return json2md8(sections);
2300
+ return json2md9(sections);
2206
2301
  }
2207
2302
  async function getLabelTool(gmailClient, params) {
2208
2303
  try {
@@ -2269,12 +2364,12 @@ This tool retrieves comprehensive details about a label, including its name, typ
2269
2364
  - System labels and custom labels are both supported`;
2270
2365
 
2271
2366
  // src/tools/get-thread.ts
2272
- import json2md9 from "json2md";
2273
- import { z as z13 } from "zod";
2274
- var GetThreadInputSchema = z13.object({
2275
- thread_id: z13.string().min(1, "Thread ID cannot be empty").describe("The Gmail thread ID to retrieve"),
2276
- include_body: z13.boolean().default(false).describe("Whether to include full email body for all messages (default: false)"),
2277
- output_format: z13.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2367
+ import json2md10 from "json2md";
2368
+ import { z as z14 } from "zod";
2369
+ var GetThreadInputSchema = z14.object({
2370
+ thread_id: z14.string().min(1, "Thread ID cannot be empty").describe("The Gmail thread ID to retrieve"),
2371
+ include_body: z14.boolean().default(false).describe("Whether to include full email body for all messages (default: false)"),
2372
+ output_format: z14.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2278
2373
  });
2279
2374
  function threadToMarkdown(threadId, messages) {
2280
2375
  const sections = [
@@ -2309,7 +2404,7 @@ function threadToMarkdown(threadId, messages) {
2309
2404
  sections.push({ p: "---" });
2310
2405
  }
2311
2406
  }
2312
- return json2md9(sections);
2407
+ return json2md10(sections);
2313
2408
  }
2314
2409
  async function getThreadTool(gmailClient, params) {
2315
2410
  try {
@@ -2367,11 +2462,11 @@ This tool retrieves all messages in a Gmail conversation thread (email chain). T
2367
2462
  - Extract all messages from a discussion thread`;
2368
2463
 
2369
2464
  // src/tools/list-attachments.ts
2370
- import json2md10 from "json2md";
2371
- import { z as z14 } from "zod";
2372
- var ListAttachmentsInputSchema = z14.object({
2373
- message_id: z14.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to list attachments from"),
2374
- output_format: z14.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2465
+ import json2md11 from "json2md";
2466
+ import { z as z15 } from "zod";
2467
+ var ListAttachmentsInputSchema = z15.object({
2468
+ message_id: z15.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to list attachments from"),
2469
+ output_format: z15.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2375
2470
  });
2376
2471
  function formatBytes(bytes) {
2377
2472
  if (bytes === 0) {
@@ -2403,7 +2498,7 @@ function attachmentsToMarkdown(messageId, attachments) {
2403
2498
  });
2404
2499
  }
2405
2500
  }
2406
- return json2md10(sections);
2501
+ return json2md11(sections);
2407
2502
  }
2408
2503
  async function listAttachmentsTool(gmailClient, params) {
2409
2504
  try {
@@ -2461,10 +2556,10 @@ This tool retrieves metadata about all attachments in a specific email message,
2461
2556
  - List attachment IDs for use with get_attachment tool`;
2462
2557
 
2463
2558
  // src/tools/list-labels.ts
2464
- import json2md11 from "json2md";
2465
- import { z as z15 } from "zod";
2466
- var ListLabelsInputSchema = z15.object({
2467
- output_format: z15.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2559
+ import json2md12 from "json2md";
2560
+ import { z as z16 } from "zod";
2561
+ var ListLabelsInputSchema = z16.object({
2562
+ output_format: z16.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2468
2563
  });
2469
2564
  function labelsToMarkdown(labels) {
2470
2565
  const sections = [{ h1: "Gmail Labels" }];
@@ -2481,7 +2576,7 @@ function labelsToMarkdown(labels) {
2481
2576
  if (labels.system.length === 0 && labels.user.length === 0) {
2482
2577
  sections.push({ p: "*No labels found*" });
2483
2578
  }
2484
- return json2md11(sections);
2579
+ return json2md12(sections);
2485
2580
  }
2486
2581
  async function listLabelsTool(gmailClient, params) {
2487
2582
  try {
@@ -2554,13 +2649,13 @@ Custom labels are created by users for organizing emails. They have IDs like \`L
2554
2649
  - Returns error if Gmail API is unreachable`;
2555
2650
 
2556
2651
  // src/tools/modify-labels.ts
2557
- import json2md12 from "json2md";
2558
- import { z as z16 } from "zod";
2559
- var ModifyLabelsInputSchema = z16.object({
2560
- message_id: z16.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to modify labels for"),
2561
- add_labels: z16.array(z16.string()).optional().describe("Label IDs to add (e.g., ['STARRED', 'INBOX', 'UNREAD'] or custom label IDs)"),
2562
- remove_labels: z16.array(z16.string()).optional().describe("Label IDs to remove (e.g., ['UNREAD', 'INBOX'] to mark read and archive)"),
2563
- output_format: z16.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2652
+ import json2md13 from "json2md";
2653
+ import { z as z17 } from "zod";
2654
+ var ModifyLabelsInputSchema = z17.object({
2655
+ message_id: z17.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to modify labels for"),
2656
+ add_labels: z17.array(z17.string()).optional().describe("Label IDs to add (e.g., ['STARRED', 'INBOX', 'UNREAD'] or custom label IDs)"),
2657
+ remove_labels: z17.array(z17.string()).optional().describe("Label IDs to remove (e.g., ['UNREAD', 'INBOX'] to mark read and archive)"),
2658
+ output_format: z17.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2564
2659
  });
2565
2660
  function labelModificationToMarkdown(email, addedLabels, removedLabels) {
2566
2661
  const sections = [
@@ -2586,7 +2681,7 @@ function labelModificationToMarkdown(email, addedLabels, removedLabels) {
2586
2681
  sections.push({
2587
2682
  p: email.labels.length > 0 ? email.labels.join(", ") : "*No labels on this message*"
2588
2683
  });
2589
- return json2md12(sections);
2684
+ return json2md13(sections);
2590
2685
  }
2591
2686
  async function modifyLabelsTool(gmailClient, params) {
2592
2687
  try {
@@ -2677,15 +2772,15 @@ This tool allows you to add or remove labels from a Gmail message. Labels are us
2677
2772
  - Move messages to trash or spam`;
2678
2773
 
2679
2774
  // src/tools/reply.ts
2680
- import json2md13 from "json2md";
2681
- import { z as z17 } from "zod";
2682
- var ReplyInputSchema = z17.object({
2683
- message_id: z17.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to reply to"),
2684
- body: z17.string().min(1, "Reply body cannot be empty").describe("Reply message body"),
2685
- content_type: z17.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML replies"),
2686
- cc: z17.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
2687
- confirm: z17.boolean().default(false).describe("Set to true to confirm and send the reply. If false, returns preview only."),
2688
- output_format: z17.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2775
+ import json2md14 from "json2md";
2776
+ import { z as z18 } from "zod";
2777
+ var ReplyInputSchema = z18.object({
2778
+ message_id: z18.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to reply to"),
2779
+ body: z18.string().min(1, "Reply body cannot be empty").describe("Reply message body"),
2780
+ content_type: z18.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML replies"),
2781
+ cc: z18.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
2782
+ confirm: z18.boolean().default(false).describe("Set to true to confirm and send the reply. If false, returns preview only."),
2783
+ output_format: z18.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2689
2784
  });
2690
2785
  function replyPreviewToMarkdown(originalEmail, replyBody, contentType, cc) {
2691
2786
  const sections = [
@@ -2713,7 +2808,7 @@ function replyPreviewToMarkdown(originalEmail, replyBody, contentType, cc) {
2713
2808
  { h2: "Reply Body" },
2714
2809
  { p: replyBody }
2715
2810
  ];
2716
- return json2md13(sections);
2811
+ return json2md14(sections);
2717
2812
  }
2718
2813
  function replySentToMarkdown(originalEmail, result, cc) {
2719
2814
  const sections = [
@@ -2732,7 +2827,7 @@ function replySentToMarkdown(originalEmail, result, cc) {
2732
2827
  p: "Your reply has been sent and added to the conversation thread."
2733
2828
  }
2734
2829
  ];
2735
- return json2md13(sections);
2830
+ return json2md14(sections);
2736
2831
  }
2737
2832
  async function replyTool(gmailClient, params) {
2738
2833
  try {
@@ -2856,13 +2951,13 @@ This tool sends a reply to an existing email, automatically threading it in the
2856
2951
  4. Call with \`confirm: true\` to send`;
2857
2952
 
2858
2953
  // src/tools/search.ts
2859
- import { z as z18 } from "zod";
2860
- var SearchEmailsInputSchema = z18.object({
2861
- query: z18.string().min(1, "Query cannot be empty").describe('Gmail search query using Gmail search syntax (e.g., "from:user@example.com subject:test is:unread")'),
2862
- max_results: z18.number().int().min(1).max(100).default(10).describe("Maximum number of emails to return (default: 10, max: 100)"),
2863
- include_body: z18.boolean().default(false).describe("Whether to include full email body in results (default: false)"),
2864
- page_token: z18.string().optional().describe("Token for pagination to fetch next page of results"),
2865
- output_format: z18.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2954
+ import { z as z19 } from "zod";
2955
+ var SearchEmailsInputSchema = z19.object({
2956
+ query: z19.string().min(1, "Query cannot be empty").describe('Gmail search query using Gmail search syntax (e.g., "from:user@example.com subject:test is:unread")'),
2957
+ max_results: z19.number().int().min(1).max(100).default(10).describe("Maximum number of emails to return (default: 10, max: 100)"),
2958
+ include_body: z19.boolean().default(false).describe("Whether to include full email body in results (default: false)"),
2959
+ page_token: z19.string().optional().describe("Token for pagination to fetch next page of results"),
2960
+ output_format: z19.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2866
2961
  });
2867
2962
  async function searchEmailsTool(gmailClient, params) {
2868
2963
  try {
@@ -2932,17 +3027,17 @@ This tool allows you to search through your Gmail messages using the same query
2932
3027
  - Empty results if no emails match the query`;
2933
3028
 
2934
3029
  // src/tools/send-email.ts
2935
- import json2md14 from "json2md";
2936
- import { z as z19 } from "zod";
2937
- var SendEmailInputSchema = z19.object({
2938
- to: z19.email("Must be a valid email address").describe("Recipient email address"),
2939
- subject: z19.string().min(1, "Subject cannot be empty").describe("Email subject"),
2940
- body: z19.string().min(1, "Body cannot be empty").describe("Email body content"),
2941
- content_type: z19.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML emails"),
2942
- cc: z19.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
2943
- bcc: z19.email("BCC must be a valid email address").optional().describe("BCC (blind carbon copy) email address"),
2944
- confirm: z19.boolean().default(false).describe("Set to true to confirm and send the email. If false, returns preview only."),
2945
- output_format: z19.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
3030
+ import json2md15 from "json2md";
3031
+ import { z as z20 } from "zod";
3032
+ var SendEmailInputSchema = z20.object({
3033
+ to: z20.email("Must be a valid email address").describe("Recipient email address"),
3034
+ subject: z20.string().min(1, "Subject cannot be empty").describe("Email subject"),
3035
+ body: z20.string().min(1, "Body cannot be empty").describe("Email body content"),
3036
+ content_type: z20.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML emails"),
3037
+ cc: z20.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
3038
+ bcc: z20.email("BCC must be a valid email address").optional().describe("BCC (blind carbon copy) email address"),
3039
+ confirm: z20.boolean().default(false).describe("Set to true to confirm and send the email. If false, returns preview only."),
3040
+ output_format: z20.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
2946
3041
  });
2947
3042
  function emailPreviewToMarkdown(params) {
2948
3043
  const sections = [
@@ -2963,7 +3058,7 @@ function emailPreviewToMarkdown(params) {
2963
3058
  { h2: "Body" },
2964
3059
  { p: params.body }
2965
3060
  ];
2966
- return json2md14(sections);
3061
+ return json2md15(sections);
2967
3062
  }
2968
3063
  function emailSentToMarkdown(params, result) {
2969
3064
  const sections = [
@@ -2983,7 +3078,7 @@ function emailSentToMarkdown(params, result) {
2983
3078
  p: "The email has been sent and will appear in your Sent folder."
2984
3079
  }
2985
3080
  ];
2986
- return json2md14(sections);
3081
+ return json2md15(sections);
2987
3082
  }
2988
3083
  async function sendEmailTool(gmailClient, params) {
2989
3084
  try {
@@ -3089,8 +3184,8 @@ This tool sends email through your Gmail account. It includes a safety feature:
3089
3184
  3. Call again with \`confirm: true\` to send`;
3090
3185
 
3091
3186
  // src/tools/update-label.ts
3092
- import json2md15 from "json2md";
3093
- import { z as z20 } from "zod";
3187
+ import json2md16 from "json2md";
3188
+ import { z as z21 } from "zod";
3094
3189
  var SYSTEM_LABELS2 = [
3095
3190
  "INBOX",
3096
3191
  "SENT",
@@ -3101,14 +3196,14 @@ var SYSTEM_LABELS2 = [
3101
3196
  "IMPORTANT",
3102
3197
  "UNREAD"
3103
3198
  ];
3104
- var UpdateLabelInputSchema = z20.object({
3105
- label_id: z20.string().min(1, "Label ID cannot be empty").describe("The label ID to update (e.g., 'Label_123' or 'INBOX')"),
3106
- name: z20.string().optional().describe("New label name. Cannot rename system labels. Use '/' for nested labels."),
3107
- message_list_visibility: z20.enum(["show", "hide"]).optional().describe("How label appears in message list"),
3108
- label_list_visibility: z20.enum(["labelShow", "labelShowIfUnread", "labelHide"]).optional().describe("How label appears in label list (sidebar)"),
3109
- background_color: z20.string().optional().describe("Background color in hex format (e.g., '#ff0000'). Must provide both background and text color together."),
3110
- text_color: z20.string().optional().describe("Text color in hex format (e.g., '#ffffff'). Must provide both background and text color together."),
3111
- output_format: z20.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
3199
+ var UpdateLabelInputSchema = z21.object({
3200
+ label_id: z21.string().min(1, "Label ID cannot be empty").describe("The label ID to update (e.g., 'Label_123' or 'INBOX')"),
3201
+ name: z21.string().optional().describe("New label name. Cannot rename system labels. Use '/' for nested labels."),
3202
+ message_list_visibility: z21.enum(["show", "hide"]).optional().describe("How label appears in message list"),
3203
+ label_list_visibility: z21.enum(["labelShow", "labelShowIfUnread", "labelHide"]).optional().describe("How label appears in label list (sidebar)"),
3204
+ background_color: z21.string().optional().describe("Background color in hex format (e.g., '#ff0000'). Must provide both background and text color together."),
3205
+ text_color: z21.string().optional().describe("Text color in hex format (e.g., '#ffffff'). Must provide both background and text color together."),
3206
+ output_format: z21.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
3112
3207
  });
3113
3208
  function updatedLabelToMarkdown(label, updates) {
3114
3209
  const sections = [
@@ -3156,7 +3251,7 @@ function updatedLabelToMarkdown(label, updates) {
3156
3251
  ]
3157
3252
  });
3158
3253
  }
3159
- return json2md15(sections);
3254
+ return json2md16(sections);
3160
3255
  }
3161
3256
  async function updateLabelTool(gmailClient, params) {
3162
3257
  try {
@@ -3434,6 +3529,14 @@ async function startServer() {
3434
3529
  inputSchema: DeleteEmailInputSchema,
3435
3530
  annotations: DESTRUCTIVE_ANNOTATIONS,
3436
3531
  handler: deleteEmailTool
3532
+ },
3533
+ {
3534
+ name: "gmcp_gmail_archive_email",
3535
+ title: "Archive Gmail Email",
3536
+ description: ARCHIVE_EMAIL_DESCRIPTION,
3537
+ inputSchema: ArchiveEmailInputSchema,
3538
+ annotations: MODIFY_ANNOTATIONS,
3539
+ handler: archiveEmailTool
3437
3540
  }
3438
3541
  ];
3439
3542
  const calendarTools = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gmcp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "GMCP Server for Google Workspace with OAuth2 authentication",
5
5
  "module": "src/index.ts",
6
6
  "main": "dist/index.js",