跳至主要內容
精選 MCP TypeScript 教學 實作 測試

建立您的第一個 MCP Server:Director Mode Assistant

透過建置實用的 MCP Server 學習 MCP 開發,展示 TDD、Auto-Cycle 和 SpecKit 概念。包含完整 TypeScript、測試和最佳實踐。

2026年1月15日 15 分鐘閱讀 作者:Claude World

🎯 您將建什麼

在本教學中,您將從頭開始建立一個完整的 MCP Server,展示三個核心 Director Mode 概念:

  • TDD 循環管理 - 追蹤並引導您的 Red-Green-Refactor 工作流程
  • Auto-Cycle 進度 - 監控自動化開發迭代
  • SpecKit 驗證 - 驗證規格與實作的一致性

這個 server 將包含 9 個工具3 個資源,具備完整 TypeScript 支援、全面測試和詳細文檔。

最終專案: github.com/claude-world/mcp-director-mode-server


📚 前置準備

開始之前,請確保您有:

# 檢查 Node.js 版本(需要 18+)
node --version  # v18.0.0 或更高

# 檢查 TypeScript
npm install -g typescript

# 驗證 Claude Code MCP 支援
claude --mcp list

所需知識

  • 基礎 TypeScript/JavaScript
  • 熟悉命令列工具
  • 瞭解 TDD 概念(有幫助但非必需)

🚀 快速開始

步驟 1:初始化專案

建立新目錄並初始化:

mkdir mcp-director-mode-server
cd mcp-director-mode-server

# 初始化 npm 專案
npm init -y

# 安裝相依套件
npm install @modelcontextprotocol/sdk
npm install --save-dev typescript @types/node vitest

# 初始化 TypeScript
npx tsc --init

更新 package.json

{
  "name": "mcp-director-mode-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "test": "vitest",
    "start": "node dist/index.js"
  }
}

步驟 2:配置 TypeScript

建立 tsconfig.json

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

🛠️ 建置 MCP Server

步驟 3:建立 Server 入口點

建立 src/index.ts

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';

// 建立 server 實例
const server = new Server(
  {
    name: 'director-mode-assistant',
    version: '1.0.0',
  },
  {
    capabilities: {
      tools: {},
      resources: {},
    },
  }
);

// 註冊工具(接下來會新增)
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: 'check_tdd_status',
      description: '檢查當前 TDD 循環狀態(RED/GREEN/REFACTOR)',
      inputSchema: {
        type: 'object',
        properties: {
          projectPath: {
            type: 'string',
            description: '專案目錄路徑',
          },
        },
        required: ['projectPath'],
      },
    },
    // ... 更多工具將在此新增
  ],
}));

// 處理工具呼叫
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case 'check_tdd_status':
      // 實作接下來會新增
      return {
        content: [{
          type: 'text',
          text: 'TDD 狀態:RED - 測試失敗中',
        }],
      };

    default:
      throw new Error(`未知工具:${name}`);
  }
});

// 啟動 server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error('Director Mode Assistant MCP Server 執行中...');
}

main().catch(console.error);

步驟 4:實作 TDD 工具

建立 src/tools/tdd.ts

import { execSync } from 'child_process';
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';

export interface TDDStatus {
  phase: 'RED' | 'GREEN' | 'REFACTOR';
  testCount: number;
  passingTests: number;
  failingTests: number;
  lastRun: Date;
}

export function checkTDDStatus(projectPath: string): TDDStatus {
  // 檢查測試檔案
  const testDir = join(projectPath, 'tests');
  if (!existsSync(testDir)) {
    return {
      phase: 'RED',
      testCount: 0,
      passingTests: 0,
      failingTests: 0,
      lastRun: new Date(),
    };
  }

  // 執行測試並解析輸出
  try {
    const output = execSync('npm test', {
      cwd: projectPath,
      encoding: 'utf-8',
    });

    // 解析測試結果(Jest 範例)
    const match = output.match(/(\d+) passed, (\d+) failed/);
    if (match) {
      const passing = parseInt(match[1]);
      const failing = parseInt(match[2]);

      return {
        phase: failing > 0 ? 'RED' : 'GREEN',
        testCount: passing + failing,
        passingTests: passing,
        failingTests: failing,
        lastRun: new Date(),
      };
    }
  } catch (error: any) {
    // 測試失敗
    const output = error.stdout || error.message;
    const match = output.match(/(\d+) passed, (\d+) failed/);
    if (match) {
      return {
        phase: 'RED',
        testCount: parseInt(match[1]) + parseInt(match[2]),
        passingTests: parseInt(match[1]),
        failingTests: parseInt(match[2]),
        lastRun: new Date(),
      };
    }
  }

  return {
    phase: 'RED',
    testCount: 0,
    passingTests: 0,
    failingTests: 0,
    lastRun: new Date(),
  };
}

export function suggestTDDNextStep(status: TDDStatus): string {
  switch (status.phase) {
    case 'RED':
      return '撰寫最小程式碼讓測試通過';
    case 'GREEN':
      return '所有測試通過!是時候重構以提升整潔度';
    case 'REFACTOR':
      return '重構完成。執行測試以確保沒有破壞任何功能';
    default:
      return '從撰寫失敗的測試開始';
  }
}

步驟 5:新增資源用於狀態管理

建立 src/resources/index.ts

import { readFileSync, writeFileSync, existsSync } from 'fs';
import { join } from 'path';

export interface ProjectState {
  currentPhase: string;
  lastUpdate: Date;
  metrics: {
    totalTests: number;
    testPassRate: number;
    lastCommit: string;
  };
}

const STATE_FILE = '.director-mode-state.json';

export function getProjectState(projectPath: string): ProjectState {
  const statePath = join(projectPath, STATE_FILE);

  if (!existsSync(statePath)) {
    return {
      currentPhase: '初始化中',
      lastUpdate: new Date(),
      metrics: {
        totalTests: 0,
        testPassRate: 0,
        lastCommit: '無',
      },
    };
  }

  const data = readFileSync(statePath, 'utf-8');
  return JSON.parse(data);
}

export function updateProjectState(
  projectPath: string,
  updates: Partial<ProjectState>
): void {
  const current = getProjectState(projectPath);
  const updated = {
    ...current,
    ...updates,
    lastUpdate: new Date(),
  };

  const statePath = join(projectPath, STATE_FILE);
  writeFileSync(statePath, JSON.stringify(updated, null, 2));
}

🧪 測試您的 MCP Server

步驟 6:建立測試

建立 tests/tdd.test.ts

import { describe, it, expect } from 'vitest';
import { checkTDDStatus, suggestTDDNextStep } from '../src/tools/tdd.js';

describe('TDD 工具', () => {
  it('應該在 RED 階段偵測到失敗的測試', () => {
    const status = {
      phase: 'RED',
      testCount: 10,
      passingTests: 7,
      failingTests: 3,
      lastRun: new Date(),
    };

    const suggestion = suggestTDDNextStep(status);
    expect(suggestion).toContain('撰寫最小程式碼');
  });

  it('應該在 GREEN 階段建議重構', () => {
    const status = {
      phase: 'GREEN',
      testCount: 10,
      passingTests: 10,
      failingTests: 0,
      lastRun: new Date(),
    };

    const suggestion = suggestTDDNextStep(status);
    expect(suggestion).toContain('重構');
  });
});

執行測試:

npm test

🚀 執行 Server

步驟 7:建置並測試

# 建置 TypeScript
npm run build

# 啟動 server
npm start

步驟 8:從 Claude Code 連接

建立或更新 ~/.claude.json

{
  "mcpServers": {
    "director-mode": {
      "command": "node",
      "args": ["/path/to/mcp-director-mode-server/dist/index.js"]
    }
  }
}

重啟 Claude Code 並驗證 server 已載入:

claude mcp list

📖 使用範例

範例 1:檢查 TDD 狀態

在 Claude Code 中:

使用 director-mode server 檢查我目前專案的 TDD 狀態

Claude 將呼叫 check_tdd_status 工具並報告:

當前 TDD 階段:GREEN
測試:15 個通過,0 個失敗
下一步:考慮重構以提升程式碼整潔度

範例 2:取得 TDD 指導

我在 RED 階段。下一步該做什麼?

Claude 將使用 server 建議:

撰寫最小程式碼讓測試通過。

現在不要擔心完美——專注於讓測試通過。
一旦所有測試都綠了,就可以重構。

🎓 展示的核心 MCP 概念

1. 工具設計

工具是 MCP server 暴露功能的主要方式:

{
  name: 'check_tdd_status',
  description: '檢查當前 TDD 循環狀態',
  inputSchema: {
    type: 'object',
    properties: {
      projectPath: { type: 'string' }
    },
    required: ['projectPath']
  }
}

最佳實踐

  • 清晰、描述性的名稱
  • 詳細的輸入驗證(JSON Schema)
  • 有幫助的描述讓 Claude 理解

2. 資源管理

資源提供狀態和配置:

export function getProjectState(projectPath: string): ProjectState
export function updateProjectState(path, updates): void

最佳實踐

  • 跨 session 的持久化狀態
  • 不可變更新(建立新狀態,不要變更原狀態)
  • JSON 序列化以保持相容性

3. 錯誤處理

總是優雅地處理錯誤:

try {
  const output = execSync('npm test', { cwd: projectPath });
  return parseSuccess(output);
} catch (error) {
  return parseFailure(error.stdout);
}

最佳實踐

  • 永遠不要讓錯誤導致 server 當機
  • 提供有意義的錯誤訊息
  • 記錄錯誤到 stderr 以便除錯

🏗️ 專案結構

mcp-director-mode-server/
├── src/
│   ├── index.ts           # Server 入口點
│   ├── tools/
│   │   ├── tdd.ts         # TDD 循環工具
│   │   ├── cycle.ts       # Auto-cycle 工具
│   │   └── spec.ts        # SpecKit 工具
│   └── resources/
│       └── index.ts       # 狀態管理
├── tests/
│   ├── tdd.test.ts        # 工具測試
│   └── integration.test.ts # 整合測試
├── examples/
│   ├── basic-usage.md     # 使用範例
│   └── tdd-workflow.md    # TDD 工作流程指南
├── docs/
│   └── ARCHITECTURE.md    # 設計決策
├── package.json
├── tsconfig.json
└── vitest.config.ts

🚦 下一步

增強您的 Server

  1. 新增更多工具

    • validate_refactor - 檢查重構是否安全
    • generate_tests - 產生測試腳手架
    • run_cycle_step - 執行 Auto-Cycle 迭代
  2. 新增資源

    • project://state - 當前專案狀態
    • project://metrics - 品質指標儀表板
    • cycle://history - Auto-Cycle 歷史記錄
  3. 改善測試

    • 新增與 mock MCP 用戶端的整合測試
    • 測試錯誤情境
    • 新增與真實 Claude Code 連線的 E2E 測試

發布您的 Server

# 發布到 npm
npm publish

# 或透過 GitHub 分享
git init
git add .
git commit -m "Initial MCP server"
git remote add origin https://github.com/YOUR_USERNAME/your-mcp-server.git
git push -u origin main

📚 更多學習


💡 實戰技巧

技巧 1:從簡單開始

不要一次建立所有 9 個工具。先從:

  • ✅ 一個簡單工具(例如 check_tdd_status
  • ✅ 基礎錯誤處理
  • ✅ 一個測試

然後從那裡迭代。

技巧 2:使用 TypeScript Strict Mode

{
  "compilerOptions": {
    "strict": true  # 早期捕獲錯誤
  }
}

技巧 3:記錄所有內容

console.error('DEBUG: 檢查 TDD 狀態', projectPath);

記錄到 stderr 有助於除錯,而不會干擾 MCP 通訊。

技巧 4:先在本地測試

# 測試您的工具邏輯
node -e "import('./dist/tools/tdd.js').then(m => console.log(m.checkTDDStatus('.')))"

🎉 恭喜!

您已經從頭建立了一個完整的 MCP Server!您現在理解:

  • ✅ 如何使用 TypeScript 建立 MCP Server
  • ✅ 工具設計和實作
  • ✅ 資源管理模式
  • ✅ 測試策略
  • ✅ 生產就緒 server 的最佳實踐

接下來做什麼?

  • 與社群分享您的 server
  • 探索更多進階 MCP 功能
  • 為您的特定工作流程建構工具

祝您開發愉快!🚀