@d-mato/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/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # gmail-mcp
2
+
3
+ MCP server for Gmail — search, read, archive, and manage your email from any MCP client.
4
+
5
+ ## Setup
6
+
7
+ Add to your MCP client configuration:
8
+
9
+ ```json
10
+ {
11
+ "mcpServers": {
12
+ "gmail": {
13
+ "command": "npx",
14
+ "args": ["-y", "@d-mato/gmail-mcp"]
15
+ }
16
+ }
17
+ }
18
+ ```
19
+
20
+ On first launch, a browser window will open for Google account authorization. After granting access, the token is stored locally at `~/.gmail-mcp/tokens.json` and you won't need to authorize again.
21
+
22
+ ## Available Tools
23
+
24
+ ### Messages
25
+
26
+ | Tool | Description |
27
+ |------|-------------|
28
+ | `gmail_search` | Search messages using Gmail query syntax (e.g. `from:user@example.com`, `is:unread`) |
29
+ | `gmail_get_message` | Get the full content of a message by ID |
30
+ | `gmail_archive` | Archive a message (remove from inbox) |
31
+ | `gmail_batch_archive` | Archive multiple messages |
32
+ | `gmail_trash` | Move a message to trash |
33
+ | `gmail_batch_trash` | Move multiple messages to trash |
34
+ | `gmail_untrash` | Remove a message from trash |
35
+ | `gmail_mark_read` | Mark a message as read |
36
+ | `gmail_mark_unread` | Mark a message as unread |
37
+
38
+ ### Labels
39
+
40
+ | Tool | Description |
41
+ |------|-------------|
42
+ | `gmail_list_labels` | List all labels |
43
+ | `gmail_add_label` | Add a label to a message |
44
+ | `gmail_remove_label` | Remove a label from a message |
45
+ | `gmail_create_label` | Create a new label |
46
+ | `gmail_delete_label` | Delete a label |
47
+
48
+ ## License
49
+
50
+ MIT
@@ -0,0 +1,5 @@
1
+ import { google } from "googleapis";
2
+ type OAuth2Client = InstanceType<typeof google.auth.OAuth2>;
3
+ export declare function authenticate(): Promise<OAuth2Client>;
4
+ export {};
5
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAUpC,KAAK,YAAY,GAAG,YAAY,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAwI5D,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,CAqC1D"}
package/build/auth.js ADDED
@@ -0,0 +1,116 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { createServer } from "node:http";
3
+ import { URL } from "node:url";
4
+ import { google } from "googleapis";
5
+ import open from "open";
6
+ import { CONFIG_DIR, GMAIL_SCOPES, OAUTH_PORT, TOKENS_PATH } from "./types.js";
7
+ // Bundled OAuth client credentials for gmail-mcp.
8
+ // Users can override by setting GMAIL_MCP_CLIENT_ID and GMAIL_MCP_CLIENT_SECRET.
9
+ const DEFAULT_CLIENT_ID = "467574130802-k6hgca5a04vgm05t37vfcqp3ok1bod4l.apps.googleusercontent.com";
10
+ const DEFAULT_CLIENT_SECRET = "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";
11
+ function getCredentials() {
12
+ const clientId = process.env.GMAIL_MCP_CLIENT_ID ?? DEFAULT_CLIENT_ID;
13
+ const clientSecret = process.env.GMAIL_MCP_CLIENT_SECRET ?? DEFAULT_CLIENT_SECRET;
14
+ return { clientId, clientSecret };
15
+ }
16
+ async function loadTokens() {
17
+ try {
18
+ const raw = await readFile(TOKENS_PATH, "utf-8");
19
+ return JSON.parse(raw);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ async function saveTokens(tokens) {
26
+ await mkdir(CONFIG_DIR, { recursive: true });
27
+ await writeFile(TOKENS_PATH, JSON.stringify(tokens, null, 2), {
28
+ mode: 0o600,
29
+ });
30
+ }
31
+ function authorizeViaLocalServer(oauth2Client) {
32
+ return new Promise((resolve, reject) => {
33
+ const authUrl = oauth2Client.generateAuthUrl({
34
+ access_type: "offline",
35
+ prompt: "consent",
36
+ scope: GMAIL_SCOPES,
37
+ });
38
+ const server = createServer(async (req, res) => {
39
+ try {
40
+ if (!req.url) {
41
+ res.writeHead(400);
42
+ res.end("Bad request");
43
+ return;
44
+ }
45
+ const url = new URL(req.url, `http://localhost:${OAUTH_PORT}`);
46
+ if (url.pathname !== "/oauth2callback") {
47
+ res.writeHead(404);
48
+ res.end("Not found");
49
+ return;
50
+ }
51
+ const code = url.searchParams.get("code");
52
+ const error = url.searchParams.get("error");
53
+ if (error) {
54
+ res.writeHead(400);
55
+ res.end(`Authorization denied: ${error}`);
56
+ reject(new Error(`OAuth authorization denied: ${error}`));
57
+ server.close();
58
+ return;
59
+ }
60
+ if (!code) {
61
+ res.writeHead(400);
62
+ res.end("Missing authorization code");
63
+ reject(new Error("Missing authorization code"));
64
+ server.close();
65
+ return;
66
+ }
67
+ const { tokens } = await oauth2Client.getToken(code);
68
+ oauth2Client.setCredentials(tokens);
69
+ await saveTokens(tokens);
70
+ res.writeHead(200, { "Content-Type": "text/html" });
71
+ res.end("<html><body><h1>Authorization successful!</h1>" +
72
+ "<p>You can close this window and return to your terminal.</p></body></html>");
73
+ server.close();
74
+ resolve();
75
+ }
76
+ catch (err) {
77
+ res.writeHead(500);
78
+ res.end("Authorization failed");
79
+ reject(err);
80
+ server.close();
81
+ }
82
+ });
83
+ server.listen(OAUTH_PORT, () => {
84
+ console.error("Opening browser for Gmail authorization...");
85
+ open(authUrl).catch(() => {
86
+ console.error(`Please open this URL manually:\n${authUrl}`);
87
+ });
88
+ });
89
+ server.on("error", (err) => {
90
+ reject(new Error(`Failed to start OAuth server on port ${OAUTH_PORT}: ${err.message}`));
91
+ });
92
+ });
93
+ }
94
+ export async function authenticate() {
95
+ const { clientId, clientSecret } = getCredentials();
96
+ const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, `http://localhost:${OAUTH_PORT}/oauth2callback`);
97
+ // Try loading existing tokens
98
+ const tokens = await loadTokens();
99
+ if (tokens) {
100
+ oauth2Client.setCredentials(tokens);
101
+ // Listen for token refresh events to persist new tokens
102
+ oauth2Client.on("tokens", (newTokens) => {
103
+ const merged = { ...tokens, ...newTokens };
104
+ saveTokens(merged).catch((err) => console.error("Failed to save refreshed tokens:", err));
105
+ });
106
+ console.error("Gmail MCP: Using stored credentials");
107
+ return oauth2Client;
108
+ }
109
+ // No tokens — run OAuth flow
110
+ await authorizeViaLocalServer(oauth2Client);
111
+ oauth2Client.on("tokens", (newTokens) => {
112
+ saveTokens(newTokens).catch((err) => console.error("Failed to save refreshed tokens:", err));
113
+ });
114
+ console.error("Gmail MCP: Authorization complete");
115
+ return oauth2Client;
116
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { type gmail_v1, google } from "googleapis";
2
+ type OAuth2Client = InstanceType<typeof google.auth.OAuth2>;
3
+ interface MessageHeader {
4
+ from: string;
5
+ to: string;
6
+ subject: string;
7
+ date: string;
8
+ }
9
+ export interface MessageSummary {
10
+ id: string;
11
+ threadId: string;
12
+ snippet: string;
13
+ headers: MessageHeader;
14
+ labelIds: string[];
15
+ }
16
+ export interface MessageDetail extends MessageSummary {
17
+ body: string;
18
+ }
19
+ export declare class GmailClient {
20
+ private gmail;
21
+ constructor(auth: OAuth2Client);
22
+ searchMessages(query: string, maxResults?: number): Promise<MessageSummary[]>;
23
+ getMessage(messageId: string, format?: "full" | "metadata" | "minimal"): Promise<MessageDetail>;
24
+ modifyMessage(messageId: string, addLabelIds?: string[], removeLabelIds?: string[]): Promise<void>;
25
+ trashMessage(messageId: string): Promise<void>;
26
+ untrashMessage(messageId: string): Promise<void>;
27
+ listLabels(): Promise<gmail_v1.Schema$Label[]>;
28
+ createLabel(name: string): Promise<gmail_v1.Schema$Label>;
29
+ deleteLabel(labelId: string): Promise<void>;
30
+ }
31
+ export {};
32
+ //# sourceMappingURL=gmail-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail-client.d.ts","sourceRoot":"","sources":["../src/gmail-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEnD,KAAK,YAAY,GAAG,YAAY,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAE5D,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,IAAI,EAAE,MAAM,CAAC;CACd;AAwED,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAiB;gBAElB,IAAI,EAAE,YAAY;IAIxB,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAW,GACtB,OAAO,CAAC,cAAc,EAAE,CAAC;IAqCtB,UAAU,CACd,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAAM,GAAG,UAAU,GAAG,SAAkB,GAC/C,OAAO,CAAC,aAAa,CAAC;IA0BnB,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAAM,EAAO,EAC1B,cAAc,GAAE,MAAM,EAAO,GAC5B,OAAO,CAAC,IAAI,CAAC;IAQV,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9C,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhD,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;IAK9C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAQzD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMlD"}
@@ -0,0 +1,158 @@
1
+ import { google } from "googleapis";
2
+ function extractHeaders(headers) {
3
+ const get = (name) => headers?.find((h) => h.name?.toLowerCase() === name.toLowerCase())?.value ??
4
+ "";
5
+ return {
6
+ from: get("From"),
7
+ to: get("To"),
8
+ subject: get("Subject"),
9
+ date: get("Date"),
10
+ };
11
+ }
12
+ function decodeBase64Url(data) {
13
+ return Buffer.from(data, "base64url").toString("utf-8");
14
+ }
15
+ function extractTextBody(payload) {
16
+ // Direct body
17
+ if (payload.mimeType === "text/plain" && payload.body?.data) {
18
+ return decodeBase64Url(payload.body.data);
19
+ }
20
+ // Multipart — recurse
21
+ if (payload.parts) {
22
+ // Prefer text/plain
23
+ for (const part of payload.parts) {
24
+ if (part.mimeType === "text/plain" && part.body?.data) {
25
+ return decodeBase64Url(part.body.data);
26
+ }
27
+ }
28
+ // Fall back to text/html with tag stripping
29
+ for (const part of payload.parts) {
30
+ if (part.mimeType === "text/html" && part.body?.data) {
31
+ return stripHtml(decodeBase64Url(part.body.data));
32
+ }
33
+ }
34
+ // Recurse into nested multipart
35
+ for (const part of payload.parts) {
36
+ const text = extractTextBody(part);
37
+ if (text)
38
+ return text;
39
+ }
40
+ }
41
+ // Fallback: HTML body at top level
42
+ if (payload.mimeType === "text/html" && payload.body?.data) {
43
+ return stripHtml(decodeBase64Url(payload.body.data));
44
+ }
45
+ return "";
46
+ }
47
+ function stripHtml(html) {
48
+ return html
49
+ .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "")
50
+ .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "")
51
+ .replace(/<br\s*\/?>/gi, "\n")
52
+ .replace(/<\/p>/gi, "\n\n")
53
+ .replace(/<[^>]+>/g, "")
54
+ .replace(/&nbsp;/g, " ")
55
+ .replace(/&amp;/g, "&")
56
+ .replace(/&lt;/g, "<")
57
+ .replace(/&gt;/g, ">")
58
+ .replace(/&quot;/g, '"')
59
+ .replace(/&#39;/g, "'")
60
+ .replace(/\n{3,}/g, "\n\n")
61
+ .trim();
62
+ }
63
+ export class GmailClient {
64
+ gmail;
65
+ constructor(auth) {
66
+ this.gmail = google.gmail({ version: "v1", auth });
67
+ }
68
+ async searchMessages(query, maxResults = 10) {
69
+ const res = await this.gmail.users.messages.list({
70
+ userId: "me",
71
+ q: query,
72
+ maxResults: Math.min(maxResults, 50),
73
+ });
74
+ const messageIds = res.data.messages ?? [];
75
+ if (messageIds.length === 0)
76
+ return [];
77
+ const messages = await Promise.all(messageIds
78
+ .filter((m) => m.id != null)
79
+ .map(async ({ id }) => {
80
+ const msg = await this.gmail.users.messages.get({
81
+ userId: "me",
82
+ id,
83
+ format: "metadata",
84
+ metadataHeaders: ["From", "To", "Subject", "Date"],
85
+ });
86
+ const data = msg.data;
87
+ if (!data.id || !data.threadId) {
88
+ throw new Error(`Invalid message data for id: ${id}`);
89
+ }
90
+ return {
91
+ id: data.id,
92
+ threadId: data.threadId,
93
+ snippet: data.snippet ?? "",
94
+ headers: extractHeaders(data.payload?.headers),
95
+ labelIds: data.labelIds ?? [],
96
+ };
97
+ }));
98
+ return messages;
99
+ }
100
+ async getMessage(messageId, format = "full") {
101
+ const msg = await this.gmail.users.messages.get({
102
+ userId: "me",
103
+ id: messageId,
104
+ format,
105
+ });
106
+ const body = format === "full" && msg.data.payload
107
+ ? extractTextBody(msg.data.payload)
108
+ : (msg.data.snippet ?? "");
109
+ const data = msg.data;
110
+ if (!data.id || !data.threadId) {
111
+ throw new Error(`Invalid message data for id: ${messageId}`);
112
+ }
113
+ return {
114
+ id: data.id,
115
+ threadId: data.threadId,
116
+ snippet: data.snippet ?? "",
117
+ headers: extractHeaders(data.payload?.headers),
118
+ labelIds: data.labelIds ?? [],
119
+ body,
120
+ };
121
+ }
122
+ async modifyMessage(messageId, addLabelIds = [], removeLabelIds = []) {
123
+ await this.gmail.users.messages.modify({
124
+ userId: "me",
125
+ id: messageId,
126
+ requestBody: { addLabelIds, removeLabelIds },
127
+ });
128
+ }
129
+ async trashMessage(messageId) {
130
+ await this.gmail.users.messages.trash({
131
+ userId: "me",
132
+ id: messageId,
133
+ });
134
+ }
135
+ async untrashMessage(messageId) {
136
+ await this.gmail.users.messages.untrash({
137
+ userId: "me",
138
+ id: messageId,
139
+ });
140
+ }
141
+ async listLabels() {
142
+ const res = await this.gmail.users.labels.list({ userId: "me" });
143
+ return res.data.labels ?? [];
144
+ }
145
+ async createLabel(name) {
146
+ const res = await this.gmail.users.labels.create({
147
+ userId: "me",
148
+ requestBody: { name },
149
+ });
150
+ return res.data;
151
+ }
152
+ async deleteLabel(labelId) {
153
+ await this.gmail.users.labels.delete({
154
+ userId: "me",
155
+ id: labelId,
156
+ });
157
+ }
158
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail-client.js","sourceRoot":"","sources":["../src/gmail-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/build/index.js ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { authenticate } from "./auth.js";
5
+ import { GmailClient } from "./gmail-client.js";
6
+ import { registerLabelTools, registerMessageTools } from "./tools/index.js";
7
+ async function main() {
8
+ const auth = await authenticate();
9
+ const gmailClient = new GmailClient(auth);
10
+ const server = new McpServer({
11
+ name: "gmail-mcp",
12
+ version: "0.1.0",
13
+ });
14
+ registerMessageTools(server, gmailClient);
15
+ registerLabelTools(server, gmailClient);
16
+ const transport = new StdioServerTransport();
17
+ await server.connect(transport);
18
+ console.error("Gmail MCP server running on stdio");
19
+ }
20
+ main().catch((error) => {
21
+ console.error("Fatal error:", error);
22
+ process.exit(1);
23
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;IAClC,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC1C,kBAAkB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAExC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACrD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { registerLabelTools } from "./labels.js";
2
+ export { registerMessageTools } from "./messages.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { registerLabelTools } from "./labels.js";
2
+ export { registerMessageTools } from "./messages.js";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { GmailClient } from "../gmail-client.js";
3
+ export declare function registerLabelTools(server: McpServer, gmail: GmailClient): void;
4
+ //# sourceMappingURL=labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/tools/labels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAqBtD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,WAAW,GACjB,IAAI,CAqGN"}
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+ function errorResponse(message) {
3
+ return {
4
+ content: [{ type: "text", text: `Error: ${message}` }],
5
+ isError: true,
6
+ };
7
+ }
8
+ function wrapGmailError(err) {
9
+ const error = err;
10
+ const code = error.code;
11
+ const msg = error.message ?? String(err);
12
+ if (code === 404)
13
+ return errorResponse("Label not found");
14
+ if (code === 400)
15
+ return errorResponse(`Invalid request: ${msg}`);
16
+ if (code === 403)
17
+ return errorResponse("Insufficient permissions");
18
+ if (code === 429)
19
+ return errorResponse("Rate limited — try again later");
20
+ return errorResponse(msg);
21
+ }
22
+ export function registerLabelTools(server, gmail) {
23
+ server.tool("gmail_list_labels", "List all Gmail labels", {}, async () => {
24
+ try {
25
+ const labels = await gmail.listLabels();
26
+ const text = labels
27
+ .map((l) => `${l.id}: ${l.name} (type: ${l.type ?? "user"})`)
28
+ .join("\n");
29
+ return { content: [{ type: "text", text: text || "No labels found." }] };
30
+ }
31
+ catch (err) {
32
+ return wrapGmailError(err);
33
+ }
34
+ });
35
+ server.tool("gmail_add_label", "Add a label to a message", {
36
+ messageId: z.string().describe("Gmail message ID"),
37
+ labelId: z.string().describe("Label ID to add"),
38
+ }, async ({ messageId, labelId }) => {
39
+ try {
40
+ await gmail.modifyMessage(messageId, [labelId], []);
41
+ return {
42
+ content: [
43
+ {
44
+ type: "text",
45
+ text: `Label ${labelId} added to message ${messageId}.`,
46
+ },
47
+ ],
48
+ };
49
+ }
50
+ catch (err) {
51
+ return wrapGmailError(err);
52
+ }
53
+ });
54
+ server.tool("gmail_remove_label", "Remove a label from a message", {
55
+ messageId: z.string().describe("Gmail message ID"),
56
+ labelId: z.string().describe("Label ID to remove"),
57
+ }, async ({ messageId, labelId }) => {
58
+ try {
59
+ await gmail.modifyMessage(messageId, [], [labelId]);
60
+ return {
61
+ content: [
62
+ {
63
+ type: "text",
64
+ text: `Label ${labelId} removed from message ${messageId}.`,
65
+ },
66
+ ],
67
+ };
68
+ }
69
+ catch (err) {
70
+ return wrapGmailError(err);
71
+ }
72
+ });
73
+ server.tool("gmail_create_label", "Create a new Gmail label", {
74
+ name: z.string().describe("Label name"),
75
+ }, async ({ name }) => {
76
+ try {
77
+ const label = await gmail.createLabel(name);
78
+ return {
79
+ content: [
80
+ {
81
+ type: "text",
82
+ text: `Label created: ${label.id} (${label.name})`,
83
+ },
84
+ ],
85
+ };
86
+ }
87
+ catch (err) {
88
+ return wrapGmailError(err);
89
+ }
90
+ });
91
+ server.tool("gmail_delete_label", "Delete a Gmail label", {
92
+ labelId: z.string().describe("Label ID to delete"),
93
+ }, async ({ labelId }) => {
94
+ try {
95
+ await gmail.deleteLabel(labelId);
96
+ return {
97
+ content: [{ type: "text", text: `Label ${labelId} deleted.` }],
98
+ };
99
+ }
100
+ catch (err) {
101
+ return wrapGmailError(err);
102
+ }
103
+ });
104
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.js","sourceRoot":"","sources":["../../src/tools/labels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { GmailClient } from "../gmail-client.js";
3
+ export declare function registerMessageTools(server: McpServer, gmail: GmailClient): void;
4
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,oBAAoB,CAAC;AAgD5B,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,WAAW,GACjB,IAAI,CAoLN"}
@@ -0,0 +1,181 @@
1
+ import { z } from "zod";
2
+ function formatMessageSummary(msg) {
3
+ return [
4
+ `ID: ${msg.id}`,
5
+ `Thread: ${msg.threadId}`,
6
+ `From: ${msg.headers.from}`,
7
+ `To: ${msg.headers.to}`,
8
+ `Subject: ${msg.headers.subject}`,
9
+ `Date: ${msg.headers.date}`,
10
+ `Labels: ${msg.labelIds.join(", ")}`,
11
+ `Snippet: ${msg.snippet}`,
12
+ ].join("\n");
13
+ }
14
+ function formatMessageDetail(msg) {
15
+ return [
16
+ `ID: ${msg.id}`,
17
+ `Thread: ${msg.threadId}`,
18
+ `From: ${msg.headers.from}`,
19
+ `To: ${msg.headers.to}`,
20
+ `Subject: ${msg.headers.subject}`,
21
+ `Date: ${msg.headers.date}`,
22
+ `Labels: ${msg.labelIds.join(", ")}`,
23
+ "",
24
+ msg.body,
25
+ ].join("\n");
26
+ }
27
+ function errorResponse(message) {
28
+ return {
29
+ content: [{ type: "text", text: `Error: ${message}` }],
30
+ isError: true,
31
+ };
32
+ }
33
+ function wrapGmailError(err) {
34
+ const error = err;
35
+ const code = error.code;
36
+ const msg = error.message ?? String(err);
37
+ if (code === 404)
38
+ return errorResponse("Message not found");
39
+ if (code === 400)
40
+ return errorResponse(`Invalid request: ${msg}`);
41
+ if (code === 403)
42
+ return errorResponse("Insufficient permissions");
43
+ if (code === 429)
44
+ return errorResponse("Rate limited — try again later");
45
+ return errorResponse(msg);
46
+ }
47
+ export function registerMessageTools(server, gmail) {
48
+ server.tool("gmail_search", "Search Gmail messages using Gmail query syntax (e.g. 'from:user@example.com', 'is:unread', 'subject:hello')", {
49
+ query: z.string().describe("Gmail search query"),
50
+ maxResults: z
51
+ .number()
52
+ .min(1)
53
+ .max(50)
54
+ .default(10)
55
+ .describe("Max results (1-50)"),
56
+ }, async ({ query, maxResults }) => {
57
+ try {
58
+ const messages = await gmail.searchMessages(query, maxResults);
59
+ if (messages.length === 0) {
60
+ return { content: [{ type: "text", text: "No messages found." }] };
61
+ }
62
+ const text = messages.map(formatMessageSummary).join("\n\n---\n\n");
63
+ return { content: [{ type: "text", text }] };
64
+ }
65
+ catch (err) {
66
+ return wrapGmailError(err);
67
+ }
68
+ });
69
+ server.tool("gmail_get_message", "Get the full content of a Gmail message by ID", {
70
+ messageId: z.string().describe("Gmail message ID"),
71
+ }, async ({ messageId }) => {
72
+ try {
73
+ const msg = await gmail.getMessage(messageId, "full");
74
+ return { content: [{ type: "text", text: formatMessageDetail(msg) }] };
75
+ }
76
+ catch (err) {
77
+ return wrapGmailError(err);
78
+ }
79
+ });
80
+ server.tool("gmail_archive", "Archive a message (remove from inbox)", {
81
+ messageId: z.string().describe("Gmail message ID"),
82
+ }, async ({ messageId }) => {
83
+ try {
84
+ await gmail.modifyMessage(messageId, [], ["INBOX"]);
85
+ return {
86
+ content: [{ type: "text", text: `Message ${messageId} archived.` }],
87
+ };
88
+ }
89
+ catch (err) {
90
+ return wrapGmailError(err);
91
+ }
92
+ });
93
+ server.tool("gmail_batch_archive", "Archive multiple messages", {
94
+ messageIds: z.array(z.string()).describe("List of Gmail message IDs"),
95
+ }, async ({ messageIds }) => {
96
+ try {
97
+ await Promise.all(messageIds.map((id) => gmail.modifyMessage(id, [], ["INBOX"])));
98
+ return {
99
+ content: [
100
+ { type: "text", text: `${messageIds.length} messages archived.` },
101
+ ],
102
+ };
103
+ }
104
+ catch (err) {
105
+ return wrapGmailError(err);
106
+ }
107
+ });
108
+ server.tool("gmail_trash", "Move a message to trash", {
109
+ messageId: z.string().describe("Gmail message ID"),
110
+ }, async ({ messageId }) => {
111
+ try {
112
+ await gmail.trashMessage(messageId);
113
+ return {
114
+ content: [{ type: "text", text: `Message ${messageId} trashed.` }],
115
+ };
116
+ }
117
+ catch (err) {
118
+ return wrapGmailError(err);
119
+ }
120
+ });
121
+ server.tool("gmail_batch_trash", "Move multiple messages to trash", {
122
+ messageIds: z.array(z.string()).describe("List of Gmail message IDs"),
123
+ }, async ({ messageIds }) => {
124
+ try {
125
+ await Promise.all(messageIds.map((id) => gmail.trashMessage(id)));
126
+ return {
127
+ content: [
128
+ { type: "text", text: `${messageIds.length} messages trashed.` },
129
+ ],
130
+ };
131
+ }
132
+ catch (err) {
133
+ return wrapGmailError(err);
134
+ }
135
+ });
136
+ server.tool("gmail_untrash", "Remove a message from trash", {
137
+ messageId: z.string().describe("Gmail message ID"),
138
+ }, async ({ messageId }) => {
139
+ try {
140
+ await gmail.untrashMessage(messageId);
141
+ return {
142
+ content: [
143
+ { type: "text", text: `Message ${messageId} removed from trash.` },
144
+ ],
145
+ };
146
+ }
147
+ catch (err) {
148
+ return wrapGmailError(err);
149
+ }
150
+ });
151
+ server.tool("gmail_mark_read", "Mark a message as read", {
152
+ messageId: z.string().describe("Gmail message ID"),
153
+ }, async ({ messageId }) => {
154
+ try {
155
+ await gmail.modifyMessage(messageId, [], ["UNREAD"]);
156
+ return {
157
+ content: [
158
+ { type: "text", text: `Message ${messageId} marked as read.` },
159
+ ],
160
+ };
161
+ }
162
+ catch (err) {
163
+ return wrapGmailError(err);
164
+ }
165
+ });
166
+ server.tool("gmail_mark_unread", "Mark a message as unread", {
167
+ messageId: z.string().describe("Gmail message ID"),
168
+ }, async ({ messageId }) => {
169
+ try {
170
+ await gmail.modifyMessage(messageId, ["UNREAD"], []);
171
+ return {
172
+ content: [
173
+ { type: "text", text: `Message ${messageId} marked as unread.` },
174
+ ],
175
+ };
176
+ }
177
+ catch (err) {
178
+ return wrapGmailError(err);
179
+ }
180
+ });
181
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const CONFIG_DIR: string;
2
+ export declare const CREDENTIALS_PATH: string;
3
+ export declare const TOKENS_PATH: string;
4
+ export declare const OAUTH_PORT: number;
5
+ export declare const GMAIL_SCOPES: string[];
6
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,QAAgC,CAAC;AACxD,eAAO,MAAM,gBAAgB,QAES,CAAC;AACvC,eAAO,MAAM,WAAW,QAC8C,CAAC;AACvE,eAAO,MAAM,UAAU,QAAqD,CAAC;AAE7E,eAAO,MAAM,YAAY,UAIxB,CAAC"}
package/build/types.js ADDED
@@ -0,0 +1,10 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ export const CONFIG_DIR = join(homedir(), ".gmail-mcp");
4
+ export const TOKENS_PATH = process.env.GMAIL_MCP_TOKENS_PATH ?? join(CONFIG_DIR, "tokens.json");
5
+ export const OAUTH_PORT = Number(process.env.GMAIL_MCP_OAUTH_PORT ?? "3000");
6
+ export const GMAIL_SCOPES = [
7
+ "https://www.googleapis.com/auth/gmail.readonly",
8
+ "https://www.googleapis.com/auth/gmail.modify",
9
+ "https://www.googleapis.com/auth/gmail.labels",
10
+ ];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,gBAAgB,GAC3B,OAAO,CAAC,GAAG,CAAC,0BAA0B;IACtC,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GACtB,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACvE,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,MAAM,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,gDAAgD;IAChD,8CAA8C;IAC9C,8CAA8C;CAC/C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@d-mato/gmail-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Gmail - search, read, archive, and manage your email",
5
+ "type": "module",
6
+ "bin": {
7
+ "gmail-mcp": "./build/index.js"
8
+ },
9
+ "files": [
10
+ "build"
11
+ ],
12
+ "keywords": [
13
+ "mcp",
14
+ "gmail",
15
+ "email",
16
+ "model-context-protocol"
17
+ ],
18
+ "license": "MIT",
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/d-mato/gmail-mcp"
25
+ },
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.12.0",
28
+ "googleapis": "^148.0.0",
29
+ "open": "^10.0.0",
30
+ "zod": "^3.24.0"
31
+ },
32
+ "devDependencies": {
33
+ "@biomejs/biome": "^2.4.8",
34
+ "@types/node": "^22.0.0",
35
+ "typescript": "6.0.0-beta"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "dev": "tsc --watch",
40
+ "typecheck": "tsc --noEmit",
41
+ "lint": "biome check .",
42
+ "lint:fix": "biome check --write ."
43
+ }
44
+ }