UNPKG

msteams-mcp-server

Version:

Microsoft Teams MCP Server - Complete Teams integration for Claude Desktop and MCP clients with secure OAuth2 authentication and comprehensive team management

1,909 lines • 96.2 kB
/**
 * Microsoft Teams MCP Server
 * A comprehensive server implementation using Model Context Protocol for Microsoft Teams API
 */
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { logger } from './utils/api.js';
import { teamsOperations } from './utils/teams-operations.js';
import { teamsAuth } from './utils/teams-auth.js';
let teamsConfig = {
    setupAuth: false,
    resetAuth: false,
    debug: false,
    nonInteractive: false,
    login: false,
    logout: false,
    verifyLogin: false,
    checkPermissions: false,
    adminConsentHelp: false,
    azureSetup: false,
    clientId: undefined,
    tenantId: undefined,
    clientSecret: undefined,
};
function parseArgs() {
    const args = process.argv.slice(2);
    const config = {
        setupAuth: false,
        resetAuth: false,
        debug: false,
        nonInteractive: false,
        login: false,
        logout: false,
        verifyLogin: false,
        checkPermissions: false,
        adminConsentHelp: false,
        azureSetup: false,
        clientId: undefined,
        tenantId: undefined,
        clientSecret: undefined,
    };
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        if (arg === '--setup-auth')
            config.setupAuth = true;
        else if (arg === '--reset-auth')
            config.resetAuth = true;
        else if (arg === '--debug')
            config.debug = true;
        else if (arg === '--non-interactive' || arg === '-n')
            config.nonInteractive = true;
        else if (arg === '--login')
            config.login = true;
        else if (arg === '--logout')
            config.logout = true;
        else if (arg === '--verify-login')
            config.verifyLogin = true;
        else if (arg === '--check-permissions')
            config.checkPermissions = true;
        else if (arg === '--admin-consent-help')
            config.adminConsentHelp = true;
        else if (arg === '--azure-setup')
            config.azureSetup = true;
        else if (arg === '--client-id') {
            if (i + 1 < args.length) {
                config.clientId = args[i + 1];
                i++; // Skip the next argument since it's the value
            }
        }
        else if (arg === '--tenant-id') {
            if (i + 1 < args.length) {
                config.tenantId = args[i + 1];
                i++; // Skip the next argument since it's the value
            }
        }
        else if (arg === '--client-secret') {
            if (i + 1 < args.length) {
                config.clientSecret = args[i + 1];
                i++; // Skip the next argument since it's the value
            }
        }
        else if (arg === '--redirect-uri') {
            if (i + 1 < args.length) {
                config.redirectUri = args[i + 1];
                i++; // Skip the next argument since it's the value
            }
        }
        else if (arg === '--user-id') {
            if (i + 1 < args.length) {
                config.userId = args[i + 1];
                i++; // Skip the next argument since it's the value
            }
        }
    }
    return config;
}
const server = new Server({
    name: "msteams-mcp-server",
    version: "1.0.25"
}, {
    capabilities: {
        resources: {
            read: true,
            list: true,
            templates: true
        },
        tools: {
            list: true,
            call: true
        },
        prompts: {
            list: true,
            get: true
        },
        resourceTemplates: {
            list: true
        }
    }
});
logger.log('Microsoft Teams MCP Server started with version 1.0.23');
// Set up the resource listing request handler
server.setRequestHandler(ListResourcesRequestSchema, async () => {
    logger.log('Received list resources request');
    return { resources: [] };
});
/**
 * Handler for reading resource information.
 */
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
    logger.log('Received read resource request: ' + JSON.stringify(request));
    throw new Error("Resource reading not implemented");
});
/**
 * Handler for listing available prompts.
 */
server.setRequestHandler(ListPromptsRequestSchema, async () => {
    logger.log('Received list prompts request');
    return { prompts: [] };
});
/**
 * Handler for getting a specific prompt.
 */
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
    logger.log('Received get prompt request: ' + JSON.stringify(request));
    throw new Error("Prompt getting not implemented");
});
/**
 * Handler for listing available resource templates.
 */
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
    logger.log('Received list resource templates request');
    return { resourceTemplates: [] };
});
/**
 * List available tools for interacting with Microsoft Teams.
 */
server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: [
            {
                name: "teams_authenticate",
                description: "Handle Microsoft Teams authentication (login, logout, status check)",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["login", "logout", "status"],
                            description: "Authentication action to perform: login (start auth), logout (clear tokens), status (check current state)"
                        }
                    },
                    required: ["action"]
                }
            },
            {
                name: "manage_teams",
                description: "Comprehensive team management - list, search, create, or get details about teams",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["list", "search", "create", "get", "get_members"],
                            description: "Action to perform on teams"
                        },
                        teamId: {
                            type: "string",
                            description: "Team ID for get, get_members actions"
                        },
                        query: {
                            type: "string",
                            description: "Search query for teams (name or description)"
                        },
                        visibility: {
                            type: "string",
                            enum: ["Private", "Public"],
                            description: "Filter teams by visibility"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of results to return",
                            default: 10
                        },
                        displayName: {
                            type: "string",
                            description: "Name for new team (create action)"
                        },
                        description: {
                            type: "string",
                            description: "Description for new team (create action)"
                        },
                        members: {
                            type: "array",
                            items: { type: "string" },
                            description: "Array of user IDs or emails for team members (create action)"
                        },
                        owners: {
                            type: "array",
                            items: { type: "string" },
                            description: "Array of user IDs or emails for team owners (create action)"
                        }
                    },
                    required: ["action"]
                }
            },
            {
                name: "manage_channels",
                description: "Channel management - list, search, create channels in teams",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["list", "search", "create"],
                            description: "Action to perform on channels"
                        },
                        teamId: {
                            type: "string",
                            description: "Team ID (required for all actions)"
                        },
                        query: {
                            type: "string",
                            description: "Search query for channels (name or description)"
                        },
                        membershipType: {
                            type: "string",
                            enum: ["standard", "private", "shared"],
                            description: "Filter channels by membership type"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of results to return",
                            default: 10
                        },
                        displayName: {
                            type: "string",
                            description: "Name for new channel (create action)"
                        },
                        description: {
                            type: "string",
                            description: "Description for new channel (create action)"
                        }
                    },
                    required: ["action", "teamId"]
                }
            },
            {
                name: "send_message",
                description: "Send a message to a Teams channel",
                inputSchema: {
                    type: "object",
                    properties: {
                        teamId: {
                            type: "string",
                            description: "ID of the team containing the channel"
                        },
                        channelId: {
                            type: "string",
                            description: "ID of the channel to send message to"
                        },
                        content: {
                            type: "string",
                            description: "Message content to send"
                        },
                        contentType: {
                            type: "string",
                            enum: ["text", "html"],
                            description: "Content type of the message",
                            default: "text"
                        },
                        mentions: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    id: { type: "string" },
                                    displayName: { type: "string" }
                                }
                            },
                            description: "Array of user mentions in the message"
                        }
                    },
                    required: ["teamId", "channelId", "content"]
                }
            },
            {
                name: "manage_messages",
                description: "Message management - get or search messages in channels",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["get", "search"],
                            description: "Action to perform on messages"
                        },
                        teamId: {
                            type: "string",
                            description: "ID of the team containing the channel"
                        },
                        channelId: {
                            type: "string",
                            description: "ID of the channel"
                        },
                        query: {
                            type: "string",
                            description: "Search query for messages (search action)"
                        },
                        fromDate: {
                            type: "string",
                            description: "Start date for message search (ISO format)"
                        },
                        toDate: {
                            type: "string",
                            description: "End date for message search (ISO format)"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of results to return",
                            default: 20
                        }
                    },
                    required: ["action", "teamId", "channelId"]
                }
            },
            {
                name: "manage_members",
                description: "Team member management - add or remove team members",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["add", "remove"],
                            description: "Action to perform on team members"
                        },
                        teamId: {
                            type: "string",
                            description: "ID of the team"
                        },
                        userId: {
                            type: "string",
                            description: "User ID or email to add/remove"
                        },
                        memberId: {
                            type: "string",
                            description: "Member ID for removal (use with remove action)"
                        },
                        roles: {
                            type: "array",
                            items: {
                                type: "string",
                                enum: ["owner", "member"]
                            },
                            description: "Roles for the user (add action)",
                            default: ["member"]
                        }
                    },
                    required: ["action", "teamId"]
                }
            },
            {
                name: "search_users",
                description: "Search for users in the organization",
                inputSchema: {
                    type: "object",
                    properties: {
                        query: {
                            type: "string",
                            description: "Search query (name or email)"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of results to return",
                            default: 10
                        }
                    },
                    required: ["query"]
                }
            },
            {
                name: "send_direct_message",
                description: "Send a direct message to a user",
                inputSchema: {
                    type: "object",
                    properties: {
                        userId: {
                            type: "string",
                            description: "User ID to send message to"
                        },
                        displayName: {
                            type: "string",
                            description: "Display name of user (used to find user ID if userId not provided)"
                        },
                        content: {
                            type: "string",
                            description: "Message content to send"
                        },
                        contentType: {
                            type: "string",
                            enum: ["text", "html"],
                            description: "Content type of the message",
                            default: "text"
                        },
                        mentions: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    id: { type: "string" },
                                    displayName: { type: "string" }
                                }
                            },
                            description: "Array of user mentions in the message"
                        }
                    },
                    required: ["content"]
                }
            },
            {
                name: "get_direct_messages",
                description: "Get direct messages from a chat with a user",
                inputSchema: {
                    type: "object",
                    properties: {
                        userId: {
                            type: "string",
                            description: "User ID to get messages from"
                        },
                        displayName: {
                            type: "string",
                            description: "Display name of user (used to find user ID if userId not provided)"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of messages to return",
                            default: 20
                        }
                    },
                    required: []
                }
            },
            {
                name: "manage_reactions",
                description: "Add or remove reactions from messages",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["add", "remove"],
                            description: "Action to perform: add or remove reaction"
                        },
                        messageType: {
                            type: "string",
                            enum: ["channel", "chat"],
                            description: "Type of message: channel message or chat/direct message"
                        },
                        teamId: {
                            type: "string",
                            description: "Team ID (required for channel messages)"
                        },
                        channelId: {
                            type: "string",
                            description: "Channel ID (required for channel messages)"
                        },
                        chatId: {
                            type: "string",
                            description: "Chat ID (required for chat messages, can be obtained from direct message operations)"
                        },
                        messageId: {
                            type: "string",
                            description: "ID of the message to react to"
                        },
                        reactionType: {
                            type: "string",
                            enum: ["like", "heart", "laugh", "surprised", "sad", "angry"],
                            description: "Type of reaction"
                        }
                    },
                    required: ["action", "messageType", "messageId", "reactionType"]
                }
            },
            {
                name: "manage_files",
                description: "Upload, download, or list files in teams and channels",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["upload", "download", "list"],
                            description: "Action to perform: upload file, download file, or list files"
                        },
                        location: {
                            type: "string",
                            enum: ["team", "channel"],
                            description: "Location for file operations: team drive or channel files"
                        },
                        teamId: {
                            type: "string",
                            description: "Team ID (required for all actions)"
                        },
                        channelId: {
                            type: "string",
                            description: "Channel ID (required for channel file operations)"
                        },
                        fileName: {
                            type: "string",
                            description: "Name for the file (upload action)"
                        },
                        fileContent: {
                            type: "string",
                            description: "Base64 encoded file content (upload action)"
                        },
                        mimeType: {
                            type: "string",
                            description: "MIME type of the file (upload action)"
                        },
                        driveId: {
                            type: "string",
                            description: "Drive ID (required for download action)"
                        },
                        itemId: {
                            type: "string",
                            description: "File item ID (required for download action)"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of files to return (list action)",
                            default: 20
                        }
                    },
                    required: ["action", "location", "teamId"]
                }
            },
            {
                name: "manage_replies",
                description: "Reply to messages or get message replies in channels and chats",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["reply", "get_replies"],
                            description: "Action to perform: reply to message or get existing replies"
                        },
                        messageType: {
                            type: "string",
                            enum: ["channel", "chat"],
                            description: "Type of message: channel message or chat/direct message"
                        },
                        teamId: {
                            type: "string",
                            description: "Team ID (required for channel messages)"
                        },
                        channelId: {
                            type: "string",
                            description: "Channel ID (required for channel messages)"
                        },
                        chatId: {
                            type: "string",
                            description: "Chat ID (required for chat messages)"
                        },
                        messageId: {
                            type: "string",
                            description: "ID of the message to reply to or get replies from"
                        },
                        content: {
                            type: "string",
                            description: "Reply content (reply action)"
                        },
                        contentType: {
                            type: "string",
                            enum: ["text", "html"],
                            description: "Content type of the reply",
                            default: "text"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of replies to return (get_replies action)",
                            default: 20
                        }
                    },
                    required: ["action", "messageType", "messageId"]
                }
            },
            {
                name: "manage_group_chats",
                description: "Create and manage group chats, add/remove members",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["create", "list", "get_members", "add_members", "remove_member"],
                            description: "Action to perform on group chats"
                        },
                        chatId: {
                            type: "string",
                            description: "Group chat ID (required for get_members, add_members, remove_member actions)"
                        },
                        topic: {
                            type: "string",
                            description: "Topic/name for the group chat (create action)"
                        },
                        members: {
                            type: "array",
                            items: { type: "string" },
                            description: "Array of user IDs to add to the group chat (create/add_members actions)"
                        },
                        membershipId: {
                            type: "string",
                            description: "Membership ID to remove (remove_member action)"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of group chats to return (list action)",
                            default: 20
                        }
                    },
                    required: ["action"]
                }
            },
            {
                name: "manage_meetings",
                description: "Create and manage online meetings and calendar events",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["create_meeting", "list_meetings", "get_calendar", "create_event"],
                            description: "Action to perform on meetings and calendar"
                        },
                        subject: {
                            type: "string",
                            description: "Meeting/event subject (create actions)"
                        },
                        startDateTime: {
                            type: "string",
                            description: "Start date and time in ISO 8601 format (create actions)"
                        },
                        endDateTime: {
                            type: "string",
                            description: "End date and time in ISO 8601 format (create actions)"
                        },
                        attendees: {
                            type: "array",
                            items: { type: "string" },
                            description: "Array of attendee email addresses (create actions)"
                        },
                        content: {
                            type: "string",
                            description: "Meeting/event description (create actions)"
                        },
                        isRecordingEnabled: {
                            type: "boolean",
                            description: "Whether recording is enabled (create_meeting action)",
                            default: false
                        },
                        startTime: {
                            type: "string",
                            description: "Filter start time for calendar events (get_calendar action)"
                        },
                        endTime: {
                            type: "string",
                            description: "Filter end time for calendar events (get_calendar action)"
                        },
                        maxResults: {
                            type: "integer",
                            description: "Maximum number of results to return",
                            default: 20
                        }
                    },
                    required: ["action"]
                }
            },
            {
                name: "manage_presence",
                description: "Get and set user presence/status information",
                inputSchema: {
                    type: "object",
                    properties: {
                        action: {
                            type: "string",
                            enum: ["get_presence", "set_presence", "get_bulk_presence"],
                            description: "Action to perform on user presence"
                        },
                        userId: {
                            type: "string",
                            description: "User ID to get presence for (get_presence action, optional for current user)"
                        },
                        userIds: {
                            type: "array",
                            items: { type: "string" },
                            description: "Array of user IDs to get presence for (get_bulk_presence action)"
                        },
                        availability: {
                            type: "string",
                            enum: ["Available", "Busy", "DoNotDisturb", "BeRightBack", "Away"],
                            description: "Availability status to set (set_presence action)"
                        },
                        activity: {
                            type: "string",
                            enum: ["Available", "Busy", "DoNotDisturb", "BeRightBack", "Away", "InAMeeting", "InACall"],
                            description: "Activity status to set (set_presence action)"
                        },
                        expirationDuration: {
                            type: "string",
                            description: "How long to keep the status (ISO 8601 duration, e.g., 'PT1H' for 1 hour)"
                        }
                    },
                    required: ["action"]
                }
            }
        ]
    };
});
/**
 * Helper function to get emoji for reaction types
 */
function getReactionEmoji(reactionType) {
    const emojiMap = {
        'like': 'šŸ‘',
        'heart': 'ā¤ļø',
        'laugh': 'šŸ˜‚',
        'surprised': '😮',
        'sad': '😢',
        'angry': '😠'
    };
    return emojiMap[reactionType.toLowerCase()] || 'šŸ‘';
}
/**
 * Helper function to safely extract arguments with defaults
 */
function safeGetArgs(args, defaultValues) {
    if (!args || typeof args !== 'object') {
        return defaultValues;
    }
    const result = { ...defaultValues };
    for (const key in defaultValues) {
        if (args[key] !== undefined) {
            result[key] = args[key];
        }
    }
    return result;
}
/**
 * Handle tool execution requests
 */
server.setRequestHandler(CallToolRequestSchema, async (request) => {
    logger.log('Received call tool request: ' + JSON.stringify(request));
    try {
        switch (request.params.name) {
            case "teams_authenticate": {
                const args = safeGetArgs(request.params.arguments, { action: '' });
                if (!args.action) {
                    throw new Error("Action is required for authentication");
                }
                switch (args.action) {
                    case "login":
                        try {
                            // Check if already authenticated
                            const authStatus = await teamsAuth.getAuthenticationStatus();
                            if (authStatus.isAuthenticated) {
                                return {
                                    content: [{
                                            type: "text",
                                            text: `āœ… **Already authenticated with Microsoft Teams!**\n\n**User:** ${authStatus.user?.displayName || 'Unknown'}\n\nšŸŽ‰ You can now use Teams commands to manage your teams, channels, and messages.`
                                        }]
                                };
                            }
                            // Start OAuth redirect authentication
                            try {
                                const result = await teamsAuth.authenticate();
                                return {
                                    content: [{
                                            type: "text",
                                            text: `āœ… **Successfully authenticated with Microsoft Teams!**\n\n**User:** ${result.account?.name || 'Unknown'}\n\nšŸŽ‰ You can now use Teams commands to manage your teams, channels, and messages.`
                                        }]
                                };
                            }
                            catch (authError) {
                                // Handle OAuth redirect required error
                                if (authError.authUrl) {
                                    return {
                                        content: [{
                                                type: "text",
                                                text: `šŸ” **Microsoft Teams Authentication Required**\n\n` +
                                                    `🌐 **Please complete authentication:**\n` +
                                                    `1. Visit: **${authError.authUrl}**\n` +
                                                    `2. Sign in with your Microsoft account\n` +
                                                    `3. Complete the authorization process\n\n` +
                                                    `šŸ’” **Direct link:** [Click here to authenticate](${authError.authUrl})\n\n` +
                                                    `šŸ”„ **Next steps:**\n` +
                                                    `- Complete authentication in your browser\n` +
                                                    `- The system will automatically detect completion\n` +
                                                    `- Try your Teams command again after authentication\n\n` +
                                                    `āš ļø  **If you're having trouble:**\n` +
                                                    `- Make sure you're signed in to the correct Microsoft account\n` +
                                                    `- Check that your organization allows Teams access\n` +
                                                    `- Ensure you have the necessary permissions for Teams operations`
                                            }]
                                    };
                                }
                                // General authentication error
                                throw authError;
                            }
                        }
                        catch (error) {
                            return {
                                content: [{
                                        type: "text",
                                        text: `āŒ **Authentication failed:** ${error.message}\n\n` +
                                            `šŸ’” **Troubleshooting steps:**\n` +
                                            `1. **Try terminal authentication:** Run \`msteams-mcp-server --login\` from your terminal\n` +
                                            `2. **Check network connection:** Ensure you can access https://login.microsoftonline.com\n` +
                                            `3. **Verify permissions:** Make sure your Azure app has Teams permissions\n` +
                                            `4. **Reset authentication:** Try \`msteams-mcp-server --reset-auth\` then retry\n\n` +
                                            `šŸ”— **Need help?** Check the README for detailed setup instructions.`
                                    }]
                            };
                        }
                    case "logout":
                        try {
                            await teamsAuth.logout();
                            return {
                                content: [{
                                        type: "text",
                                        text: "āœ… **Successfully logged out from Microsoft Teams.**\n\nšŸ—‘ļø  All stored authentication tokens have been cleared.\n\nšŸ”„ Use the authenticate tool with action 'login' to sign in again."
                                    }]
                            };
                        }
                        catch (error) {
                            return {
                                content: [{
                                        type: "text",
                                        text: `āŒ **Logout failed:** ${error.message}`
                                    }]
                            };
                        }
                    case "status":
                        try {
                            const authStatus = await teamsAuth.getAuthenticationStatus();
                            if (authStatus.isAuthenticated) {
                                return {
                                    content: [{
                                            type: "text",
                                            text: `āœ… **Authenticated with Microsoft Teams**\n\n**User:** ${authStatus.user?.displayName || 'Unknown'}\n**Status:** Ready to use Teams commands\n\nšŸŽ‰ You can now manage your teams, channels, and messages!`
                                        }]
                                };
                            }
                            else {
                                return {
                                    content: [{
                                            type: "text",
                                            text: `āŒ **Not authenticated with Microsoft Teams**\n\n**Status:** ${authStatus.message}\n\nšŸ”‘ **Next steps:**\n- Run the authenticate tool with action 'login'\n- Or use 'msteams-mcp-server --login' from terminal`
                                        }]
                                };
                            }
                        }
                        catch (error) {
                            return {
                                content: [{
                                        type: "text",
                                        text: `āŒ **Error checking authentication status:** ${error.message}`
                                    }]
                            };
                        }
                    default:
                        throw new Error(`Unknown authentication action: ${args.action}`);
                }
            }
            case "manage_teams": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    teamId: '',
                    query: '',
                    visibility: '',
                    maxResults: 10,
                    displayName: '',
                    description: '',
                    members: [],
                    owners: []
                });
                if (!args.action) {
                    throw new Error("Action is required for team management");
                }
                switch (args.action) {
                    case "list":
                        const teams = await teamsOperations.getUserTeams(args.maxResults || 10);
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ“Š **Your Teams (${teams.length})**\n\n${teams.map(team => `**${team.displayName}** (${team.visibility})\n` +
                                        `ID: ${team.id}\n` +
                                        `Description: ${team.description || 'No description'}\n` +
                                        `Created: ${new Date(team.createdDateTime).toLocaleDateString()}\n` +
                                        `šŸ”— [Open in Teams](${team.webUrl})\n`).join('\n')}`
                                }]
                        };
                    case "search":
                        if (!args.query) {
                            throw new Error("Query is required for team search");
                        }
                        const searchResults = await teamsOperations.searchTeams({
                            query: args.query,
                            visibility: args.visibility,
                            maxResults: args.maxResults
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ” **Team Search Results for "${args.query}" (${searchResults.length})**\n\n${searchResults.map(team => `**${team.displayName}** (${team.visibility})\n` +
                                        `ID: ${team.id}\n` +
                                        `Description: ${team.description || 'No description'}\n` +
                                        `šŸ”— [Open in Teams](${team.webUrl})\n`).join('\n')}`
                                }]
                        };
                    case "create":
                        if (!args.displayName) {
                            throw new Error("Display name is required for team creation");
                        }
                        const newTeam = await teamsOperations.createTeam({
                            displayName: args.displayName,
                            description: args.description,
                            visibility: args.visibility || 'Private',
                            members: args.members,
                            owners: args.owners
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Team Created Successfully!**\n\n**Name:** ${newTeam.displayName}\n**ID:** ${newTeam.id}\n**Visibility:** ${newTeam.visibility}\n**Description:** ${newTeam.description || 'No description'}\n\nšŸ”— [Open in Teams](${newTeam.webUrl})`
                                }]
                        };
                    case "get":
                        if (!args.teamId) {
                            throw new Error("Team ID is required for getting team details");
                        }
                        const team = await teamsOperations.getTeam(args.teamId);
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ“‹ **Team Details**\n\n**Name:** ${team.displayName}\n**ID:** ${team.id}\n**Visibility:** ${team.visibility}\n**Description:** ${team.description || 'No description'}\n**Created:** ${new Date(team.createdDateTime).toLocaleDateString()}\n\nšŸ”— [Open in Teams](${team.webUrl})`
                                }]
                        };
                    case "get_members":
                        if (!args.teamId) {
                            throw new Error("Team ID is required for getting team members");
                        }
                        const members = await teamsOperations.getTeamMembers(args.teamId);
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ‘„ **Team Members (${members.length})**\n\n${members.map(member => `**${member.displayName}**\n` +
                                        `Email: ${member.email}\n` +
                                        `Roles: ${member.roles.join(', ')}\n` +
                                        `ID: ${member.id}\n`).join('\n')}`
                                }]
                        };
                    default:
                        throw new Error(`Unknown team action: ${args.action}`);
                }
            }
            case "manage_channels": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    teamId: '',
                    query: '',
                    membershipType: '',
                    maxResults: 10,
                    displayName: '',
                    description: ''
                });
                if (!args.action || !args.teamId) {
                    throw new Error("Action and teamId are required for channel management");
                }
                switch (args.action) {
                    case "list":
                        const channels = await teamsOperations.getTeamChannels(args.teamId);
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ“‘ **Team Channels (${channels.length})**\n\n${channels.map(channel => `**${channel.displayName}** (${channel.membershipType})\n` +
                                        `ID: ${channel.id}\n` +
                                        `Description: ${channel.description || 'No description'}\n` +
                                        `Created: ${new Date(channel.createdDateTime).toLocaleDateString()}\n` +
                                        `šŸ”— [Open in Teams](${channel.webUrl})\n`).join('\n')}`
                                }]
                        };
                    case "search":
                        if (!args.query) {
                            throw new Error("Query is required for channel search");
                        }
                        const channelResults = await teamsOperations.searchChannels({
                            teamId: args.teamId,
                            query: args.query,
                            membershipType: args.membershipType,
                            maxResults: args.maxResults
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ” **Channel Search Results for "${args.query}" (${channelResults.length})**\n\n${channelResults.map(channel => `**${channel.displayName}** (${channel.membershipType})\n` +
                                        `ID: ${channel.id}\n` +
                                        `Description: ${channel.description || 'No description'}\n` +
                                        `šŸ”— [Open in Teams](${channel.webUrl})\n`).join('\n')}`
                                }]
                        };
                    case "create":
                        if (!args.displayName) {
                            throw new Error("Display name is required for channel creation");
                        }
                        const newChannel = await teamsOperations.createChannel(args.teamId, {
                            displayName: args.displayName,
                            description: args.description,
                            membershipType: args.membershipType || 'standard'
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Channel Created Successfully!**\n\n**Name:** ${newChannel.displayName}\n**ID:** ${newChannel.id}\n**Type:** ${newChannel.membershipType}\n**Description:** ${newChannel.description || 'No description'}\n\nšŸ”— [Open in Teams](${newChannel.webUrl})`
                                }]
                        };
                    default:
                        throw new Error(`Unknown channel action: ${args.action}`);
                }
            }
            case "send_message": {
                const args = safeGetArgs(request.params.arguments, {
                    teamId: '',
                    channelId: '',
                    content: '',
                    contentType: 'text',
                    mentions: []
                });
                if (!args.teamId || !args.channelId || !args.content) {
                    throw new Error("teamId, channelId, and content are required for sending messages");
                }
                const message = await teamsOperations.sendChannelMessage(args.teamId, args.channelId, {
                    content: args.content,
                    contentType: args.contentType,
                    mentions: args.mentions
                });
                return {
                    content: [{
                            type: "text",
                            text: `āœ… **Message Sent Successfully!**\n\n**Message ID:** ${message.id}\n**Sent at:** ${new Date(message.createdDateTime).toLocaleString()}\n**Content:** ${message.body.content.substring(0, 100)}${message.body.content.length > 100 ? '...' : ''}`
                        }]
                };
            }
            case "manage_messages": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    teamId: '',
                    channelId: '',
                    query: '',
                    fromDate: '',
                    toDate: '',
                    maxResults: 20
                });
                if (!args.action || !args.teamId || !args.channelId) {
                    throw new Error("Action, teamId, and channelId are required for message management");
                }
                switch (args.action) {
                    case "get":
                        const messages = await teamsOperations.getChannelMessages(args.teamId, args.channelId, {
                            maxResults: args.maxResults
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ’¬ **Channel Messages (${messages.length})**\n\n${messages.map(msg => `**${msg.from?.user?.displayName || 'Unknown'}** - ${new Date(msg.createdDateTime).toLocaleString()}\n` +
                                        `${msg.body.content.substring(0, 200)}${msg.body.content.length > 200 ? '...' : ''}\n` +
                                        `Message ID: ${msg.id}\n`).join('\n')}`
                                }]
                        };
                    case "search":
                        if (!args.query) {
                            throw new Error("Query is required for message search");
                        }
                        const searchMessages = await teamsOperations.searchChannelMessages({
                            teamId: args.teamId,
                            channelId: args.channelId,
                            query: args.query,
                            fromDate: args.fromDate,
                            toDate: args.toDate,
                            maxResults: args.maxResults
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ” **Message Search Results for "${args.query}" (${searchMessages.length})**\n\n${searchMessages.map(msg => `**${msg.from?.user?.displayName || 'Unknown'}** - ${new Date(msg.createdDateTime).toLocaleString()}\n` +
                                        `${msg.body.content.substring(0, 200)}${msg.body.content.length > 200 ? '...' : ''}\n` +
                                        `Message ID: ${msg.id}\n`).join('\n')}`
                                }]
                        };
                    default:
                        throw new Error(`Unknown message action: ${args.action}`);
                }
            }
            case "manage_members": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    teamId: '',
                    userId: '',
                    memberId: '',
                    roles: ['member']
                });
                if (!args.action || !args.teamId) {
                    throw new Error("Action and teamId are required for member management");
                }
                switch (args.action) {
                    case "add":
                        if (!args.userId) {
                            throw new Error("userId is required for adding members");
                        }
                        await teamsOperations.addTeamMember(args.teamId, args.userId, args.roles);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Member Added Successfully!**\n\n**User ID:** ${args.userId}\n**Roles:** ${args.roles.join(', ')}\n**Team ID:** ${args.teamId}`
                                }]
                        };
                    case "remove":
                        if (!args.memberId) {
                            throw new Error("memberId is required for removing members");
                        }
                        await teamsOperations.removeTeamMember(args.teamId, args.memberId);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Member Removed Successfully!**\n\n**Member ID:** ${args.memberId}\n**Team ID:** ${args.teamId}`
                                }]
                        };
                    default:
                        throw new Error(`Unknown member action: ${args.action}`);
                }
            }
            case "search_users": {
                const args = safeGetArgs(request.params.arguments, {
                    query: '',
                    maxResults: 10
                });
                if (!args.query) {
                    throw new Error("Query is required for user search");
                }
                const users = await teamsOperations.searchUsers(args.query, args.maxResults);
                return {
                    content: [{
                            type: "text",
                            text: `šŸ‘¤ **User Search Results for "${args.query}" (${users.length})**\n\n${users.map(user => `**${user.displayName}**\n` +
                                `Email: ${user.email}\n` +
                                `ID: ${user.id}\n`).join('\n')}`
                        }]
                };
            }
            case "send_direct_message": {
                const args = safeGetArgs(request.params.arguments, {
                    userId: '',
                    displayName: '',
                    content: '',
                    contentType: 'text',
                    mentions: []
                });
                if (!args.content) {
                    throw new Error("Content is required for sending direct messages");
                }
                // Get user ID from display name if not provided
                let userId = args.userId;
                if (!userId && args.displayName) {
                    const users = await teamsOperations.searchUsers(args.displayName, 1);
                    if (users.length > 0) {
                        userId = users[0].id;
                    }
                    else {
                        throw new Error(`Could not find user with display name: ${args.displayName}`);
                    }
                }
                if (!userId) {
                    throw new Error("Either userId or displayName is required for sending direct messages");
                }
                const message = await teamsOperations.sendDirectMessage(userId, {
                    content: args.content,
                    contentType: args.contentType,
                    mentions: args.mentions
                });
                return {
                    content: [{
                            type: "text",
                            text: `āœ… **Direct Message Sent Successfully!**\n\n**Message ID:** ${message.id}\n**Sent at:** ${new Date(message.createdDateTime).toLocaleString()}\n**Content:** ${message.body.content.substring(0, 100)}${message.body.content.length > 100 ? '...' : ''}`
                        }]
                };
            }
            case "get_direct_messages": {
                const args = safeGetArgs(request.params.arguments, {
                    userId: '',
                    displayName: '',
                    maxResults: 20
                });
                // Get user ID from display name if not provided
                let userId = args.userId;
                if (!userId && args.displayName) {
                    const users = await teamsOperations.searchUsers(args.displayName, 1);
                    if (users.length > 0) {
                        userId = users[0].id;
                    }
                    else {
                        throw new Error(`Could not find user with display name: ${args.displayName}`);
                    }
                }
                if (!userId) {
                    throw new Error("Either userId or displayName is required for getting direct messages");
                }
                const messages = await teamsOperations.getDirectMessages(userId, {
                    maxResults: args.maxResults
                });
                return {
                    content: [{
                            type: "text",
                            text: `šŸ’¬ **Direct Messages (${messages.length})**\n\n${messages.map(msg => `**${msg.from?.user?.displayName || 'Unknown'}** - ${new Date(msg.createdDateTime).toLocaleString()}\n` +
                                `${msg.body.content.substring(0, 200)}${msg.body.content.length > 200 ? '...' : ''}\n` +
                                `Message ID: ${msg.id}\n`).join('\n')}`
                        }]
                };
            }
            case "manage_reactions": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    messageType: '',
                    teamId: '',
                    channelId: '',
                    chatId: '',
                    messageId: '',
                    reactionType: ''
                });
                if (!args.action || !args.messageType || !args.messageId || !args.reactionType) {
                    throw new Error("Action, messageType, messageId, and reactionType are required");
                }
                const validReactions = ['like', 'heart', 'laugh', 'surprised', 'sad', 'angry'];
                if (!validReactions.includes(args.reactionType)) {
                    throw new Error(`Invalid reaction type. Must be one of: ${validReactions.join(', ')}`);
                }
                if (args.messageType === 'channel') {
                    if (!args.teamId || !args.channelId) {
                        throw new Error("teamId and channelId are required for channel message reactions");
                    }
                    if (args.action === 'add') {
                        await teamsOperations.addMessageReaction(args.teamId, args.channelId, args.messageId, args.reactionType);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Reaction Added!**\n\n**Reaction:** ${args.reactionType} ${getReactionEmoji(args.reactionType)}\n**Message ID:** ${args.messageId}\n**Channel:** ${args.channelId}`
                                }]
                        };
                    }
                    else {
                        await teamsOperations.removeMessageReaction(args.teamId, args.channelId, args.messageId, args.reactionType);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Reaction Removed!**\n\n**Reaction:** ${args.reactionType} ${getReactionEmoji(args.reactionType)}\n**Message ID:** ${args.messageId}\n**Channel:** ${args.channelId}`
                                }]
                        };
                    }
                }
                else if (args.messageType === 'chat') {
                    if (!args.chatId) {
                        throw new Error("chatId is required for chat message reactions");
                    }
                    if (args.action === 'add') {
                        await teamsOperations.addChatMessageReaction(args.chatId, args.messageId, args.reactionType);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Reaction Added!**\n\n**Reaction:** ${args.reactionType} ${getReactionEmoji(args.reactionType)}\n**Message ID:** ${args.messageId}\n**Chat:** ${args.chatId}`
                                }]
                        };
                    }
                    else {
                        await teamsOperations.removeChatMessageReaction(args.chatId, args.messageId, args.reactionType);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Reaction Removed!**\n\n**Reaction:** ${args.reactionType} ${getReactionEmoji(args.reactionType)}\n**Message ID:** ${args.messageId}\n**Chat:** ${args.chatId}`
                                }]
                        };
                    }
                }
                else {
                    throw new Error("messageType must be 'channel' or 'chat'");
                }
            }
            case "manage_files": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    location: '',
                    teamId: '',
                    channelId: '',
                    fileName: '',
                    fileContent: '',
                    mimeType: 'application/octet-stream',
                    driveId: '',
                    itemId: '',
                    maxResults: 20
                });
                if (!args.action || !args.location || !args.teamId) {
                    throw new Error("Action, location, and teamId are required");
                }
                switch (args.action) {
                    case "upload":
                        if (!args.fileName || !args.fileContent) {
                            throw new Error("fileName and fileContent are required for upload");
                        }
                        try {
                            // Decode base64 file content
                            const fileBuffer = Buffer.from(args.fileContent, 'base64');
                            let result;
                            if (args.location === 'team') {
                                result = await teamsOperations.uploadFileToTeam(args.teamId, {
                                    fileName: args.fileName,
                                    fileContent: fileBuffer,
                                    mimeType: args.mimeType
                                });
                            }
                            else if (args.location === 'channel') {
                                if (!args.channelId) {
                                    throw new Error("channelId is required for channel file upload");
                                }
                                result = await teamsOperations.uploadFileToChannel(args.teamId, args.channelId, {
                                    fileName: args.fileName,
                                    fileContent: fileBuffer,
                                    mimeType: args.mimeType
                                });
                            }
                            else {
                                throw new Error("location must be 'team' or 'channel'");
                            }
                            return {
                                content: [{
                                        type: "text",
                                        text: `āœ… **File Uploaded Successfully!**\n\n**Name:** ${result.name}\n**Size:** ${(result.size / 1024).toFixed(2)} KB\n**Location:** ${args.location === 'team' ? 'Team Drive' : 'Channel Files'}\n**Created:** ${new Date(result.createdDateTime).toLocaleString()}\n\nšŸ”— [Open in Teams](${result.webUrl})`
                                    }]
                            };
                        }
                        catch (error) {
                            throw new Error(`File upload failed: ${error.message}`);
                        }
                    case "download":
                        if (!args.driveId || !args.itemId) {
                            throw new Error("driveId and itemId are required for download");
                        }
                        try {
                            const downloadResult = await teamsOperations.downloadFile(args.driveId, args.itemId);
                            const base64Content = downloadResult.content.toString('base64');
                            return {
                                content: [{
                                        type: "text",
                                        text: `āœ… **File Downloaded Successfully!**\n\n**Name:** ${downloadResult.fileName}\n**Size:** ${(downloadResult.content.length / 1024).toFixed(2)} KB\n**MIME Type:** ${downloadResult.mimeType}\n\n**Base64 Content:**\n\`\`\`\n${base64Content.substring(0, 200)}${base64Content.length > 200 ? '...[truncated]' : ''}\n\`\`\``
                                    }]
                            };
                        }
                        catch (error) {
                            throw new Error(`File download failed: ${error.message}`);
                        }
                    case "list":
                        try {
                            let files;
                            if (args.location === 'team') {
                                files = await teamsOperations.getTeamFiles(args.teamId, args.maxResults);
                            }
                            else if (args.location === 'channel') {
                                if (!args.channelId) {
                                    throw new Error("channelId is required for channel file listing");
                                }
                                files = await teamsOperations.getChannelFiles(args.teamId, args.channelId, args.maxResults);
                            }
                            else {
                                throw new Error("location must be 'team' or 'channel'");
                            }
                            if (files.length === 0) {
                                return {
                                    content: [{
                                            type: "text",
                                            text: `šŸ“ **No files found in ${args.location === 'team' ? 'team drive' : 'channel files'}**`
                                        }]
                                };
                            }
                            const fileList = files.map(file => {
                                const size = file.size ? `${(file.size / 1024).toFixed(2)} KB` : 'Unknown size';
                                const type = file.folder ? 'šŸ“ Folder' : 'šŸ“„ File';
                                return `${type} **${file.name}**\n` +
                                    `Size: ${size}\n` +
                                    `Created: ${new Date(file.createdDateTime).toLocaleDateString()}\n` +
                                    `ID: ${file.id}\n` +
                                    `šŸ”— [Open in Teams](${file.webUrl})\n`;
                            }).join('\n');
                            return {
                                content: [{
                                        type: "text",
                                        text: `šŸ“ **${args.location === 'team' ? 'Team' : 'Channel'} Files (${files.length})**\n\n${fileList}`
                                    }]
                            };
                        }
                        catch (error) {
                            throw new Error(`File listing failed: ${error.message}`);
                        }
                    default:
                        throw new Error(`Unknown file action: ${args.action}`);
                }
            }
            case "manage_replies": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    messageType: '',
                    teamId: '',
                    channelId: '',
                    chatId: '',
                    messageId: '',
                    content: '',
                    contentType: 'text',
                    maxResults: 20
                });
                if (!args.action || !args.messageType || !args.messageId) {
                    throw new Error("Action, messageType, and messageId are required");
                }
                switch (args.action) {
                    case "reply":
                        if (!args.content) {
                            throw new Error("content is required for reply action");
                        }
                        if (args.messageType === 'channel') {
                            if (!args.teamId || !args.channelId) {
                                throw new Error("teamId and channelId are required for channel message replies");
                            }
                            const reply = await teamsOperations.replyToChannelMessage(args.teamId, args.channelId, args.messageId, args.content, args.contentType);
                            return {
                                content: [{
                                        type: "text",
                                        text: `āœ… **Reply Posted Successfully!**\n\n**Reply ID:** ${reply.id}\n**Original Message:** ${args.messageId}\n**Posted at:** ${new Date(reply.createdDateTime).toLocaleString()}\n**Content:** ${reply.body.content.substring(0, 100)}${reply.body.content.length > 100 ? '...' : ''}`
                                    }]
                            };
                        }
                        else if (args.messageType === 'chat') {
                            if (!args.chatId) {
                                throw new Error("chatId is required for chat message replies");
                            }
                            const reply = await teamsOperations.replyToChatMessage(args.chatId, args.messageId, args.content, args.contentType);
                            return {
                                content: [{
                                        type: "text",
                                        text: `āœ… **Reply Posted Successfully!**\n\n**Reply ID:** ${reply.id}\n**Original Message:** ${args.messageId}\n**Posted at:** ${new Date(reply.createdDateTime).toLocaleString()}\n**Content:** ${reply.body.content.substring(0, 100)}${reply.body.content.length > 100 ? '...' : ''}`
                                    }]
                            };
                        }
                        else {
                            throw new Error("messageType must be 'channel' or 'chat'");
                        }
                    case "get_replies":
                        if (args.messageType === 'channel') {
                            if (!args.teamId || !args.channelId) {
                                throw new Error("teamId and channelId are required for channel message replies");
                            }
                            const replies = await teamsOperations.getChannelMessageReplies(args.teamId, args.channelId, args.messageId, args.maxResults);
                            if (replies.length === 0) {
                                return {
                                    content: [{
                                            type: "text",
                                            text: `šŸ’¬ **No replies found for message ${args.messageId}**`
                                        }]
                                };
                            }
                            const replyList = replies.map(reply => `**${reply.from?.user?.displayName || 'Unknown'}** - ${new Date(reply.createdDateTime).toLocaleString()}\n` +
                                `${reply.body.content.substring(0, 200)}${reply.body.content.length > 200 ? '...' : ''}\n` +
                                `Reply ID: ${reply.id}\n`).join('\n');
                            return {
                                content: [{
                                        type: "text",
                                        text: `šŸ’¬ **Message Replies (${replies.length})**\n\n${replyList}`
                                    }]
                            };
                        }
                        else if (args.messageType === 'chat') {
                            if (!args.chatId) {
                                throw new Error("chatId is required for chat message replies");
                            }
                            const replies = await teamsOperations.getChatMessageReplies(args.chatId, args.messageId, args.maxResults);
                            if (replies.length === 0) {
                                return {
                                    content: [{
                                            type: "text",
                                            text: `šŸ’¬ **No replies found for message ${args.messageId}**`
                                        }]
                                };
                            }
                            const replyList = replies.map(reply => `**${reply.from?.user?.displayName || 'Unknown'}** - ${new Date(reply.createdDateTime).toLocaleString()}\n` +
                                `${reply.body.content.substring(0, 200)}${reply.body.content.length > 200 ? '...' : ''}\n` +
                                `Reply ID: ${reply.id}\n`).join('\n');
                            return {
                                content: [{
                                        type: "text",
                                        text: `šŸ’¬ **Message Replies (${replies.length})**\n\n${replyList}`
                                    }]
                            };
                        }
                        else {
                            throw new Error("messageType must be 'channel' or 'chat'");
                        }
                    default:
                        throw new Error(`Unknown reply action: ${args.action}`);
                }
            }
            case "manage_group_chats": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    chatId: '',
                    topic: '',
                    members: [],
                    membershipId: '',
                    maxResults: 20
                });
                if (!args.action) {
                    throw new Error("Action is required");
                }
                switch (args.action) {
                    case "create":
                        if (!args.members || args.members.length === 0) {
                            throw new Error("members array is required and must not be empty for group chat creation");
                        }
                        const groupChat = await teamsOperations.createGroupChat({
                            topic: args.topic,
                            members: args.members
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Group Chat Created Successfully!**\n\n**Chat ID:** ${groupChat.id}\n**Topic:** ${groupChat.topic || 'No topic set'}\n**Members:** ${args.members.length}\n**Created:** ${new Date(groupChat.createdDateTime).toLocaleString()}\n\nšŸ’¬ The group chat is now ready for messaging!`
                                }]
                        };
                    case "list":
                        const chats = await teamsOperations.getGroupChats(args.maxResults);
                        if (chats.length === 0) {
                            return {
                                content: [{
                                        type: "text",
                                        text: `šŸ‘„ **No group chats found**\n\nYou're not a member of any group chats yet.`
                                    }]
                            };
                        }
                        const chatList = chats.map(chat => `**${chat.topic || 'Untitled Chat'}**\n` +
                            `ID: ${chat.id}\n` +
                            `Created: ${new Date(chat.createdDateTime).toLocaleDateString()}\n` +
                            `Last Updated: ${new Date(chat.lastUpdatedDateTime).toLocaleDateString()}\n`).join('\n');
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ‘„ **Your Group Chats (${chats.length})**\n\n${chatList}`
                                }]
                        };
                    case "get_members":
                        if (!args.chatId) {
                            throw new Error("chatId is required for getting group chat members");
                        }
                        const members = await teamsOperations.getGroupChatMembers(args.chatId);
                        const memberList = members.map(member => `**${member.displayName}**\n` +
                            `Email: ${member.email}\n` +
                            `ID: ${member.id}\n` +
                            `Roles: ${member.roles.join(', ')}\n`).join('\n');
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ‘„ **Group Chat Members (${members.length})**\n\n${memberList}`
                                }]
                        };
                    case "add_members":
                        if (!args.chatId) {
                            throw new Error("chatId is required for adding members");
                        }
                        if (!args.members || args.members.length === 0) {
                            throw new Error("members array is required for adding members");
                        }
                        await teamsOperations.addGroupChatMembers(args.chatId, args.members);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Members Added Successfully!**\n\n**Added ${args.members.length} member(s) to chat ${args.chatId}**\n\nThe new members can now participate in the group chat.`
                                }]
                        };
                    case "remove_member":
                        if (!args.chatId || !args.membershipId) {
                            throw new Error("chatId and membershipId are required for removing members");
                        }
                        await teamsOperations.removeGroupChatMember(args.chatId, args.membershipId);
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Member Removed Successfully!**\n\n**Removed member ${args.membershipId} from chat ${args.chatId}**`
                                }]
                        };
                    default:
                        throw new Error(`Unknown group chat action: ${args.action}`);
                }
            }
            case "manage_meetings": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    subject: '',
                    startDateTime: '',
                    endDateTime: '',
                    attendees: [],
                    content: '',
                    isRecordingEnabled: false,
                    startTime: '',
                    endTime: '',
                    maxResults: 20
                });
                if (!args.action) {
                    throw new Error("Action is required");
                }
                switch (args.action) {
                    case "create_meeting":
                        if (!args.subject || !args.startDateTime || !args.endDateTime) {
                            throw new Error("subject, startDateTime, and endDateTime are required for creating meetings");
                        }
                        const meeting = await teamsOperations.createOnlineMeeting({
                            subject: args.subject,
                            startDateTime: args.startDateTime,
                            endDateTime: args.endDateTime,
                            attendees: args.attendees,
                            content: args.content,
                            isRecordingEnabled: args.isRecordingEnabled
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Online Meeting Created Successfully!**\n\n**Subject:** ${meeting.subject}\n**Meeting ID:** ${meeting.id}\n**Start:** ${new Date(meeting.startDateTime).toLocaleString()}\n**End:** ${new Date(meeting.endDateTime).toLocaleString()}\n**Recording:** ${meeting.isRecordingEnabled ? 'Enabled' : 'Disabled'}\n\nšŸ”— **Join URL:** ${meeting.joinWebUrl}\n\nšŸ“… Share this link with attendees to join the meeting!`
                                }]
                        };
                    case "list_meetings":
                        const meetings = await teamsOperations.getOnlineMeetings(args.maxResults);
                        if (meetings.length === 0) {
                            return {
                                content: [{
                                        type: "text",
                                        text: `šŸ“… **No online meetings found**\n\nYou don't have any online meetings scheduled.`
                                    }]
                            };
                        }
                        const meetingList = meetings.map(meeting => `**${meeting.subject}**\n` +
                            `Start: ${new Date(meeting.startDateTime).toLocaleString()}\n` +
                            `End: ${new Date(meeting.endDateTime).toLocaleString()}\n` +
                            `Join: ${meeting.joinWebUrl}\n` +
                            `ID: ${meeting.id}\n`).join('\n');
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ“… **Your Online Meetings (${meetings.length})**\n\n${meetingList}`
                                }]
                        };
                    case "get_calendar":
                        const events = await teamsOperations.getCalendarEvents(args.startTime, args.endTime, args.maxResults);
                        if (events.length === 0) {
                            return {
                                content: [{
                                        type: "text",
                                        text: `šŸ“… **No calendar events found**\n\nNo events found for the specified time range.`
                                    }]
                            };
                        }
                        const eventList = events.map(event => {
                            const start = new Date(event.start.dateTime).toLocaleString();
                            const end = new Date(event.end.dateTime).toLocaleString();
                            const location = event.location?.displayName || 'No location';
                            const organizer = event.organizer.emailAddress.name;
                            const isOnline = event.isOnlineMeeting ? '🌐 Online Meeting' : 'šŸ“ In-person';
                            const joinUrl = event.onlineMeeting?.joinUrl ? `\nJoin: ${event.onlineMeeting.joinUrl}` : '';
                            return `**${event.subject}** ${isOnline}\n` +
                                `Organizer: ${organizer}\n` +
                                `Start: ${start}\n` +
                                `End: ${end}\n` +
                                `Location: ${location}${joinUrl}\n`;
                        }).join('\n');
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ“… **Calendar Events (${events.length})**\n\n${eventList}`
                                }]
                        };
                    default:
                        throw new Error(`Unknown meeting action: ${args.action}`);
                }
            }
            case "manage_presence": {
                const args = safeGetArgs(request.params.arguments, {
                    action: '',
                    userId: '',
                    userIds: [],
                    availability: '',
                    activity: '',
                    expirationDuration: ''
                });
                if (!args.action) {
                    throw new Error("Action is required");
                }
                switch (args.action) {
                    case "get_presence":
                        const presence = await teamsOperations.getUserPresence(args.userId);
                        const availabilityEmoji = {
                            'Available': '🟢',
                            'AvailableIdle': '🟔',
                            'Away': '🟔',
                            'BeRightBack': '🟔',
                            'Busy': 'šŸ”“',
                            'BusyIdle': 'šŸ”“',
                            'DoNotDisturb': 'šŸ”“',
                            'Offline': '⚫',
                            'PresenceUnknown': 'ā“'
                        };
                        const emoji = availabilityEmoji[presence.availability] || 'ā“';
                        const statusMsg = presence.statusMessage?.message?.content || 'No status message';
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ‘¤ **User Presence**\n\n**Status:** ${emoji} ${presence.availability}\n**Activity:** ${presence.activity}\n**Status Message:** ${statusMsg}\n**User ID:** ${presence.id}`
                                }]
                        };
                    case "set_presence":
                        if (!args.availability || !args.activity) {
                            throw new Error("availability and activity are required for setting presence");
                        }
                        await teamsOperations.setUserPresence({
                            availability: args.availability,
                            activity: args.activity,
                            expirationDuration: args.expirationDuration
                        });
                        return {
                            content: [{
                                    type: "text",
                                    text: `āœ… **Presence Updated Successfully!**\n\n**Availability:** ${args.availability}\n**Activity:** ${args.activity}\n**Duration:** ${args.expirationDuration || 'PT1H (1 hour default)'}\n\nYour status has been updated and will be visible to your colleagues.`
                                }]
                        };
                    case "get_bulk_presence":
                        if (!args.userIds || args.userIds.length === 0) {
                            throw new Error("userIds array is required for bulk presence lookup");
                        }
                        const bulkPresence = await teamsOperations.getBulkPresence(args.userIds);
                        const presenceList = bulkPresence.map(p => {
                            const emoji = availabilityEmoji[p.availability] || 'ā“';
                            const statusMsg = p.statusMessage?.message?.content || 'No status';
                            return `**${p.id}**\n${emoji} ${p.availability} - ${p.activity}\nStatus: ${statusMsg}\n`;
                        }).join('\n');
                        return {
                            content: [{
                                    type: "text",
                                    text: `šŸ‘„ **Bulk User Presence (${bulkPresence.length})**\n\n${presenceList}`
                                }]
                        };
                    default:
                        throw new Error(`Unknown presence action: ${args.action}`);
                }
            }
            default:
                throw new Error(`Unknown tool: ${request.params.name}`);
        }
    }
    catch (error) {
        logger.error('Error executing tool:', error);
        return {
            content: [{
                    type: "text",
                    text: `āŒ **Error:** ${error.message}\n\nPlease check your authentication status and try again. If the error persists, check the log file for more details.`
                }]
        };
    }
});
async function main() {
    try {
        teamsConfig = parseArgs();
        logger.log('Parsed configuration: ' + JSON.stringify(teamsConfig));
        // Set environment variables from command line arguments if provided
        if (teamsConfig.clientId) {
            process.env.TEAMS_CLIENT_ID = teamsConfig.clientId;
            logger.log(`Set TEAMS_CLIENT_ID from command line: ${teamsConfig.clientId}`);
        }
        if (teamsConfig.tenantId) {
            process.env.TEAMS_TENANT_ID = teamsConfig.tenantId;
            logger.log(`Set TEAMS_TENANT_ID from command line: ${teamsConfig.tenantId}`);
        }
        if (teamsConfig.clientSecret) {
            process.env.TEAMS_CLIENT_SECRET = teamsConfig.clientSecret;
            logger.log(`Set TEAMS_CLIENT_SECRET from command line: [REDACTED]`);
        }
        if (teamsConfig.redirectUri) {
            process.env.TEAMS_REDIRECT_URI = teamsConfig.redirectUri;
            logger.log(`Set TEAMS_REDIRECT_URI from command line: ${teamsConfig.redirectUri}`);
        }
        if (teamsConfig.userId) {
            process.env.USER_ID = teamsConfig.userId;
            logger.log(`Set USER_ID from command line: ${teamsConfig.userId}`);
        }
        // Handle CLI commands
        if (teamsConfig.login) {
            console.log('šŸ” Starting Microsoft Teams authentication...');
            logger.log('About to call teamsAuth.authenticate()');
            try {
                logger.log('Calling teamsAuth.authenticate()');
                await teamsAuth.authenticate();
                const authStatus = await teamsAuth.getAuthenticationStatus();
                console.log(`āœ… Successfully authenticated as: ${authStatus.user?.displayName || 'Unknown user'}`);
                console.log('You can now start the MCP server with: msteams-mcp-server');
                process.exit(0);
            }
            catch (error) {
                console.error(`āŒ Authentication failed: ${error.message}`);
                process.exit(1);
            }
        }
        if (teamsConfig.logout) {
            console.log('šŸ” Logging out from Microsoft Teams...');
            try {
                await teamsAuth.logout();
                console.log('āœ… Successfully logged out');
                process.exit(0);
            }
            catch (error) {
                console.error(`āŒ Logout failed: ${error.message}`);
                process.exit(1);
            }
        }
        if (teamsConfig.verifyLogin) {
            console.log('šŸ” Checking authentication status...');
            try {
                const authStatus = await teamsAuth.getAuthenticationStatus();
                if (authStatus.isAuthenticated) {
                    console.log(`āœ… Authenticated as: ${authStatus.user?.displayName || 'Unknown user'}`);
                    process.exit(0);
                }
                else {
                    console.log('āŒ Not authenticated. Run with --login to authenticate.');
                    process.exit(1);
                }
            }
            catch (error) {
                console.error(`āŒ Error checking authentication: ${error.message}`);
                process.exit(1);
            }
        }
        if (teamsConfig.resetAuth) {
            console.log('šŸ” Resetting authentication...');
            try {
                await teamsAuth.logout();
                console.log('āœ… Authentication reset successfully');
                process.exit(0);
            }
            catch (error) {
                console.error(`āŒ Reset failed: ${error.message}`);
                process.exit(1);
            }
        }
        // Start MCP server
        const transport = new StdioServerTransport();
        await server.connect(transport);
        logger.log('Microsoft Teams MCP server connected via stdio transport');
    }
    catch (error) {
        logger.error('Fatal error in main:', error);
        console.error('Fatal error:', error.message);
        process.exit(1);
    }
}
// Handle graceful shutdown
process.on('SIGINT', async () => {
    logger.log('Received SIGINT, shutting down gracefully...');
    process.exit(0);
});
process.on('SIGTERM', async () => {
    logger.log('Received SIGTERM, shutting down gracefully...');
    process.exit(0);
});
// Start the server
main().catch((error) => {
    logger.error('Unhandled error in main:', error);
    console.error('Unhandled error:', error);
    process.exit(1);
});