Skip to content

Commit 01c9ccf

Browse files
authored
Merge pull request QuantGeekDev#2 from QuantGeekDev/feature/modularize
Feature/modularize
2 parents 2c4a0e1 + 2d68b4c commit 01c9ccf

File tree

5 files changed

+512
-301
lines changed

5 files changed

+512
-301
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) [year] [fullname]
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 151 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,57 @@
1-
# docker-mcp MCP server
1+
# 🐳 docker-mcp
22

3-
Docker MCP server
4-
Supports instantiating containers, and docker compose operations
3+
[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
56

6-
## Quickstart
7+
A powerful Model Context Protocol (MCP) server for Docker operations, enabling seamless container and compose stack management through Claude AI.
78

8-
### Install
9+
## ✨ Features
910

10-
#### Claude Desktop
11+
- 🚀 Container creation and instantiation
12+
- 📦 Docker Compose stack deployment
13+
- 🔍 Container logs retrieval
14+
- 📊 Container listing and status monitoring
15+
- 🧹 Automatic cleanup of temporary files
16+
- ♻️ Automatic image pulling
1117

12-
On MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
13-
On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
18+
### 🎬 Demos
19+
#### Deploying a Docker Compose Stack
20+
21+
<a href="https://streamable.com/0fz6kn" target="_blank">
22+
<img src="https://cdn-cf-east.streamable.com/image/0fz6kn.jpg?Expires=1733623440&Signature=PIYLK6wY6HM~9kPqmmpabnjHoObDdz9MgjE4-TVD74BN~bXTZFkHKo3B9ufF8HoVqD7lA79gpngGAJ0pJTi62UgirktBx-eG2vxXEj6IbWrTkQJnmePAV6vM8Nu5j1~v6eKiS~a8bUiYnEioyFtufxSbfgTTV3sIYzXe6blabMGf-KSHg9yoAa6CwnfDRusfrUNsJxs2uNxAfhBe8~0KC0OcPujwnPZarJmYsz7CuTgsPb3TbnREdLGb2tNxNAjMFzRxjQvkSXGbxbfytsqMGhqSDqSSuFBRcOgraZoAsJmyWt1fb2VSKaD0I6Zxzzyssr7hJ82JHMVyJZAMgT1tlQ__&Key-Pair-Id=APKAIEYUVEN4EVB2OKEQ" alt="Docker Compose Demo" width="600px"/>
23+
</a>
24+
25+
#### Analyzing Container Logs
26+
27+
<a href="https://streamable.com/3fjqi3" target="_blank">
28+
<img src="https://cdn-cf-east.streamable.com/image/3fjqi3.jpg?Expires=1733623500&Signature=XaG9q65aFAl8fmk1kvf9TsJj2RB8u035RDpWTLJ7eWzqClmVOPuYEklw4dox3JBQcrcHmg4SJFcyTvhwmyQLc19UKli9yEkO4AqwSlE9SEqrBrOBvCsWoDUa8CBuTU~-9R~sJd8fLVeQNQhvTnTyVFF9z0zkJ3XzDBWcXDMleXL4IbKiD5Z0IcYTsRTJCGD91qtjdO4dDqaaj5fpWNGQixa7ffgvSu5QZJHaLrcnspum7lKKI58eJQlS7T9WqZUXSW2c5vK-EMLrTmV~AXOfZHig-d6XqdBbz0Bg1gLBCdyWsY6PkMhUaR9MIVDVzPwQonVDy5fEDNsnS18zN~1Cfw__&Key-Pair-Id=APKAIEYUVEN4EVB2OKEQ" alt="Container Logs Demo" width="600px"/>
29+
</a>
30+
31+
📝 Click on the images above to watch the demos
32+
33+
## 🚀 Quickstart
34+
35+
### Prerequisites
36+
37+
- Python 3.12+
38+
- Docker Desktop or Docker Engine
39+
- Claude Desktop
40+
41+
### Installation
42+
43+
#### Claude Desktop Configuration
44+
45+
Add the server configuration to your Claude Desktop config file:
46+
47+
**MacOS**: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
48+
**Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
1449

1550
<details>
16-
<summary>Development/Unpublished Servers Configuration</summary>
17-
```
51+
<summary>💻 Development Configuration</summary>
52+
53+
```json
54+
{
1855
"mcpServers": {
1956
"docker-mcp": {
2057
"command": "uv",
@@ -26,12 +63,15 @@ On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
2663
]
2764
}
2865
}
29-
```
66+
}
67+
```
3068
</details>
3169

3270
<details>
33-
<summary>Published Servers Configuration</summary>
34-
```
71+
<summary>🚀 Production Configuration</summary>
72+
73+
```json
74+
{
3575
"mcpServers": {
3676
"docker-mcp": {
3777
"command": "uvx",
@@ -40,14 +80,32 @@ On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
4080
]
4181
}
4282
}
43-
```
83+
}
84+
```
4485
</details>
4586

46-
## Development
87+
## 🛠️ Development
4788

48-
### Building and Publishing
89+
### Local Setup
90+
91+
1. Clone the repository:
92+
```bash
93+
git clone https://github.com/QuantGeekDev/docker-mcp.git
94+
cd docker-mcp
95+
```
4996

50-
To prepare the package for distribution:
97+
2. Create and activate a virtual environment:
98+
```bash
99+
python -m venv venv
100+
source venv/bin/activate # On Windows: venv\Scripts\activate
101+
```
102+
103+
3. Install dependencies:
104+
```bash
105+
uv sync
106+
```
107+
108+
### Building and Publishing
51109

52110
1. Sync dependencies and update lockfile:
53111
```bash
@@ -58,25 +116,94 @@ uv sync
58116
```bash
59117
uv build
60118
```
61-
62-
This will create source and wheel distributions in the `dist/` directory.
119+
This creates source and wheel distributions in the `dist/` directory.
63120

64121
3. Publish to PyPI:
65122
```bash
66123
uv publish
67124
```
68125

69-
Note: You'll need to set PyPI credentials via environment variables or command flags:
126+
#### PyPI Credentials
127+
128+
Set your credentials via:
70129
- Token: `--token` or `UV_PUBLISH_TOKEN`
71-
- Or username/password: `--username`/`UV_PUBLISH_USERNAME` and `--password`/`UV_PUBLISH_PASSWORD`
130+
- Username/Password:
131+
- `--username`/`UV_PUBLISH_USERNAME`
132+
- `--password`/`UV_PUBLISH_PASSWORD`
72133

73-
### Inspector
134+
### 🔍 Debugging
74135

75-
You can launch the MCP Inspector with this command:
136+
Launch the MCP Inspector for debugging:
76137

77138
```bash
78139
npx @modelcontextprotocol/inspector uv --directory <path-to-docker-mcp> run docker-mcp
79140
```
80141

142+
The Inspector will provide a URL to access the debugging interface.
143+
144+
## 📝 Available Tools
145+
146+
The server provides the following tools:
147+
148+
### create-container
149+
Creates a standalone Docker container
150+
```json
151+
{
152+
"image": "image-name",
153+
"name": "container-name",
154+
"ports": {"80": "80"},
155+
"environment": {"ENV_VAR": "value"}
156+
}
157+
```
158+
159+
### deploy-compose
160+
Deploys a Docker Compose stack
161+
```json
162+
{
163+
"project_name": "example-stack",
164+
"compose_yaml": "version: '3.8'\nservices:\n service1:\n image: image1:latest\n ports:\n - '8080:80'"
165+
}
166+
```
167+
168+
### get-logs
169+
Retrieves logs from a specific container
170+
```json
171+
{
172+
"container_name": "my-container"
173+
}
174+
```
175+
176+
### list-containers
177+
Lists all Docker containers
178+
```json
179+
{}
180+
```
181+
182+
## 🚧 Current Limitations
183+
184+
- No built-in environment variable support for containers
185+
- No volume management
186+
- No network management
187+
- No container health checks
188+
- No container restart policies
189+
- No container resource limits
190+
191+
## 🤝 Contributing
192+
193+
1. Fork the repository from [docker-mcp](https://github.com/QuantGeekDev/docker-mcp)
194+
2. Create your feature branch
195+
3. Commit your changes
196+
4. Push to the branch
197+
5. Open a Pull Request
198+
199+
## 📜 License
200+
201+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
202+
203+
## ✨ Authors
204+
205+
- **Alex Andru** - *Initial work | Core contributor* - [@QuantGeekDev](https://github.com/QuantGeekDev)
206+
- **Ali Sadykov** - *Initial work | Core contributor* - [@md-archive](https://github.com/md-archive)
81207

82-
Upon launching, the Inspector will display a URL that you can access in your browser to begin debugging.
208+
---
209+
Made with ❤️ for the Claude community

src/docker_mcp/docker_executor.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from typing import Tuple, Protocol, List
2+
import asyncio
3+
import os
4+
import platform
5+
import shutil
6+
from abc import ABC, abstractmethod
7+
8+
9+
class CommandExecutor(Protocol):
10+
async def execute(self, cmd: str | List[str]) -> Tuple[int, str, str]:
11+
pass
12+
13+
14+
class WindowsExecutor:
15+
async def execute(self, cmd: str) -> Tuple[int, str, str]:
16+
process = await asyncio.create_subprocess_shell(
17+
cmd,
18+
stdout=asyncio.subprocess.PIPE,
19+
stderr=asyncio.subprocess.PIPE,
20+
shell=True
21+
)
22+
stdout, stderr = await process.communicate()
23+
return process.returncode, stdout.decode(), stderr.decode()
24+
25+
26+
class UnixExecutor:
27+
async def execute(self, cmd: List[str]) -> Tuple[int, str, str]:
28+
process = await asyncio.create_subprocess_exec(
29+
*cmd,
30+
stdout=asyncio.subprocess.PIPE,
31+
stderr=asyncio.subprocess.PIPE
32+
)
33+
stdout, stderr = await process.communicate()
34+
return process.returncode, stdout.decode(), stderr.decode()
35+
36+
37+
class DockerExecutorBase(ABC):
38+
def __init__(self):
39+
self.docker_cmd = self._initialize_docker_cmd()
40+
self.executor = WindowsExecutor() if platform.system() == 'Windows' else UnixExecutor()
41+
42+
@abstractmethod
43+
async def run_command(self, command: str, *args) -> Tuple[int, str, str]:
44+
pass
45+
46+
def _initialize_docker_cmd(self) -> str:
47+
if platform.system() == 'Windows':
48+
docker_dir = r"C:\Program Files\Docker\Docker\resources\bin"
49+
docker_paths = [
50+
os.path.join(docker_dir, "docker-compose.exe"),
51+
os.path.join(docker_dir, "docker.exe")
52+
]
53+
for path in docker_paths:
54+
if os.path.exists(path):
55+
return path
56+
57+
docker_cmd = shutil.which('docker')
58+
if not docker_cmd:
59+
raise RuntimeError("Docker executable not found")
60+
return docker_cmd
61+
62+
63+
class DockerComposeExecutor(DockerExecutorBase):
64+
def __init__(self, compose_file: str, project_name: str):
65+
super().__init__()
66+
self.compose_file = os.path.abspath(compose_file)
67+
self.project_name = project_name
68+
69+
async def run_command(self, command: str, *args) -> Tuple[int, str, str]:
70+
if platform.system() == 'Windows':
71+
cmd = self._build_windows_command(command, *args)
72+
else:
73+
cmd = self._build_unix_command(command, *args)
74+
return await self.executor.execute(cmd)
75+
76+
def _build_windows_command(self, command: str, *args) -> str:
77+
compose_file = self.compose_file.replace('\\', '/')
78+
return (f'cd "{os.path.dirname(compose_file)}" && docker compose '
79+
f'-f "{os.path.basename(compose_file)}" '
80+
f'-p {self.project_name} {command} {" ".join(args)}')
81+
82+
def _build_unix_command(self, command: str, *args) -> list[str]:
83+
return [
84+
self.docker_cmd,
85+
"compose",
86+
"-f", self.compose_file,
87+
"-p", self.project_name,
88+
command,
89+
*args
90+
]
91+
92+
async def down(self) -> Tuple[int, str, str]:
93+
return await self.run_command("down", "--volumes")
94+
95+
async def pull(self) -> Tuple[int, str, str]:
96+
return await self.run_command("pull")
97+
98+
async def up(self) -> Tuple[int, str, str]:
99+
return await self.run_command("up", "-d")
100+
101+
async def ps(self) -> Tuple[int, str, str]:
102+
return await self.run_command("ps")

0 commit comments

Comments
 (0)