ROCKI

LEARN · ARTICLE

自己做一個 MCP 小工具讀寫任務看板

發布 2026-11-09更新 2026-11-09作者 Rock Lee
自己做一個 MCP 小工具讀寫任務看板 封面示意圖

作者:Rock Lee 實測日期:2026-11-09(Asia/Taipei)

為什麼寫這篇

「MCP」最近很常見:Notion、Google、各家 AI 編輯器都說自己支援。但多數介紹停在「MCP 像 AI 的 USB-C」這句比喻,看完還是不知道它實際上在傳什麼。

這篇分兩段。先在自己電腦寫一個很小的 MCP 工具,讓 AI 讀寫一份任務看板,順便把來回傳的原始訊息攤開來看;再用我們平常接好的 Notion MCP,只讀不寫,查我們真實在用的任務看板。最後那段查出一個有點尷尬的結果,也一起寫出來。

AI 助手透過同一種插座接上看板、試算表和文件夾(示意圖,AI 生成)
AI 助手透過同一種插座接上看板、試算表和文件夾(示意圖,AI 生成)

實測環境

項目內容
本機 MCP官方 mcp Python SDK 2.3.0,Python 3.13,stdio 連線
示範看板虛構店家「小潮咖啡」的 Markdown 看板,只讀寫測試副本
Notion MCP我們已授權好的 Notion 連線;本篇只呼叫 fetch、query-data-sources 兩個讀取工具
查證來源modelcontextprotocol.io、Notion 開發者文件(2026-11-09 讀取)

步驟

1. 先搞懂 MCP 在做什麼

官方的定義是:MCP(Model Context Protocol)是一個開源標準,讓 AI 應用連到外部系統,例如檔案、資料庫、搜尋工具。

MCP 官方文件首頁(2026-11-09 擷取)
MCP 官方文件首頁(2026-11-09 擷取)

用白話講,角色只有兩個:

  • MCP server:把某個系統包成幾個「工具」,寫清楚每個工具叫什麼、要什麼參數。
  • MCP client:AI 那一端。它先問 server 有哪些工具,需要時再呼叫,拿回結果給模型看。

模型本身不會連 Notion,是 client 依照 server 公布的工具清單去呼叫。所以「接上 MCP」等於「把一組工具交給 AI 用」,權限給多大,就決定 AI 能做多少事。

2. 寫一個最小的 MCP server

我們用官方 Python SDK 寫了 board_server.py,只有兩個工具:

  • list_tasks(column):列出看板某一欄的卡片
  • add_inbox(task):在 Inbox 加一張卡,回傳新編號
board_server.py 全文:兩個工具,只讀寫測試副本
board_server.py 全文:兩個工具,只讀寫測試副本

工具的說明文字(docstring)會原封不動送給 AI,AI 靠它判斷什麼時候該用哪個工具,所以要寫得像給人看的說明。看板檔案路徑用環境變數指定,預設指向 /tmp 底下的副本,避免一不小心改到正式檔。

3. 用 client 跑一次:列工具、讀、寫

client 用 stdio 把 server 當子程序啟動,接著依序:初始化、列出工具、讀 Doing 欄、新增一張卡、再讀 Inbox 欄。

本機實跑:初始化 0.45 秒,整段 0.58 秒;diff 只多一行(2026-11-09 18:31)
本機實跑:初始化 0.45 秒,整段 0.58 秒;diff 只多一行(2026-11-09 18:31)
動作結果
initialize0.45 秒,協定版本 2025-11-25
tools/list列出 list_tasks、add_inbox
list_tasks(Doing)回 2 張卡
add_inbox回 T-005
檔案 diff只有 Inbox 那一行變了

整段 0.58 秒跑完。用 diff 比對,確認寫入只動到該動的那一行。

4. 把原始訊息攤開來看

為了看清楚 client 和 server 到底在講什麼,我們跳過 SDK,直接把三行 JSON 餵給 server:initialize、notifications/initialized、tools/call。

直接送 JSON-RPC 2.0:server 回報能力,工具結果同時有文字版和結構化版本
直接送 JSON-RPC 2.0:server 回報能力,工具結果同時有文字版和結構化版本

幾個看得到的重點:

  • 格式是 JSON-RPC 2.0,每個請求有 id,回應用同一個 id 對上。
  • 初始化時 server 會說自己有哪些能力(這裡是 tools、resources、prompts)。
  • 工具結果有兩份:content 是給模型讀的文字,structuredContent 是給程式用的結構化資料。

用 SDK 時,這些細節都被包起來了;但遇到問題要除錯時,知道它長這樣很有用。

5. 換成 Notion MCP:先看工具清單

Notion 的 MCP 是官方架好的遠端 server,網址是 https://mcp.notion.com/mcp,用 OAuth 授權。官方文件寫得很直接:授權後,AI 助手可以讀取和更新你在該 workspace 能存取的內容。

Notion 官方的手動設定說明,列出遠端 server 網址(2026-11-09 擷取)
Notion 官方的手動設定說明,列出遠端 server 網址(2026-11-09 擷取)

我們連上的 Notion MCP 今天列出 77 個工具。依名稱粗分,讀取類 39 個;新增、修改、刪除、搬移、發通知類 38 個。

我們的 Notion MCP 工具清單:讀取類與會改動內容的各占一半(2026-11-09)
我們的 Notion MCP 工具清單:讀取類與會改動內容的各占一半(2026-11-09)

一半工具會動到資料。這篇的測試只用兩個讀取工具,寫入類的一個都沒有呼叫。

6. 唯讀查真實看板

我們用 fetch 讀看板資料庫的結構,再用 query-data-sources 跑一段唯讀 SQL,按欄位數卡片數量、找最新建立時間。

唯讀查我們的任務看板:欄位結構與每欄卡片數(ID 已遮)
唯讀查我們的任務看板:欄位結構與每欄卡片數(ID 已遮)

fetch 回來的結構很完整:欄位名稱、型別、下拉選項,甚至日期欄位在 SQL 裡要用 date:截止時間:start 這種寫法,都直接告訴 AI。AI 不用猜欄位名稱,這是 MCP 實用的地方。

結果

  • 本機 MCP:兩個工具、30 多行的程式,讀和寫都通,整段 0.58 秒。寫入有用 diff 確認只改一行。
  • Notion MCP:唯讀查詢成功。看板共 21 張卡(Done 15、Doing 2、Blocked 2、Backlog 2)。
  • 尷尬的發現:最後一張卡建立於 2026-09-07,之後兩個月沒有新卡;本機那份鏡像檔標的更新日是 2026-09-17。看板一開始接得很好,後來任務沒有再同步進去,兩邊都停了。

工具接上去不難,難的是養成固定用它的流程。如果你也打算讓 AI 管看板,建議一開始就決定:哪些事一定要寫進看板、誰負責、多久對一次帳。

踩坑紀錄

  1. 舊教學的 FastMCP 寫法在 SDK 2.x 會直接報錯。 from mcp.server.fastmcp import FastMCP 在 mcp 2.3.0 會丟錯,錯誤訊息說已改名為 MCPServer(from mcp.server.mcpserver import MCPServer)。網路上很多範例還是舊寫法,要不就照新名稱改,要不就把版本鎖在 2 以下。
  2. 在套件資料夾裡執行會撞名。 我們一開始在 SDK 的安裝目錄裡跑 Python,結果出現循環匯入錯誤,因為那裡有個叫 types 的資料夾,蓋掉了 Python 內建模組。換到別的資料夾就好。
  3. 工具結果可能被拆成好幾段。 list_tasks 回傳清單時,SDK 會把每張卡拆成一個 content 區塊。只讀第一個區塊,就會以為只有一張卡。
  4. Notion 的請求有額度。 官方文件說每個工具呼叫都算在一般 API 限額裡;要等 2 秒以內會自動重試一次,再久就直接回 rate_limited 錯誤。請 AI 一次平行做很多事時要留意。
Notion 官方文件:MCP 的請求限制(2026-11-09 讀取)
Notion 官方文件:MCP 的請求限制(2026-11-09 讀取)
  1. 在 Antigravity 裡別直接用內建清單的 Notion。 Notion 文件特別寫了:建議在 Antigravity 用「自訂 server」接 https://mcp.notion.com/mcp,不要用 Antigravity MCP 清單裡預設的 Notion 連接器,因為它用的是已停止維護的舊套件 notion-mcp-server。

常見問題

Q1:MCP 跟一般 API 差在哪? API 是每個服務各自一套,AI 工具要一家一家串。MCP 是一套共同格式:server 用同樣方式公布工具,client 用同樣方式呼叫。這篇的本機 server 和 Notion 的 server 規模差很多,但講的是同一套協定:先初始化、再列工具、再呼叫。

Q2:讓 AI 讀寫 Notion 安全嗎? 看你給多大權限。Notion MCP 授權後能讀寫你看得到的內容,工具裡也有刪除頁面、搬移頁面這類操作。比較穩的做法是:讀取讓 AI 直接做,寫入和刪除前先由人看過再按確認。

Q3:一定要會寫程式才能用 Notion MCP 嗎? 不用。Notion 文件說,最簡單的方式是從你的 AI 助手的連接器(或外掛)清單找到 Notion,跟著畫面授權。自己寫 server 是為了理解原理,或要把自家資料接給 AI 時才需要。

Q4:本機 server 的資料會被傳到哪裡? 用 stdio 時,server 是你電腦上的子程序,訊息只在本機兩個程式之間傳。工具結果會交給你用的 AI 模型處理,那一段要看你用的是哪家服務。

複製這段給你的 AI agent

目標:在本機寫一個最小的 MCP server,讓我理解 MCP 怎麼運作。只用假資料,不連任何雲端服務。

前提與禁止事項:
- 建一個新資料夾和 Python 虛擬環境,安裝官方 mcp 套件(記下版本號)。不要在套件安裝目錄裡執行程式。
- 看板只用一份假的 Markdown 檔,放在 /tmp 底下;不要讀寫我的任何真實檔案。
- 不要連 Notion 或任何遠端 MCP、不要要求我提供金鑰或登入、不要安裝付費服務、不要部署。

步驟:
1. 寫一份假看板(Inbox、Doing、Done 三欄,各 1~2 張卡)。
2. 寫 MCP server,提供兩個工具:list_tasks(column) 讀某欄、add_inbox(task) 在 Inbox 新增一張卡並回傳編號。docstring 用繁體中文寫清楚。
   若 mcp 是 2.x 版,請用 MCPServer,不要用舊的 FastMCP。
3. 寫 client,用 stdio 啟動 server:initialize → tools/list → list_tasks("Doing") → add_inbox("測試卡") → list_tasks("Inbox")。工具結果可能有多個 content 區塊,要全部讀。
4. 另外直接送三行 JSON-RPC(initialize、notifications/initialized、tools/call)給 server,把原始回應貼給我看。
5. 用 diff 比對假看板前後差異。

驗收:client 印出兩個工具名稱、Doing 欄的全部卡片、新卡編號;diff 只有新增那一行;全程沒有任何網路請求。