gogcli-mcp-gmail 2.0.12 → 2.3.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ ## [2.1.0](https://github.com/chrischall/gogcli-mcp/compare/v2.0.13...v2.1.0) (2026-05-25)
4
+
5
+
6
+ ### Features
7
+
8
+ * **gmail:** add gogcli-mcp-gmail sub-package ([fac0f51](https://github.com/chrischall/gogcli-mcp/commit/fac0f515fd2ea587c570d7ac70c080cb8dc486ac))
9
+
10
+
11
+ ### Refactor
12
+
13
+ * aggressive cleanup pass (audit findings) ([e635b39](https://github.com/chrischall/gogcli-mcp/commit/e635b391cf611e9c102a422ffbce5ebe28687b80))
14
+ * review-pass cleanup (enums, shared schemas, test harness) ([ea851de](https://github.com/chrischall/gogcli-mcp/commit/ea851deb30b9cfef3f07ed506a011fc363b34018))
15
+
16
+
17
+ ### Documentation
18
+
19
+ * update gogcli repo URLs to openclaw/gogcli (was steipete/gogcli) ([951a181](https://github.com/chrischall/gogcli-mcp/commit/951a1818ebc269f203aee723ccbea32c13817d8b))
package/dist/index.js CHANGED
@@ -31074,7 +31074,7 @@ async function run(args, options = {}) {
31074
31074
 
31075
31075
  // ../gogcli-mcp/src/tools/utils.ts
31076
31076
  var accountParam = external_exports.string().optional().describe(
31077
- "Google account email to use (overrides GOG_ACCOUNT env var)"
31077
+ "Google account email to use, e.g. you@gmail.com \u2014 must be the full address, not a bare username. Overrides the GOG_ACCOUNT env var. Omit to use the single configured account."
31078
31078
  );
31079
31079
  var ids = {
31080
31080
  course: external_exports.string().describe("Course ID"),
@@ -31133,26 +31133,41 @@ function toError(err) {
31133
31133
  }
31134
31134
  var AUTH_ERROR_PATTERN = /\b(401|unauthorized|token.*(expired|revoked)|invalid_grant)\b/i;
31135
31135
  var TRANSIENT_ERROR_PATTERN = /\b429\b|\b5\d\d\b|\bquota\b|rateLimit|\bDEADLINE_EXCEEDED\b/i;
31136
+ var GRID_LIMIT_ERROR_PATTERN = /exceeds grid limits/i;
31136
31137
  var AUTH_HINT = "\n\nAuthentication may have expired. Use gog_auth_add to re-authorize the account. Ask the user if they would like to re-authenticate.";
31137
31138
  var TRANSIENT_HINT = "\n\nThis error is often transient. Retry the same call before trying a different approach (do not fall back to smaller writes or row-by-row operations).";
31139
+ var GRID_LIMIT_HINT = "\n\nThe target range is outside the sheet's current grid. Add the missing rows or columns first with gog_sheets_insert (dimension: rows or cols), then retry the write.";
31140
+ function formatAccountList(raw) {
31141
+ try {
31142
+ const parsed = JSON.parse(raw);
31143
+ if (Array.isArray(parsed?.accounts)) {
31144
+ return parsed.accounts.map((a) => a?.email).filter(Boolean).join("\n");
31145
+ }
31146
+ } catch {
31147
+ }
31148
+ return raw.trim();
31149
+ }
31150
+ async function diagnose(err) {
31151
+ const errText = toError(err).content[0].text;
31152
+ const isAuthError = AUTH_ERROR_PATTERN.test(errText);
31153
+ const isTransientError = !isAuthError && TRANSIENT_ERROR_PATTERN.test(errText);
31154
+ const isGridLimitError = GRID_LIMIT_ERROR_PATTERN.test(errText);
31155
+ const hint = isAuthError ? AUTH_HINT : isTransientError ? TRANSIENT_HINT : isGridLimitError ? GRID_LIMIT_HINT : "";
31156
+ try {
31157
+ const accounts = formatAccountList(await run(["auth", "list"]));
31158
+ return toText(`${errText}
31159
+
31160
+ Configured accounts:
31161
+ ${accounts || "(none)"}${hint}`);
31162
+ } catch {
31163
+ return toText(`${errText}${hint}`);
31164
+ }
31165
+ }
31138
31166
  async function runOrDiagnose(args, options) {
31139
31167
  try {
31140
31168
  return toText(await run(args, options));
31141
31169
  } catch (err) {
31142
- const base = toError(err);
31143
- const errText = base.content[0].text;
31144
- const isAuthError = AUTH_ERROR_PATTERN.test(errText);
31145
- const isTransientError = !isAuthError && TRANSIENT_ERROR_PATTERN.test(errText);
31146
- const hint = isAuthError ? AUTH_HINT : isTransientError ? TRANSIENT_HINT : "";
31147
- try {
31148
- const accounts = await run(["auth", "list"]);
31149
- return toText(`${errText}
31150
-
31151
- Configured accounts:
31152
- ${accounts}${hint}`);
31153
- } catch {
31154
- return toText(`${errText}${hint}`);
31155
- }
31170
+ return diagnose(err);
31156
31171
  }
31157
31172
  }
31158
31173
 
@@ -31221,7 +31236,7 @@ function registerAuthTools(server2) {
31221
31236
  // ../gogcli-mcp/src/tools/gmail.ts
31222
31237
  function registerGmailTools(server2) {
31223
31238
  server2.registerTool("gog_gmail_search", {
31224
- description: 'Search Gmail threads using Gmail query syntax (e.g. "from:alice subject:invoice is:unread").',
31239
+ description: `Search Gmail threads using Gmail query syntax (e.g. "from:alice subject:invoice is:unread"). The query is passed verbatim to Gmail; a bare name token (from:alison) matches per Gmail's own heuristics, a full address (from:alison@example.com) is exact. To match a contact across several addresses, OR them: from:(a@x.com OR b@y.com).`,
31225
31240
  annotations: { readOnlyHint: true },
31226
31241
  inputSchema: {
31227
31242
  query: external_exports.string().describe("Gmail search query"),
@@ -31272,9 +31287,15 @@ function registerGmailTools(server2) {
31272
31287
 
31273
31288
  // ../gogcli-mcp/src/tools/sheets.ts
31274
31289
  var cellValueParam = external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]);
31290
+ var dryRunParam = external_exports.boolean().optional().describe(
31291
+ "Preview the operation without modifying the sheet (gog --dry-run): reports the intended actions and exits without writing."
31292
+ );
31293
+ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
31294
+ 'Safety guard against silent overwrites: before writing, read the target range and refuse the write if any target cell already holds data. Costs one extra read. Anchor ranges (e.g. "Sheet1!A1") are expanded to the full area your values will cover; explicit and named ranges are checked as-is.'
31295
+ );
31275
31296
 
31276
31297
  // ../gogcli-mcp/src/server.ts
31277
- var VERSION = true ? "2.0.12" : "0.0.0";
31298
+ var VERSION = true ? "2.3.0" : "0.0.0";
31278
31299
  function createServer(options) {
31279
31300
  return new McpServer({
31280
31301
  name: options?.name ?? "gogcli",
@@ -31283,6 +31304,37 @@ function createServer(options) {
31283
31304
  }
31284
31305
 
31285
31306
  // src/tools/gmail-extra.ts
31307
+ var SNIPPET_HEADERS = ["From", "To", "Cc", "Subject", "Date"];
31308
+ function summarizeMessage(m) {
31309
+ const rawHeaders = m.payload?.headers;
31310
+ const headers = {};
31311
+ if (Array.isArray(rawHeaders)) {
31312
+ for (const h of rawHeaders) {
31313
+ if (h.name && SNIPPET_HEADERS.includes(h.name)) headers[h.name] = h.value;
31314
+ }
31315
+ }
31316
+ return {
31317
+ id: m.id,
31318
+ threadId: m.threadId,
31319
+ internalDate: m.internalDate,
31320
+ labelIds: m.labelIds,
31321
+ snippet: m.snippet,
31322
+ headers
31323
+ };
31324
+ }
31325
+ function trimThread(result, latestN, snippetsOnly) {
31326
+ try {
31327
+ const parsed = JSON.parse(result.content[0].text);
31328
+ const messages = parsed.thread?.messages;
31329
+ if (!Array.isArray(messages)) return result;
31330
+ let trimmed = messages;
31331
+ if (latestN !== void 0) trimmed = trimmed.slice(-latestN);
31332
+ if (snippetsOnly) trimmed = trimmed.map((m) => summarizeMessage(m));
31333
+ return toText(JSON.stringify({ ...parsed, thread: { ...parsed.thread, messages: trimmed } }));
31334
+ } catch {
31335
+ return result;
31336
+ }
31337
+ }
31286
31338
  function registerExtraGmailTools(server2) {
31287
31339
  server2.registerTool("gog_gmail_raw", {
31288
31340
  description: "Dump the raw Gmail API response as JSON (lossless; for scripting and LLM consumption).",
@@ -31424,23 +31476,27 @@ function registerExtraGmailTools(server2) {
31424
31476
  return runOrDiagnose(args, { account });
31425
31477
  });
31426
31478
  server2.registerTool("gog_gmail_thread_get", {
31427
- description: "Get a Gmail thread with all messages, optionally downloading attachments and sanitizing content for agent consumption.",
31479
+ description: "Get a Gmail thread with all messages. For long threads that overflow context, use latestN to fetch only the most recent messages and/or snippetsOnly for a lightweight per-message headers+snippet view; sanitizeContent strips raw payloads/HTML and is the biggest size reducer when you do need bodies.",
31428
31480
  annotations: { readOnlyHint: true },
31429
31481
  inputSchema: {
31430
31482
  threadId: external_exports.string().describe("Gmail thread ID"),
31431
31483
  download: external_exports.boolean().optional().describe("Download all attachments"),
31432
31484
  full: external_exports.boolean().optional().describe("Show full message bodies"),
31433
- sanitizeContent: external_exports.boolean().optional().describe("Strip HTML, remove URLs, omit raw payloads from JSON"),
31485
+ sanitizeContent: external_exports.boolean().optional().describe("Strip HTML, remove URLs, omit raw payloads from JSON (largest payload-size reduction)"),
31486
+ latestN: external_exports.number().int().positive().optional().describe("Return only the most recent N messages in the thread (wrapper-side trim; avoids overflowing context on long threads)"),
31487
+ snippetsOnly: external_exports.boolean().optional().describe("Reduce each message to its id, labels, snippet, and key headers (From/To/Cc/Subject/Date), dropping full bodies"),
31434
31488
  outDir: external_exports.string().optional().describe("Directory to write attachments to (default: current directory)"),
31435
31489
  account: accountParam
31436
31490
  }
31437
- }, async ({ threadId, download, full, sanitizeContent, outDir, account }) => {
31491
+ }, async ({ threadId, download, full, sanitizeContent, latestN, snippetsOnly, outDir, account }) => {
31438
31492
  const args = ["gmail", "thread", "get", threadId];
31439
31493
  if (download) args.push("--download");
31440
31494
  if (full) args.push("--full");
31441
31495
  if (sanitizeContent) args.push("--sanitize-content");
31442
31496
  if (outDir) args.push(`--out-dir=${outDir}`);
31443
- return runOrDiagnose(args, { account });
31497
+ const result = await runOrDiagnose(args, { account });
31498
+ if (latestN === void 0 && !snippetsOnly) return result;
31499
+ return trimThread(result, latestN, snippetsOnly);
31444
31500
  });
31445
31501
  server2.registerTool("gog_gmail_thread_modify", {
31446
31502
  description: "Modify labels on all messages in a thread (add and/or remove labels).",
@@ -31577,12 +31633,16 @@ function registerExtraGmailTools(server2) {
31577
31633
  quote: external_exports.boolean().optional().describe("Include quoted original message in reply (requires replyToMessageId)"),
31578
31634
  attach: external_exports.array(external_exports.string()).optional().describe("Attachment file paths (repeatable)"),
31579
31635
  from: external_exports.string().optional().describe("Send from this email address (must be a verified send-as alias)"),
31636
+ omitRecipients: external_exports.boolean().optional().describe("Create the draft with no recipients even if to/cc/bcc are supplied \u2014 an accidental-send guard. Populate recipients in a later update before sending."),
31637
+ returnFull: external_exports.boolean().optional().describe("After writing, re-fetch and return the full stored draft (subject, body, recipients) instead of just the write acknowledgement. Costs one extra read."),
31580
31638
  account: accountParam
31581
31639
  };
31582
31640
  function appendDraftFlags(args, f) {
31583
- if (f.to) args.push(`--to=${f.to}`);
31584
- if (f.cc) args.push(`--cc=${f.cc}`);
31585
- if (f.bcc) args.push(`--bcc=${f.bcc}`);
31641
+ if (!f.omitRecipients) {
31642
+ if (f.to) args.push(`--to=${f.to}`);
31643
+ if (f.cc) args.push(`--cc=${f.cc}`);
31644
+ if (f.bcc) args.push(`--bcc=${f.bcc}`);
31645
+ }
31586
31646
  args.push(`--subject=${f.subject}`);
31587
31647
  args.push(`--body=${f.body}`);
31588
31648
  if (f.bodyHtml) args.push(`--body-html=${f.bodyHtml}`);
@@ -31592,13 +31652,26 @@ function registerExtraGmailTools(server2) {
31592
31652
  if (f.attach) for (const path of f.attach) args.push(`--attach=${path}`);
31593
31653
  if (f.from) args.push(`--from=${f.from}`);
31594
31654
  }
31655
+ async function writeDraft(args, account, returnFull, knownDraftId) {
31656
+ const result = await runOrDiagnose(args, { account });
31657
+ if (!returnFull) return result;
31658
+ let parsed;
31659
+ try {
31660
+ parsed = JSON.parse(result.content[0].text);
31661
+ } catch {
31662
+ return result;
31663
+ }
31664
+ const draftId = knownDraftId ?? parsed.draftId;
31665
+ if (!draftId) return result;
31666
+ return runOrDiagnose(["gmail", "drafts", "get", draftId], { account });
31667
+ }
31595
31668
  server2.registerTool("gog_gmail_drafts_create", {
31596
- description: "Create a new Gmail draft.",
31669
+ description: "Create a new Gmail draft. Recipients (to/cc/bcc) are optional; omit them (or set omitRecipients) to create a recipient-less draft as an accidental-send guard.",
31597
31670
  inputSchema: draftWriteSchema
31598
- }, async ({ account, ...flags }) => {
31671
+ }, async ({ account, returnFull, ...flags }) => {
31599
31672
  const args = ["gmail", "drafts", "create"];
31600
31673
  appendDraftFlags(args, flags);
31601
- return runOrDiagnose(args, { account });
31674
+ return writeDraft(args, account, returnFull);
31602
31675
  });
31603
31676
  server2.registerTool("gog_gmail_drafts_update", {
31604
31677
  description: "Update an existing Gmail draft.",
@@ -31607,20 +31680,23 @@ function registerExtraGmailTools(server2) {
31607
31680
  draftId: external_exports.string().describe("Draft ID"),
31608
31681
  ...draftWriteSchema
31609
31682
  }
31610
- }, async ({ draftId, account, ...flags }) => {
31683
+ }, async ({ draftId, account, returnFull, ...flags }) => {
31611
31684
  const args = ["gmail", "drafts", "update", draftId];
31612
31685
  appendDraftFlags(args, flags);
31613
- return runOrDiagnose(args, { account });
31686
+ return writeDraft(args, account, returnFull, draftId);
31614
31687
  });
31615
31688
  server2.registerTool("gog_gmail_drafts_delete", {
31616
- description: "Delete a Gmail draft.",
31689
+ description: "Permanently delete a Gmail draft (not reversible \u2014 drafts do not go to Trash). Requires force:true to delete non-interactively.",
31617
31690
  annotations: { destructiveHint: true },
31618
31691
  inputSchema: {
31619
31692
  draftId: external_exports.string().describe("Draft ID"),
31693
+ force: external_exports.boolean().optional().describe("Required to delete in this non-interactive context \u2014 without it the delete is refused as a safety guard."),
31620
31694
  account: accountParam
31621
31695
  }
31622
- }, async ({ draftId, account }) => {
31623
- return runOrDiagnose(["gmail", "drafts", "delete", draftId], { account });
31696
+ }, async ({ draftId, account, force }) => {
31697
+ const args = ["gmail", "drafts", "delete", draftId];
31698
+ if (force) args.push("--force");
31699
+ return runOrDiagnose(args, { account });
31624
31700
  });
31625
31701
  server2.registerTool("gog_gmail_drafts_send", {
31626
31702
  description: "Send an existing Gmail draft.",
@@ -31687,6 +31763,225 @@ function registerExtraGmailTools(server2) {
31687
31763
  if (allowSelf) args.push("--allow-self");
31688
31764
  return runOrDiagnose(args, { account });
31689
31765
  });
31766
+ server2.registerTool("gog_gmail_messages_search", {
31767
+ description: "Search individual messages (not threads) using Gmail query syntax. Returns one result per matching message.",
31768
+ annotations: { readOnlyHint: true },
31769
+ inputSchema: {
31770
+ query: external_exports.string().describe('Gmail search query (e.g. "from:alice is:unread has:attachment")'),
31771
+ max: external_exports.number().optional().describe("Max results"),
31772
+ page: external_exports.string().optional().describe("Page token"),
31773
+ all: external_exports.boolean().optional().describe("Fetch all pages"),
31774
+ includeBody: external_exports.boolean().optional().describe("Include the decoded message body in each result"),
31775
+ full: external_exports.boolean().optional().describe("Show full message bodies without truncation (implies includeBody)"),
31776
+ bodyFormat: external_exports.enum(["text", "html"]).optional().describe("Body format preference when includeBody is set"),
31777
+ account: accountParam
31778
+ }
31779
+ }, async ({ query, max, page, all, includeBody, full, bodyFormat, account }) => {
31780
+ const args = ["gmail", "messages", "search", query];
31781
+ if (max !== void 0) args.push(`--max=${max}`);
31782
+ if (page) args.push(`--page=${page}`);
31783
+ if (all) args.push("--all");
31784
+ if (includeBody) args.push("--include-body");
31785
+ if (full) args.push("--full");
31786
+ if (bodyFormat) args.push(`--body-format=${bodyFormat}`);
31787
+ return runOrDiagnose(args, { account });
31788
+ });
31789
+ server2.registerTool("gog_gmail_labels_style", {
31790
+ description: "Change a user label's color or visibility (background/text color from Gmail's palette, label-list and message-list visibility).",
31791
+ annotations: { destructiveHint: true },
31792
+ inputSchema: {
31793
+ labelIdOrName: external_exports.string().describe("Label ID or name to restyle"),
31794
+ backgroundColor: external_exports.string().optional().describe("Background color from Gmail's label palette as #RRGGBB"),
31795
+ textColor: external_exports.string().optional().describe("Text color from Gmail's label palette as #RRGGBB"),
31796
+ labelListVisibility: external_exports.enum(["labelShow", "labelShowIfUnread", "labelHide"]).optional().describe("Label-list visibility"),
31797
+ messageListVisibility: external_exports.enum(["show", "hide"]).optional().describe("Message-list visibility"),
31798
+ account: accountParam
31799
+ }
31800
+ }, async ({ labelIdOrName, backgroundColor, textColor, labelListVisibility, messageListVisibility, account }) => {
31801
+ const args = ["gmail", "labels", "style", labelIdOrName];
31802
+ if (backgroundColor) args.push(`--background-color=${backgroundColor}`);
31803
+ if (textColor) args.push(`--text-color=${textColor}`);
31804
+ if (labelListVisibility) args.push(`--label-list-visibility=${labelListVisibility}`);
31805
+ if (messageListVisibility) args.push(`--message-list-visibility=${messageListVisibility}`);
31806
+ return runOrDiagnose(args, { account });
31807
+ });
31808
+ server2.registerTool("gog_gmail_vacation_get", {
31809
+ description: "Get the current vacation responder (auto-reply) settings.",
31810
+ annotations: { readOnlyHint: true },
31811
+ inputSchema: {
31812
+ account: accountParam
31813
+ }
31814
+ }, async ({ account }) => {
31815
+ return runOrDiagnose(["gmail", "settings", "vacation", "get"], { account });
31816
+ });
31817
+ server2.registerTool("gog_gmail_vacation_update", {
31818
+ description: "Update the vacation responder. Pass enable (with subject/body) to turn it on, or disable to turn it off; optional start/end RFC3339 times and contactsOnly/domainOnly scoping.",
31819
+ inputSchema: {
31820
+ enable: external_exports.boolean().optional().describe("Enable the vacation responder"),
31821
+ disable: external_exports.boolean().optional().describe("Disable the vacation responder"),
31822
+ subject: external_exports.string().optional().describe("Subject line for the auto-reply"),
31823
+ body: external_exports.string().optional().describe("HTML body of the auto-reply message"),
31824
+ start: external_exports.string().optional().describe("Start time in RFC3339 format (e.g. 2024-12-20T00:00:00Z)"),
31825
+ end: external_exports.string().optional().describe("End time in RFC3339 format (e.g. 2024-12-31T23:59:59Z)"),
31826
+ contactsOnly: external_exports.boolean().optional().describe("Only respond to contacts"),
31827
+ domainOnly: external_exports.boolean().optional().describe("Only respond to senders in the same domain"),
31828
+ account: accountParam
31829
+ }
31830
+ }, async ({ enable, disable, subject, body, start, end, contactsOnly, domainOnly, account }) => {
31831
+ const args = ["gmail", "settings", "vacation", "update"];
31832
+ if (enable) args.push("--enable");
31833
+ if (disable) args.push("--disable");
31834
+ if (subject) args.push(`--subject=${subject}`);
31835
+ if (body) args.push(`--body=${body}`);
31836
+ if (start) args.push(`--start=${start}`);
31837
+ if (end) args.push(`--end=${end}`);
31838
+ if (contactsOnly) args.push("--contacts-only");
31839
+ if (domainOnly) args.push("--domain-only");
31840
+ return runOrDiagnose(args, { account });
31841
+ });
31842
+ server2.registerTool("gog_gmail_filters_list", {
31843
+ description: "List all Gmail filters for the account.",
31844
+ annotations: { readOnlyHint: true },
31845
+ inputSchema: {
31846
+ account: accountParam
31847
+ }
31848
+ }, async ({ account }) => {
31849
+ return runOrDiagnose(["gmail", "settings", "filters", "list"], { account });
31850
+ });
31851
+ server2.registerTool("gog_gmail_filters_get", {
31852
+ description: "Get the criteria and actions of a single Gmail filter by ID.",
31853
+ annotations: { readOnlyHint: true },
31854
+ inputSchema: {
31855
+ filterId: external_exports.string().describe("Filter ID"),
31856
+ account: accountParam
31857
+ }
31858
+ }, async ({ filterId, account }) => {
31859
+ return runOrDiagnose(["gmail", "settings", "filters", "get", filterId], { account });
31860
+ });
31861
+ server2.registerTool("gog_gmail_filters_create", {
31862
+ description: "Create a Gmail filter. Specify match criteria (from/to/subject/query/hasAttachment) and one or more actions (label, archive, mark-read, star, important, trash, forward, never-spam).",
31863
+ inputSchema: {
31864
+ from: external_exports.string().optional().describe("Match messages from this sender"),
31865
+ to: external_exports.string().optional().describe("Match messages to this recipient"),
31866
+ subject: external_exports.string().optional().describe("Match messages with this subject"),
31867
+ query: external_exports.string().optional().describe("Advanced Gmail search query for matching"),
31868
+ hasAttachment: external_exports.boolean().optional().describe("Match messages with attachments"),
31869
+ addLabel: external_exports.string().optional().describe("Label(s) to add to matching messages (comma-separated, name or ID)"),
31870
+ removeLabel: external_exports.string().optional().describe("Label(s) to remove from matching messages (comma-separated, name or ID)"),
31871
+ archive: external_exports.boolean().optional().describe("Archive matching messages (skip inbox)"),
31872
+ markRead: external_exports.boolean().optional().describe("Mark matching messages as read"),
31873
+ star: external_exports.boolean().optional().describe("Star matching messages"),
31874
+ important: external_exports.boolean().optional().describe("Mark as important"),
31875
+ trash: external_exports.boolean().optional().describe("Move matching messages to trash"),
31876
+ neverSpam: external_exports.boolean().optional().describe("Never mark as spam"),
31877
+ forward: external_exports.string().optional().describe("Forward to this email address (must be a verified forwarding address)"),
31878
+ account: accountParam
31879
+ }
31880
+ }, async ({ from, to, subject, query, hasAttachment, addLabel, removeLabel, archive, markRead, star, important, trash, neverSpam, forward, account }) => {
31881
+ const args = ["gmail", "settings", "filters", "create"];
31882
+ if (from) args.push(`--from=${from}`);
31883
+ if (to) args.push(`--to=${to}`);
31884
+ if (subject) args.push(`--subject=${subject}`);
31885
+ if (query) args.push(`--query=${query}`);
31886
+ if (hasAttachment) args.push("--has-attachment");
31887
+ if (addLabel) args.push(`--add-label=${addLabel}`);
31888
+ if (removeLabel) args.push(`--remove-label=${removeLabel}`);
31889
+ if (archive) args.push("--archive");
31890
+ if (markRead) args.push("--mark-read");
31891
+ if (star) args.push("--star");
31892
+ if (important) args.push("--important");
31893
+ if (trash) args.push("--trash");
31894
+ if (neverSpam) args.push("--never-spam");
31895
+ if (forward) args.push(`--forward=${forward}`);
31896
+ return runOrDiagnose(args, { account });
31897
+ });
31898
+ server2.registerTool("gog_gmail_filters_delete", {
31899
+ description: "Delete a Gmail filter by ID.",
31900
+ annotations: { destructiveHint: true },
31901
+ inputSchema: {
31902
+ filterId: external_exports.string().describe("Filter ID to delete"),
31903
+ account: accountParam
31904
+ }
31905
+ }, async ({ filterId, account }) => {
31906
+ return runOrDiagnose(["gmail", "settings", "filters", "delete", filterId], { account });
31907
+ });
31908
+ server2.registerTool("gog_gmail_sendas_list", {
31909
+ description: "List all send-as aliases configured for the account.",
31910
+ annotations: { readOnlyHint: true },
31911
+ inputSchema: {
31912
+ account: accountParam
31913
+ }
31914
+ }, async ({ account }) => {
31915
+ return runOrDiagnose(["gmail", "settings", "sendas", "list"], { account });
31916
+ });
31917
+ server2.registerTool("gog_gmail_sendas_get", {
31918
+ description: "Get details of a single send-as alias by its email address.",
31919
+ annotations: { readOnlyHint: true },
31920
+ inputSchema: {
31921
+ email: external_exports.string().describe("Send-as alias email address"),
31922
+ account: accountParam
31923
+ }
31924
+ }, async ({ email: email3, account }) => {
31925
+ return runOrDiagnose(["gmail", "settings", "sendas", "get", email3], { account });
31926
+ });
31927
+ server2.registerTool("gog_gmail_sendas_create", {
31928
+ description: "Create a send-as alias. Newly added aliases generally require email verification before they can be used (see gog_gmail_sendas_verify).",
31929
+ inputSchema: {
31930
+ email: external_exports.string().describe("Email address of the new send-as alias"),
31931
+ displayName: external_exports.string().optional().describe("Name that appears in the From field"),
31932
+ replyTo: external_exports.string().optional().describe("Reply-to address"),
31933
+ signature: external_exports.string().optional().describe("HTML signature for emails sent from this alias"),
31934
+ treatAsAlias: external_exports.boolean().optional().describe("Treat as alias (replies sent from Gmail web)"),
31935
+ account: accountParam
31936
+ }
31937
+ }, async ({ email: email3, displayName, replyTo, signature, treatAsAlias, account }) => {
31938
+ const args = ["gmail", "settings", "sendas", "create", email3];
31939
+ if (displayName) args.push(`--display-name=${displayName}`);
31940
+ if (replyTo) args.push(`--reply-to=${replyTo}`);
31941
+ if (signature) args.push(`--signature=${signature}`);
31942
+ if (treatAsAlias) args.push("--treat-as-alias");
31943
+ return runOrDiagnose(args, { account });
31944
+ });
31945
+ server2.registerTool("gog_gmail_sendas_update", {
31946
+ description: "Update a send-as alias (display name, reply-to, signature, alias handling, or make it the default).",
31947
+ annotations: { destructiveHint: true },
31948
+ inputSchema: {
31949
+ email: external_exports.string().describe("Send-as alias email address to update"),
31950
+ displayName: external_exports.string().optional().describe("Name that appears in the From field"),
31951
+ replyTo: external_exports.string().optional().describe("Reply-to address"),
31952
+ signature: external_exports.string().optional().describe("HTML signature"),
31953
+ treatAsAlias: external_exports.boolean().optional().describe("Treat as alias"),
31954
+ makeDefault: external_exports.boolean().optional().describe("Make this the default send-as address"),
31955
+ account: accountParam
31956
+ }
31957
+ }, async ({ email: email3, displayName, replyTo, signature, treatAsAlias, makeDefault, account }) => {
31958
+ const args = ["gmail", "settings", "sendas", "update", email3];
31959
+ if (displayName) args.push(`--display-name=${displayName}`);
31960
+ if (replyTo) args.push(`--reply-to=${replyTo}`);
31961
+ if (signature) args.push(`--signature=${signature}`);
31962
+ if (treatAsAlias) args.push("--treat-as-alias");
31963
+ if (makeDefault) args.push("--make-default");
31964
+ return runOrDiagnose(args, { account });
31965
+ });
31966
+ server2.registerTool("gog_gmail_sendas_delete", {
31967
+ description: "Delete a send-as alias by its email address.",
31968
+ annotations: { destructiveHint: true },
31969
+ inputSchema: {
31970
+ email: external_exports.string().describe("Send-as alias email address to delete"),
31971
+ account: accountParam
31972
+ }
31973
+ }, async ({ email: email3, account }) => {
31974
+ return runOrDiagnose(["gmail", "settings", "sendas", "delete", email3], { account });
31975
+ });
31976
+ server2.registerTool("gog_gmail_sendas_verify", {
31977
+ description: "Resend the verification email for a send-as alias that is pending verification.",
31978
+ inputSchema: {
31979
+ email: external_exports.string().describe("Send-as alias email address to verify"),
31980
+ account: accountParam
31981
+ }
31982
+ }, async ({ email: email3, account }) => {
31983
+ return runOrDiagnose(["gmail", "settings", "sendas", "verify", email3], { account });
31984
+ });
31690
31985
  }
31691
31986
 
31692
31987
  // src/index.ts
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "gogcli-mcp-gmail",
5
5
  "display_name": "gogcli (Gmail)",
6
- "version": "2.0.12",
6
+ "version": "2.3.0",
7
7
  "description": "Extended Gmail for Claude via gogcli — auth + full Gmail support (threads, labels, drafts, attachments, forward, autoreply, bulk operations)",
8
8
  "author": {
9
9
  "name": "Chris Hall",
@@ -204,6 +204,62 @@
204
204
  {
205
205
  "name": "gog_gmail_autoreply",
206
206
  "description": "Reply once to all messages matching a Gmail search query"
207
+ },
208
+ {
209
+ "name": "gog_gmail_messages_search",
210
+ "description": "Search individual messages (not threads) using Gmail query syntax"
211
+ },
212
+ {
213
+ "name": "gog_gmail_labels_style",
214
+ "description": "Change a user label's color or visibility"
215
+ },
216
+ {
217
+ "name": "gog_gmail_vacation_get",
218
+ "description": "Get the current vacation responder settings"
219
+ },
220
+ {
221
+ "name": "gog_gmail_vacation_update",
222
+ "description": "Enable, disable, or update the vacation responder"
223
+ },
224
+ {
225
+ "name": "gog_gmail_filters_list",
226
+ "description": "List all Gmail filters"
227
+ },
228
+ {
229
+ "name": "gog_gmail_filters_get",
230
+ "description": "Get a single Gmail filter's criteria and actions"
231
+ },
232
+ {
233
+ "name": "gog_gmail_filters_create",
234
+ "description": "Create a Gmail filter with match criteria and actions"
235
+ },
236
+ {
237
+ "name": "gog_gmail_filters_delete",
238
+ "description": "Delete a Gmail filter by ID"
239
+ },
240
+ {
241
+ "name": "gog_gmail_sendas_list",
242
+ "description": "List all send-as aliases for the account"
243
+ },
244
+ {
245
+ "name": "gog_gmail_sendas_get",
246
+ "description": "Get details of a single send-as alias"
247
+ },
248
+ {
249
+ "name": "gog_gmail_sendas_create",
250
+ "description": "Create a send-as alias"
251
+ },
252
+ {
253
+ "name": "gog_gmail_sendas_update",
254
+ "description": "Update a send-as alias or make it the default"
255
+ },
256
+ {
257
+ "name": "gog_gmail_sendas_delete",
258
+ "description": "Delete a send-as alias"
259
+ },
260
+ {
261
+ "name": "gog_gmail_sendas_verify",
262
+ "description": "Resend the verification email for a send-as alias"
207
263
  }
208
264
  ],
209
265
  "compatibility": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp-gmail",
3
- "version": "2.0.12",
3
+ "version": "2.3.0",
4
4
  "mcpName": "io.github.chrischall/gogcli-mcp-gmail",
5
5
  "description": "Extended Gmail MCP server via gogcli — auth + full Gmail support (threads, labels, drafts, attachments, forward, autoreply, bulk operations)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",