docker_mcp 0.2.5 → 0.3.0
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.
- checksums.yaml +4 -4
- data/lib/docker_mcp/build_image.rb +65 -84
- data/lib/docker_mcp/copy_to_container.rb +87 -161
- data/lib/docker_mcp/create_container.rb +63 -115
- data/lib/docker_mcp/create_network.rb +63 -102
- data/lib/docker_mcp/create_volume.rb +57 -100
- data/lib/docker_mcp/exec_container.rb +94 -147
- data/lib/docker_mcp/fetch_container_logs.rb +64 -117
- data/lib/docker_mcp/list_containers.rb +44 -47
- data/lib/docker_mcp/list_images.rb +32 -56
- data/lib/docker_mcp/list_networks.rb +33 -60
- data/lib/docker_mcp/list_volumes.rb +33 -67
- data/lib/docker_mcp/pull_image.rb +24 -68
- data/lib/docker_mcp/push_image.rb +61 -118
- data/lib/docker_mcp/recreate_container.rb +48 -99
- data/lib/docker_mcp/remove_container.rb +49 -101
- data/lib/docker_mcp/remove_image.rb +53 -119
- data/lib/docker_mcp/remove_network.rb +42 -96
- data/lib/docker_mcp/remove_volume.rb +52 -106
- data/lib/docker_mcp/run_container.rb +72 -82
- data/lib/docker_mcp/start_container.rb +36 -76
- data/lib/docker_mcp/stop_container.rb +41 -86
- data/lib/docker_mcp/tag_image.rb +67 -121
- data/lib/docker_mcp/version.rb +1 -1
- data/lib/docker_mcp.rb +2 -0
- metadata +15 -1
@@ -1,97 +1,97 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DockerMCP
|
4
|
-
# MCP tool for running Docker containers
|
4
|
+
# MCP tool for running Docker containers.
|
5
5
|
#
|
6
|
-
# This tool
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# This tool creates and immediately starts a Docker container from a
|
7
|
+
# specified image in a single operation. It combines the functionality
|
8
|
+
# of create_container and start_container for convenience when immediate
|
9
|
+
# execution is desired.
|
10
10
|
#
|
11
11
|
# == Features
|
12
12
|
#
|
13
|
-
# -
|
14
|
-
# -
|
15
|
-
# -
|
16
|
-
# -
|
17
|
-
# -
|
18
|
-
# -
|
19
|
-
# - Comprehensive error handling
|
13
|
+
# - Creates and starts containers in one operation
|
14
|
+
# - Supports all container configuration options
|
15
|
+
# - Configures command execution and environment variables
|
16
|
+
# - Sets up port exposure and network configuration
|
17
|
+
# - Applies advanced host configurations and volume mounts
|
18
|
+
# - Handles container naming and labeling
|
20
19
|
#
|
21
20
|
# == Security Considerations
|
22
21
|
#
|
23
|
-
#
|
24
|
-
# -
|
25
|
-
# -
|
26
|
-
# -
|
27
|
-
# -
|
22
|
+
# Running containers involves significant security considerations:
|
23
|
+
# - **Immediate Execution**: Starts processes immediately upon creation
|
24
|
+
# - **Resource Consumption**: Consumes CPU, memory, and storage resources
|
25
|
+
# - **Network Exposure**: Creates active network endpoints
|
26
|
+
# - **File System Access**: Potentially accesses host directories
|
27
|
+
# - **Process Isolation**: Runs processes with configured privileges
|
28
28
|
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# -
|
34
|
-
# -
|
29
|
+
# Implement strict access controls and resource monitoring.
|
30
|
+
#
|
31
|
+
# == Parameters
|
32
|
+
#
|
33
|
+
# - **image**: Docker image to use (required)
|
34
|
+
# - **name**: Custom container name (optional)
|
35
|
+
# - **cmd**: Command to execute as space-separated string (optional)
|
36
|
+
# - **env**: Environment variables as comma-separated KEY=VALUE pairs (optional)
|
37
|
+
# - **exposed_ports**: Port exposure configuration as JSON object (optional)
|
38
|
+
# - **host_config**: Advanced host configuration as JSON object (optional)
|
35
39
|
#
|
36
40
|
# == Example Usage
|
37
41
|
#
|
38
|
-
# # Simple container
|
39
|
-
# RunContainer.call(
|
42
|
+
# # Simple container execution
|
43
|
+
# response = RunContainer.call(
|
40
44
|
# server_context: context,
|
41
|
-
# image: "
|
42
|
-
#
|
45
|
+
# image: "alpine:latest",
|
46
|
+
# cmd: "echo 'Hello World'"
|
43
47
|
# )
|
44
48
|
#
|
45
|
-
# #
|
46
|
-
# RunContainer.call(
|
49
|
+
# # Web server with port binding
|
50
|
+
# response = RunContainer.call(
|
47
51
|
# server_context: context,
|
48
|
-
# image: "
|
49
|
-
# name: "
|
50
|
-
#
|
52
|
+
# image: "nginx:latest",
|
53
|
+
# name: "web-server",
|
54
|
+
# exposed_ports: {"80/tcp" => {}},
|
51
55
|
# host_config: {
|
52
|
-
# "PortBindings" => {"
|
53
|
-
# "Binds" => ["/host/data:/var/lib/postgresql/data"]
|
56
|
+
# "PortBindings" => {"80/tcp" => [{"HostPort" => "8080"}]}
|
54
57
|
# }
|
55
58
|
# )
|
56
59
|
#
|
57
|
-
# @see CreateContainer
|
58
|
-
# @see StartContainer
|
59
60
|
# @see Docker::Container.create
|
60
61
|
# @since 0.1.0
|
61
|
-
|
62
|
+
RUN_CONTAINER_DEFINITION = ToolForge.define(:run_container) do
|
62
63
|
description 'Run a Docker container (create and start)'
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
image: {
|
67
|
-
type: 'string',
|
65
|
+
param :image,
|
66
|
+
type: :string,
|
68
67
|
description: 'Image name to use (e.g., "ubuntu:22.04")'
|
69
|
-
},
|
70
|
-
name: {
|
71
|
-
type: 'string',
|
72
|
-
description: 'Container name (optional)'
|
73
|
-
},
|
74
|
-
cmd: {
|
75
|
-
type: 'string',
|
76
|
-
description: 'Command to run as space-separated string (optional, e.g., "npm start" or "python app.py")'
|
77
|
-
},
|
78
|
-
env: {
|
79
|
-
type: 'string',
|
80
|
-
description: 'Environment variables as comma-separated KEY=VALUE pairs (optional)'
|
81
|
-
},
|
82
|
-
exposed_ports: {
|
83
|
-
type: 'object',
|
84
|
-
description: 'Exposed ports as {"port/protocol": {}} (optional)'
|
85
|
-
},
|
86
|
-
host_config: {
|
87
|
-
type: 'object',
|
88
|
-
description: 'Host configuration including port bindings, volumes, etc. (optional)'
|
89
|
-
}
|
90
|
-
},
|
91
|
-
required: ['image']
|
92
|
-
)
|
93
68
|
|
94
|
-
|
69
|
+
param :name,
|
70
|
+
type: :string,
|
71
|
+
description: 'Container name (optional)',
|
72
|
+
required: false
|
73
|
+
|
74
|
+
param :cmd,
|
75
|
+
type: :string,
|
76
|
+
description: 'Command to run as space-separated string (optional, e.g., "npm start" or "python app.py")',
|
77
|
+
required: false
|
78
|
+
|
79
|
+
param :env,
|
80
|
+
type: :string,
|
81
|
+
description: 'Environment variables as comma-separated KEY=VALUE pairs (optional)',
|
82
|
+
required: false
|
83
|
+
|
84
|
+
param :exposed_ports,
|
85
|
+
type: :object,
|
86
|
+
description: 'Exposed ports as {"port/protocol": {}} (optional)',
|
87
|
+
required: false
|
88
|
+
|
89
|
+
param :host_config,
|
90
|
+
type: :object,
|
91
|
+
description: 'Host configuration including port bindings, volumes, etc. (optional)',
|
92
|
+
required: false
|
93
|
+
|
94
|
+
execute do |image:, name: nil, cmd: nil, env: nil, exposed_ports: nil, host_config: nil|
|
95
95
|
config = { 'Image' => image }
|
96
96
|
config['name'] = name if name
|
97
97
|
|
@@ -108,25 +108,15 @@ module DockerMCP
|
|
108
108
|
container.start
|
109
109
|
container_name = container.info['Names']&.first&.delete_prefix('/')
|
110
110
|
|
111
|
-
|
112
|
-
type: 'text',
|
113
|
-
text: "Container started successfully. ID: #{container.id}, Name: #{container_name}"
|
114
|
-
}])
|
111
|
+
"Container started successfully. ID: #{container.id}, Name: #{container_name}"
|
115
112
|
rescue Docker::Error::NotFoundError
|
116
|
-
|
117
|
-
type: 'text',
|
118
|
-
text: "Image #{image} not found"
|
119
|
-
}])
|
113
|
+
"Image #{image} not found"
|
120
114
|
rescue Docker::Error::ConflictError
|
121
|
-
|
122
|
-
type: 'text',
|
123
|
-
text: "Container with name #{name} already exists"
|
124
|
-
}])
|
115
|
+
"Container with name #{name} already exists"
|
125
116
|
rescue StandardError => e
|
126
|
-
|
127
|
-
type: 'text',
|
128
|
-
text: "Error running container: #{e.message}"
|
129
|
-
}])
|
117
|
+
"Error running container: #{e.message}"
|
130
118
|
end
|
131
119
|
end
|
120
|
+
|
121
|
+
RunContainer = RUN_CONTAINER_DEFINITION.to_mcp_tool
|
132
122
|
end
|
@@ -1,112 +1,72 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DockerMCP
|
4
|
-
# MCP tool for starting
|
4
|
+
# MCP tool for starting Docker containers.
|
5
5
|
#
|
6
|
-
# This tool
|
7
|
-
#
|
8
|
-
# and
|
9
|
-
# containers.
|
6
|
+
# This tool starts a previously created Docker container that is currently
|
7
|
+
# in a "created" or "stopped" state. It transitions the container to a
|
8
|
+
# "running" state and begins executing the configured command or entrypoint.
|
10
9
|
#
|
11
10
|
# == Features
|
12
11
|
#
|
13
|
-
# -
|
14
|
-
# -
|
15
|
-
# -
|
16
|
-
# -
|
12
|
+
# - Starts containers by ID or name
|
13
|
+
# - Supports both short and full container IDs
|
14
|
+
# - Works with custom container names
|
15
|
+
# - Provides clear success/failure feedback
|
16
|
+
# - Handles container state transitions
|
17
|
+
# - Preserves all container configuration
|
17
18
|
#
|
18
19
|
# == Security Considerations
|
19
20
|
#
|
20
|
-
# Starting containers
|
21
|
-
# -
|
22
|
-
# -
|
23
|
-
# -
|
24
|
-
# -
|
21
|
+
# Starting containers involves security implications:
|
22
|
+
# - **Process Execution**: Begins running container processes
|
23
|
+
# - **Resource Activation**: Activates CPU, memory, and I/O usage
|
24
|
+
# - **Network Activation**: Brings network interfaces online
|
25
|
+
# - **Service Exposure**: Makes configured services accessible
|
25
26
|
#
|
26
|
-
# Ensure
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# -
|
27
|
+
# Ensure proper monitoring and access controls are in place.
|
28
|
+
#
|
29
|
+
# == Parameters
|
30
|
+
#
|
31
|
+
# - **id**: Container ID or name (required)
|
32
|
+
# - Accepts full container IDs
|
33
|
+
# - Accepts short container IDs (first 12+ characters)
|
34
|
+
# - Accepts custom container names
|
31
35
|
#
|
32
36
|
# == Example Usage
|
33
37
|
#
|
34
|
-
# # Start container
|
35
|
-
# StartContainer.call(
|
38
|
+
# # Start by container name
|
39
|
+
# response = StartContainer.call(
|
36
40
|
# server_context: context,
|
37
41
|
# id: "web-server"
|
38
42
|
# )
|
39
43
|
#
|
40
|
-
# # Start container
|
41
|
-
# StartContainer.call(
|
44
|
+
# # Start by container ID
|
45
|
+
# response = StartContainer.call(
|
42
46
|
# server_context: context,
|
43
47
|
# id: "a1b2c3d4e5f6"
|
44
48
|
# )
|
45
49
|
#
|
46
|
-
# @see CreateContainer
|
47
|
-
# @see StopContainer
|
48
|
-
# @see RunContainer
|
49
50
|
# @see Docker::Container#start
|
50
51
|
# @since 0.1.0
|
51
|
-
|
52
|
+
START_CONTAINER_DEFINITION = ToolForge.define(:start_container) do
|
52
53
|
description 'Start a Docker container'
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
id: {
|
57
|
-
type: 'string',
|
55
|
+
param :id,
|
56
|
+
type: :string,
|
58
57
|
description: 'Container ID or name'
|
59
|
-
}
|
60
|
-
},
|
61
|
-
required: ['id']
|
62
|
-
)
|
63
58
|
|
64
|
-
|
65
|
-
#
|
66
|
-
# This method starts a container that is currently in a stopped state.
|
67
|
-
# The container must already exist and be in a startable state. If the
|
68
|
-
# container is already running, Docker will typically ignore the start
|
69
|
-
# command without error.
|
70
|
-
#
|
71
|
-
# @param id [String] container ID (full or short) or container name
|
72
|
-
# @param server_context [Object] MCP server context (unused but required)
|
73
|
-
#
|
74
|
-
# @return [MCP::Tool::Response] start operation results
|
75
|
-
#
|
76
|
-
# @raise [Docker::Error::NotFoundError] if container doesn't exist
|
77
|
-
# @raise [StandardError] for other start failures
|
78
|
-
#
|
79
|
-
# @example Start by container name
|
80
|
-
# response = StartContainer.call(
|
81
|
-
# server_context: context,
|
82
|
-
# id: "my-app-container"
|
83
|
-
# )
|
84
|
-
#
|
85
|
-
# @example Start by container ID
|
86
|
-
# response = StartContainer.call(
|
87
|
-
# server_context: context,
|
88
|
-
# id: "abc123def456"
|
89
|
-
# )
|
90
|
-
#
|
91
|
-
# @see Docker::Container#start
|
92
|
-
def self.call(id:, server_context:)
|
59
|
+
execute do |id:|
|
93
60
|
container = Docker::Container.get(id)
|
94
61
|
container.start
|
95
62
|
|
96
|
-
|
97
|
-
type: 'text',
|
98
|
-
text: "Container #{id} started successfully"
|
99
|
-
}])
|
63
|
+
"Container #{id} started successfully"
|
100
64
|
rescue Docker::Error::NotFoundError
|
101
|
-
|
102
|
-
type: 'text',
|
103
|
-
text: "Container #{id} not found"
|
104
|
-
}])
|
65
|
+
"Container #{id} not found"
|
105
66
|
rescue StandardError => e
|
106
|
-
|
107
|
-
type: 'text',
|
108
|
-
text: "Error starting container: #{e.message}"
|
109
|
-
}])
|
67
|
+
"Error starting container: #{e.message}"
|
110
68
|
end
|
111
69
|
end
|
70
|
+
|
71
|
+
StartContainer = START_CONTAINER_DEFINITION.to_mcp_tool
|
112
72
|
end
|
@@ -1,126 +1,81 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DockerMCP
|
4
|
-
# MCP tool for stopping
|
4
|
+
# MCP tool for stopping Docker containers.
|
5
5
|
#
|
6
|
-
# This tool
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# This tool gracefully stops a running Docker container by sending a
|
7
|
+
# SIGTERM signal to the main process, allowing it to shut down cleanly.
|
8
|
+
# If the container doesn't stop within the specified timeout, it will
|
9
|
+
# be forcefully killed with SIGKILL.
|
10
10
|
#
|
11
11
|
# == Features
|
12
12
|
#
|
13
13
|
# - Graceful container shutdown with SIGTERM
|
14
|
-
# - Configurable timeout
|
15
|
-
# -
|
16
|
-
# -
|
17
|
-
# -
|
18
|
-
#
|
19
|
-
# == Shutdown Process
|
20
|
-
#
|
21
|
-
# 1. Send SIGTERM to container's main process
|
22
|
-
# 2. Wait for graceful shutdown up to timeout
|
23
|
-
# 3. Send SIGKILL if container hasn't stopped
|
24
|
-
# 4. Return success when container is stopped
|
14
|
+
# - Configurable timeout for forced termination
|
15
|
+
# - Supports container identification by ID or name
|
16
|
+
# - Handles both running and already-stopped containers
|
17
|
+
# - Provides clear feedback on operation status
|
18
|
+
# - Preserves container and data integrity
|
25
19
|
#
|
26
20
|
# == Security Considerations
|
27
21
|
#
|
28
22
|
# Stopping containers affects service availability:
|
29
|
-
# -
|
30
|
-
# -
|
31
|
-
# -
|
32
|
-
# -
|
23
|
+
# - **Service Disruption**: Terminates running services and processes
|
24
|
+
# - **Data Integrity**: May interrupt ongoing operations
|
25
|
+
# - **Resource Release**: Frees CPU, memory, and network resources
|
26
|
+
# - **State Preservation**: Maintains container state for future restart
|
27
|
+
#
|
28
|
+
# Coordinate container stops with dependent services and users.
|
33
29
|
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
# -
|
37
|
-
#
|
38
|
-
#
|
30
|
+
# == Parameters
|
31
|
+
#
|
32
|
+
# - **id**: Container ID or name (required)
|
33
|
+
# - Accepts full container IDs
|
34
|
+
# - Accepts short container IDs (first 12+ characters)
|
35
|
+
# - Accepts custom container names
|
36
|
+
# - **timeout**: Seconds to wait before killing container (optional, default: 10)
|
39
37
|
#
|
40
38
|
# == Example Usage
|
41
39
|
#
|
42
|
-
# # Stop with default timeout
|
43
|
-
# StopContainer.call(
|
40
|
+
# # Stop with default timeout
|
41
|
+
# response = StopContainer.call(
|
44
42
|
# server_context: context,
|
45
43
|
# id: "web-server"
|
46
44
|
# )
|
47
45
|
#
|
48
46
|
# # Stop with custom timeout
|
49
|
-
# StopContainer.call(
|
47
|
+
# response = StopContainer.call(
|
50
48
|
# server_context: context,
|
51
49
|
# id: "database",
|
52
50
|
# timeout: 30
|
53
51
|
# )
|
54
52
|
#
|
55
|
-
# @see StartContainer
|
56
|
-
# @see RemoveContainer
|
57
53
|
# @see Docker::Container#stop
|
58
54
|
# @since 0.1.0
|
59
|
-
|
55
|
+
STOP_CONTAINER_DEFINITION = ToolForge.define(:stop_container) do
|
60
56
|
description 'Stop a Docker container'
|
61
57
|
|
62
|
-
|
63
|
-
|
64
|
-
id: {
|
65
|
-
type: 'string',
|
58
|
+
param :id,
|
59
|
+
type: :string,
|
66
60
|
description: 'Container ID or name'
|
67
|
-
},
|
68
|
-
timeout: {
|
69
|
-
type: 'integer',
|
70
|
-
description: 'Seconds to wait before killing the container (default: 10)'
|
71
|
-
}
|
72
|
-
},
|
73
|
-
required: ['id']
|
74
|
-
)
|
75
61
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# @param id [String] container ID (full or short) or container name
|
84
|
-
# @param server_context [Object] MCP server context (unused but required)
|
85
|
-
# @param timeout [Integer] seconds to wait before force killing (default: 10)
|
86
|
-
#
|
87
|
-
# @return [MCP::Tool::Response] stop operation results
|
88
|
-
#
|
89
|
-
# @raise [Docker::Error::NotFoundError] if container doesn't exist
|
90
|
-
# @raise [StandardError] for other stop failures
|
91
|
-
#
|
92
|
-
# @example Stop with default timeout
|
93
|
-
# response = StopContainer.call(
|
94
|
-
# server_context: context,
|
95
|
-
# id: "nginx-server"
|
96
|
-
# )
|
97
|
-
#
|
98
|
-
# @example Stop database with longer timeout
|
99
|
-
# response = StopContainer.call(
|
100
|
-
# server_context: context,
|
101
|
-
# id: "postgres-db",
|
102
|
-
# timeout: 60 # Allow more time for DB shutdown
|
103
|
-
# )
|
104
|
-
#
|
105
|
-
# @see Docker::Container#stop
|
106
|
-
def self.call(id:, server_context:, timeout: 10)
|
62
|
+
param :timeout,
|
63
|
+
type: :integer,
|
64
|
+
description: 'Seconds to wait before killing the container (default: 10)',
|
65
|
+
required: false,
|
66
|
+
default: 10
|
67
|
+
|
68
|
+
execute do |id:, timeout: 10|
|
107
69
|
container = Docker::Container.get(id)
|
108
70
|
container.stop('timeout' => timeout)
|
109
71
|
|
110
|
-
|
111
|
-
type: 'text',
|
112
|
-
text: "Container #{id} stopped successfully"
|
113
|
-
}])
|
72
|
+
"Container #{id} stopped successfully"
|
114
73
|
rescue Docker::Error::NotFoundError
|
115
|
-
|
116
|
-
type: 'text',
|
117
|
-
text: "Container #{id} not found"
|
118
|
-
}])
|
74
|
+
"Container #{id} not found"
|
119
75
|
rescue StandardError => e
|
120
|
-
|
121
|
-
type: 'text',
|
122
|
-
text: "Error stopping container: #{e.message}"
|
123
|
-
}])
|
76
|
+
"Error stopping container: #{e.message}"
|
124
77
|
end
|
125
78
|
end
|
79
|
+
|
80
|
+
StopContainer = STOP_CONTAINER_DEFINITION.to_mcp_tool
|
126
81
|
end
|