MCPサーバーでカスタムツール実装:5分で独自機能を追加する実践ガイド¶
この記事の対象者
- Python基礎知識を持つ中級者で独自ツールをClaude Codeで活用したい方
この記事のポイント¶
- MCPサーバーにカスタムツールを追加
- Claude Codeからそのツールを実行
- 実用的な自動化ツールの基盤構築
なぜこの問題が今重要か¶
MCPはClaude Codeの拡張性の核心ですが、標準ツール以外の実装例が少なく、具体的な追加手順が不明確。独自業務フローの自動化には必須スキルです。
解決ステップ概要¶
| ステップ | 内容 | 到達指標 |
|---|---|---|
| 1 | MCP基本構造の実装 | server.py動作確認 |
| 2 | カスタムツール関数追加 | ツール登録成功 |
| 3 | Claude Code接続テスト | 実際のツール実行 |
ステップ1: MCP基本サーバー実装¶
最小限のMCPサーバーを作成し、カスタムツールの土台を準備します。
# server.py
import asyncio
from mcp import Tool
from mcp.server import Server
from mcp.types import ToolResult
server = Server("custom-tools")
@server.list_tools()
async def list_tools():
return [
Tool(
name="file_validator",
description="ファイル存在確認と基本情報取得",
inputSchema={
"type": "object",
"properties": {
"filepath": {"type": "string"}
},
"required": ["filepath"]
}
)
]
ステップ2: カスタムツール関数の実装¶
実用的なファイル検証ツールを実装し、MCPサーバーに登録します。
import os
import stat
from datetime import datetime
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "file_validator":
filepath = arguments["filepath"]
try:
if not os.path.exists(filepath):
return ToolResult(content=f"❌ ファイル不存在: {filepath}")
file_stat = os.stat(filepath)
size_mb = file_stat.st_size / 1024 / 1024
modified = datetime.fromtimestamp(file_stat.st_mtime)
permissions = stat.filemode(file_stat.st_mode)
result = f"""✅ ファイル検証結果:
📄 パス: {filepath}
📊 サイズ: {size_mb:.2f} MB
🕐 最終更新: {modified}
🔒 権限: {permissions}"""
return ToolResult(content=result)
except Exception as e:
return ToolResult(content=f"❌ エラー: {str(e)}", isError=True)
if __name__ == "__main__":
asyncio.run(server.run())
ステップ3: Claude Code接続設定¶
claude_desktop_config.json にサーバー情報を追加し、Claude Codeから利用可能にします。
{
"mcpServers": {
"custom-tools": {
"command": "python",
"args": ["path/to/server.py"],
"env": {}
}
}
}
よくある落とし穴と対処¶
| 症状 | 原因 | 即時対処 |
|---|---|---|
| ツールが表示されない | 設定ファイルパス誤り | 絶対パスで指定 |
| 実行エラー | Python環境不一致 | 仮想環境で統一 |
| 権限エラー | ファイルアクセス権限 | chmod +x server.py |
詳細設定(高度最適化)
### 複数ツール対応tools = [
Tool(name="file_validator", ...),
Tool(name="log_analyzer", ...),
Tool(name="config_generator", ...)
]
try:
# ツール実行
except FileNotFoundError:
return ToolResult(content="ファイル未検出", isError=True)
except PermissionError:
return ToolResult(content="アクセス権限不足", isError=True)