Skip to main content
Glama

interceptor_docker_attach

Inject proxy environment variables and CA certificates into Docker containers to enable network traffic interception. Choose between live injection for running containers or restart mode for persistent configuration.

Instructions

Inject proxy env vars and CA certificate into a Docker container. Two modes: 'exec' (inject into running container) or 'restart' (stop + restart with proxy config).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
container_idYesDocker container ID or name
modeNoInjection mode: 'exec' (live injection) or 'restart' (stop + restart)exec

Implementation Reference

  • Registration of the 'interceptor_docker_attach' tool.
    server.tool(
      "interceptor_docker_attach",
      "Inject proxy env vars and CA certificate into a Docker container. Two modes: 'exec' (inject into running container) or 'restart' (stop + restart with proxy config).",
      {
        container_id: z.string().describe("Docker container ID or name"),
        mode: z.enum(["exec", "restart"]).optional().default("exec")
          .describe("Injection mode: 'exec' (live injection) or 'restart' (stop + restart)"),
      },
      async ({ container_id, mode }) => {
        try {
          const proxyInfo = requireProxy();
          const result = await interceptorManager.activate("docker", {
            ...proxyInfo,
            containerId: container_id,
            mode,
          });
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ status: "success", ...result }),
            }],
          };
        } catch (e) {
          return { content: [{ type: "text", text: JSON.stringify({ status: "error", error: errorToString(e) }) }] };
        }
      },
    );
  • The core 'activate' logic for the Docker interceptor, which implements 'exec' and 'restart' modes for proxy injection.
    async activate(options: ActivateOptions): Promise<ActivateResult> {
      const { proxyPort, certPem } = options;
      const containerId = options.containerId as string | undefined;
      const mode = (options.mode as string) ?? "exec";
    
      if (!containerId) {
        throw new Error("'containerId' option is required for Docker interceptor.");
      }
    
      const Docker = (await import("dockerode")).default;
      const docker = new Docker();
    
      const container = docker.getContainer(containerId);
      const info = await container.inspect();
      const containerName = info.Name.replace(/^\//, "");
    
      const proxyUrl = `http://host.docker.internal:${proxyPort}`;
      const targetId = `docker_${containerId.slice(0, 12)}`;
    
      if (mode === "exec") {
        // Write cert to a temp dir that we'll copy into the container
        const certDir = join(tmpdir(), `proxy-mcp-docker-${Date.now()}`);
        mkdirSync(certDir, { recursive: true });
        const certPath = join(certDir, "proxy-mcp-ca.pem");
        writeFileSync(certPath, certPem, "utf-8");
    
        // Copy cert into container
        const { execSync } = await import("node:child_process");
        execSync(`docker cp "${certPath}" ${containerId}:/tmp/proxy-mcp-ca.pem`, { timeout: 10000 });
    
        // Set env vars inside container using exec
        const envCommands = [
          `export HTTP_PROXY=${proxyUrl}`,
          `export HTTPS_PROXY=${proxyUrl}`,
          `export http_proxy=${proxyUrl}`,
          `export https_proxy=${proxyUrl}`,
          `export SSL_CERT_FILE=/tmp/proxy-mcp-ca.pem`,
          `export NODE_EXTRA_CA_CERTS=/tmp/proxy-mcp-ca.pem`,
          `export REQUESTS_CA_BUNDLE=/tmp/proxy-mcp-ca.pem`,
          `export CURL_CA_BUNDLE=/tmp/proxy-mcp-ca.pem`,
        ];
    
        // Write a profile script that sets these on each new shell
        const profileScript = envCommands.join("\n") + "\n";
        const profileExec = await container.exec({
          Cmd: ["sh", "-c", `echo '${profileScript.replace(/'/g, "'\\''")}' > /etc/profile.d/proxy-mcp.sh 2>/dev/null || echo '${profileScript.replace(/'/g, "'\\''")}' >> /etc/profile 2>/dev/null`],
          AttachStdout: true,
          AttachStderr: true,
        });
        await profileExec.start({});
    
        // Also try updating /etc/environment for some distros
        const envExec = await container.exec({
          Cmd: ["sh", "-c", [
            `echo "HTTP_PROXY=${proxyUrl}" >> /etc/environment`,
            `echo "HTTPS_PROXY=${proxyUrl}" >> /etc/environment`,
            `echo "SSL_CERT_FILE=/tmp/proxy-mcp-ca.pem" >> /etc/environment`,
            `echo "NODE_EXTRA_CA_CERTS=/tmp/proxy-mcp-ca.pem" >> /etc/environment`,
          ].join(" && ")],
          AttachStdout: true,
          AttachStderr: true,
        });
        await envExec.start({});
    
        const target: ActiveTarget = {
          id: targetId,
          description: `${containerName} (${containerId.slice(0, 12)}) [exec mode]`,
          activatedAt: Date.now(),
          details: {
            containerId,
            containerName,
            mode: "exec",
            proxyUrl,
            certInjected: true,
            note: "Proxy env vars set. New processes in this container will use the proxy. Existing processes may need restart.",
          },
        };
    
        this.targets.set(targetId, { target, containerId, mode: "exec" });
        return { targetId, details: target.details };
    
      } else {
        // Restart mode — stop, recreate with proxy env, start
        // This is more invasive but ensures ALL processes in the container use the proxy
    
        // Save original env for restore
        const originalEnv = info.Config.Env || [];
    
        const proxyEnvVars = [
          `HTTP_PROXY=${proxyUrl}`,
          `HTTPS_PROXY=${proxyUrl}`,
          `http_proxy=${proxyUrl}`,
          `https_proxy=${proxyUrl}`,
          `SSL_CERT_FILE=/tmp/proxy-mcp-ca.pem`,
          `NODE_EXTRA_CA_CERTS=/tmp/proxy-mcp-ca.pem`,
          `REQUESTS_CA_BUNDLE=/tmp/proxy-mcp-ca.pem`,
          `CURL_CA_BUNDLE=/tmp/proxy-mcp-ca.pem`,
        ];
    
        // For restart mode, we just inject env vars via exec and restart the main process
        // Full container recreation is too invasive for an MCP tool
        await container.stop().catch(() => {});
    
        // Note: true container recreation would require Docker compose or similar
        // For now, we add env via exec after restart
        await container.start();
    
        // Copy cert and set env after restart
        const { execSync } = await import("node:child_process");
        const certDir = join(tmpdir(), `proxy-mcp-docker-${Date.now()}`);
        mkdirSync(certDir, { recursive: true });
        writeFileSync(join(certDir, "proxy-mcp-ca.pem"), certPem, "utf-8");
        execSync(`docker cp "${join(certDir, "proxy-mcp-ca.pem")}" ${containerId}:/tmp/proxy-mcp-ca.pem`, { timeout: 10000 });
    
        const envScript = proxyEnvVars.map((e) => `export ${e}`).join("\n") + "\n";
        const exec = await container.exec({
          Cmd: ["sh", "-c", `echo '${envScript.replace(/'/g, "'\\''")}' > /etc/profile.d/proxy-mcp.sh 2>/dev/null || true`],
          AttachStdout: true,
          AttachStderr: true,
        });
        await exec.start({});
    
        const target: ActiveTarget = {
          id: targetId,
          description: `${containerName} (${containerId.slice(0, 12)}) [restart mode]`,
          activatedAt: Date.now(),
          details: {
            containerId,
            containerName,
            mode: "restart",
            proxyUrl,
            restarted: true,
          },
        };
    
        this.targets.set(targetId, { target, containerId, mode: "restart", originalEnv });
        return { targetId, details: target.details };
      }
    }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yfe404/proxy-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server