msexchange-mcp
Version:
MCP server for Microsoft Exchange/Outlook email operations via Microsoft Graph API
154 lines • 5.11 kB
JavaScript
/**
* Format an email message for MCP output
*/
export function formatEmailForMCP(email, options = {}) {
const { includeBody = false, includeHeaders = false, maxBodyLength = 500, includeAttachments = true, } = options;
let output = '';
// Subject and metadata
output += `📧 **${email.subject || '(No Subject)'}**\n`;
output += `From: ${formatEmailAddress(email.from)}\n`;
if (email.toRecipients && email.toRecipients.length > 0) {
output += `To: ${email.toRecipients.map(r => formatEmailAddress(r)).join(', ')}\n`;
}
if (email.ccRecipients && email.ccRecipients.length > 0) {
output += `Cc: ${email.ccRecipients.map(r => formatEmailAddress(r)).join(', ')}\n`;
}
output += `Date: ${formatDate(email.receivedDateTime)}\n`;
// Status indicators
const indicators = [];
if (!email.isRead)
indicators.push('🔵 Unread');
if (email.hasAttachments)
indicators.push('📎 Has Attachments');
if (email.importance === 'high')
indicators.push('❗ High Priority');
if (email.flag?.flagStatus === 'flagged')
indicators.push('🚩 Flagged');
if (indicators.length > 0) {
output += `Status: ${indicators.join(' | ')}\n`;
}
// Categories/Labels
if (email.categories && email.categories.length > 0) {
output += `Labels: ${email.categories.map(c => `🏷️ ${c}`).join(', ')}\n`;
}
// ID for reference
output += `ID: ${email.id}\n`;
// Headers if requested
if (includeHeaders && email.internetMessageHeaders) {
output += '\n**Headers:**\n';
const importantHeaders = ['Message-ID', 'In-Reply-To', 'References'];
email.internetMessageHeaders
.filter(h => importantHeaders.includes(h.name))
.forEach(h => {
output += `${h.name}: ${h.value}\n`;
});
}
// Body preview or full body
if (includeBody && email.body) {
output += '\n**Content:**\n';
const bodyText = email.body.contentType === 'text'
? email.body.content
: stripHtml(email.body.content);
if (maxBodyLength && bodyText.length > maxBodyLength) {
output += bodyText.substring(0, maxBodyLength) + '...\n';
output += `(Truncated - ${bodyText.length} total characters)\n`;
}
else {
output += bodyText + '\n';
}
}
else if (email.bodyPreview) {
output += `\nPreview: ${email.bodyPreview}\n`;
}
// Attachments
if (includeAttachments && email.hasAttachments && email.attachments) {
output += '\n**Attachments:**\n';
email.attachments.forEach(att => {
output += `• ${att.name} (${formatFileSize(att.size)})\n`;
});
}
return output;
}
/**
* Format email address for display
*/
function formatEmailAddress(recipient) {
if (!recipient)
return '(Unknown)';
const { address, name } = recipient.emailAddress;
return name ? `${name} <${address}>` : address;
}
/**
* Format date for display
*/
function formatDate(dateString) {
if (!dateString)
return '(Unknown date)';
const date = new Date(dateString);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
// Today
if (diffDays === 0) {
return `Today at ${date.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
})}`;
}
// Yesterday
if (diffDays === 1) {
return `Yesterday at ${date.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
})}`;
}
// This week
if (diffDays < 7) {
return date.toLocaleDateString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true
});
}
// Older
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true
});
}
/**
* Format file size for display
*/
function formatFileSize(bytes) {
if (bytes === 0)
return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
/**
* Basic HTML stripping
*/
function stripHtml(html) {
return html
.replace(/<[^>]*>/g, '') // Remove HTML tags
.replace(/ /g, ' ') // Replace
.replace(/&/g, '&') // Replace &
.replace(/</g, '<') // Replace <
.replace(/>/g, '>') // Replace >
.replace(/"/g, '"') // Replace "
.replace(/'/g, "'") // Replace '
.replace(/\s+/g, ' ') // Collapse whitespace
.trim();
}
//# sourceMappingURL=formatters.js.map