2026年3月20日5 分鐘閱讀ai-cli-tools

20 分鐘用 Claude Code 建一個 MCP Server

手把手教學:用 TypeScript 建一個能用的 MCP server,接上 Claude Code,實際呼叫 tool 測試。

DH
Danny Huang

你會做出什麼

想像給一個圖書館員一個全新的館區。不只是更多書——是一整個有自己目錄、自己檢索系統、自己專業知識的全新區域。這就是為 Claude Code 建一個 MCP server 做的事。

這篇教學結束後,你會有一個能運作的 MCP server,可以即時查詢 GitHub 使用者資料。Claude Code 會直接從終端呼叫它。你輸入「查一下 torvalds 的 GitHub 資料」,Claude Code 就會調用你的 server、打 GitHub API、回傳結構化的結果。

MCP(Model Context Protocol)是一個開放標準,讓 AI agent 透過統一介面存取外部工具和資料。你不需要把 API 呼叫寫死在 prompt 裡,而是建一個 server 來公開 tool。任何支援 MCP 的 client(Claude Code、Claude Desktop、Cursor 等)都能自動發現並呼叫這些 tool。

這篇教學做的是真的東西。不是 hello-world echo server,是一個會打真實 API 回傳有用資料的 tool。

你需要:

  • Node.js 18+ 和 npm
  • 已安裝並驗證的 Claude Code
  • 一個終端
  • 20 分鐘

為什麼要自己建 MCP Server?

你可能已經在用 MCP server 了,只是沒意識到。Claude Code 內建的檔案讀取、網頁搜尋、bash 執行,底層都是 MCP tool。

自己建 server 代表你可以讓 Claude Code 存取任何東西:公司內部 API、資料庫、監控儀表板、deploy pipeline。Protocol 處理發現、schema 驗證和傳輸。你只寫邏輯。

三個理由讓你選擇自己建:

  1. 自訂資料來源。 把 Claude Code 接上還沒有現成 MCP server 的 API。
  2. 控制存取。 你的 server 決定公開哪些資料、怎麼格式化。邊界你來定。
  3. 重複使用。 一個 server 在所有 MCP client 上都能用。建一次,到處用。

想了解 MCP 在整個 AI CLI 工具生態裡的位置,那篇指南有完整的全景。

第一步:建立專案

建一個新目錄並初始化:

mkdir github-mcp-server
cd github-mcp-server
npm init -y

安裝 MCP SDK 和 Zod(用來做 schema 驗證):

npm install @modelcontextprotocol/sdk zod@3
npm install -D @types/node typescript

更新 package.json,啟用 ES modules 並加入 build script:

{
  "type": "module",
  "bin": {
    "github-mcp": "./build/index.js"
  },
  "scripts": {
    "build": "tsc && chmod 755 build/index.js"
  },
  "files": ["build"]
}

建立 tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

建立原始碼目錄:

mkdir src

專案結構:

github-mcp-server/
├── package.json
├── tsconfig.json
└── src/
    └── index.ts       # 接下來要寫的檔案

第二步:撰寫 Server

建立 src/index.ts。這是整個 server——每一行都有行內說明。

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// 建立 MCP server 實例。
// name 和 version 會在 client 探索 server 時顯示。
const server = new McpServer({
  name: "github-lookup",
  version: "1.0.0",
});

// 定義 GitHub API 回應的 TypeScript 介面。
// 只取我們需要的欄位。
interface GitHubUser {
  login: string;
  name: string | null;
  bio: string | null;
  public_repos: number;
  followers: number;
  following: number;
  html_url: string;
  created_at: string;
}

// 註冊一個叫 "get_github_user" 的 tool。
// 第一個參數是 tool 名稱。
// 第二個參數是 metadata:description + input schema。
// 第三個參數是 handler function。
server.registerTool(
  "get_github_user",
  {
    description: "Look up a GitHub user profile by username",
    inputSchema: {
      username: z
        .string()
        .min(1)
        .describe("GitHub username (e.g. torvalds, sindresorhus)"),
    },
  },
  async ({ username }) => {
    const url = `https://api.github.com/users/${encodeURIComponent(username)}`;

    try {
      const response = await fetch(url, {
        headers: {
          "User-Agent": "github-mcp-server/1.0",
          Accept: "application/vnd.github.v3+json",
        },
      });

      if (!response.ok) {
        return {
          content: [
            {
              type: "text" as const,
              text: `GitHub API returned ${response.status}: user "${username}" not found or rate-limited.`,
            },
          ],
        };
      }

      const user = (await response.json()) as GitHubUser;

      const summary = [
        `**${user.name || user.login}** (@${user.login})`,
        user.bio ? `Bio: ${user.bio}` : null,
        `Public repos: ${user.public_repos}`,
        `Followers: ${user.followers} | Following: ${user.following}`,
        `Profile: ${user.html_url}`,
        `Account created: ${user.created_at.split("T")[0]}`,
      ]
        .filter(Boolean)
        .join("\n");

      return {
        content: [{ type: "text" as const, text: summary }],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text" as const,
            text: `Failed to reach GitHub API: ${error instanceof Error ? error.message : "unknown error"}`,
          },
        ],
      };
    }
  },
);

// 把 server 接上 stdio transport。
// Claude Code 透過 stdin/stdout 跟 MCP server 溝通。
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("GitHub MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

重點說明:

  • server.registerTool 接收名稱、設定物件(含 description 和 inputSchema)、以及一個 async handler。inputSchema 直接使用 Zod 物件。SDK 會在 handler 執行前自動驗證輸入。
  • 回傳格式一律是 { content: [{ type: "text", text: "..." }] }。這是 MCP 標準的回應結構。
  • 用 console.error 而非 console.log。基於 stdio 的 MCP server 用 stdout 傳送 JSON-RPC 訊息。任何 console.log 都會破壞 protocol。除錯訊息一律用 console.error。這是 MCP server 開發中最常見的錯誤——就像在電話交換機上接錯了線。

第三步:Build 並在本機測試

編譯 TypeScript:

npm run build

你應該會看到 build/index.js 檔案。測試它能不能正常啟動:

node build/index.js

Process 會停住(等待 stdin 輸入)。這是正確的——server 正在監聽。按 Ctrl+C 停止。

在接上 Claude Code 之前,用 MCP Inspector 做互動式測試:

npx @modelcontextprotocol/inspector node build/index.js

這會在 http://localhost:6274 開一個 web UI。你可以選 get_github_user tool、輸入使用者名稱、看原始回應。Inspector 是在整合到任何 client 之前驗證 tool 運作最快的方法。

第四步:接上 Claude Code

Claude Code 從專案根目錄的 .mcp.json 讀取 MCP server 設定。在你的工作專案(不是 MCP server 目錄裡,而是你用 Claude Code 的那個專案)建立這個檔案:

{
  "mcpServers": {
    "github-lookup": {
      "command": "node",
      "args": ["/absolute/path/to/github-mcp-server/build/index.js"]
    }
  }
}

把 /absolute/path/to/ 換成實際路徑。在 github-mcp-server 目錄裡執行 pwd 就能拿到。

或者用 Claude Code CLI 加入,讓它在所有專案都可用:

claude mcp add github-lookup --scope user -- node /absolute/path/to/github-mcp-server/build/index.js

加完設定後重啟 Claude Code。在 Claude Code 裡執行 /mcp 確認 server 已連線。你應該會看到 github-lookup 顯示綠色狀態。

第五步:實際使用

在設定好 server 的任何專案裡打開 Claude Code,輸入:

查一下 torvalds 的 GitHub 資料

Claude Code 會:

  1. 辨識 get_github_user 是適合這個請求的 tool。
  2. 詢問你是否同意呼叫(只有第一次,除非你啟用了自動核准)。
  3. 把 {"username": "torvalds"} 傳給你的 server。
  4. 顯示格式化後的結果。

再試幾個:

sindresorhus 的 GitHub 帳號有什麼專案?
比較 gaearon 和 dan-abramov 的 GitHub 資料

Claude Code 讀取 tool 的 description 和 input schema 來決定何時、如何呼叫。你不需要寫任何 prompt engineering。MCP protocol 處理了所有接線。

疑難排解

/mcp 輸出裡看不到 server。 .mcp.json 裡的路徑不對。用絕對路徑。手動執行 node /your/path/build/index.js 確認它能啟動。

Server 啟動了但 tool 沒出現。 重新執行 npm run build。Claude Code 跑的是編譯後的 JavaScript,不是 TypeScript 原始碼。改了 src/index.ts 就必須重新 build。

GitHub 回傳 "Rate limit exceeded"。 GitHub API 未驗證的請求每小時限 60 次。要更高額度,加一個 GITHUB_TOKEN 環境變數,在 fetch headers 裡用 Bearer token。你可以在 .mcp.json 裡傳環境變數給 MCP server:

{
  "mcpServers": {
    "github-lookup": {
      "command": "node",
      "args": ["/absolute/path/to/github-mcp-server/build/index.js"],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here"
      }
    }
  }
}

Server 無聲地 crash。 檢查 stderr 輸出。手動跑 server:node build/index.js 2>&1,看有沒有錯誤訊息。常見原因:缺少 node_modules(跑 npm install)、Node.js 版本太舊(需要 18+)、build 輸出有語法錯誤。

Claude Code 出現 JSON parse 錯誤。 你的 server 程式碼裡有 console.log。把每個 console.log 都換成 console.error。Stdout 是 MCP protocol 訊息專用的。

開發 MCP Server 的多面板 workflow

在開發 MCP server 的時候,你同時要處理三件事:編輯 src/index.ts、執行 npm run build 並重啟 server、用 Claude Code 或 MCP Inspector 測試。用 Ctrl+Tab 或 Alt+Tab 在這些之間切換很慢,而且會打斷專注——就像一個鐘錶匠反覆放下又拿起同樣三個工具。

有效率的做法是三個終端面板同時可見。左邊放編輯器,右上放 build 和 server log,右下放 Claude Code 或 Inspector。存檔、看 build 輸出、測試 tool。不切視窗。不丟失脈絡。

Try Termdock — Multi Terminal Layout works out of the box. Free download →

下一步

你已經有一個能運作的 MCP server。接下來可以往這些方向走。

加更多 tool。 再呼叫一次 server.registerTool,給不同的名稱和 schema。一個 server 可以公開數十個 tool。考慮加入 get_github_repo(儲存庫詳情)、list_github_repos(列出使用者的儲存庫)、或 search_github_code(跨儲存庫搜尋程式碼)。

加 resource。 MCP server 還能公開 resource(唯讀資料,像檔案或 API 回應)和 prompt(預先寫好的範本)。SDK 三種都支援。詳情請參考 MCP 規格文件。

發布分享。 如果你的 server 對別人有用,發到 npm 上。寫清楚 README,附上 .mcp.json 設定片段。MCP 生態正在快速成長,最好的貢獻方式就是為還沒有 server 的 API 建一個。

探索生態系。 到 MCP servers 儲存庫瀏覽現有的 server 找靈感。如果你正在建構自己的 AI CLI workflow,MCP server 就是讓 agent 真正好用的可組合元件。

更深入的 Claude Code 設定模式,包括 CLAUDE.md 常見錯誤和進階 agent skill,那些指南從這篇教學結束的地方接續。

DH
Free Download

Ready to streamline your terminal workflow?

Multi-terminal drag-and-drop layout, workspace Git sync, built-in AI integration, AST code analysis — all in one app.

Download Termdock →
#mcp#model-context-protocol#claude-code#tutorial#ai-cli#server

相關文章