diff --git a/mcp_server/.dockerignore b/mcp_server/.dockerignore new file mode 100644 index 0000000000..28fbfff4d5 --- /dev/null +++ b/mcp_server/.dockerignore @@ -0,0 +1,67 @@ +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +.pytest_cache/ +.coverage +htmlcov/ +.tox/ +.nox/ +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ + +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +.git/ +.gitignore +.gitattributes +.github/ +.vscode/ +.idea/ +*.swp +*.swo +*~ + +README.md +CHANGELOG.md +LICENSE +docs/ +tests/ +examples/ +.pre-commit-config.yaml +Makefile +docker-compose.yml +docker-compose.yaml diff --git a/mcp_server/Dockerfile b/mcp_server/Dockerfile new file mode 100644 index 0000000000..d5a58edf24 --- /dev/null +++ b/mcp_server/Dockerfile @@ -0,0 +1,54 @@ +# ============================================================================= +# Build stage - Install dependencies and build the application +# ============================================================================= +FROM ghcr.io/astral-sh/uv:python3.13-alpine AS builder + +WORKDIR /app + +# Performance optimizations for uv: +# UV_COMPILE_BYTECODE=1: Pre-compile Python files to .pyc for faster startup +# UV_LINK_MODE=copy: Use copy instead of symlinks to avoid potential issues +ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy + +# Install dependencies first for better Docker layer caching +# This allows dependency layer to be reused when only source code changes +COPY uv.lock pyproject.toml ./ +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen --no-install-project + +# Copy all source code and install the project +# --frozen ensures reproducible builds by using exact versions from uv.lock +COPY . . +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen + +# ============================================================================= +# Final stage - Minimal runtime environment +# ============================================================================= +FROM python:3.13-alpine + +LABEL maintainer="https://github.com/prowler-cloud" + +# Create non-root user for security +# Using specific UID/GID for consistency across environments +RUN addgroup -g 1001 prowler && \ + adduser -D -u 1001 -G prowler prowler + +WORKDIR /app +USER prowler + +# Copy only the necessary files from builder stage to minimize image size: +# 1. Virtual environment with all dependencies and the installed package +COPY --from=builder --chown=prowler /app/.venv /app/.venv + +# 2. Source code needed at runtime (for imports and module resolution) +COPY --from=builder --chown=prowler /app/prowler_mcp_server /app/prowler_mcp_server + +# 3. Project metadata file (may be needed by some packages at runtime) +COPY --from=builder --chown=prowler /app/pyproject.toml /app/pyproject.toml + +# Add virtual environment to PATH so prowler-mcp command is available +ENV PATH="/app/.venv/bin:$PATH" + +# Entry point for the MCP server +ENTRYPOINT ["prowler-mcp"] diff --git a/mcp_server/README.md b/mcp_server/README.md index 0c5894dbd4..8e864b169f 100644 --- a/mcp_server/README.md +++ b/mcp_server/README.md @@ -23,8 +23,26 @@ It is needed to have [uv](https://docs.astral.sh/uv/) installed. git clone https://github.com/prowler-cloud/prowler.git ``` +### Using Docker + +Alternatively, you can build and run the MCP server using Docker: + +```bash +# Clone the repository +git clone https://github.com/prowler-cloud/prowler.git +cd prowler/mcp_server + +# Build the Docker image +docker build -t prowler-mcp . + +# Run the container with environment variables +docker run --rm --env-file ./.env -it prowler-mcp +``` + ## Running +### Using uv directly + After installation, start the MCP server via the console script: ```bash @@ -38,6 +56,15 @@ Alternatively, you can run from wherever you want using `uvx` command: uvx /path/to/prowler/mcp_server/ ``` +### Using Docker + +Run the pre-built Docker container: + +```bash +cd prowler/mcp_server +docker run --rm --env-file ./.env -it prowler-mcp +``` + ## Available Tools ### Prowler Hub @@ -116,7 +143,9 @@ export PROWLER_API_BASE_URL="https://api.prowler.com" ### MCP Client Configuration -Configure your MCP client, like Claude Desktop, Cursor, etc, to launch the server with the `uvx` command. Below is a generic snippet; consult your client's documentation for exact locations. +Configure your MCP client, like Claude Desktop, Cursor, etc, to launch the server. Below are examples for both direct execution and Docker deployment; consult your client's documentation for exact locations. + +#### Using uvx (Direct Execution) ```json { @@ -127,14 +156,34 @@ Configure your MCP client, like Claude Desktop, Cursor, etc, to launch the serve "env": { "PROWLER_APP_EMAIL": "your-email@example.com", "PROWLER_APP_PASSWORD": "your-password", - "PROWLER_APP_TENANT_ID": "your-tenant-id", // Optional, this can be found as `Organization ID` in your User Profile in Prowler App - "PROWLER_API_BASE_URL": "https://api.prowler.com" // Optional + "PROWLER_APP_TENANT_ID": "your-tenant-id", // Optional, this can be found as `Organization ID` in your User Profile in Prowler App, + "PROWLER_API_BASE_URL": "https://api.prowler.com" // Optional, in case not provided Prowler Cloud API will be used } } } } ``` +#### Using Docker + +```json +{ + "mcpServers": { + "prowler": { + "command": "docker", + "args": [ + "run", "--rm", "-i", + "--env", "PROWLER_APP_EMAIL=your-email@example.com", + "--env", "PROWLER_APP_PASSWORD=your-password", + "--env", "PROWLER_APP_TENANT_ID=your-tenant-id", // Optional, this can be found as `Organization ID` in your User Profile in Prowler App + "--env", "PROWLER_API_BASE_URL=https://api.prowler.com", // Optional, in case not provided Prowler Cloud API will be used + "prowler-mcp" + ] + } + } +} +``` + ### Claude Desktop (macOS/Windows) Add the example server to Claude Desktop's config file, then restart the app.