Atlas / MCP servers / bulutarkan / mac-mcp

mac-mcpBLOCK

mcp/bulutarkan/mac-mcp

Talk to your AI agent and let it work on your Mac. Open source MCP control for browser, files, apps, shell, and agents.

Verdict
BLOCK
Grade
F
Trust score
49 /100
Exposed tools
50 36r · 13w · 1d
Transport
streamable-http
License
MIT
Stars
80
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

Mac MCP is a local macOS control server for AI agents. It exposes your Mac through a native MCP endpoint and a REST/OpenAPI surface, with shell, files, browser automation, macOS UI control, delegated OpenCode/Codex agents, memory, Agent Skills, voice interaction, self-update tooling, and a local operations dashboard. The native MCP endpoint is the full capability surface; REST/OpenAPI intentionally publishes a selected compatibility subset, so some capabilities remain MCP-only.

Talk to ChatGPT. Let it work on your Mac.

Mac MCP is model-agnostic and works with MCP-compatible AI clients. But ChatGPT is an especially natural way to use it.

ChatGPT Live can use plugins during voice conversations. With Mac MCP connected, the same ChatGPT conversation you already use can become a control surface for your actual Mac. You can talk naturally while Mac MCP handles the execution: browsing in Safari or Chrome, working with files, opening apps, running commands, and coordinating agents.

Instead of moving every task into a separate coding-agent session, you can keep the interaction in ChatGPT and simply talk. From your phone, you can ask ChatGPT to work on a reachable Mac somewhere else. From your desktop, you can keep talking while Mac MCP works in the background without taking over the computer.

For example:

  • "Check my Reddit replies, answer the important ones, and close the browser when you are done."
  • "Go through the repo, run the tests, and tell me what is broken."
  • "Find three hotels for next weekend, compare the reviews, and save the shortlist on my Mac."

ChatGPT is the conversation. Mac MCP is the execution layer.

This is a powerful combination, not a Mac MCP-only voice feature. ChatGPT provides the natural voice interface and reasoning experience; Mac MCP gives it a local execution layer on macOS. Existing ChatGPT plugin permissions, approval

Read from source at commit b6aa4f9a8257OBSERVED · 2026-10-07
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add mac-mcp --env CLOUDFLARE_TUNNEL_TOKEN_FILE=${CLOUDFLARE_TUNNEL_TOKEN_FILE} --env GROQ_API_KEY=${GROQ_API_KEY} --env MAC_MCP_CHROME_BRIDGE_TOKEN=${MAC_MCP_CHROME_BRIDGE_TOKEN} --env MAC_MCP_CHROME_BRIDGE_TOKEN_FILE=${MAC_MCP_CHROME_BRIDGE_TOKEN_FILE} -- uvx mac-mcp
claude-desktop
{
  "mcpServers": {
    "mac-mcp": {
      "command": "uvx",
      "args": [
        "mac-mcp"
      ],
      "env": {
        "CLOUDFLARE_TUNNEL_TOKEN_FILE": "${CLOUDFLARE_TUNNEL_TOKEN_FILE}",
        "GROQ_API_KEY": "${GROQ_API_KEY}",
        "MAC_MCP_CHROME_BRIDGE_TOKEN": "${MAC_MCP_CHROME_BRIDGE_TOKEN}",
        "MAC_MCP_CHROME_BRIDGE_TOKEN_FILE": "${MAC_MCP_CHROME_BRIDGE_TOKEN_FILE}"
      }
    }
  }
}
03

Exposed tools (50)

36 read · 13 write · 1 destructive. Blast radius: 1 tool can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
agent_actionreadnonlocal body_calls
agent_catalogreadreturn await asyncio.to_thread(
ask_choicereadreturn {
browser_actreadreturn await asyncio.to_thread(
browser_click_selectorreadreturn _log(audit_logger,
browser_doreadnonlocal executed
browser_execute_jswritereturn _log(audit_logger,
browser_findreadreturn {
browser_get_htmlreadreturn _log(audit_logger,
browser_list_tabsreadreturn _log(audit_logger,
browser_observereadexecuted.append(
browser_press_keyreadnonlocal pasted
browser_type_selectorreadreturn _log(audit_logger,
browser_wait_for_selectorreadreturn _log(audit_logger,
clipboard_getreadreturn _log(audit_logger,
clipboard_setwritereturn _log(audit_logger,
computer_planreadreturn await execute_computer_plan(mcp.call_tool, steps=steps, max_seconds=max_seconds)
copy_filereadreturn _log(audit_logger,
delete_pathdestructivereturn _log(audit_logger,
directory_treereadreturn _log(audit_logger,
edit_filewritereturn _log(audit_logger,
get_agentreadreturn _log(audit_logger,
get_file_inforeadreturn _log(audit_logger,
get_job_outputreadreturn _log(audit_logger,
get_job_statusreadreturn _log(audit_logger,
get_system_inforeadreturn _log(audit_logger,
get_volumereadreturn _log(audit_logger,
http_requestreadreturn _log(audit_logger,
lesson_recordreadpair = current_security_session()
list_agentsreadreturn _log(audit_logger,
list_directoryreadreturn _log(audit_logger,
list_jobsreadreturn _log(audit_logger,
mac_actreadexecuted.append(
move_filewritereturn _log(audit_logger,
open_appreadreturn _log(audit_logger,
open_urlreadreturn _log(audit_logger,
process_listreadreturn _log(audit_logger,
read_filereadreturn _log(audit_logger,
read_multiple_filesreadreturn _log(audit_logger,
run_applescriptwritereturn _log(audit_logger,
run_commandwritereturn {
send_notificationwritereturn _log(audit_logger,
set_reminderwritereturn _log(audit_logger,
skill_update_indexwritereturn await asyncio.to_thread(_log, audit_logger,
spawn_agentreadreturn {
stop_jobwritereturn _log(audit_logger,
tool_discoverreadq = str(query or
tool_invokewritereturn await _invoke_registered_tool(mcp, tool_name, arguments)
write_filewritereturn _log(audit_logger,
write_files_batchwritereturn _log(audit_logger,
04

Trust audit

BLOCKgrade F · trust 49/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (16 observation(s))
Network
declared (5 observation(s))
Shell
declared (2 observation(s))
Dependencies
pinned
Secrets in source
found

Findings (25)

HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
mcp_server/tools_agents.py:2208
f'(deny process-exec (literal "{_sbpl_quote(path)}"))'
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
mcp_server/tools_agents.py:2257
f'(deny process-exec (literal "{_sbpl_quote(path)}"))' for path in _RESTRICTED_ESCAPE_EXECUTABLES
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
mcp_server/data_guard.py:86
if name in {".netrc", ".npmrc", ".pypirc", ".git-credentials", "auth.json"}:
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
mcp_server/data_guard.py:92
if "/.aws/credentials" in lower or "/.config/gcloud/application_default_credentials.json" in lower:
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
mcp_server/data_guard.py:215
if any(marker in lower for marker in ("/.ssh/", "~/.ssh/", ".env", "security find-generic-password", "security find-internet-password", "printenv", " env")):
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
mcp_server/data_guard.py:339
"~/.ssh/", "/.ssh/", ".env", ".netrc", ".npmrc", ".pypirc",
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
mcp_server/data_guard.py:340
".git-credentials", "credentials.json", "service-account.json",
Why it matters. touches a credential store
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
menu_app/ChromeVisualCompanion/bridge_config.js.example:3
token: "generated-at-install-time",
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/test_agent_resilience_dashboard.py:13
TOKEN = "resilience-dashboard-token"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/test_auth.py:63
secret = "local-dashboard-secret-0123456789-abcdefghijklmnopqrstuvwxyz"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/test_browser_visual_companion.py:33
secret = "TOP_SECRET_SENTINEL_DO_NOT_LEAK"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/test_browser_visual_companion.py:59
secret = "SIDEBAR_SECRET_MUST_NOT_LEAK"
MEDIUMHard-coded secrets · secret.github · CWE-798, CWE-321
tests/test_security_boundaries.py:590
secret = "ghp_abcdefghijklmnopqrstuvwxyz123456"
MEDIUMHard-coded secrets · secret.private_key · CWE-798, CWE-321
tests/test_security_boundaries.py:332
private_key = "-----BEGIN PRIVATE KEY-----\nQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo0123456789\n-----END PRIVATE KEY-----"
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
delete_path
Why it matters. 1 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/test_browser_visual_companion.py:87
self.assertNotIn("eval(", script)
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/test_browser_visual_companion.py:146
self.assertNotIn("eval(", source)
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
mcp_server/browser_tabs.py:356
digest = hashlib.sha1(str(native_id).encode("utf-8")).hexdigest()[:16]
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
tests/test_ssrf_revalidation.py:92
with patch.object(security.socket, "getaddrinfo", return_value=_dns("169.254.169.254")):
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:208
For the simplest Cloudflare setup, create the tunnel and hostname in Cloudflare, then paste the tunnel token once into **Settings → Advanced → Cloudflare**. Mac MCP writes it atomically to `~/.mac-mcp
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:352
http://127.0.0.1:8000/mcp
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/HARDENED_DEDICATED_USER.md:14
|  http://127.0.0.1:<port>/mcp
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/HARDENED_DEDICATED_USER.md:72
curl --fail http://127.0.0.1:8000/health
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/HARDENED_DEDICATED_USER.md:78
http://127.0.0.1:8000/mcp
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
mcp_server/tools_browser.py:1270
raw = base64.b64decode(encoded.encode("ascii"), validate=True).decode("utf-8") if encoded else ""

Gates applied: no_behavioural_pass.

Audited 2026-10-07 · audit v0.4.1 · source sha b6aa4f9a8257full audit observations/trust-audit/mcp-server/bulutarkan__mac-mcp.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-07b6aa4f9a8257BLOCKF49first audit
06

Questions

What is the mac-mcp MCP server?

Talk to your AI agent and let it work on your Mac. Open source MCP control for browser, files, apps, shell, and agents.

What tools does mac-mcp expose?

50 in total: 36 read-only, 13 that write, and 1 that can delete or overwrite (delete_path). Every one is listed on this page with its risk.

Is mac-mcp safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (49/100) and found 7 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does mac-mcp need?

It reads CLOUDFLARE_TUNNEL_TOKEN_FILE, GROQ_API_KEY, MAC_MCP_CHROME_BRIDGE_TOKEN, MAC_MCP_CHROME_BRIDGE_TOKEN_FILE, MAC_MCP_DASHBOARD_TOKEN_FILE, MAC_MCP_FAKE_PARENT_SECRET, MAC_MCP_OPENROUTER_KEYCHAIN_ACCOUNT, MAC_MCP_OPENROUTER_KEYCHAIN_SERVICE, MAC_MCP_SCOPED_AUTH_DB, MAC_MCP_VOICE_GROQ_API_KEY, MAC_MCP_VOICE_GROQ_DEFAULTS_KEY and MAC_MCP_VOICE_GROQ_KEYCHAIN_ACCOUNT from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does mac-mcp run?

It speaks streamable-http, so it runs as a service you connect to over the network. It is published on PyPI as mac-mcp.

How current is this page?

The grade is for one exact copy of the source (b6aa4f9a8257), read on 2026-10-07. The repository is watched and re-audited when it changes.

Advertisement