Skip to main content
Glama
docker.py5.13 kB
""" Docker API utilities for container introspection and port discovery. Enables automatic discovery of Docker port mappings for OAuth loopback flows when running in containers with ephemeral port bindings. """ import re from pathlib import Path from typing import Optional from google_docs_mcp.utils import log def get_container_id() -> Optional[str]: """ Get the current container ID if running in a Docker container. Supports both cgroup v1 and v2: - cgroup v1: Reads from /proc/self/cgroup - cgroup v2: Reads from /proc/self/mountinfo Returns: Container ID (64-char hex string) or None if not in container """ # Try cgroup v1 format first cgroup_path = Path("/proc/self/cgroup") if cgroup_path.exists(): try: content = cgroup_path.read_text() # Look for patterns like: 12:name=systemd:/docker/CONTAINER_ID # or: 1:name=systemd:/docker/containers/CONTAINER_ID match = re.search(r"/docker(?:/containers)?/([0-9a-f]{64})", content) if match: return match.group(1) # Also check for shorter container IDs (12 chars) match = re.search(r"/docker(?:/containers)?/([0-9a-f]{12,})", content) if match: return match.group(1) except Exception as e: log(f"[Port Discovery] Error reading cgroup: {e}") # Try cgroup v2 / mountinfo format mountinfo_path = Path("/proc/self/mountinfo") if mountinfo_path.exists(): try: content = mountinfo_path.read_text() # Look for patterns in mountinfo match = re.search(r"/docker/containers/([0-9a-f]{64})", content) if match: return match.group(1) match = re.search(r"/docker/containers/([0-9a-f]{12,})", content) if match: return match.group(1) except Exception as e: log(f"[Port Discovery] Error reading mountinfo: {e}") return None def get_published_port(container_port: int) -> Optional[int]: """ Get the host port mapped to a container port via Docker API. Requires Docker socket to be mounted at /var/run/docker.sock Args: container_port: The port number inside the container Returns: Host port number or None if not found or Docker unavailable """ try: import docker except ImportError: log("[Port Discovery] Docker SDK not installed") return None try: # Connect to Docker socket client = docker.from_env() # Get current container ID container_id = get_container_id() if not container_id: log("[Port Discovery] Not running in Docker container") return None # Get container object container = client.containers.get(container_id) # Get port bindings # Format: {'3000/tcp': [{'HostIp': '0.0.0.0', 'HostPort': '32768'}]} port_bindings = container.attrs.get("NetworkSettings", {}).get("Ports", {}) # Look for our container port port_key = f"{container_port}/tcp" if port_key in port_bindings: bindings = port_bindings[port_key] if bindings and len(bindings) > 0: # Use first binding host_port = bindings[0].get("HostPort") if host_port: return int(host_port) log(f"[Port Discovery] No port mapping found for container port {container_port}") return None except docker.errors.DockerException as e: log(f"[Port Discovery] Docker API error: {e}") return None except Exception as e: log(f"[Port Discovery] Unexpected error during port discovery: {e}") return None def discover_oauth_port(default_port: int = 3000) -> int: """ Discover the host port mapped to the container's OAuth port. Uses Docker API to query port mappings when running in a container with Docker socket mounted. Falls back to default port if: - Not running in Docker - Docker socket not available - No port mapping found - Any errors occur Args: default_port: Port to use if discovery fails (default: 3000) Returns: Discovered host port or default_port """ try: container_id = get_container_id() if not container_id: log(f"[Port Discovery] Not running in Docker container, using default port {default_port}") return default_port log(f"[Port Discovery] Detected container ID: {container_id[:12]}...") host_port = get_published_port(default_port) if host_port: log(f"[Port Discovery] Discovered OAuth host port via Docker API: {host_port}") return host_port else: log(f"[Port Discovery] No port mapping found, using default port {default_port}") return default_port except Exception as e: log(f"[Port Discovery] Error during discovery: {e}, using default port {default_port}") return default_port

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/nickweedon/google-docs-mcp-docker'

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