@honest-magic/mail-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/LICENSE +21 -0
- package/README.md +178 -0
- package/dist/cli/accounts.d.ts +7 -0
- package/dist/cli/accounts.js +171 -0
- package/dist/cli/accounts.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +48 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +658 -0
- package/dist/index.js +556 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/imap.d.ts +29 -0
- package/dist/protocol/imap.js +255 -0
- package/dist/protocol/imap.js.map +1 -0
- package/dist/protocol/smtp.d.ts +8 -0
- package/dist/protocol/smtp.js +56 -0
- package/dist/protocol/smtp.js.map +1 -0
- package/dist/security/keychain.d.ts +3 -0
- package/dist/security/keychain.js +18 -0
- package/dist/security/keychain.js.map +1 -0
- package/dist/security/oauth2.d.ts +9 -0
- package/dist/security/oauth2.js +51 -0
- package/dist/security/oauth2.js.map +1 -0
- package/dist/services/mail.d.ts +45 -0
- package/dist/services/mail.js +200 -0
- package/dist/services/mail.js.map +1 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/markdown.d.ts +1 -0
- package/dist/utils/markdown.js +11 -0
- package/dist/utils/markdown.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 honest-magic
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# mail-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for IMAP/SMTP email access — works with Claude and other MCP clients.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js >=18
|
|
8
|
+
- macOS (credentials stored in Keychain)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
### Run without installing (recommended)
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @honest-magic/mail-mcp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Global install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @honest-magic/mail-mcp
|
|
22
|
+
mail-mcp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
### 1. Add an account (interactive)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx @honest-magic/mail-mcp accounts add
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This prompts for IMAP/SMTP settings, stores the account in `~/.config/mail-mcp/accounts.json`, and saves the password in macOS Keychain.
|
|
34
|
+
|
|
35
|
+
### Manage accounts
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
mail-mcp accounts list # show configured accounts
|
|
39
|
+
mail-mcp accounts remove ID # remove an account and its keychain entry
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Manual setup
|
|
43
|
+
|
|
44
|
+
Alternatively, create `~/.config/mail-mcp/accounts.json` by hand:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
[
|
|
48
|
+
{
|
|
49
|
+
"id": "work",
|
|
50
|
+
"name": "Work Email",
|
|
51
|
+
"host": "imap.example.com",
|
|
52
|
+
"port": 993,
|
|
53
|
+
"smtpHost": "smtp.example.com",
|
|
54
|
+
"smtpPort": 587,
|
|
55
|
+
"user": "you@example.com",
|
|
56
|
+
"authType": "login",
|
|
57
|
+
"useTLS": true
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then store the password in macOS Keychain:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
security add-generic-password \
|
|
66
|
+
-s ch.honest-magic.config.mail-server \
|
|
67
|
+
-a <account-id> \
|
|
68
|
+
-w <password-or-app-password>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Account fields
|
|
72
|
+
|
|
73
|
+
| Field | Type | Required | Description |
|
|
74
|
+
|-------|------|----------|-------------|
|
|
75
|
+
| `id` | string | yes | Unique identifier used by MCP tools |
|
|
76
|
+
| `name` | string | yes | Human-readable label |
|
|
77
|
+
| `host` | string | yes | IMAP hostname |
|
|
78
|
+
| `port` | number | yes | IMAP port (993 for TLS, 143 for STARTTLS) |
|
|
79
|
+
| `smtpHost` | string | no | SMTP hostname (omit for read-only use) |
|
|
80
|
+
| `smtpPort` | number | no | SMTP port (587 for STARTTLS, 465 for TLS) |
|
|
81
|
+
| `user` | string | yes | Login username / email address |
|
|
82
|
+
| `authType` | string | yes | `login` or `oauth2` |
|
|
83
|
+
| `useTLS` | boolean | yes | `true` for implicit TLS on IMAP; `false` for STARTTLS |
|
|
84
|
+
|
|
85
|
+
**OAuth2** — after starting the server, call the `register_oauth2_account` MCP tool:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"tool": "register_oauth2_account",
|
|
90
|
+
"arguments": {
|
|
91
|
+
"accountId": "work",
|
|
92
|
+
"clientId": "<oauth2-client-id>",
|
|
93
|
+
"clientSecret": "<oauth2-client-secret>",
|
|
94
|
+
"refreshToken": "<oauth2-refresh-token>",
|
|
95
|
+
"tokenEndpoint": "https://oauth2.googleapis.com/token"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The credentials are stored in Keychain under the same service name. Token refresh is handled automatically.
|
|
101
|
+
|
|
102
|
+
### 3. Add to your MCP client
|
|
103
|
+
|
|
104
|
+
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"mail": {
|
|
110
|
+
"command": "npx",
|
|
111
|
+
"args": ["-y", "@honest-magic/mail-mcp"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Generic MCP client**:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"mcpServers": {
|
|
122
|
+
"mail": {
|
|
123
|
+
"command": "mail-mcp"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Use `"command": "mail-mcp"` if installed globally, or `"command": "npx", "args": ["-y", "@honest-magic/mail-mcp"]` otherwise.
|
|
130
|
+
|
|
131
|
+
## Available Tools
|
|
132
|
+
|
|
133
|
+
| Tool | Description |
|
|
134
|
+
|------|-------------|
|
|
135
|
+
| `list_accounts` | List all configured email accounts |
|
|
136
|
+
| `list_emails` | List recent emails from a folder with metadata and snippets |
|
|
137
|
+
| `search_emails` | Search emails by sender, subject, date range, or keywords |
|
|
138
|
+
| `read_email` | Fetch the full content of an email as Markdown |
|
|
139
|
+
| `send_email` | Send a new email via SMTP |
|
|
140
|
+
| `create_draft` | Save a draft to the Drafts folder without sending |
|
|
141
|
+
| `list_folders` | List all available folders and labels in a mailbox |
|
|
142
|
+
| `move_email` | Move a message to another folder (Archive, Trash, Spam, etc.) |
|
|
143
|
+
| `modify_labels` | Add or remove IMAP flags / provider labels on a message |
|
|
144
|
+
| `get_thread` | Fetch all messages in a conversation thread |
|
|
145
|
+
| `get_attachment` | Download attachment content via MCP Resource URI |
|
|
146
|
+
| `extract_attachment_text` | Extract plain text from PDF and document attachments |
|
|
147
|
+
| `register_oauth2_account` | Store OAuth2 tokens in Keychain for an account |
|
|
148
|
+
| `batch_operations` | Apply move, delete, or label actions to multiple emails at once |
|
|
149
|
+
|
|
150
|
+
## Read-Only Mode
|
|
151
|
+
|
|
152
|
+
Start the server with `--read-only` to disable all write operations:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npx @honest-magic/mail-mcp --read-only
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
In read-only mode:
|
|
159
|
+
- Write tools (`send_email`, `create_draft`, `move_email`, `modify_labels`, `batch_operations`, `register_oauth2_account`) are removed from the tool list entirely and return a descriptive error if called directly.
|
|
160
|
+
- SMTP authentication is skipped — only IMAP connects.
|
|
161
|
+
- The active mode is advertised to the MCP client at handshake via `InitializeResult.instructions`.
|
|
162
|
+
|
|
163
|
+
Claude Desktop read-only config:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"mcpServers": {
|
|
168
|
+
"mail-readonly": {
|
|
169
|
+
"command": "npx",
|
|
170
|
+
"args": ["-y", "@honest-magic/mail-mcp", "--read-only"]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handle `mail-mcp accounts <subcommand>` CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Returns true if a CLI subcommand was handled (caller should process.exit),
|
|
5
|
+
* false if not a CLI command (caller should start the MCP server).
|
|
6
|
+
*/
|
|
7
|
+
export declare function handleAccountsCommand(args: string[]): Promise<boolean>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline/promises';
|
|
2
|
+
import { getAccounts, saveAccounts, ACCOUNTS_PATH } from '../config.js';
|
|
3
|
+
import { saveCredentials, removeCredentials } from '../security/keychain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handle `mail-mcp accounts <subcommand>` CLI commands.
|
|
6
|
+
*
|
|
7
|
+
* Returns true if a CLI subcommand was handled (caller should process.exit),
|
|
8
|
+
* false if not a CLI command (caller should start the MCP server).
|
|
9
|
+
*/
|
|
10
|
+
export async function handleAccountsCommand(args) {
|
|
11
|
+
if (args[0] !== 'accounts') {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const subcommand = args[1];
|
|
15
|
+
switch (subcommand) {
|
|
16
|
+
case 'list':
|
|
17
|
+
await listAccounts();
|
|
18
|
+
return true;
|
|
19
|
+
case 'remove':
|
|
20
|
+
await removeAccount(args[2]);
|
|
21
|
+
return true;
|
|
22
|
+
case 'add':
|
|
23
|
+
await addAccount();
|
|
24
|
+
return true;
|
|
25
|
+
default:
|
|
26
|
+
console.log('Usage: mail-mcp accounts <add|list|remove>');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function listAccounts() {
|
|
31
|
+
const accounts = getAccounts();
|
|
32
|
+
if (accounts.length === 0) {
|
|
33
|
+
console.log('No accounts configured.');
|
|
34
|
+
console.log(`Config file: ${ACCOUNTS_PATH}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const colWidths = {
|
|
38
|
+
id: Math.max(2, ...accounts.map((a) => a.id.length)),
|
|
39
|
+
name: Math.max(4, ...accounts.map((a) => a.name.length)),
|
|
40
|
+
host: Math.max(4, ...accounts.map((a) => a.host.length)),
|
|
41
|
+
user: Math.max(4, ...accounts.map((a) => a.user.length)),
|
|
42
|
+
};
|
|
43
|
+
const pad = (s, n) => s.padEnd(n);
|
|
44
|
+
const header = `${pad('ID', colWidths.id)} ${pad('Name', colWidths.name)} ${pad('Host', colWidths.host)} ${pad('User', colWidths.user)}`;
|
|
45
|
+
const divider = `${'-'.repeat(colWidths.id)} ${'-'.repeat(colWidths.name)} ${'-'.repeat(colWidths.host)} ${'-'.repeat(colWidths.user)}`;
|
|
46
|
+
console.log(header);
|
|
47
|
+
console.log(divider);
|
|
48
|
+
for (const account of accounts) {
|
|
49
|
+
console.log(`${pad(account.id, colWidths.id)} ${pad(account.name, colWidths.name)} ${pad(account.host, colWidths.host)} ${pad(account.user, colWidths.user)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function removeAccount(id) {
|
|
53
|
+
if (!id) {
|
|
54
|
+
console.error('Usage: mail-mcp accounts remove <id>');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
const accounts = getAccounts();
|
|
58
|
+
const index = accounts.findIndex((a) => a.id === id);
|
|
59
|
+
if (index === -1) {
|
|
60
|
+
console.error(`Account '${id}' not found.`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
accounts.splice(index, 1);
|
|
64
|
+
saveAccounts(accounts);
|
|
65
|
+
try {
|
|
66
|
+
await removeCredentials(id);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
console.error(`Warning: could not remove keychain entry for '${id}' (may not exist).`);
|
|
70
|
+
}
|
|
71
|
+
console.log(`Account '${id}' removed.`);
|
|
72
|
+
}
|
|
73
|
+
async function addAccount() {
|
|
74
|
+
const rl = createInterface({
|
|
75
|
+
input: process.stdin,
|
|
76
|
+
output: process.stdout,
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
const existingAccounts = getAccounts();
|
|
80
|
+
const existingIds = new Set(existingAccounts.map((a) => a.id));
|
|
81
|
+
// id
|
|
82
|
+
let id = '';
|
|
83
|
+
while (!id) {
|
|
84
|
+
const raw = await rl.question('Account ID (required, unique): ');
|
|
85
|
+
const trimmed = raw.trim();
|
|
86
|
+
if (!trimmed) {
|
|
87
|
+
console.log(' ID is required.');
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (existingIds.has(trimmed)) {
|
|
91
|
+
console.log(` ID '${trimmed}' already exists. Choose a different ID.`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
id = trimmed;
|
|
95
|
+
}
|
|
96
|
+
// name
|
|
97
|
+
const nameRaw = await rl.question(`Name [${id}]: `);
|
|
98
|
+
const name = nameRaw.trim() || id;
|
|
99
|
+
// host (IMAP)
|
|
100
|
+
let host = '';
|
|
101
|
+
while (!host) {
|
|
102
|
+
const raw = await rl.question('IMAP host (e.g. imap.gmail.com): ');
|
|
103
|
+
const trimmed = raw.trim();
|
|
104
|
+
if (!trimmed) {
|
|
105
|
+
console.log(' Host is required.');
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
host = trimmed;
|
|
109
|
+
}
|
|
110
|
+
// port
|
|
111
|
+
const portRaw = await rl.question('IMAP port [993]: ');
|
|
112
|
+
const port = parseInt(portRaw.trim(), 10) || 993;
|
|
113
|
+
// user
|
|
114
|
+
let user = '';
|
|
115
|
+
while (!user) {
|
|
116
|
+
const raw = await rl.question('Email address (user): ');
|
|
117
|
+
const trimmed = raw.trim();
|
|
118
|
+
if (!trimmed) {
|
|
119
|
+
console.log(' Email address is required.');
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
user = trimmed;
|
|
123
|
+
}
|
|
124
|
+
// authType
|
|
125
|
+
const authTypeRaw = await rl.question('Auth type (login/oauth2) [login]: ');
|
|
126
|
+
const authType = authTypeRaw.trim() === 'oauth2' ? 'oauth2' : 'login';
|
|
127
|
+
// useTLS
|
|
128
|
+
const tlsRaw = await rl.question('Use TLS? (y/n) [y]: ');
|
|
129
|
+
const useTLS = tlsRaw.trim().toLowerCase() !== 'n';
|
|
130
|
+
// smtpHost
|
|
131
|
+
const defaultSmtpHost = host.includes('imap') ? host.replace('imap', 'smtp') : '';
|
|
132
|
+
const smtpHostRaw = await rl.question(`SMTP host [${defaultSmtpHost || 'press enter to skip'}]: `);
|
|
133
|
+
const smtpHost = smtpHostRaw.trim() || defaultSmtpHost || undefined;
|
|
134
|
+
// smtpPort
|
|
135
|
+
let smtpPort;
|
|
136
|
+
if (smtpHost) {
|
|
137
|
+
const smtpPortRaw = await rl.question('SMTP port [587]: ');
|
|
138
|
+
smtpPort = parseInt(smtpPortRaw.trim(), 10) || 587;
|
|
139
|
+
}
|
|
140
|
+
// password (only for login auth)
|
|
141
|
+
let password;
|
|
142
|
+
if (authType === 'login') {
|
|
143
|
+
const passwordRaw = await rl.question('Password (will be stored in macOS Keychain, NOT in config file): ');
|
|
144
|
+
password = passwordRaw || undefined;
|
|
145
|
+
}
|
|
146
|
+
const account = {
|
|
147
|
+
id,
|
|
148
|
+
name,
|
|
149
|
+
host,
|
|
150
|
+
port,
|
|
151
|
+
user,
|
|
152
|
+
authType,
|
|
153
|
+
useTLS,
|
|
154
|
+
...(smtpHost !== undefined ? { smtpHost } : {}),
|
|
155
|
+
...(smtpPort !== undefined ? { smtpPort } : {}),
|
|
156
|
+
};
|
|
157
|
+
existingAccounts.push(account);
|
|
158
|
+
saveAccounts(existingAccounts);
|
|
159
|
+
if (authType === 'login' && password) {
|
|
160
|
+
await saveCredentials(id, password);
|
|
161
|
+
console.log(`Account '${id}' added. Password stored in macOS Keychain.`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
console.log(`Account '${id}' added.`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
rl.close();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/cli/accounts.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EmailAccount } from './types/index.js';
|
|
2
|
+
export declare const ACCOUNTS_PATH: string;
|
|
3
|
+
export declare const config: {
|
|
4
|
+
serviceName: string;
|
|
5
|
+
logLevel: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Writes account definitions to ~/.config/mail-mcp/accounts.json.
|
|
9
|
+
* Creates the directory if it does not exist.
|
|
10
|
+
*/
|
|
11
|
+
export declare function saveAccounts(accounts: EmailAccount[]): void;
|
|
12
|
+
/**
|
|
13
|
+
* Reads account definitions from ~/.config/mail-mcp/accounts.json.
|
|
14
|
+
* Returns an empty array if the file does not exist or cannot be parsed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAccounts(): EmailAccount[];
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
export const ACCOUNTS_PATH = path.join(os.homedir(), '.config', 'mail-mcp', 'accounts.json');
|
|
6
|
+
const configSchema = z.object({
|
|
7
|
+
serviceName: z.string().default('ch.honest-magic.config.mail-server'),
|
|
8
|
+
logLevel: z.string().default('info'),
|
|
9
|
+
});
|
|
10
|
+
export const config = configSchema.parse({
|
|
11
|
+
serviceName: process.env.SERVICE_NAME,
|
|
12
|
+
logLevel: process.env.LOG_LEVEL,
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Writes account definitions to ~/.config/mail-mcp/accounts.json.
|
|
16
|
+
* Creates the directory if it does not exist.
|
|
17
|
+
*/
|
|
18
|
+
export function saveAccounts(accounts) {
|
|
19
|
+
const configPath = ACCOUNTS_PATH;
|
|
20
|
+
const dir = path.dirname(configPath);
|
|
21
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
22
|
+
fs.writeFileSync(configPath, JSON.stringify(accounts, null, 2), 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Reads account definitions from ~/.config/mail-mcp/accounts.json.
|
|
26
|
+
* Returns an empty array if the file does not exist or cannot be parsed.
|
|
27
|
+
*/
|
|
28
|
+
export function getAccounts() {
|
|
29
|
+
const configPath = ACCOUNTS_PATH;
|
|
30
|
+
if (!fs.existsSync(configPath)) {
|
|
31
|
+
console.error('No accounts config found at ~/.config/mail-mcp/accounts.json');
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
36
|
+
const parsed = JSON.parse(raw);
|
|
37
|
+
if (!Array.isArray(parsed)) {
|
|
38
|
+
console.error(`Failed to parse accounts config at ${configPath}: expected an array`);
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(`Failed to parse accounts config at ${configPath}:`, error);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAG9B,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AAE7F,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,oCAAoC,CAAC;IACrE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC;IACvC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;IACrC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS;CAChC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAwB;IACnD,MAAM,UAAU,GAAG,aAAa,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,UAAU,GAAG,aAAa,CAAC;IAEjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAC9E,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,sCAAsC,UAAU,qBAAqB,CAAC,CAAC;YACrF,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,MAAwB,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,UAAU,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1E,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|