UNPKG

outlook-mcp

Version:

Comprehensive MCP server for Claude to access Microsoft Outlook and Teams via Microsoft Graph API - including Email, Calendar, Contacts, Tasks, Teams, Chats, and Online Meetings

154 lines (136 loc) 4.21 kB
#!/usr/bin/env node /** * Outlook MCP Server - Main entry point * * A Model Context Protocol server that provides access to * Microsoft Outlook through the Microsoft Graph API. */ const { Server } = require("@modelcontextprotocol/sdk/server/index.js"); const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js"); const config = require('./config'); // Import module tools const { authTools } = require('./auth'); const { calendarTools } = require('./calendar'); const { emailTools } = require('./email'); const { folderTools } = require('./folder'); const { rulesTools } = require('./rules'); const { contactsTools } = require('./contacts'); const { tasksTools } = require('./tasks'); const { teamsTools } = require('./teams'); // Log startup information console.error(`STARTING ${config.SERVER_NAME.toUpperCase()} MCP SERVER`); console.error(`Test mode is ${config.USE_TEST_MODE ? 'enabled' : 'disabled'}`); // Combine all tools const TOOLS = [ ...authTools, ...calendarTools, ...emailTools, ...folderTools, ...rulesTools, ...contactsTools, ...tasksTools, ...teamsTools ]; // Create server with tools capabilities const server = new Server( { name: config.SERVER_NAME, version: config.SERVER_VERSION }, { capabilities: { tools: TOOLS.reduce((acc, tool) => { acc[tool.name] = {}; return acc; }, {}) } } ); // Handle all requests server.fallbackRequestHandler = async (request) => { try { const { method, params, id } = request; console.error(`REQUEST: ${method} [${id}]`); // Initialize handler if (method === "initialize") { console.error(`INITIALIZE REQUEST: ID [${id}]`); return { protocolVersion: "2024-11-05", capabilities: { tools: TOOLS.reduce((acc, tool) => { acc[tool.name] = {}; return acc; }, {}) }, serverInfo: { name: config.SERVER_NAME, version: config.SERVER_VERSION } }; } // Tools list handler if (method === "tools/list") { console.error(`TOOLS LIST REQUEST: ID [${id}]`); console.error(`TOOLS COUNT: ${TOOLS.length}`); console.error(`TOOLS NAMES: ${TOOLS.map(t => t.name).join(', ')}`); return { tools: TOOLS.map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema })) }; } // Required empty responses for other capabilities if (method === "resources/list") return { resources: [] }; if (method === "prompts/list") return { prompts: [] }; // Tool call handler if (method === "tools/call") { try { const { name, arguments: args = {} } = params || {}; console.error(`TOOL CALL: ${name}`); // Find the tool handler const tool = TOOLS.find(t => t.name === name); if (tool && tool.handler) { return await tool.handler(args); } // Tool not found return { error: { code: -32601, message: `Tool not found: ${name}` } }; } catch (error) { console.error(`Error in tools/call:`, error); return { error: { code: -32603, message: `Error processing tool call: ${error.message}` } }; } } // For any other method, return method not found return { error: { code: -32601, message: `Method not found: ${method}` } }; } catch (error) { console.error(`Error in fallbackRequestHandler:`, error); return { error: { code: -32603, message: `Error processing request: ${error.message}` } }; } }; // Make the script executable process.on('SIGTERM', () => { console.error('SIGTERM received but staying alive'); }); // Start the server const transport = new StdioServerTransport(); server.connect(transport) .then(() => console.error(`${config.SERVER_NAME} connected and listening`)) .catch(error => { console.error(`Connection error: ${error.message}`); process.exit(1); });