msexchange-mcp
Version:
MCP server for Microsoft Exchange/Outlook email operations via Microsoft Graph API
155 lines • 7.98 kB
JavaScript
import { z } from 'zod';
import { MailService } from '../mail/mailService.js';
import accountsConfig from '../config/accountsLoader.js';
export const modifyMailRuleTool = {
name: 'modify_mail_rule',
description: 'Modify an existing mail rule or change its enabled status',
parameters: z.object({
user_id: z.string().describe('The user ID or email address'),
rule_id: z.string().describe('ID of the rule to modify'),
rule_name: z.string().optional().describe('New name for the mail rule'),
conditions: z.object({
from_addresses: z.array(z.string()).optional().describe('Email addresses to match in From field'),
subject_contains: z.array(z.string()).optional().describe('Keywords that must be in subject'),
body_contains: z.array(z.string()).optional().describe('Keywords that must be in body'),
to_me: z.boolean().optional().describe('Email is addressed to me'),
cc_me: z.boolean().optional().describe('Email has me in CC'),
sent_to: z.array(z.string()).optional().describe('Email is sent to these addresses'),
importance: z.enum(['low', 'normal', 'high']).optional().describe('Message importance level'),
has_attachments: z.boolean().optional().describe('Email has attachments'),
}).optional().describe('Updated conditions that trigger the rule'),
actions: z.object({
move_to_folder: z.string().optional().describe('Folder ID to move emails to'),
copy_to_folder: z.string().optional().describe('Folder ID to copy emails to'),
add_categories: z.array(z.string()).optional().describe('Categories to add to the email'),
mark_as_read: z.boolean().optional().describe('Mark email as read'),
mark_importance: z.enum(['low', 'normal', 'high']).optional().describe('Set importance level'),
forward_to: z.string().optional().describe('Email address to forward to'),
delete_message: z.boolean().optional().describe('Delete the message'),
stop_processing: z.boolean().optional().describe('Stop processing additional rules'),
}).optional().describe('Updated actions to perform when conditions are met'),
enabled: z.boolean().optional().describe('Whether the rule is enabled'),
sequence: z.number().optional().describe('Rule execution order (lower numbers run first)'),
}),
execute: async (params) => {
try {
const account = accountsConfig.accounts.find(acc => acc.id === params.user_id || acc.email === params.user_id);
if (!account) {
throw new Error(`User not found: ${params.user_id}`);
}
const mailService = new MailService(account.email);
// Get existing rule first
const existingRule = await mailService.getMailRule(params.rule_id);
if (!existingRule) {
throw new Error(`Rule not found: ${params.rule_id}`);
}
// Build update data, only including provided fields
const updateData = {};
if (params.rule_name !== undefined) {
updateData.displayName = params.rule_name;
}
if (params.enabled !== undefined) {
updateData.isEnabled = params.enabled;
}
if (params.sequence !== undefined) {
updateData.sequence = params.sequence;
}
// Build updated conditions if provided
if (params.conditions) {
const graphConditions = {};
if (params.conditions.from_addresses?.length > 0) {
graphConditions.fromAddresses = params.conditions.from_addresses.map((addr) => ({
emailAddress: { address: addr }
}));
}
if (params.conditions.subject_contains?.length > 0) {
graphConditions.subjectContains = params.conditions.subject_contains;
}
if (params.conditions.body_contains?.length > 0) {
graphConditions.bodyContains = params.conditions.body_contains;
}
if (params.conditions.sent_to?.length > 0) {
graphConditions.recipientContains = params.conditions.sent_to.map((addr) => ({
emailAddress: { address: addr }
}));
}
if (params.conditions.importance) {
graphConditions.importance = params.conditions.importance;
}
if (params.conditions.has_attachments !== undefined) {
graphConditions.hasAttachments = params.conditions.has_attachments;
}
if (params.conditions.to_me) {
graphConditions.sentToMe = true;
}
if (params.conditions.cc_me) {
graphConditions.sentCcMe = true;
}
updateData.conditions = graphConditions;
}
// Build updated actions if provided
if (params.actions) {
const graphActions = {};
if (params.actions.move_to_folder) {
graphActions.moveToFolder = params.actions.move_to_folder;
}
if (params.actions.copy_to_folder) {
graphActions.copyToFolder = params.actions.copy_to_folder;
}
if (params.actions.add_categories?.length > 0) {
graphActions.assignCategories = params.actions.add_categories;
}
if (params.actions.mark_as_read !== undefined) {
graphActions.markAsRead = params.actions.mark_as_read;
}
if (params.actions.mark_importance) {
graphActions.markImportance = params.actions.mark_importance;
}
if (params.actions.forward_to) {
graphActions.forwardTo = {
emailAddress: { address: params.actions.forward_to }
};
}
if (params.actions.delete_message) {
graphActions.delete = true;
}
if (params.actions.stop_processing !== undefined) {
graphActions.stopProcessingRules = params.actions.stop_processing;
}
updateData.actions = graphActions;
}
const updatedRule = await mailService.updateMailRule(params.rule_id, updateData);
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
rule: {
id: updatedRule.id,
displayName: updatedRule.displayName,
sequence: updatedRule.sequence,
isEnabled: updatedRule.isEnabled,
conditions: updatedRule.conditions,
actions: updatedRule.actions,
},
changes_made: Object.keys(updateData),
message: `Successfully updated mail rule '${updatedRule.displayName}'`,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error modifying mail rule: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
};
}
},
};
//# sourceMappingURL=modifyMailRule.js.map