From 20fc1f39890d830e301700741504c745dc763aea Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 18:31:53 +0000 Subject: [PATCH] feat: Add Docker support and configure for Cloud Run This change adds the necessary files and configuration to allow the application to be run in a Docker container and deployed to Google Cloud Run. - Adds a Dockerfile to containerize the application. - Adds a .dockerignore file to exclude unnecessary files from the Docker image. - Updates the server to listen on the host and port specified by the HOST and PORT environment variables, which is a requirement for Cloud Run. - Sets the transport to "streamable-http" for production environments. - Updates the README.md with instructions on how to build and run the application using Docker. --- .dockerignore | 37 +++++++++++++++++++++++++++++++++++++ Dockerfile | 23 +++++++++++++++++++++++ README.md | 28 ++++++++++++++++++++++++++++ analytics_mcp/server.py | 7 ++++++- 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a34b18d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,37 @@ +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Git +.git/ +.gitignore + +# Docker +.dockerignore +Dockerfile + +# Testing +tests/ +noxfile.py + +# GitHub +.github/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ff164cd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# Use the official lightweight Python image. +# https://hub.docker.com/_/python +FROM python:3.11-slim + +# Set the working directory in the container. +WORKDIR /app + +# Copy the dependency file to the working directory. +COPY pyproject.toml . + +# Install any dependencies. +RUN pip install --no-cache-dir -e . + +# Copy the rest of the working directory contents into the container. +COPY . . + +# Set the port that the container will listen on. +# This is the default port for Cloud Run. +ENV PORT=8080 +ENV HOST=0.0.0.0 + +# Run the application. +CMD ["analytics-mcp"] diff --git a/README.md b/README.md index 279da1d..686ab25 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,34 @@ Here are some sample prompts to get you started: what are the custom dimensions and custom metrics in my property? ``` +## Running with Docker 🐳 + +This project includes a `Dockerfile` that can be used to run the server in a +container. + +### Build the image + +From the root of the repository, run the following command to build the Docker +image: + +```shell +docker build -t analytics-mcp . +``` + +### Run the container + +To run the server in a Docker container, you will need to provide your +Application Default Credentials (ADC) to the container. You can do this by +mounting the directory containing your `gcloud` configuration to the container. + +```shell +docker run -p 8080:8080 \ + -v ~/.config/gcloud:/root/.config/gcloud \ + analytics-mcp +``` + +The server will be available at `http://localhost:8080`. + ## Contributing ✨ Contributions welcome! See the [Contributing Guide](CONTRIBUTING.md). diff --git a/analytics_mcp/server.py b/analytics_mcp/server.py index 234f493..eebfc5d 100755 --- a/analytics_mcp/server.py +++ b/analytics_mcp/server.py @@ -16,6 +16,7 @@ """Entry point for the Google Analytics MCP server.""" +import os from analytics_mcp.coordinator import mcp # The following imports are necessary to register the tools with the `mcp` @@ -32,7 +33,11 @@ def run_server() -> None: Serves as the entrypoint for the 'runmcp' command. """ - mcp.run() + # For Cloud Run, the server must listen on 0.0.0.0 and a port specified by + # the PORT environment variable. + host = os.environ.get("HOST", "127.0.0.1") + port = int(os.environ.get("PORT", "8000")) + mcp.run(transport="streamable-http", host=host, port=port) if __name__ == "__main__":