Metadata-Version: 2.5
Name: cloud-bicep-mcp-server
Version: 0.3.1
Summary: MCP Server for discovering and exploring Cloud Bicep Modules
Author: Cloud Team
License-Expression: MIT
Requires-Python: <4.0.0,>=3.13
Requires-Dist: fastmcp>=4.0.11
Requires-Dist: pydantic-settings>=2.15.0
Requires-Dist: python-dotenv<2.0.0,>=1.2.4
Requires-Dist: requests>=2.34.2
Requires-Dist: uvicorn>=0.30.0
Description-Content-Type: text/markdown

<table>
  <tr>
    <td><img src="https://xtratuscloud.github.io/assets/cloud-bicep-mcp.jpg" alt="Cloud Bicep MCP logo" width="300" /></td>
    <td>
      <h1>cloud-bicep-mcp-server</h1>
      MCP Server for discovering and exploring Cloud Bicep Modules from the private <code>cloud_bicep-registry-modules</code> repository.
    </td>
  </tr>
</table>

## 🎯 Overview

This MCP server enables AI agents and tools to search, discover, and retrieve detailed information about Cloud Bicep Modules via the Model Context Protocol (MCP). It connects directly to the private GitHub repository to provide up-to-date module information, versions, parameters, and usage examples.

Cloud Bicep Modules are a collection of standardized, validated, and well-documented Infrastructure as Code (IaC) modules for deploying Azure resources using Bicep, tailored to your cloud infrastructure requirements and best practices.

## ❓ When to Use Cloud Bicep MCP Server?

Cloud Bicep Modules provide a standardized approach to deploying Azure resources within your cloud infrastructure. However, discovering the right module and understanding its parameters can be challenging:

- **Discovery Challenge**: With multiple modules available, finding the right module for your use case requires searching through documentation
- **Parameter Complexity**: Each module has numerous parameters with specific requirements and defaults
- **Version Management**: Keeping track of module versions and updates across the private repository
- **Documentation Access**: Module documentation is scattered across the private GitHub repository

This MCP server solves these challenges by:

- Providing fast, intelligent search across all Cloud Bicep modules
- Retrieving module versions directly from the repository
- Extracting detailed parameter information and usage examples
- Enabling AI agents to help you find and use the right modules
- Supporting secure authentication for private repository access

## 🛠️ Features

- **Search Bicep Modules**: Intelligent search supporting multiple query formats (e.g., "key vault", "key-vault", "keyvault")
- **List Module Current Version**: Retrieve the current version for any Cloud Bicep module
- **Module Details**: Extract resource types, parameters, and usage examples from module documentation
- **Fast Filtering**: Optimized search that quickly narrows down results
- **Direct Repository Access**: Connects to the private GitHub repository for real-time module information
- **Secure Authentication**: GitHub PAT authentication for private repository access
- **Multiple Transports**: Supports STDIO, HTTP, and SSE transports for different use cases

The server loads its icon metadata from `server.json` at startup. `GET /mcp/icon.png` serves the bundled 96×96 PNG without authentication so MCP clients can fetch it separately from the protected tools. Set `icons[].src` to the public URL where the icon is hosted (e.g., the raw content URL in the GitHub repository) and ensure the ingress routes `/mcp/icon.png` to the MCP service. Both the manifest and PNG are included in the wheel and Docker image.

## 📋 Prerequisites

- Python 3.13 or newer
- Poetry package manager
- uv (for `uvx`-based local installations from PyPI)
- Podman (for containerized deployments)
- Internet connectivity (to access the private GitHub repository)
- Node.js and npm (for MCP inspector tools, optional)

### 1. Python

- **Official Download Page:**
  [https://www.python.org/downloads/](https://www.python.org/downloads/)

- Download the installer for your OS (Windows, macOS, Linux) and follow the setup instructions.

---

### 2. Poetry (Python Package Manager)

- **Official Documentation & Source:**
  [https://python-poetry.org/](https://python-poetry.org/)
  [Poetry Documentation](https://python-poetry.org/docs/)

- **Installation (Windows):**

  ```powershell
  (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python -
  ```

- **Installation (macOS/Linux):**

  ```bash
  curl -sSL https://install.python-poetry.org | python3 -
  ```

- **More Info:**
  [Poetry Installation Guide](https://python-poetry.org/docs/#installation)

---

### 3. Podman (Container Runtime)

- **Official Documentation & Source:**
  [https://podman.io/](https://podman.io/)
  [Podman Documentation](https://docs.podman.io/)

- **Installation (Windows):**
  Podman Desktop is recommended for Windows:
  [https://podman-desktop.io/](https://podman-desktop.io/)

- **Installation (macOS):**

  ```bash
  brew install podman
  podman machine init
  podman machine start
  ```

- **Installation (Linux):**

  ```bash
  # Ubuntu/Debian
  sudo apt-get install podman

  # Fedora
  sudo dnf install podman
  ```

- **More Info:**
  [Podman Installation Guide](https://docs.podman.io/en/latest/Installation.html)

---

### 4. Claude Desktop (Optional)

- **Official Download Page:**
  [https://claude.ai/download](https://claude.ai/download)

- Download the installer for your OS (Windows, macOS) and follow the setup instructions.

## 🚀 Installation

1. Clone the repository:

   ```powershell
   git clone https://github.com/xtratuscloud/cloud_bicep-registry-modules.git
   cd cloud_bicep-registry-modules/mcp
   ```

2. Install dependencies with Poetry:

   ```powershell
   poetry install
   ```

3. Install with dev dependencies (for testing):

   ```powershell
   poetry install --with dev
   ```

## ⚙️ Configuration

### 🔧 Environment Variables

Create a `.env` file in the `mcp` directory:

```env
# API Key for client authentication
MCP_API_KEY=your-secret-api-key-here

# GitHub Repository Configuration
GITHUB_REPO_OWNER=xtratuscloud
GITHUB_REPO_NAME=cloud_bicep-registry-modules

# GitHub Access
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Optional: Debug mode
MCP_DEBUG=false

# Bicep module registry (OCI registry and repository path where bicep modules are published)
# Used to build module references (br:<registry>/<name>:<version>)
BICEP_MODULE_REGISTRY=yourregistry.azurecr.io/bicep/modules
```

See `.env.example` for a complete example.

### 🔧 Claude Desktop Setup

#### Option 1: Using Poetry with Local Installation

Add the following to your `claude_desktop_config.json` file:

```json
{
  "mcpServers": {
    "cloud-bicep-mcp-server": {
      "type": "stdio",
      "command": "poetry",
      "args": [
        "run",
        "python",
        "C:\\code\\xtratuscloud\\cloud_bicep-registry-modules\\mcp\\server.py"
      ],
      "cwd": "C:\\code\\xtratuscloud\\cloud_bicep-registry-modules\\mcp"
    }
  }
}
```

**Note**: Adjust the paths to match your installation location.

#### Option 2: Using uvx (After Publishing to PyPI)

```json
{
  "mcpServers": {
    "cloud-bicep-mcp-server": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "cloud-bicep-mcp-server"
      ]
    }
  }
}
```

#### Option 3: Using uvx from Local Directory

```json
{
  "mcpServers": {
    "cloud-bicep-mcp-server": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "--from",
        "C:\\code\\xtratuscloud\\cloud_bicep-registry-modules\\mcp",
        "cloud-bicep-mcp-server"
      ]
    }
  }
}
```

### 🔧 VSCode Setup

VSCode (GitHub Copilot) runs the server locally via STDIO. Add one of the following to `%USERPROFILE%\.copilot\mcp-config.json`:

#### Option 1: Using uvx (After Publishing to PyPI)

```json
{
  "servers": {
    "cloud-bicep-mcp-server": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "cloud-bicep-mcp-server"
      ],
      "env": {
        "GITHUB_REPO_OWNER": "<GITHUB_REPO_OWNER>",
        "GITHUB_REPO_NAME": "<GITHUB_REPO_NAME>",
        "GITHUB_TOKEN": "<GITHUB_TOKEN>",
        "BICEP_MODULE_REGISTRY": "<BICEP_MODULE_REGISTRY>"
      }
    }
  }
}
```

**Note**: Replace `<GITHUB_REPO_OWNER>`, `<GITHUB_REPO_NAME>`, `<GITHUB_TOKEN>` and `<BICEP_MODULE_REGISTRY>` with your values.

#### Option 2: Using Podman

```json
{
  "servers": {
    "cloud-bicep-mcp-server": {
      "type": "stdio",
      "command": "podman",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e", "GITHUB_REPO_OWNER=<GITHUB_REPO_OWNER>",
        "-e", "GITHUB_REPO_NAME=<GITHUB_REPO_NAME>",
        "-e", "GITHUB_TOKEN=<GITHUB_TOKEN>",
        "-e", "BICEP_MODULE_REGISTRY=<BICEP_MODULE_REGISTRY>",
        "ghcr.io/xtratuscloud/cloud-bicep-mcp-server"
      ]
    }
  }
}
```

**Notes**: The container defaults to STDIO transport. `docker` can be used instead of `podman` — the syntax is identical.

### 🔧 Devin Setup

Add one of the following to your Devin MCP configuration (`%APPDATA%\devin\mcp_config.json` on Windows):

#### Option 1: Using uvx (After Publishing to PyPI)

```json
"cloud-bicep-mcp-server": {
  "command": "uvx",
  "args": [
    "cloud-bicep-mcp-server"
  ],
  "env": {
    "GITHUB_REPO_OWNER": "<GITHUB_REPO_OWNER>",
    "GITHUB_REPO_NAME": "<GITHUB_REPO_NAME>",
    "GITHUB_TOKEN": "<GITHUB_TOKEN>",
    "BICEP_MODULE_REGISTRY": "<BICEP_MODULE_REGISTRY>"
  }
}
```

#### Option 2: Using Podman

```json
"cloud-bicep-mcp-server": {
  "command": "podman",
  "args": [
    "run",
    "-i",
    "--rm",
    "-e", "GITHUB_REPO_OWNER=<GITHUB_REPO_OWNER>",
    "-e", "GITHUB_REPO_NAME=<GITHUB_REPO_NAME>",
    "-e", "GITHUB_TOKEN=<GITHUB_TOKEN>",
    "-e", "BICEP_MODULE_REGISTRY=<BICEP_MODULE_REGISTRY>",
    "ghcr.io/xtratuscloud/cloud-bicep-mcp-server"
  ]
}
```

**Note**: Replace the `<...>` placeholders with your values. The container defaults to STDIO transport. `docker` can be used instead of `podman` — the syntax is identical.

## 🚀 Publishing

Publishing is handled by two workflows: the **CI workflow** builds, tests and publishes the Docker image, and the **release workflow** creates the Git tag, the GitHub Release and publishes to PyPI.

### CI Workflow (`bicep-mcp-ci.yml`)

Runs on push to main, PRs to main and manual dispatch, when there are changes under `mcp/**`:

1. **Determine version** from `mcp/pyproject.toml`
2. **Run tests**: Python 3.13, 3.14, 3.15 + package build validation
3. **Publish Docker image to GitHub Packages**: always

| Branch | Docker tag | `latest` tag | Git tag / GitHub Release | PyPI |
|---|---|---|---|---|
| non-main (pre-release) | `0.3.0.20261015.1` | No | No | No |
| main (official release) | `0.3.0` | Yes | Yes (release workflow) | Yes (release workflow) |

### Release Workflow (`bicep-mcp-release.yml`)

Runs automatically after a successful CI run on main:

1. **Create Git tag and GitHub Release**: `mcp/v0.3.0`, with the changelog section for the version as release notes
2. **Publish to PyPI**: `poetry build` + `poetry publish` (official releases only)

### Docker Image (GitHub Packages)

- **Registry**: `ghcr.io`
- **Image**: `ghcr.io/xtratuscloud/cloud-bicep-mcp-server`
- **Tags**:
  - Pre-releases: `0.3.0.20261015.1`
  - Official releases: `0.3.0` and `latest`

### Pull Docker Images

```bash
# Pull a specific pre-release
docker pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:0.3.0.20261015.1

# Pull latest official release
docker pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:latest

# Pull a specific official release
docker pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:0.3.0
```

### PyPI

- **Package**: `cloud-bicep-mcp-server`
- **Install**: `uvx cloud-bicep-mcp-server` (or `pip install cloud-bicep-mcp-server`)

### Required Repository Secrets

| Secret | Used by | Description |
|---|---|---|
| `GHCR_USERNAME` | CI workflow | GitHub username of a member of the account owning the image namespace |
| `GHCR_TOKEN` | CI workflow | Classic PAT with `write:packages` scope |
| `PYPI_API_TOKEN` | Release workflow | PyPI API token |

## 🏃 Running the Server

### Using Poetry (Local Installation)

If you cloned the repository:

```powershell
poetry run python server.py
```

### Running with Different Transports

The server supports multiple transport methods for different use cases:

#### 1. STDIO Transport (Default)

Standard input/output - ideal for Claude Desktop and MCP Inspector:

```bash
poetry run python server.py --transport stdio
```

This is the default mode and is used when no transport is specified.

#### 2. HTTP Transport

Streamable HTTP transport - ideal for web applications and REST API integrations:

**Option A: Using startup scripts (recommended)**

The MCP server includes startup scripts that automatically load environment variables from `.env`:

**Windows:**
```powershell
cd mcp
.\start_http.bat
```

**Linux/macOS:**
```bash
cd mcp
chmod +x start_http.sh
./start_http.sh
```

**Option B: Manual startup with Poetry**

```bash
# Set environment variables manually (Linux/macOS)
export $(cat .env | grep -v '^#' | xargs)
poetry run python server.py --transport http --host 0.0.0.0 --port 8080

# Or on Windows PowerShell
Get-Content .env | ForEach-Object { if ($_ -notmatch '^#') { $var = $_.Split('='); [Environment]::SetEnvironmentVariable($var[0], $var[1]) } }
poetry run python server.py --transport http --host 0.0.0.0 --port 8080
```

**Test the server is running:**
```bash
# Simple tools listing endpoint (GET request)
curl http://localhost:8080/tools

# MCP protocol endpoint (requires POST with JSON-RPC format)
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "capabilities": {},
      "clientInfo": {"name": "test-client", "version": "1.0.0"}
    }
  }'
```

**Note**: The Streamable HTTP endpoint is `/mcp` without a trailing slash. `/mcp/` redirects to `/mcp`, which can break MCP clients behind reverse proxies. Use Streamable HTTP with JSON-RPC POST requests; legacy SSE uses `/sse` only when the server starts with `--transport sse`.

#### 3. SSE Transport

Server-Sent Events transport - ideal for real-time streaming applications:

```bash
poetry run python server.py --transport sse --host 0.0.0.0 --port 8080
```

#### Additional Options

- `--debug`: Enable debug logging
- `--host`: Host address to bind to (default: 0.0.0.0 for HTTP/SSE)
- `--port`: Port to use (default: 8080 for HTTP/SSE)

Example with debug mode:
```bash
poetry run python server.py --transport http --port 8081 --debug
```

#### Configuration via Environment Variables

You can also configure the server using a `.env` file:

```env
MCP_HOST=0.0.0.0
MCP_PORT=8080
MCP_DEBUG=false
LOG_LEVEL=INFO
```

### Running with Docker/Podman

#### Option 1: Build from Source

For containerized deployments, use the included Dockerfile:

```bash
# Build the image
docker build -t cloud-bicep-mcp-server .

# Run the container in HTTP transport mode
docker run --env-file .env -e MCP_TRANSPORT=http -p 8080:8080 cloud-bicep-mcp-server
```

The container defaults to STDIO transport. Set `MCP_TRANSPORT=http` to expose the HTTP endpoints. To use a different port:

```bash
docker run --env-file .env -e MCP_TRANSPORT=http -p 9000:8080 cloud-bicep-mcp-server
```

To run with SSE transport instead:

```bash
docker run --env-file .env -p 8080:8080 cloud-bicep-mcp-server python server.py --transport sse --port 8080
```

#### Option 2: Pull from GitHub Packages (Recommended for Production)

Pull the pre-built image from GitHub Packages (no login required for public images):

```bash
# Pull a specific version
docker pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:0.3.0

# Pull the latest version
docker pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:latest

# Run the container in HTTP transport mode
docker run --env-file .env -e MCP_TRANSPORT=http -p 8080:8080 ghcr.io/xtratuscloud/cloud-bicep-mcp-server:0.3.0
```

#### Additional Docker Commands

**Build with custom tag:**
```bash
docker build -t cloud-bicep-mcp-server:latest .
```

**Run in background (detached mode):**
```bash
docker run -d --env-file .env -e MCP_TRANSPORT=http -p 8080:8080 --name cloud-bicep-mcp-server cloud-bicep-mcp-server
```

**View logs:**
```bash
docker logs cloud-bicep-mcp-server
```

**Stop the container:**
```bash
docker stop cloud-bicep-mcp-server
```

**Remove the container:**
```bash
docker rm cloud-bicep-mcp-server
```

**Remove the image:**
```bash
docker rmi cloud-bicep-mcp-server
```

#### Using Podman

Podman is a Docker-compatible alternative. Replace `docker` with `podman` in all commands above:

```bash
# Build with Podman
podman build -t cloud-bicep-mcp-server .

# Run with Podman
podman run --env-file .env -e MCP_TRANSPORT=http -p 8080:8080 cloud-bicep-mcp-server

# Pull from GitHub Packages with Podman
podman pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:latest
```

### Inspect MCP Server

The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is a useful tool for testing and debugging MCP servers.

#### STDIO Transport (Default)

Using Poetry with local installation:

```powershell
npx @modelcontextprotocol/inspector poetry run python server.py
```

#### HTTP Transport

First, start the server in HTTP mode:

```powershell
poetry run python server.py --transport http --port 8080
```

Then open the MCP Inspector web UI and connect to the HTTP endpoint:

```powershell
npx @modelcontextprotocol/inspector
```

In the Inspector UI, enter `http://localhost:8080/mcp` as the server URL and select "Streamable HTTP" as the transport type.

Alternatively, use curl to verify the server is running:

```powershell
# Check the tools endpoint
curl http://localhost:8080/tools

# Or test the MCP endpoint directly
curl -X POST http://localhost:8080/mcp `
  -H "Content-Type: application/json" `
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}'
```

#### SSE Transport

First, start the server in SSE mode:

```powershell
poetry run python server.py --transport sse --port 8080
```

Then open the MCP Inspector web UI:

```powershell
npx @modelcontextprotocol/inspector
```

In the Inspector UI, enter `http://localhost:8080/sse` as the server URL and select "SSE" as the transport type.

### Kubernetes Deployment

The server includes a `GET /health` endpoint for Kubernetes health checks. This endpoint returns a 200 status when the server is running. HTTP/SSE authentication middleware exempts only `GET /health` from API key and GitHub token configuration checks; all other requests remain protected.

#### Health Check Endpoint

```bash
curl http://localhost:8080/health
```

Response:
```json
{
  "status": "healthy",
  "version": "0.3.0",
  "timestamp": 1728768000.0
}
```

#### Kubernetes Deployment Example

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cloud-bicep-mcp-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cloud-bicep-mcp-server
  template:
    metadata:
      labels:
        app: cloud-bicep-mcp-server
    spec:
      containers:
      - name: cloud-bicep-mcp-server
        image: ghcr.io/xtratuscloud/cloud-bicep-mcp-server:0.3.0
        ports:
        - containerPort: 8080
        env:
        - name: MCP_TRANSPORT
          value: "http"
        - name: MCP_API_KEY
          valueFrom:
            secretKeyRef:
              name: bicep-mcp-server-secrets
              key: bicep-mcp-api-key
        - name: GITHUB_TOKEN
          valueFrom:
            secretKeyRef:
              name: bicep-mcp-server-secrets
              key: bicep-mcp-github-token
        - name: GITHUB_REPO_OWNER
          value: "xtratuscloud"
        - name: GITHUB_REPO_NAME
          value: "cloud_bicep-registry-modules"
        - name: GITHUB_DEFAULT_BRANCH
          value: "main"
        - name: BICEP_MODULE_REGISTRY
          value: "yourregistry.azurecr.io/bicep/modules"
        - name: MCP_CACHE_TTL_SECONDS
          value: "86400"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        startupProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 0
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 12
---
apiVersion: v1
kind: Service
metadata:
  name: cloud-bicep-mcp-service
spec:
  selector:
    app: cloud-bicep-mcp-server
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer
```

#### Probe Configuration Guidelines

- **Liveness Probe**: Checks if the container is running. Set `initialDelaySeconds` to allow the server to start (typically 30s).
- **Readiness Probe**: Checks if the container is ready to serve traffic. Can have a shorter `initialDelaySeconds` (typically 10s).
- **Startup Probe**: Gives the container additional time to start during initial deployment. Set `failureThreshold` to allow for slow startups.

## 🔐 Authentication

The MCP server uses two separate authentication layers:

1. **API Key Authentication** - Validates the caller (client authentication) - **ALWAYS REQUIRED**
2. **GitHub Access** - Uses the configured `GITHUB_TOKEN` to access the private repository

### Authentication Behavior

**Important:** The server will return an error if:
- `MCP_API_KEY` is not configured → **500 Error** (server configuration error)
- The client doesn't provide the `X-API-Key` header → **401 Error** (authentication required)
- The `X-API-Key` header doesn't match the configured `MCP_API_KEY` → **401 Error** (invalid credentials)

### Layer 1: API Key Authentication (Client Validation) - ALWAYS REQUIRED

The server **always** validates callers using an API Key configured via the `MCP_API_KEY` environment variable. This is mandatory for all requests.

#### Setup:

1. **Configure the API Key (REQUIRED):**
   ```env
   MCP_API_KEY=your-secret-api-key-here
   ```

2. **Client authentication:**
   The client must send the API Key in the `X-API-Key` header:
   ```bash
   curl -H "X-API-Key: your-secret-api-key-here" http://localhost:8080/mcp
   ```

#### Security Notes:
- **Never commit** API keys to Git
- Use strong, random API keys
- Rotate API keys regularly
- Store API keys in secure secret management systems (e.g., Azure Key Vault, GitHub Secrets)
- **API Key is mandatory** - the server will not accept requests without it

### Layer 2: GitHub Access (Repository Authentication)

After API Key validation, the server needs to access the private GitHub repository using a GitHub Personal Access Token (PAT).

**Setup:**

1. **Generate a GitHub PAT:**
   - Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
   - Click "Generate new token (classic)"
   - Select the `repo` scope (required for private repositories)
   - Generate and copy the token

2. **Configure the server:**
   ```env
   GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   ```

3. **Security Notes:**
   - **Never commit** tokens to Git
   - Use the minimum required scope (`repo` for private repos)
   - Rotate tokens regularly
   - Store the token in a secure secret management system (e.g., Azure Key Vault, GitHub Secrets)

### Complete Configuration Example

```env
# API Key for client authentication (REQUIRED)
MCP_API_KEY=your-secret-api-key-here

# GitHub Repository Configuration (owner and repository REQUIRED - no defaults)
GITHUB_REPO_OWNER=xtratuscloud
GITHUB_REPO_NAME=cloud_bicep-registry-modules
# Optional: branch used to build documentation links (defaults to main)
GITHUB_DEFAULT_BRANCH=main

# GitHub Access via PAT (REQUIRED)
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Bicep module registry (REQUIRED - no defaults)
BICEP_MODULE_REGISTRY=yourregistry.azurecr.io/bicep/modules
```

## 📚 Module README Documentation Format

The MCP server extracts information from module README.md files. To ensure proper extraction, module READMEs should follow this structure:

### Required Sections

#### 1. Resources Section (Optional but Recommended)
The MCP server searches for resource information in this order:
- **"## Resources Created"** (priority 1) - Lists Azure resources created by the module
- **"## Deployed Resources"** (priority 2) - Alternative name for resources section
- **"## Resource Types"** (priority 3) - Fallback pattern

**Example:**
```markdown
## Resources Created

| Resource Type | API Version | References |
| :-- | :-- | :-- |
| `Microsoft.KeyVault/vaults` | 2023-02-01 | [Azure Key Vault Documentation](https://docs.microsoft.com/azure/key-vault/) |
```

#### 2. Parameters Section (Required)
The MCP server extracts parameter information from:
- **"## Parameters"** (required)

**Example:**
```markdown
## Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `environment` | `Environment` | Yes | - | Environment used by naming and network-access logic. |
| `functionalityId` | string | Yes | - | Functionality identifier included in the resource name. |
```

#### 3. Outputs Section (Required)
The MCP server extracts output information from:
- **"## Outputs"** (required)

**Example:**
```markdown
## Outputs

| Output | Type | Description |
|--------|------|-------------|
| `id` | string | Resource ID of the deployed resource. |
| `name` | string | Generated resource name. |
```

#### 4. Usage Examples Section (Optional but Recommended)
The MCP server searches for usage examples in this order:
- **"## Usage Examples"** (priority 1)
- **"## Examples"** (priority 2 - fallback)

**Example:**
```markdown
## Usage Examples

### Example 1: Basic deployment

```bicep
module myResource 'modules/my-resource/main.bicep' = {
  name: 'myResourceDeployment'
  params: {
    environment: 'production'
    functionalityId: 'myapp'
    resourceGroupName: 'RG-WE-P-APP-001'
    location: 'westeurope'
  }
}
```
```

### Section Naming Guidelines

- Use **exact** section names as specified above
- Section names are **case-sensitive**
- Use **markdown level 2** headers (`##`)
- The MCP server uses regex patterns to find these sections
- Multiple patterns are supported for flexibility (e.g., "Resources Created" OR "Deployed Resources")

### Current Module README Status

As of the latest review, the following modules have READMEs that follow the expected format:

**Fully Compliant (16 modules):**
- acr, apim, app-configuration, application-insights, capacity-reservation, cognitive-services, fabric, keyvault, log-analytics, managed-redis, nsg, private-endpoint, service-plan, common, redis-cache (partial), search-service (partial)

**Need Updates (4 modules):**
- app-service, flex-function-app, function-app, static-web-app (missing Resources section)

## 📝 Poetry Commands

Here are the most common Poetry commands for managing this project:

### Installation
```bash
poetry install                    # Install dependencies
poetry install --with dev        # Install with dev dependencies
poetry update                     # Update dependencies to latest compatible versions
poetry lock                       # Regenerate poetry.lock file
```

### Dependency Management
```bash
poetry add <package>             # Add a new dependency
poetry add --group dev <package> # Add a dev dependency
poetry remove <package>          # Remove a dependency
poetry show                       # Show all dependencies
poetry show <package>            # Show details of a specific package
```

### Environment Management
```bash
poetry shell                      # Activate the virtual environment
poetry env list                   # List all virtual environments
poetry env remove <name>          # Remove a virtual environment
poetry env info                   # Show current environment info
```

### Running Commands
```bash
poetry run <command>             # Run a command in the virtual environment
poetry run pytest tests/ -v      # Run tests with verbose output
poetry run python server.py       # Run the server
```

### Building and Publishing
```bash
poetry build                      # Build the package
poetry publish                    # Publish to PyPI
```

## 📖 Available Tools

### 1. `list_bicep_modules`

List all Cloud Bicep modules from the private repository. Returns a lightweight, full module inventory to keep the response small.

**Parameters:** None.

**Returns:**
JSON array with minimal module information per module:

- Module name
- Display name
- Module reference (`br:<registry>/<name>:<version>` — includes the current version)

Use `search_bicep_modules` to get complete module information (description, resource type, documentation, etc.).

**Example Usage:**

```text
"List all available Bicep modules"
"Show me the full module inventory"
```

**Example Response:**

```json
[
  {
    "name": "keyvault",
    "displayName": "Key Vault",
    "moduleReference": "br:yourregistry.azurecr.io/bicep/modules/keyvault:1.0.0"
  }
]
```

### 2. `search_bicep_modules`

Search Cloud Bicep modules by name, Azure resource type or description. Returns only the modules matching the search term. Use `list_bicep_modules` instead when a full inventory is required.

**Parameters:**

- `search_term` (required): Term to search for. Matches (case-insensitive) against:
  - Module name (e.g., `"keyvault"`, `"storage-account"`)
  - Display name (e.g., `"key vault"`, `"Key Vault"`)
  - Canonical Azure resource type (e.g., `"Microsoft.KeyVault/vaults"`)
  - Description
  - Multi-word terms match when every word of the term is present

**Returns:**
JSON array with complete information for the matching modules: name, display name,
description, current version, Azure resource type (canonicalType), owners,
documentation link and module reference (`br:<registry>/<name>:<version>`).

**Example Usage:**

```text
"Find Bicep modules for key vault"
"Search modules with resource type Microsoft.Storage/storageAccounts"
"Which modules can I use for Azure Storage?"
```

### 3. `scrape_bicep_module_details`

Fetch detailed information from a Cloud Bicep module's README documentation.

**Parameters:**

- `url` (required): GitHub URL of the Cloud Bicep module repository
  - Example: `https://github.com/xtratuscloud/cloud_bicep-registry-modules/tree/main/modules/keyvault`

**Returns:**
Formatted markdown containing:

- **Module Reference**: Bicep module reference (`br:<registry>/<name>:<version>`)
- **Resource Types**: Azure resources deployed by the module
- **Parameters**: Complete parameter reference with types, defaults, and descriptions
- **Outputs**: Module outputs
- **Usage Examples**: Large parameter set examples showing real-world usage

**Example Usage:**

```text
"Get the details for the key vault module"
"Show me the parameters for the storage account module"
"What resources does the virtual network module deploy?"
```

**Example Response:**

```markdown
## Resource Types

|| Resource Type | API Version ||
|| :-- | :-- ||
|| `Microsoft.KeyVault/vaults` | [2023-02-01] ||

## Parameters

**Required parameters**

|| Parameter | Type | Required | Default | Description ||
|| :-- | :-- | :-- | :-- | :-- ||
|| `name` | string | Yes | - | Name of the Key Vault. ||
...
```

## 📖 Available Prompts

### 1. `get_bicep_module_details_prompt`

A prompt to get the details of a specific module.

**Parameters:**

- `module_name` (required): The name of the module.

**Example Usage:**

```text
"Get details for the 'keyvault' module"
```

### 2. `suggest_bicep_module_for_service_prompt`

A prompt to suggest a module for a specific Azure service.

**Parameters:**

- `azure_service` (required): The Azure service to find a module for.

**Example Usage:**

```text
"Suggest a Bicep module for 'Azure Key Vault'"
```

## 💡 Usage Examples

### Search for modules

```text
"Find all Bicep modules for storage"
"List Bicep modules for Key Vault"
"Show me networking modules"
```

### Get module current version

```text
"What is the current version of the storage account module?"
"Show me the version for the key vault module"
```

**Note:** Currently returns the current version from the module's `version.json` file. Future implementation will include historical versions from GitHub tags/releases.

### Explore module details

```text
"Show me the parameters for the keyvault module"
"What resources does the virtual network module deploy?"
"Get usage examples for the storage account module"
```

### Combined workflows

```text
"Find the storage account module and show me its parameters"
"I need to deploy a key vault - find the module and explain its parameters"
"Search for virtual network modules and show me usage examples"
```

## 🔍 How It Works

### Module Discovery

1. Reads the private GitHub repository structure
2. Filters entries to directories under `modules/`
3. Applies intelligent search matching:
   - Normalizes search terms (lowercase, hyphenated, compact)
   - Matches any token from multi-word queries
   - Returns all matching modules

### Version Retrieval

1. For each matching module, reads the `version.json` file
2. Decodes the current semantic version from the file
3. Returns that version together with module metadata

### Documentation Extraction

1. Converts GitHub tree URLs to raw content URLs
2. Fetches README.md content from the private repository
3. Extracts relevant sections using regex patterns:
   - Resource Types tables
   - Parameters documentation
   - Usage examples with large parameter sets

### Publishing Workflow

The CI and release workflows handle all publishing scenarios:

**Pre-release from feature branch:**
```
git push origin feature/new-auth
→ CI workflow triggered
→ Docker version: 0.3.0.20261015.1
→ Publish Docker image to GitHub Packages only
→ No GitHub Release
```

**Official release from main:**
```
git push origin main
→ CI workflow triggered
→ Docker version: 0.3.0
→ Publish Docker image to GitHub Packages (0.3.0 + latest)
→ Release workflow triggered
→ Create Git tag mcp/v0.3.0 and GitHub Release
→ Publish to PyPI
```

**Testing pre-release:**
```bash
docker pull ghcr.io/xtratuscloud/cloud-bicep-mcp-server:0.3.0.20261015.1
docker run --env-file .env -p 8080:8080 <image>
```

**Merge to main (after testing):**
```
git checkout main
git merge feature/new-auth
git push origin main
→ Workflow triggered
→ Version: v0.3.0
→ Official release created
```

## 🧪 Testing

The project includes a comprehensive test suite to ensure code quality and catch issues before release.

### Running Tests

```powershell
# Install dev dependencies
poetry install --with dev

# Run all tests with coverage
poe test

# Run linting
poe lint
```

### Running Tests Manually

```powershell
# Run all tests
poetry run pytest

# Run tests with verbose output
poetry run pytest -v
```

### Running Tests with Coverage

```powershell
poetry run pytest --cov=. --cov-report=html --cov-report=term
```

This will:
- Run all tests with coverage tracking
- Generate an HTML coverage report in `htmlcov/` directory
- Print coverage summary to the terminal

Open the HTML report:
```powershell
# Windows
start htmlcov/index.html

# macOS/Linux
open htmlcov/index.html
```

### What the Tests Check

The test suite validates:
- Distribution tests ensure required files are included in the wheel
- Authentication tests validate GitHub header formatting and token handling
- Server tests validate MCP server functionality (currently disabled due to MCP version compatibility)

## 🔧 Available Tools

### `list_bicep_modules`

List all Cloud Bicep modules. Returns a lightweight, full module inventory to keep the response small.

**Parameters:** None.

**Returns:** JSON array with minimal module information per module:
- `name`: Module name
- `displayName`: Display name from metadata
- `moduleReference`: Bicep module reference in the registry (`br:<registry>/<name>:<version>` — includes the current version)

**Example:**
```json
{
  "name": "keyvault",
  "displayName": "Key Vault",
  "moduleReference": "br:yourregistry.azurecr.io/bicep/modules/keyvault:1.0.0"
}
```

### `search_bicep_modules`

Search Cloud Bicep modules by name, Azure resource type or description. Returns complete module information for the matching modules.

**Parameters:**
- `search_term` (required): Term to search for. Matches module name, display name, canonical Azure resource type and description (case-insensitive).

**Returns:** JSON with the matching modules, including `name`, `displayName`, `description`, `currentVersion`, `canonicalType`, `owners`, `documentation` and `moduleReference`.

**Example:**
```text
"Find Bicep modules for key vault"
"Search modules with resource type Microsoft.Storage/storageAccounts"
```

### `scrape_bicep_module_details`

Get detailed information about a specific module from its README.

**Parameters:**
- `url` (required): GitHub URL of the module

**Returns:** Markdown with:
- Module Reference (Bicep module reference in the registry)
- Resource Types (table with API versions)
- Parameters (required and optional with types and descriptions)
- Outputs (module outputs)
- Usage Examples

**Example:**
```bash
# Input
{"url": "https://github.com/xtratuscloud/cloud_bicep-registry-modules/tree/main/modules/keyvault"}

# Output (Markdown)
## Resource Types

| Resource Type | API Version |
| :-- | :-- |
| `Microsoft.KeyVault/vaults` | [2023-02-01] |

## Parameters

**Required parameters**

| Parameter | Type | Required | Default | Description |
| :-- | :-- | :-- | :-- | :-- |
| `name` | string | Yes | - | Name of the Key Vault. |

...
```

## 💬 Available Prompts

### `get_bicep_module_details_prompt`

Help get details of a specific module.

**Parameters:**
- `module_name` (required): Module name

### `suggest_bicep_module_for_service_prompt`

Suggest a Bicep module for an Azure service.

**Parameters:**
- `azure_service` (required): Azure service name

## 🔧 Troubleshooting

### Common Issues

1. **"Failed to fetch modules" error**
   - Check internet connectivity
   - Verify access to the private GitHub repository
   - Check that the GitHub token is valid and has the `repo` scope
   - Check for firewall/proxy restrictions

2. **"Could not fetch README.md" error**
   - Verify the GitHub URL format is correct
   - Ensure the module documentation exists in the repository
   - Check internet connectivity to `raw.githubusercontent.com`
   - Verify authentication credentials are valid

3. **No modules found for search query**
   - Try different search terms (e.g., "storage" instead of "storage-account")
   - Use partial names (e.g., "key" to find "key-vault")
   - Search against the display name or Azure resource type (e.g., "key vault", "Microsoft.Storage/storageAccounts")
   - Use `list_bicep_modules` to get the full inventory first

4. **Server won't start in Claude Desktop**
   - Verify Python 3.13 or newer is installed
   - Check that Poetry is properly installed
   - Ensure the path in `claude_desktop_config.json` is correct
   - Review Claude Desktop logs for detailed error messages

5. **Authentication errors (401)**
   - Ensure the Authorization header is provided
   - Verify the GitHub token is valid
   - Review the `.env` file configuration

## 🚀 Future Enhancements

Planned features for future releases:

### 1. Get Module Changelog

Get the change history of a module by reading its `CHANGELOG.md`.

**Use case:** See what has changed between versions before updating.

**Implementation:** Read and parse the `CHANGELOG.md` file from the module directory.

### 2. Generate Basic Usage Example

Generate a minimal, functional usage example for a module.

**Use case:** Help new users get started quickly with a module.

**Implementation:** Analyze required parameters and generate a Bicep code example with realistic values.

## 📝 Development

### Project Structure

```
mcp/
├── server.py              # Main MCP server implementation
├── config.py              # Configuration management
├── auth.py                # Authentication utilities
├── pyproject.toml        # Project configuration (Poetry)
├── Dockerfile            # Docker configuration
├── .env.example          # Environment variables example
├── .gitignore            # Git ignore rules
├── tests/                # Test suite
│   ├── __init__.py
│   ├── test_auth.py
│   ├── test_distribution.py
│   └── test_server.py
└── README.md             # This file
```

### Adding New Tools

To add a new tool to the MCP server:

1. Add the tool function in `server.py` with the `@mcp.tool()` decorator
2. Document the tool in the "Available Tools" section of this README
3. Add tests in `tests/test_server.py` (once MCP compatibility is resolved)

### Adding New Prompts

To add a new prompt to the MCP server:

1. Add the prompt using `@mcp.prompt()` decorator in `server.py`
2. Document the prompt in the "Available Prompts" section of this README

## 🤝 Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request

## 📄 License

MIT License - see LICENSE file for details

## 🔗 Links

- [Cloud Bicep Modules Repository](https://github.com/xtratuscloud/cloud_bicep-registry-modules)
- [Model Context Protocol](https://modelcontextprotocol.io)
- [MCP Documentation](https://modelcontextprotocol.io/docs)

---

*Have a suggestion for a new feature? Open an issue or contribute a pull request!*
