Hunch:用MCP协议让任意LLM无焦点驱动Mac的自动化实践
如果你想做的不是“和 AI 聊天”而是“让 AI 直接帮你操作电脑”——比如打开应用、控制播放、整理文件、执行快捷指令并且整个过程不需要你切到某个窗口、不需要你盯着一块界面那么 Hunch 就是最近很值得关注的一个开源项目。Hunch 的定位非常明确用任意 LLM 驱动 Mac全程无焦点、后台运行并通过 MCPModel Context Protocol协议完成通信。它把“LLM 作为大脑”和“Mac 作为双手”连接了起来。这篇文章就围绕这个项目整理一份完整的理解与实战笔记包含 MCP 概念、环境准备、最小可运行示例、常见权限问题以及工程化建议适合对 macOS 自动化、MCP 协议和 LocalAI/大模型应用开发感兴趣的开发者。1. Hunch 到底是什么在动手配置之前先把这个项目本身讲清楚。1.1 它解决什么问题目前大多数 LLM 应用的形态仍然是“对话框”。你输入文字模型返回文字最多通过插件获取一些外部资料。但如果你想让模型直接操作系统比如用语音命令打开某个应用定时让 Mac 朗读一段文字根据 LLM 的决策自动整理 Downloads 目录把 LLM 接入到快捷指令里形成个人自动化。传统做法非常割裂要么你用 AppleScript、Automator 写死流程要么使用第三方快捷键工具但无法让“模型根据当前情况动态决定下一步动作”。Hunch 想做的事就是把 macOS 的系统能力封装成标准工具然后通过 MCP 暴露给任意 LLM。LLM 可以根据任务需要在后台调用这些工具而不需要你打开某个 App 去点击确认。用一句话概括Hunch 运行在 Mac 后台的 MCP 服务端 macOS 系统能力执行层。它让 LLM 不再只是“回答问题”而是变成“能操作你电脑的 AI 代理”。1.2 什么是 MCPMCP全称 Model Context Protocol是一个用于连接大语言模型与外部工具/数据源的开放协议。它由 Anthropic 提出后迅速被开源社区接受目前已经成为 LLM 工具调用的“通用插口”。可以把 MCP 理解成 LLM 世界的 USB-C 接口LLM 是主机MCP Server 是外设外设提供标准化的“能力”比如查询文件、控制播放器、执行命令主机通过协议发现能力、调用能力、读取结果。MCP 最大的价值是标准化。过去每个 Agent 框架都有一套自己的工具定义方式现在只要遵循 MCP 协议同一套系统能力可以无缝接入 Claude、OpenAI 兼容接口以及本地部署的开源模型。MCP 的通信模型中有两个角色角色作用MCP Client发起请求的一方通常是 LLM 应用、IDE、Agent 框架MCP Server提供工具/资源的一方负责执行具体动作并返回结果Hunch 在 MCP 体系中的角色可以理解为 macOS 这一侧的 MCP Server负责把系统能力翻译成标准工具。1.3 核心特性拆解结合项目标题可以提炼出四个关键点特性含义Any LLM只要符合 MCP 协议OpenAI、Claude、本地模型都可以接入Focus-free不需要把窗口切到前台不打断当前正在进行的操作Background常驻后台运行通过监听/定时/被动调用的方式工作Over MCP所有任务描述和结果反馈都通过 MCP 标准协议传输不过要注意工具实现的具体细节比如使用哪些系统 API、支持哪些事件触发方式不同版本可能会有差异。本文重点讲清楚原理和最小闭环具体能力以项目仓库当前文档为准。2. 环境准备这一节面向准备实际运行 Hunch 的读者。如果你暂时只是了解原理可以跳过后面的实战部分再回来看。2.1 运行环境从“Drive your Mac”这个描述可以确定Hunch 的运行环境是 macOS。安装之前建议满足以下条件macOS 版本建议较新的 macOS 系统本文不写死具体版本号因为自动化权限、MCP 支持都依赖系统版本内存取决于你接入的是云端 LLM 还是本地模型网络如果使用云端 LLM API需要正常的网络连接Python可选如果你打算编写或调试 MCP Server建议安装 Python 3.10Homebrew可选用于安装部分系统依赖。如果你还没有安装 Homebrew可以在终端执行/bin/bash -c $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)2.2 获取与安装 HunchHunch 的获取方式有两种途径一是从项目 GitHub Releases 下载最新的安装包二是如果项目提供命令行工具也可以通过以下方式安装。先确认 macOS 上已经具备基础环境sw_vers uname -a which python3然后根据 Release 页面的说明下载对应包。安装完成后可以在终端确认可执行文件是否可用hunch --version如果提示command not found可能是安装目录没有加入 PATH也可以尝试export PATH$HOME/.local/bin:$PATH注意版本不同命令名可能不同请以实际项目说明为准。2.3 权限准备这是 Hunch 能否正常工作的关键。macOS 对系统能力控制非常严格。只要你想让某个后台进程发送快捷键、读取窗口信息、控制其他 App就一定会触发权限申请。常见的几类权限包括辅助功能Accessibility用于读取 UI 元素、模拟鼠标键盘事件自动化Automation用于控制其他 App比如 AppleScript 调用 System Events完全磁盘访问用于访问某些受保护的目录输入监控用于读取键盘事件。安装后第一次启动 Hunch系统会弹窗询问是否允许控制其他应用。此时需要去“系统设置” “隐私与安全性”中确认相应选项已打开。如果你在终端里通过命令行调用 Hunch还需要确保终端本身被授予辅助功能权限否则功能可能静默失败。3. 核心原理拆解在写代码之前先理解 Hunch 这类工具是怎么工作的。这部分的重点不是背诵概念而是搞清楚“LLM 如何一步步操作 Mac”。3.1 后台运行与无焦点执行所谓“无焦点”指的是执行任务时不把当前前台 App 抢过来。实现方式有很多种常见的是通过后台守护进程接收指令通过 macOS Accessibility API 读取和控制其他应用通过 AppleScript/Shortcuts 发起系统操作通过 URL Scheme 唤起特定应用并传参。举一个最简单的例子。用 AppleScript 让 Mac 播报语音就不会抢占当前焦点say Hello from Hunch在终端中执行osascript -e say Hello from Hunch这条命令不会弹出窗口也不会打断用户当前工作非常适合作为后台任务的输出方式。再比如如果想获取当前前台应用的名称osascript -e tell application System Events to get name of first application process whose frontmost is true这类操作不需要用户点击任何界面所以整个流程可以完全在后台完成。3.2 LLM 如何调用 Mac 能力Hunch 的价值在于把这些系统能力封装成“工具”。MCP 协议中一个工具包含三个重要内容name工具名例如say_textdescription给 LLM 看的说明用于让它判断什么情况下调用input schema参数定义告知 LLM 需要传入哪些字段。LLM 收到用户请求后会先判断“我是否需要调用工具”。如果需要它会构造一个工具调用请求由 MCP Client 转发给 MCP Server。Server 执行完后把结果返回给 LLMLLM 再组织最终回复。整个过程可以理解为一条链路用户输入 → LLM 判断 → 工具调用请求 → MCP 协议转发 → Hunch 执行系统操作 → 返回结果 → LLM 生成回复这里没有中间的图形界面确认所以安全性高度依赖权限配置和工具设计。3.3 Hunch 在 MCP 中的角色按照 MCP 协议的定义Hunch 更接近一个 MCP Server但它可能同时包含“宿主Host”的逻辑。也就是说Hunch 进程本身可以加载一系列 macOS 工具通过 stdio 或 HTTP 与 LLM Client 建立连接接收工具调用请求并执行 AppleScript、快捷指令、Shell 命令返回标准输出、错误信息和执行状态。由于不同接入方式配置不同下面我们用一个最小 MCP Server 来体验这套流程。你可以把这个 MCP Server 想象成 Hunch 的“核心骨架”理解了它再去看 Hunch 的实际实现就会轻松很多。3.4 “任意 LLM”的接入方式“Any LLM”主要通过两种方式实现LLM 应用侧支持 MCP Client比如 Claude Desktop、Cline、自建 Agent 框架。它们可以作为 MCP Client 连接 Hunch本地模型 支持工具调用的框架通过 OpenAI 兼容接口或 Ollama 等加载本地模型再通过 MCP 客户端连接 Hunch。因此不管模型背后是谁只要协议一致Hunch 就能“一鱼多吃”。这也是 MCP 最值得学习的地方。4. 完整实战从零到最小可运行下面我们来构建一个最小可运行的 MCP 工具链。这个例子不强依赖 Hunch 的闭门细节而是演示“MCP Server macOS 工具”的标准写法。你可以在这个基础上把工具函数替换成 Hunch 实际提供的能力。4.1 创建项目结构先创建一个实验目录mkdir -p ~/hunch-demo cd ~/hunch-demo目录结构如下hunch-demo/ ├── mac_tools.py ├── mcp.json └── README.md4.2 编写 MCP Server安装 MCP Python SDKpip install mcp然后创建mac_tools.py# 文件路径~/hunch-demo/mac_tools.py import subprocess from mcp.server.fastmcp import FastMCP mcp FastMCP(hunch-mac-tools) mcp.tool() def say_text(text: str) - str: 让 Mac 使用系统语音朗读指定文本。 Args: text: 需要朗读的文本内容。 subprocess.run([say, text], checkTrue) return 已执行语音播报 mcp.tool() def open_app(app_name: str) - str: 打开指定应用程序。 Args: app_name: 应用的英文名称例如 Mail、Safari。 subprocess.run([open, -a, app_name], checkTrue) return f已打开 {app_name} mcp.tool() def get_frontmost_app() - str: 获取当前处于前台的应用名称。 script ( tell application System Events to get name of first application process whose frontmost is true ) result subprocess.run( [osascript, -e, script], capture_outputTrue, textTrue ) return result.stdout.strip() if __name__ __main__: mcp.run()这段代码做了什么通过FastMCP创建了一个 MCP Server每个mcp.tool()装饰的函数都会暴露给 LLM函数内部的subprocess调用 macOS 系统命令mcp.run()启动服务默认通过 stdio 通信。注意mcp包的版本和FastMCP路径可能随版本变化如果导入失败请检查安装版本并查阅对应文档。4.3 配置 MCP Client 连接接下来创建一个标准的 MCP Client 配置mcp.json{ mcpServers: { hunch-mac: { command: python3, args: [/Users/你的用户名/hunch-demo/mac_tools.py], env: {} } } }这里最关键的是command和args。MCP Client 会启动该进程并通过标准输入输出与它通信。如果你是初次配置建议先用一个简单的测试脚本来验证 MCP Server 能不能被正确拉起。4.4 验证 MCP Server因为 MCP Server 本身是一个长期运行的进程手动验证时可以先只测试工具函数。在mac_tools.py同目录下打开 Python 交互环境from mac_tools import say_text say_text(Hello from Hunch demo)如果听到 Mac 发出语音说明工具函数可以正常工作。要完整验证 MCP 协议流程你需要一个 MCP Client。这里给出一个简单的异步调用示例# 文件路径~/hunch-demo/client_demo.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): server_params StdioServerParameters( commandpython3, args[/Users/你的用户名/hunch-demo/mac_tools.py], envNone, ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools await session.list_tools() print(可用工具, [tool.name for tool in tools]) result await session.call_tool( say_text, {text: MCP 连接成功} ) print(调用结果, result) asyncio.run(main())运行python3 client_demo.py预期输出中能看到工具列表里包含say_text、open_app、get_frontmost_app并且 Mac 会再次朗读“MCP 连接成功”。4.5 将 Hunch 接入当你理解了上述最小闭环后再去看 Hunch 的实际接入方式就会清晰很多。通常流程是启动 Hunch 后台服务在 Hunch 的配置中注册要暴露给 LLM 的工具在支持 MCP Client 的 LLM 应用中添加 Hunch 的 Server 入口发起自然语言请求LLM 自动决定是否调用 Hunch 工具。配置方式可能会提供图形化界面也可能是配置文件。在项目文档中会给出当前版本的mcp.json或config.yaml示例。修改配置后需要重启 Hunch 才会生效。5. 常用自动化场景示例最小示例跑通之后我们可以扩展几个更贴近实际使用的场景。每个场景都可以通过 MCP Server 中的工具函数实现。5.1 语音播报与提醒很多 AI 助手场景需要“说出来”而不是只在屏幕上显示文字。可以用say实现mcp.tool() def remind(text: str, minutes: int) - str: 在指定分钟后使用语音提醒。 import time time.sleep(minutes * 60) subprocess.run([say, f提醒{text}], checkTrue) return 提醒已设置生产环境不建议让线程阻塞可以改成定时任务或异步任务。这里只是演示思路。5.2 定时任务联动如果你希望 LLM 参与定时任务的决策可以结合 macOS 的crontab或launchd。例如让 LLM 生成一条 crontab 命令mcp.tool() def schedule_task(command: str, cron_expr: str) - str: 向当前用户 crontab 写入定时任务。 full_command f{cron_expr} {command} proc subprocess.run( [crontab, -l], capture_outputTrue, textTrue ) existing proc.stdout new_crontab existing.rstrip() \n full_command \n subprocess.run([crontab, -], inputnew_crontab, textTrue) return 定时任务已添加这个工具的风险很高建议设置参数白名单只允许固定命令模板不要让 LLM 随意拼接。5.3 文件与访达操作macOS 可以通过osascript控制访达。下面的工具可以把指定文件移动到归档目录mcp.tool() def archive_file(file_path: str, dest_dir: str) - str: 移动文件到目标目录。 import shutil import os os.makedirs(dest_dir, exist_okTrue) shutil.move(file_path, dest_dir) return f文件已移动到 {dest_dir}更安全的方式是使用 MCP 的文件访问类工具并在系统层面限制访问范围不要让 LLM 拥有全盘读取和写入权限。5.4 与开发工具集成对开发者来说更实用的场景是让 LLM 直接读取 git 状态、查看日志、执行测试命令。mcp.tool() def git_status(project_dir: str) - str: 查看指定项目的 git 状态。 result subprocess.run( [git, -C, project_dir, status], capture_outputTrue, textTrue ) return result.stdout这类工具的好处是闭环速度快你在写代码时LLM 可以帮你确认当前分支和变更情况。要注意的是向 LLM 暴露任意目录的 git 信息可能产生隐私问题需要做好路径检查。6. 常见问题与排查思路在实际运行中最常见的故障集中在权限、MCP 连接和工具调用三方面。问题现象常见原因解决思路Hunch 启动后无响应未授予辅助功能权限检查“系统设置”“隐私与安全性”中的辅助功能AppleScript 报 -1002UI 脚本权限未授权给终端/Hunch 勾选辅助功能然后重启应用MCP Server 启动失败Python 环境缺少 mcp 包重新执行pip install mcpLLM 返回“无法调用工具”工具描述不清晰完善 description写明参数含义与使用时机调用say_text没有声音系统音量静音检查音量手动执行say testMCP 配置文件不生效路径错误或 JSON 语法错误用python3 -m json.tool mcp.json校验Hunch 进程被系统杀掉电池优化/后台限制确认 App 允许后台运行本地模型无法使用 MCP模型不支持工具调用换用支持 Function Calling 的模型或框架执行 Shell 命令权限不足未授予自动化权限允许 Hunch 终端控制对应 App如果你遇到的问题不在表中可以按下面的顺序排查先确认系统权限是否全部开启手动在终端执行 Hunch 对应的系统命令查看 Hunch 日志输出在 MCP Client 中单独测试工具调用重启 Hunch 或电脑后再试。7. 最佳实践与工程建议最后这部分非常重要。Hunch 这类工具能力非常强但如果不加约束风险也会很大。下面是我在接触 MCP 系统自动化后总结的几条经验。7.1 权限最小化不要给 Hunch 无脑授权所有权限。建议遵循最小权限原则先只授权当前场景需要的最小权限比如只做语音播报就不需要辅助功能权限如果能用 AppleScript 实现优先于 Accessibility API定期检查系统隐私设置清理不再使用的授权。7.2 工具设计要清晰MCP 工具的质量直接决定 LLM 能不能正确调用。经验是工具名称用动词开头例如open_app、send_notificationdescription 要写清楚“什么时候用、什么时候不要用”参数不要用简单字符串拼接来拼成复杂 command每个工具函数尽量只做一件事情。给 LLM 的 description 示例发送系统通知。当用户需要提醒、通知或后台任务完成提示时使用。 参数 title 为通知标题message 为通知正文。7.3 对系统操作设置白名单不要暴露一个“执行任意 Shell 命令”之类的工具。即使必须有也要加入白名单机制ALLOWED_COMMANDS { say, open, pwd, } def run_safe_command(cmd: list[str]) - str: if cmd[0] not in ALLOWED_COMMANDS: raise ValueError(命令不在白名单中) ...这种限制能有效降低误操作风险。7.4 日志与审计后台无人值守的任务需要完整的日志。建议记录以下信息调用时间工具名称参数内容返回结果或错误实际执行的系统命令。日志不仅方便调试也能在你排查“电脑为什么突然多了一个文件”这类问题时提供依据。7.5 敏感信息保护如果 LLM 是云端模型注意不要让它通过工具读取以下内容密码文件私人聊天记录浏览器 Cookie.env、id_rsa等密钥文件。可以给工具增加路径约束只暴露指定工作目录。如果使用本地模型也要注意模型本身可能被第三方扩展调用。7.6 版本兼容MCP 协议还在演进不同库版本之间的兼容性很容易出问题。建议固定 Python 依赖版本在项目中保存一份requirements.txt升级 Hunch 或 SDK 前先阅读更新日志为 MCP Server 编写简单的冒烟测试脚本。这样即使上游变更也能快速定位问题。8. 总结与下一步路线Hunch 这个项目把两件原本很复杂的事连接在了一起一是 macOS 后台自动化二是 LLM 工具调用。它借助 MCP 协议让任意 LLM 都能成为 Mac 的“遥控器”而且不需要任何图形界面参与。通过本文的实战你应该已经亲手跑通了一条最小链路用 Python 启动 MCP Server、把 macOS 命令封装成工具、再由 LLM 客户端调用工具并返回结果。这套方法论完全可以迁移到 Hunch 或任何支持 MCP 的其他工具上。如果继续深入学习建议按这个路线推进阅读 MCP 官方协议文档理解initialize、tools/list、tools/call等核心方法学习 macOS 的osascript和 Shortcuts 命令语法研究 AppleScript 自动化中“UI 元素”“System Events”的边界尝试为 Hunch 编写一个自定义 MCP 工具插件最后再考虑如何加入定时触发、事件监听和更复杂的任务编排。我强烈建议你先从最小场景跑通比如让本地模型调用say_text完成一次播报。这个过程中你会遇到权限弹窗、SDK 版本差异、AppleScript 语法错误等问题。这些问题看起来琐碎但每解决一个你对 MCP 和 macOS 自动化的理解就会深一层。动手跑一遍比看十篇文档都管用。希望这篇笔记能帮你少踩几个坑。