1. 為什麼需要一個獨立的協定
在本模組中,我們終於會弄清楚什麼是 MCP(Model Context Protocol),以及它如何融入 ChatGPT App 的堆疊。讓我們先固定 MCP 在整體架構中的位置,拿它與「典型的 REST」比較,並梳理協定的主要實體:tools、resources 與 prompts。
想像你在寫一個一般的網路服務。照慣例你會起一個 REST API:例如有 /api/gifts、/api/users、/api/orders, 每個端點都有自己輸入/輸出的格式、錯誤碼與授權機制。這很熟悉,但有個重點:你必須向每個客戶端解釋你實作了什麼、怎麼用。文件、OpenAPI、範例、SDK——這些都需要,因為 API 的格式是你自己定義的。
在 ChatGPT App 情境下會更複雜。你的客戶端不僅是前端,還有模型本身。模型需要:
- 知道有哪些可用的操作;
- 了解每個操作需要哪些參數;
- 在對話進行中呼叫這些操作,有時會呼叫多次,或用不同參數;
- 解讀結構化回應,並決定哪些要展示給使用者、哪些只作為下一句對話的上下文。
若每位開發者都自訂 API 格式,模型就會陷入整合地獄:每個 App 都要客製化客戶端、一堆樣板「包裝」與脆弱的邏輯。協定這個想法正是為了化解這個問題。
MCP(Model Context Protocol) 是一套開放規格,定義了 LLM 客戶端(ChatGPT、IDE 外掛、代理等)如何與你的工具與資料伺服器溝通的標準方式。它提供一種共同語言:伺服器宣告自己的工具、資源與提示詞,客戶端則能呼叫並取得結果。
直觀地說,MCP 就像 AI 世界的 USB‑C:如果你做的是「隨身碟」(服務、資料庫、CRM、搜尋引擎),你只需要實作一種標準介面。那麼任何「筆電」(ChatGPT、其他代理、IDE)就能不用客製化的線材直接接上。
2. 俯瞰:MCP 在 ChatGPT App 架構中的位置
為了固定整體畫面,回想我們先前看過的架構,這次把 MCP 這一層明確標出來。
現在的心智模型你已看過:使用者與 ChatGPT 互動,對話中會渲染小工具(Apps SDK),而你的後端在外面運作。現在把 MCP 加進來,分層看清楚。
這是一張簡化的示意:
使用者
↓(自然語言)
ChatGPT(模型 + UI)
↓(透過 MCP 的 tool 呼叫)
ChatGPT 內部的 MCP 客戶端
↓(JSON-RPC,MCP)
你的 MCP 伺服器(後端)
↓
你的資料庫 / 外部 API / 佇列
這裡的「ChatGPT 內部的 MCP 客戶端」指的是平台內部與你的 MCP 伺服器對話的部分:它做 discovery、呼叫工具並讀取資源。
就 Apps SDK 的觀點,最小可用的 ChatGPT App 由三個元件組成。其一是 MCP 伺服器,負責宣告工具並回傳結構化資料。其二是 UI 套件(小工具),在 ChatGPT 內渲染並透過 window.openai 讀取這些資料。其三是模型本身,決定何時該呼叫哪個工具、以及如何回覆使用者。
關鍵在於:在之前的模組裡,你多半是在 Apps SDK 與小工具層工作,也就是圖的上半部。現在我們往下走到 MCP 伺服器層——這是你和 ChatGPT 以及任何其他客戶端交流的官方「語言」。
3. MCP 對比「典型的 REST」:有哪些差異
上面的圖幫我們釐清了 MCP 在 ChatGPT App 架構中的位置。接著來仔細比較「自家 REST」與 MCP 的做法,理解為什麼在 ChatGPT Apps 的脈絡下,後者幾乎總是更有優勢。
在 REST 模式下,你會照自己的習慣設計端點、請求與回應格式。為了讓客戶端能用,必須知道 URL、方法、結構與錯誤碼。有時靠 OpenAPI,有時只是在 README 丟一個請求範例。模型本身對這些一無所知:它需要一層程式碼,把「幫我替 50 歲的媽媽找禮物」轉成具體的 HTTP 請求,再把 JSON 回應轉成能用於對話的資料。
在 MCP 中則不同。協定本身就定義了:
- 客戶端如何得知你的工具清單;
- 如何用 JSON Schema 描述參數與結果;
- 如何描述資源與提示詞;
- 工具的呼叫長怎樣、回應又是什麼格式。
因此,ChatGPT 與其他 MCP 客戶端可以自動:
- 執行 discovery——得知你有哪些 tools/resources/prompts;
- 為每個工具建立內部的參數結構;
- 不需客製化硬編碼邏輯就能呼叫;
- 快取中繼資料,並在應用搜尋與排序中加以利用。
可以將差異整理成一張小表格。
| 問題 | 自家 REST / gRPC | MCP |
|---|---|---|
| 客戶端如何得知你提供哪些能力? | 從文件、README、OpenAPI | 透過標準的 discovery 方法(列出 tools/resources) |
| 誰來描述參數? | 你自行定義(JSON、FormData 等等) | 在工具欄位中使用 JSON Schema |
| 模型如何呼叫函式? | 透過你客製的客戶端程式碼 | 直接透過 MCP 原語 |
| 客戶端需要多少樣板/包裝? | 很多,且每個服務都不同 | 一個通用協定,適用於所有 MCP 伺服器 |
| 多個客戶端的支援 | 必須為每個客戶端撰寫 SDK | MCP 伺服器具自我描述能力,客戶端可重用邏輯 |
若用更直白的方式說:REST 是「各做各的」,MCP 是「整個生態系就如何與模型與資料互動所達成的共同協議」。
4. MCP 的核心實體:tools、resources、prompts
現在我們用名稱點出 MCP 的三個主角:工具、資源與提示詞。
Tools:你已經很熟悉的動作
你在第 4 模組已經碰過 tools:我們為工具命名、加上描述與參數的 JSON Schema,然後模型透過 callTool 來呼叫它。站在 MCP 層次,工具是具有明確契約的伺服器端操作:
- 名稱與描述(給模型與給 UX/discovery 用);
- 參數的 JSON Schema;
- 結果的 JSON Schema 或結構描述;
- 額外的中繼資訊(例如在 Apps SDK 中綁定到特定 UI 元件)。
MCP 伺服器至少必須能回應「工具清單請求」並處理「工具呼叫」,回傳結構化的結果。
在我們的教學應用「Gift 助手」中,假設已有工具 suggest_gifts,接受年齡、性別、預算與偏好等,並回傳推薦禮物清單。
在 MCP 伺服器的程式碼裡,一個概念性的 TypeScript 草圖可能長這樣(偽代碼/範例):
// 偽代碼,非最終的 SDK API
const suggestGiftsTool = defineTool({
name: "suggest_gifts",
description: "根據收禮者的參數挑選禮物點子",
inputSchema: z.object({
age: z.number(),
relation: z.enum(["friend", "partner", "parent"]),
budgetUsd: z.number(),
}),
handler: async (input) => {
// TODO: 你的商業邏輯
return { items: [] };
},
});
真實的函式簽章我們會在後續講解,這裡重點是:工具不只是 REST 端點,而是帶有已宣告結構的協定元素。
資源(resources):可透過 ID/URI 存取的資料
在 MCP 中,資源(resources)是描述可用資料的方式:檔案、目錄、資料庫紀錄、wiki 頁面,甚至是搜尋索引的結果。客戶端可以:
- 取得資源清單;
- 依 ID/URI 讀取特定資源;
- 有時也能對它們進行搜尋。
和「會執行動作」的 tools 不同,resources 通常「承載資料」。例如在 Gift‑App 中,你可以把商品目錄表示為資源 gift_catalog,讓模型查詢可用分類、篩選條件、價格區間等。
在程式碼中,概念上可能像這樣:
const giftCatalogResource = defineResource({
uri: "catalog://gifts",
description: "可供推薦的禮物目錄",
read: async () => {
// 回傳目錄結構
return { categories: [], priceRanges: [] };
},
});
我們暫時不深入 MCP 訊息格式,但請記住:資源是可被定址的實體,MCP 伺服器可以引用它們,客戶端則能讀取並用作對話的上下文。
Prompts:預先準備的提示詞
在 MCP 的語境中,Prompts 是伺服器可提供給客戶端的提示或指令樣板。比方說,你可以宣告一個 gift_followup 的提示詞,描述模型在呼叫工具之前,該如何向使用者確認收禮者的細節。
一個典型的協定化做法是:伺服器提供提示詞的名稱、用途,有時也包含參數。客戶端可以請求提示詞清單,選擇需要的並套用到模型請求中。
這對 ChatGPT App 有什麼用?首先,它提供在不同客戶端之間重用複雜提示詞的統一方式。其次,MCP 讓這些提示詞成為明確且「契約化」的要素,而不是散落在程式不同角落的隱形片段。
Capabilities:宣告你支援的內容
最後是第四個元素——capabilities。這是一份宣告:伺服器會說自己支援哪些實體(tools、resources、prompts、通知等),以及具體實作了哪些方法。對客戶端而言,這能避免猜測,並根據伺服器能力調整自身行為。
實務上,ChatGPT 連上你的 MCP 伺服器時,會先進行「握手」,取得 capabilities 清單,然後才會詢問:「好的,把你的工具與資源清單給我看看」。
5. MCP 如何嵌入你現有的 App
這些聽起來也許有點抽象,但其實你已經透過 Apps SDK 與 MCP 交手過了。先來釐清它如何與你在 Apps SDK 內已經寫好的內容對接。讓我們把剛介紹的幾個實體,對應到你現在的 App 範本中。
回憶一下你在範本中實作過的流程:
- 小工具透過 window.openai 或現成的 hooks,以工具名稱與參數呼叫 callTool。
- Apps SDK 在 ChatGPT 內部把這件事轉成對 App 伺服端的呼叫。
- 伺服端執行工具並回傳 ToolOutput,包含 structuredContent、content 與 _meta。
- 小工具接收 ToolOutput 並渲染 UI。
秘訣在於,第 2–3 步其實是透過 MCP 對話完成的。你的 Next.js 範本裡有個端點(通常是 app/mcp/route.ts 或相近的檔案),它就是 MCP 伺服器。它會:
- 註冊你的工具;
- 用 JSON Schema 描述它們;
- 實作處理器;
- 回應 ChatGPT 的 MCP 請求 list tools 與 call tool。
也就是說,即便你現在只是使用範本,你其實已在「自動駕駛」地使用 MCP:大部分的協定機制被 SDK 隱藏起來了。
第 6 模組的目的,就是讓你不再把 MCP 視為「神秘的黑箱」,而能主動地設計它:
- 新增與版本化工具;
- 不只用 tools,還要運用 resources 與 prompts;
- 閱讀並理解 MCP 日誌;
- 必要時在 Next.js 範本之外啟動獨立的 MCP 伺服器(例如:用 Python 服務連接 ML 模型,或專責企業資料存取的服務)。
6. 從不同角色看 MCP:產品 vs. 開發
有必要分別說清楚 MCP 對產品經理與工程師帶來的價值。
MCP 給產品經理
從產品角度看,MCP 讓你的服務成為整個客戶端動物園的「可插拔模組」:ChatGPT、其他 LLM 客戶端、IDE 外掛、自家代理等。一旦你把伺服器能力描述為 tools/resources/prompts 的集合,任何客戶端都能:
- 自動發現你的服務;
- 理解它能解決哪些問題;
- 安全地呼叫所需的操作。
在 ChatGPT App 的情境下,這也能提高你的應用被選用的機率:模型會利用你工具的中繼資料,來判斷何時向使用者推薦你的 App,以及如何正確地呈現它。
一句話總結:MCP 讓你的服務成為生態系中的標準「積木」,而非只為一兩個客戶端打造的客製整合。
MCP 給開發者
從工程角度看,MCP 是一份契約與一個協定。它回答了:
- 我該用什麼格式宣告工具?
- 如何描述參數並回傳結果?
- 客戶端如何知道我支援資源與提示詞?
- 網路上實際傳遞的 JSON 長什麼樣子?
有了這樣的協定,就更容易:
- 用不同語言撰寫伺服器(官方提供 TypeScript 與 Python SDK);
- 透過 MCP Inspector 或類似工具來除錯;
- 在團隊間分工:一組做含資料與工具的 MCP 伺服器,另一組做基於 Apps SDK 的小工具,再來第三組可以在同一個 MCP 伺服器上建自己的代理。
7. 簡短的實務視角:我們的第一個 MCP 伺服器
本講我們刻意不深入訊息格式與伺服器實作——那會在接下來的主題詳談。不過,先看一下最小型 MCP 伺服器在 TypeScript 下的大致結構,會有助於你理解我們要走向哪裡。
實務上,官方的 TypeScript MCP 函式庫提供了建立伺服器、註冊 tools/resources/prompts 與啟動傳輸層(通常是 HTTP 或 SSE)的原語。
一個概念性的偽範例可能像這樣:
// 這是概念性範例,我們稍後再講解 SDK API
import { createServer } from "@modelcontextprotocol/sdk";
const server = createServer({
name: "gift-genius",
version: "1.0.0",
});
// 註冊工具
server.tool("suggest_gifts", {
description: "根據收禮者的偏好挑選禮物",
inputSchema: {/* ... */},
handler: async (input) => {
// 你的邏輯
return { items: [] };
},
});
// 啟動傳輸層(例如 HTTP)
server.listen(3001);
重點是:這裡完全沒有提到 ChatGPT、Apps SDK 或你的特定前端。MCP 伺服器是自給自足的。它只是會回應 MCP 請求。ChatGPT App 只是眾多可能客戶端中的一種。
在課程中我們會沿用 Next.js 範本,讓 MCP 伺服器與專案共存,但這絕不是唯一做法。
8. MCP 在生態系中的角色:Apps SDK、Agents SDK 與 ACP
為了不把 MCP 視為「只給 Apps SDK 用的功能」,我們把視野放大一些。
首先,Apps SDK 直接建立在 MCP 之上,作為 ChatGPT 與外部服務之間的標準橋樑。官方文件強調:Apps SDK 可以對接任何 MCP 伺服器。協定本身允許描述工具、回傳結構化資料,並指定在 UI 中要渲染的元件。
其次,你會在另一個模組學到的 Agents SDK,也能連接 MCP 伺服器。這代表同一個包含商業邏輯的 MCP 伺服器可以被用在:
- ChatGPT 內,作為你 App 的一部分;
- 自治代理之中,例如在你產品的背景任務或批次模式中運行。
第三,ACP(Agentic Commerce Protocol),當你需要購物與即時結帳(Instant Checkout)時會用到,它在邏輯上是建立在 MCP 思維之上的:模型與代理會呼叫 commerce 工具,而這些工具同樣透過標準化契約來描述。
因此,MCP 成為基礎:UI(Apps SDK)、代理情境(Agents SDK)與商務(ACP)都建構在其上。只要你熟悉 MCP,其他部分就更容易掌握且可預測。
備註:形式上,ACP 不一定依賴 MCP 這份規格,但在實務上,ACP 工具很可能會由模型透過 MCP 介面來呼叫。兩者能非常優雅地疊合,因此應該很快就能看到更緊密的結合。
9. 實作前的小小腦內練習
在下一講深入 MCP 訊息格式之前,先做幾個思考練習,幫助你把思維從「典型的 REST」切換到「協定 + 契約」。
想像不只 ChatGPT,還有 VS Code 的 IDE 外掛與公司內部的 Slack 助理都想接上你的 Gift‑App。用一句話描述他們都需要知道你服務的哪些資訊。大概會是:「我們有一個工具 suggest_gifts(具備這些參數),以及可以透過某個資源讀取的禮物目錄」。這正是 MCP 要形式化的內容。
也請嘗試用兩句話說明:
- MCP 對你的產品經理而言是什麼(提示:將功能封裝給不同客戶端共享的標準方式);
- 對開發者而言的 MCP 是什麼(提示:具有清晰 tools/resources/prompts 原語的 JSON‑RPC 協定)。
如果你能流暢地講出來——你已經走在熟練使用 MCP 的半路上了。
把上述內容濃縮成一句話:MCP 不是另一層包在上面的 API,而是你的商業邏輯與 LLM 客戶端之間的基礎契約。接下來我們會深入協定本身:剖析 MCP 訊息格式、handshake/capabilities,並學會用檢視工具觀察流量,讓這些原則變成真正的工作利器,而不是抽象概念。
10. 圍繞 MCP 的常見錯誤與迷思
錯誤 №1:把 MCP 當成「疊在我 REST 之上的另一層 API」。
有時會想:「我已經有 REST 了,不如寫個薄薄的轉接層,把 MCP 呼叫轉成 REST 再轉回來,然後就忘了它。」形式上可行,但你往往會把舊 API 的各種特性「帶」進 MCP:奇特的型別、非結構化的回應、缺少明確的 schema。久而久之轉接層臃腫、MCP 的收益下降。更好的做法是把 MCP 當成主要契約,把舊 REST(若仍需要)當作內部實作細節。
錯誤 №2:以為 MCP「只給 ChatGPT Apps 用」。
MCP 是面向任何 LLM 客戶端的開放協定:ChatGPT、IDE 外掛、自主代理等等。如果你把 MCP 伺服器只設計給一個 App 用,就限制了未來擴展。更有利的策略是從一開始就思考「其他客戶端也能用」,並把工具與資源設計得更通用。
錯誤 №3:忽略 JSON Schema,用「文字」描述參數。
即使 SDK 允許你在某些地方傳入「任意 JSON」,也別偷懶:請為參數與結果寫好 schema。模型能否正確呼叫你的工具、autocomplete 與 discovery 的品質、以及透過檢視工具除錯的效率,都直接仰賴 schema。沒有或寫得很差的參數描述,是邁向各種神祕 tool‑call 錯誤的捷徑。
錯誤 №4:把 MCP 當成「魔法運輸層」,不看日誌。
在一切運作正常時,MCP 彷彿是個看不見的東西,不需要管它。但一旦出問題,若不理解 MCP 的結構,你會長時間猜測:「是 Apps SDK?是模型?還是我的後端?」養成及早查看 MCP 訊息與日誌的習慣,可以省去許多無用功。
錯誤 №5:只想用 REST 設計複雜流程,忽略 MCP 原語。
當流程變得多步驟(找禮物 → 釐清偏好 → 選擇 → 下單),你可能會想「乾脆做一個大型的 REST 端點」。在 ChatGPT Apps 的脈絡中,這常會降低可控性:模型較難理解中間步驟,MCP 客戶端也失去重用資源與提示詞的機會。更好的方式是把功能拆成多個描述完善的 tools/resources,再用系統提示與正確的描述把邏輯串起來。
GO TO FULL VERSION