gmcp 0.3.0 → 0.4.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 +3 -2
  2. package/dist/index.js +190 -93
  3. package/package.json +6 -6
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 (15 tools)
151
+ ### Gmail (16 tools)
152
152
 
153
153
  | Tool | Description |
154
154
  |------|-------------|
@@ -160,6 +160,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
160
160
  | `gmcp_gmail_send_email` | Send new email |
161
161
  | `gmcp_gmail_reply` | Reply to email in thread |
162
162
  | `gmcp_gmail_create_draft` | Create draft message |
163
+ | `gmcp_gmail_delete_email` | Permanently delete email (bypasses trash) |
163
164
  | `gmcp_gmail_list_labels` | List all labels |
164
165
  | `gmcp_gmail_get_label` | Get label details |
165
166
  | `gmcp_gmail_create_label` | Create custom label |
@@ -193,7 +194,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
193
194
  |-------|--------|
194
195
  | `gmail.readonly` | Read emails and labels |
195
196
  | `gmail.send` | Send emails |
196
- | `gmail.modify` | Read, modify labels |
197
+ | `gmail.modify` | Read, modify labels, delete emails |
197
198
  | `gmail.labels` | Manage labels |
198
199
  | `gmail.compose` | Create drafts and send |
199
200
  | `calendar.readonly` | Read calendars and events |
package/dist/index.js CHANGED
@@ -647,6 +647,16 @@ function createGmailClient(auth, logger) {
647
647
  } catch (error) {
648
648
  throw new Error(`Failed to delete label ${labelId}: ${error}`);
649
649
  }
650
+ },
651
+ async deleteEmail(messageId) {
652
+ try {
653
+ await gmail.users.messages.delete({
654
+ userId: "me",
655
+ id: messageId
656
+ });
657
+ } catch (error) {
658
+ throw new Error(`Failed to delete message ${messageId}: ${error}`);
659
+ }
650
660
  }
651
661
  };
652
662
  }
@@ -1760,9 +1770,88 @@ This tool creates a new label with customizable visibility and color settings. L
1760
1770
  **Scope Requirements**:
1761
1771
  - Requires \`gmail.labels\` or \`gmail.modify\` scope`;
1762
1772
 
1763
- // src/tools/delete-label.ts
1773
+ // src/tools/delete-email.ts
1764
1774
  import json2md5 from "json2md";
1765
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")
1779
+ });
1780
+ function deletionToMarkdown(messageId) {
1781
+ const sections = [
1782
+ { h1: "Email Deleted Successfully" },
1783
+ {
1784
+ p: `Message with ID **${messageId}** has been permanently deleted from your Gmail account.`
1785
+ },
1786
+ { h2: "Important Notes" },
1787
+ {
1788
+ ul: [
1789
+ "The email has been permanently deleted (not moved to trash)",
1790
+ "This action cannot be undone",
1791
+ "The email cannot be recovered"
1792
+ ]
1793
+ }
1794
+ ];
1795
+ return json2md5(sections);
1796
+ }
1797
+ async function deleteEmailTool(gmailClient, params) {
1798
+ try {
1799
+ await gmailClient.deleteEmail(params.message_id);
1800
+ const output = {
1801
+ message_id: params.message_id,
1802
+ deleted: true,
1803
+ message: "Email permanently deleted. This action cannot be undone."
1804
+ };
1805
+ const textContent = params.output_format === "json" ? JSON.stringify(output, null, 2) : deletionToMarkdown(params.message_id);
1806
+ return {
1807
+ content: [{ type: "text", text: textContent }],
1808
+ structuredContent: output
1809
+ };
1810
+ } catch (error) {
1811
+ return createErrorResponse("deleting email", error);
1812
+ }
1813
+ }
1814
+ var DELETE_EMAIL_DESCRIPTION = `Permanently delete a Gmail email message.
1815
+
1816
+ **WARNING: This is a destructive operation that CANNOT be undone. The email is permanently deleted and bypasses the trash folder.**
1817
+
1818
+ This tool permanently deletes an email message from your Gmail account. Unlike moving to trash, this operation immediately and permanently removes the email.
1819
+
1820
+ **Parameters**:
1821
+ - \`message_id\` (string, required): The Gmail message ID to delete
1822
+ - \`output_format\` (string, optional): Output format: "markdown" (default) or "json"
1823
+
1824
+ **Returns**:
1825
+ - \`message_id\`: The deleted message ID
1826
+ - \`deleted\`: Always true on success
1827
+ - \`message\`: Confirmation message
1828
+
1829
+ **Examples**:
1830
+ - Delete email: \`{ "message_id": "18f3c5d4e8a2b1c0" }\`
1831
+ - Delete with JSON output: \`{ "message_id": "18f3c5d4e8a2b1c0", "output_format": "json" }\`
1832
+
1833
+ **Safety Considerations**:
1834
+ - This is a destructive operation marked with \`destructiveHint: true\`
1835
+ - The email is permanently deleted, not moved to trash
1836
+ - This action cannot be undone - the email cannot be recovered
1837
+ - Consider using \`modify_labels\` with \`add_labels: ["TRASH"]\` if you want recoverable deletion
1838
+ - Use \`get_email\` first to verify which email you're deleting
1839
+
1840
+ **Use Cases**:
1841
+ - Permanently remove sensitive emails
1842
+ - Clean up emails that should not be recoverable
1843
+ - Remove emails that are already in trash permanently
1844
+
1845
+ **Error Handling**:
1846
+ - Returns error if message ID doesn't exist
1847
+ - Returns error if authentication lacks sufficient permissions
1848
+
1849
+ **Scope Requirements**:
1850
+ - Requires \`gmail.modify\` or full \`mail.google.com\` scope`;
1851
+
1852
+ // src/tools/delete-label.ts
1853
+ import json2md6 from "json2md";
1854
+ import { z as z9 } from "zod";
1766
1855
  var SYSTEM_LABELS = [
1767
1856
  "INBOX",
1768
1857
  "SENT",
@@ -1778,11 +1867,11 @@ var SYSTEM_LABELS = [
1778
1867
  "CATEGORY_UPDATES",
1779
1868
  "CATEGORY_FORUMS"
1780
1869
  ];
1781
- var DeleteLabelInputSchema = z8.object({
1782
- label_id: z8.string().min(1, "Label ID cannot be empty").describe("The label ID to delete (e.g., 'Label_123'). Cannot delete system labels."),
1783
- output_format: z8.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
1784
1873
  });
1785
- function deletionToMarkdown(labelId) {
1874
+ function deletionToMarkdown2(labelId) {
1786
1875
  const sections = [
1787
1876
  { h1: "Label Deleted Successfully" },
1788
1877
  {
@@ -1798,7 +1887,7 @@ function deletionToMarkdown(labelId) {
1798
1887
  ]
1799
1888
  }
1800
1889
  ];
1801
- return json2md5(sections);
1890
+ return json2md6(sections);
1802
1891
  }
1803
1892
  async function deleteLabelTool(gmailClient, params) {
1804
1893
  try {
@@ -1830,7 +1919,7 @@ async function deleteLabelTool(gmailClient, params) {
1830
1919
  deleted: true,
1831
1920
  message: "Label deleted successfully. The label has been removed from all messages."
1832
1921
  };
1833
- const textContent = params.output_format === "json" ? JSON.stringify(output, null, 2) : deletionToMarkdown(params.label_id);
1922
+ const textContent = params.output_format === "json" ? JSON.stringify(output, null, 2) : deletionToMarkdown2(params.label_id);
1834
1923
  return {
1835
1924
  content: [{ type: "text", text: textContent }],
1836
1925
  structuredContent: output
@@ -1920,11 +2009,11 @@ This tool permanently deletes a user-created label from your Gmail account. Syst
1920
2009
  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.`;
1921
2010
 
1922
2011
  // src/tools/get-attachment.ts
1923
- import { z as z9 } from "zod";
1924
- var GetAttachmentInputSchema = z9.object({
1925
- message_id: z9.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID containing the attachment"),
1926
- attachment_id: z9.string().min(1, "Attachment ID cannot be empty").describe("The attachment ID to download (from list_attachments)"),
1927
- output_format: z9.enum(["base64", "json"]).default("base64").describe("Output format: base64 (default, returns raw base64url string) or json (returns structured object)")
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)")
1928
2017
  });
1929
2018
  async function getAttachmentTool(gmailClient, params) {
1930
2019
  try {
@@ -1991,12 +2080,12 @@ To decode:
1991
2080
  3. Decode base64url data to get original file content`;
1992
2081
 
1993
2082
  // src/tools/get-email.ts
1994
- import json2md6 from "json2md";
1995
- import { z as z10 } from "zod";
1996
- var GetEmailInputSchema = z10.object({
1997
- message_id: z10.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to retrieve"),
1998
- include_body: z10.boolean().default(true).describe("Whether to include full email body in results (default: true)"),
1999
- output_format: z10.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2000
2089
  });
2001
2090
  function emailToMarkdown(email) {
2002
2091
  const sections = [
@@ -2023,7 +2112,7 @@ function emailToMarkdown(email) {
2023
2112
  sections.push({ h2: "Snippet" });
2024
2113
  sections.push({ p: email.snippet });
2025
2114
  }
2026
- return json2md6(sections);
2115
+ return json2md7(sections);
2027
2116
  }
2028
2117
  async function getEmailTool(gmailClient, params) {
2029
2118
  try {
@@ -2074,11 +2163,11 @@ This tool retrieves a specific email message from Gmail using its unique message
2074
2163
  - Retrieve email for further processing or analysis`;
2075
2164
 
2076
2165
  // src/tools/get-label.ts
2077
- import json2md7 from "json2md";
2078
- import { z as z11 } from "zod";
2079
- var GetLabelInputSchema = z11.object({
2080
- label_id: z11.string().min(1, "Label ID cannot be empty").describe("The label ID to retrieve (e.g., 'INBOX', 'Label_123')"),
2081
- output_format: z11.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2082
2171
  });
2083
2172
  function labelToMarkdown(label) {
2084
2173
  const sections = [
@@ -2113,7 +2202,7 @@ function labelToMarkdown(label) {
2113
2202
  ]
2114
2203
  });
2115
2204
  }
2116
- return json2md7(sections);
2205
+ return json2md8(sections);
2117
2206
  }
2118
2207
  async function getLabelTool(gmailClient, params) {
2119
2208
  try {
@@ -2180,12 +2269,12 @@ This tool retrieves comprehensive details about a label, including its name, typ
2180
2269
  - System labels and custom labels are both supported`;
2181
2270
 
2182
2271
  // src/tools/get-thread.ts
2183
- import json2md8 from "json2md";
2184
- import { z as z12 } from "zod";
2185
- var GetThreadInputSchema = z12.object({
2186
- thread_id: z12.string().min(1, "Thread ID cannot be empty").describe("The Gmail thread ID to retrieve"),
2187
- include_body: z12.boolean().default(false).describe("Whether to include full email body for all messages (default: false)"),
2188
- output_format: z12.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2189
2278
  });
2190
2279
  function threadToMarkdown(threadId, messages) {
2191
2280
  const sections = [
@@ -2220,7 +2309,7 @@ function threadToMarkdown(threadId, messages) {
2220
2309
  sections.push({ p: "---" });
2221
2310
  }
2222
2311
  }
2223
- return json2md8(sections);
2312
+ return json2md9(sections);
2224
2313
  }
2225
2314
  async function getThreadTool(gmailClient, params) {
2226
2315
  try {
@@ -2278,11 +2367,11 @@ This tool retrieves all messages in a Gmail conversation thread (email chain). T
2278
2367
  - Extract all messages from a discussion thread`;
2279
2368
 
2280
2369
  // src/tools/list-attachments.ts
2281
- import json2md9 from "json2md";
2282
- import { z as z13 } from "zod";
2283
- var ListAttachmentsInputSchema = z13.object({
2284
- message_id: z13.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to list attachments from"),
2285
- output_format: z13.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2286
2375
  });
2287
2376
  function formatBytes(bytes) {
2288
2377
  if (bytes === 0) {
@@ -2314,7 +2403,7 @@ function attachmentsToMarkdown(messageId, attachments) {
2314
2403
  });
2315
2404
  }
2316
2405
  }
2317
- return json2md9(sections);
2406
+ return json2md10(sections);
2318
2407
  }
2319
2408
  async function listAttachmentsTool(gmailClient, params) {
2320
2409
  try {
@@ -2372,10 +2461,10 @@ This tool retrieves metadata about all attachments in a specific email message,
2372
2461
  - List attachment IDs for use with get_attachment tool`;
2373
2462
 
2374
2463
  // src/tools/list-labels.ts
2375
- import json2md10 from "json2md";
2376
- import { z as z14 } from "zod";
2377
- var ListLabelsInputSchema = z14.object({
2378
- output_format: z14.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2379
2468
  });
2380
2469
  function labelsToMarkdown(labels) {
2381
2470
  const sections = [{ h1: "Gmail Labels" }];
@@ -2392,7 +2481,7 @@ function labelsToMarkdown(labels) {
2392
2481
  if (labels.system.length === 0 && labels.user.length === 0) {
2393
2482
  sections.push({ p: "*No labels found*" });
2394
2483
  }
2395
- return json2md10(sections);
2484
+ return json2md11(sections);
2396
2485
  }
2397
2486
  async function listLabelsTool(gmailClient, params) {
2398
2487
  try {
@@ -2465,13 +2554,13 @@ Custom labels are created by users for organizing emails. They have IDs like \`L
2465
2554
  - Returns error if Gmail API is unreachable`;
2466
2555
 
2467
2556
  // src/tools/modify-labels.ts
2468
- import json2md11 from "json2md";
2469
- import { z as z15 } from "zod";
2470
- var ModifyLabelsInputSchema = z15.object({
2471
- message_id: z15.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to modify labels for"),
2472
- add_labels: z15.array(z15.string()).optional().describe("Label IDs to add (e.g., ['STARRED', 'INBOX', 'UNREAD'] or custom label IDs)"),
2473
- remove_labels: z15.array(z15.string()).optional().describe("Label IDs to remove (e.g., ['UNREAD', 'INBOX'] to mark read and archive)"),
2474
- output_format: z15.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2475
2564
  });
2476
2565
  function labelModificationToMarkdown(email, addedLabels, removedLabels) {
2477
2566
  const sections = [
@@ -2497,7 +2586,7 @@ function labelModificationToMarkdown(email, addedLabels, removedLabels) {
2497
2586
  sections.push({
2498
2587
  p: email.labels.length > 0 ? email.labels.join(", ") : "*No labels on this message*"
2499
2588
  });
2500
- return json2md11(sections);
2589
+ return json2md12(sections);
2501
2590
  }
2502
2591
  async function modifyLabelsTool(gmailClient, params) {
2503
2592
  try {
@@ -2588,15 +2677,15 @@ This tool allows you to add or remove labels from a Gmail message. Labels are us
2588
2677
  - Move messages to trash or spam`;
2589
2678
 
2590
2679
  // src/tools/reply.ts
2591
- import json2md12 from "json2md";
2592
- import { z as z16 } from "zod";
2593
- var ReplyInputSchema = z16.object({
2594
- message_id: z16.string().min(1, "Message ID cannot be empty").describe("The Gmail message ID to reply to"),
2595
- body: z16.string().min(1, "Reply body cannot be empty").describe("Reply message body"),
2596
- content_type: z16.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML replies"),
2597
- cc: z16.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
2598
- confirm: z16.boolean().default(false).describe("Set to true to confirm and send the reply. If false, returns preview only."),
2599
- output_format: z16.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2600
2689
  });
2601
2690
  function replyPreviewToMarkdown(originalEmail, replyBody, contentType, cc) {
2602
2691
  const sections = [
@@ -2624,7 +2713,7 @@ function replyPreviewToMarkdown(originalEmail, replyBody, contentType, cc) {
2624
2713
  { h2: "Reply Body" },
2625
2714
  { p: replyBody }
2626
2715
  ];
2627
- return json2md12(sections);
2716
+ return json2md13(sections);
2628
2717
  }
2629
2718
  function replySentToMarkdown(originalEmail, result, cc) {
2630
2719
  const sections = [
@@ -2643,7 +2732,7 @@ function replySentToMarkdown(originalEmail, result, cc) {
2643
2732
  p: "Your reply has been sent and added to the conversation thread."
2644
2733
  }
2645
2734
  ];
2646
- return json2md12(sections);
2735
+ return json2md13(sections);
2647
2736
  }
2648
2737
  async function replyTool(gmailClient, params) {
2649
2738
  try {
@@ -2767,13 +2856,13 @@ This tool sends a reply to an existing email, automatically threading it in the
2767
2856
  4. Call with \`confirm: true\` to send`;
2768
2857
 
2769
2858
  // src/tools/search.ts
2770
- import { z as z17 } from "zod";
2771
- var SearchEmailsInputSchema = z17.object({
2772
- query: z17.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")'),
2773
- max_results: z17.number().int().min(1).max(100).default(10).describe("Maximum number of emails to return (default: 10, max: 100)"),
2774
- include_body: z17.boolean().default(false).describe("Whether to include full email body in results (default: false)"),
2775
- page_token: z17.string().optional().describe("Token for pagination to fetch next page of results"),
2776
- output_format: z17.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2777
2866
  });
2778
2867
  async function searchEmailsTool(gmailClient, params) {
2779
2868
  try {
@@ -2843,17 +2932,17 @@ This tool allows you to search through your Gmail messages using the same query
2843
2932
  - Empty results if no emails match the query`;
2844
2933
 
2845
2934
  // src/tools/send-email.ts
2846
- import json2md13 from "json2md";
2847
- import { z as z18 } from "zod";
2848
- var SendEmailInputSchema = z18.object({
2849
- to: z18.email("Must be a valid email address").describe("Recipient email address"),
2850
- subject: z18.string().min(1, "Subject cannot be empty").describe("Email subject"),
2851
- body: z18.string().min(1, "Body cannot be empty").describe("Email body content"),
2852
- content_type: z18.enum(["text/plain", "text/html"]).default("text/plain").describe("Content type: text/plain (default) or text/html for HTML emails"),
2853
- cc: z18.email("CC must be a valid email address").optional().describe("CC (carbon copy) email address"),
2854
- bcc: z18.email("BCC must be a valid email address").optional().describe("BCC (blind carbon copy) email address"),
2855
- confirm: z18.boolean().default(false).describe("Set to true to confirm and send the email. If false, returns preview only."),
2856
- output_format: z18.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
2857
2946
  });
2858
2947
  function emailPreviewToMarkdown(params) {
2859
2948
  const sections = [
@@ -2874,7 +2963,7 @@ function emailPreviewToMarkdown(params) {
2874
2963
  { h2: "Body" },
2875
2964
  { p: params.body }
2876
2965
  ];
2877
- return json2md13(sections);
2966
+ return json2md14(sections);
2878
2967
  }
2879
2968
  function emailSentToMarkdown(params, result) {
2880
2969
  const sections = [
@@ -2894,7 +2983,7 @@ function emailSentToMarkdown(params, result) {
2894
2983
  p: "The email has been sent and will appear in your Sent folder."
2895
2984
  }
2896
2985
  ];
2897
- return json2md13(sections);
2986
+ return json2md14(sections);
2898
2987
  }
2899
2988
  async function sendEmailTool(gmailClient, params) {
2900
2989
  try {
@@ -3000,8 +3089,8 @@ This tool sends email through your Gmail account. It includes a safety feature:
3000
3089
  3. Call again with \`confirm: true\` to send`;
3001
3090
 
3002
3091
  // src/tools/update-label.ts
3003
- import json2md14 from "json2md";
3004
- import { z as z19 } from "zod";
3092
+ import json2md15 from "json2md";
3093
+ import { z as z20 } from "zod";
3005
3094
  var SYSTEM_LABELS2 = [
3006
3095
  "INBOX",
3007
3096
  "SENT",
@@ -3012,14 +3101,14 @@ var SYSTEM_LABELS2 = [
3012
3101
  "IMPORTANT",
3013
3102
  "UNREAD"
3014
3103
  ];
3015
- var UpdateLabelInputSchema = z19.object({
3016
- label_id: z19.string().min(1, "Label ID cannot be empty").describe("The label ID to update (e.g., 'Label_123' or 'INBOX')"),
3017
- name: z19.string().optional().describe("New label name. Cannot rename system labels. Use '/' for nested labels."),
3018
- message_list_visibility: z19.enum(["show", "hide"]).optional().describe("How label appears in message list"),
3019
- label_list_visibility: z19.enum(["labelShow", "labelShowIfUnread", "labelHide"]).optional().describe("How label appears in label list (sidebar)"),
3020
- background_color: z19.string().optional().describe("Background color in hex format (e.g., '#ff0000'). Must provide both background and text color together."),
3021
- text_color: z19.string().optional().describe("Text color in hex format (e.g., '#ffffff'). Must provide both background and text color together."),
3022
- output_format: z19.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (default) or json")
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")
3023
3112
  });
3024
3113
  function updatedLabelToMarkdown(label, updates) {
3025
3114
  const sections = [
@@ -3067,7 +3156,7 @@ function updatedLabelToMarkdown(label, updates) {
3067
3156
  ]
3068
3157
  });
3069
3158
  }
3070
- return json2md14(sections);
3159
+ return json2md15(sections);
3071
3160
  }
3072
3161
  async function updateLabelTool(gmailClient, params) {
3073
3162
  try {
@@ -3337,6 +3426,14 @@ async function startServer() {
3337
3426
  inputSchema: DeleteLabelInputSchema,
3338
3427
  annotations: DESTRUCTIVE_ANNOTATIONS,
3339
3428
  handler: deleteLabelTool
3429
+ },
3430
+ {
3431
+ name: "gmcp_gmail_delete_email",
3432
+ title: "Delete Gmail Email",
3433
+ description: DELETE_EMAIL_DESCRIPTION,
3434
+ inputSchema: DeleteEmailInputSchema,
3435
+ annotations: DESTRUCTIVE_ANNOTATIONS,
3436
+ handler: deleteEmailTool
3340
3437
  }
3341
3438
  ];
3342
3439
  const calendarTools = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gmcp",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "GMCP Server for Google Workspace with OAuth2 authentication",
5
5
  "module": "src/index.ts",
6
6
  "main": "dist/index.js",
@@ -50,19 +50,19 @@
50
50
  "googleapis": "^170.1.0",
51
51
  "json2md": "^2.0.3",
52
52
  "kleur": "^4.1.5",
53
- "pino": "^9.7.0",
54
- "pino-pretty": "^13.0.0",
53
+ "pino": "^10.3.0",
54
+ "pino-pretty": "^13.1.3",
55
55
  "zod": "^4.3.6"
56
56
  },
57
57
  "devDependencies": {
58
- "@biomejs/biome": "2.3.12",
58
+ "@biomejs/biome": "2.3.13",
59
59
  "@changesets/changelog-github": "^0.5.2",
60
60
  "@changesets/cli": "^2.29.8",
61
61
  "@types/bun": "latest",
62
62
  "@types/json2md": "^1.5.4",
63
63
  "bunup": "^0.16.20",
64
- "lefthook": "^2.0.15",
65
- "ultracite": "7.0.12",
64
+ "lefthook": "^2.0.16",
65
+ "ultracite": "7.1.1",
66
66
  "vitest": "^4.0.18"
67
67
  },
68
68
  "peerDependencies": {