@agenticmail/mcp 0.7.8 → 0.9.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/README.md +27 -1
- package/dist/index.js +64 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,33 @@ 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
|
|
17
|
+
|
|
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:
|
|
19
|
+
```js
|
|
20
|
+
await call_agent({
|
|
21
|
+
target: 'vesper',
|
|
22
|
+
task: 'Audit row 34 of the YAML patch.',
|
|
23
|
+
outputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
required: ['summary', 'findings', 'recommendation'],
|
|
26
|
+
properties: {
|
|
27
|
+
summary: { type: 'string' },
|
|
28
|
+
findings: { type: 'array', items: { type: 'string' } },
|
|
29
|
+
recommendation: { type: 'string', enum: ['proceed', 'block'] },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
- **📥 `tail_worker(workerId, lines?)`** — paired with `check_activity`. When a worker shows up as long-running or stale, `tail_worker` returns the trailing N lines of its log (every tool call, result, and assistant chunk as a one-liner). Master-key only. Lives in the `multi_agent_extras` tier so it ships in the default toolbelt for hosts that delegate work.
|
|
35
|
+
- **📊 `check_activity` shows live progress** — output now includes last tool used, tool-call count, duration in `Xh Ym Zs`, and a `stale` flag derived from heartbeat age. Workers are no longer auto-evicted from the registry; staleness is diagnostic.
|
|
36
|
+
|
|
37
|
+
## ✨ Earlier — 0.7.7
|
|
12
38
|
|
|
13
39
|
- **`wake` parameter on every send tool** — `send_email`, `reply_email`, `forward_email`, `template_send`, `manage_drafts(send)` all accept `wake: ["alice", "bob"]` (or comma-separated string). The dispatcher gives a Claude turn only to listed agents; the rest still receive the mail but stay asleep. Single biggest token saver on multi-agent threads.
|
|
14
40
|
- **`check_activity` tool** (in the `essential` set) — see which agents the dispatcher has woken right now, what they're working on, how long they've been running, plus a preview of recently-finished work. Answers "did the agent I just emailed actually start working?" without waiting for a reply.
|
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.",
|
|
@@ -23322,14 +23355,15 @@ var toolDefinitions = [
|
|
|
23322
23355
|
},
|
|
23323
23356
|
{
|
|
23324
23357
|
name: "call_agent",
|
|
23325
|
-
description: `Synchronous RPC to delegate work to another AgenticMail agent. Pipeline: the task is queued in AgenticMail, the target agent processes it AS THEMSELVES (under their real identity, mailbox, persona, and audit trail), and the structured result returns into your call. THIS IS HOW MULTI-AGENT COORDINATION IS SUPPOSED TO WORK from any MCP host. Do not, instead, spawn one of your host's native sub-agents and tell it to "act as <target>" \u2014 that produces output under your identity, never touches the target's inbox, and skips their persona. Times out after the specified duration (default 180s, max 300s).`,
|
|
23358
|
+
description: `Synchronous RPC to delegate work to another AgenticMail agent. Pipeline: the task is queued in AgenticMail, the target agent processes it AS THEMSELVES (under their real identity, mailbox, persona, and audit trail), and the structured result returns into your call. THIS IS HOW MULTI-AGENT COORDINATION IS SUPPOSED TO WORK from any MCP host. Do not, instead, spawn one of your host's native sub-agents and tell it to "act as <target>" \u2014 that produces output under your identity, never touches the target's inbox, and skips their persona. Pass outputSchema to require a structured deliverable shape: the API validates the worker's submit_result against the schema and rejects mismatches with validator errors, so the worker can retry with a correct shape rather than returning free-form prose. Times out after the specified duration (default 180s, max 300s).`,
|
|
23326
23359
|
inputSchema: {
|
|
23327
23360
|
type: "object",
|
|
23328
23361
|
properties: {
|
|
23329
23362
|
target: { type: "string", description: "Name of the agent to call" },
|
|
23330
23363
|
task: { type: "string", description: "Task description" },
|
|
23331
23364
|
payload: { type: "object", description: "Additional data" },
|
|
23332
|
-
timeout: { type: "number", description: "Max seconds to wait (default: 180, max: 300)" }
|
|
23365
|
+
timeout: { type: "number", description: "Max seconds to wait (default: 180, max: 300)" },
|
|
23366
|
+
outputSchema: { type: "object", description: "Optional JSON Schema (draft-7 subset: type, required, properties, items, enum, additionalProperties, minLength/maxLength, minimum/maximum) describing the shape submit_result must conform to. The worker sees the schema in the wake prompt and the API validates on submission." }
|
|
23333
23367
|
},
|
|
23334
23368
|
required: ["target", "task"]
|
|
23335
23369
|
}
|
|
@@ -24591,6 +24625,24 @@ ${r.agents.map(
|
|
|
24591
24625
|
}
|
|
24592
24626
|
throw new Error("Invalid action. Use: list_inactive, cleanup, or set_persistent");
|
|
24593
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
|
+
}
|
|
24594
24646
|
case "tail_worker": {
|
|
24595
24647
|
if (!args2.workerId) throw new Error("workerId is required");
|
|
24596
24648
|
const lines = typeof args2.lines === "number" ? args2.lines : 80;
|
|
@@ -24667,7 +24719,11 @@ ${r.tasks.map(
|
|
|
24667
24719
|
const created = await apiRequest("POST", "/tasks/assign", {
|
|
24668
24720
|
assignee: args2.target,
|
|
24669
24721
|
taskType: "rpc",
|
|
24670
|
-
payload: { task: args2.task, ...args2.payload || {} }
|
|
24722
|
+
payload: { task: args2.task, ...args2.payload || {} },
|
|
24723
|
+
// Pass outputSchema through verbatim. The API persists it
|
|
24724
|
+
// and renders it into the worker's wake prompt; validation
|
|
24725
|
+
// happens server-side on submit_result.
|
|
24726
|
+
...args2.outputSchema ? { outputSchema: args2.outputSchema } : {}
|
|
24671
24727
|
});
|
|
24672
24728
|
if (!created?.id) throw new Error("Failed to create task");
|
|
24673
24729
|
const taskId = created.id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
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.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"tsup": "^8.4.0",
|