用 WordPress Abilities API 寫 MCP server:從手刻 Function Call 到官方標準


這禮拜的主題比較硬一點,但如果你有在用 AI 開發外掛然後想讓自己的 Antigravity 或是 Claude Code 讀到網站的內容像是查訂單,這篇教學就非常適合貼給 AI 請它幫你開發~

話說之前做 DWP 的 LINE 聊天機器人查 WooCommerce 訂單,會員可以直接在 LINE 裡問訂單狀態、查活動,背後是 OpenAI 的 Function Call 在跑。整個架子是自己刻的——每一個會員問句能對應到的後端動作,要自己定義一份 JSON Schema 告訴模型「這個工具吃什麼參數、回什麼結構」,再寫一個 dispatcher 收到 model 的 tool_calls 之後手動 routing 到對應的 WP 函式,回傳值也要自己塞回對話 context。

換一家模型供應商就要重做一次 schema 格式(OpenAI、Anthropic、Gemini 的欄位名稱都不一樣),漏處理一個錯誤路徑 LINE 那邊就吐出一堆奇怪的字。一份「查訂單狀態」的能力,被綁死在這個 LINE Bot 專案裡,搬不到別處用。

直到 WordPress 6.9 把 WordPress Abilities API 正式收進 core,加上 Automattic 維護的 MCP Adapter,這套東西就有了官方標準。同一個 ability 一次註冊,就同時能從 PHP、REST API、跟 MCP(給 Claude Code、Claude Desktop、Cursor 這些 AI client 直接呼叫)三個路徑使用。這篇就是用我們做的 cdx-mcp 外掛當實例,把整條路走過一次。

WordPress Abilities API 是什麼

Abilities API 是 WordPress 6.9 開始進 core 的官方標準,讓你把一段「可被外部呼叫的功能」用統一格式註冊起來,附上輸入/輸出 schema、權限檢查跟標籤——之後 PHP、REST、AI agent 都能用同一份定義去呼叫它。

對應到之前 LINE Bot 自刻 Function Call 的痛點,差別在:

手刻 Function CallAbilities API每個 model 廠商一份 schema一份 input/output schema 全平台共用自己寫 dispatcher routing用 wp_register_ability( $name, $args ) 註冊自己驗證權限、自己回錯誤permission_callback + 回 WP_Error 是標準約定只能在那個專案內用註冊完同時走 PHP/REST/MCP

註冊一個 ability 需要的關鍵欄位:

  • labeldescription:description 是寫給 AI 看的,講清楚做什麼、吃什麼、回什麼
  • category:先用 wp_register_ability_category() 註冊好,ability 才能歸到那個 category 底下
  • input_schema / output_schema:JSON Schema 格式
  • execute_callback:實際做事的 PHP function
  • permission_callbackRequired,不是 optional(官方 PHP API 文件曾經寫成 optional,後來修正)
  • meta.annotations:標示這個 ability 的特性(唯讀、是否會破壞資料、是否冪等)

meta.annotations 這幾個旗標被 MCP Adapter 自動映射成 readOnlyHintdestructiveHintidempotentHint,AI 會看這幾個值來決定要不要自動呼叫。特別注意 destructive 預設值是 true,純查詢的 ability 一定要手動設成 false,不然 Claude 會以為這動作有破壞性而拒絕自動執行。這是文件埋得比較深的雷。

MCP Adapter 把 ability 轉成 MCP tool

Abilities API 解決了「功能怎麼註冊」,MCP Adapter 解決的是「怎麼讓 AI agent 找得到並呼叫它」。

Model Context Protocol(MCP)是 Anthropic 推出的開放協定,讓 AI client(Claude Code、Claude Desktop、Cursor、VS Code 等)能透過統一介面去呼叫外部工具。MCP Adapter 就是 WordPress 這端的橋——把已註冊的 ability 包裝成 MCP server 暴露出去,AI client 用 tools/listtools/call 兩個方法就能讀到 schema 並執行。

裝起來有兩種選擇:

  1. 用 default server:裝完 mcp-adapter 外掛就會自動建一個叫 mcp-adapter-default-server 的 server,要把 ability 加進去得在註冊時加一個 meta.mcp.public = true 旗標
  2. 自己建 custom server:在自己的外掛裡明確指定要暴露哪些 ability,乾淨可控,且不需要那個 public 旗標

我走第二條直接用 Composer 安裝,就不用讓使用者還要另外去裝 adapter 外掛了。

實戰:cdx-mcp 外掛把 WooCommerce 訂單查詢變 MCP tool

我做了一個外掛叫 cdx-mcp,功能很單純:給一個 WooCommerce 訂單 ID,回傳這筆訂單的完整結構化資料(狀態、金額、客戶、付款方式、品項),給 Claude Code 直接拿來查訂單。整個外掛大概 200 行 PHP,因為程式碼有點多,請幫我移駕到這邊吧:https://oberonlai.blog/wordpress-abilities-api-mcp-server/

WordPress 開發日常

Read more from WordPress 開發日常

昨天下午跑去臺北中山地下街想說放空一下抽離每天的日常工作,結果逛書店逛到一半,旁邊走過的兩個人開始在高談闊論,聊著關於 AI 上下文超過 50% 能力表現就會開始衰退的話題,害我都很想過去跟著討論一番XD Typeless 不只是語音輸入工具,更是 AI 助理 語音輸入軟體 Typeless 的方便性應該不用我再多說了,有很多朋友應該都有在用,但最近我發現了幾個進階的用法,能夠再進一步提升我的 AI coding 效率甚至是平常的文書作業。首先是「隨便問」這個功能,Mac 上預設的快速鍵是 Fn + Space,我發現它有以下用法: 一、潤飾文字稿 當我語音輸入完、想要把輸入好的內容再重新順一下時,我可以直接把剛剛輸入的文字選取起來,然後使用 Fn + Space 跟它說:「請幫我潤飾一下這段文字,並且幫我把原始文字括號,讓我知道你修改了哪些地方。」 二、深度分析與摘要 當你面對冗長的文件、複雜的報告或大量的資訊時,不必逐字閱讀。只需將內容選取後呼叫「隨便問」,它便能迅速為你梳理出核心論點、關鍵數據及邏輯架構,並將繁瑣的資訊轉化為簡潔易懂的重點摘要。 三、網頁搜尋...

最近在讀一本書叫做《Vibe Coding 聖經》,在現在 AI 相關的書籍多到爆炸的狀況下,很容易就覺得這只是另外一本在教人用 AI 寫 Code 的過時書籍而略過,但讓我眼睛一亮的是本書的其中一位共同作者 Gene Kim 是我超愛的一本軟體專案管理小說神作《鳳凰專案》的作者,他與另一位骨灰級工程師合著,因此二話不說就立刻買回來看。 這本書是 2025 年中出版的。在那個時間點,Vibe Coding 的說法剛出來不久,所以第一章的篇幅著墨在說服還沒有嘗試過 Vibe Coding 的工程師來實際體驗看看,書中舉了很多矽谷創業圈的例子來佐證,證明 Vibe Coding 是真的會改變軟體設計的一種典範轉移。 Kim 也提到有很多早就因為寫不下去程式碼而離開這個產業的工程師,因為這一波 Vibe Coding 的浪潮又重新找回軟體開發的樂趣,其中就包含他自己。他的本業是協助企業來如何透過 IT 來管理企業,而《鳳凰專案》這本書在講的就是這個的主題。 《Vibe Coding 聖經》提到 AI 協作開發把工程師最討厭的瑣事像是除錯、寫測試、部署流程全部都外包給...

上一次也是第一次參加鐵人賽是 2021 年,因為受到社群夥伴 Eric 的邀約,我寫了關於接案以及 WooCommerce 金流串接的主題,雖然只有得到全勤獎且壓力爆棚,但還是靠著意志力完成這個累死人不償命的比賽。 IT 鐵人賽是由台灣最大的技術開發社群 IT邦每年都會舉辦的線上活動,邀請所有技術產業的從業人員把他們的研究心得或是實作經驗以連續三十天的頻率發表出來,挑戰前可以選擇要投稿的題目,剩下的就是在半夜 12 點前準時發文,如果遲了一分鐘挑戰就算失敗。 當年參賽挑了一個我很害怕的主題:WooCommerce 金流串接,這是我自學程式的大魔王關卡,很大一部分是因爲當年閱讀技術文件非常吃力,然後 WooCommerce 的 API 又有很多看不懂的寫法,我想用鐵人賽來克服心魔。 這是我當年參賽後的心得:「參賽前我一直很擔心自己沒有辦法寫完這三十天,不停的在懷疑自己是否有辦法辦到,但就跟做很多一開始覺得很困難的案子一樣,頭洗下去之後就會慢慢看得到終點了,今天的我感覺自己突破了很大的一關!」...