UNPKG

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

166 lines (139 loc) 5.63 kB
#!/usr/bin/env node /** * Script to find and move existing GitHub notification emails * to the GitHub Notifications subfolder */ const https = require('https'); const fs = require('fs'); const path = require('path'); // Configuration const homePath = process.env.HOME || '/Users/ryaker'; const tokenPath = path.join(homePath, '.outlook-mcp-tokens.json'); const githubFolderId = 'AAMkAGQ0NzYwMTdmLTYzMWUtNDE1ZS04ZDYyLTZjZmQ5YjkyNWM0OQAuAAAAAAAMiw_uRKMyQ4cvWGcmDNGZAQD-pkus0juzTK_ueB_BlgMCAAGKmpqoAAA='; const notificationsFolderId = 'AAMkAGQ0NzYwMTdmLTYzMWUtNDE1ZS04ZDYyLTZjZmQ5YjkyNWM0OQAuAAAAAAAMiw_uRKMyQ4cvWGcmDNGZAQD-pkus0juzTK_ueB_BlgMCAAGKmpqpAAA='; // Main function async function moveGitHubEmails() { try { // Read the authentication token from file console.log(`Reading token from ${tokenPath}`); const tokenData = JSON.parse(fs.readFileSync(tokenPath, 'utf8')); const accessToken = tokenData.access_token; if (!accessToken) { console.error('No access token found in token file!'); process.exit(1); } console.log('Successfully read access token'); // Step 1: Search for GitHub notification emails in the inbox console.log('\nSearching for GitHub notification emails...'); const searchParams = new URLSearchParams({ $filter: "from/emailAddress/address eq 'notifications@github.com' or from/emailAddress/address eq 'noreply@github.com'", $top: 100, $select: 'id,subject,from,receivedDateTime' }); const inboxEmails = await callGraphAPI(`me/mailFolders/inbox/messages?${searchParams.toString()}`); console.log(`Found ${inboxEmails.value.length} GitHub notification emails in inbox`); // Step 2: Classify emails as workflow notifications or other const workflowEmails = []; const otherEmails = []; inboxEmails.value.forEach(email => { const subject = email.subject.toLowerCase(); if ( subject.includes('workflow') || subject.includes('run failed') || subject.includes('run completed') || subject.includes('github actions') ) { workflowEmails.push(email); } else if (subject.includes('[gondola')) { workflowEmails.push(email); // These are also notifications } else { otherEmails.push(email); } }); console.log(`Workflow notifications: ${workflowEmails.length}`); console.log(`Other GitHub emails: ${otherEmails.length}`); // Step 3: Move workflow notifications to the Notifications subfolder if (workflowEmails.length > 0) { console.log('\nMoving workflow notifications to Notifications subfolder...'); let movedCount = 0; for (const email of workflowEmails) { try { await callGraphAPI(`me/messages/${email.id}/move`, 'POST', { destinationId: notificationsFolderId }); movedCount++; console.log(`Moved ${movedCount}/${workflowEmails.length}: "${email.subject}"`); } catch (error) { console.error(`Failed to move email: ${error.message}`); } } console.log(`Successfully moved ${movedCount} workflow notifications to Notifications subfolder`); } // Step 4: Move other GitHub emails to the main GitHub folder if (otherEmails.length > 0) { console.log('\nMoving other GitHub emails to GitHub folder...'); let movedCount = 0; for (const email of otherEmails) { try { await callGraphAPI(`me/messages/${email.id}/move`, 'POST', { destinationId: githubFolderId }); movedCount++; console.log(`Moved ${movedCount}/${otherEmails.length}: "${email.subject}"`); } catch (error) { console.error(`Failed to move email: ${error.message}`); } } console.log(`Successfully moved ${movedCount} other GitHub emails to GitHub folder`); } console.log('\nEmail organization complete!'); } catch (error) { console.error('Error:', error); } } /** * Helper function to call Microsoft Graph API */ async function callGraphAPI(endpoint, method = 'GET', data = null) { return new Promise((resolve, reject) => { // Read token from file again to ensure it's fresh const tokenData = JSON.parse(fs.readFileSync(tokenPath, 'utf8')); const accessToken = tokenData.access_token; const options = { hostname: 'graph.microsoft.com', path: `/v1.0/${endpoint}`, method: method, headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }; const req = https.request(options, (res) => { let responseData = ''; res.on('data', (chunk) => { responseData += chunk; }); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { try { const jsonResponse = responseData ? JSON.parse(responseData) : {}; resolve(jsonResponse); } catch (error) { reject(new Error(`Failed to parse API response: ${error.message}`)); } } else { reject(new Error(`API request failed with status ${res.statusCode}: ${responseData}`)); } }); }); req.on('error', (error) => { reject(new Error(`Network error: ${error.message}`)); }); if (data && (method === 'POST' || method === 'PATCH' || method === 'PUT')) { req.write(JSON.stringify(data)); } req.end(); }); } // Run the script moveGitHubEmails();