Skip to main content
Glama
README.md
# DCI MCP Server

This project provides a Model Context Protocol (MCP) server adapted for the [DCI API](https://doc.distributed-ci.io/dci-control-server/docs/API/).
It allows AI models to interact with [DCI](https://doc.distributed-ci.io/) for comprehensive data extraction about DCI jobs, components, topics and files.

## Features

- šŸš€ **FastAPI**: Built on a modern, fast web framework
- šŸ¤– **MCP**: Implements the Model Context Protocol for AI integration
- šŸ” **Comprehensive DCI API**: Full access to DCI components, jobs, files, pipelines, products, teams, and topics
- šŸ”§ **Smart PR Detection**: Advanced PR build finder that analyzes job URLs and metadata
- šŸ” **DCI Integration**: Native DCI API support with authentication
- šŸ“ **Easy Configuration**: Support for .env files for simple setup
- āœ… **Code Quality**: Comprehensive pre-commit checks and linting
- šŸ“Š **Google Drive Integration**: Convert DCI reports to Google Docs with rich formatting
- šŸŽ« **Jira Integration**: Collect comprehensive ticket data from Jira with comments and changelog
- šŸ™ **GitHub Integration**: Search issues and pull requests using GitHub's powerful search API
- šŸ”“ **Red Hat Support Case Integration**: Access Red Hat support case data from the Customer Portal

## Installation

```bash
# Clone the repository
git clone https://github.com/redhat-community-ai-tools/dci-mcp-server
cd dci-mcp-server

# Install dependencies
uv sync

# Activate virtual environment
source .venv/bin/activate
```

### Configuration

The server supports multiple ways to configure DCI authentication:

Copy the example file and customize it:

```bash
cp env.example .env
# Edit .env with your DCI credentials
```

Example `.env` file:

```bash
# Method 1: API Key Authentication
DCI_CLIENT_ID=<client_type>/<client_id>
DCI_API_SECRET=<api_secret>

# Method 2: User ID/Password (alternative to API key)
# DCI_LOGIN=foo
# DCI_PASSWORD=bar

# Google Drive Integration (optional)
# GOOGLE_CREDENTIALS_PATH=credentials.json
# GOOGLE_TOKEN_PATH=token.json
```

### MCP Configuration

#### Cursor IDE (stdio transport)

Add to your `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "dci": {
      "command": "uv",
      "args": ["run", "/path/to/dci-mcp-server/.venv/bin/python", "/path/to/dci-mcp-server/main.py"],
      "description": "MCP server for DCI integration"
    }
  }
}
```

#### Claude Desktop (`~/.claude.json`)

```json
{
  "mcpServers": {
    "dci": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/dci-mcp-server", "main.py"],
      "env": {
        "DCI_CLIENT_ID": "your-client-id",
        "DCI_API_SECRET": "your-secret",
        "DCI_CS_URL": "https://api.distributed-ci.io"
      }
    }
  }
}
```

#### Claude CLI (`~/.claude.json`)

- close the claude cli
- include the block above in the ~/.claude.json file
- start a claude session from the /path/to/dci-mcp-server/ directory
- verify MCP is connected with /mcp


#### Web-based Integration (SSE transport)

For web applications or services that need HTTP-based communication:

```json
{
  "mcpServers": {
    "dci": {
      "url": "http://0.0.0.0:8000/sse/",
      "description": "MCP server for DCI integration with direct SSE",
      "env": {
        "MCP_TRANSPORT": "sse"
      }
    }
  }
}
```

**SSE Endpoint**: `http://0.0.0.0:8000/sse/`

> **Note**: Make sure to start the SSE server separately with `MCP_TRANSPORT=sse uv run main.py` before using this configuration.

## Prompts

You can then use [prompts](PROMPTS.md) to explore the DCI data.

There are also parameterized prompts defined in the MCP server:

- `/dci/rca <job id>` conducts a Root Cause Analysis of a failing DCI job. The prompt is **dynamic**: it pre-fetches job metadata and files, classifies the job type (ACM, ZTP, upgrade, day2, SNO, or standard), and tailors the guidance and file priority list accordingly. Downloads files to `/tmp/dci/<job id>/` and generates a report at `/tmp/dci/rca-<job id>.md`.
- `/dci/weekly <team name/id or remoteci name/id>` conducts a report for the last 7 days stored at `/tmp/dci`.
- `/dci/biweekly <team name/id or remoteci name/id>` conducts a report for the last 14 days stored at `/tmp/dci`.
- `/dci/quarterly <remoteci name/id>` conducts a comprehensive quarterly analysis (last 3 months) with statistics about pipelines, topics, failure rates, trends, and component usage. Uses pagination and caching to handle large datasets. Report stored at `/tmp/dci/<remoteci>/quarterly/<date-range>/report.md`.
- `/dci/support_case_report <case number>` generates a comprehensive support case report. Fetches the support case details, follows all linked Jira tickets (including transitive links), gathers associated PRs/MRs with diffs, and checks for related errata/advisories. The report includes an executive summary, root cause analysis, timeline, code changes classification (short-term vs long-term), corrective measures, and next steps. Report stored at `/tmp/dci/support-case-<case_number>-<YYYY-MM-DD>.md`.

### Debugging Prompts

You can render any prompt outside the MCP server for debugging:

```bash
# List available prompts
uv run python -m mcp_server.prompts --list

# Render a prompt with its parameters
uv run python -m mcp_server.prompts rca dci_job_id=<job-id>
uv run python -m mcp_server.prompts weekly subject=<team-name>

# Also available as a standalone command
uv run dci-render-prompt rca dci_job_id=<job-id>
```

## Google Drive Integration

The server includes Google Drive integration to convert DCI reports and markdown content to Google Docs with rich formatting support.

### Features
- šŸ“„ **Markdown to Google Docs**: Convert markdown content to properly formatted Google Docs
- šŸ“Š **DCI Report Conversion**: Specialized tools for converting DCI weekly/biweekly reports
- šŸŽØ **Rich Formatting**: Support for tables, code blocks, headers, lists, and links
- šŸ” **OAuth2 Authentication**: Secure authentication with Google Drive API
- šŸ“ **Folder Organization**: Option to organize documents in specific Google Drive folders

### Setup
To use Google Drive features, follow the [Google Drive Setup Guide](GOOGLE_DRIVE_SETUP.md) for detailed configuration instructions.

**Quick Setup:**
1. Set up Google Cloud Project and enable Google Drive API
2. Download OAuth2 credentials and save as `credentials.json`
3. Initialize the service: `uv run python -c "from mcp_server.services.google_drive_service import GoogleDriveService; GoogleDriveService()"`
4. Complete browser authentication when prompted

### Usage Examples
```python
# Convert a DCI report to Google Doc in a specific folder by name
result = await convert_dci_report_to_google_doc(
    report_path="/tmp/dci/the_weekly_report_2025-09-09.md",
    doc_title="The Weekly Report - September 2025",
    folder_name="DCI Reports"
)

# Create a Google Doc from markdown content in a folder by ID
result = await create_google_doc_from_markdown(
    markdown_content="# My Report\n\nThis is a **test** document.",
    doc_title="My Custom Report",
    folder_id="1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
)

# Create a Google Doc from a file in a folder by name
result = await create_google_doc_from_file(
    file_path="/path/to/report.md",
    doc_title="My Report",
    folder_name="Project Documents"
)
```

## Jira Integration

The server includes Jira integration to collect comprehensive ticket data from Red Hat Jira, including comments and changelog information.

### Features
- šŸŽ« **Ticket Data Collection**: Retrieve comprehensive ticket information including summary, description, status, and dates
- šŸ’¬ **Comments Analysis**: Get up to 50 recent comments with author and timestamp information
- šŸ“ **Changelog Tracking**: Access complete ticket history and field changes
- šŸ” **JQL Search**: Search tickets using Jira Query Language (JQL)
- šŸ“Š **Project Information**: Get project details and metadata
- šŸ”— **DCI Integration**: Seamlessly extract Jira tickets from DCI job comments
- āœļø **Write Operations** (opt-in): Create tickets, update fields, add comments, and transition status

### Setup
To use Jira features, follow the [Jira Setup Guide](JIRA_SETUP.md) for detailed configuration instructions.

**Quick Setup:**
1. Get your Jira API token from [https://id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens)
2. Set environment variables in your `.env` file:
   ```bash
   JIRA_API_TOKEN=your_jira_api_token_here
   JIRA_EMAIL=you@redhat.com
   JIRA_URL=https://redhat.atlassian.net
   # Optional: enable write operations (create/update tickets, add comments)
   JIRA_WRITE_ENABLED=true
   ```

### Usage Examples
```python
# Get comprehensive ticket data with comments
ticket_data = await get_jira_ticket("CILAB-1234", max_comments=10)

# Search for tickets using JQL
open_tickets = await search_jira_tickets("project = CILAB AND status = Open")

# Get project information
project_info = await get_jira_project_info("CILAB")

# Extract Jira tickets from DCI job comments
jobs_with_tickets = await search_dci_jobs("comment=~'.*CILAB.*'")
for job in jobs_with_tickets:
    if job.get('comment'):
        ticket_data = await get_jira_ticket(job['comment'])
```

## GitHub Integration

The server includes GitHub integration to search for issues and pull requests and retrieve detailed information about them.

### Features
- šŸ” **Issue & PR Search**: Search using GitHub's powerful query syntax
- šŸ“Š **Comprehensive Data**: Get detailed information including comments, labels, assignees, and more
- šŸ”€ **Pull Request Metadata**: Access PR-specific data like merge status, branch info, and file changes
- šŸ“ˆ **Repository Information**: Retrieve repository metadata and statistics
- šŸ” **Token Authentication**: Secure authentication with GitHub personal access tokens

### Setup

**Quick Setup:**
1. Get your GitHub personal access token from [https://github.com/settings/tokens](https://github.com/settings/tokens)
2. Create a new token (classic) with `repo` scope (for private repos) or `public_repo` (for public repos only)
3. Set environment variable in your `.env` file:
   ```bash
   GITHUB_TOKEN=your_github_token_here
   ```

## GitLab Integration

The server includes GitLab integration to search for issues, merge requests, and retrieve diffs and project information.

### Setup

**Quick Setup:**
1. Create a personal access token in your GitLab instance (User Settings → Access Tokens) with `read_api` scope
2. Set environment variables in your `.env` file:
   ```bash
   GITLAB_TOKEN=your_gitlab_token_here
   GITLAB_URL=https://gitlab.cee.redhat.com
   ```

**SSL verification** — for internal GitLab instances with corporate CA certificates, point `GITLAB_SSL_VERIFY` to your CA bundle instead of disabling verification:
   ```bash
   GITLAB_SSL_VERIFY=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
   ```

**Host allowlist** — the `gitlab_url` tool parameter is LLM-controlled. To prevent your token from being sent to unauthorized hosts, only the host from `GITLAB_URL` is allowed by default. To allow additional hosts:
   ```bash
   GITLAB_ALLOWED_HOSTS=gitlab.com,gitlab.cee.redhat.com
   ```

## Red Hat Support Case Integration

The server includes Red Hat Support Case integration to retrieve case data from the Red Hat Customer Portal.

### Features
- šŸ“‹ **Case Data Retrieval**: Get comprehensive case information including summary, status, severity, and product details
- šŸ’¬ **Comments**: Access case comments and communication history
- šŸ› **Linked Bugs**: View Bugzilla bugs linked to the case
- šŸ“¢ **Errata/Advisory Details**: Retrieve errata information including CVEs, affected products, and references
- šŸ” **Offline Token Authentication**: Secure authentication using Red Hat API offline tokens

### Setup

**Quick Setup:**
1. Get your offline token from [https://access.redhat.com/management/api](https://access.redhat.com/management/api)
2. Set environment variable in your `.env` file:
   ```bash
   OFFLINE_TOKEN=your_offline_token_here
   ```

## Available Tools exposed by the MCP server

The server provides tools for interacting with DCI API components:

### Component Tools

- `query_dci_components(query, limit, offset, sort, fields)`: Query components with advanced query language and pagination

### Date Tools

Enabled by default. Set `DATE_TOOLS_ENABLED=false` to disable.

- `today()`: Returns today's date in YYYY-MM-DD format.
- `now()`: Returns current date and time in DCI compatible format (GMT).

### Job Tools

- `search_dci_jobs(query, sort, limit, offset, fields)`: Search jobs with advanced query language and pagination

### File Tools

- `download_dci_file(job_id, file_id, output_path)`: Download a file to local path

### Google Drive Tools

- `create_google_doc_from_markdown(markdown_content, doc_title, folder_id, folder_name)`: Create a Google Doc from markdown content
- `create_google_doc_from_file(file_path, doc_title, folder_id, folder_name)`: Create a Google Doc from a markdown file
- `convert_dci_report_to_google_doc(report_path, doc_title, folder_id, folder_name)`: Convert a DCI report to Google Doc
- `list_google_docs(query, max_results)`: List Google Docs in your Drive

**Note**: For folder placement, you can use either `folder_id` (exact folder ID) or `folder_name` (searches for folder by name). Do not use both parameters together.

### Jira Tools

- `get_jira_ticket(ticket_key, max_comments)`: Get comprehensive ticket data including comments and changelog
- `search_jira_tickets(jql, max_results)`: Search tickets using JQL (Jira Query Language)
- `get_jira_project_info(project_key)`: Get project information and metadata
- `search_jira_child_tickets(parent_jql, child_jql, ...)`: Traverse a 2-level Jira hierarchy (e.g. TELCOSTRAT → Epics → Stories) in a single call, returning leaf tickets with full ancestry info

**Note**: Jira tools require `JIRA_API_TOKEN` environment variable to be set.

### Jira Write Tools

- `create_jira_ticket(project_key, summary, ...)`: Create a new Jira ticket with optional description, issue type, priority, labels, components, and assignee
- `update_jira_ticket(ticket_key, ...)`: Update ticket fields (summary, description, priority, labels, components, assignee) or transition status
- `add_jira_comment(ticket_key, body)`: Add a comment to a ticket
- `add_jira_issue_link(ticket_key, target_ticket_key, link_type)`: Create a typed link between two tickets (e.g., "Blocks", "Clones", "Duplicates"). Use `list_jira_issue_link_types` to discover available link types
- `add_jira_weblink(ticket_key, url, title)`: Add a web/remote link to a ticket
- `list_jira_transitions(ticket_key)`: List available workflow transitions for a ticket
- `list_jira_issue_link_types()`: List available issue link types with their inward/outward descriptions

**Note**: Jira write tools require both `JIRA_API_TOKEN` and `JIRA_WRITE_ENABLED=true` environment variables.

### GitHub Tools

- `search_github_issues(query, max_results)`: Search issues and pull requests using GitHub search query syntax
- `get_github_issue(repo, issue_number, max_comments)`: Get comprehensive issue/PR data including comments and PR-specific information
- `get_github_repository_info(repo)`: Get repository information and statistics
- `get_github_pr_diff(repo, pull_number, max_files)`: Get the diff/patch for a pull request with per-file unified diffs
- `get_github_pr_checks(repo, pull_number)`: Get CI check runs and commit statuses for a pull request, including status, conclusion, and links to each CI job

**Note**: GitHub tools require `GITHUB_TOKEN` environment variable to be set.

### Support Case Tools

- `get_support_case(case_number)`: Get Red Hat support case data including comments and linked Bugzilla bugs
- `get_support_case_comments(case_number, start_date?, end_date?)`: Get comments for a case with optional date filtering
- `list_support_case_attachments(case_number)`: List attachment metadata for a case
- `get_errata(advisory_id)`: Get Red Hat errata/advisory details (RHSA, RHBA, RHEA)

**Note**: Support Case tools require `OFFLINE_TOKEN` environment variable to be set.

## Code Quality Checks

The project includes comprehensive code quality checks:

#### Manual Checks
```bash
# Run all checks
bash scripts/run-checks.sh

# Or run individual checks
./.venv/bin/python -m black --check .
./.venv/bin/python -m isort --check-only .
./.venv/bin/python -m ruff check .
./.venv/bin/python -m mypy mcp_server/
./.venv/bin/python -m bandit -r mcp_server/ -c pyproject.toml
```

#### Pre-commit Hooks (Optional)
```bash
# Install pre-commit hooks
./.venv/bin/python -m pre_commit install

# Run pre-commit on all files
./.venv/bin/python -m pre_commit run --all-files
```

## Development

### Project Structure

```
mcp_server/
ā”œā”€ā”€ config.py             # Configuration and authentication
ā”œā”€ā”€ main.py               # Server entry point
ā”œā”€ā”€ services/             # DCI API services
│   ā”œā”€ā”€ dci_base_service.py
│   ā”œā”€ā”€ dci_component_service.py
│   ā”œā”€ā”€ dci_job_service.py
│   ā”œā”€ā”€ dci_file_service.py
│   ā”œā”€ā”€ dci_log_service.py
│   ā”œā”€ā”€ dci_pipeline_service.py
│   ā”œā”€ā”€ dci_product_service.py
│   ā”œā”€ā”€ dci_team_service.py
│   ā”œā”€ā”€ dci_remoteci_service.py
│   ā”œā”€ā”€ dci_topic_service.py
│   ā”œā”€ā”€ google_drive_service.py
│   ā”œā”€ā”€ jira_service.py
│   ā”œā”€ā”€ github_service.py
│   └── support_case_service.py
ā”œā”€ā”€ prompts/              # Templatized prompts
│   ā”œā”€ā”€ prompts.py        # Prompt definitions and registration
│   ā”œā”€ā”€ render.py         # Render prompts outside MCP (library)
│   └── __main__.py       # CLI: python -m mcp_server.prompts
ā”œā”€ā”€ tools/                # MCP tools
│   ā”œā”€ā”€ component_tools.py
│   ā”œā”€ā”€ date_tools.py
│   ā”œā”€ā”€ job_tools.py
│   ā”œā”€ā”€ file_tools.py
│   ā”œā”€ā”€ google_drive_tools.py
│   ā”œā”€ā”€ jira_tools.py
│   ā”œā”€ā”€ jira_write_tools.py
│   ā”œā”€ā”€ github_tools.py
│   ā”œā”€ā”€ support_case_tools.py
│   └── log_tools.py
└── utils/                # Utility functions
    └── http_client.py
```

### Testing

```bash
# Run all checks (format, lint, tests + evals)
bash scripts/run-checks.sh

# Run evals only
uv run pytest -m eval -v

# Run evals with a different model
EVAL_MODEL=haiku uv run pytest -m eval -v
```

Eval tests use `claude -p` to verify that Claude selects the correct MCP tools for natural language prompts. Each eval case is automatically skipped if its required credentials (DCI, Jira, GitHub, etc.) are not configured in `.env`.

### Adding New Tools

1. Create a new service in `mcp_server/services/` if needed
2. Create a new tool file in `mcp_server/tools/`
3. Register the tools in `mcp_server/main.py`
4. Update this README with documentation

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: file download, time utilities, and querying different entities (components, remotecis, teams, jobs). No overlap or ambiguity between tool functions.

Naming Consistency3/5

Naming is inconsistent: 'now' and 'today' are standalone, while other tools use prefix patterns like 'query_dci_plural' or 'search_dci_jobs'. There are minor style differences (singular vs plural) and verb choice inconsistencies (query vs search).

Tool Count5/5

7 tools is well-scoped for a DCI server. It covers essential query operations and file download without being excessive or insufficient.

Completeness3/5

The tool set provides read-only queries and file download, but lacks any create, update, or delete operations. While likely intentional for a query-focused server, notable gaps exist in lifecycle coverage.

Maintenance

ActivityActive
ResponsivenessNo issues