contacts
Search and retrieve contacts from the Apple Contacts app using a name or partial name query; returns all contacts if no name is specified.
Instructions
Search and retrieve contacts from Apple Contacts app
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Name to search for (optional - if not provided, returns all contacts). Can be partial name to search. |
Input Schema (JSON Schema)
{
"properties": {
"name": {
"description": "Name to search for (optional - if not provided, returns all contacts). Can be partial name to search.",
"type": "string"
}
},
"type": "object"
}
Implementation Reference
- tools.ts:3-15 (registration)Registration of the 'contacts' tool, defining its name, description, and input schema for optional name search.const CONTACTS_TOOL: Tool = { name: "contacts", description: "Search and retrieve contacts from Apple Contacts app", inputSchema: { type: "object", properties: { name: { type: "string", description: "Name to search for (optional - if not provided, returns all contacts). Can be partial name to search." } } } };
- tools.ts:6-14 (schema)Input schema for the 'contacts' tool allowing optional 'name' parameter.inputSchema: { type: "object", properties: { name: { type: "string", description: "Name to search for (optional - if not provided, returns all contacts). Can be partial name to search." } } }
- utils/contacts.ts:17-49 (helper)Helper function to retrieve all contacts mapped to their phone numbers, used for listing all or searching contacts.async function getAllNumbers() { try { if (!await checkContactsAccess()) { return {}; } const nums: { [key: string]: string[] } = await run(() => { const Contacts = Application('Contacts'); const people = Contacts.people(); const phoneNumbers: { [key: string]: string[] } = {}; for (const person of people) { try { const name = person.name(); const phones = person.phones().map((phone: any) => phone.value()); if (!phoneNumbers[name]) { phoneNumbers[name] = []; } phoneNumbers[name] = [...phoneNumbers[name], ...phones]; } catch (error) { // Skip contacts that can't be processed } } return phoneNumbers; }); return nums; } catch (error) { throw new Error(`Error accessing contacts: ${error instanceof Error ? error.message : String(error)}`); } }
- utils/contacts.ts:51-77 (helper)Helper function to find phone numbers by contact name using exact and fuzzy matching.async function findNumber(name: string) { try { if (!await checkContactsAccess()) { return []; } const nums: string[] = await run((name: string) => { const Contacts = Application('Contacts'); const people = Contacts.people.whose({name: {_contains: name}}); const phones = people.length > 0 ? people[0].phones() : []; return phones.map((phone: any) => phone.value()); }, name); // If no numbers found, run getNumbers() to find the closest match if (nums.length === 0) { const allNumbers = await getAllNumbers(); const closestMatch = Object.keys(allNumbers).find(personName => personName.toLowerCase().includes(name.toLowerCase()) ); return closestMatch ? allNumbers[closestMatch] : []; } return nums; } catch (error) { throw new Error(`Error finding contact: ${error instanceof Error ? error.message : String(error)}`); } }
- utils/contacts.ts:79-109 (helper)Helper function to find contact name by phone number with normalization.async function findContactByPhone(phoneNumber: string): Promise<string | null> { try { if (!await checkContactsAccess()) { return null; } // Normalize the phone number for comparison const searchNumber = phoneNumber.replace(/[^0-9+]/g, ''); // Get all contacts and their numbers const allContacts = await getAllNumbers(); // Look for a match for (const [name, numbers] of Object.entries(allContacts)) { const normalizedNumbers = numbers.map(num => num.replace(/[^0-9+]/g, '')); if (normalizedNumbers.some(num => num === searchNumber || num === `+${searchNumber}` || num === `+1${searchNumber}` || `+1${num}` === searchNumber )) { return name; } } return null; } catch (error) { // Return null instead of throwing to handle gracefully return null; } }