MCP Language Server

#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, CallToolRequest, } from '@modelcontextprotocol/sdk/types.js'; import { Client, AuthProviderCallback } from '@microsoft/microsoft-graph-client'; import 'isomorphic-fetch'; const TENANT_ID = process.env.TENANT_ID; const CLIENT_ID = process.env.CLIENT_ID; const CLIENT_SECRET = process.env.CLIENT_SECRET; if (!TENANT_ID || !CLIENT_ID || !CLIENT_SECRET) { throw new Error('Required environment variables are missing'); } interface ExternalDomainArgs { domains: string[]; } function isExternalDomainArgs(args: unknown): args is ExternalDomainArgs { if (typeof args !== 'object' || args === null) return false; const a = args as Record<string, unknown>; return ( Array.isArray(a.domains) && a.domains.every(domain => typeof domain === 'string') ); } class TeamsServer { private server: Server; private graphClient: Client; private token: string | null = null; constructor() { this.server = new Server( { name: 'cisa-teams', version: '0.1.0', }, { capabilities: { tools: {}, }, } ); // Initialize Graph client with token acquisition this.graphClient = Client.init({ authProvider: async (done: AuthProviderCallback) => { try { if (!this.token) { this.token = await this.getAccessToken(); } done(null, this.token); } catch (error) { done(error as Error, null); } }, }); this.setupToolHandlers(); // Error handling this.server.onerror = (error: Error) => console.error('[MCP Error]', error); process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } private async getAccessToken(): Promise<string> { const tokenEndpoint = `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`; const scope = 'https://graph.microsoft.com/.default'; const response = await fetch(tokenEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ client_id: CLIENT_ID!, client_secret: CLIENT_SECRET!, scope, grant_type: 'client_credentials', }), }); if (!response.ok) { throw new Error('Failed to acquire access token'); } const data = await response.json(); return data.access_token; } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'disable_anonymous_meetings', description: 'Disable anonymous users from starting meetings (MS.TEAMS.1.2v1)', inputSchema: { type: 'object', properties: {}, }, }, { name: 'configure_external_access', description: 'Configure external access on per-domain basis (MS.TEAMS.2.1v1)', inputSchema: { type: 'object', properties: { domains: { type: 'array', items: { type: 'string', }, description: 'List of allowed external domains', }, }, required: ['domains'], }, }, { name: 'disable_unmanaged_users', description: 'Prevent unmanaged users from initiating contact (MS.TEAMS.2.2v1)', inputSchema: { type: 'object', properties: {}, }, }, { name: 'block_skype_users', description: 'Block contact with Skype users (MS.TEAMS.3.1v1)', inputSchema: { type: 'object', properties: {}, }, }, { name: 'disable_email_integration', description: 'Disable Teams email integration (MS.TEAMS.4.1v1)', inputSchema: { type: 'object', properties: {}, }, }, { name: 'get_policy_status', description: 'Get current status of all CISA Teams security policies', inputSchema: { type: 'object', properties: {}, }, }, ], })); this.server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => { try { switch (request.params.name) { case 'disable_anonymous_meetings': return await this.disableAnonymousMeetings(); case 'configure_external_access': { if (!isExternalDomainArgs(request.params.arguments)) { throw new McpError( ErrorCode.InvalidParams, 'Invalid external domain arguments' ); } return await this.configureExternalAccess(request.params.arguments); } case 'disable_unmanaged_users': return await this.disableUnmanagedUsers(); case 'block_skype_users': return await this.blockSkypeUsers(); case 'disable_email_integration': return await this.disableEmailIntegration(); case 'get_policy_status': return await this.getPolicyStatus(); default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } } catch (error: unknown) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Error executing tool: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }); } private async disableAnonymousMeetings() { try { // Configure Teams meeting policy using Microsoft Graph API await this.graphClient .api('/policies/teamsAppSetupPolicies/global') .patch({ allowAnonymousUsersToStartMeeting: false, allowAnonymousUsersToJoinMeeting: false, }); return { content: [ { type: 'text', text: 'Anonymous users disabled from starting meetings successfully', }, ], }; } catch (error: unknown) { throw new McpError( ErrorCode.InternalError, `Failed to disable anonymous meetings: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } private async configureExternalAccess(args: ExternalDomainArgs) { try { // Configure Teams federation settings using Microsoft Graph API await this.graphClient .api('/policies/teamsFederationSettings') .patch({ allowedDomains: args.domains, allowFederatedUsers: true, allowTeamsConsumer: false, allowTeamsB2BUsers: true, }); return { content: [ { type: 'text', text: `External access configured for domains: ${args.domains.join(', ')}`, }, ], }; } catch (error: unknown) { throw new McpError( ErrorCode.InternalError, `Failed to configure external access: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } private async disableUnmanagedUsers() { try { // Configure Teams external user settings using Microsoft Graph API await this.graphClient .api('/policies/teamsExternalUserSettings') .patch({ allowUnmanagedUsersToCreateMeetings: false, allowUnmanagedUsersToStartChat: false, }); return { content: [ { type: 'text', text: 'Unmanaged users disabled from initiating contact successfully', }, ], }; } catch (error: unknown) { throw new McpError( ErrorCode.InternalError, `Failed to disable unmanaged users: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } private async blockSkypeUsers() { try { // Configure Teams Skype federation using Microsoft Graph API await this.graphClient .api('/policies/teamsFederationSettings') .patch({ allowSkypeUsers: false, allowSkypeFederation: false, }); return { content: [ { type: 'text', text: 'Contact with Skype users blocked successfully', }, ], }; } catch (error: unknown) { throw new McpError( ErrorCode.InternalError, `Failed to block Skype users: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } private async disableEmailIntegration() { try { // Configure Teams email integration using Microsoft Graph API await this.graphClient .api('/policies/teamsEmailSettings') .patch({ allowEmailIntegration: false, allowChannelEmail: false, }); return { content: [ { type: 'text', text: 'Teams email integration disabled successfully', }, ], }; } catch (error: unknown) { throw new McpError( ErrorCode.InternalError, `Failed to disable email integration: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } private async getPolicyStatus() { try { // Get current settings using Microsoft Graph API const [ meetingPolicy, federationSettings, externalUserSettings, emailSettings, ] = await Promise.all([ this.graphClient.api('/policies/teamsAppSetupPolicies/global').get(), this.graphClient.api('/policies/teamsFederationSettings').get(), this.graphClient.api('/policies/teamsExternalUserSettings').get(), this.graphClient.api('/policies/teamsEmailSettings').get(), ]); const status = { anonymousMeetings: { disabled: !meetingPolicy.allowAnonymousUsersToStartMeeting, compliant: !meetingPolicy.allowAnonymousUsersToStartMeeting, }, externalAccess: { allowedDomains: federationSettings.allowedDomains, compliant: federationSettings.allowedDomains.length > 0 && !federationSettings.allowTeamsConsumer, }, unmanagedUsers: { disabled: !externalUserSettings.allowUnmanagedUsersToStartChat, compliant: !externalUserSettings.allowUnmanagedUsersToStartChat, }, skypeUsers: { blocked: !federationSettings.allowSkypeUsers, compliant: !federationSettings.allowSkypeUsers, }, emailIntegration: { disabled: !emailSettings.allowEmailIntegration, compliant: !emailSettings.allowEmailIntegration, }, }; return { content: [ { type: 'text', text: JSON.stringify(status, null, 2), }, ], }; } catch (error: unknown) { throw new McpError( ErrorCode.InternalError, `Failed to get policy status: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Teams MCP server running on stdio'); } } const server = new TeamsServer(); server.run().catch(console.error);