UNPKG

teams-mcp-server

Version:

Microsoft Teams MCP server with direct messaging support

175 lines (174 loc) 6.25 kB
import { Client } from '@microsoft/microsoft-graph-client'; import { RateLimiter } from './rateLimiter.js'; export class TeamsClient { authManager; rateLimiter; graphClient; constructor(authManager) { this.authManager = authManager; this.rateLimiter = new RateLimiter(); } async getClient() { if (!this.graphClient) { const token = await this.authManager.getToken(); if (!token) { throw new Error('Authentication required. Please authenticate first.'); } this.graphClient = Client.init({ authProvider: async (done) => { done(null, token.accessToken); } }); } return this.graphClient; } async ensureAuthenticated() { const token = await this.authManager.getToken(); if (!token) { throw new Error('Not authenticated. Please run auth_status to authenticate.'); } } async listChats(limit = 50, filter) { return this.rateLimiter.execute(async () => { const client = await this.getClient(); const chats = []; try { let request = client.api('/chats') .select('id,topic,chatType,createdDateTime,lastUpdatedDateTime,webUrl,tenantId') .top(limit); if (filter) { request = request.filter(filter); } const response = await request.get(); if (response.value) { chats.push(...response.value); } return chats; } catch (error) { throw this.handleError(error); } }); } async createChat(request) { return this.rateLimiter.execute(async () => { const client = await this.getClient(); const members = await Promise.all(request.members.map(async (member) => { const userResponse = await client .api(`/users/${member.email}`) .select('id') .get(); return { '@odata.type': '#microsoft.graph.aadUserConversationMember', roles: [member.role || 'owner'], 'user@odata.bind': `https://graph.microsoft.com/v1.0/users('${userResponse.id}')` }; })); const chatData = { chatType: request.chatType, members }; if (request.topic && request.chatType === 'group') { chatData.topic = request.topic; } try { const response = await client.api('/chats').post(chatData); return response; } catch (error) { throw this.handleError(error); } }); } async sendMessage(request) { return this.rateLimiter.execute(async () => { const client = await this.getClient(); const messageData = { body: { contentType: request.contentType || 'text', content: request.content } }; try { const response = await client .api(`/chats/${request.chatId}/messages`) .post(messageData); return response; } catch (error) { throw this.handleError(error); } }); } async getMessages(chatId, limit = 50, since) { return this.rateLimiter.execute(async () => { const client = await this.getClient(); const messages = []; try { let request = client .api(`/chats/${chatId}/messages`) .top(limit) .orderby('createdDateTime desc'); if (since) { request = request.filter(`createdDateTime gt ${since.toISOString()}`); } const response = await request.get(); if (response.value) { messages.push(...response.value); } return messages.reverse(); // Return in chronological order } catch (error) { throw this.handleError(error); } }); } async getChatMembers(chatId) { return this.rateLimiter.execute(async () => { const client = await this.getClient(); try { const response = await client .api(`/chats/${chatId}/members`) .get(); return response.value || []; } catch (error) { throw this.handleError(error); } }); } async getUserProfile() { return this.rateLimiter.execute(async () => { const client = await this.getClient(); try { return await client .api('/me') .select('id,displayName,mail,userPrincipalName') .get(); } catch (error) { throw this.handleError(error); } }); } getRateLimitStats() { return this.rateLimiter.getStats(); } handleError(error) { if (error.statusCode === 401) { this.graphClient = undefined; // Clear client to force re-authentication return new Error('Authentication expired. Please re-authenticate.'); } if (error.statusCode === 403) { return new Error('Insufficient permissions. Ensure you have the required scopes.'); } if (error.statusCode === 404) { return new Error('Resource not found. Check the chat ID or user email.'); } if (error.body?.error) { const teamsError = error.body.error; return new Error(`${teamsError.code}: ${teamsError.message}`); } return new Error(error.message || 'An unexpected error occurred'); } }