mcpField
H
hammerspoon-mcp

hammerspoon-mcp

本地服务
github.com/vukvukovich生产力111 周前更新

关于 hammerspoon-mcp

hammerspoon-mcp 是连接 MCP 客户端与 Hammerspoon 的 macOS 自动化服务,面向希望通过 Agent 管理窗口、应用和系统功能的用户。它使用静态 Lua 工具体并将参数单独传递,默认仅开放安全操作。

主要功能

  1. 01列出、聚焦和调整窗口
  2. 02启动及切换应用
  3. 03查询 Hammerspoon API 文档
  4. 04读取控制台并重载配置
  5. 05查看和控制系统功能
  6. 06默认关闭任意 Lua 执行

适用场景

  1. 01整理桌面窗口布局
  2. 02查找 Hammerspoon API 用法
  3. 03编辑配置后重载并排查错误
  4. 04切换音频设备或桌面空间

MCP 相关

通过 stdio 向 MCP 客户端提供类型化工具,以调用 Hammerspoon 执行 macOS 操作。默认提供安全工具;设置 HS_MCP_TOOLS=all 后才注册任意 Lua 等受限工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"vukvukovich-hammerspoon": {
"command": "npx",
"args": [
"-y",
"@vukvukovich/hammerspoon-mcp"
],
"env": {
"HS_MCP_TOOLS": "<HS_MCP_TOOLS>",
"HS_MCP_TRANSPORT": "<HS_MCP_TRANSPORT>",
"HS_MCP_HS_PATH": "<HS_MCP_HS_PATH>",
"HS_MCP_DOCS_PATH": "<HS_MCP_DOCS_PATH>",
"HS_MCP_LOG_LEVEL": "<HS_MCP_LOG_LEVEL>"
}
}
}
}
启动命令npx -y @vukvukovich/hammerspoon-mcp
需要配置的环境变量
HS_MCP_TOOLSWhich tools to expose. "safe" (default) exposes inspection, window management, and system tools only. "all" additionally exposes hs_eval, hs_applescript, and hs_ui_press, which run arbitrary Lua and AppleScript and press UI elements - anything the user can do.
HS_MCP_TRANSPORTHow Lua reaches Hammerspoon. "socket" (default) keeps one persistent Unix domain socket, self-installed on first call, with automatic fallback to spawning; "spawn" runs one hs process per call.
HS_MCP_HS_PATHExplicit path to the Hammerspoon hs command line tool. Only needed when Hammerspoon is installed somewhere unusual.
HS_MCP_DOCS_PATHExplicit path to Hammerspoon's bundled docs.json, used by hs_api_search.
HS_MCP_LOG_LEVELLog verbosity on stderr: debug, info (default), warn, or error.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@vukvukovich/hammerspoon-mcp0.4.0

工具

38

收录的工具列表 · 更新于 2 周前

此工具无需参数。

详细介绍

Hammerspoon MCP

npm CI node license

让 AI Agent 通过 Hammerspoon 操控你的 Mac,同时绝不将输入拼接到 Lua 源码中。

简介

Hammerspoon 是一款使用 Lua 编写脚本的 macOS 自动化应用。它通过 hs.ipc 模块提供命令行接口,因此 hs -c "<lua>" 会在正在运行的 Hammerspoon 进程中执行 Lua。

本项目是一个 MCP(Model Context Protocol)服务,位于该命令行接口前端。它为 Agent 提供一组有类型的工具(列出窗口、移动窗口、聚焦应用、搜索 Hammerspoon API 文档、查看控制台日志、重新加载配置),并将每次工具调用转换为由 Hammerspoon 执行的 Lua 程序。

它通过 stdio 使用 MCP,因此任何 MCP 客户端都可以使用它:Claude Code、Claude Desktop,或你自己的客户端。

项目状态

已在 npm 上发布,版本为 v0.4.x:包含 38 个安全级别工具,另有 3 个工具需设置 HS_MCP_TOOLS=all 才可使用。项目仍处于 1.0 之前,因此工具名称和参数形式可能会在次要版本之间发生变化。

与众不同之处

1. 从设计上防止注入

“帮我运行 Lua”桥接中的大部分风险,都出现在构建 Lua 的那一刻。通常的做法是将参数插入源码字符串,并转义危险字符。转义是一种需要遵循的规范,而规范总有疏漏的时候。

此服务绝不进行插值。每个工具的 Lua 主体都是 TypeScript 源码中的静态常量。参数单独传递:

  1. 将经过验证的参数对象编码为 JSON。
  2. 将该 JSON 编码为 base64。
  3. 将 base64 文本仅拼接一次,放入一行固定的前置代码中:
local ARGS = hs.json.decode(hs.base64.decode("<base64>"))

随后,工具主体会读取 ARGS.title、ARGS.windowId 等字段。

base64 字符集为 A-Z、a-z、0-9、+、/ 和 =。它不包含引号、反斜杠、换行符、方括号或连字符。因此,载荷无法闭合 Lua 字符串、无法开始转义序列、无法开启长括号,也无法开启注释。注入之所以不可能,是因为字符集的限制,而不是因为有人记得正确转义。

这里也没有 shell 层。此服务通过持久的 Unix 套接字与 Hammerspoon 通信;如果不可用,则回退到使用 argv 数组调用 spawn(hsPath, ["-c", lua]),因此这两种路径都不会由 sh 解析命令。

2. 分级工具,默认安全

默认级别为 safe:读取、检查和排列操作。任意 Lua 求值功能以 hs_eval 的形式提供,但除非设置 HS_MCP_TOOLS=all,否则不会启用。

请参阅安全性,了解相关原因。简而言之:威胁来自提示词注入,而不是你。

3. 专为配置开发循环打造

Hammerspoon 的大部分价值都来自你自己的 init.lua。因此,服务不仅能帮你操控 Hammerspoon,还能帮你编写配置:

  • hs_api_search 可搜索 Hammerspoon 内置的 API 文档,让 Agent 查找 hs.window.moveToUnit 的实际签名,而不是凭空猜测。
  • hs_console_tail 可读取 Hammerspoon 控制台的输出,让 Agent 查看自己的错误。
  • hs_reload_config 可在编辑后重新加载 init.lua。

编辑、重新加载、读取控制台、修复。Agent 可以自行完成这个循环。

快速开始

前提条件
  • macOS。

  • Node.js 24 或更高版本。

  • 已安装并运行的 Hammerspoon:

    brew install --cask hammerspoon
    
  • 在 Hammerspoon 配置中加载 hs.ipc 模块。将此行添加到 ~/.hammerspoon/init.lua:

    require("hs.ipc")
    

    然后从 Hammerspoon 菜单栏图标重新加载配置。这样就会安装并启用 hs 命令行工具。没有它,hs -c 就无从交互。

连接任何客户端之前,请先手动验证桥接是否正常:

hs -c "return 1 + 1"

如果输出为 2,就表示已准备就绪。

将其添加到 MCP 客户端

Claude Code:

claude mcp add hammerspoon -- npx -y @vukvukovich/hammerspoon-mcp

任何接受 mcpServers JSON 配置块的客户端:

{
  "mcpServers": {
    "hammerspoon": {
      "command": "npx",
      "args": ["-y", "@vukvukovich/hammerspoon-mcp"]
    }
  }
}

要启用不安全层,请添加环境变量。Claude Code:

claude mcp add hammerspoon -e HS_MCP_TOOLS=all -- npx -y @vukvukovich/hammerspoon-mcp

JSON:

{
  "mcpServers": {
    "hammerspoon": {
      "command": "npx",
      "args": ["-y", "@vukvukovich/hammerspoon-mcp"],
      "env": {
        "HS_MCP_TOOLS": "all"
      }
    }
  }
}

让 Agent 首先调用 hs_health。它会报告是否找到了 hs 二进制文件、Hammerspoon 是否正在运行,以及 hs.ipc 是否有响应。

工具参考

共 41 个工具:安全层中有 38 个,另有 3 个受限工具。

工具等级功能
hs_healthsafe报告桥接状态:已解析的 hs 路径、Hammerspoon 是否有响应及其版本。
hs_api_searchsafe搜索 Hammerspoon 内置的 API 参考,并返回准确的签名。
hs_console_tailsafe返回 Hammerspoon 控制台的最后 N 行。
hs_reload_configsafe重新加载 ~/.hammerspoon/init.lua。
hs_notifysafe显示临时屏幕提醒,不会抢占焦点。
hs_list_windowssafe列出窗口及其 ID、标题、所属应用、屏幕和窗口框架。
hs_focus_windowsafe按 ID 或标题中的子字符串聚焦窗口。
hs_move_windowsafe按绝对屏幕像素移动或调整指定 ID 的窗口大小。
hs_window_layoutsafe将窗口贴靠到命名预设位置,例如 left-half 或 quarter-top-left。
hs_list_appssafe列出正在运行的应用及其 bundle ID、PID 和窗口数量。
hs_launch_appsafe按名称启动应用;如果应用已在运行,则将其聚焦。
hs_focus_appsafe将已在运行的应用置于前台。
hs_screenssafe列出屏幕及其 ID、名称、框架,以及哪个屏幕为主屏幕。
hs_machine_statussafe一次调用即可获取电池、亮度、Wi-Fi、空闲时间、音频和主机信息。
hs_audio_devicessafe列出音频输出和输入设备,并显示当前默认设备。
hs_audio_set_devicesafe切换默认输出或输入设备,例如切换到耳机。
hs_audio_volumesafe获取或设置默认设备的音量和静音状态。
hs_brightnesssafe获取或设置内置显示器的亮度。
hs_media_controlsafe通过系统媒体按键播放、暂停、跳过或返回。
hs_list_spacessafe按屏幕列出桌面(Spaces)、其位置以及当前桌面。
hs_goto_spacesafe按 ID 或从 1 开始的位置序号切换桌面。
hs_evalunsafe执行任意 Lua 代码。需要设置 HS_MCP_TOOLS=all。
hs_applescriptunsafe运行 AppleScript。可访问 Mail、Notes、Reminders 和 Finder。需要设置 HS_MCP_TOOLS=all。
hs_ui_pressunsafe按下由 hs_ui_inspect 找到的 UI 元素。若未提供检查结果中的 expectLabel 或 expectRole,则拒绝执行;若该元素当前已与检查结果不匹配,也会拒绝执行。需要设置 HS_MCP_TOOLS=all。
hs_window_layout 预设:left-half、right-half、top-half、bottom-half、
maximize、center、thirds-left、thirds-center、thirds-right、
two-thirds-left、two-thirds-right,以及四个 quarter-* 角落布局。
位置根据屏幕的可用区域计算,因此会避开菜单栏和 Dock;在原点为负值的第二台显示器上也能正常使用。

hs_ui_inspect 只返回结构和标签,不会返回文本字段或文档的内容。Agent 需要结构才能执行操作;而密码管理器中存放的正是内容。

除非选择启用,否则不会注册 unsafe 层级中的工具。使用默认设置连接的客户端不会在工具列表中看到 hs_eval、hs_applescript 或 hs_ui_press。

配置

所有配置均为环境变量,在启动时读取一次。

变量值默认值含义
HS_MCP_TOOLSsafe | allsafe要注册的层级。all 会添加 unsafe 层级:hs_eval、hs_applescript 和 hs_ui_press。
HS_MCP_TRANSPORTsocket | spawnsocketLua 连接 Hammerspoon 的方式:使用持久 Unix 套接字(速度约快 10 倍,首次调用时自动安装,必要时自动回退到 spawn),或每次调用启动一个 hs 进程。
HS_MCP_HS_PATH绝对路径自动检测hs 二进制文件的路径。如果安装位置不常见,请设置此项。
HS_MCP_DOCS_PATH绝对路径来自应用程序包Hammerspoon 内置 API 文档 JSON 的路径,供 hs_api_search 使用。
HS_MCP_LOG_LEVELdebug | info | warn | errorinfostderr 日志的详细程度。日志不会写入承载协议的 stdout。

如果 HS_MCP_TOOLS 的值无法识别,系统会记录醒目的警告,并回退到 safe,而不会切换到权限更宽泛的层级。拼写错误可能导致你无法使用受限工具,但 绝不会因此授予这些工具。有关 hs 路径默认值的查找顺序,请参阅 docs/ARCHITECTURE.md。

安全

将 HS_MCP_TOOLS=all 之前,请先阅读本节。

服务运行位置

该服务是一个本地进程。MCP 客户端会启动它,通过 stdio 与它通信;它以你的用户账户运行。它不会监听网络,也没有远程暴露面。

这也意味着它会继承你的权限。Hammerspoon 拥有 macOS TCC (透明度、同意与控制)授权,例如辅助功能权限,也可能拥有屏幕录制和自动化权限。在 Hammerspoon 内运行的任何程序都会使用这些授权。此服务不会增加权限,也无法撤销任何权限。

实际威胁模型

风险不在于你不可信,风险在于提示词注入。

Agent 会不断读取不可信文本:网页、README 文件、问题正文、日志行以及其他工具的输出。其中任何内容都可能包含指令。有时 Agent 会照做。这并非假设,而且尚未得到解决。

因此,对每个工具都要问:如果 Agent 被说服调用它,会造成多大危害?

  • 精心设计的动词只有很小的影响范围。使用 hs_move_window 时,最糟糕的情况是窗口被移到了错误的位置。令人烦恼,但可以撤销,也看得见。
  • 任意 Lua 的影响范围没有上限。Hammerspoon 的 Lua 可以运行 shell 命令、读取剪贴板、捕获屏幕、监视按键并发起网络请求。只要注入成功一次,就能悄无声息地完全控制这台机器。

这就是划分层级的全部原因。

HS_MCP_TOOLS=all 的含义

它会注册 hs_eval、hs_applescript 和 hs_ui_press。从那一刻起,Agent 就能在持有你授予的辅助功能权限的进程中,执行它能编写的任意 Lua 或 AppleScript,并按下界面元素。请把它视作交出一个同时能访问屏幕和键盘的 shell。

这确实是一种很实用的模式。让 Agent 直接尝试代码片段,可以大大加快编写和调试 Hammerspoon 配置的速度。请在你能监看的会话中,将它用于你要求的工作,然后再将其关闭。不要在会浏览网页的长期运行或无人值守的 Agent 中启用它。

默认安全并不是说你不能被信任去使用危险工具,而是说,启用它应该是你在特定日期、出于特定原因,有意做出的决定。

有意不提供的功能

这些并非疏忽,而是有原因的拒绝。

  • 原始 shell 执行。 Agent 已经有由其自身宿主沙箱隔离并审计的 shell 工具。Mac 控制服务不需要再变成一个更糟糕的 shell。
  • 按键和点击模拟。 向当前获得焦点的任意窗口模拟输入,等同于换了种方式执行任意代码。如果该窗口是终端,那么“输入这段文本”和“运行这条命令”就是同一个操作。
  • 读取剪贴板。 你的剪贴板里存有密码、令牌和私人消息,而且往往就在你复制后几秒内。能读取剪贴板的工具,就是一种能窃取你最敏感的短期数据的手段。
  • 屏幕截图。 理由相同。屏幕捕获包含所有可见内容,包括 Agent 未被要求查看的窗口。

其中一些功能以后可能会重新加入,各自需要明确选择启用,就像现在对 hs_eval 的限制一样。它们永远不会出现在默认层级中。

报告漏洞

请在代码库中提交安全公告,不要公开提交问题。

有一点需要了解:调用会排队

Hammerspoon 在单线程上运行 Lua,因此无论收到多少调用,它一次只会执行一个。实测结果:同时发出的 4 个 400ms 调用需要 1629ms,而不是 417ms。

因此,服务会相应排队,一次最多处理 4 个正在执行的调用。这不是为了限流而限流。如果不加限制,同时发起的调用不只是需要等待,还会开始失败(测试中 15 个调用只有 5 个成功),而且这种模式曾在 Hammerspoon 自身的 IPC 层中导致两次崩溃。

实际影响是:一个缓慢的工具会阻塞其他工具,因为所有调用共用一个队列。如果感觉卡住了,通常是有一个调用正在占用队列。ARCHITECTURE.md中列出了实测数据。

故障排查

先运行 hs_health。它会告诉你遇到的是以下哪种情况。

找不到 hs。 服务会检查固定的一系列位置,然后检查 PATH。如果你的 Hammerspoon 安装在其他位置,请将 HS_MCP_HS_PATH 设置为二进制文件的绝对路径。请注意,通过图形界面启动的 MCP 客户端通常只有精简的 PATH,其中不包含 Homebrew,因此在终端中可用的路径对服务来说可能无效。如有疑问,请设置该变量。

Hammerspoon 未运行。 hs CLI 是客户端,需要 Hammerspoon 应用运行后才能与其通信。启动 Hammerspoon,然后重试。

未加载 hs.ipc。 Hammerspoon 正在运行,但没有响应,或者 hs 二进制文件根本不存在。这两种情况通常都意味着 ~/.hammerspoon/init.lua 中缺少 require("hs.ipc")。添加该语句,从菜单栏图标重新加载配置,然后在终端中运行 hs -c "return 1 + 1" 检查。

客户端的工具列表中缺少工具。 如果缺少的是 hs_eval,说明默认层级正在按预期工作。在客户端的服务配置中设置 HS_MCP_TOOLS=all,然后重启客户端,让服务在新环境下重新启动。

工具超时。 Hammerspoon 是单线程的。如果配置陷入循环,或模态对话框阻塞了运行,调用就不会返回。使用 hs_console_tail 检查控制台,或重新加载配置。

开发

git clone https://github.com/vukvukovich/hammerspoon-mcp.git
cd hammerspoon-mcp
npm install
脚本功能
npm run build使用 tsc 将 TypeScript 编译到 dist/。
npm run typecheck对所有内容进行类型检查,不生成输出。
npm run lintESLint。
npm run lint:fix使用自动修复运行 ESLint。
npm run format使用 Prettier 格式化并写入。
npm run format:check仅使用 Prettier 检查格式。
npm test单元测试(Vitest)。
npm run test:watch以监视模式运行单元测试。
npm run test:coverage运行单元测试并生成覆盖率报告。
npm run test:integration集成测试。需要真实运行的 Hammerspoon。
npm run checkCI 运行的全部检查:类型检查、lint、格式检查、测试。

技术栈:严格模式下的 TypeScript 5.9、仅限 ESM、Node 24+、@modelcontextprotocol/server v2 SDK、用于架构定义的 Zod v4、Vitest 4,以及搭配 Prettier 3 的 typescript-eslint 8。使用纯 tsc 构建,不使用打包工具。

贡献前,请阅读 CONVENTIONS.md(约束性规则)和 CONTRIBUTING.md(工作流和提交格式)。设计说明见 docs/ARCHITECTURE.md。

许可证

MIT。版权所有 (c) 2026 Vuk Vukovich。详见 LICENSE。

Hammerspoon 是一个独立项目,拥有自己的许可证,与本项目无关。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。