Skip to content

Commit c4db2db

Browse files
committed
wip
1 parent b21fac8 commit c4db2db

23 files changed

+457
-688
lines changed

README.md

Lines changed: 243 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,270 @@
1-
# RubyLLM::Docker
1+
# DockerMCP
22

3-
TODO: Delete this and the text below, and describe your gem
3+
A Model Context Protocol (MCP) server that provides comprehensive Docker management capabilities through a standardized interface. This tool enables AI assistants and other MCP clients to interact with Docker containers, images, networks, and volumes programmatically.
44

5-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ruby_llm/docker`. To experiment with that code, run `bin/console` for an interactive prompt.
5+
## ⚠️ Security Warning
66

7-
## Installation
7+
**This tool is inherently unsafe and should be used with extreme caution.**
8+
9+
- **Arbitrary Code Execution**: The `exec_container` tool allows execution of arbitrary commands inside Docker containers
10+
- **File System Access**: The `copy_to_container` tool can copy files from the host system into containers
11+
- **Container Management**: Full container lifecycle management including creation, modification, and deletion
12+
- **Network & Volume Control**: Complete control over Docker networks and volumes
813

9-
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
14+
**Recommendations:**
15+
- Only use in trusted environments
16+
- Ensure proper Docker daemon security configuration
17+
- Consider running with restricted Docker permissions
18+
- Monitor and audit all container operations
19+
- Be cautious when exposing this tool to external or untrusted MCP clients
20+
21+
## Installation
1022

1123
Install the gem and add to the application's Gemfile by executing:
1224

1325
```bash
14-
bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
26+
bundle add docker_mcp
1527
```
1628

1729
If bundler is not being used to manage dependencies, install the gem by executing:
1830

1931
```bash
20-
gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
32+
gem install docker_mcp
2133
```
2234

35+
## Prerequisites
36+
37+
- Docker Engine installed and running
38+
- Ruby 3.2+
39+
- Docker permissions for the user running the MCP server
40+
2341
## Usage
2442

25-
TODO: Write usage instructions here
43+
### MCP Client Configuration
44+
45+
Add this to your MCP client configuration after installing the gem:
46+
47+
```json
48+
{
49+
"docker_mcp": {
50+
"command": "bash",
51+
"args": [
52+
"-l",
53+
"-c",
54+
"docker_mcp"
55+
]
56+
}
57+
}
58+
```
59+
60+
### Example Usage
61+
62+
Once configured, you can use the tools through your MCP client:
63+
64+
```
65+
# List all containers
66+
list_containers
67+
68+
# Create and run a new container
69+
run_container image="nginx:latest" name="my-web-server"
70+
71+
# Execute commands in a container
72+
exec_container id="my-web-server" cmd="nginx -v"
73+
74+
# Copy files to a container
75+
copy_to_container id="my-web-server" source_path="/local/file.txt" destination_path="/var/www/html/"
76+
77+
# View container logs
78+
fetch_container_logs id="my-web-server"
79+
```
80+
81+
## 🔨 Tools
82+
83+
This MCP server provides 22 comprehensive Docker management tools organized by functionality:
84+
85+
### Container Management
86+
87+
- **`list_containers`** - List all Docker containers (running and stopped) with detailed information
88+
- **`create_container`** - Create a new container from an image without starting it
89+
- **`run_container`** - Create and immediately start a container from an image
90+
- **`start_container`** - Start an existing stopped container
91+
- **`stop_container`** - Stop a running container gracefully
92+
- **`remove_container`** - Delete a container (must be stopped first unless forced)
93+
- **`recreate_container`** - Stop, remove, and recreate a container with the same configuration
94+
- **`exec_container`** ⚠️ - Execute arbitrary commands inside a running container
95+
- **`fetch_container_logs`** - Retrieve stdout/stderr logs from a container
96+
- **`copy_to_container`** ⚠️ - Copy files or directories from host to container
97+
98+
### Image Management
99+
100+
- **`list_images`** - List all Docker images available locally
101+
- **`pull_image`** - Download an image from a Docker registry
102+
- **`push_image`** - Upload an image to a Docker registry
103+
- **`build_image`** - Build a new image from a Dockerfile
104+
- **`tag_image`** - Create a new tag for an existing image
105+
- **`remove_image`** - Delete an image from local storage
106+
107+
### Network Management
108+
109+
- **`list_networks`** - List all Docker networks
110+
- **`create_network`** - Create a new Docker network
111+
- **`remove_network`** - Delete a Docker network
112+
113+
### Volume Management
114+
115+
- **`list_volumes`** - List all Docker volumes
116+
- **`create_volume`** - Create a new Docker volume for persistent data
117+
- **`remove_volume`** - Delete a Docker volume
118+
119+
### Tool Parameters
120+
121+
Most tools accept standard Docker parameters:
122+
- **Container ID/Name**: Can use either the full container ID, short ID, or container name
123+
- **Image**: Specify images using `name:tag` format (e.g., `nginx:latest`, `ubuntu:22.04`)
124+
- **Ports**: Use Docker port mapping syntax (e.g., `"8080:80"`)
125+
- **Volumes**: Use Docker volume mount syntax (e.g., `"/host/path:/container/path"`)
126+
- **Environment**: Set environment variables as `KEY=VALUE` pairs
127+
128+
## Common Use Cases
129+
130+
### Development Environment Setup
131+
```bash
132+
# Pull development image
133+
pull_image from_image="node:18-alpine"
134+
135+
# Create development container with volume mounts
136+
run_container image="node:18-alpine" name="dev-env" \
137+
host_config='{"PortBindings":{"3000/tcp":[{"HostPort":"3000"}]},"Binds":["/local/project:/app"]}'
138+
139+
# Execute development commands
140+
exec_container id="dev-env" cmd="npm install"
141+
exec_container id="dev-env" cmd="npm start"
142+
```
143+
144+
### Container Debugging
145+
```bash
146+
# Check container status
147+
list_containers
148+
149+
# View container logs
150+
fetch_container_logs id="problematic-container"
151+
152+
# Execute diagnostic commands
153+
exec_container id="problematic-container" cmd="ps aux"
154+
exec_container id="problematic-container" cmd="df -h"
155+
exec_container id="problematic-container" cmd="netstat -tlnp"
156+
```
157+
158+
### File Management
159+
```bash
160+
# Copy configuration files to container
161+
copy_to_container id="web-server" \
162+
source_path="/local/nginx.conf" \
163+
destination_path="/etc/nginx/"
164+
165+
# Copy application code
166+
copy_to_container id="app-container" \
167+
source_path="/local/src" \
168+
destination_path="/app/"
169+
```
170+
171+
## Error Handling
172+
173+
The server provides detailed error messages for common issues:
174+
175+
- **Container Not Found**: When referencing non-existent containers
176+
- **Image Not Available**: When trying to use images that aren't pulled locally
177+
- **Permission Denied**: When Docker daemon access is restricted
178+
- **Network Conflicts**: When creating networks with conflicting configurations
179+
- **Volume Mount Issues**: When specified paths don't exist or lack permissions
180+
181+
All errors include descriptive messages to help diagnose and resolve issues.
182+
183+
## Troubleshooting
184+
185+
### Docker Daemon Connection Issues
186+
```bash
187+
# Check if Docker daemon is running
188+
docker info
189+
190+
# Verify Docker permissions
191+
docker ps
192+
193+
# Check MCP server logs for connection errors
194+
```
195+
196+
### Container Operation Failures
197+
- Ensure container IDs/names are correct (use `list_containers` to verify)
198+
- Check if containers are in the expected state (running/stopped)
199+
- Verify image availability with `list_images`
200+
201+
### Permission Issues
202+
- Ensure the user running the MCP server has Docker permissions
203+
- Consider adding user to the `docker` group: `sudo usermod -aG docker $USER`
204+
- Verify Docker socket permissions: `ls -la /var/run/docker.sock`
205+
206+
## Limitations
207+
208+
- **Platform Specific**: Some container operations may behave differently across operating systems
209+
- **Docker API Version**: Requires compatible Docker Engine API version
210+
- **Resource Limits**: Large file copies and image operations may timeout
211+
- **Concurrent Operations**: Heavy concurrent usage may impact performance
212+
213+
## Contributing
214+
215+
We welcome contributions! Areas for improvement:
216+
217+
- **Enhanced Security**: Additional safety checks and permission validation
218+
- **Better Error Handling**: More specific error messages and recovery suggestions
219+
- **Performance Optimization**: Streaming for large file operations
220+
- **Extended Functionality**: Support for Docker Compose, Swarm, etc.
221+
- **Testing**: Comprehensive test coverage for all tools
26222

27223
## Development
28224

29225
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30226

31-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
227+
### Running Tests
228+
```bash
229+
# Install dependencies
230+
bundle install
32231

33-
## Contributing
232+
# Run the test suite
233+
bundle exec rake spec
234+
235+
# Run tests with coverage
236+
bundle exec rake spec COVERAGE=true
237+
```
238+
239+
### Local Development Setup
240+
```bash
241+
# Clone the repository
242+
git clone https://github.com/afstanton/docker_mcp.git
243+
cd docker_mcp
34244

35-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ruby_llm-docker.
245+
# Install dependencies
246+
bin/setup
247+
248+
# Start development console
249+
bin/console
250+
251+
# Build the gem locally
252+
bundle exec rake build
253+
254+
# Install locally built gem
255+
bundle exec rake install
256+
```
257+
258+
### Testing with MCP Client
259+
```bash
260+
# Start the MCP server locally
261+
bundle exec exe/docker_mcp
262+
263+
# Configure your MCP client to use local development server
264+
# Use file path instead of installed gem command
265+
```
266+
267+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
36268

37269
## License
38270

lib/ruby_llm/docker.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
# frozen_string_literal: true
22

33
require 'ruby_llm'
4+
require 'docker'
45
require 'zeitwerk'
56

67
loader = Zeitwerk::Loader.for_gem_extension(RubyLLM)
7-
88
loader.setup
99

1010
require_relative 'docker/version'
1111

1212
module RubyLLM
1313
module Docker
1414
class Error < StandardError; end
15-
# Your code goes here...
1615
end
1716
end

lib/ruby_llm/docker/build_image.rb

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,8 @@ module Docker
5454
class BuildImage < RubyLLM::Tool
5555
description 'Build a Docker image'
5656

57-
input_schema(
58-
properties: {
59-
dockerfile: {
60-
type: 'string',
61-
description: 'Dockerfile content as a string'
62-
},
63-
tag: {
64-
type: 'string',
65-
description: 'Tag for the built image (e.g., "myimage:latest")'
66-
}
67-
},
68-
required: ['dockerfile']
69-
)
57+
param :dockerfile, type: :string, description: 'Dockerfile content as a string'
58+
param :tag, type: :string, description: 'Tag for the built image (e.g., "myimage:latest")', required: false
7059

7160
# Build a Docker image from Dockerfile content.
7261
#
@@ -92,16 +81,15 @@ class BuildImage < RubyLLM::Tool
9281
# CMD ["nginx", "-g", "daemon off;"]
9382
# DOCKERFILE
9483
#
95-
# response = BuildImage.call(
96-
# server_context: context,
84+
# response = tool.execute(
9785
# dockerfile: dockerfile,
9886
# tag: "my-nginx:latest"
9987
# )
10088
#
10189
# @see Docker::Image.build
102-
def self.call(dockerfile:, server_context:, tag: nil)
90+
def execute(dockerfile:, tag: nil)
10391
# Build the image
104-
image = Docker::Image.build(dockerfile)
92+
image = ::Docker::Image.build(dockerfile)
10593

10694
# If a tag was specified, tag the image
10795
if tag
@@ -114,15 +102,9 @@ def self.call(dockerfile:, server_context:, tag: nil)
114102
response_text = "Image built successfully. ID: #{image.id}"
115103
response_text += ", Tag: #{tag}" if tag
116104

117-
RubyLLM::Tool::Response.new([{
118-
type: 'text',
119-
text: response_text
120-
}])
105+
response_text
121106
rescue StandardError => e
122-
RubyLLM::Tool::Response.new([{
123-
type: 'text',
124-
text: "Error building image: #{e.message}"
125-
}])
107+
"Error building image: #{e.message}"
126108
end
127109
end
128110
end

0 commit comments

Comments
 (0)