@bobfrankston/rmfmail 1.2.129 → 1.2.131
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 +11 -0
- package/bin/mailx.js +27 -0
- package/bin/mailx.js.map +1 -1
- package/bin/mailx.ts +23 -0
- package/bin/mcp-server.js +204 -0
- package/bin/mcp-server.js.map +1 -0
- package/bin/mcp-server.ts +200 -0
- package/bin/popout-server.js +25 -2
- package/bin/popout-server.js.map +1 -1
- package/bin/popout-server.ts +30 -2
- package/package.json +5 -4
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* rmfmail-mcp — Model Context Protocol server over the running rmfmail
|
|
4
|
+
* daemon, so an AI (Claude Code, Claude Desktop, anything MCP-speaking) can
|
|
5
|
+
* process mail on the user's behalf.
|
|
6
|
+
*
|
|
7
|
+
* claude mcp add rmfmail -- rmfmail-mcp
|
|
8
|
+
*
|
|
9
|
+
* Transport: MCP stdio (newline-delimited JSON-RPC 2.0). Hand-rolled — the
|
|
10
|
+
* protocol subset needed (initialize / tools/list / tools/call) is ~100
|
|
11
|
+
* lines and not worth an SDK dependency.
|
|
12
|
+
*
|
|
13
|
+
* Backend: the daemon's /rpc endpoint, discovered via ~/.rmfmail/agent.json
|
|
14
|
+
* (written each boot, removed on shutdown; a dead pid means stale). Scope:
|
|
15
|
+
* the TRIAGE token by default — reads plus flag/mark-read. Set
|
|
16
|
+
* RMFMAIL_MCP_FULL=1 to use the full token, which unlocks move_message and
|
|
17
|
+
* create_draft. There is deliberately NO send tool at either scope: AI
|
|
18
|
+
* drafts, the human sends (standing policy).
|
|
19
|
+
*/
|
|
20
|
+
import fs from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import readline from "node:readline";
|
|
23
|
+
const CONFIG_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".rmfmail");
|
|
24
|
+
const AGENT_JSON = path.join(CONFIG_DIR, "agent.json");
|
|
25
|
+
const FULL = process.env.RMFMAIL_MCP_FULL === "1";
|
|
26
|
+
function loadAgentInfo() {
|
|
27
|
+
let raw;
|
|
28
|
+
try {
|
|
29
|
+
raw = fs.readFileSync(AGENT_JSON, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw new Error(`rmfmail daemon not running (no ${AGENT_JSON}) — start it with: rmfmail`);
|
|
33
|
+
}
|
|
34
|
+
const info = JSON.parse(raw);
|
|
35
|
+
try {
|
|
36
|
+
process.kill(info.pid, 0);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error(`agent.json is stale (pid ${info.pid} not running) — start rmfmail`);
|
|
40
|
+
}
|
|
41
|
+
return info;
|
|
42
|
+
}
|
|
43
|
+
let rpcSeq = 0;
|
|
44
|
+
async function rpc(action, params = {}) {
|
|
45
|
+
const info = loadAgentInfo();
|
|
46
|
+
const token = FULL ? info.tokens.full : info.tokens.triage;
|
|
47
|
+
const r = await fetch(`${info.rpcUrl}?t=${token}`, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: { "content-type": "application/json" },
|
|
50
|
+
body: JSON.stringify({ _action: action, _cbid: String(++rpcSeq), ...params }),
|
|
51
|
+
});
|
|
52
|
+
if (!r.ok)
|
|
53
|
+
throw new Error(`daemon rpc HTTP ${r.status}`);
|
|
54
|
+
const res = await r.json();
|
|
55
|
+
if (res.error)
|
|
56
|
+
throw new Error(res.error);
|
|
57
|
+
return res.result;
|
|
58
|
+
}
|
|
59
|
+
// ── Tools ──
|
|
60
|
+
/** Trim a message object down to what an LLM needs — full envelopes carry
|
|
61
|
+
* parsed MIME internals that waste context. */
|
|
62
|
+
function slimMessage(m, includeBody) {
|
|
63
|
+
const one = (x) => x?.name ? `${x.name} <${x.address}>` : (x?.address || x || "");
|
|
64
|
+
const addr = (a) => Array.isArray(a) ? a.map(one).join(", ") : (a && typeof a === "object" ? one(a) : a);
|
|
65
|
+
const out = {
|
|
66
|
+
accountId: m.accountId, uid: m.uid, folderId: m.folderId,
|
|
67
|
+
date: m.date, from: addr(m.from), to: addr(m.to), cc: addr(m.cc) || undefined,
|
|
68
|
+
subject: m.subject, seen: m.seen, flagged: m.flagged,
|
|
69
|
+
snippet: m.preview || undefined,
|
|
70
|
+
};
|
|
71
|
+
if (includeBody) {
|
|
72
|
+
out.bodyText = m.bodyText || undefined;
|
|
73
|
+
// Fall back to a crude strip when only HTML exists.
|
|
74
|
+
if (!out.bodyText && m.bodyHtml)
|
|
75
|
+
out.bodyText = String(m.bodyHtml).replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 20000);
|
|
76
|
+
if (m.bodyError)
|
|
77
|
+
out.bodyError = m.bodyError;
|
|
78
|
+
if (Array.isArray(m.attachments) && m.attachments.length) {
|
|
79
|
+
out.attachments = m.attachments.map((a) => ({ id: a.id, filename: a.filename, mimeType: a.mimeType, size: a.size }));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
const str = (description) => ({ type: "string", description });
|
|
85
|
+
const num = (description) => ({ type: "number", description });
|
|
86
|
+
const bool = (description) => ({ type: "boolean", description });
|
|
87
|
+
const obj = (props, required) => ({ type: "object", properties: props, required });
|
|
88
|
+
const TOOLS = {
|
|
89
|
+
list_accounts: {
|
|
90
|
+
description: "List configured mail accounts (id, name, email).",
|
|
91
|
+
inputSchema: obj({}, []),
|
|
92
|
+
run: async () => (await rpc("getAccounts")).map((a) => ({ id: a.id, name: a.name, email: a.email })),
|
|
93
|
+
},
|
|
94
|
+
list_folders: {
|
|
95
|
+
description: "List folders for an account, with unread/total counts.",
|
|
96
|
+
inputSchema: obj({ accountId: str("Account id from list_accounts") }, ["accountId"]),
|
|
97
|
+
run: async (a) => (await rpc("getFolders", { accountId: a.accountId })).map((f) => ({ id: f.id, path: f.path, specialUse: f.specialUse || undefined, unread: f.unreadCount, total: f.totalCount })),
|
|
98
|
+
},
|
|
99
|
+
list_messages: {
|
|
100
|
+
description: "List messages in a folder, newest first (paged, 50/page). Returns envelopes with snippets, no bodies.",
|
|
101
|
+
inputSchema: obj({ accountId: str("Account id"), folderId: num("Folder id from list_folders"), page: num("1-based page, default 1") }, ["accountId", "folderId"]),
|
|
102
|
+
run: async (a) => {
|
|
103
|
+
const r = await rpc("getMessages", { accountId: a.accountId, folderId: a.folderId, page: a.page || 1, pageSize: 50 });
|
|
104
|
+
return { total: r.total, messages: (r.items || []).map((m) => slimMessage({ ...m, accountId: a.accountId, folderId: a.folderId }, false)) };
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
search_messages: {
|
|
108
|
+
description: "Full-text search across all local mail (FTS). Query supports plain words; results span accounts/folders.",
|
|
109
|
+
inputSchema: obj({ query: str("Search text"), includeTrashSpam: bool("Also search Trash/Spam (default false)") }, ["query"]),
|
|
110
|
+
run: async (a) => {
|
|
111
|
+
const r = await rpc("searchMessages", { query: (a.query || "").trim(), page: 1, pageSize: 50, scope: "all", accountId: "", folderId: 0, includeTrashSpam: !!a.includeTrashSpam });
|
|
112
|
+
return { total: r.total, messages: (r.items || []).map((m) => slimMessage(m, false)) };
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
get_message: {
|
|
116
|
+
description: "Fetch one message including its text body and attachment list.",
|
|
117
|
+
inputSchema: obj({ accountId: str("Account id"), uid: num("Message uid"), folderId: num("Folder id the uid lives in") }, ["accountId", "uid", "folderId"]),
|
|
118
|
+
run: async (a) => slimMessage(await rpc("getMessage", { accountId: a.accountId, uid: a.uid, folderId: a.folderId, allowRemote: false }), true),
|
|
119
|
+
},
|
|
120
|
+
flag_message: {
|
|
121
|
+
description: "Set or clear flags on a message. flags is the COMPLETE new flag list, e.g. [\"\\\\Seen\", \"\\\\Flagged\"] or [\"\\\\Seen\"] to unflag.",
|
|
122
|
+
inputSchema: obj({ accountId: str("Account id"), uid: num("Message uid"), folderId: num("Folder id"), flags: { type: "array", items: { type: "string" }, description: "Complete flag list" } }, ["accountId", "uid", "folderId", "flags"]),
|
|
123
|
+
run: async (a) => rpc("updateFlags", { accountId: a.accountId, uid: a.uid, folderId: a.folderId, flags: a.flags }),
|
|
124
|
+
},
|
|
125
|
+
move_message: {
|
|
126
|
+
description: "Move a message to another folder (same account). FULL scope only.",
|
|
127
|
+
inputSchema: obj({ accountId: str("Account id"), uid: num("Message uid"), folderId: num("Source folder id"), targetFolderId: num("Destination folder id") }, ["accountId", "uid", "folderId", "targetFolderId"]),
|
|
128
|
+
fullOnly: true,
|
|
129
|
+
run: async (a) => rpc("moveMessages", { accountId: a.accountId, uids: [a.uid], folderIds: [a.folderId], targetFolderId: a.targetFolderId }),
|
|
130
|
+
},
|
|
131
|
+
create_draft: {
|
|
132
|
+
description: "Create a draft (NOT sent — drafts are for the human to review and send). FULL scope only.",
|
|
133
|
+
inputSchema: obj({ accountId: str("Account id to draft from"), to: str("To recipients, comma-separated"), cc: str("Cc recipients (optional)"), subject: str("Subject"), bodyText: str("Plain-text body") }, ["accountId", "to", "subject", "bodyText"]),
|
|
134
|
+
fullOnly: true,
|
|
135
|
+
run: async (a) => rpc("saveDraft", { accountId: a.accountId, subject: a.subject, bodyHtml: String(a.bodyText).replace(/&/g, "&").replace(/</g, "<").replace(/\n/g, "<br>"), bodyText: a.bodyText, to: a.to, cc: a.cc || "" }),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
// ── MCP stdio plumbing (JSON-RPC 2.0, one message per line) ──
|
|
139
|
+
const out = (msg) => { process.stdout.write(JSON.stringify(msg) + "\n"); };
|
|
140
|
+
function toolList() {
|
|
141
|
+
return Object.entries(TOOLS)
|
|
142
|
+
.filter(([, t]) => FULL || !t.fullOnly)
|
|
143
|
+
.map(([name, t]) => ({ name, description: t.description, inputSchema: t.inputSchema }));
|
|
144
|
+
}
|
|
145
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
146
|
+
rl.on("line", (line) => { void handle(line); });
|
|
147
|
+
async function handle(line) {
|
|
148
|
+
if (!line.trim())
|
|
149
|
+
return;
|
|
150
|
+
let req;
|
|
151
|
+
try {
|
|
152
|
+
req = JSON.parse(line);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const { id, method, params } = req;
|
|
158
|
+
const reply = (result) => out({ jsonrpc: "2.0", id, result });
|
|
159
|
+
const fail = (code, message) => out({ jsonrpc: "2.0", id, error: { code, message } });
|
|
160
|
+
try {
|
|
161
|
+
switch (method) {
|
|
162
|
+
case "initialize":
|
|
163
|
+
reply({
|
|
164
|
+
protocolVersion: params?.protocolVersion || "2024-11-05",
|
|
165
|
+
capabilities: { tools: {} },
|
|
166
|
+
serverInfo: { name: "rmfmail", version: "1.0.0" },
|
|
167
|
+
instructions: `Email triage over the local rmfmail daemon (scope: ${FULL ? "full — includes move + draft creation" : "triage — reads and flags only"}). There is no send tool: draft, never send.`,
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
case "notifications/initialized":
|
|
171
|
+
case "notifications/cancelled":
|
|
172
|
+
return; // notifications get no response
|
|
173
|
+
case "tools/list":
|
|
174
|
+
reply({ tools: toolList() });
|
|
175
|
+
return;
|
|
176
|
+
case "tools/call": {
|
|
177
|
+
const tool = TOOLS[params?.name];
|
|
178
|
+
if (!tool || (tool.fullOnly && !FULL)) {
|
|
179
|
+
fail(-32602, `unknown tool: ${params?.name}`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const result = await tool.run(params?.arguments || {});
|
|
184
|
+
reply({ content: [{ type: "text", text: JSON.stringify(result, null, 1) }] });
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
reply({ content: [{ type: "text", text: `Error: ${e?.message || e}` }], isError: true });
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
case "ping":
|
|
192
|
+
reply({});
|
|
193
|
+
return;
|
|
194
|
+
default:
|
|
195
|
+
if (id !== undefined)
|
|
196
|
+
fail(-32601, `method not found: ${method}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
200
|
+
if (id !== undefined)
|
|
201
|
+
fail(-32603, e?.message || String(e));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["mcp-server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,UAAU,CAAC,CAAC;AAC7F,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AACvD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC;AAIlD,SAAS,aAAa;IAClB,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QAAC,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAAC,CAAC;IACnD,MAAM,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,kCAAkC,UAAU,4BAA4B,CAAC,CAAC;IAAC,CAAC;IACpG,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IAC1C,IAAI,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAAC,CAAC;IAClC,MAAM,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,GAAG,+BAA+B,CAAC,CAAC;IAAC,CAAC;IAC/F,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,IAAI,MAAM,GAAG,CAAC,CAAC;AACf,KAAK,UAAU,GAAG,CAAC,MAAc,EAAE,SAA8B,EAAE;IAC/D,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC3D,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,MAAM,KAAK,EAAE,EAAE;QAC/C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;KAChF,CAAC,CAAC;IACH,IAAI,CAAC,CAAC,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAQ,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,GAAG,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,GAAG,CAAC,MAAM,CAAC;AACtB,CAAC;AAED,cAAc;AAEd;gDACgD;AAChD,SAAS,WAAW,CAAC,CAAM,EAAE,WAAoB;IAC7C,MAAM,GAAG,GAAG,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACvF,MAAM,IAAI,GAAG,CAAC,CAAM,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9G,MAAM,GAAG,GAAQ;QACb,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACxD,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,SAAS;QAC7E,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO;QACpD,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,SAAS;KAClC,CAAC;IACF,IAAI,WAAW,EAAE,CAAC;QACd,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC;QACvC,oDAAoD;QACpD,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ;YAAE,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACjL,IAAI,CAAC,CAAC,SAAS;YAAE,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;QAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YACvD,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9H,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AASD,MAAM,GAAG,GAAG,CAAC,WAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;AACvE,MAAM,GAAG,GAAG,CAAC,WAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;AACvE,MAAM,IAAI,GAAG,CAAC,WAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;AACzE,MAAM,GAAG,GAAG,CAAC,KAAU,EAAE,QAAkB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;AAElG,MAAM,KAAK,GAAyB;IAChC,aAAa,EAAE;QACX,WAAW,EAAE,kDAAkD;QAC/D,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;QACxB,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;KAC5G;IACD,YAAY,EAAE;QACV,WAAW,EAAE,wDAAwD;QACrE,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,+BAA+B,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC;QACpF,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;KAC3M;IACD,aAAa,EAAE;QACX,WAAW,EAAE,uGAAuG;QACpH,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,6BAA6B,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,yBAAyB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACjK,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACb,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;YACtH,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;QACrJ,CAAC;KACJ;IACD,eAAe,EAAE;QACb,WAAW,EAAE,0GAA0G;QACvH,WAAW,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,wCAAwC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;QAC5H,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACb,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAClL,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;QAChG,CAAC;KACJ;IACD,WAAW,EAAE;QACT,WAAW,EAAE,gEAAgE;QAC7E,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,4BAA4B,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QAC1J,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC;KACjJ;IACD,YAAY,EAAE;QACV,WAAW,EAAE,yIAAyI;QACtJ,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,oBAAoB,EAAE,EAAE,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAC1O,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;KACrH;IACD,YAAY,EAAE;QACV,WAAW,EAAE,mEAAmE;QAChF,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,kBAAkB,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,uBAAuB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;QAChN,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,cAAc,EAAE,CAAC;KAC9I;IACD,YAAY,EAAE;QACV,WAAW,EAAE,2FAA2F;QACxG,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,0BAA0B,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,gCAAgC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,0BAA0B,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QACvP,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;KACvO;CACJ,CAAC;AAEF,gEAAgE;AAEhE,MAAM,GAAG,GAAG,CAAC,GAAQ,EAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtF,SAAS,QAAQ;IACb,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SACvB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/E,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhD,KAAK,UAAU,MAAM,CAAC,IAAY;IAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO;IACzB,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO;IAAC,CAAC;IACjD,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACnC,MAAM,KAAK,GAAG,CAAC,MAAW,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACnE,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,OAAe,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACtG,IAAI,CAAC;QACD,QAAQ,MAAM,EAAE,CAAC;YACb,KAAK,YAAY;gBACb,KAAK,CAAC;oBACF,eAAe,EAAE,MAAM,EAAE,eAAe,IAAI,YAAY;oBACxD,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;oBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;oBACjD,YAAY,EAAE,sDAAsD,IAAI,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,+BAA+B,8CAA8C;iBACrM,CAAC,CAAC;gBACH,OAAO;YACX,KAAK,2BAA2B,CAAC;YACjC,KAAK,yBAAyB;gBAC1B,OAAO,CAAC,gCAAgC;YAC5C,KAAK,YAAY;gBACb,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;gBAC7B,OAAO;YACX,KAAK,YAAY,CAAC,CAAC,CAAC;gBAChB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBACjC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAAC,IAAI,CAAC,CAAC,KAAK,EAAE,iBAAiB,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACjG,IAAI,CAAC;oBACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;oBACvD,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAClF,CAAC;gBAAC,OAAO,CAAM,EAAE,CAAC;oBACd,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC7F,CAAC;gBACD,OAAO;YACX,CAAC;YACD,KAAK,MAAM;gBACP,KAAK,CAAC,EAAE,CAAC,CAAC;gBACV,OAAO;YACX;gBACI,IAAI,EAAE,KAAK,SAAS;oBAAE,IAAI,CAAC,CAAC,KAAK,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC;QAC1E,CAAC;IACL,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACd,IAAI,EAAE,KAAK,SAAS;YAAE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* rmfmail-mcp — Model Context Protocol server over the running rmfmail
|
|
4
|
+
* daemon, so an AI (Claude Code, Claude Desktop, anything MCP-speaking) can
|
|
5
|
+
* process mail on the user's behalf.
|
|
6
|
+
*
|
|
7
|
+
* claude mcp add rmfmail -- rmfmail-mcp
|
|
8
|
+
*
|
|
9
|
+
* Transport: MCP stdio (newline-delimited JSON-RPC 2.0). Hand-rolled — the
|
|
10
|
+
* protocol subset needed (initialize / tools/list / tools/call) is ~100
|
|
11
|
+
* lines and not worth an SDK dependency.
|
|
12
|
+
*
|
|
13
|
+
* Backend: the daemon's /rpc endpoint, discovered via ~/.rmfmail/agent.json
|
|
14
|
+
* (written each boot, removed on shutdown; a dead pid means stale). Scope:
|
|
15
|
+
* the TRIAGE token by default — reads plus flag/mark-read. Set
|
|
16
|
+
* RMFMAIL_MCP_FULL=1 to use the full token, which unlocks move_message and
|
|
17
|
+
* create_draft. There is deliberately NO send tool at either scope: AI
|
|
18
|
+
* drafts, the human sends (standing policy).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import readline from "node:readline";
|
|
24
|
+
|
|
25
|
+
const CONFIG_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".rmfmail");
|
|
26
|
+
const AGENT_JSON = path.join(CONFIG_DIR, "agent.json");
|
|
27
|
+
const FULL = process.env.RMFMAIL_MCP_FULL === "1";
|
|
28
|
+
|
|
29
|
+
interface AgentInfo { rpcUrl: string; tokens: { triage: string; full: string }; pid: number; version: string }
|
|
30
|
+
|
|
31
|
+
function loadAgentInfo(): AgentInfo {
|
|
32
|
+
let raw: string;
|
|
33
|
+
try { raw = fs.readFileSync(AGENT_JSON, "utf-8"); }
|
|
34
|
+
catch { throw new Error(`rmfmail daemon not running (no ${AGENT_JSON}) — start it with: rmfmail`); }
|
|
35
|
+
const info = JSON.parse(raw) as AgentInfo;
|
|
36
|
+
try { process.kill(info.pid, 0); }
|
|
37
|
+
catch { throw new Error(`agent.json is stale (pid ${info.pid} not running) — start rmfmail`); }
|
|
38
|
+
return info;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let rpcSeq = 0;
|
|
42
|
+
async function rpc(action: string, params: Record<string, any> = {}): Promise<any> {
|
|
43
|
+
const info = loadAgentInfo();
|
|
44
|
+
const token = FULL ? info.tokens.full : info.tokens.triage;
|
|
45
|
+
const r = await fetch(`${info.rpcUrl}?t=${token}`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "content-type": "application/json" },
|
|
48
|
+
body: JSON.stringify({ _action: action, _cbid: String(++rpcSeq), ...params }),
|
|
49
|
+
});
|
|
50
|
+
if (!r.ok) throw new Error(`daemon rpc HTTP ${r.status}`);
|
|
51
|
+
const res: any = await r.json();
|
|
52
|
+
if (res.error) throw new Error(res.error);
|
|
53
|
+
return res.result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ── Tools ──
|
|
57
|
+
|
|
58
|
+
/** Trim a message object down to what an LLM needs — full envelopes carry
|
|
59
|
+
* parsed MIME internals that waste context. */
|
|
60
|
+
function slimMessage(m: any, includeBody: boolean): any {
|
|
61
|
+
const one = (x: any) => x?.name ? `${x.name} <${x.address}>` : (x?.address || x || "");
|
|
62
|
+
const addr = (a: any) => Array.isArray(a) ? a.map(one).join(", ") : (a && typeof a === "object" ? one(a) : a);
|
|
63
|
+
const out: any = {
|
|
64
|
+
accountId: m.accountId, uid: m.uid, folderId: m.folderId,
|
|
65
|
+
date: m.date, from: addr(m.from), to: addr(m.to), cc: addr(m.cc) || undefined,
|
|
66
|
+
subject: m.subject, seen: m.seen, flagged: m.flagged,
|
|
67
|
+
snippet: m.preview || undefined,
|
|
68
|
+
};
|
|
69
|
+
if (includeBody) {
|
|
70
|
+
out.bodyText = m.bodyText || undefined;
|
|
71
|
+
// Fall back to a crude strip when only HTML exists.
|
|
72
|
+
if (!out.bodyText && m.bodyHtml) out.bodyText = String(m.bodyHtml).replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 20000);
|
|
73
|
+
if (m.bodyError) out.bodyError = m.bodyError;
|
|
74
|
+
if (Array.isArray(m.attachments) && m.attachments.length) {
|
|
75
|
+
out.attachments = m.attachments.map((a: any) => ({ id: a.id, filename: a.filename, mimeType: a.mimeType, size: a.size }));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type Tool = {
|
|
82
|
+
description: string;
|
|
83
|
+
inputSchema: any;
|
|
84
|
+
fullOnly?: boolean;
|
|
85
|
+
run: (a: any) => Promise<any>;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const str = (description: string) => ({ type: "string", description });
|
|
89
|
+
const num = (description: string) => ({ type: "number", description });
|
|
90
|
+
const bool = (description: string) => ({ type: "boolean", description });
|
|
91
|
+
const obj = (props: any, required: string[]) => ({ type: "object", properties: props, required });
|
|
92
|
+
|
|
93
|
+
const TOOLS: Record<string, Tool> = {
|
|
94
|
+
list_accounts: {
|
|
95
|
+
description: "List configured mail accounts (id, name, email).",
|
|
96
|
+
inputSchema: obj({}, []),
|
|
97
|
+
run: async () => (await rpc("getAccounts")).map((a: any) => ({ id: a.id, name: a.name, email: a.email })),
|
|
98
|
+
},
|
|
99
|
+
list_folders: {
|
|
100
|
+
description: "List folders for an account, with unread/total counts.",
|
|
101
|
+
inputSchema: obj({ accountId: str("Account id from list_accounts") }, ["accountId"]),
|
|
102
|
+
run: async (a) => (await rpc("getFolders", { accountId: a.accountId })).map((f: any) => ({ id: f.id, path: f.path, specialUse: f.specialUse || undefined, unread: f.unreadCount, total: f.totalCount })),
|
|
103
|
+
},
|
|
104
|
+
list_messages: {
|
|
105
|
+
description: "List messages in a folder, newest first (paged, 50/page). Returns envelopes with snippets, no bodies.",
|
|
106
|
+
inputSchema: obj({ accountId: str("Account id"), folderId: num("Folder id from list_folders"), page: num("1-based page, default 1") }, ["accountId", "folderId"]),
|
|
107
|
+
run: async (a) => {
|
|
108
|
+
const r = await rpc("getMessages", { accountId: a.accountId, folderId: a.folderId, page: a.page || 1, pageSize: 50 });
|
|
109
|
+
return { total: r.total, messages: (r.items || []).map((m: any) => slimMessage({ ...m, accountId: a.accountId, folderId: a.folderId }, false)) };
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
search_messages: {
|
|
113
|
+
description: "Full-text search across all local mail (FTS). Query supports plain words; results span accounts/folders.",
|
|
114
|
+
inputSchema: obj({ query: str("Search text"), includeTrashSpam: bool("Also search Trash/Spam (default false)") }, ["query"]),
|
|
115
|
+
run: async (a) => {
|
|
116
|
+
const r = await rpc("searchMessages", { query: (a.query || "").trim(), page: 1, pageSize: 50, scope: "all", accountId: "", folderId: 0, includeTrashSpam: !!a.includeTrashSpam });
|
|
117
|
+
return { total: r.total, messages: (r.items || []).map((m: any) => slimMessage(m, false)) };
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
get_message: {
|
|
121
|
+
description: "Fetch one message including its text body and attachment list.",
|
|
122
|
+
inputSchema: obj({ accountId: str("Account id"), uid: num("Message uid"), folderId: num("Folder id the uid lives in") }, ["accountId", "uid", "folderId"]),
|
|
123
|
+
run: async (a) => slimMessage(await rpc("getMessage", { accountId: a.accountId, uid: a.uid, folderId: a.folderId, allowRemote: false }), true),
|
|
124
|
+
},
|
|
125
|
+
flag_message: {
|
|
126
|
+
description: "Set or clear flags on a message. flags is the COMPLETE new flag list, e.g. [\"\\\\Seen\", \"\\\\Flagged\"] or [\"\\\\Seen\"] to unflag.",
|
|
127
|
+
inputSchema: obj({ accountId: str("Account id"), uid: num("Message uid"), folderId: num("Folder id"), flags: { type: "array", items: { type: "string" }, description: "Complete flag list" } }, ["accountId", "uid", "folderId", "flags"]),
|
|
128
|
+
run: async (a) => rpc("updateFlags", { accountId: a.accountId, uid: a.uid, folderId: a.folderId, flags: a.flags }),
|
|
129
|
+
},
|
|
130
|
+
move_message: {
|
|
131
|
+
description: "Move a message to another folder (same account). FULL scope only.",
|
|
132
|
+
inputSchema: obj({ accountId: str("Account id"), uid: num("Message uid"), folderId: num("Source folder id"), targetFolderId: num("Destination folder id") }, ["accountId", "uid", "folderId", "targetFolderId"]),
|
|
133
|
+
fullOnly: true,
|
|
134
|
+
run: async (a) => rpc("moveMessages", { accountId: a.accountId, uids: [a.uid], folderIds: [a.folderId], targetFolderId: a.targetFolderId }),
|
|
135
|
+
},
|
|
136
|
+
create_draft: {
|
|
137
|
+
description: "Create a draft (NOT sent — drafts are for the human to review and send). FULL scope only.",
|
|
138
|
+
inputSchema: obj({ accountId: str("Account id to draft from"), to: str("To recipients, comma-separated"), cc: str("Cc recipients (optional)"), subject: str("Subject"), bodyText: str("Plain-text body") }, ["accountId", "to", "subject", "bodyText"]),
|
|
139
|
+
fullOnly: true,
|
|
140
|
+
run: async (a) => rpc("saveDraft", { accountId: a.accountId, subject: a.subject, bodyHtml: String(a.bodyText).replace(/&/g, "&").replace(/</g, "<").replace(/\n/g, "<br>"), bodyText: a.bodyText, to: a.to, cc: a.cc || "" }),
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// ── MCP stdio plumbing (JSON-RPC 2.0, one message per line) ──
|
|
145
|
+
|
|
146
|
+
const out = (msg: any): void => { process.stdout.write(JSON.stringify(msg) + "\n"); };
|
|
147
|
+
|
|
148
|
+
function toolList(): any[] {
|
|
149
|
+
return Object.entries(TOOLS)
|
|
150
|
+
.filter(([, t]) => FULL || !t.fullOnly)
|
|
151
|
+
.map(([name, t]) => ({ name, description: t.description, inputSchema: t.inputSchema }));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
155
|
+
rl.on("line", (line) => { void handle(line); });
|
|
156
|
+
|
|
157
|
+
async function handle(line: string): Promise<void> {
|
|
158
|
+
if (!line.trim()) return;
|
|
159
|
+
let req: any;
|
|
160
|
+
try { req = JSON.parse(line); } catch { return; }
|
|
161
|
+
const { id, method, params } = req;
|
|
162
|
+
const reply = (result: any) => out({ jsonrpc: "2.0", id, result });
|
|
163
|
+
const fail = (code: number, message: string) => out({ jsonrpc: "2.0", id, error: { code, message } });
|
|
164
|
+
try {
|
|
165
|
+
switch (method) {
|
|
166
|
+
case "initialize":
|
|
167
|
+
reply({
|
|
168
|
+
protocolVersion: params?.protocolVersion || "2024-11-05",
|
|
169
|
+
capabilities: { tools: {} },
|
|
170
|
+
serverInfo: { name: "rmfmail", version: "1.0.0" },
|
|
171
|
+
instructions: `Email triage over the local rmfmail daemon (scope: ${FULL ? "full — includes move + draft creation" : "triage — reads and flags only"}). There is no send tool: draft, never send.`,
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
case "notifications/initialized":
|
|
175
|
+
case "notifications/cancelled":
|
|
176
|
+
return; // notifications get no response
|
|
177
|
+
case "tools/list":
|
|
178
|
+
reply({ tools: toolList() });
|
|
179
|
+
return;
|
|
180
|
+
case "tools/call": {
|
|
181
|
+
const tool = TOOLS[params?.name];
|
|
182
|
+
if (!tool || (tool.fullOnly && !FULL)) { fail(-32602, `unknown tool: ${params?.name}`); return; }
|
|
183
|
+
try {
|
|
184
|
+
const result = await tool.run(params?.arguments || {});
|
|
185
|
+
reply({ content: [{ type: "text", text: JSON.stringify(result, null, 1) }] });
|
|
186
|
+
} catch (e: any) {
|
|
187
|
+
reply({ content: [{ type: "text", text: `Error: ${e?.message || e}` }], isError: true });
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
case "ping":
|
|
192
|
+
reply({});
|
|
193
|
+
return;
|
|
194
|
+
default:
|
|
195
|
+
if (id !== undefined) fail(-32601, `method not found: ${method}`);
|
|
196
|
+
}
|
|
197
|
+
} catch (e: any) {
|
|
198
|
+
if (id !== undefined) fail(-32603, e?.message || String(e));
|
|
199
|
+
}
|
|
200
|
+
}
|
package/bin/popout-server.js
CHANGED
|
@@ -31,6 +31,18 @@ import { dispatch } from "@bobfrankston/mailx-service/jsonrpc.js";
|
|
|
31
31
|
* window. Returns null if the server can't bind (popout disabled). */
|
|
32
32
|
export async function startPopoutServer(svc, onAction) {
|
|
33
33
|
const token = crypto.randomBytes(18).toString("hex");
|
|
34
|
+
const agentTokens = { triage: crypto.randomBytes(18).toString("hex"), full: crypto.randomBytes(18).toString("hex") };
|
|
35
|
+
// Actions a TRIAGE-scoped agent may call: reads plus flag/read-state.
|
|
36
|
+
// Deliberately excludes send/move/delete/settings and every popout/window
|
|
37
|
+
// action. Full-scope agents get the whole dispatcher.
|
|
38
|
+
const TRIAGE_ACTIONS = new Set([
|
|
39
|
+
"getVersion", "getAccounts", "getFolders", "getMessages", "getUnifiedInbox",
|
|
40
|
+
"getMessage", "searchMessages", "getThreadMessages", "getAttachment",
|
|
41
|
+
"getMessageSource", "searchContacts", "listContacts", "getCalendarEvents",
|
|
42
|
+
"getCalendars", "getTasks", "getOutboxStatus", "getSyncPending",
|
|
43
|
+
"getDiagnostics", "getPriorityLists", "hasCcHistoryTo", "hasBccHistoryTo",
|
|
44
|
+
"updateFlags", "markFolderRead", "logClientEvent",
|
|
45
|
+
]);
|
|
34
46
|
// Static root for /app/<token>/... — the app package root, so pages under
|
|
35
47
|
// client/ can reach ../styles, ../../node_modules etc. exactly as they do
|
|
36
48
|
// through msger's custom protocol.
|
|
@@ -53,7 +65,13 @@ export async function startPopoutServer(svc, onAction) {
|
|
|
53
65
|
return;
|
|
54
66
|
}
|
|
55
67
|
// Token gate on every request — loopback TCP is locally reachable.
|
|
56
|
-
|
|
68
|
+
// Three tokens: the per-launch window token (full surface), and two
|
|
69
|
+
// agent tokens published in ~/.rmfmail/agent.json.
|
|
70
|
+
const presented = url.searchParams.get("t");
|
|
71
|
+
const isWindowToken = presented === token;
|
|
72
|
+
const isFullAgent = presented === agentTokens.full;
|
|
73
|
+
const isTriageAgent = presented === agentTokens.triage;
|
|
74
|
+
if (!isWindowToken && !isFullAgent && !isTriageAgent) {
|
|
57
75
|
res.writeHead(403).end("forbidden");
|
|
58
76
|
return;
|
|
59
77
|
}
|
|
@@ -90,6 +108,11 @@ export async function startPopoutServer(svc, onAction) {
|
|
|
90
108
|
res.writeHead(400).end("bad rpc request");
|
|
91
109
|
return;
|
|
92
110
|
}
|
|
111
|
+
if (isTriageAgent && !TRIAGE_ACTIONS.has(rpcReq._action)) {
|
|
112
|
+
res.writeHead(200, { "content-type": "application/json", "cache-control": "no-store" });
|
|
113
|
+
res.end(JSON.stringify({ _cbid: rpcReq._cbid, error: `action "${rpcReq._action}" requires the full agent token (triage scope is reads + flags)` }));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
93
116
|
const rpcRes = await dispatch(svc, rpcReq);
|
|
94
117
|
res.writeHead(200, { "content-type": "application/json", "cache-control": "no-store" });
|
|
95
118
|
res.end(JSON.stringify(rpcRes));
|
|
@@ -185,7 +208,7 @@ export async function startPopoutServer(svc, onAction) {
|
|
|
185
208
|
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
186
209
|
if (port) {
|
|
187
210
|
console.log(` [popout] window server on http://127.0.0.1:${port} (loopback, token-gated)`);
|
|
188
|
-
resolve({ port, token, broadcastEvent });
|
|
211
|
+
resolve({ port, token, agentTokens, broadcastEvent });
|
|
189
212
|
}
|
|
190
213
|
else {
|
|
191
214
|
resolve(null);
|
package/bin/popout-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popout-server.js","sourceRoot":"","sources":["popout-server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"popout-server.js","sourceRoot":"","sources":["popout-server.ts"],"names":[],"mappings":"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"}
|
package/bin/popout-server.ts
CHANGED
|
@@ -29,6 +29,11 @@ import { dispatch } from "@bobfrankston/mailx-service/jsonrpc.js";
|
|
|
29
29
|
export interface PopoutServerInfo {
|
|
30
30
|
port: number;
|
|
31
31
|
token: string;
|
|
32
|
+
/** Agent tokens (written to ~/.rmfmail/agent.json for third-party apps
|
|
33
|
+
* and AI agents). `triage` = reads + flagging; `full` = everything the
|
|
34
|
+
* UI can do. Sending remains a human act by convention — the MCP layer
|
|
35
|
+
* exposes drafts, not send. */
|
|
36
|
+
agentTokens: { triage: string; full: string };
|
|
32
37
|
/** Push a daemon event to every connected popout/secondary window
|
|
33
38
|
* (SSE). The main window gets events over the msger service channel;
|
|
34
39
|
* popout-served pages subscribe to GET /events and receive the same
|
|
@@ -49,6 +54,18 @@ export interface PopoutAction {
|
|
|
49
54
|
* window. Returns null if the server can't bind (popout disabled). */
|
|
50
55
|
export async function startPopoutServer(svc: any, onAction?: (act: PopoutAction) => void): Promise<PopoutServerInfo | null> {
|
|
51
56
|
const token = crypto.randomBytes(18).toString("hex");
|
|
57
|
+
const agentTokens = { triage: crypto.randomBytes(18).toString("hex"), full: crypto.randomBytes(18).toString("hex") };
|
|
58
|
+
// Actions a TRIAGE-scoped agent may call: reads plus flag/read-state.
|
|
59
|
+
// Deliberately excludes send/move/delete/settings and every popout/window
|
|
60
|
+
// action. Full-scope agents get the whole dispatcher.
|
|
61
|
+
const TRIAGE_ACTIONS = new Set([
|
|
62
|
+
"getVersion", "getAccounts", "getFolders", "getMessages", "getUnifiedInbox",
|
|
63
|
+
"getMessage", "searchMessages", "getThreadMessages", "getAttachment",
|
|
64
|
+
"getMessageSource", "searchContacts", "listContacts", "getCalendarEvents",
|
|
65
|
+
"getCalendars", "getTasks", "getOutboxStatus", "getSyncPending",
|
|
66
|
+
"getDiagnostics", "getPriorityLists", "hasCcHistoryTo", "hasBccHistoryTo",
|
|
67
|
+
"updateFlags", "markFolderRead", "logClientEvent",
|
|
68
|
+
]);
|
|
52
69
|
// Static root for /app/<token>/... — the app package root, so pages under
|
|
53
70
|
// client/ can reach ../styles, ../../node_modules etc. exactly as they do
|
|
54
71
|
// through msger's custom protocol.
|
|
@@ -74,7 +91,13 @@ export async function startPopoutServer(svc: any, onAction?: (act: PopoutAction)
|
|
|
74
91
|
}
|
|
75
92
|
|
|
76
93
|
// Token gate on every request — loopback TCP is locally reachable.
|
|
77
|
-
|
|
94
|
+
// Three tokens: the per-launch window token (full surface), and two
|
|
95
|
+
// agent tokens published in ~/.rmfmail/agent.json.
|
|
96
|
+
const presented = url.searchParams.get("t");
|
|
97
|
+
const isWindowToken = presented === token;
|
|
98
|
+
const isFullAgent = presented === agentTokens.full;
|
|
99
|
+
const isTriageAgent = presented === agentTokens.triage;
|
|
100
|
+
if (!isWindowToken && !isFullAgent && !isTriageAgent) {
|
|
78
101
|
res.writeHead(403).end("forbidden");
|
|
79
102
|
return;
|
|
80
103
|
}
|
|
@@ -109,6 +132,11 @@ export async function startPopoutServer(svc: any, onAction?: (act: PopoutAction)
|
|
|
109
132
|
res.writeHead(400).end("bad rpc request");
|
|
110
133
|
return;
|
|
111
134
|
}
|
|
135
|
+
if (isTriageAgent && !TRIAGE_ACTIONS.has(rpcReq._action)) {
|
|
136
|
+
res.writeHead(200, { "content-type": "application/json", "cache-control": "no-store" });
|
|
137
|
+
res.end(JSON.stringify({ _cbid: rpcReq._cbid, error: `action "${rpcReq._action}" requires the full agent token (triage scope is reads + flags)` }));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
112
140
|
const rpcRes = await dispatch(svc, rpcReq);
|
|
113
141
|
res.writeHead(200, { "content-type": "application/json", "cache-control": "no-store" });
|
|
114
142
|
res.end(JSON.stringify(rpcRes));
|
|
@@ -183,7 +211,7 @@ export async function startPopoutServer(svc: any, onAction?: (act: PopoutAction)
|
|
|
183
211
|
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
184
212
|
if (port) {
|
|
185
213
|
console.log(` [popout] window server on http://127.0.0.1:${port} (loopback, token-gated)`);
|
|
186
|
-
resolve({ port, token, broadcastEvent });
|
|
214
|
+
resolve({ port, token, agentTokens, broadcastEvent });
|
|
187
215
|
} else {
|
|
188
216
|
resolve(null);
|
|
189
217
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/rmfmail",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.131",
|
|
4
4
|
"description": "Local-first email client with IMAP sync and standalone native app",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/mailx.js",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"node": ">=24.2.0"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
|
-
"rmfmail": "bin/mailx.js"
|
|
11
|
+
"rmfmail": "bin/mailx.js",
|
|
12
|
+
"rmfmail-mcp": "bin/mcp-server.js"
|
|
12
13
|
},
|
|
13
14
|
"workspaces": [
|
|
14
15
|
"packages/mailx-types",
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
"@bobfrankston/mailx-store-web": "^0.1.38",
|
|
40
41
|
"@bobfrankston/mailx-sync": "^0.1.27",
|
|
41
42
|
"@bobfrankston/miscinfo": "^1.0.13",
|
|
42
|
-
"@bobfrankston/msger": "^0.1.
|
|
43
|
+
"@bobfrankston/msger": "^0.1.391",
|
|
43
44
|
"@bobfrankston/node-tcp-transport": "^0.1.10",
|
|
44
45
|
"@bobfrankston/oauthsupport": "^1.0.34",
|
|
45
46
|
"@bobfrankston/rmf-tiny": "^0.1.38",
|
|
@@ -117,7 +118,7 @@
|
|
|
117
118
|
"@bobfrankston/mailx-store-web": "^0.1.38",
|
|
118
119
|
"@bobfrankston/mailx-sync": "^0.1.27",
|
|
119
120
|
"@bobfrankston/miscinfo": "^1.0.13",
|
|
120
|
-
"@bobfrankston/msger": "^0.1.
|
|
121
|
+
"@bobfrankston/msger": "^0.1.391",
|
|
121
122
|
"@bobfrankston/node-tcp-transport": "^0.1.10",
|
|
122
123
|
"@bobfrankston/oauthsupport": "^1.0.34",
|
|
123
124
|
"@bobfrankston/rmf-tiny": "^0.1.38",
|