@agenticmail/mcp 0.7.9 → 0.9.1
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 +6 -1
- package/dist/index.js +59 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,12 @@ The MCP (Model Context Protocol) server for [AgenticMail](https://github.com/age
|
|
|
8
8
|
|
|
9
9
|
When connected, your AI agent can send emails and texts, check inboxes, reply to messages, receive verification codes, manage contacts, schedule emails, assign tasks to other agents, and more — all through natural language. The server provides 62 tools that cover every email, SMS, and agent management operation.
|
|
10
10
|
|
|
11
|
-
## ✨ What's new in 0.
|
|
11
|
+
## ✨ What's new in 0.9.0
|
|
12
|
+
|
|
13
|
+
- **🧠 `get_thread_id` + `save_thread_memory`** — two new tools in the `multi_agent_extras` tier. Workers call `get_thread_id({uid})` once after reading a new message, then `save_thread_memory({threadId, summary, commitments?, openQuestions?, lastAction?, lastUid?})` at end-of-wake. The dispatcher reads the memory back into the next wake's prompt automatically. Pairs with the dispatcher-side ThreadCache to flatten wake cost — agents no longer have to re-read 10 prior messages every time.
|
|
14
|
+
- **🎯 `send_email` / `reply_email` / `forward_email` / `template_send` docs updated** for the new `wake` defaults. CC'd local agents no longer wake by default; `wake: 'all'` opts back into the pre-0.9.0 behaviour.
|
|
15
|
+
|
|
16
|
+
## ✨ Earlier — 0.7.9
|
|
12
17
|
|
|
13
18
|
- **📐 `call_agent` accepts `outputSchema`** — pass a JSON Schema (draft-7 subset) describing the deliverable shape and the API validates `submit_result` against it; mismatches come back as validator errors so the worker can retry with a correct shape instead of returning free-form prose. The schema is rendered into the worker's wake prompt up-front. Example:
|
|
14
19
|
```js
|
package/dist/index.js
CHANGED
|
@@ -22406,6 +22406,13 @@ var TOOL_SETS = {
|
|
|
22406
22406
|
// the running log of what it actually did — every tool call, every
|
|
22407
22407
|
// result. Paired with check_activity so they ship in the same tier.
|
|
22408
22408
|
"tail_worker",
|
|
22409
|
+
// Wake-context memory tools. Agents call get_thread_id once when
|
|
22410
|
+
// they read a message to find the stable thread id, then
|
|
22411
|
+
// save_thread_memory at end-of-wake to persist their judgment.
|
|
22412
|
+
// The dispatcher reads both back into the next wake's prompt so
|
|
22413
|
+
// the agent doesn't re-read prior messages from scratch.
|
|
22414
|
+
"get_thread_id",
|
|
22415
|
+
"save_thread_memory",
|
|
22409
22416
|
"check_tasks"
|
|
22410
22417
|
],
|
|
22411
22418
|
/** Less-common mail operations. */
|
|
@@ -22620,7 +22627,7 @@ async function apiRequest(method, path, body, useMasterKey = false, timeoutMs =
|
|
|
22620
22627
|
var toolDefinitions = [
|
|
22621
22628
|
{
|
|
22622
22629
|
name: "send_email",
|
|
22623
|
-
description:
|
|
22630
|
+
description: 'Send an email from the agent\'s mailbox. Supports multiple recipients on To and CC (comma-separated). The PRIMARY primitive for multi-agent coordination. WAKE SEMANTICS (changed in 0.9.0): by default only local @localhost recipients on `To:` get a Claude wake; CC\'d local agents receive the mail but don\'t wake \u2014 they see it on their next natural wake (replies addressed to them, or a future inbox check). This mirrors the email convention "To is for action, CC is for awareness" and prevents wake-thrash on multi-CC threads. To override: pass `wake: ["alice","bob"]` to wake specific agents regardless of To/CC position, or `wake: "all"` to opt back into the pre-0.9.0 "wake every CC\'d recipient" behaviour. Pass `wake: []` to deliver silently with no wakes at all. External emails are scanned for sensitive content; HIGH severity detections are BLOCKED for owner approval.',
|
|
22624
22631
|
inputSchema: {
|
|
22625
22632
|
type: "object",
|
|
22626
22633
|
properties: {
|
|
@@ -22628,11 +22635,9 @@ var toolDefinitions = [
|
|
|
22628
22635
|
subject: { type: "string", description: "Email subject line" },
|
|
22629
22636
|
text: { type: "string", description: "Plain text body" },
|
|
22630
22637
|
html: { type: "string", description: "HTML body (optional)" },
|
|
22631
|
-
cc: { type: "string", description: 'CC recipients \u2014 the team. Comma-separated, e.g. "vesper@localhost, orion@localhost".
|
|
22638
|
+
cc: { type: "string", description: 'CC recipients \u2014 the team. Comma-separated, e.g. "vesper@localhost, orion@localhost". CC\'d local recipients receive the mail but DO NOT wake by default (0.9.0+). Put the actor on `to`; CC the rest for awareness.' },
|
|
22632
22639
|
wake: {
|
|
22633
|
-
|
|
22634
|
-
items: { type: "string" },
|
|
22635
|
-
description: 'Optional. Names (or @localhost addresses) of the agents the dispatcher should give a Claude turn to when this mail lands. CC\'d agents NOT in this list still receive the email but get no Claude turn \u2014 they will see it the next time someone explicitly wakes them or they check their inbox. Use this to scope cost on large threads: send to 15 agents but wake only the 1 or 2 who need to act next. Pass an empty array `[]` for "deliver silently \u2014 wake nobody". Omit entirely to keep the default "wake everyone CC\'d" behaviour.'
|
|
22640
|
+
description: 'Optional wake-control. Accepts: (1) an array of agent names \u2014 `["alice","bob"]` \u2014 to wake exactly those agents (overrides default To-only behaviour); (2) the string `"all"` to wake every local recipient on To and CC (pre-0.9.0 behaviour); (3) an empty array `[]` to deliver silently with no wakes; (4) omit entirely to use the default \u2014 wake local recipients on `To:` only. CC\'d recipients NOT in the wake list still receive the mail in their inbox and will see it when they next wake naturally.'
|
|
22636
22641
|
},
|
|
22637
22642
|
inReplyTo: { type: "string", description: "Message-ID to reply to (optional)" },
|
|
22638
22643
|
references: {
|
|
@@ -23263,6 +23268,34 @@ var toolDefinitions = [
|
|
|
23263
23268
|
required: ["action"]
|
|
23264
23269
|
}
|
|
23265
23270
|
},
|
|
23271
|
+
{
|
|
23272
|
+
name: "save_thread_memory",
|
|
23273
|
+
description: "Persist a one-paragraph memory of where THIS agent stands on the given thread. Called at the end of every wake \u2014 Claude Code reads it back into the next wake's prompt so the agent doesn't re-derive context from scratch by re-reading 10 prior messages. Pass `threadId` from `get_thread_id`. Fields are a snapshot: summary (where the thread stands), commitments (what you committed to), openQuestions (what you are blocked on), lastAction (what you just did), lastUid (newest UID you have digested). The file overwrites; you do not need to merge with the previous version \u2014 the dispatcher reads only the most recent write.",
|
|
23274
|
+
inputSchema: {
|
|
23275
|
+
type: "object",
|
|
23276
|
+
properties: {
|
|
23277
|
+
threadId: { type: "string", description: "Stable thread id from get_thread_id. Required." },
|
|
23278
|
+
summary: { type: "string", description: "One-paragraph narrative of where the thread stands." },
|
|
23279
|
+
commitments: { type: "array", items: { type: "string" }, description: "Things you have committed to doing on this thread." },
|
|
23280
|
+
openQuestions: { type: "array", items: { type: "string" }, description: "Things you are waiting on / open questions." },
|
|
23281
|
+
lastAction: { type: "string", description: 'The last action you took on the thread (e.g. "replied UID 41 asking for raw counts").' },
|
|
23282
|
+
lastUid: { type: "number", description: "Newest message UID you have digested into this memory." }
|
|
23283
|
+
},
|
|
23284
|
+
required: ["threadId"]
|
|
23285
|
+
}
|
|
23286
|
+
},
|
|
23287
|
+
{
|
|
23288
|
+
name: "get_thread_id",
|
|
23289
|
+
description: "Resolve the stable thread id for a message UID. Use this BEFORE calling save_thread_memory or when you want to inspect the cache for a thread. Pass the UID of any message on the thread (root or reply) \u2014 the API normalises the subject, resolves the canonical root sender, and returns the same id every time. `folder` defaults to INBOX.",
|
|
23290
|
+
inputSchema: {
|
|
23291
|
+
type: "object",
|
|
23292
|
+
properties: {
|
|
23293
|
+
uid: { type: "number", description: "Message UID." },
|
|
23294
|
+
folder: { type: "string", description: "IMAP folder where the UID lives. Defaults to INBOX." }
|
|
23295
|
+
},
|
|
23296
|
+
required: ["uid"]
|
|
23297
|
+
}
|
|
23298
|
+
},
|
|
23266
23299
|
{
|
|
23267
23300
|
name: "tail_worker",
|
|
23268
23301
|
description: "Tail the log of a running (or recently-finished) dispatcher worker. Use this when check_activity shows a worker has been running a long time or is marked stale, and you want to see what it is actually doing \u2014 every tool call, tool result, and assistant chunk is logged as a one-liner. Returns the last N lines (default 80). The workerId comes from check_activity output. Requires master key.",
|
|
@@ -24592,6 +24625,24 @@ ${r.agents.map(
|
|
|
24592
24625
|
}
|
|
24593
24626
|
throw new Error("Invalid action. Use: list_inactive, cleanup, or set_persistent");
|
|
24594
24627
|
}
|
|
24628
|
+
case "save_thread_memory": {
|
|
24629
|
+
if (!args2.threadId) throw new Error("threadId is required (call get_thread_id first)");
|
|
24630
|
+
const body = {};
|
|
24631
|
+
if (typeof args2.summary === "string") body.summary = args2.summary;
|
|
24632
|
+
if (Array.isArray(args2.commitments)) body.commitments = args2.commitments;
|
|
24633
|
+
if (Array.isArray(args2.openQuestions)) body.openQuestions = args2.openQuestions;
|
|
24634
|
+
if (typeof args2.lastAction === "string") body.lastAction = args2.lastAction;
|
|
24635
|
+
if (typeof args2.lastUid === "number") body.lastUid = args2.lastUid;
|
|
24636
|
+
await apiRequest("POST", `/agents/me/memory/threads/${encodeURIComponent(String(args2.threadId))}`, body);
|
|
24637
|
+
return `Memory saved for thread ${args2.threadId}.`;
|
|
24638
|
+
}
|
|
24639
|
+
case "get_thread_id": {
|
|
24640
|
+
if (typeof args2.uid !== "number" || args2.uid < 1) throw new Error("uid (number, \u22651) is required");
|
|
24641
|
+
const folder = typeof args2.folder === "string" ? args2.folder : "INBOX";
|
|
24642
|
+
const r = await apiRequest("GET", `/agents/me/thread-id?uid=${args2.uid}&folder=${encodeURIComponent(folder)}`);
|
|
24643
|
+
if (!r?.threadId) throw new Error("Failed to resolve thread id");
|
|
24644
|
+
return `Thread ${r.threadId} (subject "${r.subject}", root from ${r.rootFromAddr}).`;
|
|
24645
|
+
}
|
|
24595
24646
|
case "tail_worker": {
|
|
24596
24647
|
if (!args2.workerId) throw new Error("workerId is required");
|
|
24597
24648
|
const lines = typeof args2.lines === "number" ? args2.lines : 80;
|
|
@@ -24623,13 +24674,15 @@ ${r.tail.join("\n")}`;
|
|
|
24623
24674
|
const from = w.trigger?.from ? ` (from ${w.trigger.from})` : "";
|
|
24624
24675
|
const preview = w.resultPreview ? `
|
|
24625
24676
|
\u2192 ${String(w.resultPreview).slice(0, 140).replace(/\s+/g, " ").trim()}` : "";
|
|
24677
|
+
const usage = w.usage ? `
|
|
24678
|
+
\u26A1 ${String(w.usage)}` : "";
|
|
24626
24679
|
let status = w.endedAtMs ? w.ok === false ? "failed" : "finished" : "running";
|
|
24627
24680
|
if (!w.endedAtMs && w.stale) status = "running (stale heartbeat)";
|
|
24628
24681
|
const turns = !w.endedAtMs && typeof w.turnCount === "number" ? ` \xB7 ${w.turnCount} tool calls` : "";
|
|
24629
24682
|
const tool = !w.endedAtMs && w.lastTool ? ` \xB7 last tool: ${w.lastTool}` : "";
|
|
24630
24683
|
const idHint = !w.endedAtMs ? `
|
|
24631
24684
|
id: ${w.workerId} (use tail_worker for the log)` : "";
|
|
24632
|
-
return ` ${prefix} ${w.agentName} [${w.kind}] ${status} ${dur}${turns}${tool}${trig}${from}${preview}${idHint}`;
|
|
24685
|
+
return ` ${prefix} ${w.agentName} [${w.kind}] ${status} ${dur}${turns}${tool}${trig}${from}${preview}${usage}${idHint}`;
|
|
24633
24686
|
};
|
|
24634
24687
|
const lines = [];
|
|
24635
24688
|
if (activeList.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"mcpName": "io.github.agenticmail/mcp",
|
|
5
5
|
"description": "MCP server for AgenticMail — give any AI client real email and SMS capabilities",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
32
32
|
"zod": "^3.24.0",
|
|
33
|
-
"@agenticmail/core": "^0.
|
|
33
|
+
"@agenticmail/core": "^0.9.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"tsup": "^8.4.0",
|