msexchange-mcp
Version:
MCP server for Microsoft Exchange/Outlook email operations via Microsoft Graph API
95 lines • 4.33 kB
JavaScript
import { z } from 'zod';
import { UnifiedSearchService } from '../services/unifiedSearch.js';
import { MailService } from '../services/mail.js';
import { formatEmailForMCP } from '../utils/formatters.js';
import { logger } from '../utils/logger.js';
const inputSchema = z.object({
user_id: z.string().describe('The user ID or email address'),
query: z.string().describe('Natural language description of what emails to find (e.g., "emails from john@example.com about project X", "unread emails with attachments", "emails from KPMG")'),
limit: z.number().optional().default(20).describe('Maximum number of results'),
include_body: z.boolean().optional().default(false).describe('Include full email content'),
date_start: z.string().optional().describe('Start date in ISO format (e.g., "2025-01-01")'),
date_end: z.string().optional().describe('End date in ISO format (e.g., "2025-01-31")'),
});
export const simpleEmailSearchTool = {
name: 'simple_email_search',
description: 'Simple, user-friendly email search that automatically handles complex query optimization. Just describe what you\'re looking for in natural language.',
parameters: inputSchema,
execute: async ({ user_id, query, limit, include_body, date_start, date_end }) => {
try {
logger.info('Simple email search (redirecting to unified search)', { user_id, query });
const mailService = MailService.getInstance();
const searchService = new UnifiedSearchService(mailService);
// Build search query with date range if provided
const searchQuery = {
text: query,
requireAllTerms: true,
includeAliases: true,
semanticSearch: true,
limit,
dateRange: (date_start || date_end) ? {
start: date_start ? new Date(date_start) : undefined,
end: date_end ? new Date(date_end) : undefined,
} : undefined,
};
// Use unified search
const result = await searchService.search(searchQuery, {
accountId: user_id,
limit,
includeBody: include_body,
});
// Format response
if (result.emails.length === 0) {
let response = 'No emails found matching your search.\n\n';
if (result.suggestions && result.suggestions.length > 0) {
response += 'Suggestions:\n';
result.suggestions.forEach(suggestion => {
response += `• ${suggestion}\n`;
});
}
return {
content: [
{
type: 'text',
text: response,
},
],
};
}
let response = `Found ${result.totalCount} email${result.totalCount !== 1 ? 's' : ''}`;
if (result.searchStrategy === 'or_fallback') {
response += ' (showing emails with ANY of your search terms)';
}
response += '\n\n';
const formattedEmails = result.emails.map(email => formatEmailForMCP(email, {
includeBody: include_body,
includeHeaders: false,
maxBodyLength: include_body ? 1000 : 0,
}));
response += formattedEmails.join('\n' + '─'.repeat(50) + '\n');
if (result.hasMore) {
response += `\n\nShowing ${limit} of ${result.totalCount}+ results.`;
}
return {
content: [
{
type: 'text',
text: response,
},
],
};
}
catch (error) {
logger.error('Simple email search error', { error });
return {
content: [
{
type: 'text',
text: `Search failed: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
},
};
//# sourceMappingURL=simpleEmailSearch.js.map