Claude Code MCP Server構築ガイド|自作MCPで機能拡張する方法【2026年版】
Claude Codeの真の力を引き出すのがMCP(Model Context Protocol)です。MCPサーバーを追加することで、Claude Codeにデータベース操作やAPI連携、ファイル管理など、標準にない機能を自由に拡張できます。この記事では、MCPの仕組みからTypeScript/Node.jsでの自作方法、settings.jsonでの設定、実用的なサーバー例3選、公開MCPの探し方まで、2026年最新の情報を網羅的に解説します。
目次
1. MCPとは何か? アーキテクチャ図解
MCP(Model Context Protocol)は、Anthropicが策定したオープンプロトコルです。AIアプリケーション(クライアント)と外部ツール(サーバー)を標準化された方法でつなぎ、Claude Codeのようなツールに無限の拡張性をもたらします。
MCPのアーキテクチャ
MCPはクライアント-サーバーモデルで動作します。以下の図で全体像を把握しましょう。
┌─────────────────────────────────────────────────────────┐
│ Claude Code (Host) │
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌─────────────┐ │
│ │ MCP Client 1 │ │ MCP Client 2 │ │ MCP Client 3│ │
│ └───────┬───────┘ └───────┬───────┘ └──────┬──────┘ │
└──────────┼──────────────────┼─────────────────┼────────┘
│ stdio │ stdio │ SSE
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ MCP Server │ │ MCP Server │ │ MCP Server │
│ (ファイル操作) │ │ (DB操作) │ │ (API連携) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ ローカルファイル │ │ PostgreSQL │ │ Slack API │
│ │ │ MySQL │ │ GitHub API │
└──────────────┘ └──────────────┘ └──────────────┘
MCPが提供する3つの機能
MCPサーバーは以下の3種類の機能を提供できます。
| 機能 | 説明 | 例 |
|---|---|---|
| Tools(ツール) | AIが呼び出せる関数 | DBクエリ実行、ファイル作成 |
| Resources(リソース) | AIが読み取れるデータソース | 設定ファイル、ログデータ |
| Prompts(プロンプト) | 再利用可能なプロンプトテンプレート | コードレビュー、SQLクエリ生成 |
Claude Codeでは主にToolsが活用されます。ツールとして定義した関数をClaude Codeが自動的に認識し、必要に応じて呼び出してくれます。
なぜMCPが重要なのか
- 標準化: ツールごとに独自のAPIを学ぶ必要がなくなる
- 再利用性: 一度作ったMCPサーバーはどのMCPクライアントでも使える
- セキュリティ: サーバーが明示的に公開した機能だけがアクセス可能
- エコシステム: npm/GitHubで公開されたサーバーをすぐに利用できる
2. MCPサーバーの開発環境セットアップ
必要な環境
- Node.js 18以上(20 LTS推奨)
- npm 9以上
- TypeScript 5.0以上
- Claude Code(最新版)
プロジェクトの初期化
まず、MCPサーバー用のプロジェクトを作成します。
# プロジェクトディレクトリの作成
mkdir my-mcp-server
cd my-mcp-server
# package.json の初期化
npm init -y
# 必要パッケージのインストール
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
# TypeScript設定の生成
npx tsc --init
tsconfig.json の設定
MCPサーバー開発に適した設定を行います。
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "build"]
}
package.json の調整
ビルドスクリプトとエントリポイントを設定します。
{
"name": "my-mcp-server",
"version": "1.0.0",
"type": "module",
"bin": {
"my-mcp-server": "./build/index.js"
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"start": "node build/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.5.0"
}
}
ポイント: "type": "module" を必ず指定してください。MCP SDKはESModuleで提供されています。
3. 自作MCPサーバーをステップバイステップで構築
ここから、実際にMCPサーバーを一から構築します。最もシンプルな「Hello World」サーバーから始めて、段階的に機能を追加していきます。
Step 1: 最小構成のMCPサーバー
src/index.ts にサーバーの本体を作成します。
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// MCPサーバーの作成
const server = new McpServer({
name: "my-first-mcp",
version: "1.0.0",
});
// ツールの定義: greet
server.tool(
"greet", // ツール名
"指定した名前で挨拶を返す", // 説明(Claude Codeが判断材料にする)
{
name: z.string().describe("挨拶する相手の名前"),
},
async ({ name }) => {
return {
content: [
{
type: "text",
text: `こんにちは、${name}さん!MCPサーバーから挨拶します。`,
},
],
};
}
);
// サーバーの起動
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP Server is running on stdio");
}
main().catch(console.error);
Step 2: ビルドと動作確認
# ビルド
npm run build
# 動作確認(Ctrl+Cで終了)
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | node build/index.js
JSONレスポンスが返ってくれば、サーバーは正常に動作しています。
Step 3: Claude Codeに登録する
# MCPサーバーをClaude Codeに登録
claude mcp add my-first-mcp node /absolute/path/to/my-mcp-server/build/index.js
# 登録確認
claude mcp list
登録後、Claude Codeを起動すると自動的にMCPサーバーに接続します。「○○さんに挨拶して」のように話しかけると、定義したgreetツールが呼び出されます。
Step 4: 複数ツールの追加
ツールは何個でも追加できます。以下は現在時刻を返すツールの例です。
// ツールの定義: current_time
server.tool(
"current_time",
"現在の日時をISO 8601形式で返す",
{}, // パラメータなし
async () => {
const now = new Date().toISOString();
return {
content: [
{
type: "text",
text: `現在時刻: ${now}`,
},
],
};
}
);
// ツールの定義: calculate
server.tool(
"calculate",
"四則演算を実行する",
{
expression: z.string().describe("計算式(例: 2 + 3 * 4)"),
},
async ({ expression }) => {
try {
// 安全な計算(Functionコンストラクタでの直接eval回避)
const sanitized = expression.replace(/[^0-9+\-*/().%\s]/g, "");
const result = new Function(`return (${sanitized})`)();
return {
content: [{ type: "text", text: `計算結果: ${expression} = ${result}` }],
};
} catch (error) {
return {
content: [{ type: "text", text: `計算エラー: ${String(error)}` }],
isError: true,
};
}
}
);
Step 5: リソースの追加
ToolsだけでなくResourcesも定義できます。リソースはClaude Codeがコンテキストとして読み取れるデータです。
// リソースの定義: サーバー設定情報
server.resource(
"server-config",
"config://server",
async (uri) => {
const config = {
serverName: "my-first-mcp",
version: "1.0.0",
availableTools: ["greet", "current_time", "calculate"],
startedAt: new Date().toISOString(),
};
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(config, null, 2),
},
],
};
}
);
4. .claude/settings.json でのMCP設定方法
MCPサーバーの登録情報は ~/.claude/settings.json に保存されます。CLIコマンドでの追加が便利ですが、直接JSONを編集することも可能です。
CLIでの管理コマンド
# MCPサーバーを追加(stdioトランスポート)
claude mcp add <server-name> <command> [args...]
# 具体例
claude mcp add my-server node /path/to/build/index.js
claude mcp add db-server npx -y @example/db-mcp-server
# 環境変数付きで追加
claude mcp add api-server -e API_KEY=sk-xxx node /path/to/server.js
# サーバー一覧の表示
claude mcp list
# サーバーの削除
claude mcp remove <server-name>
settings.json の構造
~/.claude/settings.json のMCPセクションは以下のような構造です。
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/absolute/path/to/build/index.js"],
"env": {}
},
"db-server": {
"command": "npx",
"args": ["-y", "@example/db-mcp-server"],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
}
},
"remote-server": {
"type": "sse",
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer your-api-key"
}
}
}
}
プロジェクト固有の設定
プロジェクトごとにMCPサーバーを設定したい場合は、プロジェクトルートの .claude/settings.json に記述します。
# グローバル設定に追加(全プロジェクトで使用)
claude mcp add -s user my-server node /path/to/server.js
# プロジェクト固有の設定に追加
claude mcp add -s project my-server node /path/to/server.js
| 設定ファイルの場所 | スコープ | 用途 |
|---|---|---|
~/.claude/settings.json |
グローバル | 全プロジェクトで使うサーバー |
.claude/settings.json |
プロジェクト | そのプロジェクト専用のサーバー |
注意: settings.jsonを直接編集する場合、JSONの構文が正しいことを確認してください。コンマの付け忘れやパスの誤りは最もよくあるエラー原因です。
5. 実用例1: ファイル操作MCPサーバー
最初の実用例として、ファイルの検索・読み取り・メタデータ取得を行うMCPサーバーを構築します。Claude Codeにはファイル操作機能が内蔵されていますが、特定のディレクトリ構造に特化した操作や、ファイルの統計情報の取得などをMCPで拡張する例です。
// src/file-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import * as fs from "fs/promises";
import * as path from "path";
const server = new McpServer({
name: "file-tools",
version: "1.0.0",
});
// ツール1: ディレクトリのファイル一覧を取得
server.tool(
"list_files",
"指定ディレクトリのファイル一覧をサイズ・更新日時付きで返す",
{
directory: z.string().describe("対象ディレクトリの絶対パス"),
pattern: z.string().optional().describe("フィルター用の拡張子(例: .ts)"),
},
async ({ directory, pattern }) => {
const entries = await fs.readdir(directory, { withFileTypes: true });
const results = [];
for (const entry of entries) {
if (pattern && !entry.name.endsWith(pattern)) continue;
const fullPath = path.join(directory, entry.name);
const stat = await fs.stat(fullPath);
results.push({
name: entry.name,
type: entry.isDirectory() ? "directory" : "file",
size: stat.size,
modified: stat.mtime.toISOString(),
});
}
return {
content: [{
type: "text",
text: JSON.stringify(results, null, 2),
}],
};
}
);
// ツール2: ファイルの統計情報
server.tool(
"file_stats",
"指定ディレクトリ配下のファイル統計情報(総数、合計サイズ、拡張子別内訳)",
{
directory: z.string().describe("対象ディレクトリの絶対パス"),
recursive: z.boolean().optional().default(true).describe("再帰的に探索するか"),
},
async ({ directory, recursive }) => {
const stats: Record<string, { count: number; totalSize: number }> = {};
let totalFiles = 0;
let totalSize = 0;
async function scan(dir: string) {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory() && recursive) {
await scan(fullPath);
} else if (entry.isFile()) {
const ext = path.extname(entry.name) || "(no ext)";
const stat = await fs.stat(fullPath);
if (!stats[ext]) stats[ext] = { count: 0, totalSize: 0 };
stats[ext].count++;
stats[ext].totalSize += stat.size;
totalFiles++;
totalSize += stat.size;
}
}
}
await scan(directory);
return {
content: [{
type: "text",
text: JSON.stringify({ totalFiles, totalSize, byExtension: stats }, null, 2),
}],
};
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);
このサーバーを登録すれば、Claude Codeに「srcディレクトリのTypeScriptファイル一覧を見せて」と聞くだけで、サイズや更新日付きのリストが返ります。
6. 実用例2: データベース操作MCPサーバー
データベースへのクエリ実行は、MCPサーバーの最も実用的な活用例のひとつです。ここではSQLiteを使った例を紹介しますが、MySQLやPostgreSQLにも同じパターンで応用できます。
追加パッケージのインストール
npm install better-sqlite3
npm install -D @types/better-sqlite3
サーバーの実装
// src/db-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import Database from "better-sqlite3";
const DB_PATH = process.env.DB_PATH || "./data.db";
const db = new Database(DB_PATH, { readonly: false });
const server = new McpServer({
name: "sqlite-tools",
version: "1.0.0",
});
// ツール1: テーブル一覧を取得
server.tool(
"list_tables",
"データベースのテーブル一覧を返す",
{},
async () => {
const tables = db.prepare(
"SELECT name, sql FROM sqlite_master WHERE type='table' ORDER BY name"
).all();
return {
content: [{ type: "text", text: JSON.stringify(tables, null, 2) }],
};
}
);
// ツール2: テーブルのスキーマ情報
server.tool(
"describe_table",
"指定テーブルのカラム情報を返す",
{
table: z.string().describe("テーブル名"),
},
async ({ table }) => {
// SQLインジェクション対策: テーブル名のバリデーション
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
return {
content: [{ type: "text", text: "不正なテーブル名です" }],
isError: true,
};
}
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
return {
content: [{ type: "text", text: JSON.stringify(columns, null, 2) }],
};
}
);
// ツール3: SELECTクエリの実行
server.tool(
"query",
"SELECT文を実行して結果を返す(読み取り専用)",
{
sql: z.string().describe("実行するSELECT SQL文"),
},
async ({ sql }) => {
// SELECT文のみ許可
const trimmed = sql.trim().toUpperCase();
if (!trimmed.startsWith("SELECT") && !trimmed.startsWith("WITH")) {
return {
content: [{ type: "text", text: "SELECT文またはWITH句のみ実行できます" }],
isError: true,
};
}
try {
const rows = db.prepare(sql).all();
return {
content: [{
type: "text",
text: `${rows.length}件の結果:\n${JSON.stringify(rows, null, 2)}`,
}],
};
} catch (error) {
return {
content: [{ type: "text", text: `クエリエラー: ${String(error)}` }],
isError: true,
};
}
}
);
// ツール4: INSERT/UPDATE/DELETEの実行
server.tool(
"execute",
"INSERT/UPDATE/DELETE文を実行する",
{
sql: z.string().describe("実行するSQL文"),
params: z.array(z.any()).optional().describe("プレースホルダーの値"),
},
async ({ sql, params }) => {
const trimmed = sql.trim().toUpperCase();
if (trimmed.startsWith("SELECT")) {
return {
content: [{ type: "text", text: "SELECT文にはqueryツールを使用してください" }],
isError: true,
};
}
// DROP/ALTERなどの危険な操作を制限
if (trimmed.startsWith("DROP") || trimmed.startsWith("ALTER")) {
return {
content: [{ type: "text", text: "DROP/ALTER文は安全のため実行できません" }],
isError: true,
};
}
try {
const result = db.prepare(sql).run(...(params || []));
return {
content: [{
type: "text",
text: `実行完了: ${result.changes}行に影響`,
}],
};
} catch (error) {
return {
content: [{ type: "text", text: `実行エラー: ${String(error)}` }],
isError: true,
};
}
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);
Claude Codeへの登録(環境変数付き)
# DB_PATHを環境変数で渡す
claude mcp add sqlite-tools -e DB_PATH=/path/to/myproject.db node /path/to/db-server/build/index.js
活用例: 「usersテーブルのスキーマを見せて」「先月登録されたユーザー数を教えて」「status が inactive のレコードを active に更新して」など、自然言語でDB操作ができます。
7. 実用例3: 外部API連携MCPサーバー
外部APIとの連携も、MCPサーバーの強力な活用法です。ここでは天気予報APIを例に、HTTPリクエストの結果を返すMCPサーバーを構築します。
// src/weather-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "weather-api",
version: "1.0.0",
});
// ツール: 天気情報の取得
server.tool(
"get_weather",
"指定都市の現在の天気情報を取得する",
{
city: z.string().describe("都市名(英語: Tokyo, Osaka 等)"),
},
async ({ city }) => {
try {
// Open-Meteo API(無料・APIキー不要)を使用
const geoRes = await fetch(
`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1`
);
const geoData = await geoRes.json() as any;
if (!geoData.results?.length) {
return {
content: [{ type: "text", text: `都市「${city}」が見つかりません` }],
isError: true,
};
}
const { latitude, longitude, name } = geoData.results[0];
const weatherRes = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code`
);
const weather = await weatherRes.json() as any;
const current = weather.current;
const result = {
city: name,
temperature: `${current.temperature_2m}°C`,
humidity: `${current.relative_humidity_2m}%`,
windSpeed: `${current.wind_speed_10m} km/h`,
weatherCode: current.weather_code,
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2),
}],
};
} catch (error) {
return {
content: [{ type: "text", text: `API通信エラー: ${String(error)}` }],
isError: true,
};
}
}
);
// ツール: 複数都市の天気比較
server.tool(
"compare_weather",
"複数都市の天気を比較する",
{
cities: z.array(z.string()).min(2).max(5).describe("比較する都市名の配列"),
},
async ({ cities }) => {
const results = [];
for (const city of cities) {
try {
const geoRes = await fetch(
`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1`
);
const geoData = await geoRes.json() as any;
if (geoData.results?.length) {
const { latitude, longitude, name } = geoData.results[0];
const weatherRes = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,relative_humidity_2m`
);
const weather = await weatherRes.json() as any;
results.push({
city: name,
temperature: `${weather.current.temperature_2m}°C`,
humidity: `${weather.current.relative_humidity_2m}%`,
});
}
} catch (e) {
results.push({ city, error: "取得失敗" });
}
}
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);
APIキーが必要なサービス(OpenAI、Stripe、Slackなど)を連携する場合は、環境変数で安全にキーを渡しましょう。
# APIキーを環境変数で渡してMCPサーバーを登録
claude mcp add slack-tools \
-e SLACK_BOT_TOKEN=xoxb-your-token \
-e SLACK_CHANNEL_ID=C0123456789 \
node /path/to/slack-server/build/index.js
8. OpenClawとMCPの連携
OpenClawは、Claude CodeをベースにしたAIエージェントフレームワークです。MCPサーバーとOpenClawを組み合わせることで、さらに高度な自動化が実現できます。
OpenClawのMCPサポート
OpenClawはClaude Codeと同じMCPプロトコルをサポートしているため、Claude Code用に作成したMCPサーバーをそのままOpenClawでも利用できます。これにより、エージェントが外部システムと連携する際の開発コストが大幅に削減されます。
OpenClawでのMCP設定例
# OpenClawの設定ファイルでMCPサーバーを指定
# ~/.openclaw/config.json
{
"agents": [
{
"name": "main",
"model": "claude-sonnet-4-20250514",
"mcpServers": {
"db-tools": {
"command": "node",
"args": ["/path/to/db-server/build/index.js"],
"env": {
"DB_PATH": "/path/to/production.db"
}
},
"notification": {
"command": "node",
"args": ["/path/to/notification-server/build/index.js"]
}
}
}
]
}
活用シナリオ
- 定期レポート生成: DB操作MCPでデータ取得 → レポート作成 → 通知MCP でSlack送信
- 障害対応自動化: 監視MCP でアラート検知 → ログ分析 → 対処の実行
- コンテンツ管理: CMS用MCP で記事一覧取得 → 分析 → 改善提案
Claude Codeで問題が発生した場合の対処法は トラブルシューティング完全ガイド をご確認ください。MCP接続エラーの解決方法も詳しく解説しています。
9. 公開MCPサーバーの探し方(npm・GitHub)
MCPのエコシステムは急速に拡大しており、すでに多数のMCPサーバーが公開されています。自作する前に、既存のサーバーを活用できないか確認しましょう。
npmでの検索
# @modelcontextprotocolスコープで検索
npm search @modelcontextprotocol
# mcp-server キーワードで検索
npm search mcp-server
# 特定のサーバーをnpxで直接実行(インストール不要)
npx -y @modelcontextprotocol/server-filesystem /path/to/directory
GitHubでの検索
GitHubではトピックやキーワードで検索できます。
# GitHubトピック検索
https://github.com/topics/mcp-server
# Anthropic公式リポジトリ
https://github.com/modelcontextprotocol/servers
MCPディレクトリサイト
| サイト | URL | 特徴 |
|---|---|---|
| mcp.so | mcp.so | カテゴリ別検索、人気順ランキング |
| Glama MCP Directory | glama.ai/mcp/servers | レビュー付き、インストール手順付き |
| Smithery | smithery.ai | ワンクリックインストール機能 |
| MCP Hub | mcphub.io | 用途別のキュレーション |
おすすめの公式MCPサーバー
| サーバー名 | 用途 | インストール |
|---|---|---|
| @modelcontextprotocol/server-filesystem | ファイルシステム操作 | npx -y @modelcontextprotocol/server-filesystem |
| @modelcontextprotocol/server-postgres | PostgreSQL操作 | npx -y @modelcontextprotocol/server-postgres |
| @modelcontextprotocol/server-github | GitHub API連携 | npx -y @modelcontextprotocol/server-github |
| @modelcontextprotocol/server-slack | Slack連携 | npx -y @modelcontextprotocol/server-slack |
| @modelcontextprotocol/server-puppeteer | Webスクレイピング | npx -y @modelcontextprotocol/server-puppeteer |
公開MCPサーバーのワンライナー登録例
# ファイルシステムサーバー(指定ディレクトリに限定してアクセス許可)
claude mcp add filesystem npx -y @modelcontextprotocol/server-filesystem /Users/me/projects
# GitHubサーバー
claude mcp add github -e GITHUB_TOKEN=ghp_xxxx npx -y @modelcontextprotocol/server-github
# PostgreSQLサーバー
claude mcp add postgres -e DATABASE_URL=postgresql://localhost/mydb npx -y @modelcontextprotocol/server-postgres
10. MCP開発のベストプラクティスとTips
1. ツール名と説明は具体的にする
Claude Codeはツールの名前と説明文を読んで、いつ・どのツールを呼び出すか判断します。抽象的な名前(do_stuff)ではなく、具体的な名前(list_active_users)をつけましょう。
// NG: 抽象的すぎる
server.tool("get_data", "データを取得する", ...);
// OK: 具体的で分かりやすい
server.tool(
"get_active_users_count",
"過去30日間にログインしたアクティブユーザー数を返す",
...
);
2. エラーハンドリングを必ず実装する
MCPツールのエラーは isError: true で返します。Claude Codeはエラーレスポンスを受け取ると、ユーザーに状況を説明し、別のアプローチを試みます。
server.tool("risky_operation", "...", { ... }, async (params) => {
try {
const result = await doSomething(params);
return {
content: [{ type: "text", text: JSON.stringify(result) }],
};
} catch (error) {
// isError: true でエラーを明示
return {
content: [{
type: "text",
text: `操作に失敗しました: ${error instanceof Error ? error.message : String(error)}`,
}],
isError: true,
};
}
});
3. Zodで入力バリデーションする
MCPのSDKはZodスキーマを使ってパラメータを定義します。.describe()で各パラメータの説明を必ず付けましょう。
// パラメータの定義例
{
email: z.string().email().describe("対象ユーザーのメールアドレス"),
limit: z.number().min(1).max(100).default(10).describe("取得件数の上限"),
status: z.enum(["active", "inactive", "pending"]).describe("フィルターするステータス"),
tags: z.array(z.string()).optional().describe("タグによるフィルタリング"),
}
4. セキュリティに注意する
- APIキーやパスワードはソースコードに書かず、環境変数で渡す
- ファイル操作は許可ディレクトリに制限する
- SQLはプリペアドステートメントを使用する
- 破壊的な操作(DELETE、DROP)は確認フラグを設ける
- MCPサーバーをnpmに公開する場合、APIキーが含まれていないか確認する
5. デバッグ方法
# MCPサーバーのログを確認する
# stdioサーバーのconsole.errorはクライアントに渡らないため、
# デバッグにはconsole.errorを活用
# MCP Inspectorを使ったデバッグ(公式ツール)
npx @modelcontextprotocol/inspector node build/index.js
# Claude Codeのデバッグモード
claude --debug
Tips: MCP Inspectorは、MCPサーバーの動作をWebブラウザ上でテストできる公式ツールです。ツールの呼び出し、レスポンスの確認、エラーのデバッグが視覚的に行えるため、開発時に非常に便利です。
6. npmに公開する
作成したMCPサーバーはnpmに公開して、他のユーザーと共有できます。
# package.json に以下を追加
{
"name": "@your-org/mcp-server-name",
"bin": {
"mcp-server-name": "./build/index.js"
},
"files": ["build"],
"keywords": ["mcp", "mcp-server", "claude-code"]
}
# ビルドして公開
npm run build
npm publish --access public
公開後は、誰でも以下のコマンドで利用できます。
claude mcp add my-awesome-tool npx -y @your-org/mcp-server-name
11. よくある質問(FAQ)
Q. MCP Serverとは何ですか?Claude Codeとの関係を教えてください。
A.MCP(Model Context Protocol)Serverは、Claude CodeなどのAIツールに外部機能を提供するサーバーです。Claude Codeはクライアントとして動作し、MCPサーバーに接続することで、データベース操作、ファイル管理、API連携など、標準では備わっていない機能を利用できるようになります。
Q. MCPサーバーを自作するには何が必要ですか?
A.Node.js 18以上とnpmが必要です。TypeScriptでの開発が推奨されており、@modelcontextprotocol/sdk パッケージを使うことで、ツール定義やリクエストハンドラを簡潔に実装できます。stdioトランスポートを使う場合、Webサーバーの設定は不要です。
Q. MCPサーバーをClaude Codeに登録する方法は?
A.claude mcp add コマンドを使います。例えば「claude mcp add my-server node /path/to/server/build/index.js」のように、サーバー名とコマンドを指定します。登録内容は ~/.claude/settings.json に保存され、claude mcp list で確認できます。
Q. MCPサーバーが接続できない場合の対処法は?
A.まず「claude mcp list」でサーバーが登録されているか確認し、パスが正しいかチェックしてください。次に、サーバー単体で「node build/index.js」を実行してエラーがないか確認します。settings.jsonの記述ミス(コンマ漏れ等)も多い原因です。詳しくはトラブルシューティング記事をご覧ください。
Q. 公開されているMCPサーバーを探すにはどうすればよいですか?
A.npmで「@modelcontextprotocol」スコープのパッケージを検索するのが最も手軽です。GitHubでは「mcp-server」トピックで検索できます。また、mcp.so やGlama MCP Directoryなどのディレクトリサイトで用途別に探すこともできます。
Q. MCPサーバーでできることの具体例を教えてください。
A.データベースへのクエリ実行、外部APIとの連携(Slack、GitHub、Jiraなど)、ファイルシステムの操作、Webスクレイピング、画像生成、メール送信など多岐にわたります。本質的には、Claude Codeに「新しいツール」を追加するものなので、プログラムで実現できることなら何でもMCPサーバー化できます。
Q. stdioトランスポートとSSEトランスポートの違いは?
A.stdioは標準入出力を使った通信で、ローカル環境での利用に適しています。Claude Codeとの連携ではstdioが主流です。SSE(Server-Sent Events)はHTTPベースの通信で、リモートサーバーとして公開する場合に使います。ローカル用途ならstdio、チームやサービス公開にはSSEを選びましょう。
まとめ
MCP(Model Context Protocol)は、Claude Codeの能力を無限に拡張できるオープンプロトコルです。この記事で解説した内容をまとめます。
- MCPの仕組み: クライアント-サーバーモデルで、Tools/Resources/Promptsの3機能を提供
- 自作の手順: TypeScript + @modelcontextprotocol/sdk で簡潔に実装可能
- settings.jsonの設定: CLIコマンドまたはJSON直接編集で登録
- 実用例: ファイル操作、DB操作、API連携の3パターンを解説
- 公開MCPの活用: npm/GitHub/ディレクトリサイトで既存サーバーを探せる
- ベストプラクティス: 具体的な命名、エラーハンドリング、セキュリティの3点が重要
MCPエコシステムは2026年に入って急速に拡大しており、今からMCPサーバー開発を始めることで、Claude Codeをより強力なツールとして活用できるようになります。まずはこの記事の「Hello World」サーバーから始めて、段階的に自分の業務に特化したMCPサーバーを構築していきましょう。