@forwardemail/mcp-server 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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: Forward Email LLC
6
+ Licensed Work: @forwardemail/mcp-server
7
+ The Licensed Work is (c) 2025 Forward Email LLC.
8
+ Additional Use Grant: You may make use of the Licensed Work, provided that
9
+ you may not use the Licensed Work for an Email Service
10
+ that is Competitive with the Licensed Work.
11
+
12
+ A "Competitive" service is a service that offers
13
+ email forwarding, email hosting, or email API services
14
+ that are substantially similar to those offered by
15
+ Forward Email (https://forwardemail.net).
16
+
17
+ Change Date: Four years from the date the Licensed Work is published.
18
+
19
+ Change License: MIT
20
+
21
+ For information about alternative licensing arrangements for the Licensed Work,
22
+ please visit: https://forwardemail.net
package/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # @forwardemail/mcp-server
2
+
3
+ [Model Context Protocol](https://github.com/modelcontextprotocol/specification) (MCP) server for [Forward Email](https://forwardemail.net). Connect AI assistants to your inbox.
4
+
5
+ ## Overview
6
+
7
+ This package provides a local MCP server that wraps the [Forward Email API](https://forwardemail.net/email-api). It lets AI agents (Claude, ChatGPT, Cursor, Windsurf, and others) send email, manage domains, and read your inbox through natural language.
8
+
9
+ The server runs locally on your machine via `stdio`. Your API key never leaves your device.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g @forwardemail/mcp-server
15
+ ```
16
+
17
+ Or run directly with `npx`:
18
+
19
+ ```bash
20
+ npx @forwardemail/mcp-server
21
+ ```
22
+
23
+ ## Setup
24
+
25
+ ### 1. Get your API key
26
+
27
+ Log in at <https://forwardemail.net/my-account/security> and copy your API key.
28
+
29
+ ### 2. Set the environment variable
30
+
31
+ ```bash
32
+ export FORWARD_EMAIL_API_KEY=your-api-key
33
+ ```
34
+
35
+ ### 3. Configure your AI client
36
+
37
+ #### Claude Desktop
38
+
39
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "forwardemail": {
45
+ "command": "npx",
46
+ "args": ["@forwardemail/mcp-server"],
47
+ "env": {
48
+ "FORWARD_EMAIL_API_KEY": "your-api-key"
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ #### Cursor
56
+
57
+ Add to `.cursor/mcp.json` in your project:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "forwardemail": {
63
+ "command": "npx",
64
+ "args": ["@forwardemail/mcp-server"],
65
+ "env": {
66
+ "FORWARD_EMAIL_API_KEY": "your-api-key"
67
+ }
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ ## Available Tools
74
+
75
+ This server exposes the complete [Forward Email API](https://forwardemail.net/email-api) as MCP tools. Every endpoint is covered.
76
+
77
+ ### Account
78
+
79
+ * `getAccount` - Get your account details
80
+ * `updateAccount` - Update your account
81
+
82
+ ### Logs
83
+
84
+ * `downloadLogs` - Download email delivery logs
85
+
86
+ ### Contacts (CardDAV)
87
+
88
+ * `listContacts` - List all contacts
89
+ * `createContact` - Create a contact
90
+ * `getContact` - Get a contact by ID
91
+ * `updateContact` - Update a contact
92
+ * `deleteContact` - Delete a contact
93
+
94
+ ### Calendars (CalDAV)
95
+
96
+ * `listCalendars` - List all calendars
97
+ * `createCalendar` - Create a calendar
98
+ * `getCalendar` - Get a calendar by ID
99
+ * `updateCalendar` - Update a calendar
100
+ * `deleteCalendar` - Delete a calendar
101
+
102
+ ### Calendar Events (CalDAV)
103
+
104
+ * `listCalendarEvents` - List all calendar events
105
+ * `createCalendarEvent` - Create a calendar event
106
+ * `getCalendarEvent` - Get a calendar event by ID
107
+ * `updateCalendarEvent` - Update a calendar event
108
+ * `deleteCalendarEvent` - Delete a calendar event
109
+
110
+ ### Domains
111
+
112
+ * `listDomains` - List all domains
113
+ * `createDomain` - Create a new domain
114
+ * `getDomain` - Get a domain by ID or name
115
+ * `updateDomain` - Update a domain
116
+ * `deleteDomain` - Delete a domain
117
+ * `verifyDomainRecords` - Verify domain DNS records
118
+ * `verifySmtpRecords` - Verify domain SMTP records
119
+ * `testS3Connection` - Test custom S3 connection for a domain
120
+
121
+ ### Domain Catch-All Passwords
122
+
123
+ * `listCatchAllPasswords` - List domain-wide catch-all passwords
124
+ * `createCatchAllPassword` - Create a domain-wide catch-all password
125
+ * `deleteCatchAllPassword` - Remove a domain-wide catch-all password
126
+
127
+ ### Domain Invites
128
+
129
+ * `acceptDomainInvite` - Accept a domain invite
130
+ * `createDomainInvite` - Invite a user to a domain
131
+ * `removeDomainInvite` - Remove a domain invite
132
+
133
+ ### Domain Members
134
+
135
+ * `updateDomainMember` - Update a domain member role
136
+ * `removeDomainMember` - Remove a member from a domain
137
+
138
+ ### Aliases
139
+
140
+ * `listAliases` - List aliases for a domain
141
+ * `createAlias` - Create a new alias
142
+ * `getAlias` - Get an alias by ID
143
+ * `updateAlias` - Update an alias
144
+ * `deleteAlias` - Delete an alias
145
+ * `generateAliasPassword` - Generate or set a password for an alias
146
+
147
+ ### Sieve Scripts
148
+
149
+ * `listSieveScripts` - List Sieve scripts for an alias
150
+ * `createSieveScript` - Create a Sieve script for an alias
151
+ * `getSieveScript` - Get a Sieve script by ID
152
+ * `updateSieveScript` - Update a Sieve script
153
+ * `deleteSieveScript` - Delete a Sieve script
154
+ * `activateSieveScript` - Activate a Sieve script
155
+
156
+ ### Sieve Scripts (Alias Auth)
157
+
158
+ * `listSieveScriptsAliasAuth` - List Sieve scripts (alias auth)
159
+ * `createSieveScriptAliasAuth` - Create a Sieve script (alias auth)
160
+ * `getSieveScriptAliasAuth` - Get a Sieve script (alias auth)
161
+ * `updateSieveScriptAliasAuth` - Update a Sieve script (alias auth)
162
+ * `deleteSieveScriptAliasAuth` - Delete a Sieve script (alias auth)
163
+ * `activateSieveScriptAliasAuth` - Activate a Sieve script (alias auth)
164
+
165
+ ### Emails (Outbound SMTP)
166
+
167
+ * `listEmails` - List outbound SMTP emails
168
+ * `sendEmail` - Send an email via outbound SMTP
169
+ * `getEmailLimit` - Get outbound SMTP email sending limit
170
+ * `getEmail` - Get an outbound SMTP email by ID
171
+ * `deleteEmail` - Delete an outbound SMTP email
172
+
173
+ ### Messages (IMAP)
174
+
175
+ * `listMessages` - List and search messages in a folder
176
+ * `createMessage` - Create a new message (draft)
177
+ * `getMessage` - Get a message by ID
178
+ * `updateMessage` - Update a message
179
+ * `deleteMessage` - Delete a message
180
+
181
+ ### Folders (IMAP)
182
+
183
+ * `listFolders` - List all folders
184
+ * `createFolder` - Create a new folder
185
+ * `getFolder` - Get a folder by ID
186
+ * `updateFolder` - Update a folder
187
+ * `deleteFolder` - Delete a folder
188
+
189
+ ### Encrypt
190
+
191
+ * `encryptRecord` - Encrypt a plaintext Forward Email TXT record
192
+
193
+ ## Development
194
+
195
+ ```bash
196
+ git clone https://github.com/forwardemail/mcp-server.git
197
+ cd mcp-server
198
+ pnpm install
199
+ pnpm test
200
+ ```
201
+
202
+ ## License
203
+
204
+ [BUSL-1.1](LICENSE)
205
+
206
+ ## Links
207
+
208
+ * [Forward Email](https://forwardemail.net)
209
+ * [Forward Email API Docs](https://forwardemail.net/email-api)
210
+ * [MCP Specification](https://github.com/modelcontextprotocol/specification)
211
+ * [MCP Landing Page](https://forwardemail.net/mcp)
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ const {McpServer} = require('../lib/index.js');
3
+
4
+ const server = new McpServer();
5
+ server.listen();
package/lib/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export type McpServerOptions = {
2
+ apiKey?: string;
3
+ baseURL?: string;
4
+ };
5
+
6
+ export class McpServer {
7
+ constructor(options?: McpServerOptions);
8
+ listen(): void;
9
+ }
package/lib/index.js ADDED
@@ -0,0 +1,63 @@
1
+ const readline = require('node:readline');
2
+ const {getTools} = require('./tools.js');
3
+
4
+ class McpServer {
5
+ constructor(options = {}) {
6
+ this.tools = getTools(options);
7
+ this.rl = readline.createInterface({
8
+ input: process.stdin,
9
+ output: process.stdout,
10
+ terminal: false,
11
+ });
12
+ }
13
+
14
+ listen() {
15
+ this.rl.on('line', async (line) => {
16
+ try {
17
+ const request = JSON.parse(line);
18
+ await this.handleRequest(request);
19
+ } catch (error) {
20
+ this.sendError(error.message);
21
+ }
22
+ });
23
+ }
24
+
25
+ async handleRequest(request) {
26
+ if (request.type === 'listTools') {
27
+ return this.sendResponse(request.id, {
28
+ tools: Object.values(this.tools).map((tool) => tool.toolSpec),
29
+ });
30
+ }
31
+
32
+ if (request.type === 'invokeTool') {
33
+ const tool = this.tools[request.name];
34
+ if (tool) {
35
+ try {
36
+ const result = await tool.invoke(request.arguments);
37
+ return this.sendResponse(request.id, {result});
38
+ } catch (error) {
39
+ const errorMessage = error.response?.data?.message || error.message;
40
+ return this.sendError(errorMessage, request.id);
41
+ }
42
+ }
43
+
44
+ return this.sendError(`Tool not found: ${request.name}`, request.id);
45
+ }
46
+
47
+ return this.sendError(`Unknown request type: ${request.type}`, request.id);
48
+ }
49
+
50
+ sendResponse(id, payload) {
51
+ this.send({type: 'toolResponse', id, ...payload});
52
+ }
53
+
54
+ sendError(message, id = null) {
55
+ this.send({type: 'error', id, message});
56
+ }
57
+
58
+ send(data) {
59
+ process.stdout.write(JSON.stringify(data) + '\n');
60
+ }
61
+ }
62
+
63
+ module.exports = {McpServer};
package/lib/tools.js ADDED
@@ -0,0 +1,577 @@
1
+ const axios = require('axios');
2
+
3
+ const getTools = (options = {}) => {
4
+ const client = axios.create({
5
+ baseURL: options.baseURL || 'https://api.forwardemail.net',
6
+ headers: {
7
+ Authorization: `Bearer ${options.apiKey || process.env.FORWARD_EMAIL_API_KEY}`,
8
+ },
9
+ });
10
+
11
+ const createTool = (spec) => ({
12
+ toolSpec: {
13
+ name: spec.name,
14
+ description: spec.description,
15
+ input: {
16
+ type: 'object',
17
+ properties: spec.inputs || {},
18
+ },
19
+ },
20
+ async invoke(arguments_) {
21
+ let {path} = spec;
22
+ const pathParameters = path.match(/{(\w+)}/g) || [];
23
+ const queryArguments = {};
24
+ const bodyArguments = {};
25
+
26
+ for (const key in arguments_) {
27
+ if (Object.hasOwn(arguments_, key)) {
28
+ if (pathParameters.includes(`{${key}}`)) {
29
+ path = path.replace(`{${key}}`, arguments_[key]);
30
+ } else if (spec.query && spec.query.includes(key)) {
31
+ queryArguments[key] = arguments_[key];
32
+ } else {
33
+ bodyArguments[key] = arguments_[key];
34
+ }
35
+ }
36
+ }
37
+
38
+ const config = {params: queryArguments};
39
+ const hasBody = Object.keys(bodyArguments).length > 0;
40
+
41
+ let response;
42
+ if (spec.method === 'get' || spec.method === 'delete') {
43
+ response = await client[spec.method](path, config);
44
+ } else {
45
+ response = await client[spec.method](
46
+ path,
47
+ hasBody ? bodyArguments : undefined,
48
+ config,
49
+ );
50
+ }
51
+
52
+ return response.data;
53
+ },
54
+ });
55
+
56
+ const tools = {
57
+ //
58
+ // Account
59
+ //
60
+ getAccount: createTool({
61
+ name: 'getAccount',
62
+ description: 'Get your account details',
63
+ method: 'get',
64
+ path: '/v1/account',
65
+ }),
66
+ updateAccount: createTool({
67
+ name: 'updateAccount',
68
+ description: 'Update your account',
69
+ method: 'put',
70
+ path: '/v1/account',
71
+ }),
72
+
73
+ //
74
+ // Logs
75
+ //
76
+ downloadLogs: createTool({
77
+ name: 'downloadLogs',
78
+ description: 'Download email delivery logs',
79
+ method: 'get',
80
+ path: '/v1/logs/download',
81
+ query: [
82
+ 'domain',
83
+ 'q',
84
+ 'bounce_category',
85
+ 'response_code',
86
+ 'always_send_email',
87
+ ],
88
+ }),
89
+
90
+ //
91
+ // Contacts (CardDAV)
92
+ //
93
+ listContacts: createTool({
94
+ name: 'listContacts',
95
+ description: 'List all contacts',
96
+ method: 'get',
97
+ path: '/v1/contacts',
98
+ }),
99
+ createContact: createTool({
100
+ name: 'createContact',
101
+ description: 'Create a contact',
102
+ method: 'post',
103
+ path: '/v1/contacts',
104
+ }),
105
+ getContact: createTool({
106
+ name: 'getContact',
107
+ description: 'Get a contact by ID',
108
+ method: 'get',
109
+ path: '/v1/contacts/{id}',
110
+ }),
111
+ updateContact: createTool({
112
+ name: 'updateContact',
113
+ description: 'Update a contact',
114
+ method: 'put',
115
+ path: '/v1/contacts/{id}',
116
+ }),
117
+ deleteContact: createTool({
118
+ name: 'deleteContact',
119
+ description: 'Delete a contact',
120
+ method: 'delete',
121
+ path: '/v1/contacts/{id}',
122
+ }),
123
+
124
+ //
125
+ // Calendars (CalDAV)
126
+ //
127
+ listCalendars: createTool({
128
+ name: 'listCalendars',
129
+ description: 'List all calendars',
130
+ method: 'get',
131
+ path: '/v1/calendars',
132
+ }),
133
+ createCalendar: createTool({
134
+ name: 'createCalendar',
135
+ description: 'Create a calendar',
136
+ method: 'post',
137
+ path: '/v1/calendars',
138
+ }),
139
+ getCalendar: createTool({
140
+ name: 'getCalendar',
141
+ description: 'Get a calendar by ID',
142
+ method: 'get',
143
+ path: '/v1/calendars/{id}',
144
+ }),
145
+ updateCalendar: createTool({
146
+ name: 'updateCalendar',
147
+ description: 'Update a calendar',
148
+ method: 'put',
149
+ path: '/v1/calendars/{id}',
150
+ }),
151
+ deleteCalendar: createTool({
152
+ name: 'deleteCalendar',
153
+ description: 'Delete a calendar',
154
+ method: 'delete',
155
+ path: '/v1/calendars/{id}',
156
+ }),
157
+
158
+ //
159
+ // Calendar Events (CalDAV)
160
+ //
161
+ listCalendarEvents: createTool({
162
+ name: 'listCalendarEvents',
163
+ description: 'List all calendar events',
164
+ method: 'get',
165
+ path: '/v1/calendar-events',
166
+ }),
167
+ createCalendarEvent: createTool({
168
+ name: 'createCalendarEvent',
169
+ description: 'Create a calendar event',
170
+ method: 'post',
171
+ path: '/v1/calendar-events',
172
+ }),
173
+ getCalendarEvent: createTool({
174
+ name: 'getCalendarEvent',
175
+ description: 'Get a calendar event by ID',
176
+ method: 'get',
177
+ path: '/v1/calendar-events/{id}',
178
+ }),
179
+ updateCalendarEvent: createTool({
180
+ name: 'updateCalendarEvent',
181
+ description: 'Update a calendar event',
182
+ method: 'put',
183
+ path: '/v1/calendar-events/{id}',
184
+ }),
185
+ deleteCalendarEvent: createTool({
186
+ name: 'deleteCalendarEvent',
187
+ description: 'Delete a calendar event',
188
+ method: 'delete',
189
+ path: '/v1/calendar-events/{id}',
190
+ }),
191
+
192
+ //
193
+ // Domains
194
+ //
195
+ listDomains: createTool({
196
+ name: 'listDomains',
197
+ description: 'List all domains',
198
+ method: 'get',
199
+ path: '/v1/domains',
200
+ query: ['sort', 'page', 'limit'],
201
+ }),
202
+ createDomain: createTool({
203
+ name: 'createDomain',
204
+ description: 'Create a new domain',
205
+ method: 'post',
206
+ path: '/v1/domains',
207
+ }),
208
+ getDomain: createTool({
209
+ name: 'getDomain',
210
+ description: 'Get a domain by ID or name',
211
+ method: 'get',
212
+ path: '/v1/domains/{domain_id}',
213
+ }),
214
+ updateDomain: createTool({
215
+ name: 'updateDomain',
216
+ description: 'Update a domain',
217
+ method: 'put',
218
+ path: '/v1/domains/{domain_id}',
219
+ }),
220
+ deleteDomain: createTool({
221
+ name: 'deleteDomain',
222
+ description: 'Delete a domain',
223
+ method: 'delete',
224
+ path: '/v1/domains/{domain_id}',
225
+ }),
226
+ verifyDomainRecords: createTool({
227
+ name: 'verifyDomainRecords',
228
+ description: 'Verify domain DNS records',
229
+ method: 'get',
230
+ path: '/v1/domains/{domain_id}/verify-records',
231
+ }),
232
+ verifySmtpRecords: createTool({
233
+ name: 'verifySmtpRecords',
234
+ description: 'Verify domain SMTP records',
235
+ method: 'get',
236
+ path: '/v1/domains/{domain_id}/verify-smtp',
237
+ }),
238
+ testS3Connection: createTool({
239
+ name: 'testS3Connection',
240
+ description: 'Test custom S3 connection for a domain',
241
+ method: 'post',
242
+ path: '/v1/domains/{domain_id}/test-s3-connection',
243
+ }),
244
+
245
+ //
246
+ // Domain Catch-All Passwords
247
+ //
248
+ listCatchAllPasswords: createTool({
249
+ name: 'listCatchAllPasswords',
250
+ description: 'List domain-wide catch-all passwords',
251
+ method: 'get',
252
+ path: '/v1/domains/{domain_id}/catch-all-passwords',
253
+ }),
254
+ createCatchAllPassword: createTool({
255
+ name: 'createCatchAllPassword',
256
+ description: 'Create a domain-wide catch-all password',
257
+ method: 'post',
258
+ path: '/v1/domains/{domain_id}/catch-all-passwords',
259
+ }),
260
+ deleteCatchAllPassword: createTool({
261
+ name: 'deleteCatchAllPassword',
262
+ description: 'Remove a domain-wide catch-all password',
263
+ method: 'delete',
264
+ path: '/v1/domains/{domain_id}/catch-all-passwords/{token_id}',
265
+ }),
266
+
267
+ //
268
+ // Domain Invites
269
+ //
270
+ acceptDomainInvite: createTool({
271
+ name: 'acceptDomainInvite',
272
+ description: 'Accept a domain invite',
273
+ method: 'get',
274
+ path: '/v1/domains/{domain_id}/invites',
275
+ }),
276
+ createDomainInvite: createTool({
277
+ name: 'createDomainInvite',
278
+ description: 'Invite a user to a domain',
279
+ method: 'post',
280
+ path: '/v1/domains/{domain_id}/invites',
281
+ }),
282
+ removeDomainInvite: createTool({
283
+ name: 'removeDomainInvite',
284
+ description: 'Remove a domain invite',
285
+ method: 'delete',
286
+ path: '/v1/domains/{domain_id}/invites',
287
+ }),
288
+
289
+ //
290
+ // Domain Members
291
+ //
292
+ updateDomainMember: createTool({
293
+ name: 'updateDomainMember',
294
+ description: 'Update a domain member role (admin or user)',
295
+ method: 'put',
296
+ path: '/v1/domains/{domain_id}/members/{member_id}',
297
+ }),
298
+ removeDomainMember: createTool({
299
+ name: 'removeDomainMember',
300
+ description: 'Remove a member from a domain',
301
+ method: 'delete',
302
+ path: '/v1/domains/{domain_id}/members/{member_id}',
303
+ }),
304
+
305
+ //
306
+ // Aliases
307
+ //
308
+ listAliases: createTool({
309
+ name: 'listAliases',
310
+ description: 'List aliases for a domain',
311
+ method: 'get',
312
+ path: '/v1/domains/{domain_id}/aliases',
313
+ query: ['sort', 'page', 'limit'],
314
+ }),
315
+ createAlias: createTool({
316
+ name: 'createAlias',
317
+ description: 'Create a new alias',
318
+ method: 'post',
319
+ path: '/v1/domains/{domain_id}/aliases',
320
+ }),
321
+ getAlias: createTool({
322
+ name: 'getAlias',
323
+ description: 'Get an alias by ID',
324
+ method: 'get',
325
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}',
326
+ }),
327
+ updateAlias: createTool({
328
+ name: 'updateAlias',
329
+ description: 'Update an alias',
330
+ method: 'put',
331
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}',
332
+ }),
333
+ deleteAlias: createTool({
334
+ name: 'deleteAlias',
335
+ description: 'Delete an alias',
336
+ method: 'delete',
337
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}',
338
+ }),
339
+ generateAliasPassword: createTool({
340
+ name: 'generateAliasPassword',
341
+ description: 'Generate or set a password for an alias',
342
+ method: 'post',
343
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/generate-password',
344
+ }),
345
+
346
+ //
347
+ // Sieve Scripts (domain-scoped, authenticated via API key)
348
+ //
349
+ listSieveScripts: createTool({
350
+ name: 'listSieveScripts',
351
+ description: 'List Sieve scripts for an alias',
352
+ method: 'get',
353
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/sieve',
354
+ }),
355
+ createSieveScript: createTool({
356
+ name: 'createSieveScript',
357
+ description: 'Create a Sieve script for an alias',
358
+ method: 'post',
359
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/sieve',
360
+ }),
361
+ getSieveScript: createTool({
362
+ name: 'getSieveScript',
363
+ description: 'Get a Sieve script by ID',
364
+ method: 'get',
365
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/sieve/{script_id}',
366
+ }),
367
+ updateSieveScript: createTool({
368
+ name: 'updateSieveScript',
369
+ description: 'Update a Sieve script',
370
+ method: 'put',
371
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/sieve/{script_id}',
372
+ }),
373
+ deleteSieveScript: createTool({
374
+ name: 'deleteSieveScript',
375
+ description: 'Delete a Sieve script',
376
+ method: 'delete',
377
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/sieve/{script_id}',
378
+ }),
379
+ activateSieveScript: createTool({
380
+ name: 'activateSieveScript',
381
+ description: 'Activate a Sieve script',
382
+ method: 'post',
383
+ path: '/v1/domains/{domain_id}/aliases/{alias_id}/sieve/{script_id}/activate',
384
+ }),
385
+
386
+ //
387
+ // Sieve Scripts (alias auth, authenticated via alias credentials)
388
+ //
389
+ listSieveScriptsAliasAuth: createTool({
390
+ name: 'listSieveScriptsAliasAuth',
391
+ description: 'List Sieve scripts (alias auth)',
392
+ method: 'get',
393
+ path: '/v1/sieve-scripts',
394
+ }),
395
+ createSieveScriptAliasAuth: createTool({
396
+ name: 'createSieveScriptAliasAuth',
397
+ description: 'Create a Sieve script (alias auth)',
398
+ method: 'post',
399
+ path: '/v1/sieve-scripts',
400
+ }),
401
+ getSieveScriptAliasAuth: createTool({
402
+ name: 'getSieveScriptAliasAuth',
403
+ description: 'Get a Sieve script (alias auth)',
404
+ method: 'get',
405
+ path: '/v1/sieve-scripts/{script_id}',
406
+ }),
407
+ updateSieveScriptAliasAuth: createTool({
408
+ name: 'updateSieveScriptAliasAuth',
409
+ description: 'Update a Sieve script (alias auth)',
410
+ method: 'put',
411
+ path: '/v1/sieve-scripts/{script_id}',
412
+ }),
413
+ deleteSieveScriptAliasAuth: createTool({
414
+ name: 'deleteSieveScriptAliasAuth',
415
+ description: 'Delete a Sieve script (alias auth)',
416
+ method: 'delete',
417
+ path: '/v1/sieve-scripts/{script_id}',
418
+ }),
419
+ activateSieveScriptAliasAuth: createTool({
420
+ name: 'activateSieveScriptAliasAuth',
421
+ description: 'Activate a Sieve script (alias auth)',
422
+ method: 'post',
423
+ path: '/v1/sieve-scripts/{script_id}/activate',
424
+ }),
425
+
426
+ //
427
+ // Emails (Outbound SMTP)
428
+ //
429
+ listEmails: createTool({
430
+ name: 'listEmails',
431
+ description: 'List outbound SMTP emails',
432
+ method: 'get',
433
+ path: '/v1/emails',
434
+ query: ['q', 'domain', 'is_scheduled', 'sort', 'page', 'limit'],
435
+ }),
436
+ sendEmail: createTool({
437
+ name: 'sendEmail',
438
+ description: 'Send an email via outbound SMTP',
439
+ method: 'post',
440
+ path: '/v1/emails',
441
+ }),
442
+ getEmailLimit: createTool({
443
+ name: 'getEmailLimit',
444
+ description: 'Get outbound SMTP email sending limit',
445
+ method: 'get',
446
+ path: '/v1/emails/limit',
447
+ }),
448
+ getEmail: createTool({
449
+ name: 'getEmail',
450
+ description: 'Get an outbound SMTP email by ID',
451
+ method: 'get',
452
+ path: '/v1/emails/{id}',
453
+ }),
454
+ deleteEmail: createTool({
455
+ name: 'deleteEmail',
456
+ description: 'Delete an outbound SMTP email',
457
+ method: 'delete',
458
+ path: '/v1/emails/{id}',
459
+ }),
460
+
461
+ //
462
+ // Messages (IMAP)
463
+ //
464
+ listMessages: createTool({
465
+ name: 'listMessages',
466
+ description: 'List and search messages in a folder',
467
+ method: 'get',
468
+ path: '/v1/messages',
469
+ query: [
470
+ 'folder',
471
+ 'is_unread',
472
+ 'is_flagged',
473
+ 'is_deleted',
474
+ 'is_draft',
475
+ 'is_junk',
476
+ 'is_copied',
477
+ 'is_encrypted',
478
+ 'is_searchable',
479
+ 'is_expired',
480
+ 'has_attachments',
481
+ 'has_attachment',
482
+ 'subject',
483
+ 'body',
484
+ 'text',
485
+ 'headers',
486
+ 'message_id',
487
+ 'search',
488
+ 'q',
489
+ 'since',
490
+ 'before',
491
+ 'min_size',
492
+ 'max_size',
493
+ 'from',
494
+ 'to',
495
+ 'cc',
496
+ 'bcc',
497
+ 'date',
498
+ 'reply-to',
499
+ ],
500
+ }),
501
+ createMessage: createTool({
502
+ name: 'createMessage',
503
+ description: 'Create a new message (draft)',
504
+ method: 'post',
505
+ path: '/v1/messages',
506
+ }),
507
+ getMessage: createTool({
508
+ name: 'getMessage',
509
+ description: 'Get a message by ID',
510
+ method: 'get',
511
+ path: '/v1/messages/{id}',
512
+ query: ['eml', 'nodemailer', 'attachments', 'raw'],
513
+ }),
514
+ updateMessage: createTool({
515
+ name: 'updateMessage',
516
+ description: 'Update a message',
517
+ method: 'put',
518
+ path: '/v1/messages/{id}',
519
+ query: ['eml'],
520
+ }),
521
+ deleteMessage: createTool({
522
+ name: 'deleteMessage',
523
+ description: 'Delete a message',
524
+ method: 'delete',
525
+ path: '/v1/messages/{id}',
526
+ }),
527
+
528
+ //
529
+ // Folders (IMAP)
530
+ //
531
+ listFolders: createTool({
532
+ name: 'listFolders',
533
+ description: 'List all folders',
534
+ method: 'get',
535
+ path: '/v1/folders',
536
+ query: ['subscribed'],
537
+ }),
538
+ createFolder: createTool({
539
+ name: 'createFolder',
540
+ description: 'Create a new folder',
541
+ method: 'post',
542
+ path: '/v1/folders',
543
+ }),
544
+ getFolder: createTool({
545
+ name: 'getFolder',
546
+ description: 'Get a folder by ID',
547
+ method: 'get',
548
+ path: '/v1/folders/{id}',
549
+ }),
550
+ updateFolder: createTool({
551
+ name: 'updateFolder',
552
+ description: 'Update a folder',
553
+ method: 'put',
554
+ path: '/v1/folders/{id}',
555
+ }),
556
+ deleteFolder: createTool({
557
+ name: 'deleteFolder',
558
+ description: 'Delete a folder',
559
+ method: 'delete',
560
+ path: '/v1/folders/{id}',
561
+ }),
562
+
563
+ //
564
+ // Encrypt
565
+ //
566
+ encryptRecord: createTool({
567
+ name: 'encryptRecord',
568
+ description: 'Encrypt a plaintext Forward Email TXT record',
569
+ method: 'post',
570
+ path: '/v1/encrypt',
571
+ }),
572
+ };
573
+
574
+ return tools;
575
+ };
576
+
577
+ module.exports = {getTools};
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@forwardemail/mcp-server",
3
+ "description": "Model Context Protocol (MCP) server for Forward Email. Connect AI to your inbox.",
4
+ "version": "1.0.0",
5
+ "author": "Forward Email LLC <support@forwardemail.net> (https://forwardemail.net)",
6
+ "bin": {
7
+ "mcp-server": "./bin/mcp-server.js"
8
+ },
9
+ "bugs": {
10
+ "url": "https://github.com/forwardemail/mcp-server/issues"
11
+ },
12
+ "dependencies": {
13
+ "axios": "^1.7.2",
14
+ "cosmiconfig": "^9.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@commitlint/cli": "^19.3.0",
18
+ "@commitlint/config-conventional": "^19.2.2",
19
+ "c8": "^10.1.2",
20
+ "fixpack": "^4.0.0",
21
+ "husky": "^9.0.11",
22
+ "lint-staged": "^15.2.2",
23
+ "prettier": "^3.2.5",
24
+ "remark-cli": "^12.0.1",
25
+ "remark-preset-lint-recommended": "^7.0.1",
26
+ "xo": "^0.58.0"
27
+ },
28
+ "engines": {
29
+ "node": ">=18.0.0"
30
+ },
31
+ "exports": {
32
+ ".": {
33
+ "import": "./lib/index.js",
34
+ "require": "./lib/index.js",
35
+ "types": "./lib/index.d.ts"
36
+ }
37
+ },
38
+ "files": [
39
+ "lib/",
40
+ "bin/",
41
+ "README.md",
42
+ "LICENSE"
43
+ ],
44
+ "homepage": "https://forwardemail.net/mcp",
45
+ "keywords": [
46
+ "ai",
47
+ "automation",
48
+ "chatgpt",
49
+ "claude",
50
+ "email",
51
+ "forward-email",
52
+ "llm",
53
+ "mcp",
54
+ "model-context-protocol"
55
+ ],
56
+ "license": "BUSL-1.1",
57
+ "main": "lib/index.js",
58
+ "prettier": {
59
+ "useTabs": false,
60
+ "tabWidth": 2,
61
+ "singleQuote": true
62
+ },
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "https://github.com/forwardemail/mcp-server.git"
66
+ },
67
+ "types": "lib/index.d.ts",
68
+ "xo": {
69
+ "space": 2,
70
+ "prettier": true,
71
+ "rules": {
72
+ "unicorn/prefer-module": "off",
73
+ "import-x/extensions": "off",
74
+ "n/prefer-global/process": "off"
75
+ }
76
+ },
77
+ "scripts": {
78
+ "lint": "fixpack && remark . -qfo && xo --fix",
79
+ "pre-commit": "lint-staged",
80
+ "pretest": "pnpm run lint",
81
+ "test": "c8 --reporter=text --reporter=html node --test"
82
+ }
83
+ }