hypermail-mcp 0.4.3 → 0.5.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 +8 -3
- package/dist/cli.js +20 -17
- package/dist/cli.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
A **Model Context Protocol** server that lets an agent operate any of the user's
|
|
4
4
|
inboxes through a single, unified tool surface.
|
|
5
5
|
|
|
6
|
+
> **v0.5.0** — Replaced optional `isHtml` boolean with required `format`
|
|
7
|
+
> parameter (`"html"` | `"markdown"`) on `send_email`, `draft_email`, and
|
|
8
|
+
> `edit_draft`. Markdown bodies are converted to HTML via `marked` so
|
|
9
|
+
> recipients always see clean HTML.
|
|
10
|
+
>
|
|
6
11
|
> **v0.4.3** — Upgraded Zod to v4.4.3. Fixed MCP SDK v1.29.0 compatibility
|
|
7
12
|
> by wrapping all tool schemas in `z.object()` and replacing discriminated
|
|
8
13
|
> union output schemas that caused `validateToolOutput` crashes.
|
|
@@ -121,9 +126,9 @@ account store.
|
|
|
121
126
|
| `archive_email` | `account`, `id` | Move a message to the Archive folder. Disabled under `--read-only`. |
|
|
122
127
|
| `trash_email` | `account`, `id` | Move a message to Deleted Items (trash). Disabled under `--read-only`. |
|
|
123
128
|
| `move_email` | `account`, `id`, `destination` | Move to any folder by well-known name (`inbox`, `drafts`, etc.) or custom folder ID. Disabled under `--read-only`. |
|
|
124
|
-
| `send_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `
|
|
125
|
-
| `draft_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `
|
|
126
|
-
| `edit_draft` | `account`, `id`, `to?`, `cc?`, `bcc?`, `subject?`, `body?`, `
|
|
129
|
+
| `send_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `format`, `include_signature?`, `inReplyTo?`, `replyAll?`, `forwardMessageId?` | Send an email. `format` (`"html"` or `"markdown"`) controls body format — Markdown is converted to HTML via `marked`. Appends signature when `include_signature` is true. `inReplyTo` sends as threaded reply; `forwardMessageId` sends as forward. Disabled under `--read-only`. |
|
|
130
|
+
| `draft_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `format`, `include_signature?`, `inReplyTo?`, `replyAll?`, `forwardMessageId?` | Save as draft instead of sending. `format` (`"html"` or `"markdown"`) controls body format — Markdown is converted to HTML via `marked`. Returns the draft message ID and HTML body (`draftHtml`). Disabled under `--read-only`. |
|
|
131
|
+
| `edit_draft` | `account`, `id`, `to?`, `cc?`, `bcc?`, `subject?`, `body?`, `format?`, `include_signature?` | Edit an existing draft by ID. Only provided fields are updated. `format` only meaningful when `body` is provided. Returns the updated draft ID and HTML body (`draftHtml`). Disabled under `--read-only`. |
|
|
127
132
|
| `send_draft` | `account`, `id` | Send an existing draft email by ID. Use with draft IDs returned by `draft_email` or `edit_draft`. Disabled under `--read-only`. |
|
|
128
133
|
| `add_attachment_to_draft` | `account`, `id`, `path` | Attach a local file to an existing draft email. Disabled under `--read-only`. |
|
|
129
134
|
| `list_folders` | `account`, `parentFolderId?` | List available mail folders. Returns top-level folders by default, or children of `parentFolderId`. |
|
package/dist/cli.js
CHANGED
|
@@ -2459,6 +2459,14 @@ function buildRegistry(opts) {
|
|
|
2459
2459
|
|
|
2460
2460
|
// src/tools/shared.ts
|
|
2461
2461
|
import { z } from "zod";
|
|
2462
|
+
|
|
2463
|
+
// src/markdown-to-html.ts
|
|
2464
|
+
import { marked } from "marked";
|
|
2465
|
+
function markdownToHtml(md) {
|
|
2466
|
+
return marked.parse(md, { async: false });
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
// src/tools/shared.ts
|
|
2462
2470
|
function ok(data, structuredContent) {
|
|
2463
2471
|
const result = {
|
|
2464
2472
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
@@ -2535,21 +2543,15 @@ var folderInfoOutputSchema = z.object({
|
|
|
2535
2543
|
unreadItemCount: z.number()
|
|
2536
2544
|
});
|
|
2537
2545
|
function composeBody(input) {
|
|
2538
|
-
const { body,
|
|
2546
|
+
const { body, format, signature, style, includeSignature } = input;
|
|
2547
|
+
const htmlBody = format === "markdown" ? markdownToHtml(body) : body;
|
|
2539
2548
|
const hasSignature = includeSignature && !!signature;
|
|
2540
2549
|
const hasStyle = !!(style && (style.fontFamily || style.fontSize || style.fontColor));
|
|
2541
2550
|
if (!hasSignature && !hasStyle) {
|
|
2542
|
-
return { body, isHtml };
|
|
2551
|
+
return { body: htmlBody, isHtml: true };
|
|
2543
2552
|
}
|
|
2544
2553
|
const styleAttr = hasStyle ? buildStyleAttr(style) : "";
|
|
2545
|
-
|
|
2546
|
-
let result2 = hasStyle ? `<div style="${styleAttr}">${body}</div>` : body;
|
|
2547
|
-
if (hasSignature) result2 += `
|
|
2548
|
-
<div class="signature">${signature}</div>`;
|
|
2549
|
-
return { body: result2, isHtml: true };
|
|
2550
|
-
}
|
|
2551
|
-
const escaped = escapeHtml(body);
|
|
2552
|
-
let result = `<div style="${styleAttr}">${escaped}</div>`;
|
|
2554
|
+
let result = hasStyle ? `<div style="${styleAttr}">${htmlBody}</div>` : htmlBody;
|
|
2553
2555
|
if (hasSignature) result += `
|
|
2554
2556
|
<div class="signature">${signature}</div>`;
|
|
2555
2557
|
return { body: result, isHtml: true };
|
|
@@ -2561,9 +2563,6 @@ function buildStyleAttr(style) {
|
|
|
2561
2563
|
if (style.fontColor) parts.push(`color: ${style.fontColor}`);
|
|
2562
2564
|
return parts.join("; ");
|
|
2563
2565
|
}
|
|
2564
|
-
function escapeHtml(text) {
|
|
2565
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/\n/g, "<br>");
|
|
2566
|
-
}
|
|
2567
2566
|
function shouldRegister(name, tools) {
|
|
2568
2567
|
if (tools.enabledTools) {
|
|
2569
2568
|
return tools.enabledTools.has(name);
|
|
@@ -3258,7 +3257,9 @@ function registerComposeTools(server, ctx) {
|
|
|
3258
3257
|
bcc: z6.array(emailAddrSchema).optional(),
|
|
3259
3258
|
subject: z6.string(),
|
|
3260
3259
|
body: z6.string(),
|
|
3261
|
-
|
|
3260
|
+
format: z6.enum(["html", "markdown"]).describe(
|
|
3261
|
+
"Body format. 'html' sends the body as-is (must be valid HTML). 'markdown' converts the body from Markdown to HTML for clean rendering on the recipient side."
|
|
3262
|
+
),
|
|
3262
3263
|
include_signature: z6.boolean().describe(
|
|
3263
3264
|
"Whether to append the account's saved HTML signature to the email. If true, don't include a signature in the body param to avoid double signature. Returns an error if true but no signature is configured for this account."
|
|
3264
3265
|
),
|
|
@@ -3282,7 +3283,7 @@ function registerComposeTools(server, ctx) {
|
|
|
3282
3283
|
}
|
|
3283
3284
|
const composed = composeBody({
|
|
3284
3285
|
body: args.body,
|
|
3285
|
-
|
|
3286
|
+
format: args.format,
|
|
3286
3287
|
signature: account.signature,
|
|
3287
3288
|
style: account.style,
|
|
3288
3289
|
includeSignature: args.include_signature
|
|
@@ -3362,7 +3363,9 @@ function registerComposeTools(server, ctx) {
|
|
|
3362
3363
|
bcc: z6.array(emailAddrSchema).optional(),
|
|
3363
3364
|
subject: z6.string().optional(),
|
|
3364
3365
|
body: z6.string().optional(),
|
|
3365
|
-
|
|
3366
|
+
format: z6.enum(["html", "markdown"]).optional().describe(
|
|
3367
|
+
"Body format. Only meaningful when `body` is also provided. 'html' sends the body as-is (must be valid HTML). 'markdown' converts the body from Markdown to HTML for clean rendering on the recipient side."
|
|
3368
|
+
),
|
|
3366
3369
|
include_signature: z6.boolean().optional().describe(
|
|
3367
3370
|
"Whether to re-apply the account's saved HTML signature to the body. If true, don't include a signature in the body param. Only meaningful when `body` is also provided. Returns an error if true but no signature is configured for this account."
|
|
3368
3371
|
)
|
|
@@ -3394,7 +3397,7 @@ function registerComposeTools(server, ctx) {
|
|
|
3394
3397
|
if (a.body !== void 0) {
|
|
3395
3398
|
const composed = composeBody({
|
|
3396
3399
|
body: a.body,
|
|
3397
|
-
|
|
3400
|
+
format: a.format ?? "html",
|
|
3398
3401
|
signature: account.signature,
|
|
3399
3402
|
style: account.style,
|
|
3400
3403
|
includeSignature: !!a.include_signature
|