如何為 Claude 建立本地 MCP Server:檔案操作、指令執行、螢幕截圖與應用程式控制

@hrswatigupta
英語1 個月前 · 2026年6月04日
1.0M
72
16
2
224

TL;DR

本指南示範如何為 Claude 建立基於 Python 的本地 MCP Server,透過安全的白名單架構,實現對本地檔案、指令與桌面工具的安全且受控的存取。

Claude 一旦不再只是純聊天介面,它的實用性就會大幅提升。

本機 MCP 伺服器能讓 Claude 與你的實際機器互動:讀取本機檔案、執行經核准的指令、擷取螢幕截圖、啟動應用程式。關鍵不在於原始存取權限,而在於受控的存取權限。

在這份指南中,我們將為 Claude 建立一個實用、範圍明確且足夠安全,能應用於真實工作流程的本機 MCP 伺服器。

在開始建構之前,先提個重點

本文刻意避開了不負責任的「電腦控制」版本。

我們打算給 Claude 無限制的 shell 存取權、完整的檔案系統權限,或是在沒有防護措施的情況下讓它任意修改你的電腦。建立糟糕的本機 MCP 伺服器最快的方法,就是暴露一個巨大的 run_anything() 工具,然後稱之為創新。

更好的模式是:

  • 允許清單中的目錄
  • 允許清單中的指令
  • 安全預設值
  • 人類可讀的日誌
  • 明確的回應
  • 唯讀與操作型工具之間有清楚的區隔

如果 Claude 什麼都能做,你只是做出了展示品。

如果 Claude 能安全地做對的事情,你才做出了可用的工具。

為什麼這種架構值得學習

本機 MCP 伺服器的價值不在於新奇,而在於減少摩擦。

如果沒有本機工具層,你的工作流程會像這樣:

  1. 問 Claude 要怎麼做
  2. 複製答案
  3. 自己打開資料夾
  4. 自己執行指令
  5. 自己擷取螢幕截圖
  6. 把結果貼回對話框

有了本機 MCP 伺服器,這個循環就能大幅縮短。Claude 可以檢查它需要的上下文,使用範圍狹窄的工具,並根據你實際的機器狀態提供答案。

這在以下情境中非常實用:

  • 開發工作流程
  • 日誌檢查
  • 內容運營
  • 研究流程
  • 桌面自動化
  • 可重複的管理任務

而且因為工具層是你的,你可以精準選擇模型在哪裡停止。

想要學習 AI 並在職涯中保持領先嗎?

我分享:

1,000 多個 AI 提示詞

AI 工具與自動化

職涯與 LinkedIn 成長技巧

精選科技與生產力資源

在此訂閱:

https://bytebuilders.beehiiv.com/subscribe

追蹤我以獲得更多 AI 技巧

👇

我們要建立的設計

Swati Gupta - inline image

我們將建立一個包含五個工具的本機伺服器:

  1. list_files — 查看核准資料夾內有哪些內容
  2. read_file — 開啟安全的文字檔案
  3. run_command — 執行一組經過核准的本機指令
  4. take_screenshot — 將螢幕截圖儲存到指定位置
  5. open_target — 開啟應用程式、檔案、資料夾或網址
Swati Gupta - inline image

這個範圍是刻意設定的。

它足以讓 Claude 在本機機器上發揮實際效用,同時又不至於淪為不安全的一般用途自動化工具。

心智模型應該是這樣:

Claude → MCP 客戶端 → 本機 MCP 伺服器 → 狹窄工具 → 作業系統

Claude 永遠不該直接與你的作業系統對話。你的 MCP 伺服器是中間的控制層。

技術棧

對於本機建置,Python 是個乾淨的選擇,因為官方 MCP SDK 已成熟、FastMCP 抽象層簡潔,而且 Python 仍然是處理檔案系統、子程序和桌面腳本最簡單的語言 4 2

我們將使用:

  • Python 3.11+
  • mcp[cli] 作為 MCP 伺服器執行環境
  • mss 用於跨平台螢幕截圖
  • 標準函式庫模組用於檔案存取、子程序呼叫和作業系統處理

建立一個新專案:

bash
1mkdir local-mcp-server
2cd local-mcp-server
3uv init --python 3.11
4uv add "mcp[cli]>=1.0,<2.0" "mss>=9.0,<10.0"

基於裝飾器的 FastMCP 風格能讓你避開協定層的繁瑣,專注於工具品質,而不是連線配置 4 5

一個簡單的專案結構就很好用:

text
1mkdir local-mcp-server
2cd local-mcp-server
3uv init --python 3.11
4uv add "mcp[cli]>=1.0,<2.0" "mss>=9.0,<10.0"

v1 不需要複雜的架構。你需要的是清晰度。

實際的伺服器程式碼

建立 server.py 並從基於政策的實作開始。

python
1from __future__ import annotations
2
3import json
4import os
5import platform
6import shlex
7import subprocess
8from pathlib import Path
9from typing import Any
10
11import mss
12from mcp.server.fastmcp import FastMCP
13
14app = FastMCP("local-computer-control", json_response=True)
15
16HOME = Path.home()
17PROJECT_ROOT = Path(__file__).parent.resolve()
18CAPTURE_DIR = PROJECT_ROOT / "captures"
19CAPTURE_DIR.mkdir(exist_ok=True)
20
21ALLOWED_ROOTS = [
22 HOME / "Documents",
23 HOME / "Desktop",
24 PROJECT_ROOT,
25]
26
27ALLOWED_COMMANDS = {
28 "pwd",
29 "ls",
30 "git status",
31 "git diff --stat",
32 "python --version",
33 "node --version",
34 "npm --version",
35}
36
37READABLE_EXTENSIONS = {
38 ".txt",
39 ".md",
40 ".json",
41 ".py",
42 ".js",
43 ".ts",
44 ".tsx",
45 ".jsx",
46 ".yaml",
47 ".yml",
48 ".toml",
49 ".csv",
50 ".log",
51}
52
53def _resolve_path(raw_path: str) -> Path:
54 path = Path(raw_path).expanduser().resolve()
55 for root in ALLOWED_ROOTS:
56 root = root.resolve()
57 if path == root or root in path.parents:
58 return path
59 raise ValueError(f"不允許的路徑:{path}")
60
61def _ensure_safe_command(command: str) -> str:
62 normalized = " ".join(shlex.split(command))
63 if normalized not in ALLOWED_COMMANDS:
64 raise ValueError(
65 "指令不被允許。如果你真的需要,請手動將其加入 ALLOWED_COMMANDS。"
66 )
67 return normalized
68
69@app.tool()
70def list_files(path: str = "~") -> dict[str, Any]:
71 """列出核准目錄中的檔案與資料夾。"""
72 target = _resolve_path(path)
73 if not target.is_dir():
74 raise ValueError(f"不是目錄:{target}")
75
76 items = []
77 for child in sorted(target.iterdir(), key=lambda p: (not p.is_dir(), p.name.lower())):
78 items.append(
79 {
80 "name": child.name,
81 "path": str(child),
82 "type": "directory" if child.is_dir() else "file",
83 }
84 )
85
86 return {
87 "path": str(target),
88 "count": len(items),
89 "items": items,
90 }
91
92@app.tool()
93def read_file(path: str, max_chars: int = 12000) -> dict[str, Any]:
94 """從核准位置讀取安全的文字檔案。"""
95 target = _resolve_path(path)
96 if not target.is_file():
97 raise ValueError(f"不是檔案:{target}")
98 if target.suffix.lower() not in READABLE_EXTENSIONS:
99 raise ValueError(f"不支援的檔案類型:{target.suffix}")
100
101 content = target.read_text(encoding="utf-8", errors="replace")
102 truncated = len(content) > max_chars
103 content = content[:max_chars]
104
105 return {
106 "path": str(target),
107 "truncated": truncated,
108 "content": content,
109 }
110
111@app.tool()
112def run_command(command: str, cwd: str | None = None, timeout: int = 15) -> dict[str, Any]:
113 """執行一個核准的本機指令。"""
114 safe_command = _ensure_safe_command(command)
115 working_dir = _resolve_path(cwd) if cwd else PROJECT_ROOT
116
117 completed = subprocess.run(
118 safe_command,
119 shell=True,
120 cwd=str(working_dir),
121 capture_output=True,
122 text=True,
123 timeout=timeout,
124 )
125
126 return {
127 "command": safe_command,
128 "cwd": str(working_dir),
129 "returncode": completed.returncode,
130 "stdout": completed.stdout.strip(),
131 "stderr": completed.stderr.strip(),
132 }
133
134@app.tool()
135def take_screenshot(name: str = "latest") -> dict[str, Any]:
136 """擷取螢幕截圖並儲存到本機。"""
137 output_path = CAPTURE_DIR / f"{name}.png"
138
139 with mss.mss() as sct:
140 sct.shot(output=str(output_path))
141
142 return {
143 "saved": True,
144 "path": str(output_path),
145 }
146
147@app.tool()
148def open_target(target: str) -> dict[str, Any]:
149 """使用本機作業系統開啟核准的檔案、資料夾、應用程式或網址。"""
150 system = platform.system().lower()
151
152 if target.startswith("http://") or target.startswith("https://"):
153 resolved = target
154 else:
155 resolved = str(_resolve_path(target))
156
157 if system == "darwin":
158 subprocess.run(["open", resolved], check=True)
159 elif system == "windows":
160 os.startfile(resolved) # type: ignore[attr-defined]
161 else:
162 subprocess.run(["xdg-open", resolved], check=True)
163
164 return {
165 "opened": True,
166 "target": resolved,
167 }
168
169if __name__ == "__main__":
170 app.run(transport="stdio")

這是一個精簡的伺服器,但重點不在於它有多短,而在於介面的形狀:

  • 每個工具都有非常明確的職責
  • 每個工具都回傳結構化資料
  • 指令執行受到管控
  • 檔案存取有根目錄限制
  • 螢幕截圖會儲存到已知的資料夾

這正是你希望在本機 MCP 伺服器中看到的。

為什麼這些工具要這樣設計

關於代理工具的高階內容絕對不該只停留在「這裡是程式碼」。工具的設計形狀才是真正的學問。

list_files

這個工具讓 Claude 擁有安全的探索空間。它應該能夠回答像這樣的問題:

  • 這個專案資料夾裡有什麼?
  • Documents 裡有哪些筆記?
  • 有沒有我可以檢查的日誌檔案?

但它不該變成一個遞迴的全磁碟爬蟲。

read_file

這通常是最實用的本機工具。大量真實工作仍然藏在本機的 Markdown 筆記、日誌、CSV、文件和專案檔案中。

max_chars 上限很重要。大型檔案會造成上下文與延遲問題。回傳整個巨大日誌檔的內容很少有意義。

run_command

這是大多數人最容易草率處理的地方。

安全的模式不是「允許 shell 存取,然後祈禱沒事」。安全的模式是「允許一組經過審查的精準指令」。這就是為什麼範例使用嚴格的允許清單。

take_screenshot

螢幕截圖工具很有價值,因為它能讓 Claude 參與桌面工作流程。即使你的第一個版本只將圖片儲存到磁碟,這對報告、UI 除錯、文件擷取和結構化交接來說已經很有用。

open_target

應用程式控制不需要從 GUI 自動化開始。對許多工作流程來說,「開啟正確的資料夾、檔案或網址」就足夠了。

這比假設你第一天就需要完整滑鼠游標自動化更耐久。

將伺服器連接到 Claude

本機 MCP 伺服器通常透過 stdio 執行,這表示 Claude 會在本機啟動程序,並直接透過 stdin/stdout 與之通訊。對於本機電腦控制伺服器來說,這是正確的預設選項,因為它能避免不必要的網路暴露 4 5

Claude Desktop 透過設定支援本機 MCP 伺服器,它會幫你啟動伺服器程序。實務上,使用直譯器和腳本的絕對路徑是最不容易出錯的設定方式,因為本機 GUI 應用環境通常比你的終端機更嚴格 2

一個最簡設定範例如下:

json
1{
2 "mcpServers": {
3 "local-computer-control": {
4 "command": "/absolute/path/to/python",
5 "args": [
6 "/absolute/path/to/local-mcp-server/server.py"
7 ]
8 }
9 }
10}

如果你偏好使用 uv,那也沒問題:

json
1{
2 "mcpServers": {
3 "local-computer-control": {
4 "command": "/absolute/path/to/uv",
5 "args": [
6 "--directory",
7 "/absolute/path/to/local-mcp-server",
8 "run",
9 "python",
10 "server.py"
11 ]
12 }
13 }
14}

儲存設定並重新啟動 Claude 後,伺服器工具應該會出現在本機 MCP 工具清單中。Claude Desktop 的本機 MCP 設定正是基於這個模型:啟動一個本機程序,透過 stdio 連接,然後將工具暴露給模型 2 3

Swati Gupta - inline image

實際有用的測試提示詞

伺服器連接好之後,不要一開始就進行複雜的編排。從直接、基本的功能檢查開始。

試著使用這些提示詞:

  • 「列出我桌面資料夾中的檔案。」
  • 「讀取 ~/Documents/todo.md 並總結前三項優先事項。」
  • 「在我的本機專案資料夾中執行 git status,並解釋有哪些變更。」
  • 「拍一張名為 workspace-check 的螢幕截圖。」
  • 「開啟我的專案 README。」

如果這些簡單的流程都能穩定運作,你就擁有一個值得擴展的伺服器。

如果不能,添加更多工具只會掩蓋真正的問題。

本機 MCP 伺服器真正有價值的地方

最明顯的用途是開發,但那只是其中一環。

開發者工作流程

Claude 可以:

  • 檢查儲存庫資料夾
  • 讀取設定檔
  • 執行 git status
  • 擷取錯誤狀態的螢幕截圖
  • 開啟專案目錄

這已經消除了大量的上下文切換。

研究流程

Claude 可以:

  • 列出研究資料夾
  • 開啟並總結 Markdown 筆記
  • 讀取結構化的 CSV
  • 儲存來自工具或儀表板的螢幕截圖
  • 開啟原始碼檔案或瀏覽器連結

內容工作流程

Claude 可以:

  • 掃描草稿資料夾
  • 讀取現有的文章點子
  • 擷取設計參考的螢幕截圖
  • 開啟正確的寫作檔案或網址
  • 執行有限的指令來產生構建產物或草稿匯出

運維工作流程

Claude 可以:

  • 從核准目錄檢查日誌
  • 執行唯讀診斷指令
  • 開啟相關資料夾或儀表板連結
  • 儲存證據截圖

這就是這個架構的真正重點:不是作為噱頭的「電腦控制」,而是工作流程壓縮

安全性層就是產品本身

這是太多技術文章輕描淡寫的部分。

本機 MCP 的危險之處不在於協定,而在於糟糕的權限設計。

如果你希望這個伺服器在展示之外還能實際使用,請儘早建立安全模型。

Swati Gupta - inline image

使用目錄允許清單

Claude 只能看到你明確核准的路徑。這就是為什麼 _resolve_path() 是檔案工具的核心。

使用指令允許清單

永遠不要在初版暴露任意 shell 執行。從你能逐行審計的精準指令開始。

區分唯讀工具與操作型工具

唯讀工具應該是預設值。操作型工具應該經過審慎引入。

記錄所有操作

即使是簡單的附加式 JSON 日誌,也能大幅提升除錯和信任度。

為寫入操作加入確認層

如果你之後添加了 write_filemove_filedelete_file,請讓這些工具要麼需要第二次確認權杖,要麼保持預設禁用。

考慮乾執行模式

對於操作型工具,乾執行模式常被低估。它能讓 Claude 在實際執行之前說明它打算做什麼。

盡可能以受限制的使用者執行

如果你認真對待本機自動化,不要給你的 MCP 伺服器超出必要的作業系統權限。

一個有用的經驗法則:

  • 第 1 級: 唯讀工具
  • 第 2 級: 低風險操作,如開啟檔案 / 開啟應用程式
  • 第 3 級: 需確認的寫入操作
  • 第 4 級: 你不該隨意暴露的破壞性操作

大多數人永遠不需要第 4 級。

Swati Gupta - inline image

v1 之後可以改進的地方

穩固的初版讓你贏得進階能力的機會。

一旦基礎伺服器穩定,接下來合理的升級是:

  1. 集中化政策檔案

將你的規則移至 config/policy.json,讓變更變成宣告式。

範例:

json
1{
2 "allowed_roots": [
3 "~/Documents",
4 "~/Desktop",
5 "./"
6 ],
7 "allowed_commands": [
8 "pwd",
9 "ls",
10 "git status",
11 "git diff --stat",
12 "python --version"
13 ]
14}
  1. 結構化日誌

將工具呼叫、時間戳、引數和結果記錄到 logs/server.log 或 JSONL 檔案。

  1. 更安全的指令執行

不要使用單一的通用指令工具,而是將指令拆分為更狹窄的工具,例如:

  • git_status
  • show_current_directory
  • list_project_files

這能讓 Claude 更容易選擇工具,也讓你更容易確保安全。

  1. 更好的螢幕截圖處理

你可以從「將螢幕截圖儲存到磁碟」進化為:

  • 時間戳記擷取
  • 作用中視窗擷取
  • 區域擷取
  • 檔案保留規則
  1. 特定作業系統的自動化轉接器

在 macOS 上,你之後可以加入 AppleScript 或 Shortcuts。在 Windows 上,加入 PowerShell 或 UI Automation。在 Linux 上,加入桌面特定的啟動器和視窗工具。

但這些應該等到基礎的本機核心可靠之後再進行。

人們在使用本機 MCP 伺服器時常犯的錯誤

這些錯誤是可以預測的。

錯誤 1:權限給得太早、太多

人們喜歡完全控制電腦的想法,但痛恨除錯的過程。從更小的範圍開始。

錯誤 2:工具名稱含糊不清

如果你的工具名稱不明確,Claude 就會用得很糟。請明確命名。

糟糕的例子:

  • system_action
  • computer_control

更好的例子:

  • list_files
  • read_file
  • run_command
  • take_screenshot
  • open_target

錯誤 3:非結構化輸出

一團混雜的文字比乾淨的 JSON 物件更難讓 Claude 進行推理。

錯誤 4:沒有日誌

如果工具失敗了而你無法得知原因,系統就會變成猜謎遊戲。

錯誤 5:將模型當作控制層

Claude 是推理層。你的伺服器仍然必須是執行層。

這個區別不容妥協。

這種架構比純自動化更好的地方

傳統的桌面自動化通常是以下兩種之一:

  • 脆弱的 GUI 腳本
  • 需要人類精準知道何時執行的孤立腳本

本機 MCP 伺服器改變了這一點,因為 Claude 可以根據使用者的請求和可用上下文來決定使用哪個工具。

這意味著你不只是在自動化一個指令。你是在建立一個模型可以推理的本機能力層。

這就是為什麼 MCP 讓人覺得重要。它不僅僅是另一個整合模式。它是一種更乾淨的方式,將工具使用暴露給模型,而無需在應用層硬編碼每一種可能的工作流程。

你應該尊重的限制

即使是一個好的本機 MCP 伺服器也有實際的限制。

  • 桌面自動化在不同的作業系統上可能不穩定。
  • 螢幕截圖很有用,但並非萬能。
  • 啟動應用程式很容易,可靠的 UI 操縱更困難。
  • 通用的 shell 存取很危險。
  • 如果工具輸出過大,上下文膨脹是真實問題。
  • 對於任何重要的事項,人類審批仍然很有價值。

換句話說:不要混淆「模型可以執行動作」和「模型應該在沒有監管的情況下行動」。

更有價值的模式是協作控制,而不是盲目自主。

一鍵儲存

使用 YouMind AI 深度閱讀爆款文章

保存原文、追問細節、總結觀點,並在一個 AI 工作空間裡把爆款文章沉澱成可複用筆記。

了解 YouMind
寫給創作者

把你的 Markdown 變成乾淨的 𝕏 文章

圖片上傳、表格、程式碼區塊,往 𝕏 上手動重排太痛苦。YouMind 把整篇 Markdown 一鍵轉成乾淨、可直接發佈的 𝕏 文章草稿。

試試 Markdown 轉 𝕏

更多可拆解樣本

近期爆款文章

探索更多爆款文章