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,065 lines (1,064 loc) ⢠96.2 kB
JavaScript
/**
* 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.29"
}, {
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,