Skip to main content
Glama
index.ts9.29 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { OutlookClient } from './outlook-client.js'; const outlookClient = new OutlookClient(); const server = new Server( { name: 'outlook-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'set_access_token', description: 'Set the Microsoft Graph API access token for Outlook access', inputSchema: { type: 'object', properties: { access_token: { type: 'string', description: 'Microsoft Graph API access token', }, }, required: ['access_token'], }, }, { name: 'list_emails', description: 'List emails from Outlook inbox', inputSchema: { type: 'object', properties: { top: { type: 'number', description: 'Number of emails to retrieve (default: 10)', default: 10, }, skip: { type: 'number', description: 'Number of emails to skip (for pagination)', }, filter: { type: 'string', description: 'OData filter query (e.g., "isRead eq false")', }, orderBy: { type: 'string', description: 'Order by field (e.g., "receivedDateTime DESC")', default: 'receivedDateTime DESC', }, search: { type: 'string', description: 'Search query to find emails', }, }, }, }, { name: 'get_email', description: 'Get detailed information about a specific email', inputSchema: { type: 'object', properties: { message_id: { type: 'string', description: 'The ID of the email message', }, }, required: ['message_id'], }, }, { name: 'search_emails', description: 'Search for emails using a search query', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query to find emails', }, top: { type: 'number', description: 'Maximum number of results to return (default: 10)', default: 10, }, }, required: ['query'], }, }, { name: 'mark_as_read', description: 'Mark an email as read or unread', inputSchema: { type: 'object', properties: { message_id: { type: 'string', description: 'The ID of the email message', }, is_read: { type: 'boolean', description: 'Mark as read (true) or unread (false)', default: true, }, }, required: ['message_id'], }, }, { name: 'delete_email', description: 'Delete an email', inputSchema: { type: 'object', properties: { message_id: { type: 'string', description: 'The ID of the email message to delete', }, }, required: ['message_id'], }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params; switch (name) { case 'set_access_token': { const { access_token } = args as { access_token: string }; if (!access_token) { throw new McpError( ErrorCode.InvalidParams, 'Access token is required' ); } outlookClient.setAccessToken(access_token); return { content: [ { type: 'text', text: 'Access token has been set successfully.', }, ], }; } case 'list_emails': { const { top, skip, filter, orderBy, search } = args as { top?: number; skip?: number; filter?: string; orderBy?: string; search?: string; }; const emails = await outlookClient.listEmails({ top: top || 10, skip, filter, orderBy: orderBy || 'receivedDateTime DESC', search, }); const emailList = emails.map((email) => ({ id: email.id, subject: email.subject, from: `${email.from.emailAddress.name} <${email.from.emailAddress.address}>`, received: email.receivedDateTime, preview: email.bodyPreview, isRead: email.isRead, hasAttachments: email.hasAttachments, importance: email.importance, })); return { content: [ { type: 'text', text: JSON.stringify(emailList, null, 2), }, ], }; } case 'get_email': { const { message_id } = args as { message_id: string }; if (!message_id) { throw new McpError( ErrorCode.InvalidParams, 'Message ID is required' ); } const email = await outlookClient.getEmail(message_id); return { content: [ { type: 'text', text: JSON.stringify({ id: email.id, subject: email.subject, from: `${email.from.emailAddress.name} <${email.from.emailAddress.address}>`, received: email.receivedDateTime, body: email.body?.content || email.bodyPreview, bodyType: email.body?.contentType || 'preview', isRead: email.isRead, hasAttachments: email.hasAttachments, importance: email.importance, }, null, 2), }, ], }; } case 'search_emails': { const { query, top } = args as { query: string; top?: number }; if (!query) { throw new McpError( ErrorCode.InvalidParams, 'Search query is required' ); } const emails = await outlookClient.searchEmails(query, top || 10); const emailList = emails.map((email) => ({ id: email.id, subject: email.subject, from: `${email.from.emailAddress.name} <${email.from.emailAddress.address}>`, received: email.receivedDateTime, preview: email.bodyPreview, isRead: email.isRead, hasAttachments: email.hasAttachments, })); return { content: [ { type: 'text', text: JSON.stringify(emailList, null, 2), }, ], }; } case 'mark_as_read': { const { message_id, is_read } = args as { message_id: string; is_read?: boolean; }; if (!message_id) { throw new McpError( ErrorCode.InvalidParams, 'Message ID is required' ); } await outlookClient.markAsRead(message_id, is_read !== false); return { content: [ { type: 'text', text: `Email ${message_id} has been marked as ${is_read !== false ? 'read' : 'unread'}.`, }, ], }; } case 'delete_email': { const { message_id } = args as { message_id: string }; if (!message_id) { throw new McpError( ErrorCode.InvalidParams, 'Message ID is required' ); } await outlookClient.deleteEmail(message_id); return { content: [ { type: 'text', text: `Email ${message_id} has been deleted.`, }, ], }; } default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error: any) { if (error instanceof McpError) { throw error; } if (error.message.includes('Access token is required') || error.message.includes('Invalid or expired access token')) { throw new McpError( ErrorCode.InvalidParams, 'Please set a valid Microsoft Graph API access token first using the set_access_token tool.' ); } throw new McpError(ErrorCode.InternalError, error.message); } }); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('Outlook MCP server running on stdio'); } main().catch((error) => { console.error('Server error:', error); process.exit(1); });

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/ryoshin0830/outlook-mcp'

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