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

234 lines (197 loc) • 6.45 kB
/** * Teams management functionality */ const { callGraphAPI } = require('../utils/graph-api'); const { ensureAuthenticated, createAuthRequiredResponse } = require('../auth'); const config = require('../config'); /** * List teams handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleListTeams(args) { try { const { count = config.DEFAULT_PAGE_SIZE } = args; // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // Check if authentication is required if (!accessToken) { return await createAuthRequiredResponse('list-teams'); } // Validate count parameter const validCount = Math.min(Math.max(1, count), config.MAX_RESULT_COUNT); // Build the API path const apiPath = 'me/joinedTeams'; // Build query parameters const queryParams = { '$select': config.TEAMS_SELECT_FIELDS, '$top': validCount, '$orderby': 'displayName asc' }; console.error(`Fetching ${validCount} teams`); // Make API call const response = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams); const teams = response.value || []; return { content: [ { type: "text", text: `Found ${teams.length} teams:\n\n${teams.map(team => { const visibility = team.visibility || 'Unknown'; const description = team.description || 'No description'; const messagingSettings = team.messagingSettings || {}; const memberSettings = team.memberSettings || {}; return `šŸ¢ ${team.displayName} ID: ${team.id} Visibility: ${visibility} Description: ${description} Messaging: ${messagingSettings.allowUserEditMessages ? 'Edit allowed' : 'Edit restricted'} Members: ${memberSettings.allowCreateUpdateChannels ? 'Can create channels' : 'Channel creation restricted'}`; }).join('\n\n')}` } ] }; } catch (error) { console.error('Error in handleListTeams:', error); return { error: { code: -32603, message: `Failed to list teams: ${error.message}` } }; } } /** * Get team details handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleGetTeamDetails(args) { try { const { teamId } = args; if (!teamId) { return { content: [{ type: "text", text: "Team ID is required" }] }; } // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // Check if authentication is required if (!accessToken) { return await createAuthRequiredResponse('get-team-details'); } // Build the API path const apiPath = `teams/${teamId}`; // Build query parameters const queryParams = { '$select': config.TEAMS_DETAIL_FIELDS }; console.error(`Getting team details: ${teamId}`); // Make API call const team = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams); const formatSettings = (settings) => { if (!settings) return 'Not configured'; return Object.entries(settings) .map(([key, value]) => `${key}: ${value}`) .join(', '); }; return { content: [ { type: "text", text: `šŸ¢ Team Details **Name:** ${team.displayName} **Team ID:** ${team.id} **Description:** ${team.description || 'No description'} **Visibility:** ${team.visibility || 'Unknown'} **Created:** ${team.createdDateTime ? new Date(team.createdDateTime).toLocaleString() : 'Unknown'} **Settings:** • Member Settings: ${formatSettings(team.memberSettings)} • Guest Settings: ${formatSettings(team.guestSettings)} • Messaging Settings: ${formatSettings(team.messagingSettings)} • Fun Settings: ${formatSettings(team.funSettings)} • Discovery Settings: ${formatSettings(team.discoverySettings)} **Internal ID:** ${team.internalId || 'Not available'}` } ] }; } catch (error) { console.error('Error in handleGetTeamDetails:', error); return { content: [{ type: "text", text: `Error getting team details: ${error.message}` }] }; } } /** * List team members handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleListTeamMembers(args) { try { const { teamId, count = config.DEFAULT_PAGE_SIZE } = args; if (!teamId) { return { content: [{ type: "text", text: "Team ID is required" }] }; } // Ensure user is authenticated const accessToken = await ensureAuthenticated(); // Check if authentication is required if (!accessToken) { return await createAuthRequiredResponse('list-team-members'); } // Validate count parameter const validCount = Math.min(Math.max(1, count), config.MAX_RESULT_COUNT); // Build the API path const apiPath = `teams/${teamId}/members`; // Build query parameters const queryParams = { '$select': 'id,displayName,email,roles,userId,tenantId', '$top': validCount, '$orderby': 'displayName asc' }; console.error(`Fetching ${validCount} team members for team: ${teamId}`); // Make API call const response = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams); const members = response.value || []; return { content: [ { type: "text", text: `Found ${members.length} team members:\n\n${members.map(member => { const roles = member.roles && member.roles.length > 0 ? member.roles.join(', ') : 'Member'; const email = member.email || 'No email'; return `šŸ‘¤ ${member.displayName} ID: ${member.id} Email: ${email} Roles: ${roles} User ID: ${member.userId || 'Unknown'}`; }).join('\n\n')}` } ] }; } catch (error) { console.error('Error in handleListTeamMembers:', error); return { content: [{ type: "text", text: `Error listing team members: ${error.message}` }] }; } } module.exports = { handleListTeams, handleGetTeamDetails, handleListTeamMembers };