outlook-mcp
Version:
Comprehensive MCP server for Claude to access Microsoft Outlook and Teams via Microsoft Graph API - including Email, Calendar, Contacts, Tasks, Teams, Chats, and Online Meetings
156 lines (132 loc) • 4.24 kB
JavaScript
/**
* Email attachments functionality
*/
const { callGraphAPI } = require('../utils/graph-api');
const { ensureAuthenticated } = require('../auth');
/**
* List email attachments handler
* @param {object} args - Tool arguments
* @returns {object} - MCP response
*/
async function handleListAttachments(args) {
try {
const { emailId } = args;
if (!emailId) {
return {
error: {
code: -32602,
message: "Email ID is required"
}
};
}
// Ensure user is authenticated
const accessToken = await ensureAuthenticated();
// Build the API path
const apiPath = `me/messages/${emailId}/attachments`;
// Build query parameters
const queryParams = {
'$select': 'id,name,size,contentType,isInline,lastModifiedDateTime'
};
console.error(`Fetching attachments for email: ${emailId}`);
// Make API call
const response = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams);
const attachments = response.value || [];
// Format file size
const formatSize = (bytes) => {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
return {
content: [
{
type: "text",
text: `Found ${attachments.length} attachments:\n\n${attachments.map(attachment => {
const inline = attachment.isInline ? ' (Inline)' : '';
const modified = attachment.lastModifiedDateTime ?
new Date(attachment.lastModifiedDateTime).toLocaleString() : 'Unknown';
return `📎 ${attachment.name}${inline}
ID: ${attachment.id}
Size: ${formatSize(attachment.size)}
Type: ${attachment.contentType}
Modified: ${modified}`;
}).join('\n\n')}`
}
]
};
} catch (error) {
console.error('Error in handleListAttachments:', error);
return {
error: {
code: -32603,
message: `Failed to list attachments: ${error.message}`
}
};
}
}
/**
* Download email attachment handler
* @param {object} args - Tool arguments
* @returns {object} - MCP response
*/
async function handleDownloadAttachment(args) {
try {
const { emailId, attachmentId } = args;
if (!emailId || !attachmentId) {
return {
error: {
code: -32602,
message: "Email ID and attachment ID are required"
}
};
}
// Ensure user is authenticated
const accessToken = await ensureAuthenticated();
// Build the API path
const apiPath = `me/messages/${emailId}/attachments/${attachmentId}`;
// Build query parameters - get full attachment data
const queryParams = {
'$select': 'id,name,size,contentType,contentBytes,isInline'
};
console.error(`Downloading attachment: ${attachmentId} from email: ${emailId}`);
// Make API call
const attachment = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams);
// Format file size
const formatSize = (bytes) => {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
return {
content: [
{
type: "text",
text: `✅ Attachment downloaded successfully!
**File Name:** ${attachment.name}
**Size:** ${formatSize(attachment.size)}
**Type:** ${attachment.contentType}
**Content:** The attachment content is available in base64 format.
**Base64 Content:**
${attachment.contentBytes}
You can decode this base64 content to save the file locally.`
}
]
};
} catch (error) {
console.error('Error in handleDownloadAttachment:', error);
return {
error: {
code: -32603,
message: `Failed to download attachment: ${error.message}`
}
};
}
}
module.exports = {
handleListAttachments,
handleDownloadAttachment
};