# Technical Documentation - Docker MCP Server
## 1. Architecture Overview
### 1.1 System Design
```mermaid
graph TB
A[Claude Code] -->|JSON-RPC| B[Docker MCP Server]
B -->|Python Docker SDK| C[Docker Daemon]
C --> D[Containers]
C --> E[Images]
C --> F[Volumes]
C --> G[Networks]
B --> H[Handler Layer]
H --> I[Docker Executor]
I --> J[Response Formatter]
```
### 1.2 Component Responsibilities
| Component | Responsibility | Technology |
|-----------|---------------|------------|
| Server Entry Point | Initialize MCP server, handle lifecycle | Python asyncio |
| Handler Layer | Process tool calls, validate inputs | MCP SDK |
| Docker Executor | Execute Docker operations | docker-py |
| Response Formatter | Format responses for Claude | JSON/Text |
## 2. Installation & Setup
### 2.1 Prerequisites
```bash
# System Requirements
- Docker Engine 20.10+
- Python 3.11+
- 100MB disk space
- Unix-based OS (Linux/macOS)
```
### 2.2 Installation Steps
#### Method 1: Docker Container (Recommended)
```bash
# Clone repository
git clone https://github.com/your-org/docker-mcp-py
cd docker-mcp-py
# Build Docker image
sudo docker build -t docker-mcp-py:latest .
# Configure Claude Code
cat >> ~/.claude.json << 'EOF'
{
"mcpServers": {
"docker-mcp-py": {
"type": "stdio",
"command": "/path/to/docker-mcp-py/start-docker.sh",
"args": [],
"env": {}
}
}
}
EOF
```
#### Method 2: Local Python Installation
```bash
# Install dependencies
pip install -r requirements.txt
# Run directly
python docker_mcp_server.py
```
## 3. API Reference
### 3.1 Container Management
#### create-container
Creates a new Docker container.
**Parameters:**
```typescript
{
image: string; // Required: Docker image
name?: string; // Container name
ports?: { // Port mapping
[containerPort: string]: hostPort: string
};
environment?: { // Environment variables
[key: string]: value: string
};
volumes?: string[]; // Volume mounts
network?: string; // Network to join
restart?: string; // Restart policy
command?: string; // Override CMD
}
```
**Example:**
```json
{
"image": "nginx:alpine",
"name": "web-server",
"ports": {"80": "8080"},
"environment": {"ENV": "production"}
}
```
#### list-containers
Lists Docker containers with filtering options.
**Parameters:**
```typescript
{
all?: boolean; // Include stopped containers
filters?: {
status?: string; // running|exited|paused
label?: string; // Label filter
name?: string; // Name pattern
network?: string; // Network name
}
}
```
#### get-logs
Retrieves container logs.
**Parameters:**
```typescript
{
container_name: string; // Required
tail?: number; // Lines from end (default: 100)
follow?: boolean; // Stream logs
timestamps?: boolean; // Include timestamps
since?: string; // Since timestamp
until?: string; // Until timestamp
}
```
### 3.2 Docker Compose Management
#### deploy-compose
Deploys a Docker Compose stack.
**Parameters:**
```typescript
{
project_name: string; // Required: Project name
compose_yaml?: string; // YAML content
compose_file?: string; // OR file path
environment?: { // Environment overrides
[key: string]: string
}
}
```
**Example:**
```json
{
"project_name": "myapp",
"compose_yaml": "version: '3.8'\nservices:\n web:\n image: nginx"
}
```
#### compose-down
Stops and removes a Compose stack.
**Parameters:**
```typescript
{
project_name: string; // Required
remove_volumes?: boolean; // Remove named volumes
remove_images?: boolean; // Remove images
}
```
### 3.3 Image Management
#### pull-image
Downloads a Docker image.
**Parameters:**
```typescript
{
image: string; // Image name with optional tag
}
```
#### list-images
Lists available Docker images.
**Parameters:**
```typescript
{} // No parameters required
```
### 3.4 Volume Management
#### list-volumes
Lists Docker volumes.
**Parameters:**
```typescript
{
filters?: {
dangling?: boolean; // Only dangling volumes
label?: string; // Label filter
}
}
```
## 4. Error Handling
### 4.1 Error Response Format
```json
{
"type": "text",
"text": "Error: <error_type>: <message> | Context: <details>"
}
```
### 4.2 Common Errors
| Error Code | Description | Resolution |
|------------|-------------|------------|
| DKR-001 | Docker daemon not accessible | Check Docker service status |
| DKR-002 | Container not found | Verify container name/ID |
| DKR-003 | Image not found | Pull image first |
| DKR-004 | Invalid configuration | Check parameter format |
| DKR-005 | Permission denied | Check socket permissions |
| DKR-006 | Port already in use | Use different port |
### 4.3 Error Recovery
```python
# Automatic retry logic
MAX_RETRIES = 3
RETRY_DELAY = 1 # seconds
async def execute_with_retry(operation):
for attempt in range(MAX_RETRIES):
try:
return await operation()
except TransientError as e:
if attempt < MAX_RETRIES - 1:
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
else:
raise
```
## 5. Security Implementation
### 5.1 Input Validation
```python
# Parameter validation using Pydantic
from pydantic import BaseModel, validator
class ContainerParams(BaseModel):
image: str
name: Optional[str] = None
ports: Optional[Dict[str, str]] = None
@validator('image')
def validate_image(cls, v):
if not re.match(r'^[a-zA-Z0-9][a-zA-Z0-9_.-]+(/[a-zA-Z0-9_.-]+)*(:[a-zA-Z0-9_.-]+)?$', v):
raise ValueError('Invalid image format')
return v
```
### 5.2 Socket Security
```yaml
# Docker socket mounting (read-only where possible)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
```
### 5.3 Secret Handling
```python
# Never log sensitive information
def sanitize_env_vars(env_dict):
sensitive_keys = ['PASSWORD', 'SECRET', 'TOKEN', 'KEY']
sanitized = {}
for key, value in env_dict.items():
if any(s in key.upper() for s in sensitive_keys):
sanitized[key] = '***REDACTED***'
else:
sanitized[key] = value
return sanitized
```
## 6. Performance Optimization
### 6.1 Async Operations
```python
# Parallel execution for multiple operations
async def list_all_resources():
tasks = [
list_containers(),
list_images(),
list_volumes(),
list_networks()
]
results = await asyncio.gather(*tasks)
return combine_results(results)
```
### 6.2 Caching Strategy
```python
# LRU cache for frequently accessed data
from functools import lru_cache
from datetime import datetime, timedelta
@lru_cache(maxsize=128)
def get_cached_image_info(image_id):
return docker_client.images.get(image_id)
# Cache invalidation
def invalidate_cache():
get_cached_image_info.cache_clear()
```
### 6.3 Resource Limits
```yaml
# Container resource constraints
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
```
## 7. Testing
### 7.1 Unit Test Example
```python
import pytest
from unittest.mock import Mock, patch
@pytest.mark.asyncio
async def test_create_container():
mock_docker = Mock()
mock_docker.containers.create.return_value = Mock(id='abc123')
with patch('docker.from_env', return_value=mock_docker):
result = await create_container({
'image': 'nginx:latest',
'name': 'test-container'
})
assert 'abc123' in result['text']
mock_docker.containers.create.assert_called_once()
```
### 7.2 Integration Test
```python
@pytest.mark.integration
async def test_full_container_lifecycle():
# Create container
create_result = await create_container({
'image': 'alpine:latest',
'name': 'test-lifecycle',
'command': 'sleep 30'
})
# Verify running
list_result = await list_containers({'filters': {'name': 'test-lifecycle'}})
assert 'test-lifecycle' in list_result
# Stop and remove
await stop_container({'container_name': 'test-lifecycle'})
await remove_container({'container_name': 'test-lifecycle'})
```
## 8. Debugging
### 8.1 Debug Mode
```bash
# Enable debug logging
export MCP_DEBUG=true
export LOG_LEVEL=DEBUG
# Run with verbose output
./start-docker.sh 2>&1 | tee debug.log
```
### 8.2 Common Issues
#### Issue: Connection Failed
```bash
# Check Docker daemon
sudo systemctl status docker
# Verify socket permissions
ls -la /var/run/docker.sock
# Test socket connectivity
docker version
```
#### Issue: Import Error - Module Path
```python
# Fixed import path issue
# Wrong:
from src.docker_mcp.server import main
# Correct:
from src.server import main
```
#### Issue: Async Runtime Warning
```python
# Wrong: Missing async context
if __name__ == "__main__":
sys.exit(main()) # RuntimeWarning
# Correct: Proper async execution
if __name__ == "__main__":
asyncio.run(main())
```
### 8.3 Log Analysis
```bash
# Filter errors from logs
grep -E "ERROR|CRITICAL" /var/log/docker-mcp-py.log
# Monitor real-time
tail -f /var/log/docker-mcp-py.log | grep -v DEBUG
# JSON log parsing
cat logs.json | jq '.[] | select(.level == "ERROR")'
```
## 9. Monitoring
### 9.1 Health Check Implementation
```python
@server.list_resources()
async def handle_health_check():
try:
docker_client = docker.from_env()
docker_client.ping()
return {
"status": "healthy",
"docker": "connected",
"version": docker_client.version()
}
except Exception as e:
return {
"status": "unhealthy",
"error": str(e)
}
```
### 9.2 Metrics Collection
```python
# Prometheus metrics
from prometheus_client import Counter, Histogram
operation_counter = Counter('docker_mcp_operations_total',
'Total operations', ['operation', 'status'])
operation_duration = Histogram('docker_mcp_operation_duration_seconds',
'Operation duration', ['operation'])
@operation_duration.time()
async def tracked_operation(operation_name, func):
try:
result = await func()
operation_counter.labels(operation_name, 'success').inc()
return result
except Exception as e:
operation_counter.labels(operation_name, 'error').inc()
raise
```
## 10. Migration Guide
### 10.1 From Direct Docker Commands
```bash
# Before: Direct Docker CLI
docker run -d --name web -p 8080:80 nginx
# After: Via MCP Tool
{
"tool": "create-container",
"params": {
"image": "nginx",
"name": "web",
"ports": {"80": "8080"}
}
}
```
### 10.2 From Docker Compose CLI
```bash
# Before: Docker Compose CLI
docker-compose -f stack.yml up -d
# After: Via MCP Tool
{
"tool": "deploy-compose",
"params": {
"project_name": "mystack",
"compose_file": "stack.yml"
}
}
```
---
**Document Version**: 1.0.0
**Last Updated**: 2025-08-28
**Technical Contact**: DevOps Team