初めての MCP Server を構築:Director Mode Assistant
実用的な MCP Server を構築しながら MCP 開発を学びましょう。TDD、Auto-Cycle、SpecKit の概念をデモンストレーション。TypeScript、テスト、ベストプラクティスが含まれています。
🎯 構築するもの
このチュートリアルでは、3つのコア Director Mode 概念を実証する完全な MCP Server をゼロから構築します:
- TDD サイクル管理 - Red-Green-Refactor ワークフローの追跡とガイダンス
- Auto-Cycle 進度状況 - 自動化された開発イテレーションの監視
- SpecKit 検証 - 仕様と実装の一貫性の検証
このサーバーには 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:サーバーエントリポイントを作成
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';
// サーバーインスタンスを作成
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}`);
}
});
// サーバーを起動
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
🚀 サーバーを実行
ステップ 7:ビルドしてテスト
# TypeScript をビルド
npm run build
# サーバーを起動
npm start
ステップ 8:Claude Code から接続
~/.claude.json を作成または更新:
{
"mcpServers": {
"director-mode": {
"command": "node",
"args": ["/path/to/mcp-director-mode-server/dist/index.js"]
}
}
}
Claude Code を再起動してサーバーが読み込まれたことを確認:
claude mcp list
📖 使用例
例 1:TDD 状態を確認
Claude Code で:
director-mode server を使って現在のプロジェクトの TDD 状態を確認して
Claude は check_tdd_status ツールを呼び出して報告:
現在の TDD フェーズ:GREEN
テスト:15 件合格、0 件失敗
次のステップ:コードをきれいにするリファクリングを検討
例 2:TDD ガイダンスを取得
RED フェーズにいます。次は何をすべきですか?
Claude はサーバーを使って提案:
テストを通過させる最小限のコードを書いてください。
今は完璧さを気にせず、テストを通すことに集中してください。
すべてのテストが緑色になったら、リファクリングできます。
🎓 実証されるコア MCP 概念
1. ツール設計
ツールは MCP サーバーが機能を公開する主な方法です:
{
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
ベストプラクティス:
- セッションをまたぐ持久化状態
- 不変更新(新しい状態を作成、既存を変更しない)
- 互換性のための JSON シリアライゼーション
3. エラー処理
常にエラーを優雅に処理:
try {
const output = execSync('npm test', { cwd: projectPath });
return parseSuccess(output);
} catch (error) {
return parseFailure(error.stdout);
}
ベストプラクティス:
- サーバーをクラッシュさせない
- 意味のあるエラーメッセージを提供
- デバッグのために stderr にエラーを記録
🏗️ プロジェクト構造
mcp-director-mode-server/
├── src/
│ ├── index.ts # サーバーエントリポイント
│ ├── 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
🚦 次のステップ
サーバーを強化
-
さらにツールを追加
validate_refactor- リファクリングが安全か確認generate_tests- テストスキャフォールドを生成run_cycle_step- Auto-Cycle イテレーションを実行
-
リソースを追加
project://state- 現在のプロジェクト状態project://metrics- 品質メトリクスダッシュボードcycle://history- Auto-Cycle 履歴ログ
-
テストを改善
- モック MCP クライアントでの統合テストを追加
- エラーシナリオをテスト
- 本物の Claude Code 接続での E2E テストを追加
サーバーを公開
# 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 ツールを作らないで。まずは:
- ✅ 1 つのシンプルなツール(例:
check_tdd_status) - ✅ 基本的なエラー処理
- ✅ 1 つのテスト
そこから反復していく。
ヒント 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 を構築する方法
- ✅ ツールの設計と実装
- ✅ リソース管理パターン
- ✅ テスト戦略
- ✅ 本番対応サーバーのベストプラクティス
次は何をしましょう?
- サーバーをコミュニティと共有
- さらに高度な MCP 機能を探索
- あなたの特定のワークフローのためのツールを構築
ハッピーコーディング!🚀