Skip to content

Commit 5cc120e

Browse files
committed
refactor(email): improve type safety and cleanup function signatures
- Added specific Email property types with proper enum validation - Removed unused getConfig and createClient parameters from registerEmailTools - Improved type safety with proper JMAP types for filters and updates - Added missing type imports for Email, EmailCreate, FilterCondition etc. - Version bump to 0.1.1
1 parent 0641d18 commit 5cc120e

File tree

3 files changed

+51
-42
lines changed

3 files changed

+51
-42
lines changed

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@wyattjoh/jmap-mcp",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"license": "MIT",
55
"exports": "./src/mod.ts",
66
"publish": {

src/mod.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,7 @@ Works with any JMAP-compliant email server including Cyrus IMAP, Stalwart Mail S
8888
const account = session.accounts[accountId];
8989

9090
if ("urn:ietf:params:jmap:mail" in session.capabilities) {
91-
registerEmailTools(
92-
server,
93-
jam,
94-
accountId,
95-
account.isReadOnly,
96-
getJMAPConfig,
97-
createJAMClient,
98-
);
91+
registerEmailTools(server, jam, accountId, account.isReadOnly);
9992
console.warn("Registered urn:ietf:params:jmap:mail tools");
10093

10194
if (

src/tools/email.ts

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
import { z } from "zod";
33
import type JamClient from "jmap-jam";
4-
import type { EmailFilterCondition } from "jmap-jam";
4+
import type {
5+
Email,
6+
EmailCreate,
7+
EmailFilterCondition,
8+
FilterCondition,
9+
GetEmailArguments,
10+
MailboxFilterCondition,
11+
} from "jmap-jam";
512
import { formatError } from "../utils.ts";
613

714
export const SearchEmailsSchema = z.object({
@@ -57,8 +64,37 @@ export const GetEmailsSchema = z.object({
5764
ids: z.array(z.string()).min(1).max(50).describe(
5865
"Array of email IDs to retrieve",
5966
),
60-
properties: z.array(z.string()).optional().describe(
61-
"Specific properties to return (default: all)",
67+
properties: z.array(z.enum(
68+
[
69+
"id",
70+
"blobId",
71+
"threadId",
72+
"mailboxIds",
73+
"keywords",
74+
"size",
75+
"receivedAt",
76+
"headers",
77+
"messageId",
78+
"inReplyTo",
79+
"references",
80+
"sender",
81+
"from",
82+
"to",
83+
"cc",
84+
"bcc",
85+
"replyTo",
86+
"subject",
87+
"sentAt",
88+
"bodyStructure",
89+
"bodyValues",
90+
"textBody",
91+
"htmlBody",
92+
"attachments",
93+
"hasAttachment",
94+
"preview",
95+
] as const satisfies Array<keyof Email>,
96+
)).optional().describe(
97+
"Specific Email properties to return (default: all).",
6298
),
6399
});
64100

@@ -141,14 +177,6 @@ export function registerEmailTools(
141177
jam: JamClient,
142178
accountId: string,
143179
isReadOnly: boolean,
144-
getConfig: () => {
145-
sessionUrl: string;
146-
bearerToken: string;
147-
accountId?: string;
148-
},
149-
createClient: (
150-
config: { sessionUrl: string; bearerToken: string; accountId?: string },
151-
) => JamClient,
152180
) {
153181
server.tool(
154182
"search_emails",
@@ -205,7 +233,7 @@ export function registerEmailTools(
205233
GetMailboxesSchema.shape,
206234
async (args) => {
207235
try {
208-
let filter: Record<string, unknown> | undefined;
236+
let filter: FilterCondition<MailboxFilterCondition> | undefined;
209237
if (args.parentId) {
210238
filter = { parentId: args.parentId };
211239
}
@@ -260,21 +288,13 @@ export function registerEmailTools(
260288
GetEmailsSchema.shape,
261289
async (args) => {
262290
try {
263-
const config = getConfig();
264-
const jam = createClient(config);
265-
const accountId = config.accountId || await jam.getPrimaryAccount();
266-
267-
const [result] = await jam.api.Email.get({
268-
accountId,
269-
ids: args.ids,
270-
properties: args.properties as
271-
| readonly (
272-
| keyof import("jmap-jam").Email
273-
| import("jmap-jam").HeaderFieldKey
274-
)[]
275-
| null
276-
| undefined,
277-
});
291+
const [result] = await jam.api.Email.get(
292+
{
293+
accountId,
294+
ids: args.ids,
295+
properties: args.properties,
296+
} satisfies GetEmailArguments,
297+
);
278298

279299
return {
280300
content: [
@@ -350,11 +370,7 @@ export function registerEmailTools(
350370
MarkEmailsSchema.shape,
351371
async (args) => {
352372
try {
353-
const config = getConfig();
354-
const jam = createClient(config);
355-
const accountId = config.accountId || await jam.getPrimaryAccount();
356-
357-
const updates: Record<string, Record<string, unknown>> = {};
373+
const updates: Record<string, EmailCreate> = {};
358374

359375
for (const id of args.ids) {
360376
const keywords: Record<string, boolean> = {};
@@ -408,7 +424,7 @@ export function registerEmailTools(
408424
MoveEmailsSchema.shape,
409425
async (args) => {
410426
try {
411-
const updates: Record<string, Record<string, unknown>> = {};
427+
const updates: Record<string, EmailCreate> = {};
412428

413429
for (const id of args.ids) {
414430
updates[id] = {

0 commit comments

Comments
 (0)