[object Object]

← back to George Mcp

add gmail_send_attachment tool: send email with local-file attachments via /api/send-with-attachment

d9bbb802de4ba5a43f3ca8d9db93480c6d960171 · 2026-07-10 11:22:13 -0700 · Steve Abrams

Files touched

Diff

commit d9bbb802de4ba5a43f3ca8d9db93480c6d960171
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Jul 10 11:22:13 2026 -0700

    add gmail_send_attachment tool: send email with local-file attachments via /api/send-with-attachment
---
 index.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/index.js b/index.js
index 54a051b..88ea4d3 100755
--- a/index.js
+++ b/index.js
@@ -220,6 +220,29 @@ const TOOLS = [
       additionalProperties: false,
     },
   },
+  {
+    name: "gmail_send_attachment",
+    description:
+      "Send an email WITH one or more file attachments from a DW Gmail account (steve-office / steve@designerwallcoverings.com by default — pass account:'info' to send from info@). Body is HTML. `attachments` are LOCAL filesystem paths — the bridge reads each file, base64-encodes it, and posts to George's /api/send-with-attachment. Use this instead of gmail_send whenever a file must be attached.",
+    inputSchema: {
+      type: "object",
+      properties: {
+        to: { type: "string" },
+        subject: { type: "string" },
+        body: { type: "string", description: "HTML body" },
+        cc: { type: "string" },
+        bcc: { type: "string" },
+        attachments: {
+          type: "array",
+          description: "Local filesystem paths to attach.",
+          items: { type: "string" },
+        },
+        ...ACCOUNT_PROP,
+      },
+      required: ["to", "subject", "body", "attachments"],
+      additionalProperties: false,
+    },
+  },
   {
     name: "gmail_create_draft",
     description: "Create a Gmail draft instead of sending immediately.",
@@ -316,6 +339,38 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
       case "gmail_send":
         data = await george("/api/send", { method: "POST", body: args });
         break;
+      case "gmail_send_attachment": {
+        const fs = await import("node:fs");
+        const path = await import("node:path");
+        const MIME = {
+          ".pdf": "application/pdf",
+          ".doc": "application/msword",
+          ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+          ".xls": "application/vnd.ms-excel",
+          ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+          ".png": "image/png",
+          ".jpg": "image/jpeg",
+          ".jpeg": "image/jpeg",
+          ".gif": "image/gif",
+          ".txt": "text/plain",
+          ".csv": "text/csv",
+          ".zip": "application/zip",
+        };
+        const paths = Array.isArray(args.attachments) ? args.attachments : [args.attachments];
+        const attachments = paths.filter(Boolean).map((p) => {
+          const ext = path.extname(String(p)).toLowerCase();
+          return {
+            filename: path.basename(String(p)),
+            content_base64: fs.readFileSync(String(p)).toString("base64"),
+            mime_type: MIME[ext] || "application/octet-stream",
+          };
+        });
+        data = await george("/api/send-with-attachment", {
+          method: "POST",
+          body: { to: args.to, cc: args.cc, bcc: args.bcc, subject: args.subject, body: args.body, account, attachments },
+        });
+        break;
+      }
       case "gmail_create_draft":
         data = await george("/api/drafts", { method: "POST", body: args });
         break;

← b2cbb3d fix gmail_get_attachment: fetch raw bytes + save locally (re  ·  back to George Mcp  ·  chore: lint, refactor, v0.2.0 (session close) 67b3cb6 →