Claude Code完全ガイド2025 - AIペアプログラミングの新時代
Anthropicが2025年5月に正式リリースしたClaude Codeの全機能を徹底解説。ターミナルで動作するAIコーディングエージェントの設定から実践的な使い方まで、開発効率を劇的に向上させる方法を紹介します。
AnthropicのModel Context Protocol(MCP)を使ってClaude用のカスタムツールを開発する方法を徹底解説。ローカルサーバーの構築から実装、デバッグまで実践的なガイドです。
2024 年 11 月に Anthropic が発表した Model Context Protocol(MCP)は、ai アシスタントとデータソースを接続するためのオープンスタンダードです。MCP を使うことで、Claude を Google Drive、Slack、GitHub、データベースなど様々なシステムと統合できます。
本記事では、MCP 開発の基本から実践的なサーバー実装まで、エンジニア向けに包括的に解説します。
Model Context Protocol(MCP)は、ai システムとデータソースを接続するための統一されたプロトコルです。従来、各データソースへの接続には個別の実装が必要でしたが、MCP によって標準化されたインターフェースでの接続が可能になりました。
チャートを読み込み中...
特徴 | 説明 | メリット |
---|---|---|
統一プロトコル | 標準化されたインターフェース | 開発の簡素化 |
双方向通信 | サーバーとクライアント間の対話的なやり取り | リアルタイムな情報取得 |
セキュア | 認証・認可の仕組みを内包 | 安全なデータアクセス |
拡張可能 | カスタムツールの実装が容易 | 柔軟な機能拡張 |
オープンソース | コミュニティ主導の開発 | 透明性と信頼性 |
Node.js 18以上をインストール
最新版をダウンロード
TypeScript/JavaScriptで開発開始
カスタムMCPサーバーを作成
# プロジェクトディレクトリの作成
mkdir my-mcp-server
cd my-mcp-server
# package.jsonの初期化
npm init -y
# 必要なパッケージのインストール
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node tsx
// server.ts(基本実装)
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server({
name: 'my-simple-server',
version: '1.0.0',
});
// ツールの登録
server.setRequestHandler('tools/list', async () => ({
tools: [{
name: 'hello',
description: 'Say hello',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string' }
}
}
}]
}));
// サーバー起動
const transport = new StdioServerTransport();
await server.connect(transport);
// server.ts(プロダクション実装)
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
class MyMCPServer {
private server: Server;
constructor() {
this.server = new Server({
name: 'my-production-server',
version: '1.0.0',
}, {
capabilities: {
tools: {},
resources: {}
}
});
this.setupHandlers();
}
private setupHandlers() {
// スキーマ定義
const HelloSchema = z.object({
name: z.string().min(1),
language: z.enum(['en', 'ja']).default('ja')
});
// ツールハンドラー
this.server.setRequestHandler('tools/list', async () => ({
tools: [{
name: 'hello',
description: '多言語対応の挨拶ツール',
inputSchema: HelloSchema
}]
}));
this.server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
if (name === 'hello') {
const validated = HelloSchema.parse(args);
const greeting = validated.language === 'ja'
? `こんにちは、${validated.name}さん!`
: `Hello, ${validated.name}!`;
return {
content: [{
type: 'text',
text: greeting
}]
};
}
throw new Error(`Unknown tool: ${name}`);
});
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('MCP Server started');
}
}
// サーバー起動
const server = new MyMCPServer();
await server.start();
// server.ts(基本実装)
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server({
name: 'my-simple-server',
version: '1.0.0',
});
// ツールの登録
server.setRequestHandler('tools/list', async () => ({
tools: [{
name: 'hello',
description: 'Say hello',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string' }
}
}
}]
}));
// サーバー起動
const transport = new StdioServerTransport();
await server.connect(transport);
// server.ts(プロダクション実装)
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
class MyMCPServer {
private server: Server;
constructor() {
this.server = new Server({
name: 'my-production-server',
version: '1.0.0',
}, {
capabilities: {
tools: {},
resources: {}
}
});
this.setupHandlers();
}
private setupHandlers() {
// スキーマ定義
const HelloSchema = z.object({
name: z.string().min(1),
language: z.enum(['en', 'ja']).default('ja')
});
// ツールハンドラー
this.server.setRequestHandler('tools/list', async () => ({
tools: [{
name: 'hello',
description: '多言語対応の挨拶ツール',
inputSchema: HelloSchema
}]
}));
this.server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
if (name === 'hello') {
const validated = HelloSchema.parse(args);
const greeting = validated.language === 'ja'
? `こんにちは、${validated.name}さん!`
: `Hello, ${validated.name}!`;
return {
content: [{
type: 'text',
text: greeting
}]
};
}
throw new Error(`Unknown tool: ${name}`);
});
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('MCP Server started');
}
}
// サーバー起動
const server = new MyMCPServer();
await server.start();
MCP サーバーは、ツールだけでなくリソース(ファイル、データ)も提供できます。
// リソースの定義
server.setRequestHandler('resources/list', async () => ({
resources: [
{
uri: 'file://config.json',
name: '設定ファイル',
description: 'アプリケーションの設定',
mimeType: 'application/json'
},
{
uri: 'db://users',
name: 'ユーザーデータ',
description: 'データベースのユーザー情報'
}
]
}));
// リソースの実装
server.setRequestHandler('resources/read', async (request) => {
const { uri } = request.params;
if (uri === 'file://config.json') {
const config = await fs.readFile('./config.json', 'utf-8');
return {
contents: [{
uri,
mimeType: 'application/json',
text: config
}]
};
}
if (uri.startsWith('db://')) {
const table = uri.replace('db://', '');
const data = await database.query(`SELECT * FROM ${table}`);
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(data, null, 2)
}]
};
}
throw new Error(`Resource not found: ${uri}`);
});
// claude_desktop_config.json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["./dist/server.js"],
"env": {
"DATABASE_URL": "postgresql://localhost/mydb",
"API_KEY": "your-api-key"
}
}
}
}
実際に使えるファイルシステム操作用の MCP サーバーを実装してみましょう。
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import fs from 'fs/promises';
import path from 'path';
class FileSystemMCPServer {
private server: Server;
private baseDir: string;
constructor(baseDir: string = process.cwd()) {
this.baseDir = baseDir;
this.server = new Server({
name: 'filesystem-server',
version: '1.0.0',
});
this.setupHandlers();
}
private setupHandlers() {
// ツール一覧
this.server.setRequestHandler('tools/list', async () => ({
tools: [
{
name: 'list_files',
description: 'ディレクトリ内のファイル一覧を取得',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '対象ディレクトリのパス(相対パス)'
}
},
required: ['path']
}
},
{
name: 'read_file',
description: 'ファイルの内容を読み取る',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '読み取るファイルのパス'
}
},
required: ['path']
}
},
{
name: 'write_file',
description: 'ファイルに内容を書き込む',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '書き込むファイルのパス'
},
content: {
type: 'string',
description: '書き込む内容'
}
},
required: ['path', 'content']
}
}
]
}));
// ツール実行
this.server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'list_files':
return await this.listFiles(args.path);
case 'read_file':
return await this.readFile(args.path);
case 'write_file':
return await this.writeFile(args.path, args.content);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [{
type: 'text',
text: `エラー: ${error.message}`
}],
isError: true
};
}
});
}
private async listFiles(relativePath: string) {
const fullPath = path.join(this.baseDir, relativePath);
const files = await fs.readdir(fullPath, { withFileTypes: true });
const fileList = files.map(file => ({
name: file.name,
type: file.isDirectory() ? 'directory' : 'file',
path: path.join(relativePath, file.name)
}));
return {
content: [{
type: 'text',
text: JSON.stringify(fileList, null, 2)
}]
};
}
private async readFile(relativePath: string) {
const fullPath = path.join(this.baseDir, relativePath);
const content = await fs.readFile(fullPath, 'utf-8');
return {
content: [{
type: 'text',
text: content
}]
};
}
private async writeFile(relativePath: string, content: string) {
const fullPath = path.join(this.baseDir, relativePath);
await fs.writeFile(fullPath, content, 'utf-8');
return {
content: [{
type: 'text',
text: `ファイル ${relativePath} に書き込みました。`
}]
};
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
}
// 起動
const server = new FileSystemMCPServer();
await server.start();
~/Library/Application Support/Claude/claude_desktop_config.json
%APPDATA%\Claude\claude_desktop_config.json
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"filesystem": {
"command": "node",
"args": ["./path/to/filesystem-server.js"],
"env": {
"BASE_DIR": "/Users/username/Documents"
}
},
"database": {
"command": "python",
"args": ["./path/to/db-server.py"],
"env": {
"DATABASE_URL": "postgresql://localhost/mydb"
}
}
}
}
問題 | 原因 | 解決方法 |
---|---|---|
サーバーが起動しない | パスの問題 | 絶対パスを使用する |
ツールが表示されない | ハンドラーの登録ミス | tools/listの実装を確認 |
エラーが返される | 例外処理の不足 | try-catchで適切にハンドリング |
接続が切れる | タイムアウト | 定期的なpingを実装 |
権限エラー | ファイルアクセス権 | 適切な権限を設定 |
ログ出力を活用
console.error(`[MCP] ${new Date().toISOString()} - ${message}`);
エラーハンドリングの徹底
try {
// 処理
} catch (error) {
console.error('[MCP Error]', error);
return { content: [{ type: 'text', text: `エラー: ${error.message}` }] };
}
開発用ツールの作成
// デバッグ用のechoツール
{
name: 'debug_echo',
description: 'デバッグ用:入力をそのまま返す',
inputSchema: { type: 'object' }
}
Claude Code がリモート MCP サーバーをサポートしました。これにより、ローカルだけでなくクラウド上の MCP サーバーとも連携可能になり、チーム開発での活用が大幅に向上しています。
オープンソースとして公開
Python、Go対応
Claude Codeで実装
組織向け機能強化(予定)
Model Context Protocol(MCP)は、ai システムとデータソースを接続する新しい標準として、開発者に大きな可能性を提供します。
MCP を活用することで、Claude をより強力な ai アシスタントとして活用できます。ぜひ自分のユースケースに合わせた MCP サーバーを開発してみてください。