@jaingxyz/personal-gmail-mcp 0.1.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/.env.example +6 -0
- package/LICENSE +661 -0
- package/README.md +142 -0
- package/dist/auth.js +200 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.js +90 -0
- package/dist/config.js.map +1 -0
- package/dist/google.js +27 -0
- package/dist/google.js.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/whoami.js +16 -0
- package/dist/scripts/whoami.js.map +1 -0
- package/dist/server.js +136 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/calendar.js +296 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/helpers.js +125 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/mutate.js +75 -0
- package/dist/tools/mutate.js.map +1 -0
- package/dist/tools/read.js +120 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/send.js +166 -0
- package/dist/tools/send.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 jaingxyz
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { gmailClient } from "../google.js";
|
|
5
|
+
export const markReadSchema = z.object({
|
|
6
|
+
messageId: z.string().min(1),
|
|
7
|
+
isRead: z
|
|
8
|
+
.boolean()
|
|
9
|
+
.default(true)
|
|
10
|
+
.describe("true to mark read (remove UNREAD), false to mark unread."),
|
|
11
|
+
});
|
|
12
|
+
export async function markRead(input) {
|
|
13
|
+
const gmail = await gmailClient();
|
|
14
|
+
// Read state in Gmail is the presence/absence of the UNREAD label.
|
|
15
|
+
await gmail.users.messages.modify({
|
|
16
|
+
userId: "me",
|
|
17
|
+
id: input.messageId,
|
|
18
|
+
requestBody: input.isRead
|
|
19
|
+
? { removeLabelIds: ["UNREAD"] }
|
|
20
|
+
: { addLabelIds: ["UNREAD"] },
|
|
21
|
+
});
|
|
22
|
+
return { ok: true, messageId: input.messageId, isRead: input.isRead };
|
|
23
|
+
}
|
|
24
|
+
export const modifyLabelsSchema = z.object({
|
|
25
|
+
messageId: z.string().min(1),
|
|
26
|
+
addLabelIds: z
|
|
27
|
+
.array(z.string())
|
|
28
|
+
.default([])
|
|
29
|
+
.describe("Label ids to add (e.g. a custom label id, or STARRED)."),
|
|
30
|
+
removeLabelIds: z
|
|
31
|
+
.array(z.string())
|
|
32
|
+
.default([])
|
|
33
|
+
.describe("Label ids to remove. Removing INBOX archives the message; adding INBOX un-archives."),
|
|
34
|
+
});
|
|
35
|
+
export async function modifyLabels(input) {
|
|
36
|
+
const gmail = await gmailClient();
|
|
37
|
+
const res = await gmail.users.messages.modify({
|
|
38
|
+
userId: "me",
|
|
39
|
+
id: input.messageId,
|
|
40
|
+
requestBody: {
|
|
41
|
+
addLabelIds: input.addLabelIds,
|
|
42
|
+
removeLabelIds: input.removeLabelIds,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
messageId: input.messageId,
|
|
48
|
+
labelIds: res.data.labelIds ?? [],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export const deleteSchema = z.object({
|
|
52
|
+
messageId: z.string().min(1),
|
|
53
|
+
hardDelete: z
|
|
54
|
+
.boolean()
|
|
55
|
+
.default(false)
|
|
56
|
+
.describe("false (default): move to Trash (recoverable, auto-purged after ~30 days). true: permanently delete now — not recoverable."),
|
|
57
|
+
});
|
|
58
|
+
export async function deleteMessage(input) {
|
|
59
|
+
const gmail = await gmailClient();
|
|
60
|
+
if (input.hardDelete) {
|
|
61
|
+
await gmail.users.messages.delete({ userId: "me", id: input.messageId });
|
|
62
|
+
return { ok: true, messageId: input.messageId, mode: "hard" };
|
|
63
|
+
}
|
|
64
|
+
await gmail.users.messages.trash({ userId: "me", id: input.messageId });
|
|
65
|
+
return { ok: true, messageId: input.messageId, mode: "soft" };
|
|
66
|
+
}
|
|
67
|
+
export const untrashSchema = z.object({
|
|
68
|
+
messageId: z.string().min(1),
|
|
69
|
+
});
|
|
70
|
+
export async function untrash(input) {
|
|
71
|
+
const gmail = await gmailClient();
|
|
72
|
+
await gmail.users.messages.untrash({ userId: "me", id: input.messageId });
|
|
73
|
+
return { ok: true, messageId: input.messageId };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=mutate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../src/tools/mutate.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,8BAA8B;AAC9B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,CAAC;SACN,OAAO,EAAE;SACT,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,0DAA0D,CAAC;CACxE,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAoB;IACjD,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,mEAAmE;IACnE,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAChC,MAAM,EAAE,IAAI;QACZ,EAAE,EAAE,KAAK,CAAC,SAAS;QACnB,WAAW,EAAE,KAAK,CAAC,MAAM;YACvB,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,QAAQ,CAAC,EAAE;YAChC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE;KAChC,CAAC,CAAC;IACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,WAAW,EAAE,CAAC;SACX,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,wDAAwD,CAAC;IACrE,cAAc,EAAE,CAAC;SACd,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CACP,qFAAqF,CACtF;CACJ,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAwB;IACzD,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5C,MAAM,EAAE,IAAI;QACZ,EAAE,EAAE,KAAK,CAAC,SAAS;QACnB,WAAW,EAAE;YACX,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,cAAc,EAAE,KAAK,CAAC,cAAc;SACrC;KACF,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,IAAI;QACR,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,CAAC;SACV,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CACP,2HAA2H,CAC5H;CACJ,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAkB;IACpD,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QACzE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAChE,CAAC;IACD,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACxE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC7B,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAmB;IAC/C,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;IAClC,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IAC1E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 jaingxyz
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { gmailClient } from "../google.js";
|
|
5
|
+
import { summarizeMessage, extractBody, header, hasAttachments, truncate, } from "./helpers.js";
|
|
6
|
+
const DEFAULT_MAX_BODY_CHARS = 20000;
|
|
7
|
+
export const listLabelsSchema = z.object({});
|
|
8
|
+
export async function listLabels(_input) {
|
|
9
|
+
const gmail = await gmailClient();
|
|
10
|
+
const res = await gmail.users.labels.list({ userId: "me" });
|
|
11
|
+
return {
|
|
12
|
+
labels: (res.data.labels ?? []).map((l) => ({
|
|
13
|
+
id: l.id,
|
|
14
|
+
name: l.name,
|
|
15
|
+
type: l.type, // "system" | "user"
|
|
16
|
+
messagesUnread: l.messagesUnread,
|
|
17
|
+
messagesTotal: l.messagesTotal,
|
|
18
|
+
})),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export const listRecentSchema = z.object({
|
|
22
|
+
label: z
|
|
23
|
+
.string()
|
|
24
|
+
.default("INBOX")
|
|
25
|
+
.describe("Label id to list. System labels: INBOX, SENT, DRAFT, TRASH, SPAM, STARRED, IMPORTANT, UNREAD. Custom labels use their id (from gmail_list_labels)."),
|
|
26
|
+
limit: z.number().int().min(1).max(100).default(25),
|
|
27
|
+
unreadOnly: z.boolean().default(false),
|
|
28
|
+
cursor: z
|
|
29
|
+
.string()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Opaque pagination token from a previous call's nextCursor. When set, returns the next page."),
|
|
32
|
+
});
|
|
33
|
+
export async function listRecent(input) {
|
|
34
|
+
const gmail = await gmailClient();
|
|
35
|
+
const labelIds = [input.label];
|
|
36
|
+
if (input.unreadOnly)
|
|
37
|
+
labelIds.push("UNREAD");
|
|
38
|
+
const list = await gmail.users.messages.list({
|
|
39
|
+
userId: "me",
|
|
40
|
+
labelIds,
|
|
41
|
+
maxResults: input.limit,
|
|
42
|
+
pageToken: input.cursor,
|
|
43
|
+
});
|
|
44
|
+
return hydrate(gmail, list.data.messages, list.data.nextPageToken);
|
|
45
|
+
}
|
|
46
|
+
export const searchSchema = z.object({
|
|
47
|
+
query: z
|
|
48
|
+
.string()
|
|
49
|
+
.min(1)
|
|
50
|
+
.describe("Gmail search query. Supports Gmail operators: from:, to:, subject:, has:attachment, newer_than:7d, label:, is:unread, etc."),
|
|
51
|
+
limit: z.number().int().min(1).max(100).default(25),
|
|
52
|
+
cursor: z
|
|
53
|
+
.string()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Opaque pagination token from a previous call's nextCursor."),
|
|
56
|
+
});
|
|
57
|
+
export async function search(input) {
|
|
58
|
+
const gmail = await gmailClient();
|
|
59
|
+
const list = await gmail.users.messages.list({
|
|
60
|
+
userId: "me",
|
|
61
|
+
q: input.query,
|
|
62
|
+
maxResults: input.limit,
|
|
63
|
+
pageToken: input.cursor,
|
|
64
|
+
});
|
|
65
|
+
return hydrate(gmail, list.data.messages, list.data.nextPageToken);
|
|
66
|
+
}
|
|
67
|
+
// messages.list returns only {id, threadId} stubs. Fetch metadata for each so
|
|
68
|
+
// the caller gets useful summaries (from/subject/date/snippet) in one round.
|
|
69
|
+
async function hydrate(gmail, stubs, nextPageToken) {
|
|
70
|
+
const ids = (stubs ?? []).map((m) => m.id).filter((id) => !!id);
|
|
71
|
+
const full = await Promise.all(ids.map((id) => gmail.users.messages
|
|
72
|
+
.get({
|
|
73
|
+
userId: "me",
|
|
74
|
+
id,
|
|
75
|
+
format: "metadata",
|
|
76
|
+
metadataHeaders: ["From", "To", "Subject", "Date"],
|
|
77
|
+
})
|
|
78
|
+
.then((r) => r.data)));
|
|
79
|
+
return {
|
|
80
|
+
messages: full.map(summarizeMessage),
|
|
81
|
+
nextCursor: nextPageToken ?? null,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export const readSchema = z.object({
|
|
85
|
+
messageId: z.string().min(1),
|
|
86
|
+
maxBodyChars: z
|
|
87
|
+
.number()
|
|
88
|
+
.int()
|
|
89
|
+
.min(0)
|
|
90
|
+
.max(1000000)
|
|
91
|
+
.default(DEFAULT_MAX_BODY_CHARS)
|
|
92
|
+
.describe("Truncate the body to this many characters (a marker is appended when truncated). 0 disables the cap. Defaults to 20000."),
|
|
93
|
+
});
|
|
94
|
+
export async function read(input) {
|
|
95
|
+
const gmail = await gmailClient();
|
|
96
|
+
const res = await gmail.users.messages.get({
|
|
97
|
+
userId: "me",
|
|
98
|
+
id: input.messageId,
|
|
99
|
+
format: "full",
|
|
100
|
+
});
|
|
101
|
+
const msg = res.data;
|
|
102
|
+
const body = extractBody(msg);
|
|
103
|
+
const { text: content, truncated } = truncate(body.content, input.maxBodyChars ?? DEFAULT_MAX_BODY_CHARS);
|
|
104
|
+
return {
|
|
105
|
+
id: msg.id,
|
|
106
|
+
threadId: msg.threadId,
|
|
107
|
+
from: header(msg, "From") ?? null,
|
|
108
|
+
to: header(msg, "To") ?? null,
|
|
109
|
+
cc: header(msg, "Cc") ?? null,
|
|
110
|
+
subject: header(msg, "Subject") ?? null,
|
|
111
|
+
date: header(msg, "Date") ?? null,
|
|
112
|
+
labelIds: msg.labelIds ?? [],
|
|
113
|
+
unread: (msg.labelIds ?? []).includes("UNREAD"),
|
|
114
|
+
hasAttachments: hasAttachments(msg),
|
|
115
|
+
messageIdHeader: header(msg, "Message-ID") ?? null,
|
|
116
|
+
references: header(msg, "References") ?? null,
|
|
117
|
+
body: { contentType: body.contentType, content, truncated },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 jaingxyz
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { gmailClient } from "../google.js";
|
|
5
|
+
import { buildRawMessage, header } from "./helpers.js";
|
|
6
|
+
const recipientList = z
|
|
7
|
+
.array(z.string().email())
|
|
8
|
+
.min(1)
|
|
9
|
+
.describe("One or more email addresses.");
|
|
10
|
+
const optionalRecipientList = z.array(z.string().email()).default([]);
|
|
11
|
+
const bodyFormat = z
|
|
12
|
+
.enum(["text", "html"])
|
|
13
|
+
.default("text")
|
|
14
|
+
.describe("Body content type: 'text' (plain) or 'html'.");
|
|
15
|
+
export const sendSchema = z.object({
|
|
16
|
+
to: recipientList,
|
|
17
|
+
cc: optionalRecipientList,
|
|
18
|
+
bcc: optionalRecipientList,
|
|
19
|
+
subject: z.string().default(""),
|
|
20
|
+
body: z.string().default(""),
|
|
21
|
+
bodyFormat,
|
|
22
|
+
});
|
|
23
|
+
export async function send(input) {
|
|
24
|
+
const gmail = await gmailClient();
|
|
25
|
+
const raw = buildRawMessage({
|
|
26
|
+
to: input.to,
|
|
27
|
+
cc: input.cc,
|
|
28
|
+
bcc: input.bcc,
|
|
29
|
+
subject: input.subject,
|
|
30
|
+
body: input.body,
|
|
31
|
+
bodyFormat: input.bodyFormat,
|
|
32
|
+
});
|
|
33
|
+
const res = await gmail.users.messages.send({
|
|
34
|
+
userId: "me",
|
|
35
|
+
requestBody: { raw },
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
ok: true,
|
|
39
|
+
id: res.data.id,
|
|
40
|
+
threadId: res.data.threadId,
|
|
41
|
+
to: input.to,
|
|
42
|
+
subject: input.subject,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export const replySchema = z.object({
|
|
46
|
+
messageId: z.string().min(1).describe("Id of the message being replied to."),
|
|
47
|
+
body: z.string().min(1).describe("Reply body."),
|
|
48
|
+
bodyFormat,
|
|
49
|
+
replyAll: z
|
|
50
|
+
.boolean()
|
|
51
|
+
.default(false)
|
|
52
|
+
.describe("If true, reply to all original recipients (To + Cc)."),
|
|
53
|
+
});
|
|
54
|
+
export async function reply(input) {
|
|
55
|
+
const gmail = await gmailClient();
|
|
56
|
+
// Fetch the original to derive recipients + threading headers.
|
|
57
|
+
const orig = (await gmail.users.messages.get({
|
|
58
|
+
userId: "me",
|
|
59
|
+
id: input.messageId,
|
|
60
|
+
format: "metadata",
|
|
61
|
+
metadataHeaders: [
|
|
62
|
+
"From",
|
|
63
|
+
"To",
|
|
64
|
+
"Cc",
|
|
65
|
+
"Subject",
|
|
66
|
+
"Message-ID",
|
|
67
|
+
"References",
|
|
68
|
+
],
|
|
69
|
+
})).data;
|
|
70
|
+
const from = header(orig, "From");
|
|
71
|
+
const to = from ? [extractEmail(from)] : [];
|
|
72
|
+
const cc = [];
|
|
73
|
+
if (input.replyAll) {
|
|
74
|
+
for (const raw of [header(orig, "To"), header(orig, "Cc")]) {
|
|
75
|
+
for (const addr of splitAddresses(raw)) {
|
|
76
|
+
const email = extractEmail(addr);
|
|
77
|
+
if (email && email !== to[0])
|
|
78
|
+
cc.push(email);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const origSubject = header(orig, "Subject") ?? "";
|
|
83
|
+
const subject = /^re:/i.test(origSubject)
|
|
84
|
+
? origSubject
|
|
85
|
+
: `Re: ${origSubject}`;
|
|
86
|
+
const origMsgId = header(orig, "Message-ID");
|
|
87
|
+
const origRefs = header(orig, "References");
|
|
88
|
+
const raw = buildRawMessage({
|
|
89
|
+
to,
|
|
90
|
+
cc,
|
|
91
|
+
subject,
|
|
92
|
+
body: input.body,
|
|
93
|
+
bodyFormat: input.bodyFormat,
|
|
94
|
+
inReplyTo: origMsgId,
|
|
95
|
+
references: [origRefs, origMsgId].filter(Boolean).join(" ") || undefined,
|
|
96
|
+
});
|
|
97
|
+
const res = await gmail.users.messages.send({
|
|
98
|
+
userId: "me",
|
|
99
|
+
// threadId keeps the reply in the same conversation.
|
|
100
|
+
requestBody: { raw, threadId: orig.threadId ?? undefined },
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
id: res.data.id,
|
|
105
|
+
threadId: res.data.threadId,
|
|
106
|
+
repliedTo: input.messageId,
|
|
107
|
+
replyAll: input.replyAll,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export const createDraftSchema = z.object({
|
|
111
|
+
to: recipientList,
|
|
112
|
+
cc: optionalRecipientList,
|
|
113
|
+
bcc: optionalRecipientList,
|
|
114
|
+
subject: z.string().default(""),
|
|
115
|
+
body: z.string().default(""),
|
|
116
|
+
bodyFormat,
|
|
117
|
+
});
|
|
118
|
+
export async function createDraft(input) {
|
|
119
|
+
const gmail = await gmailClient();
|
|
120
|
+
const raw = buildRawMessage({
|
|
121
|
+
to: input.to,
|
|
122
|
+
cc: input.cc,
|
|
123
|
+
bcc: input.bcc,
|
|
124
|
+
subject: input.subject,
|
|
125
|
+
body: input.body,
|
|
126
|
+
bodyFormat: input.bodyFormat,
|
|
127
|
+
});
|
|
128
|
+
const res = await gmail.users.drafts.create({
|
|
129
|
+
userId: "me",
|
|
130
|
+
requestBody: { message: { raw } },
|
|
131
|
+
});
|
|
132
|
+
return { ok: true, draftId: res.data.id, subject: input.subject };
|
|
133
|
+
}
|
|
134
|
+
export const sendDraftSchema = z.object({
|
|
135
|
+
draftId: z.string().min(1).describe("Id of an existing draft."),
|
|
136
|
+
});
|
|
137
|
+
export async function sendDraft(input) {
|
|
138
|
+
const gmail = await gmailClient();
|
|
139
|
+
const res = await gmail.users.drafts.send({
|
|
140
|
+
userId: "me",
|
|
141
|
+
requestBody: { id: input.draftId },
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
draftId: input.draftId,
|
|
146
|
+
id: res.data.id,
|
|
147
|
+
threadId: res.data.threadId,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// "Display Name <a@b.com>" -> "a@b.com"; bare "a@b.com" -> "a@b.com".
|
|
151
|
+
export function extractEmail(addr) {
|
|
152
|
+
const m = addr.match(/<([^>]+)>/);
|
|
153
|
+
return (m ? m[1] : addr).trim();
|
|
154
|
+
}
|
|
155
|
+
// Split a header value on commas that separate addresses (naive but adequate
|
|
156
|
+
// for reply-all recipient gathering; quoted display names rarely contain commas
|
|
157
|
+
// in practice and a stray cc is harmless).
|
|
158
|
+
export function splitAddresses(raw) {
|
|
159
|
+
if (!raw)
|
|
160
|
+
return [];
|
|
161
|
+
return raw
|
|
162
|
+
.split(",")
|
|
163
|
+
.map((s) => s.trim())
|
|
164
|
+
.filter(Boolean);
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=send.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/tools/send.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jaingxyz/personal-gmail-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Model Context Protocol server for a personal Gmail (consumer Google account) inbox and calendar, via the Gmail and Google Calendar APIs. Stdio transport, loopback OAuth, OS-keyring token cache.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "AGPL-3.0-or-later",
|
|
7
|
+
"author": "jaingxyz",
|
|
8
|
+
"homepage": "https://github.com/jaingxyz/personal-gmail-mcp#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/jaingxyz/personal-gmail-mcp.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/jaingxyz/personal-gmail-mcp/security/advisories/new"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"gmail",
|
|
20
|
+
"google-calendar",
|
|
21
|
+
"google-api",
|
|
22
|
+
"claude",
|
|
23
|
+
"anthropic"
|
|
24
|
+
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"personal-gmail-mcp": "dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
".env.example"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
36
|
+
"dev": "tsc --watch",
|
|
37
|
+
"start": "node dist/index.js",
|
|
38
|
+
"whoami": "node dist/scripts/whoami.js",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"test:watch": "vitest",
|
|
41
|
+
"test:coverage": "vitest run --coverage",
|
|
42
|
+
"lint": "eslint .",
|
|
43
|
+
"lint:fix": "eslint . --fix",
|
|
44
|
+
"format": "prettier --write .",
|
|
45
|
+
"format:check": "prettier --check .",
|
|
46
|
+
"prepublishOnly": "npm run build && npm run lint && npm run format:check && npm test",
|
|
47
|
+
"clean": "rm -rf dist coverage"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=22.22.1"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
54
|
+
"@napi-rs/keyring": "^1.3.0",
|
|
55
|
+
"googleapis": "^173.0.0",
|
|
56
|
+
"zod": "^4.4.3"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@eslint/js": "^10.0.1",
|
|
60
|
+
"@types/node": "^25.9.2",
|
|
61
|
+
"@vitest/coverage-v8": "^4.1.6",
|
|
62
|
+
"eslint": "^10.4.0",
|
|
63
|
+
"eslint-config-prettier": "^10.1.8",
|
|
64
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
65
|
+
"prettier": "^3.8.3",
|
|
66
|
+
"typescript": "^6.0.3",
|
|
67
|
+
"typescript-eslint": "^8.59.4",
|
|
68
|
+
"vitest": "^4.1.6"
|
|
69
|
+
}
|
|
70
|
+
}
|