container-manager-mcp 1.0.3__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. container_manager_mcp/__init__.py +23 -17
  2. container_manager_mcp/__main__.py +2 -2
  3. container_manager_mcp/container_manager.py +555 -441
  4. container_manager_mcp/container_manager_a2a.py +339 -0
  5. container_manager_mcp/container_manager_mcp.py +2055 -1323
  6. container_manager_mcp/mcp_config.json +7 -0
  7. container_manager_mcp/skills/container-manager-compose/SKILL.md +25 -0
  8. container_manager_mcp/skills/container-manager-containers/SKILL.md +28 -0
  9. container_manager_mcp/skills/container-manager-containers/troubleshoot.md +5 -0
  10. container_manager_mcp/skills/container-manager-images/SKILL.md +25 -0
  11. container_manager_mcp/skills/container-manager-info/SKILL.md +23 -0
  12. container_manager_mcp/skills/container-manager-logs/SKILL.md +22 -0
  13. container_manager_mcp/skills/container-manager-networks/SKILL.md +22 -0
  14. container_manager_mcp/skills/container-manager-swarm/SKILL.md +28 -0
  15. container_manager_mcp/skills/container-manager-swarm/orchestrate.md +4 -0
  16. container_manager_mcp/skills/container-manager-system/SKILL.md +19 -0
  17. container_manager_mcp/skills/container-manager-volumes/SKILL.md +23 -0
  18. container_manager_mcp/utils.py +31 -0
  19. container_manager_mcp-1.2.0.dist-info/METADATA +371 -0
  20. container_manager_mcp-1.2.0.dist-info/RECORD +26 -0
  21. container_manager_mcp-1.2.0.dist-info/entry_points.txt +4 -0
  22. {container_manager_mcp-1.0.3.dist-info → container_manager_mcp-1.2.0.dist-info}/top_level.txt +1 -0
  23. scripts/validate_a2a_agent.py +150 -0
  24. scripts/validate_agent.py +67 -0
  25. container_manager_mcp-1.0.3.dist-info/METADATA +0 -243
  26. container_manager_mcp-1.0.3.dist-info/RECORD +0 -10
  27. container_manager_mcp-1.0.3.dist-info/entry_points.txt +0 -3
  28. {container_manager_mcp-1.0.3.dist-info → container_manager_mcp-1.2.0.dist-info}/WHEEL +0 -0
  29. {container_manager_mcp-1.0.3.dist-info → container_manager_mcp-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ container-manager = container_manager_mcp.container_manager:container_manager
3
+ container-manager-a2a = container_manager_mcp.container_manager_a2a:agent_server
4
+ container-manager-mcp = container_manager_mcp.container_manager_mcp:container_manager_mcp
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env python3
2
+ import asyncio
3
+ import httpx
4
+ import json
5
+ import uuid
6
+
7
+ # Configuration
8
+ A2A_URL = (
9
+ "http://localhost:9000/" # Discovered endpoint is POST / based on 405 on GET /
10
+ )
11
+
12
+
13
+ async def main():
14
+ print(f"Validating A2A Agent at {A2A_URL}...")
15
+
16
+ questions = [
17
+ "Can you list the container images available?",
18
+ # "List all the running containers."
19
+ # "Create a standard docker network named 'test_network'. Once its created, verify it exists by showing all of the docker networks.",
20
+ ]
21
+
22
+ async with httpx.AsyncClient(timeout=10000.0) as client:
23
+ # First, let's verify connectivity and maybe infer output schema
24
+
25
+ for q in questions:
26
+ print(f"\n\n\nUser: {q}")
27
+ print("--- Sending Request ---")
28
+
29
+ # Construct JSON-RPC payload
30
+ payload = {
31
+ "jsonrpc": "2.0",
32
+ "method": "message/send",
33
+ "params": {
34
+ "message": {
35
+ "kind": "message",
36
+ "role": "user",
37
+ "parts": [{"kind": "text", "text": q}],
38
+ "messageId": str(uuid.uuid4()),
39
+ }
40
+ },
41
+ "id": 1,
42
+ }
43
+
44
+ try:
45
+ # Attempt POST to root
46
+ url = A2A_URL
47
+ print(f"Trying POST {url} with JSON-RPC (message/send)...")
48
+ resp = await client.post(
49
+ url, json=payload, headers={"Content-Type": "application/json"}
50
+ )
51
+
52
+ print(f"Status Code: {resp.status_code}")
53
+ if resp.status_code == 200:
54
+ try:
55
+ data = resp.json()
56
+ print(f"Response (JSON):\n{json.dumps(data, indent=2)}")
57
+
58
+ if "result" in data and "id" in data["result"]:
59
+ task_id = data["result"]["id"]
60
+ print(
61
+ f"\nTask Submitted with ID: {task_id}. Polling for result..."
62
+ )
63
+
64
+ # Poll tasks/get
65
+ while True:
66
+ await asyncio.sleep(2) # Wait a bit
67
+ poll_payload = {
68
+ "jsonrpc": "2.0",
69
+ "method": "tasks/get",
70
+ "params": {"id": task_id},
71
+ "id": 2,
72
+ }
73
+ poll_resp = await client.post(
74
+ url,
75
+ json=poll_payload,
76
+ headers={"Content-Type": "application/json"},
77
+ )
78
+ if poll_resp.status_code == 200:
79
+ poll_data = poll_resp.json()
80
+ if "result" in poll_data:
81
+ state = poll_data["result"]["status"]["state"]
82
+ print(f"Task State: {state}")
83
+ if state not in [
84
+ "submitted",
85
+ "running",
86
+ "working",
87
+ ]: # Assuming terminal states
88
+ print(
89
+ f"\nTask Finished with state: {state}"
90
+ )
91
+
92
+ # Extract final result
93
+ if "history" in poll_data["result"]:
94
+ history = poll_data["result"]["history"]
95
+ if history:
96
+ # Find last non-user message
97
+ last_msg = None
98
+ for msg in reversed(history):
99
+ if msg.get("role") != "user":
100
+ last_msg = msg
101
+ break
102
+
103
+ if last_msg and "parts" in last_msg:
104
+ print(
105
+ "\n--- Agent Response ---"
106
+ )
107
+ for part in last_msg["parts"]:
108
+ if "text" in part:
109
+ print(part["text"])
110
+ elif "content" in part:
111
+ print(part["content"])
112
+ elif last_msg:
113
+ print(
114
+ f"Final Message (No parts): {last_msg}"
115
+ )
116
+ else:
117
+ print(
118
+ "\n--- No Agent Response Found in History ---"
119
+ )
120
+
121
+ print(
122
+ f"Full Result Debug:\n{json.dumps(poll_data, indent=2)}"
123
+ )
124
+ break
125
+ else:
126
+ print("Starting polling error key check...")
127
+ if "error" in poll_data:
128
+ print(
129
+ f"Polling Error: {poll_data['error']}"
130
+ )
131
+ break
132
+ else:
133
+ print(f"Polling Failed: {poll_resp.status_code}")
134
+ print(f"Polling Error Details: {poll_resp.text}")
135
+ break
136
+
137
+ if "error" in data:
138
+ print(f"JSON-RPC Error: {data['error']}")
139
+ except json.JSONDecodeError:
140
+ print(f"Response (Text):\n{resp.text}")
141
+ else:
142
+ print(f"Error: {resp.status_code}")
143
+ print(resp.text)
144
+
145
+ except httpx.RequestError as e:
146
+ print(f"Connection failed to {url}: {e}")
147
+
148
+
149
+ if __name__ == "__main__":
150
+ asyncio.run(main())
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env python3
2
+ import asyncio
3
+ import sys
4
+ from container_manager_mcp.container_manager_a2a import stream_chat, chat, node_chat
5
+
6
+ # Attempt to import assuming dependencies are installed
7
+ import os
8
+
9
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
10
+
11
+ try:
12
+ from container_manager_mcp.container_manager_a2a import create_agent
13
+ except ImportError as e:
14
+ print(f"Import Error: {e}")
15
+ print("Please install dependencies via `pip install .[all]`")
16
+ sys.exit(1)
17
+
18
+
19
+ async def main():
20
+ print("Initializing A2A Agent...")
21
+ try:
22
+ agent = create_agent(
23
+ provider="openai",
24
+ model_id=os.getenv("MODEL_ID", "qwen/qwen3-8b"),
25
+ base_url=os.getenv(
26
+ "OPENAI_BASE_URL", "http://localhost:1234/v1"
27
+ ), # 127.0.0.1
28
+ api_key=os.getenv("OPENAI_API_KEY", "llama"),
29
+ mcp_url=os.getenv("MCP_URL", "http://localhost:8015/mcp"), # 127.0.0.1
30
+ #mcp_config=None,
31
+ )
32
+
33
+ print("Agent initialized successfully.")
34
+
35
+ # Define sample questions
36
+ questions = [
37
+ "Can you list the container images available on the host?",
38
+ "List all the running containers."
39
+ "Create a standard docker network named 'test_network'. Once its created, verify it exists by showing all of the docker networks.",
40
+ ]
41
+
42
+ print("\n--- Starting Sample Chat Validation ---\n")
43
+
44
+ for q in questions:
45
+ print(f"\n\n\nUser: {q}")
46
+ try:
47
+ # Only run one to test
48
+ await stream_chat(agent=agent, prompt=q)
49
+ await chat(agent=agent, prompt=q)
50
+ await node_chat(agent=agent, prompt=q)
51
+ if hasattr(agent, "tools"):
52
+ print(f"Agent Tools: {[t.__name__ for t in agent.tools]}")
53
+ elif hasattr(agent, "_tools"):
54
+ print(f"Agent Tools: {[t.__name__ for t in agent._tools]}")
55
+
56
+ except Exception as e:
57
+ print(f"\n\nError processing question '{q}': {e}")
58
+
59
+ except Exception as e:
60
+ print(f"Validation failed with error: {e}")
61
+ import traceback
62
+
63
+ traceback.print_exc()
64
+
65
+
66
+ if __name__ == "__main__":
67
+ asyncio.run(main())
@@ -1,243 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: container-manager-mcp
3
- Version: 1.0.3
4
- Summary: Container Manager manage Docker, Docker Swarm, and Podman containers as an MCP Server
5
- Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
- License: MIT
7
- Classifier: Development Status :: 5 - Production/Stable
8
- Classifier: License :: Public Domain
9
- Classifier: Environment :: Console
10
- Classifier: Operating System :: POSIX :: Linux
11
- Classifier: Programming Language :: Python :: 3
12
- Requires-Python: >=3.10
13
- Description-Content-Type: text/markdown
14
- License-File: LICENSE
15
- Requires-Dist: requests>=2.28.1
16
- Requires-Dist: fastmcp>=2.11.3
17
- Requires-Dist: podman>=5.6.0
18
- Provides-Extra: podman
19
- Requires-Dist: podman>=5.6.0; extra == "podman"
20
- Provides-Extra: docker
21
- Requires-Dist: docker>=7.1.0; extra == "docker"
22
- Provides-Extra: all
23
- Requires-Dist: requests>=2.28.1; extra == "all"
24
- Requires-Dist: fastmcp>=2.11.3; extra == "all"
25
- Requires-Dist: docker>=7.1.0; extra == "all"
26
- Requires-Dist: podman>=5.6.0; extra == "all"
27
- Dynamic: license-file
28
-
29
- # Container Manager MCP Server
30
-
31
- ![PyPI - Version](https://img.shields.io/pypi/v/container-manager-mcp)
32
- ![PyPI - Downloads](https://img.shields.io/pypi/dd/container-manager-mcp)
33
- ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/container-manager-mcp)
34
- ![GitHub forks](https://img.shields.io/github/forks/Knuckles-Team/container-manager-mcp)
35
- ![GitHub contributors](https://img.shields.io/github/contributors/Knuckles-Team/container-manager-mcp)
36
- ![PyPI - License](https://img.shields.io/pypi/l/container-manager-mcp)
37
- ![GitHub](https://img.shields.io/github/license/Knuckles-Team/container-manager-mcp)
38
-
39
- ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/container-manager-mcp)
40
- ![GitHub pull requests](https://img.shields.io/github/issues-pr/Knuckles-Team/container-manager-mcp)
41
- ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Knuckles-Team/container-manager-mcp)
42
- ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/container-manager-mcp)
43
-
44
- ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/container-manager-mcp)
45
- ![GitHub language count](https://img.shields.io/github/languages/count/Knuckles-Team/container-manager-mcp)
46
- ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/container-manager-mcp)
47
- ![GitHub repo file count (file type)](https://img.shields.io/github/directory-file-count/Knuckles-Team/container-manager-mcp)
48
- ![PyPI - Wheel](https://img.shields.io/pypi/wheel/container-manager-mcp)
49
- ![PyPI - Implementation](https://img.shields.io/pypi/implementation/container-manager-mcp)
50
-
51
- *Version: 1.0.3*
52
-
53
- Container Manager MCP Server provides a robust interface to manage Docker and Podman containers, networks, volumes, and Docker Swarm services through a FastMCP server, enabling programmatic and remote container management.
54
-
55
- This repository is actively maintained - Contributions are welcome!
56
-
57
- ## Features
58
-
59
- - Manage Docker and Podman containers, images, volumes, and networks
60
- - Support for Docker Swarm operations
61
- - Support for Docker Compose and Podman Compose operations
62
- - FastMCP server for remote API access
63
- - Comprehensive logging and error handling
64
- - Extensible architecture for additional container runtimes
65
-
66
- <details>
67
- <summary><b>Usage:</b></summary>
68
-
69
- | Short Flag | Long Flag | Description |
70
- |------------|----------------|-----------------------------------------------|
71
- | -h | --help | Display help information |
72
- | -t | --transport | Transport method (stdio or http, default: stdio) |
73
- | -h | --host | Host address for HTTP transport (default: 0.0.0.0) |
74
- | -p | --port | Port for HTTP transport (default: 8000) |
75
-
76
- ### Available MCP Tools
77
- - `get_version`: Retrieve version information of the container runtime
78
- - `get_info`: Get system information about the container runtime
79
- - `list_images`: List all available images
80
- - `pull_image`: Pull an image from a registry
81
- - `remove_image`: Remove an image
82
- - `list_containers`: List running or all containers
83
- - `run_container`: Run a new container
84
- - `stop_container`: Stop a running container
85
- - `remove_container`: Remove a container
86
- - `get_container_logs`: Retrieve logs from a container
87
- - `exec_in_container`: Execute a command in a container
88
- - `list_volumes`: List all volumes
89
- - `create_volume`: Create a new volume
90
- - `remove_volume`: Remove a volume
91
- - `list_networks`: List all networks
92
- - `create_network`: Create a new network
93
- - `remove_network`: Remove a network
94
- - `compose_up`: Start services defined in a Compose file
95
- - `compose_down`: Stop and remove services defined in a Compose file
96
- - `compose_ps`: List containers for a Compose project
97
- - `compose_logs`: View logs for a Compose project or specific service
98
- - `init_swarm`: Initialize a Docker Swarm
99
- - `leave_swarm`: Leave a Docker Swarm
100
- - `list_nodes`: List nodes in a Docker Swarm
101
- - `list_services`: List services in a Docker Swarm
102
- - `create_service`: Create a new service in a Docker Swarm
103
- - `remove_service`: Remove a service from a Docker Swarm
104
-
105
- </details>
106
-
107
- <details>
108
- <summary><b>Example:</b></summary>
109
-
110
- ## Use with AI
111
-
112
- Configure `mcp.json`
113
-
114
- ```json
115
- {
116
- "mcpServers": {
117
- "container_manager": {
118
- "command": "uv",
119
- "args": [
120
- "run",
121
- "--with",
122
- "container-manager-mcp",
123
- "container-manager-mcp"
124
- ],
125
- "env": {
126
- "SILENT": "False", //Optional
127
- "LOG_FILE": "~/Documents/container_manager_mcp.log" //Optional
128
- },
129
- "timeout": 200000
130
- }
131
- }
132
- }
133
- ```
134
-
135
- ### Deploy MCP Server as a container
136
- ```bash
137
- docker pull knucklessg1/container-manager:latest
138
- ```
139
-
140
- Modify the `compose.yml`
141
-
142
- ```compose
143
- services:
144
- container-manager-mcp:
145
- image: knucklessg1/container-manager:latest
146
- environment:
147
- - HOST=0.0.0.0
148
- - PORT=8015
149
- ports:
150
- - 8015:8015
151
- ```
152
-
153
- </details>
154
-
155
- <details>
156
- <summary><b>Installation Instructions:</b></summary>
157
-
158
- ### Install Python Package
159
-
160
- ```bash
161
- python -m pip install container-manager-mcp
162
- ```
163
-
164
- or
165
-
166
- ```bash
167
- uv pip install --upgrade container-manager-mcp
168
- ```
169
-
170
- ## Test Server
171
-
172
- ```bash
173
- container-manager-mcp --transport http --host 127.0.0.1 --port 8080
174
- ```
175
-
176
- This starts the MCP server using HTTP transport on localhost port 8080.
177
-
178
- To interact with the MCP server programmatically, you can use a FastMCP client or make HTTP requests to the exposed endpoints. Example using curl to pull an image:
179
-
180
- ```bash
181
- curl -X POST http://127.0.0.1:8080/pull_image \
182
- -H "Content-Type: application/json" \
183
- -d '{"image": "nginx", "tag": "latest", "manager_type": "docker"}'
184
- ```
185
-
186
- Install the Python package:
187
-
188
- ```bash
189
- python -m pip install container-manager-mcp
190
- ```
191
-
192
- ### Dependencies
193
- - Python 3.7+
194
- - `fastmcp` for MCP server functionality
195
- - `docker` for Docker support
196
- - `podman` for Podman support
197
- - `pydantic` for data validation
198
-
199
- Install dependencies:
200
-
201
- ```bash
202
- python -m pip install fastmcp docker podman pydantic
203
- ```
204
-
205
- Ensure Docker or Podman is installed and running on your system.
206
-
207
- </details>
208
-
209
-
210
- <details>
211
- <summary><b>Development and Contribution:</b></summary>
212
-
213
- ## Development and Contribution
214
-
215
- Contributions are welcome! To contribute:
216
-
217
- 1. Fork the repository
218
- 2. Create a feature branch (`git checkout -b feature/your-feature`)
219
- 3. Commit your changes (`git commit -am 'Add your feature'`)
220
- 4. Push to the branch (`git push origin feature/your-feature`)
221
- 5. Create a new Pull Request
222
-
223
- Please ensure your code follows the project's coding standards and includes appropriate tests.
224
-
225
- </details>
226
-
227
- <details>
228
- <summary><b>License:</b></summary>
229
-
230
- ## License
231
-
232
- This project is licensed under the MIT License - see the [LICENSE](https://github.com/Knuckles-Team/container-manager-mcp/blob/main/LICENSE) file for details.
233
-
234
- </details>
235
- <details>
236
- <summary><b>Repository Owners:</b></summary>
237
-
238
- <img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
239
-
240
- ![GitHub followers](https://img.shields.io/github/followers/Knucklessg1)
241
- ![GitHub User's stars](https://img.shields.io/github/stars/Knucklessg1)
242
-
243
- </details>
@@ -1,10 +0,0 @@
1
- container_manager_mcp/__init__.py,sha256=N3bhKd_oh5YmBBl9N1omfZgaXhJyP0vOzH4VKxs68_g,506
2
- container_manager_mcp/__main__.py,sha256=zic5tX336HG8LfdzQQ0sDVx-tMSOsgOZCtaxHWgJ4Go,134
3
- container_manager_mcp/container_manager.py,sha256=1HN_sKQFGVtf35wk66Uez9MtHOv2B9LJ4tbTbEzCXEA,84152
4
- container_manager_mcp/container_manager_mcp.py,sha256=M43YmLt_qoOfpnlK2VyyGX2vJ6gMBxepSqBauvMS4AA,46204
5
- container_manager_mcp-1.0.3.dist-info/licenses/LICENSE,sha256=Z1xmcrPHBnGCETO_LLQJUeaSNBSnuptcDVTt4kaPUOE,1060
6
- container_manager_mcp-1.0.3.dist-info/METADATA,sha256=RfIVbh9AeL0roB2yyqtXBJR2o8H7MqTpV82epVm0V1I,8238
7
- container_manager_mcp-1.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- container_manager_mcp-1.0.3.dist-info/entry_points.txt,sha256=I23pXcCgAShlfYbENzs3kbw3l1lU9Gy7lODPfRqeeiA,156
9
- container_manager_mcp-1.0.3.dist-info/top_level.txt,sha256=B7QQLOd9mBdu0lsPKqyu4T8-zUtbqKzQJbMbtAzoozU,22
10
- container_manager_mcp-1.0.3.dist-info/RECORD,,
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- container-manager = container_manager_mcp.container_manager:main
3
- container-manager-mcp = container_manager_mcp.container_manager_mcp:main