Skip to main content
Glama

CAKE MCP

CAKE = CAD Automation Knowledge Engine.

把工程圖說讀成結構化資料的 MCP server,給 Claude 用來「看圖」。 .dxf.dwg 都能直接給路徑(DWG 會借本機 CAD 引擎轉檔快取), 沒有 CAD 檔、只有 .pdf 圖說時也讀得到read_pdfrender_pdf)。 工具只給客觀的幾何與文字;領域判讀(鋼筋、梁配筋…)建在它上面、分開呈現。

能拿它做什麼

不是把 DXF 轉成另一種檔案格式,是讓模型能對著圖回答問題、把圖上的東西整理成 你要的形式。你用自然語言問,模型自己決定調哪個工具。

查圖上的某個資訊。「B5-10 這根梁在哪、斷面多少?」「3F 平面圖在這個檔的 哪個位置?」——find_text 定出座標,render_view 只畫那一小塊回來看上下文。 先定位再截圖是主要用法,比整張畫快一個量級。

做文書作業。 門窗表、梁配筋登錄表、數量統計這種原本要人對著圖一格一格抄的 東西:

資料在哪

用什麼撈

圖框標題欄、門窗編號(藏在 INSERT 屬性裡,搜文字撈不到)

get_block_attributes

圖上貼的 Excel、AutoCAD 原生表格、純線條畫的表

read_ole_tablesread_acad_tables

尺寸、跨長

get_dimensions

編號、標籤、任何文字

find_text

資料量大時(上千筆要分群、配對、交叉比對)直接 import tools 寫腳本一次輸出 xlsx,比串一堆工具呼叫快也準——README 後面有寫什麼時候該這樣做。

摸清一個沒看過的檔。 一個 modelspace 常平鋪幾十張圖。 get_document_info(what="frames") 列出所有圖框連同圖名圖號,等於一份圖紙目錄; what="layers" 給每層的物件數、型別分布與文字樣本——圖層名多是 A_1G-1 這種無意義代號,靠樣本內容認用途。

交付。 render_view 出 PNG、export_pdf 出 PDF,都能只框指定範圍或圖層。

只有 PDF、沒有 CAD 檔時。 工程圖說常常只以 PDF 流通——實測某案的鋼筋施工圖 資料夾 180 份 PDF 對 58 份 dwg,其中筏基、地下層四個資料夾一個 dwg 都沒有。 read_pdf(what="pages") 先回逐頁地圖(哪些頁有文字層、哪些只是掃描影像), 有文字層的頁 what="text" 抽出來無損、與解析度無關;掃描頁用 render_pdf 以原生解析度裁一塊來看(整頁縮圖必糊,裁一小塊則一字不差)。 拿得到 .dwg/.dxf 時仍請優先走 CAD 那條路——PDF 沒有圖層、沒有 DIMENSION。

它不替你判讀。 哪個圖層是料單、哪個顏色代表修訂、加鐵標註怎麼算——每張圖、 每家事務所都不一樣。工具只給客觀的幾何與文字,語意一律從這張圖自己的內容推, 不把別張圖的慣例套過來。判讀邏輯建在它上面,跟原始資料分開呈現。

安裝

最省事的方式:把這個 repo 的網址丟給 Claude Code 或 Codex,叫它照 README 裝好並掛上 MCP。 它會自己 clone、建虛擬環境、裝相依、算出絕對路徑寫進設定 檔。下面「接上 client」那關最容易出錯的就是路徑,交給它比人手打穩。

https://github.com/luckyman9487/CAKE
照這個 repo 的 README 把它裝起來,然後掛進我的 MCP 設定

自己動手也可以:

git clone https://github.com/luckyman9487/CAKE.git
cd CAKE
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt

沒有打包成套件,也沒發 PyPI——就是 clone 下來直接跑。

需求

Python

3.13

.dxf

任何作業系統

.dwg 直傳

只有 Windows 原生 + 本機裝了 AutoCAD/相容 CAD 才能用。偵測不到引擎時會回一則說明該怎麼辦的錯誤,不是當掉

WSL

跑得起來,但只剩 DXF——DWG 轉檔要呼叫本機 CAD 引擎(tools/_core/_dwg.py

接上 client

先自己跑一次確認裝好了:

.venv/Scripts/python services/server.py            # stdio 模式,不會有輸出,Ctrl-C 結束
npx @modelcontextprotocol/inspector .venv/Scripts/python services/server.py

底下三種寫法路徑一律用絕對路徑——server 靠 __file__ 推專案根,但 client 啟動它時的工作目錄不保證在專案根。

掛進 Claude Code:

claude mcp add cake -- <.venv 的 python 絕對路徑> <server.py 絕對路徑>

掛進 Claude Desktop(claude_desktop_config.json):

{
  "mcpServers": {
    "cake": {
      "command": "C:\\...\\CAKE\\.venv\\Scripts\\python.exe",
      "args": ["C:\\...\\CAKE\\services\\server.py"]
    }
  }
}

掛進 Codex(~/.codex/config.toml):

[mcp_servers.cake]
command = "<.venv 的 python 絕對路徑>"
args = ["<server.py 絕對路徑>"]
startup_timeout_sec = 30      # 預設 10s,冷開機時不夠
tool_timeout_sec = 600        # 預設約 60s,render/大圖一定會超過

tool_timeout_sec 非調不可:整張 render_viewexport_pdf 約 2 分鐘, 大圖載入也要 3~68 秒。(實際用的時候別畫整張:先 find_text 定位,再帶 region=layers= 只畫那一小塊,畫前就濾掉範圍外實體,快一個量級。)

重開 client 就會看到 14 個工具。不用另外裝 skill 或抄 SOP—— services/workflow.md(四步讀圖流程 + 兩條鐵律)走 MCP 協議的 server instructions,初始化握手時自動送給每一個連上的 client,接上即得。

結構

services/server.py   MCP 協議層——14 個 @mcp.tool(),只轉接,不寫解析邏輯
services/workflow.md 讀圖流程(四步 + 兩鐵律),server 當 instructions 送出
tools/               業務邏輯層(純 Python,不知道 MCP 存在)
  _core/               共用底層:載入/快取(_io)、DWG 轉檔(_dwg)、
                       實體→JSON(_describe)、bbox/near(_geom)、
                       便宜外接框(_bbox,空間過濾的先篩)、
                       分群與相對座標(_cluster)、版面推斷(_layout)、
                       inline 回傳量控(_payload)、取值例外(_errors)
  document/            文件總覽:版本、圖層、配置、範圍、系統變數、外參、圖框
  entity/              幾何物件查詢:線、圓、弧、聚合線…
  semantic/            帶語意的內容:文字、引線註解、標註量測值
  block/               區塊定義、內容與插入屬性(圖框標題欄在這)
  embedded/            內嵌物:OLE Excel 表格、ACAD 原生表格、純線條畫的表
  render/              PNG / PDF 輸出(唯一需要 matplotlib 的分類)
  pdf/                 讀 PDF 圖說:逐頁地圖、文字+座標、原生解析度裁圖
                       (只用 pypdf + Pillow,不需要任何外部光柵器)
scripts/             輔助腳本(AGENTS.md 由 _WORKFLOW 產生,不手抄)
test/                測試套件與測試圖(未進版控,見「測試」)
docs/regulations/    法規參考 PDF(未進版控)

相依方向固定由上往下:各分類 → _core。分類之間只有一條例外—— document 轉接 embedded.tables.list_xrefs(原因見 tools/embedded/__init__.py)。

對外 14 個工具的清單在 tools/__init__.py__all__; 被合併掉的 9 個舊函式仍保留在原分類內(_SUPERSEDED),供回退與測試比對。

同一件事只能有一份實作。 從實體身上取值的邏輯集中在 _core/_describe.py 的共用取值器(text_anchor / dimension_points / mleader_text),專用工具與 describe_entity 都呼叫它,不要各自再寫一份——否則會出現「同一個實體、換個 工具問就換個答案」,而 golden 抓不到(各自都跟自己的基準一致)。

取值失敗收 ATTR_ERRORS,不要收 Exception DXF 的欄位是選用的,取不到很 正常,所以到處都是「try 取值、失敗退回預設」。這種地方一律收 tools/_core/_errors.pyATTR_ERRORS——收 Exception 會連 NameError (名字打錯)、ImportErrorMemoryError 一起吞掉,症狀是欄位安靜消失、回傳 看起來完全正常,正是這個專案最怕的錯法,而且 golden 抓不到(基準是跟著錯的 一起錄的)。真的需要放寬的只有第三方/外部程序的邊界(CAD 引擎、pypdf、 matplotlib),名單與理由寫在 pyproject.tomlper-file-ignorespip install ruff && ruff check . 會擋下新的漏網。

render/ 的 matplotlib 是延後到第一次渲染才 import 的(_load_backend()), 不要改回模組層 import:它佔 server 啟動時間的四分之三,而 14 個工具只有 2 個 用得到,冷開機會撞上某些 client 的 10s 啟動逾時。 (pdf/ 沒有這個問題:pypdf 與 Pillow 都是輕量 import。)

使用指引放哪裡

放在工具的 docstring,不要另外寫 SOP 文件。

docstring 是掛上 MCP 後唯一會自動進入模型 context 的說明;另寫的 skill/ 指南要靠被觸發,而且是工具行為的副本——工具一改就默默過期,golden 測試也 守不到 markdown。實際踩過:一份剛寫好的 SOP 在一小時內就有兩處變成假的 (「find_text 不支援 layer/bbox」、「世界座標 = 插入點 + 局部座標」,後者 沒算 scale,實測差 7996 個單位)。

反過來說,領域判讀知識(梁怎麼讀、斷筋點怎麼算、加鐵標註的意思)該寫成 skill——那不是工具行為的副本,工具再改也不會讓它過期。

docstring 的正本在 tools/server.py 只用 @_doc_from(dxf.x) 借過去, 不要在 wrapper 手寫第二份——兩份會各改各的漂掉。@_doc_from 必須放在 @mcp.tool() 下面(先執行),FastMCP 在裝飾當下就抓 __doc__ 當工具描述。

跨工具的讀圖流程services/workflow.md(server.py 讀進來當 MCP 握手的 server instructions),Claude Code 與 Codex 都收得到,專案裡不必再放一份 AGENTS.md。哪天遇到不吃 instructions 的 client,用 scripts/gen_agents_md.py 產一份,不要手抄--check 可驗有沒有漂)。

它是散文不是程式碼,所以獨立成一個 .md——夾在 server.py 中間會佔掉那個檔案 三分之一,改一句流程就得動 Python 檔。

什麼時候該繞過 MCP 直接寫腳本

MCP 工具是「一問一答」用的。這些情況直接用 .venv/Scripts/python import tools,比串一堆工具呼叫快也準:

  • 對上萬筆資料做統計、分群、交叉比對(回傳量與 context 都吃不消)

  • 兩兩配對的邏輯:文字按 x 連續性切群、跟最近的標註配對、算相對位移

  • 一次輸出整張表(存 xlsx,別用 markdown 直出)

import sys
sys.path.insert(0, r"<專案根>")
import tools as R                     # 與 MCP 同一份程式碼、同一份快取
hits = R.find_text(DXF, layer="NBAR", include_blocks=True, output="file")

Windows 上用 Bash 跑要加 PYTHONIOENCODING=utf-8,否則中文印成亂碼—— 那是主控台顯示問題,不是資料壞掉,別誤判。

測試

測試套件不在這個 repo 裡。 它跑在真實的客戶施工圖上(三張 .dxf 共 53MB), 斷言與基準檔寫著那些圖上的實際值——梁編號、斷面尺寸、鋼筋標註。那是客戶的 東西,不該因為「拿來當測試資料」就變成公開內容,所以整個 test/ 留在本機。

實際跑的是四道底線,改任何讀取邏輯後都要綠:

  • golden verify — 縱向:既有行為沒被改壞

  • golden equiv — 縱向:合併後的新工具與被取代的舊工具輸出等價

  • test_consistency — 橫向:同一個實體從不同工具問到的值一致

  • test_boxes — 空間過濾的先篩(_core/_bbox)必須是真超集: 對三張圖逐一實體驗證 outer_box(e) ⊇ extents(e, fast=True),並比對 「先篩後的命中數 = 逐一算 extents 的命中數」。這條一破,bbox=near= 的結果會悄悄變少(該命中的實體被判在框外),而回傳看起來完全正常

後兩者守的不是同一件事。 golden 守「同一個工具前後輸出一致」,consistency 守「同一個實體換個工具問還是同一個答案」。後者是踩過坑才加的——find_text 修好文字錨點但 describe_entity 沒跟上,同一個字兩個工具回不同座標,golden 完全抓不到,因為各自都跟自己的基準一致。

重錄基準不是拿來讓紅燈變綠的。 verify 紅了先逐欄位查差在哪、確認每一項都 是故意改的,才重錄;否則只是把 bug 蓋章成新標準。

要自己建一套:拿任意幾張 DXF 放本機、對 tools/ 的公開函式錄一份輸出當基準, 之後比對。核心不變量就是上面那三條,跟用哪張圖無關。

原始碼註解裡到處是 test_S1test_S2test_S3 加一個數字(「實測 test_S2 全部 5706 個 TEXT 都差半個字高」、「test_S1 有 1422 個小 block 插入會被擋下」) ——那就是這三張圖的代號。檔案不在 repo 裡,但那些數字是每個判斷與門檻值的來由, 留著比拿掉有用:至少你知道那個 20000 的上限不是隨手寫的。

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/luckyman9487/CAKE'

If you have feedback or need assistance with the MCP directory API, please join our Discord server