teams-mcp-server
Version:
Microsoft Teams MCP server with direct messaging support
175 lines (174 loc) • 6.25 kB
JavaScript
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');
}
}