outlook-mcp
Version:
Comprehensive MCP server for Claude to access Microsoft Outlook and Teams via Microsoft Graph API - including Email, Calendar, Contacts, Tasks, Teams, Chats, and Online Meetings
113 lines (95 loc) • 3.34 kB
JavaScript
/**
* Search contacts functionality
*/
const { callGraphAPI } = require('../utils/graph-api');
const { ensureAuthenticated } = require('../auth');
const config = require('../config');
/**
* Search contacts handler
* @param {object} args - Tool arguments
* @returns {object} - MCP response
*/
async function handleSearchContacts(args) {
try {
const {
query = '',
name = '',
email = '',
company = '',
jobTitle = '',
folder = 'contacts',
count = config.DEFAULT_PAGE_SIZE
} = args;
// Ensure user is authenticated
const accessToken = await ensureAuthenticated();
// Validate count parameter
const validCount = Math.min(Math.max(1, count), config.MAX_RESULT_COUNT);
// Build the API path
let apiPath = 'me/contacts';
if (folder && folder !== 'contacts') {
apiPath = `me/contactFolders/${folder}/contacts`;
}
// Build filter conditions
const filterConditions = [];
if (query) {
filterConditions.push(`(contains(displayName,'${query}') or contains(companyName,'${query}') or contains(jobTitle,'${query}'))`);
}
if (name) {
filterConditions.push(`contains(displayName,'${name}')`);
}
if (email) {
filterConditions.push(`emailAddresses/any(e: contains(e/address,'${email}'))`);
}
if (company) {
filterConditions.push(`contains(companyName,'${company}')`);
}
if (jobTitle) {
filterConditions.push(`contains(jobTitle,'${jobTitle}')`);
}
// Build query parameters
const queryParams = {
'$select': config.CONTACTS_SELECT_FIELDS,
'$top': validCount,
'$orderby': 'displayName asc'
};
if (filterConditions.length > 0) {
queryParams['$filter'] = filterConditions.join(' and ');
}
console.error(`Searching contacts with filters: ${queryParams['$filter'] || 'none'}`);
// Make API call
const response = await callGraphAPI(accessToken, 'GET', apiPath, null, queryParams);
const contacts = response.value || [];
return {
content: [
{
type: "text",
text: `Found ${contacts.length} contacts matching your search:\n\n${contacts.map(contact => {
const name = contact.displayName || 'No name';
const company = contact.companyName ? ` (${contact.companyName})` : '';
const emails = contact.emailAddresses && contact.emailAddresses.length > 0
? contact.emailAddresses.map(e => e.address).join(', ')
: 'No email';
const phones = contact.businessPhones && contact.businessPhones.length > 0
? contact.businessPhones.join(', ')
: contact.mobilePhone || 'No phone';
return `📧 ${name}${company}
ID: ${contact.id}
Email: ${emails}
Phone: ${phones}
${contact.jobTitle ? `Title: ${contact.jobTitle}` : ''}
${contact.department ? `Department: ${contact.department}` : ''}`;
}).join('\n\n')}`
}
]
};
} catch (error) {
console.error('Error in handleSearchContacts:', error);
return {
error: {
code: -32603,
message: `Failed to search contacts: ${error.message}`
}
};
}
}
module.exports = handleSearchContacts;