@node2flow/gmail-mcp 1.0.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/src/types.ts ADDED
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Gmail API v1 Types
3
+ */
4
+
5
+ // ========== Message ==========
6
+
7
+ export interface Message {
8
+ id: string;
9
+ threadId: string;
10
+ labelIds?: string[];
11
+ snippet?: string;
12
+ historyId?: string;
13
+ internalDate?: string;
14
+ payload?: MessagePart;
15
+ sizeEstimate?: number;
16
+ raw?: string;
17
+ }
18
+
19
+ export interface MessagePart {
20
+ partId?: string;
21
+ mimeType?: string;
22
+ filename?: string;
23
+ headers?: MessagePartHeader[];
24
+ body?: MessagePartBody;
25
+ parts?: MessagePart[];
26
+ }
27
+
28
+ export interface MessagePartHeader {
29
+ name: string;
30
+ value: string;
31
+ }
32
+
33
+ export interface MessagePartBody {
34
+ attachmentId?: string;
35
+ size?: number;
36
+ data?: string;
37
+ }
38
+
39
+ export interface MessageList {
40
+ messages?: MessageRef[];
41
+ nextPageToken?: string;
42
+ resultSizeEstimate?: number;
43
+ }
44
+
45
+ export interface MessageRef {
46
+ id: string;
47
+ threadId: string;
48
+ }
49
+
50
+ // ========== Thread ==========
51
+
52
+ export interface Thread {
53
+ id: string;
54
+ historyId?: string;
55
+ messages?: Message[];
56
+ snippet?: string;
57
+ }
58
+
59
+ export interface ThreadList {
60
+ threads?: ThreadRef[];
61
+ nextPageToken?: string;
62
+ resultSizeEstimate?: number;
63
+ }
64
+
65
+ export interface ThreadRef {
66
+ id: string;
67
+ historyId?: string;
68
+ snippet?: string;
69
+ }
70
+
71
+ // ========== Label ==========
72
+
73
+ export interface Label {
74
+ id: string;
75
+ name: string;
76
+ messageListVisibility?: 'show' | 'hide';
77
+ labelListVisibility?: 'labelShow' | 'labelShowIfUnread' | 'labelHide';
78
+ type?: 'system' | 'user';
79
+ messagesTotal?: number;
80
+ messagesUnread?: number;
81
+ threadsTotal?: number;
82
+ threadsUnread?: number;
83
+ color?: LabelColor;
84
+ }
85
+
86
+ export interface LabelColor {
87
+ textColor?: string;
88
+ backgroundColor?: string;
89
+ }
90
+
91
+ export interface LabelList {
92
+ labels: Label[];
93
+ }
94
+
95
+ // ========== Draft ==========
96
+
97
+ export interface Draft {
98
+ id: string;
99
+ message?: Message;
100
+ }
101
+
102
+ export interface DraftList {
103
+ drafts?: DraftRef[];
104
+ nextPageToken?: string;
105
+ resultSizeEstimate?: number;
106
+ }
107
+
108
+ export interface DraftRef {
109
+ id: string;
110
+ message?: MessageRef;
111
+ }
112
+
113
+ // ========== Profile ==========
114
+
115
+ export interface Profile {
116
+ emailAddress: string;
117
+ messagesTotal: number;
118
+ threadsTotal: number;
119
+ historyId: string;
120
+ }
121
+
122
+ // ========== Vacation Settings ==========
123
+
124
+ export interface VacationSettings {
125
+ enableAutoReply: boolean;
126
+ responseSubject?: string;
127
+ responseBodyPlainText?: string;
128
+ responseBodyHtml?: string;
129
+ restrictToContacts?: boolean;
130
+ restrictToDomain?: boolean;
131
+ startTime?: string;
132
+ endTime?: string;
133
+ }
134
+
135
+ // ========== History ==========
136
+
137
+ export interface HistoryList {
138
+ history?: HistoryRecord[];
139
+ nextPageToken?: string;
140
+ historyId: string;
141
+ }
142
+
143
+ export interface HistoryRecord {
144
+ id: string;
145
+ messages?: Message[];
146
+ messagesAdded?: MessageAdded[];
147
+ messagesDeleted?: MessageDeleted[];
148
+ labelsAdded?: LabelModification[];
149
+ labelsRemoved?: LabelModification[];
150
+ }
151
+
152
+ export interface MessageAdded {
153
+ message: Message;
154
+ }
155
+
156
+ export interface MessageDeleted {
157
+ message: Message;
158
+ }
159
+
160
+ export interface LabelModification {
161
+ message: Message;
162
+ labelIds: string[];
163
+ }
164
+
165
+ // ========== Filter ==========
166
+
167
+ export interface Filter {
168
+ id: string;
169
+ criteria?: FilterCriteria;
170
+ action?: FilterAction;
171
+ }
172
+
173
+ export interface FilterCriteria {
174
+ from?: string;
175
+ to?: string;
176
+ subject?: string;
177
+ query?: string;
178
+ negatedQuery?: string;
179
+ hasAttachment?: boolean;
180
+ excludeChats?: boolean;
181
+ size?: number;
182
+ sizeComparison?: 'larger' | 'smaller';
183
+ }
184
+
185
+ export interface FilterAction {
186
+ addLabelIds?: string[];
187
+ removeLabelIds?: string[];
188
+ forward?: string;
189
+ }
190
+
191
+ export interface FilterList {
192
+ filter: Filter[];
193
+ }
194
+
195
+ // ========== Attachment ==========
196
+
197
+ export interface Attachment {
198
+ size: number;
199
+ data: string;
200
+ }
201
+
202
+ // ========== Modify Request ==========
203
+
204
+ export interface ModifyRequest {
205
+ addLabelIds?: string[];
206
+ removeLabelIds?: string[];
207
+ }
208
+
209
+ // ========== Batch Request ==========
210
+
211
+ export interface BatchDeleteRequest {
212
+ ids: string[];
213
+ }
214
+
215
+ export interface BatchModifyRequest {
216
+ ids: string[];
217
+ addLabelIds?: string[];
218
+ removeLabelIds?: string[];
219
+ }
220
+
221
+ // ========== Tool Definition ==========
222
+
223
+ export interface MCPToolDefinition {
224
+ name: string;
225
+ description: string;
226
+ inputSchema: {
227
+ type: 'object';
228
+ properties: Record<string, unknown>;
229
+ required?: string[];
230
+ };
231
+ annotations?: {
232
+ title?: string;
233
+ readOnlyHint?: boolean;
234
+ destructiveHint?: boolean;
235
+ idempotentHint?: boolean;
236
+ openWorldHint?: boolean;
237
+ };
238
+ }
package/src/worker.ts ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Cloudflare Worker entry — Stateless Streamable HTTP MCP
3
+ */
4
+
5
+ import {
6
+ WebStandardStreamableHTTPServerTransport,
7
+ } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
8
+
9
+ import { createServer } from './server.js';
10
+ import { TOOLS } from './tools.js';
11
+
12
+ function corsHeaders(): Record<string, string> {
13
+ return {
14
+ 'Access-Control-Allow-Origin': '*',
15
+ 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
16
+ 'Access-Control-Allow-Headers': 'Content-Type, mcp-session-id, Accept, mcp-protocol-version',
17
+ 'Access-Control-Expose-Headers': 'mcp-session-id',
18
+ };
19
+ }
20
+
21
+ function addCors(response: Response): Response {
22
+ const headers = new Headers(response.headers);
23
+ for (const [key, value] of Object.entries(corsHeaders())) {
24
+ headers.set(key, value);
25
+ }
26
+ return new Response(response.body, {
27
+ status: response.status,
28
+ statusText: response.statusText,
29
+ headers,
30
+ });
31
+ }
32
+
33
+ export default {
34
+ async fetch(request: Request): Promise<Response> {
35
+ const url = new URL(request.url);
36
+
37
+ if (request.method === 'OPTIONS') {
38
+ return new Response(null, { status: 204, headers: corsHeaders() });
39
+ }
40
+
41
+ if (url.pathname === '/' && request.method === 'GET') {
42
+ return addCors(Response.json({
43
+ name: 'gmail-mcp',
44
+ version: '1.0.0',
45
+ status: 'ok',
46
+ tools: TOOLS.length,
47
+ transport: 'streamable-http',
48
+ endpoints: { mcp: '/mcp' },
49
+ }));
50
+ }
51
+
52
+ if (url.pathname !== '/mcp') {
53
+ return addCors(new Response('Not Found', { status: 404 }));
54
+ }
55
+
56
+ if (request.method !== 'POST') {
57
+ return addCors(Response.json(
58
+ { jsonrpc: '2.0', error: { code: -32000, message: 'Method not allowed. Use POST.' }, id: null },
59
+ { status: 405 }
60
+ ));
61
+ }
62
+
63
+ const clientId = url.searchParams.get('GOOGLE_CLIENT_ID') || '';
64
+ const clientSecret = url.searchParams.get('GOOGLE_CLIENT_SECRET') || '';
65
+ const refreshToken = url.searchParams.get('GOOGLE_REFRESH_TOKEN') || '';
66
+ const config = clientId && clientSecret && refreshToken
67
+ ? { clientId, clientSecret, refreshToken }
68
+ : undefined;
69
+
70
+ try {
71
+ const transport = new WebStandardStreamableHTTPServerTransport({
72
+ sessionIdGenerator: undefined,
73
+ enableJsonResponse: true,
74
+ });
75
+
76
+ const server = createServer(config);
77
+ await server.connect(transport);
78
+
79
+ const response = await transport.handleRequest(request);
80
+ return addCors(response);
81
+ } catch (error: any) {
82
+ return addCors(Response.json(
83
+ { jsonrpc: '2.0', error: { code: -32603, message: error.message || 'Internal server error' }, id: null },
84
+ { status: 500 }
85
+ ));
86
+ }
87
+ },
88
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
package/wrangler.toml ADDED
@@ -0,0 +1,14 @@
1
+ name = "gmail-mcp-community"
2
+ main = "src/worker.ts"
3
+ compatibility_date = "2025-01-01"
4
+ workers_dev = true
5
+
6
+ [[routes]]
7
+ pattern = "gmail-mcp-community.node2flow.net"
8
+ custom_domain = true
9
+
10
+ [placement]
11
+ mode = "smart"
12
+
13
+ [observability]
14
+ enabled = true