hypermail-mcp 0.4.2 → 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 +12 -3
- package/dist/cli.js +94 -96
- package/dist/cli.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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
|
+
>
|
|
11
|
+
> **v0.4.3** — Upgraded Zod to v4.4.3. Fixed MCP SDK v1.29.0 compatibility
|
|
12
|
+
> by wrapping all tool schemas in `z.object()` and replacing discriminated
|
|
13
|
+
> union output schemas that caused `validateToolOutput` crashes.
|
|
14
|
+
|
|
6
15
|
The agent doesn't care whether an address is a work Outlook account, a personal
|
|
7
16
|
Microsoft account, or (soon) a personal IMAP mailbox — it just calls
|
|
8
17
|
`list_emails`, `search_emails`, `read_email`, `send_email` and passes the email
|
|
@@ -117,9 +126,9 @@ account store.
|
|
|
117
126
|
| `archive_email` | `account`, `id` | Move a message to the Archive folder. Disabled under `--read-only`. |
|
|
118
127
|
| `trash_email` | `account`, `id` | Move a message to Deleted Items (trash). Disabled under `--read-only`. |
|
|
119
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`. |
|
|
120
|
-
| `send_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `
|
|
121
|
-
| `draft_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `
|
|
122
|
-
| `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`. |
|
|
123
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`. |
|
|
124
133
|
| `add_attachment_to_draft` | `account`, `id`, `path` | Attach a local file to an existing draft email. Disabled under `--read-only`. |
|
|
125
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) }]
|
|
@@ -2504,7 +2512,7 @@ var accountFullOutputSchema = z.object({
|
|
|
2504
2512
|
email: z.string(),
|
|
2505
2513
|
provider: providerIdEnum,
|
|
2506
2514
|
displayName: z.string().optional(),
|
|
2507
|
-
tokens: z.record(z.unknown()),
|
|
2515
|
+
tokens: z.record(z.string(), z.unknown()),
|
|
2508
2516
|
addedAt: z.string(),
|
|
2509
2517
|
signature: z.string().optional(),
|
|
2510
2518
|
style: styleOutputSchema.optional()
|
|
@@ -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);
|
|
@@ -2578,15 +2577,15 @@ function shouldRegister(name, tools) {
|
|
|
2578
2577
|
import { z as z2 } from "zod";
|
|
2579
2578
|
function registerAccountTools(server, ctx) {
|
|
2580
2579
|
const { store, registry, tools } = ctx;
|
|
2581
|
-
const listAccountsOutputSchema = {
|
|
2580
|
+
const listAccountsOutputSchema = z2.object({
|
|
2582
2581
|
accounts: z2.array(accountSummaryOutputSchema)
|
|
2583
|
-
};
|
|
2582
|
+
});
|
|
2584
2583
|
if (shouldRegister("list_accounts", tools)) {
|
|
2585
2584
|
server.registerTool(
|
|
2586
2585
|
"list_accounts",
|
|
2587
2586
|
{
|
|
2588
2587
|
description: "List all email accounts known to this server (no secrets). Use the returned `email` value as the `account` argument to other tools.",
|
|
2589
|
-
inputSchema: {},
|
|
2588
|
+
inputSchema: z2.object({}),
|
|
2590
2589
|
outputSchema: listAccountsOutputSchema
|
|
2591
2590
|
},
|
|
2592
2591
|
async () => {
|
|
@@ -2603,36 +2602,31 @@ function registerAccountTools(server, ctx) {
|
|
|
2603
2602
|
}
|
|
2604
2603
|
);
|
|
2605
2604
|
}
|
|
2606
|
-
const addAccountOutputSchema = z2.
|
|
2607
|
-
z2.
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
z2.object({
|
|
2618
|
-
status: z2.literal("ready"),
|
|
2619
|
-
account: accountFullOutputSchema
|
|
2620
|
-
})
|
|
2621
|
-
]);
|
|
2605
|
+
const addAccountOutputSchema = z2.object({
|
|
2606
|
+
status: z2.enum(["pending", "ready"]),
|
|
2607
|
+
handle: z2.string().optional(),
|
|
2608
|
+
verification: z2.object({
|
|
2609
|
+
userCode: z2.string(),
|
|
2610
|
+
verificationUri: z2.string(),
|
|
2611
|
+
expiresAt: z2.string(),
|
|
2612
|
+
message: z2.string()
|
|
2613
|
+
}).optional(),
|
|
2614
|
+
account: accountFullOutputSchema.optional()
|
|
2615
|
+
});
|
|
2622
2616
|
if (shouldRegister("add_account", tools)) {
|
|
2623
2617
|
server.registerTool(
|
|
2624
2618
|
"add_account",
|
|
2625
2619
|
{
|
|
2626
2620
|
description: "Start adding an email account. For Outlook this returns a device code the user must enter at the verification URL; then call `complete_add_account` with the returned `handle` to finalize. Disabled in --read-only mode.",
|
|
2627
|
-
inputSchema: {
|
|
2621
|
+
inputSchema: z2.object({
|
|
2628
2622
|
provider: providerIdEnum.describe("Email backend. 'outlook' (Microsoft Graph) and 'imap' are fully implemented."),
|
|
2629
2623
|
email: z2.string().email().optional().describe(
|
|
2630
2624
|
"Optional hint \u2014 the provider will verify it against the auth result."
|
|
2631
2625
|
),
|
|
2632
|
-
config: z2.record(z2.unknown()).optional().describe(
|
|
2626
|
+
config: z2.record(z2.string(), z2.unknown()).optional().describe(
|
|
2633
2627
|
"Provider-specific config (e.g. IMAP host/port). Unused for Outlook."
|
|
2634
2628
|
)
|
|
2635
|
-
},
|
|
2629
|
+
}),
|
|
2636
2630
|
outputSchema: addAccountOutputSchema
|
|
2637
2631
|
},
|
|
2638
2632
|
async (args) => {
|
|
@@ -2659,10 +2653,10 @@ function registerAccountTools(server, ctx) {
|
|
|
2659
2653
|
"complete_add_account",
|
|
2660
2654
|
{
|
|
2661
2655
|
description: "Poll/finalize a pending add_account flow. Returns `pending` until the user completes the device-code step, then `ready` with the persisted account.",
|
|
2662
|
-
inputSchema: {
|
|
2656
|
+
inputSchema: z2.object({
|
|
2663
2657
|
provider: providerIdEnum,
|
|
2664
2658
|
handle: z2.string().min(1)
|
|
2665
|
-
},
|
|
2659
|
+
}),
|
|
2666
2660
|
outputSchema: completeAddAccountOutputSchema
|
|
2667
2661
|
},
|
|
2668
2662
|
async (args) => {
|
|
@@ -2681,16 +2675,16 @@ function registerAccountTools(server, ctx) {
|
|
|
2681
2675
|
}
|
|
2682
2676
|
);
|
|
2683
2677
|
}
|
|
2684
|
-
const accountSettingsOutputSchema = {
|
|
2678
|
+
const accountSettingsOutputSchema = z2.object({
|
|
2685
2679
|
signature: z2.string().nullable(),
|
|
2686
2680
|
style: styleOutputSchema.nullable()
|
|
2687
|
-
};
|
|
2681
|
+
});
|
|
2688
2682
|
if (shouldRegister("get_account_settings", tools)) {
|
|
2689
2683
|
server.registerTool(
|
|
2690
2684
|
"get_account_settings",
|
|
2691
2685
|
{
|
|
2692
2686
|
description: "Get signature (HTML) and style preferences for an account.",
|
|
2693
|
-
inputSchema: { account: z2.string().email() },
|
|
2687
|
+
inputSchema: z2.object({ account: z2.string().email() }),
|
|
2694
2688
|
outputSchema: accountSettingsOutputSchema
|
|
2695
2689
|
},
|
|
2696
2690
|
async (args) => {
|
|
@@ -2714,7 +2708,7 @@ function registerAccountTools(server, ctx) {
|
|
|
2714
2708
|
"set_account_settings",
|
|
2715
2709
|
{
|
|
2716
2710
|
description: "Set signature (HTML snippet) and/or style preferences for an account. Disabled in --read-only mode.",
|
|
2717
|
-
inputSchema: {
|
|
2711
|
+
inputSchema: z2.object({
|
|
2718
2712
|
account: z2.string().email(),
|
|
2719
2713
|
signature: z2.string().optional().describe(
|
|
2720
2714
|
"HTML snippet \u2014 may contain formatting, images, links. Pass null to clear."
|
|
@@ -2726,7 +2720,7 @@ function registerAccountTools(server, ctx) {
|
|
|
2726
2720
|
}).optional().describe(
|
|
2727
2721
|
"Font preferences applied to outgoing HTML emails. Pass null to clear."
|
|
2728
2722
|
)
|
|
2729
|
-
},
|
|
2723
|
+
}),
|
|
2730
2724
|
outputSchema: accountSettingsOutputSchema
|
|
2731
2725
|
},
|
|
2732
2726
|
async (args) => {
|
|
@@ -2750,16 +2744,16 @@ function registerAccountTools(server, ctx) {
|
|
|
2750
2744
|
}
|
|
2751
2745
|
);
|
|
2752
2746
|
}
|
|
2753
|
-
const removeAccountOutputSchema = {
|
|
2747
|
+
const removeAccountOutputSchema = z2.object({
|
|
2754
2748
|
removed: z2.boolean(),
|
|
2755
2749
|
email: z2.string()
|
|
2756
|
-
};
|
|
2750
|
+
});
|
|
2757
2751
|
if (shouldRegister("remove_account", tools)) {
|
|
2758
2752
|
server.registerTool(
|
|
2759
2753
|
"remove_account",
|
|
2760
2754
|
{
|
|
2761
2755
|
description: "Forget an account and delete its stored tokens. Disabled in --read-only mode.",
|
|
2762
|
-
inputSchema: { email: z2.string().email() },
|
|
2756
|
+
inputSchema: z2.object({ email: z2.string().email() }),
|
|
2763
2757
|
outputSchema: removeAccountOutputSchema
|
|
2764
2758
|
},
|
|
2765
2759
|
async (args) => {
|
|
@@ -2803,30 +2797,30 @@ function selectBody(msg, format) {
|
|
|
2803
2797
|
// src/tools/browse.ts
|
|
2804
2798
|
function registerBrowseTools(server, ctx) {
|
|
2805
2799
|
const { registry, tools } = ctx;
|
|
2806
|
-
const emailListOutputSchema = {
|
|
2800
|
+
const emailListOutputSchema = z3.object({
|
|
2807
2801
|
account: z3.string(),
|
|
2808
2802
|
count: z3.number(),
|
|
2809
2803
|
items: z3.array(emailSummaryOutputSchema),
|
|
2810
2804
|
skip: z3.number(),
|
|
2811
2805
|
hasMore: z3.boolean()
|
|
2812
|
-
};
|
|
2813
|
-
const searchEmailsOutputSchema = {
|
|
2806
|
+
});
|
|
2807
|
+
const searchEmailsOutputSchema = z3.object({
|
|
2814
2808
|
account: z3.string(),
|
|
2815
2809
|
count: z3.number(),
|
|
2816
2810
|
items: z3.array(emailSummaryOutputSchema)
|
|
2817
|
-
};
|
|
2811
|
+
});
|
|
2818
2812
|
if (shouldRegister("list_emails", tools)) {
|
|
2819
2813
|
server.registerTool(
|
|
2820
2814
|
"list_emails",
|
|
2821
2815
|
{
|
|
2822
2816
|
description: "List recent emails in a folder of the given account. Pass the user's email address as `account`; the server routes to the correct backend automatically.",
|
|
2823
|
-
inputSchema: {
|
|
2817
|
+
inputSchema: z3.object({
|
|
2824
2818
|
account: z3.string().email(),
|
|
2825
2819
|
folder: z3.string().default("inbox").optional(),
|
|
2826
2820
|
limit: z3.number().int().positive().max(100).optional(),
|
|
2827
2821
|
unreadOnly: z3.boolean().optional(),
|
|
2828
2822
|
skip: z3.number().int().min(0).optional()
|
|
2829
|
-
},
|
|
2823
|
+
}),
|
|
2830
2824
|
outputSchema: emailListOutputSchema
|
|
2831
2825
|
},
|
|
2832
2826
|
async (args) => {
|
|
@@ -2857,11 +2851,11 @@ function registerBrowseTools(server, ctx) {
|
|
|
2857
2851
|
"search_emails",
|
|
2858
2852
|
{
|
|
2859
2853
|
description: "Search emails by free-text query (KQL on Outlook). Returns lightweight summaries.",
|
|
2860
|
-
inputSchema: {
|
|
2854
|
+
inputSchema: z3.object({
|
|
2861
2855
|
account: z3.string().email(),
|
|
2862
2856
|
query: z3.string().min(1),
|
|
2863
2857
|
limit: z3.number().int().positive().max(100).optional()
|
|
2864
|
-
},
|
|
2858
|
+
}),
|
|
2865
2859
|
outputSchema: searchEmailsOutputSchema
|
|
2866
2860
|
},
|
|
2867
2861
|
async (args) => {
|
|
@@ -2882,7 +2876,7 @@ function registerBrowseTools(server, ctx) {
|
|
|
2882
2876
|
}
|
|
2883
2877
|
);
|
|
2884
2878
|
}
|
|
2885
|
-
const readEmailOutputSchema = {
|
|
2879
|
+
const readEmailOutputSchema = z3.object({
|
|
2886
2880
|
id: z3.string(),
|
|
2887
2881
|
subject: z3.string(),
|
|
2888
2882
|
from: emailAddrOutputSchema.optional(),
|
|
@@ -2897,19 +2891,19 @@ function registerBrowseTools(server, ctx) {
|
|
|
2897
2891
|
attachments: z3.array(attachmentMetaOutputSchema).optional(),
|
|
2898
2892
|
body: z3.string(),
|
|
2899
2893
|
bodyFormat: z3.enum(["markdown", "html", "text"])
|
|
2900
|
-
};
|
|
2894
|
+
});
|
|
2901
2895
|
if (shouldRegister("read_email", tools)) {
|
|
2902
2896
|
server.registerTool(
|
|
2903
2897
|
"read_email",
|
|
2904
2898
|
{
|
|
2905
2899
|
description: "Fetch a single email with full body and recipients by id. Body is returned as `body` with `bodyFormat` indicating the format. Default format is 'markdown' \u2014 HTML is automatically converted to save context tokens.",
|
|
2906
|
-
inputSchema: {
|
|
2900
|
+
inputSchema: z3.object({
|
|
2907
2901
|
account: z3.string().email(),
|
|
2908
2902
|
id: z3.string().min(1),
|
|
2909
2903
|
format: z3.enum(["markdown", "html", "text"]).default("markdown").optional().describe(
|
|
2910
2904
|
"Output body format. 'markdown' converts HTML to Markdown (default), 'html' returns the raw HTML, 'text' returns plain text."
|
|
2911
2905
|
)
|
|
2912
|
-
},
|
|
2906
|
+
}),
|
|
2913
2907
|
outputSchema: readEmailOutputSchema
|
|
2914
2908
|
},
|
|
2915
2909
|
async (args) => {
|
|
@@ -2941,21 +2935,21 @@ function registerBrowseTools(server, ctx) {
|
|
|
2941
2935
|
}
|
|
2942
2936
|
);
|
|
2943
2937
|
}
|
|
2944
|
-
const readAttachmentOutputSchema = {
|
|
2938
|
+
const readAttachmentOutputSchema = z3.object({
|
|
2945
2939
|
name: z3.string(),
|
|
2946
2940
|
contentType: z3.string().optional(),
|
|
2947
2941
|
path: z3.string()
|
|
2948
|
-
};
|
|
2942
|
+
});
|
|
2949
2943
|
if (shouldRegister("read_attachment", tools)) {
|
|
2950
2944
|
server.registerTool(
|
|
2951
2945
|
"read_attachment",
|
|
2952
2946
|
{
|
|
2953
2947
|
description: "Download an email attachment to a temporary file and return its path. Use messageId and attachmentId from a prior read_email call.",
|
|
2954
|
-
inputSchema: {
|
|
2948
|
+
inputSchema: z3.object({
|
|
2955
2949
|
account: z3.string().email(),
|
|
2956
2950
|
messageId: z3.string().min(1),
|
|
2957
2951
|
attachmentId: z3.string().min(1)
|
|
2958
|
-
},
|
|
2952
|
+
}),
|
|
2959
2953
|
outputSchema: readAttachmentOutputSchema
|
|
2960
2954
|
},
|
|
2961
2955
|
async (args) => {
|
|
@@ -2979,22 +2973,22 @@ function registerBrowseTools(server, ctx) {
|
|
|
2979
2973
|
import { z as z4 } from "zod";
|
|
2980
2974
|
function registerFolderTools(server, ctx) {
|
|
2981
2975
|
const { registry, tools } = ctx;
|
|
2982
|
-
const listFoldersOutputSchema = {
|
|
2976
|
+
const listFoldersOutputSchema = z4.object({
|
|
2983
2977
|
account: z4.string(),
|
|
2984
2978
|
count: z4.number(),
|
|
2985
2979
|
items: z4.array(folderInfoOutputSchema)
|
|
2986
|
-
};
|
|
2980
|
+
});
|
|
2987
2981
|
if (shouldRegister("list_folders", tools)) {
|
|
2988
2982
|
server.registerTool(
|
|
2989
2983
|
"list_folders",
|
|
2990
2984
|
{
|
|
2991
2985
|
description: "List available mail folders. Returns top-level folders by default, or child folders of the given parent when `parentFolderId` is provided.",
|
|
2992
|
-
inputSchema: {
|
|
2986
|
+
inputSchema: z4.object({
|
|
2993
2987
|
account: z4.string().email(),
|
|
2994
2988
|
parentFolderId: z4.string().optional().describe(
|
|
2995
2989
|
"When provided, lists child folders of this folder. When omitted, lists top-level folders (children of the root)."
|
|
2996
2990
|
)
|
|
2997
|
-
},
|
|
2991
|
+
}),
|
|
2998
2992
|
outputSchema: listFoldersOutputSchema
|
|
2999
2993
|
},
|
|
3000
2994
|
async (args) => {
|
|
@@ -3015,22 +3009,22 @@ function registerFolderTools(server, ctx) {
|
|
|
3015
3009
|
}
|
|
3016
3010
|
);
|
|
3017
3011
|
}
|
|
3018
|
-
const createFolderOutputSchema = {
|
|
3012
|
+
const createFolderOutputSchema = z4.object({
|
|
3019
3013
|
created: z4.literal(true),
|
|
3020
3014
|
folder: folderInfoOutputSchema
|
|
3021
|
-
};
|
|
3015
|
+
});
|
|
3022
3016
|
if (shouldRegister("create_folder", tools)) {
|
|
3023
3017
|
server.registerTool(
|
|
3024
3018
|
"create_folder",
|
|
3025
3019
|
{
|
|
3026
3020
|
description: "Create a new mail folder. Creates under the root folder by default, or under the specified parent when `parentFolderId` is provided. Disabled in --read-only mode.",
|
|
3027
|
-
inputSchema: {
|
|
3021
|
+
inputSchema: z4.object({
|
|
3028
3022
|
account: z4.string().email(),
|
|
3029
3023
|
displayName: z4.string().min(1).describe("Name of the new folder"),
|
|
3030
3024
|
parentFolderId: z4.string().optional().describe(
|
|
3031
3025
|
"When provided, creates the folder as a child of this folder. When omitted, creates under the root folder."
|
|
3032
3026
|
)
|
|
3033
|
-
},
|
|
3027
|
+
}),
|
|
3034
3028
|
outputSchema: createFolderOutputSchema
|
|
3035
3029
|
},
|
|
3036
3030
|
async (args) => {
|
|
@@ -3048,19 +3042,19 @@ function registerFolderTools(server, ctx) {
|
|
|
3048
3042
|
}
|
|
3049
3043
|
);
|
|
3050
3044
|
}
|
|
3051
|
-
const deleteFolderOutputSchema = {
|
|
3045
|
+
const deleteFolderOutputSchema = z4.object({
|
|
3052
3046
|
deleted: z4.literal(true),
|
|
3053
3047
|
id: z4.string()
|
|
3054
|
-
};
|
|
3048
|
+
});
|
|
3055
3049
|
if (shouldRegister("delete_folder", tools)) {
|
|
3056
3050
|
server.registerTool(
|
|
3057
3051
|
"delete_folder",
|
|
3058
3052
|
{
|
|
3059
3053
|
description: "Delete a mail folder by ID. Disabled in --read-only mode.",
|
|
3060
|
-
inputSchema: {
|
|
3054
|
+
inputSchema: z4.object({
|
|
3061
3055
|
account: z4.string().email(),
|
|
3062
3056
|
folderId: z4.string().min(1).describe("ID of the folder to delete")
|
|
3063
|
-
},
|
|
3057
|
+
}),
|
|
3064
3058
|
outputSchema: deleteFolderOutputSchema
|
|
3065
3059
|
},
|
|
3066
3060
|
async (args) => {
|
|
@@ -3075,20 +3069,20 @@ function registerFolderTools(server, ctx) {
|
|
|
3075
3069
|
}
|
|
3076
3070
|
);
|
|
3077
3071
|
}
|
|
3078
|
-
const renameFolderOutputSchema = {
|
|
3072
|
+
const renameFolderOutputSchema = z4.object({
|
|
3079
3073
|
renamed: z4.literal(true),
|
|
3080
3074
|
folder: folderInfoOutputSchema
|
|
3081
|
-
};
|
|
3075
|
+
});
|
|
3082
3076
|
if (shouldRegister("rename_folder", tools)) {
|
|
3083
3077
|
server.registerTool(
|
|
3084
3078
|
"rename_folder",
|
|
3085
3079
|
{
|
|
3086
3080
|
description: "Rename an existing mail folder. Disabled in --read-only mode.",
|
|
3087
|
-
inputSchema: {
|
|
3081
|
+
inputSchema: z4.object({
|
|
3088
3082
|
account: z4.string().email(),
|
|
3089
3083
|
folderId: z4.string().min(1).describe("ID of the folder to rename"),
|
|
3090
3084
|
newName: z4.string().min(1).describe("New display name for the folder")
|
|
3091
|
-
},
|
|
3085
|
+
}),
|
|
3092
3086
|
outputSchema: renameFolderOutputSchema
|
|
3093
3087
|
},
|
|
3094
3088
|
async (args) => {
|
|
@@ -3126,14 +3120,14 @@ function registerOrganizeTools(server, ctx) {
|
|
|
3126
3120
|
const data = { marked: true, id: args.id, isRead };
|
|
3127
3121
|
return ok(data, data);
|
|
3128
3122
|
}
|
|
3129
|
-
const archiveMoveSchema = {
|
|
3123
|
+
const archiveMoveSchema = z5.object({
|
|
3130
3124
|
account: z5.string().email(),
|
|
3131
3125
|
id: z5.string().min(1).describe("Message ID to move")
|
|
3132
|
-
};
|
|
3133
|
-
const archiveOutputSchema = {
|
|
3126
|
+
});
|
|
3127
|
+
const archiveOutputSchema = z5.object({
|
|
3134
3128
|
archived: z5.literal(true),
|
|
3135
3129
|
id: z5.string()
|
|
3136
|
-
};
|
|
3130
|
+
});
|
|
3137
3131
|
if (shouldRegister("archive_email", tools)) {
|
|
3138
3132
|
server.registerTool(
|
|
3139
3133
|
"archive_email",
|
|
@@ -3151,10 +3145,10 @@ function registerOrganizeTools(server, ctx) {
|
|
|
3151
3145
|
}
|
|
3152
3146
|
);
|
|
3153
3147
|
}
|
|
3154
|
-
const trashOutputSchema = {
|
|
3148
|
+
const trashOutputSchema = z5.object({
|
|
3155
3149
|
trashed: z5.literal(true),
|
|
3156
3150
|
id: z5.string()
|
|
3157
|
-
};
|
|
3151
|
+
});
|
|
3158
3152
|
if (shouldRegister("trash_email", tools)) {
|
|
3159
3153
|
server.registerTool(
|
|
3160
3154
|
"trash_email",
|
|
@@ -3172,23 +3166,23 @@ function registerOrganizeTools(server, ctx) {
|
|
|
3172
3166
|
}
|
|
3173
3167
|
);
|
|
3174
3168
|
}
|
|
3175
|
-
const moveEmailOutputSchema = {
|
|
3169
|
+
const moveEmailOutputSchema = z5.object({
|
|
3176
3170
|
moved: z5.literal(true),
|
|
3177
3171
|
id: z5.string(),
|
|
3178
3172
|
destination: z5.string()
|
|
3179
|
-
};
|
|
3173
|
+
});
|
|
3180
3174
|
if (shouldRegister("move_email", tools)) {
|
|
3181
3175
|
server.registerTool(
|
|
3182
3176
|
"move_email",
|
|
3183
3177
|
{
|
|
3184
3178
|
description: "Move a message to any folder by well-known name (e.g. 'inbox', 'drafts', 'junkemail', 'sentitems', 'outbox') or custom folder ID. Disabled in --read-only mode.",
|
|
3185
|
-
inputSchema: {
|
|
3179
|
+
inputSchema: z5.object({
|
|
3186
3180
|
account: z5.string().email(),
|
|
3187
3181
|
id: z5.string().min(1).describe("Message ID to move"),
|
|
3188
3182
|
destination: z5.string().min(1).describe(
|
|
3189
3183
|
"Destination folder \u2014 a well-known folder name ('archive', 'deleteditems', 'inbox', 'drafts', 'junkemail', 'sentitems', 'outbox') or a raw folder ID."
|
|
3190
3184
|
)
|
|
3191
|
-
},
|
|
3185
|
+
}),
|
|
3192
3186
|
outputSchema: moveEmailOutputSchema
|
|
3193
3187
|
},
|
|
3194
3188
|
async (args) => {
|
|
@@ -3207,15 +3201,15 @@ function registerOrganizeTools(server, ctx) {
|
|
|
3207
3201
|
}
|
|
3208
3202
|
);
|
|
3209
3203
|
}
|
|
3210
|
-
const markReadInputSchema = {
|
|
3204
|
+
const markReadInputSchema = z5.object({
|
|
3211
3205
|
account: z5.string().email(),
|
|
3212
3206
|
id: z5.string().min(1).describe("Message ID to mark as read")
|
|
3213
|
-
};
|
|
3214
|
-
const markReadOutputSchema = {
|
|
3207
|
+
});
|
|
3208
|
+
const markReadOutputSchema = z5.object({
|
|
3215
3209
|
marked: z5.literal(true),
|
|
3216
3210
|
id: z5.string(),
|
|
3217
3211
|
isRead: z5.boolean()
|
|
3218
|
-
};
|
|
3212
|
+
});
|
|
3219
3213
|
if (shouldRegister("mark_read", tools)) {
|
|
3220
3214
|
server.registerTool(
|
|
3221
3215
|
"mark_read",
|
|
@@ -3263,7 +3257,9 @@ function registerComposeTools(server, ctx) {
|
|
|
3263
3257
|
bcc: z6.array(emailAddrSchema).optional(),
|
|
3264
3258
|
subject: z6.string(),
|
|
3265
3259
|
body: z6.string(),
|
|
3266
|
-
|
|
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
|
+
),
|
|
3267
3263
|
include_signature: z6.boolean().describe(
|
|
3268
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."
|
|
3269
3265
|
),
|
|
@@ -3287,7 +3283,7 @@ function registerComposeTools(server, ctx) {
|
|
|
3287
3283
|
}
|
|
3288
3284
|
const composed = composeBody({
|
|
3289
3285
|
body: args.body,
|
|
3290
|
-
|
|
3286
|
+
format: args.format,
|
|
3291
3287
|
signature: account.signature,
|
|
3292
3288
|
style: account.style,
|
|
3293
3289
|
includeSignature: args.include_signature
|
|
@@ -3367,7 +3363,9 @@ function registerComposeTools(server, ctx) {
|
|
|
3367
3363
|
bcc: z6.array(emailAddrSchema).optional(),
|
|
3368
3364
|
subject: z6.string().optional(),
|
|
3369
3365
|
body: z6.string().optional(),
|
|
3370
|
-
|
|
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
|
+
),
|
|
3371
3369
|
include_signature: z6.boolean().optional().describe(
|
|
3372
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."
|
|
3373
3371
|
)
|
|
@@ -3399,7 +3397,7 @@ function registerComposeTools(server, ctx) {
|
|
|
3399
3397
|
if (a.body !== void 0) {
|
|
3400
3398
|
const composed = composeBody({
|
|
3401
3399
|
body: a.body,
|
|
3402
|
-
|
|
3400
|
+
format: a.format ?? "html",
|
|
3403
3401
|
signature: account.signature,
|
|
3404
3402
|
style: account.style,
|
|
3405
3403
|
includeSignature: !!a.include_signature
|