Custom Tool Implementation for MCP Server: 5-Minute Guide to Adding Unique Features¶
Target Audience
- Intermediate developers with Python basics who want to leverage custom tools in Claude Code
Key Points¶
- Add custom tools to MCP server
- Execute those tools from Claude Code
- Build foundation for practical automation tools
Why This Matters Now¶
MCP is the core of Claude Code extensibility, but practical implementation examples beyond standard tools are scarce, making custom business workflow automation unclear.
Solution Steps Overview¶
| Step | Content | Success Metric |
|---|---|---|
| 1 | Implement basic MCP structure | server.py operational |
| 2 | Add custom tool functions | Tool registration success |
| 3 | Test Claude Code connection | Actual tool execution |
Step 1: Basic MCP Server Implementation¶
Create minimal MCP server and prepare foundation for custom tools.
# 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="File existence check and basic info retrieval",
inputSchema={
"type": "object",
"properties": {
"filepath": {"type": "string"}
},
"required": ["filepath"]
}
)
]
Step 2: Custom Tool Function Implementation¶
Implement practical file validation tool and register it with MCP server.
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"❌ File not found: {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"""✅ File validation result:
📄 Path: {filepath}
📊 Size: {size_mb:.2f} MB
🕐 Last modified: {modified}
🔒 Permissions: {permissions}"""
return ToolResult(content=result)
except Exception as e:
return ToolResult(content=f"❌ Error: {str(e)}", isError=True)
if __name__ == "__main__":
asyncio.run(server.run())
Step 3: Claude Code Connection Setup¶
Add server information to claude_desktop_config.json to make it available from Claude Code.
{
"mcpServers": {
"custom-tools": {
"command": "python",
"args": ["path/to/server.py"],
"env": {}
}
}
}
Common Pitfalls and Solutions¶
| Symptom | Cause | Immediate Fix |
|---|---|---|
| Tools not showing | Config file path error | Use absolute path |
| Execution errors | Python environment mismatch | Unify with virtual env |
| Permission errors | File access permissions | chmod +x server.py |
Advanced Configuration (Optimization)
### Multiple Tools Supporttools = [
Tool(name="file_validator", ...),
Tool(name="log_analyzer", ...),
Tool(name="config_generator", ...)
]
try:
# Tool execution
except FileNotFoundError:
return ToolResult(content="File not detected", isError=True)
except PermissionError:
return ToolResult(content="Insufficient access rights", isError=True)