CodeGym /課程 /ChatGPT Apps /MCP 檢查與除錯:MCP Jam、Inspector、日誌

MCP 檢查與除錯:MCP Jam、Inspector、日誌

ChatGPT Apps
等級 6 , 課堂 4
開放

1. 為什麼需要 MCP 檢查器

想像你在除錯前端,但被禁止打開 DevTools。沒有 MCP 檢查器的生活大概就是這樣。 MCP 協定在 ChatGPT 與 Apps SDK 的「引擎蓋下」運作;如果你只看聊天視窗的回覆,心想:「為什麼它看不到我的工具?」——其實就是在盲射。

MCP Inspector(官方)或 MCP Jam 這類工具,都是專門給開發者使用的 MCP 用戶端。它們能:

  • 與 ChatGPT 相同的方式連線到你的 MCP 伺服器;
  • 完成握手 / capabilities;
  • 請求 tools/resources/prompts 清單;
  • 手動以任意引數呼叫任何 tool;
  • 顯示原始的 JSON 訊息(requests / replies / errors)。

本質上,這是「有腦袋的 MCP 版 Postman」。和一般的 REST 用戶端不同,檢查器了解 MCP 的特性: 它懂得 tools/listtools/call,能展示引數的 schema, 有時甚至支援受保護伺服器的 OAuth 流程。

如果沒有檢查器,除錯往往變成:你打開 ChatGPT,嘗試呼叫 App,看到「Error talking to app」 或工具根本沒有被呼叫,然後開始猜:是模型不想用工具?是你的 MCP 沒有啟動?還是 JSON 出錯? 有了檢查器,你可以逐層檢查:先用檢查器單獨對接 MCP 伺服器,再看 ChatGPT ↔ MCP 的串接。

2. 檢查器小評:MCP Inspector、Jam 與夥伴

實務上,你多半會使用兩類 MCP 檢查器。

其一是 官方的 MCP Inspector,來自 Model Context Protocol 的儲存庫。這是個網頁應用 (通常是 React 的 SPA),可以本機啟動,或透過 npx/Docker, 並能透過 HTTP/SSE 連上你的 MCP 伺服器。

其二是 MCP Jam 類的檢查器,經常加入更方便的 OAuth 能力。 它們可以自行讀取 .well-known/oauth-protected-resource,從中取出 authorization_endpointtoken_endpoint,走 PKCE 流程, 並在已授權狀態下與 MCP 通訊。

MCP Jam 是在 MCP Inspector 基礎上由開發者打造的。如果 MCP Inspector 實作的是最小必要集的除錯工具, 那麼 MCP Jam 幾乎實作了開發者日常所需的一切。 我個人建議直接使用 MCP Jam,以免之後還要改變習慣。

就本課程而言,差異在於:

  • 基本款 Inspector 隨時都用得上,即使是最簡單、未受保護的 MCP 伺服器;
  • MCP Jam(或同類工具)在你學到鑑別與授權章節時會特別好用。

但核心概念相同:它是一般的 MCP 用戶端,只是把 ChatGPT「默默」做的事清楚地展示出來。

3. 典型的 MCP 檢查器使用流程

讓我們走一遍常見流程:你在自己的 MCP 伺服器中寫了一個新 tool,想確認它真的可用。

在上一堂課,你已經啟動了最小化的 MCP 伺服器。現在加上系統化驗證:依序跑一圈 「伺服器 → 檢查器 → JSON 邏輯」。

步驟 1 — 啟動 MCP 伺服器

你之前已經做過了:假設你有腳本 npm run mcp-dev

# MCP 伺服器的啟動範例
npm run mcp-dev
# 底下大概是:ts-node src/mcp-server.ts

重要的是伺服器要監聽你選的傳輸通道:在本課通常是某個埠上的 HTTP endpoint /mcp, 例如 http://localhost:4001/mcp

步驟 2 — 啟動 MCP Jam

開第二個終端機:

# 啟動 MCP Jam 的其中一種方式
npx @mcpjam/inspector@latest
# 需要時可加上 --port 4002 等參數

之後檢查器會在瀏覽器中開啟,通常是 http://localhost:6274 或類似埠號。

在 MCP Jam 的起始畫面,會請你輸入 MCP 伺服器的 URL。你輸入:

http://localhost:4001/mcp

或是你的對外通道(tunnel)URL,如果你已經透過 ngrok 等工具轉出。

步驟 3 — 握手 / 能力宣告

MCP Jam 一旦連上,就會自動做和 ChatGPT 相同的事:

  1. 送出初始化請求(initialize),附上用戶端資訊。
  2. 收到回應,其中包含協定版本與伺服器的 capabilities
  3. 依據 capabilities 判斷伺服器是否支援 tools、resources、prompts 等功能。

在 UI 上通常會看到像這樣:

Connected
Protocol: mcp/2025-06-18
Capabilities:
- tools: list, call
- resources: list, read
- prompts: list, get

如果在這一步檢查器就無法連線(connection refused、CORS、500 等),你會立刻看到錯誤,並能確定: 問題不在模型與 ChatGPT,而是在你的伺服器端或網路設定。

步驟 4 — 探索:查看 tools/resources/prompts

握手成功後,檢查器通常會自動呼叫 tools/listresources/listprompts/list 等方法,來填入側邊欄。你會看到:

  • 工具清單,包含描述與輸入引數的 JSON Schema;
  • 資源清單,依集合/路徑分組;
  • 提示(prompts)清單與簡短描述。

如果你剛新增的 tool 不在清單內,表示它沒有正確在伺服器上註冊, 或伺服器沒有載入更新後的程式。這裡會比你苦惱「為什麼 ChatGPT 不想叫我的工具」更容易發現問題。

4. 透過 MCP Jam 手動呼叫工具

MCP Jam 最有用的功能就是手動呼叫工具。它是針對 tools/call 的專屬 UI。

選擇工具並填入引數

假設你在前一個單元寫了 tool suggest_gifts

// 位於 src/mcp/tools/suggestGifts.ts 的某處
export const suggestGiftsTool = {
  name: "suggest_gifts",
  description: "依年齡、預算與興趣推薦禮物點子",
  inputSchema: {
    type: "object",
    properties: {
      age: { type: "number" },
      budget: { type: "number" },
      interests: {
        type: "array",
        items: { type: "string" }
      }
    },
    required: ["age", "budget"]
  },
  // handler 另行定義
};

在 MCP Jam 中點選 suggest_gifts。右側會依 inputSchema 產生表單。 然後你填入:

{
  "age": 30,
  "budget": 100,
  "interests": ["遊戲", "書籍"]
}

接著按下「Call」或相應的按鈕。

檢查器會送出 tools/call 的 MCP 請求,你立刻就能看到:

  • 原始的 JSON 請求資料(實際送到伺服器的是什麼);
  • 原始的 JSON 回應資料(resulterror);
  • 有時還有更易讀的結果預覽格式。

在檢查器中閱讀 JSON 日誌

檢查器通常會顯示類似:

// Request
{
  "id": "1",
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "suggest_gifts",
    "arguments": {
      "age": 30,
      "budget": 100,
      "interests": ["遊戲", "書籍"]
    }
  }
}
// Reply
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "1) 桌上遊戲 ... 2) 書店禮物卡 ..."
      }
    ]
  }
}

如果你的 handler 丟出了例外,你會看到 JSON-RPC 風格的 error

{
  "id": "1",
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal error",
    "data": "TypeError: Cannot read properties of undefined ..."
  }
}

重點是:你在這裡看到的是協定層級。如果回應格式不是 Apps SDK/ChatGPT 所期待的,你能在抱怨「GPT 有 bug」之前就先發現。

5. 資源與提示(prompts)的除錯

工具不是 MCP 的全部。你也知道還有 resourcesprompts

透過檢查器,你可以:

  • 打開資源清單(resources/list)查看其中繼資料;
  • 讀取指定資源(resources/read),確保回傳資料正確;
  • (如果你有實作)對資源執行搜尋;
  • 查看預設好的 prompts 與其內容。

例如,你有一個資源 gift_catalog

// 註冊資源的偽代碼
registerResource({
  uri: "resource://giftgenius/catalog",
  name: "禮物目錄",
  mimeType: "application/json",
  handler: async () => {
    return JSON.stringify(giftCatalogData);
  }
});

在檢查器中你會看到這個資源,點進去就能直接查看 JSON。如果 JSON 無效, 或 MIME 類型怪怪的——你會在 ChatGPT 嘗試讀取或嵌入到小工具前就把問題抓出來。

6. MCP 伺服器日誌:記錄什麼、寫到哪裡、怎麼記

MCP Jam 很好用,但還不夠:你需要MCP 伺服器本身的日誌。沒有日誌,任何上線都像在碰運氣。

要記錄什麼

建議的最低限度:

  • 每一則進來的 MCP 訊息(request/notification),包含:
    • 時間;
    • 方法(tools/calltools/list 等);
    • 工具名稱(若有);
    • 截斷後的引數(不含敏感資料);
  • 每一則送出的回應:
    • 狀態(成功 / 錯誤);
    • 執行時間;
    • 精簡版的結果或至少類型;
  • 技術性錯誤:
    • JSON 解析;
    • handler 中的非預期例外。

同時也非常重要:不要把 PII 與密鑰完整寫入日誌,例如 token、密碼、完整的機敏請求本文。 在生產等級的日誌建議中,通常都會強調以截斷/遮罩 PII 的方式記錄資料。

日誌寫去哪裡:stdout / stderr

MCP 有個關鍵要求:JSON 訊息必須走「正確的通道」,而所有除錯日誌走另一個。 例如你使用 stdout/stderr 作為傳輸層時:

  • JSON-RPC 訊息必須寫到 stdout
  • 所有 console.logconsole.error 等,應該導到 stderr

若把 JSON 與文字日誌混在同一個串流,客戶端(MCP Jam 或 ChatGPT)就無法解析, 因為在 JSON 中間會突然出現像 Server started at http://localhost:4001 這樣的字串。 這是 MCP 伺服器常見的錯誤之一。

在 HTTP 情境中問題稍微簡單,但原則一致:HTTP 回應必須是純 JSON, 所有日誌要寫到主控台/檔案,而不是回應本文。

TypeScript MCP 伺服器的簡易記錄器

讓我們在範例 MCP 伺服器中加上一個小記錄器:

// src/logger.ts
export function logRequest(method: string, details: unknown) {
  console.error(
    JSON.stringify({
      level: "info",
      type: "request",
      method,
      details,
      ts: new Date().toISOString(),
    })
  );
}

export function logError(method: string, error: unknown) {
  console.error(
    JSON.stringify({
      level: "error",
      type: "error",
      method,
      error: String(error),
      ts: new Date().toISOString(),
    })
  );
}

接著在 tools 的處理器中:

// src/mcp-server.ts (片段)
server.setRequestHandler("tools/call", async (req) => {
  logRequest("tools/call", {
    name: req.params?.name,
    // 這裡最好不要放整個 payload,而只放安全的欄位
  });

  try {
    const result = await handleToolCall(req);
    return result;
  } catch (e) {
    logError("tools/call", e);
    throw e;
  }
});

如此一來你就能在主控台看到結構化的 JSON 日誌,之後可以透過 ts 或額外的 requestId 來對照關聯。

7. 組合拳:MCP Jam + 日誌

正確的 MCP 除錯策略幾乎總是這樣:

  1. 先在檢查器中重現問題:看到 tools/list 回傳空清單、 tools/call 失敗、JSON 回應怪異等等。
  2. 同時查看 MCP 伺服器日誌:啟動時寫了什麼、對每則訊息輸出了哪些錯誤、有沒有 stack trace。
  3. 把日誌中的 idmethodts 與檢查器看到的內容對上。

例如你在檢查器中看到:

{
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}

同時在日誌裡看到:

{
  "level": "error",
  "type": "error",
  "method": "tools/call",
  "error": "TypeError: Cannot read properties of undefined (reading 'age')",
  "ts": "2025-11-21T10:15:12.345Z"
}

OK,診斷清楚:某處的 handler 期待 age,但 schema/引數不一致。

8. 迷你清單:你的 MCP 伺服器是否已準備好接 App?

在把 MCP 伺服器接上真正的 ChatGPT App 之前,建議用檢查器跑一份小清單。

首先,握手與 capabilities 必須無錯通過。MCP Jam 要能顯示伺服器支援你需要的實體: 至少要有 tools,若有使用,還需要 resources / prompts

其次,檢查器中的 tools/resources/prompts 清單,應與你自認已實作的工具、資源與提示一致。 像 name 的拼寫、遺漏註冊等問題,都能在這裡立刻抓到。

第三,以有效引數呼叫工具應能穩定回傳正確的 result。 最好嘗試幾個你在實際環境中真會依賴的典型案例。

第四,以無效引數呼叫時,應回傳清楚的 JSON-RPC 風格 error 回應, 而不是直接 500。舉例來說,若缺少必要參數,最好回傳結構化錯誤,之後 ChatGPT 能將其轉換為對使用者友善的訊息。

第五,伺服器日誌不應在這些測試中以大量 stack trace 淹沒主控台。錯誤要結構化, 敏感資料要妥善過濾。

若以上在檢查器中都能通過,就可以更安心地把 MCP 伺服器接到 Apps SDK,並在 Dev Mode 與小工具玩起來。

9. 常見的 MCP 伺服器臭蟲,以及如何用檢查器抓出來

接下來看看重點——最常壞的是什麼,以及怎麼看得出來。

設定與連線

有時你以為「伺服器壞了」,其實是根本沒有監聽正確的埠或 endpoint。 檢查器會如實回報 connection refused 或乾脆連不上。 常見原因:URL 錯了(例如 /mcp 寫成 /api/mcp), 埠被其他程序占用,通道沒有打開,或是 CORS 阻擋了請求。

JSON 不合法/把日誌和協定混在一起

最痛的案例之一:你在 stdout 印出 console.log("Server started"), 而 JSON-RPC 訊息也應該走 stdout。客戶端預期是純 JSON,卻收到「文字 + JSON」,嘗試解析後就因格式錯誤而失敗。

解法很簡單:嚴格區分什麼走協定串流(stdout 或 HTTP 回應本文),什麼走日誌(stderr 或獨立日誌檔)。

Schema 與工具實作不一致

另一個常見錯誤:在 inputSchema 宣告了一套,程式碼卻期待另一套。 例如,schema 說 age 是數字、interests 是可選的字串陣列, 但程式碼卻做了 arguments.interests.toLowerCase()。模型(與檢查器)會忠實地把 interests 傳為 null 或根本不帶這個欄位——結果就爆。

檢查器可以讓你明確看到,實際送進 tools/call 的 JSON 長怎樣, 再來對照你的程式碼。

工具/資源命名錯誤

如果在 capabilities / tools/list 你把工具匯出為 suggest_gifts_v2, 但在 Apps 的 manifest 或小工具中期待的是 suggest_gifts,那麼「找不到工具」會一路陪你到專案結束。 在檢查器中透過工具清單與其 name 欄位,馬上就能看到,不用猜 GPT 在想什麼。

工具很慢或掛住

如果在檢查器中呼叫工具要 30 秒才跑完,最後還因逾時失敗——別指望 ChatGPT 會比較好。 MCP 檢查器能幫你判斷到底卡在哪:網路、資料庫,或外部 API。 在日誌中記下每個請求的開始與結束時間,有助於快速找出 outliers。

10. 檢查與除錯 MCP 時的常見錯誤

錯誤 №1:只透過 ChatGPT 除錯 MCP。
許多開發者先把 MCP 接到 App,看到「哪裡不對勁」,就開始改 prompt、改工具描述, 甚至改模型版本。但此時 MCP 伺服器根本沒啟動,或 tools/list 是空的。 一定要先用檢查器:如果這裡就爛掉,問題根本與模型無關。

錯誤 №2:把 JSON-RPC 與日誌混在同一個串流。
當 MCP 用戶端期待的是純 JSON,而你在 stdout 印除錯字串,結果可想而知——解析失敗, Inspector 會顯示奇怪的錯誤。日誌應該分開(stderr、檔案、外部日誌系統), 協定訊息則要嚴格走自己的通道。

錯誤 №3:不看 capabilities 與工具清單。
工具「消失」的原因,常常是你忘了註冊或漏開相應的 capability。 如果不在檢查器中看 capabilitiestools/list, 你會一直以為是模型的問題,而不是你的註冊程式碼。

錯誤 №4:忽略 schema 錯誤與 JSON 不相符。
inputSchema 與實際 JSON 不一致時,模型與檢查器的行為異常很合理。 如果你不看檢查器中的原始 JSON 訊息,也不驗證 schema,這些錯誤會在最意想不到的地方跳出來。

錯誤 №5:把所有東西都寫入日誌,包括 PII 與 token。
在除錯熱情中,很容易就把完整的 request body 印到日誌,包括可能的個資或機密。 在生產環境這是顆未爆彈:外洩、合規問題等通通找上門。 只記錄真的對診斷有用的資訊,並且以截斷/匿名化的方式處理敏感資料。

錯誤 №6:不以最小重現來複製問題。
有時臭蟲只在 ChatGPT 的複雜對話中出現,開發者就照著那樣除錯。 更有效的做法是在檢查器中用一兩個 MCP 請求重現相同情境,切開 prompt、對話歷史, 以及模型的「心情」這些影響。

1
問卷/小測驗
MCP 協議,等級 6,課堂 4
未開放
MCP 協議
MCP:協議、伺服器與檢查
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION