化控制電腦的一切操作:用MCP打通macOS桌面自動(dòng)化的配置骨架)
1. 為什么我決定在 macOS 上折騰 MCP 桌面自動(dòng)化MCPModel Context Protocol是讓大語(yǔ)言模型標(biāo)準(zhǔn)化調(diào)用外部工具的開放協(xié)議你可以把它理解成 AI 的「USB-C 接口」——模型本身只會(huì)思考和輸出文本接上 MCP 之后它才真正長(zhǎng)出「手和眼」能讀寫文件、控制應(yīng)用、執(zhí)行系統(tǒng)命令。macOS 桌面自動(dòng)化則是把這套能力落到本地讓 AI 幫你整理桌面、調(diào)整窗口、批量重命名、定時(shí)觸發(fā)腳本。適合誰(shuí)適合已經(jīng)用過(guò) Cursor、Claude Desktop 這類客戶端想讓 AI 從「聊天框」走進(jìn)「真實(shí)桌面」的開發(fā)者尤其是手里有一堆重復(fù)操作想交給 AI 的人。我試過(guò)純 AppleScript 寫自動(dòng)化痛點(diǎn)很明顯腳本要一行行手寫改一個(gè)邏輯就得重調(diào)語(yǔ)法而且 AI 沒法直接理解你的意圖。MCP 的價(jià)值在于把「意圖 → 工具調(diào)用 → 系統(tǒng)執(zhí)行」這條鏈路標(biāo)準(zhǔn)化了。你只需要在配置文件里聲明有哪些工具可用AI 就能根據(jù)自然語(yǔ)言自己決定調(diào)哪個(gè)、傳什么參數(shù)。macOS 本身有 AppleScript 和 JXAJavaScript for Automation兩套原生自動(dòng)化能力MCP 服務(wù)器只要把它們包一層AI 就能間接操控整個(gè)桌面。這篇不聊虛的直接給你兩份能跑的配置骨架config.toml和settings.json再走一遍從配置到觸發(fā)桌面動(dòng)作的完整驗(yàn)證流程。目標(biāo)很明確——你照著填完能親眼看到 AI 讓 Finder 彈出一個(gè)窗口或者讓某個(gè) App 執(zhí)行一次操作。2. TaoToken 前置把模型調(diào)用這層先打通MCP 負(fù)責(zé)「AI 調(diào)工具」但 AI 本身得先能跑起來(lái)。如果你用的是本地模型或者已經(jīng)配好的客戶端這步可以跳過(guò)如果你希望用云端模型驅(qū)動(dòng)整個(gè)自動(dòng)化流程就需要一個(gè)穩(wěn)定的模型接入層。TaoToken 在這里的角色是提供兼容 OpenAI 風(fēng)格的 API 入口讓客戶端能統(tǒng)一調(diào)用不同模型不用為每個(gè)模型單獨(dú)改代碼。官網(wǎng)地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。注意 API 地址不帶 UTM 參數(shù)配置里填這個(gè)就行。你需要先拿到 API Key。進(jìn)入控制臺(tái)創(chuàng)建密鑰https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 然后在 API Keys 頁(yè)面生成https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。生成后復(fù)制那串sk-開頭的字符串后面配置里要用。如果你還沒決定用哪個(gè)模型可以先在模型對(duì)話頁(yè)面試一下https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。對(duì)于桌面自動(dòng)化這種需要理解工具 schema、生成結(jié)構(gòu)化調(diào)用的場(chǎng)景建議選指令遵循能力強(qiáng)的模型不然它可能把參數(shù)傳錯(cuò)。注意API Key 只顯示一次生成后立刻保存到本地密碼管理器或環(huán)境變量里別直接寫進(jìn)會(huì)提交到 Git 的配置文件。3. 可復(fù)制配置config.toml 與 settings.json 骨架MCP 的配置分兩層一層是 MCP 服務(wù)器自己的config.toml聲明這個(gè)服務(wù)器提供哪些工具、每個(gè)工具的參數(shù) schema另一層是客戶端的settings.json告訴客戶端去哪里啟動(dòng)這個(gè)服務(wù)器、用什么命令。下面兩份骨架你可以直接復(fù)制改。3.1 config.toml聲明 macOS 桌面工具這份配置定義了一個(gè)名為macos-desktop的 MCP 服務(wù)器暴露三個(gè)工具open_app打開應(yīng)用、move_file移動(dòng)文件、resize_window調(diào)整窗口大小。每個(gè)工具的參數(shù)用 JSON Schema 描述AI 會(huì)根據(jù)這個(gè) schema 生成調(diào)用參數(shù)。# config.toml - macOS 桌面自動(dòng)化 MCP 服務(wù)器配置 [server] name macos-desktop version 0.1.0 description 通過(guò) AppleScript 控制 macOS 桌面操作 [server.transport] type stdio # 本地進(jìn)程通信用 stdio最省事 [[tools]] name open_app description 打開指定的 macOS 應(yīng)用程序 [tools.input_schema] type object properties.app_name { type string, description 應(yīng)用名稱如 Safari、Finder } required [app_name] [[tools]] name move_file description 把文件從源路徑移動(dòng)到目標(biāo)目錄 [tools.input_schema] type object properties.source { type string, description 源文件絕對(duì)路徑 } properties.target_dir { type string, description 目標(biāo)目錄絕對(duì)路徑 } required [source, target_dir] [[tools]] name resize_window description 調(diào)整指定應(yīng)用主窗口的尺寸 [tools.input_schema] type object properties.app_name { type string, description 應(yīng)用名稱 } properties.width { type integer, description 寬度像素 } properties.height { type integer, description 高度像素 } required [app_name, width, height]這份 TOML 的關(guān)鍵點(diǎn)是transport.type stdio。本地 MCP 服務(wù)器最常用的就是標(biāo)準(zhǔn)輸入輸出通信客戶端啟動(dòng)一個(gè)子進(jìn)程通過(guò) stdin/stdout 交換 JSON-RPC 消息。你不需要開端口也不需要處理網(wǎng)絡(luò)鑒權(quán)進(jìn)程生命周期由客戶端管理。3.2 settings.json客戶端接入配置客戶端這邊以常見的 MCP 客戶端配置格式為例在settings.json里加一段mcpServers。這里假設(shè)你的服務(wù)器啟動(dòng)命令是node /Users/you/mcp-macos/server.js實(shí)際路徑按你的項(xiàng)目改。{ mcpServers: { macos-desktop: { command: node, args: [/Users/you/mcp-macos/server.js], env: { TAOTOKEN_API_KEY: sk-你的密鑰, TAOTOKEN_BASE_URL: https://taotoken.net/api } } } }如果你用的是 Python 寫的服務(wù)器把command改成python3args改成腳本路徑即可。env里放 API Key 是為了讓服務(wù)器內(nèi)部在需要調(diào)用模型做二次判斷時(shí)能直接讀取比如「根據(jù)文件內(nèi)容決定移到哪個(gè)目錄」這種需要語(yǔ)義理解的場(chǎng)景。注意settings.json如果放在項(xiàng)目目錄里記得加進(jìn).gitignore別把 Key 提交上去。更穩(wěn)妥的做法是用系統(tǒng)環(huán)境變量配置里只寫變量名。3.3 服務(wù)器端最小實(shí)現(xiàn)骨架配置文件只是聲明真正執(zhí)行動(dòng)作的是服務(wù)器代碼。下面是一個(gè) Node.js 最小骨架用child_process調(diào) AppleScript 實(shí)現(xiàn)open_app和resize_window。// server.js - 最小 MCP 服務(wù)器骨架 const { exec } require(child_process); const readline require(readline); const rl readline.createInterface({ input: process.stdin }); function runAppleScript(script) { return new Promise((resolve, reject) { exec(osascript -e ${script}, (err, stdout) { if (err) reject(err); else resolve(stdout.trim()); }); }); } const tools { open_app: async ({ app_name }) { await runAppleScript(tell application ${app_name} to activate); return 已打開 ${app_name}; }, resize_window: async ({ app_name, width, height }) { const script tell application ${app_name} to set bounds of front window to {0, 0, ${width}, ${height}}; await runAppleScript(script); return ${app_name} 窗口已調(diào)整為 ${width}x${height}; }, }; rl.on(line, async (line) { const msg JSON.parse(line); if (msg.method tools/call) { const { name, arguments: args } msg.params; const result await tools[name](args); process.stdout.write(JSON.stringify({ id: msg.id, result }) \n); } });這段代碼只處理了tools/call真實(shí)場(chǎng)景還要處理tools/list、初始化握手等但作為驗(yàn)證骨架夠用了。重點(diǎn)是讓你看到MCP 服務(wù)器本質(zhì)就是一個(gè)「收到 JSON-RPC 請(qǐng)求 → 執(zhí)行本地操作 → 返回結(jié)果」的進(jìn)程。4. 驗(yàn)證請(qǐng)求從配置到觸發(fā)一次桌面動(dòng)作配置寫完怎么確認(rèn)它真的通了分三步走。4.1 先單獨(dú)測(cè)服務(wù)器進(jìn)程在終端里直接跑服務(wù)器手動(dòng)喂一條 JSON-RPC 請(qǐng)求看它能不能正確調(diào) AppleScript。echo {id:1,method:tools/call,params:{name:open_app,arguments:{app_name:Finder}}} | node server.js如果 Finder 被激活到前臺(tái)終端輸出類似{id:1,result:已打開 Finder}說(shuō)明服務(wù)器本身沒問(wèn)題。這一步排除了 AppleScript 權(quán)限和路徑問(wèn)題。4.2 再測(cè)客戶端能否拉起服務(wù)器重啟你的 MCP 客戶端在對(duì)話里輸入「幫我打開 Finder 并把窗口調(diào)整到 800x600」。觀察客戶端日志里有沒有macos-desktop服務(wù)器的啟動(dòng)記錄。如果客戶端報(bào)「server not found」八成是settings.json路徑寫錯(cuò)或者command不在 PATH 里。4.3 完整鏈路驗(yàn)證當(dāng)客戶端能列出macos-desktop的工具列表并且 AI 在收到「打開 Safari」時(shí)生成了open_app調(diào)用整條鏈路就通了。你會(huì)在客戶端里看到工具調(diào)用卡片點(diǎn)開能看到參數(shù)和返回結(jié)果。如果想讓驗(yàn)證更直觀可以加一個(gè)move_file工具讓 AI 把桌面上的某個(gè)測(cè)試文件移到~/Documents/test-archive/。這個(gè)動(dòng)作有明確的文件系統(tǒng)結(jié)果比窗口調(diào)整更容易確認(rèn)。提示第一次運(yùn)行 AppleScript 控制其他應(yīng)用時(shí)macOS 會(huì)彈權(quán)限請(qǐng)求去「系統(tǒng)設(shè)置 → 隱私與安全性 → 自動(dòng)化」里勾選允許。這一步不勾腳本會(huì)靜默失敗。5. 本篇常見錯(cuò)排查5.1 AppleScript 報(bào)「不允許發(fā)送事件」這是 macOS 自動(dòng)化權(quán)限沒給。終端或你的客戶端進(jìn)程需要在「隱私與安全性 → 自動(dòng)化」里被授權(quán)控制目標(biāo)應(yīng)用。如果列表里沒有你的進(jìn)程先手動(dòng)觸發(fā)一次操作系統(tǒng)會(huì)彈窗詢問(wèn)。5.2 MCP 服務(wù)器啟動(dòng)后立刻退出常見原因是readline沒保持進(jìn)程存活或者 stdin 被關(guān)閉。檢查你的服務(wù)器代碼有沒有在rl.on(line)之外的地方調(diào)用了process.exit()。另外客戶端如果配置了stdio但服務(wù)器往 stdout 打了非 JSON 的日志也會(huì)導(dǎo)致解析失敗退出。日志一律走 stderr。5.3 工具調(diào)用參數(shù)類型不對(duì)AI 生成的參數(shù)可能把width傳成字符串800而不是整數(shù)800。在服務(wù)器端做一層類型轉(zhuǎn)換或者在 schema 里寫清楚type: integer。實(shí)測(cè)下來(lái)schema 描述越具體模型傳錯(cuò)的概率越低。5.4 路徑含空格導(dǎo)致 AppleScript 失敗move_file如果直接用osascript -e拼路徑遇到帶空格的目錄名會(huì)斷掉。解決辦法是用quoted form of包路徑或者改用 JXA 傳參數(shù)數(shù)組。這是踩過(guò)的坑里最常見的一個(gè)。5.5 客戶端讀不到 settings.json不同客戶端的配置文件名和位置不一樣。有的讀項(xiàng)目根目錄的.mcp.json有的讀用戶目錄下的settings.json。先確認(rèn)你的客戶端文檔里寫的加載路徑別放錯(cuò)地方。6. 接下來(lái)怎么走按場(chǎng)景選入口配置跑通之后下一步取決于你想拿它做什么。如果你主要卡在接入和排障上比如服務(wù)器起不來(lái)、工具列表讀不到、AppleScript 權(quán)限反復(fù)彈窗建議先把 API Key 和接入文檔過(guò)一遍API Keys 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 接入文檔在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。文檔里有完整的請(qǐng)求格式和錯(cuò)誤碼說(shuō)明比在客戶端日志里猜快得多。如果你想先驗(yàn)證模型對(duì)工具調(diào)用的理解能力不想一上來(lái)就配服務(wù)器可以直接在模型對(duì)話里試https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。把工具 schema 貼進(jìn)去看模型能不能正確生成調(diào)用參數(shù)這一步能幫你篩掉不合適的模型。如果你打算把桌面自動(dòng)化做成長(zhǎng)期跑的編碼或 Agent 工作流比如讓 AI 持續(xù)監(jiān)控某個(gè)目錄、自動(dòng)整理文件、定時(shí)觸發(fā)腳本那 Coding Plan 更合適https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它針對(duì)長(zhǎng)會(huì)話和工具調(diào)用場(chǎng)景做了優(yōu)化不用每次手動(dòng)拼請(qǐng)求。最后補(bǔ)一個(gè)實(shí)用技巧把常用的 AppleScript 片段封裝成獨(dú)立工具而不是讓 AI 每次現(xiàn)寫腳本。工具越原子AI 組合起來(lái)越穩(wěn)。比如open_app、move_file、resize_window這三個(gè)拆開比一個(gè)「幫我整理桌面」的大工具可靠得多。