{"slug": "show-hn-apple-contacts-mcp-local-ai-access-to-macos-contacts", "title": "Show HN: Apple Contacts MCP – Local AI Access to macOS Contacts", "summary": "A new open-source tool called Apple Contacts MCP enables local AI agents to search, edit, and maintain Apple Contacts on macOS through a local-first MCP server. The server uses AppleScript automation and macOS privacy prompts instead of cloud credentials, with write operations set to dry-run by default and requiring explicit user confirmation. This allows AI assistants like Claude and Codex to interact with a user's local contact database while maintaining privacy and user control over changes.", "body_md": "Local-first MCP server for safely searching, editing, and maintaining Apple Contacts notes on macOS.\n\nThe server uses `Contacts.app`\n\nautomation through AppleScript today. That keeps install simple and uses macOS privacy prompts instead of cloud credentials. Writes are dry-run by default and require explicit confirmation.\n\n`contacts_status`\n\n: check Contacts.app access and return aggregate counts.`search_contacts`\n\n: search local contacts by name, organization, job title, email, or phone.`create_contact`\n\n: create a contact. Dry-run by default.`update_contact`\n\n: update scalar fields, notes, or add email/phone values. Dry-run by default.`append_contact_note`\n\n: append a dated interaction log entry to a contact note. Dry-run by default.`delete_contact`\n\n: delete a contact. Dry-run by default and requires a confirmation phrase.`test_roundtrip`\n\n: create, edit, verify, and delete one dummy contact.\n\n- macOS with Contacts.app\n- Node.js 18 or newer\n- Contacts/Automation permissions when macOS prompts\n\n```\ngit clone <repo-url>\ncd apple-contacts-mcp\nnpm test\nnpm run smoke\n```\n\n`npm run smoke`\n\nverifies the MCP handshake and tool list without touching Contacts.\n\nTo run a live dummy create/edit/note/delete roundtrip:\n\n```\nnpm run smoke:live\n```\n\nmacOS may prompt for Contacts or Automation permissions. The live smoke test creates one dummy contact, edits it, appends a note, verifies the change, and deletes the dummy.\n\nThis is a stdio MCP server. Any MCP-capable agent needs the same command:\n\n```\nnode /absolute/path/to/apple-contacts-mcp/bin/apple-contacts-mcp.cjs\n```\n\nUse an absolute path. Relative paths are easy to break when an agent launches MCP servers from another working directory.\n\nAfter cloning:\n\n```\ncodex mcp add apple-contacts -- node /absolute/path/to/apple-contacts-mcp/bin/apple-contacts-mcp.cjs\n```\n\nThen restart Codex or start a new Codex thread so the MCP tools are loaded.\n\nTo confirm the server is registered:\n\n```\ncodex mcp list\n```\n\nAsk Codex:\n\n```\nUse apple-contacts to run contacts_status.\n```\n\nOpen the Claude Desktop config file on macOS:\n\n```\nopen \"$HOME/Library/Application Support/Claude/claude_desktop_config.json\"\n```\n\nAdd this under the top-level `mcpServers`\n\nobject, then restart Claude Desktop:\n\n```\n{\n  \"mcpServers\": {\n    \"apple-contacts\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/apple-contacts-mcp/bin/apple-contacts-mcp.cjs\"]\n    }\n  }\n}\n```\n\nIf the file already has other MCP servers, add only the `apple-contacts`\n\nentry inside the existing `mcpServers`\n\nobject.\n\nAsk Claude:\n\n```\nUse the Apple Contacts MCP server to run contacts_status. Do not show any contact values.\n```\n\nAdd a stdio MCP server with:\n\n```\n{\n  \"mcpServers\": {\n    \"apple-contacts\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/apple-contacts-mcp/bin/apple-contacts-mcp.cjs\"]\n    }\n  }\n}\n```\n\nIf your agent has an MCP CLI, use its equivalent of:\n\n```\n<agent> mcp add apple-contacts -- node /absolute/path/to/apple-contacts-mcp/bin/apple-contacts-mcp.cjs\n```\n\nGood first prompt for any agent:\n\n```\nInstall this repository as a local MCP server named apple-contacts. Use the absolute path to bin/apple-contacts-mcp.cjs, then restart or reload your MCP tools and run contacts_status. Treat contact data as personal data and keep writes dry-run unless I explicitly approve them.\n```\n\nThis server automates `Contacts.app`\n\nlocally. The first live call may trigger macOS permission prompts for Contacts and/or Automation. Approve those prompts for the terminal or app that is launching the MCP server.\n\nIf a call fails because `Contacts.app`\n\nis not running, open Contacts and retry:\n\n```\nopen -a Contacts\n```\n\nCreate, update, and delete operations are dry-run by default. An actual write must pass both:\n\n```\n{\n  \"dryRun\": false,\n  \"confirm\": true\n}\n```\n\nDelete also requires:\n\n```\n{\n  \"confirmPhrase\": \"delete contact\"\n}\n```\n\nThis gives agents a natural two-step flow: propose the change first, then apply only after user approval.\n\nUse `append_contact_note`\n\nfor CRM-style interaction logs instead of overwriting the full note field.\n\nInput:\n\n```\n{\n  \"contactId\": \"CONTACT-ID-FROM-search_contacts\",\n  \"date\": \"2026-06-04\",\n  \"summary\": \"Met at an AI founder dinner. They are interested in local-first agent tooling.\",\n  \"openThreads\": [\n    \"Send the GitHub repo\",\n    \"Follow up about a demo next week\"\n  ],\n  \"dryRun\": true\n}\n```\n\nThe appended note entry uses:\n\n```\n- 2026-06-04 - Met at an AI founder dinner. They are interested in local-first agent tooling.\n  Open threads: Send the GitHub repo; Follow up about a demo next week\n```\n\nAn actual append requires:\n\n```\n{\n  \"dryRun\": false,\n  \"confirm\": true\n}\n```\n\nThis server runs locally on your Mac. It does not call a cloud API or upload contacts on its own. Your agent will still see whatever contact data you ask the MCP server to return, so use field filters and redaction when possible.\n\nContacts may sync through iCloud, Google, Exchange, or another configured account. A local write can propagate to those services.\n\nThe first backend is AppleScript automation of `Contacts.app`\n\n. A future backend may use a signed Swift helper around Apple's `Contacts.framework`\n\nfor more structured access.\n\nDirect SQLite writes to `~/Library/Application Support/AddressBook`\n\nare intentionally not supported.\n\nMIT", "url": "https://wpnews.pro/news/show-hn-apple-contacts-mcp-local-ai-access-to-macos-contacts", "canonical_source": "https://github.com/lu-wo/apple-contacts-mcp", "published_at": "2026-06-06 02:21:33+00:00", "updated_at": "2026-06-06 03:17:56.448769+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "ai-products"], "entities": ["Apple Contacts", "macOS", "Node.js", "MCP"], "alternates": {"html": "https://wpnews.pro/news/show-hn-apple-contacts-mcp-local-ai-access-to-macos-contacts", "markdown": "https://wpnews.pro/news/show-hn-apple-contacts-mcp-local-ai-access-to-macos-contacts.md", "text": "https://wpnews.pro/news/show-hn-apple-contacts-mcp-local-ai-access-to-macos-contacts.txt", "jsonld": "https://wpnews.pro/news/show-hn-apple-contacts-mcp-local-ai-access-to-macos-contacts.jsonld"}}