mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
fix(mcp): inject --rm flag for Docker MCP containers to prevent accumulation
Docker containers spawned by MCP servers configured with `docker run` were not cleaned up after being stopped, causing exited containers to accumulate and fill up Docker storage over time. Closes #8103
This commit is contained in:
committed by
Johnny Eric Amancio
parent
66421421a7
commit
def64b8913
@@ -170,6 +170,14 @@ export namespace MCP {
|
||||
return typeof entry === "object" && entry !== null && "type" in entry
|
||||
}
|
||||
|
||||
// kilocode_change — exported for testing
|
||||
export function ensureDockerRm(cmd: string, args: string[]): string[] {
|
||||
if (cmd !== "docker" || args[0] !== "run") return args
|
||||
// Always inject --rm right after "run". Docker treats duplicate --rm as
|
||||
// a no-op, so this is safe even when the user already specified it.
|
||||
return ["run", "--rm", ...args.slice(1)]
|
||||
}
|
||||
|
||||
async function descendants(pid: number): Promise<number[]> {
|
||||
if (process.platform === "win32") return []
|
||||
const pids: number[] = []
|
||||
@@ -456,11 +464,14 @@ export namespace MCP {
|
||||
|
||||
if (mcp.type === "local") {
|
||||
const [cmd, ...args] = mcp.command
|
||||
// kilocode_change — inject --rm for Docker containers to prevent stopped
|
||||
// containers from accumulating when MCP servers are toggled on/off.
|
||||
const finalArgs = ensureDockerRm(cmd, args)
|
||||
const cwd = Instance.directory
|
||||
const transport = new StdioClientTransport({
|
||||
stderr: "pipe",
|
||||
command: cmd,
|
||||
args,
|
||||
args: finalArgs,
|
||||
cwd,
|
||||
env: {
|
||||
...process.env,
|
||||
@@ -590,7 +601,6 @@ export namespace MCP {
|
||||
const s = await state()
|
||||
s.status[name] = result.status
|
||||
if (result.mcpClient) {
|
||||
// Close existing client if present to prevent memory leaks
|
||||
const existingClient = s.clients[name]
|
||||
if (existingClient) {
|
||||
await existingClient.close().catch((error) => {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { test, expect, describe } from "bun:test"
|
||||
import { MCP } from "../../src/mcp"
|
||||
|
||||
describe("ensureDockerRm", () => {
|
||||
test("injects --rm after 'run' for docker run commands", () => {
|
||||
const result = MCP.ensureDockerRm("docker", ["run", "-i", "my-image"])
|
||||
expect(result).toEqual(["run", "--rm", "-i", "my-image"])
|
||||
})
|
||||
|
||||
test("keeps existing --rm and adds another (Docker treats duplicates as no-op)", () => {
|
||||
const result = MCP.ensureDockerRm("docker", ["run", "--rm", "-i", "my-image"])
|
||||
expect(result).toEqual(["run", "--rm", "--rm", "-i", "my-image"])
|
||||
})
|
||||
|
||||
test("does not modify non-docker commands", () => {
|
||||
const args = ["-y", "@modelcontextprotocol/server-filesystem"]
|
||||
const result = MCP.ensureDockerRm("npx", args)
|
||||
expect(result).toBe(args)
|
||||
})
|
||||
|
||||
test("does not modify docker commands that are not 'run'", () => {
|
||||
const args = ["build", "-t", "my-image", "."]
|
||||
const result = MCP.ensureDockerRm("docker", args)
|
||||
expect(result).toBe(args)
|
||||
})
|
||||
|
||||
test("handles docker run with no additional args", () => {
|
||||
const result = MCP.ensureDockerRm("docker", ["run"])
|
||||
expect(result).toEqual(["run", "--rm"])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user