Skip to main content
Glama
index.ts6.18 kB
#!/usr/bin/env node import { promises as fs } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; import { DeviceCodeCredential } from "@azure/identity"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { GraphService } from "./services/graph.js"; import { registerAuthTools } from "./tools/auth.js"; import { registerChatTools } from "./tools/chats.js"; import { registerSearchTools } from "./tools/search.js"; import { registerTeamsTools } from "./tools/teams.js"; import { registerUsersTools } from "./tools/users.js"; const CLIENT_ID = "14d82eec-204b-4c2f-b7e8-296a70dab67e"; const TOKEN_PATH = join(homedir(), ".msgraph-mcp-auth.json"); // Authentication functions async function authenticate() { console.log("🔐 Microsoft Graph Authentication for MCP Server"); console.log("=".repeat(50)); try { const credential = new DeviceCodeCredential({ clientId: CLIENT_ID, tenantId: "common", userPromptCallback: (info) => { console.log("\n📱 Please complete authentication:"); console.log(`🌐 Visit: ${info.verificationUri}`); console.log(`🔑 Enter code: ${info.userCode}`); console.log("\n⏳ Waiting for you to complete authentication..."); }, }); // Get the actual token const token = await credential.getToken([ "User.Read", "User.ReadBasic.All", "Team.ReadBasic.All", "Channel.ReadBasic.All", "ChannelMessage.Read.All", "ChannelMessage.Send", "TeamMember.Read.All", "Chat.ReadBasic", "Chat.ReadWrite", ]); if (token) { // Save authentication info with the actual token const authInfo = { clientId: CLIENT_ID, authenticated: true, timestamp: new Date().toISOString(), expiresAt: token.expiresOnTimestamp ? new Date(token.expiresOnTimestamp).toISOString() : undefined, token: token.token, // Save the actual access token }; await fs.writeFile(TOKEN_PATH, JSON.stringify(authInfo, null, 2)); console.log("\n✅ Authentication successful!"); console.log(`💾 Credentials saved to: ${TOKEN_PATH}`); console.log("\n🚀 You can now use the MCP server in Cursor!"); console.log(" The server will automatically use these credentials."); } } catch (error) { console.error( "\n❌ Authentication failed:", error instanceof Error ? error.message : String(error) ); process.exit(1); } } async function checkAuth() { try { const data = await fs.readFile(TOKEN_PATH, "utf8"); const authInfo = JSON.parse(data); if (authInfo.authenticated && authInfo.clientId) { console.log("✅ Authentication found"); console.log(`📅 Authenticated on: ${authInfo.timestamp}`); // Check if we have expiration info if (authInfo.expiresAt) { const expiresAt = new Date(authInfo.expiresAt); const now = new Date(); if (expiresAt > now) { console.log(`⏰ Token expires: ${expiresAt.toLocaleString()}`); console.log("🎯 Ready to use with MCP server!"); } else { console.log("⚠️ Token may have expired - please re-authenticate"); return false; } } else { console.log("🎯 Ready to use with MCP server!"); } return true; } } catch (_error) { console.log("❌ No authentication found"); return false; } return false; } async function logout() { try { await fs.unlink(TOKEN_PATH); console.log("✅ Successfully logged out"); console.log("🔄 Run 'npx @floriscornel/teams-mcp@latest authenticate' to re-authenticate"); } catch (_error) { console.log("ℹ️ No authentication to clear"); } } // MCP Server setup async function startMcpServer() { // Create MCP server const server = new McpServer({ name: "teams-mcp", version: "0.3.3", }); // Initialize Graph service (singleton) const graphService = GraphService.getInstance(); // Register all tools registerAuthTools(server, graphService); registerUsersTools(server, graphService); registerTeamsTools(server, graphService); registerChatTools(server, graphService); registerSearchTools(server, graphService); // Start server const transport = new StdioServerTransport(); await server.connect(transport); console.error("Microsoft Graph MCP Server started"); } // Main function to handle both CLI and MCP server modes async function main() { const args = process.argv.slice(2); const command = args[0]; // CLI commands switch (command) { case "authenticate": case "auth": await authenticate(); return; case "check": await checkAuth(); return; case "logout": await logout(); return; case "help": case "--help": case "-h": console.log("Microsoft Graph MCP Server"); console.log(""); console.log("Usage:"); console.log( " npx @floriscornel/teams-mcp@latest authenticate # Authenticate with Microsoft" ); console.log( " npx @floriscornel/teams-mcp@latest check # Check authentication status" ); console.log(" npx @floriscornel/teams-mcp@latest logout # Clear authentication"); console.log(" npx @floriscornel/teams-mcp@latest # Start MCP server (default)"); return; case undefined: // No command = start MCP server await startMcpServer(); return; default: console.error(`Unknown command: ${command}`); console.error("Use --help to see available commands"); process.exit(1); } } // Handle uncaught errors process.on("uncaughtException", (error) => { console.error("Uncaught exception:", error); process.exit(1); }); process.on("unhandledRejection", (reason, promise) => { console.error("Unhandled rejection at:", promise, "reason:", reason); process.exit(1); }); main().catch((error) => { console.error("Failed to start:", error); process.exit(1); });

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/floriscornel/teams-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server