Skip to main content
Glama

DCI MCP Server

This project provides a Model Context Protocol (MCP) server adapted for the DCI API. It allows AI models to interact with DCI 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

Related MCP server: ask-panda

Installation

# 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:

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

Example .env file:

# 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:

{
  "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)

{
  "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:

{
  "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 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:

# 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 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

# 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 for detailed configuration instructions.

Quick Setup:

  1. Get your Jira API token from https://id.atlassian.com/manage-profile/security/api-tokens

  2. Set environment variables in your .env file:

    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

# 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

  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:

    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:

    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:

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:

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

  2. Set environment variable in your .env file:

    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

# 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)

# 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

# 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

Available Tools

7 tools
download_dci_fileB

Download a DCI file to a local path.

Returns: JSON string with download status

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYesThe ID of the job associated with the file
file_idYesThe ID of the file to download
output_pathYesLocal path where to save the file. If not instructed otherwise, always ask to download to /tmp/dci/<dci job id>/.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It only mentions the return format but lacks details on file size limits, overwrite behavior, permissions, or error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise with only two lines: one for purpose and one for return. It is well-structured but could be slightly more front-loaded with the return note.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity with three parameters and an output schema, the description is minimally complete. It lacks details on error handling and specific behavioral expectations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% coverage with descriptions for all parameters. The description adds no additional parameter information beyond what the schema provides, so it meets the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Download a DCI file to a local path,' which is a specific verb and resource. It distinguishes itself from sibling tools, which are query and time tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives is provided. The purpose is clear, but the description does not include when-not-to-use or mention of prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

nowA

Get current date and time.

Returns: JSON string with current date and time in this format: "2025-09-12T21:47:02.908617"

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description clearly states the return format (JSON string with timestamp) and implies no side effects. Although no annotations are provided, the description is transparent about what the tool returns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with two sentences, no filler, and front-loads the purpose immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with an output schema, the description is complete: it defines the action and the exact return format. No additional context is necessary.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are no parameters, so the description does not need to add parameter-specific information. The schema coverage is 100%, and the description appropriately omits parameter details. Baseline 4 for zero parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Get current date and time' with a specific verb and resource. However, it does not differentiate from the sibling tool 'today', which likely serves a similar purpose, leading to slight ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus the sibling 'today'. For a simple tool, minimal guidance is acceptable, but the presence of a similar sibling necessitates some differentiation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_dci_componentsA

Lookup DCI components with an advanced query language.

Common queries:

  • List OCP/OpenShift components: eq(type,ocp) (filter by type, NOT by name)

  • List all components: ilike(name,%)

  • List GA OCP components: and(eq(type,ocp),contains(tags,build:ga))

The query language is based on this DSL:

eq(<field>,<value>) to lookup resources with a <field> having the value <value>.
IMPORTANT: Values must NOT be quoted. Use eq(type,ocp) not eq(type,'ocp').

You can use the comparison functions gt (greater than), ge (greater or equal),
lt (less than) or le (less or equal) using the same syntax as eq: <op>(<field>,<value>).

like(<field>,<value with percent>) and ilike(<field>,<value with percent>)
to lookup a field with a SQL glob like way. For example, to get the components
with a specific name pattern, use like(name,ocp-%).

contains(<field>,<value1>,...) and not_contains(<field>,<value1>,...)
to lookup elements in an array. This is useful mainly for tags.

and(<op1>(...),<op2>(...)), or(<op1>(...),<op2>(...)) and not(<op>) allow
to build nested boolean queries.

null(<field>) to lookup resources with a field having a NULL value.

Here are all the fields of a DCI component that can be used in the query:

- id: unique identifier

- name: name of the component

- type: type of the component. Use `eq(type,ocp)` to query OpenShift components (do NOT use name for this).

- team_id: The ID of the team that owns the component. Use the `query_dci_teams` tool to get it.

- released_at: The release timestamp. Use `today` tool to compute relative dates.

- topic_id: The ID of the topic associated with the component. Use the `query_dci_topics` tool to get it.

- state: The current state of the component (active, inactive, etc.).

- url: The URL of the component, if applicable.

- tags: list of tags associated with the component. For components of type ocp, it has a build status tag like `build:dev` (also called engineering candidate or ec), `build:candidate` (also called release candidate or rc), `build:ga` or `build:nightly`.

Counting Components: To get the total count of components matching a query, set limit=1 and read the count field in the _meta section of the response.

Example for counting components by type:

{
  "query": "eq(type,ocp)",
  "limit": 1,
  "offset": 0,
  "fields": []
}

This will return a response like:

{
  "components": [],
  "_meta": {"count": 150},
  ...
}

The total count is 150 components.

Returns: JSON string with list of components and pagination info

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYessearch criteria (e.g., eq(type,ocp) for OpenShift components, and(eq(type,ocp),contains(tags,build:ga)) for GA builds). To list all, use ilike(name,%)
sortNoSort criteria-created_at
limitNoMaximum number of results to return for pagination (default 20, max 200). Use limit=1 to get count from metadata.
offsetNoOffset for pagination
fieldsNoList of fields to return. Fields are the one listed in the query description and responses. Must be specified as a list of strings. If empty, no fields are returned.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It thoroughly explains the query language, supported fields, counting method, and return format. It does not mention auth or rate limits, but for a read-only lookup tool this is sufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections for common queries, DSL syntax, fields, and counting. It is front-loaded with the main purpose. While somewhat lengthy, every section serves a purpose and the structure aids readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (custom query language, multiple parameters, output schema present), the description is remarkably complete. It covers query syntax, all fields, examples for counting, and expected output structure. The output schema is described in text, making the tool self-contained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All 5 parameters have schema descriptions (100% coverage). The description adds significant value by explaining the query syntax, providing common examples, detailing field semantics, and illustrating the counting technique. It goes beyond the schema to clarify usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it is for looking up DCI components with an advanced query language. It provides specific examples like listing OCP components and all components, and distinguishes the tool from siblings by focusing on component-specific queries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description offers explicit guidance on when to use specific query patterns (e.g., using eq(type,ocp) instead of name for OpenShift components). It references other tools like query_dci_teams for field values, but does not provide explicit when-not-to-use or exhaustive alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_dci_remotecisA

Lookup DCI remotecis with an advanced query language.

Listing all remotecis: To list all remotecis, use ilike(name,%) as the query.

The query language is based on this DSL:

eq(<field>,<value>) to lookup resources with a <field> having the value <value>.
IMPORTANT: Values must NOT be quoted. Use eq(name,dallas) not eq(name,'dallas').

You can use the comparison functions gt (greater than), ge (greater or equal),
lt (less than) or le (less or equal) using the same syntax as eq: <op>(<field>,<value>).

like(<field>,<value with percent>) and ilike(<field>,<value with percent>)
to lookup a field with a SQL glob like way. For example, to get the remotecis
with a specific name pattern, use like(name,dallas-%).

contains(<field>,<value1>,...) and not_contains(<field>,<value1>,...)
to lookup elements in an array. This is useful mainly for tags.

and(<op1>(...),<op2>(...)), or(<op1>(...),<op2>(...)) and not(<op>) allow
to build nested boolean queries.

null(<field>) to lookup resources with a field having a NULL value.

Here are all the fields of a DCI remoteci that can be used in the query:

- id: unique identifier

- name: name of the remoteci (lab)

- created_at: The creation timestamp. Use `today` tool to compute relative dates.

- updated_at: The last update timestamp. Use `today` tool to compute relative dates.

- tags: list of tags associated with the remoteci.

Listing all remotecis: To list all remotecis, use ilike(name,%) as the query.

Counting Remotecis: To get the total count of remotecis matching a query, set limit=1 and read the count field in the _meta section of the response.

Example for counting remotecis by name:

{
  "query": "eq(name,dallas)",
  "limit": 1,
  "offset": 0,
  "fields": []
}

This will return a response like:

{
  "remotecis": [],
  "_meta": {"count": 2},
  ...
}

The total count is 2 remotecis.

Returns: JSON string with list of remotecis and pagination info

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYessearch criteria (e.g., and(ilike(name,dallas),contains(tags,ga))). To list all, use ilike(name,%)
sortNoSort criteria-created_at
limitNoMaximum number of results to return for pagination (default 20, max 200). Use limit=1 to get count from metadata.
offsetNoOffset for pagination
fieldsNoList of fields to return. Fields are the one listed in the query description and responses. Must be specified as a list of strings. If empty, no fields are returned.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must handle behavioral disclosure. It explains the query syntax, fields, and output format (JSON with list and _meta). It doesn't mention authentication or error handling, but for a read-oriented query tool, this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately long for a complex query tool, well-structured with sections, examples, and bullet points. Every sentence adds value, and the most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (DSL, pagination, sorting, counting) and the presence of an output schema, the description covers all essential aspects: query language, fields, parameters, examples, and output format. It is complete for an agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already describes parameter types and defaults. The description adds significant value by explaining the query language, field usage, and providing examples, enriching parameter semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Lookup DCI remotecis with an advanced query language,' clearly stating the verb and resource. It differentiates from sibling tools like query_dci_components by focusing specifically on remotecis.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit examples for listing all remotecis, counting, and using the DSL. While it doesn't explicitly say when not to use it or compare to siblings, it gives clear context for its use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_dci_teamsA

Lookup DCI teams with an advanced query language.

Listing all teams: To list all teams, use ilike(name,%) as the query.

The query language is based on this DSL:

eq(<field>,<value>) to lookup resources with a <field> having the value <value>.
IMPORTANT: Values must NOT be quoted. Use eq(name,DCI) not eq(name,'DCI').

You can use the comparison functions gt (greater than), ge (greater or equal),
lt (less than) or le (less or equal) using the same syntax as eq: <op>(<field>,<value>).

like(<field>,<value with percent>) and ilike(<field>,<value with percent>)
to lookup a field with a SQL glob with at least one % character. For example, to get the teams
with a specific name pattern, use like(name,%Name%).

contains(<field>,<value1>,...) and not_contains(<field>,<value1>,...)
to lookup elements in an array. This is useful mainly for tags.

and(<op1>(...),<op2>(...)), or(<op1>(...),<op2>(...)) and not(<op>) allow
to build nested boolean queries.

null(<field>) to lookup resources with a field having a NULL value.

Here are all the fields of a DCI team that can be used in the query:

- id: unique identifier

- name: name of the team

- created_at: The creation timestamp. Use `today` tool to compute relative dates.

- updated_at: The last update timestamp. Use `today` tool to compute relative dates.

- tags: list of tags associated with the team.

Listing all teams: To list all teams, use ilike(name,%) as the query.

Counting Teams: To get the total count of teams matching a query, set limit=1 and read the count field in the _meta section of the response.

Example for counting teams by name:

{
  "query": "eq(name,DCI)",
  "limit": 1,
  "offset": 0,
  "fields": []
}

This will return a response like:

{
  "teams": [],
  "_meta": {"count": 10},
  ...
}

The total count is 10 teams.

Returns: JSON string with list of teams and pagination info

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYessearch criteria (e.g., and(ilike(name,qa),contains(tags,ga))). To list all, use ilike(name,%)
sortNoSort criteria-created_at
limitNoMaximum number of results to return for pagination (default 20, max 200). Use limit=1 to get count from metadata.
offsetNoOffset for pagination
fieldsNoList of fields to return. Fields are the one listed in the query description and responses. Must be specified as a list of strings. If empty, no fields are returned.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully carries the burden. It discloses the return format (JSON with list and pagination), the behavior of the query DSL (including the important note that values must not be quoted), how fields parameter works (empty returns no fields), and how to count. This is highly transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a summary, DSL explanation, field list, and examples. It is front-loaded. However, there is slight repetition (listing all teams mentioned twice) and it is fairly verbose, which prevents a perfect score. Nevertheless, every section adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of the tool (custom query DSL, pagination, counting) and the presence of an output schema (implied), the description covers everything needed: query syntax, list of queryable fields, counting method, pagination parameters, and a complete example. No gaps are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, baseline 3. The description adds significant value beyond the schema: it explains the query language, how limit is used for counting, the effect of fields being empty, sorting defaults, and provides examples. This greatly enhances parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Lookup DCI teams with an advanced query language.' It specifies the resource (DCI teams) and the action (lookup/query). Among sibling tools, it is the only one for querying teams, so it effectively distinguishes itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides extensive usage guidelines: how to list all teams using ilike(name,%), how to count teams via limit=1 and reading _meta.count, details on the query DSL with examples, and pagination. It covers when and how to use the tool comprehensively.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_dci_jobsA

Search DCI (Distributed CI) job documents from Elasticsearch.

DCI jobs represent CI/CD pipeline executions that test software components (like OpenShift, storage solutions, etc.) across different environments.

āš ļø COMMON MISTAKES TO AVOID

1. ALWAYS wrap conditions in parentheses - CRITICAL RULE

Each condition MUST be wrapped in parentheses. When combining conditions with AND/OR, add EXTRA parentheses to group them.

Single condition:

  • āŒ status='failure' → INVALID (no parentheses)

  • āœ… (status='failure') → VALID (wrapped)

Two conditions (AND/OR):

  • āŒ (status='failure') and (tags in ['daily']) → INVALID (missing outer parentheses)

  • āœ… ((status='failure') and (tags in ['daily'])) → VALID (each condition + outer grouping)

Three or more conditions:

  • āŒ ((status='failure') and (created_at>='2024-01-01') and (duration>=1000)) → MAY FAIL

  • āœ… (((status='failure') and (created_at>='2024-01-01')) and (duration>=1000)) → VALID (proper grouping)

  • āœ… (((tests.testsuites.testcases.action='failure') and (nodes.hardware.cpu_vendor='Intel')) and (created_at>='2024-01-01')) → VALID (complex nested fields)

Rule of thumb: Count your conditions. If N conditions, you need N pairs of parentheses PLUS (N-1) grouping pairs.

  • 1 condition = 1 pair: (field='value')

  • 2 conditions = 3 pairs: ((cond1) and (cond2))

  • 3 conditions = 5 pairs: (((cond1) and (cond2)) and (cond3))

2. NEVER use = for dates

  • āŒ created_at='2024-01-15' → INVALID

  • āœ… (created_at>='2024-01-15') → VALID for "since Jan 15"

  • āœ… ((created_at>='2024-01-15') and (created_at<='2024-01-20')) → VALID for period

3. Use in for lists, not =

  • āŒ status='failure' or status='error' → Works but verbose

  • āœ… (status in ['failure', 'error']) → BETTER

  • āŒ tags='daily' → INVALID

  • āœ… (tags in ['daily']) → VALID

4. Multiple components = separate conditions with AND

  • āŒ (components.type in ['ocp', 'storage']) → Finds jobs with OCP OR storage

  • āœ… (((components.type='ocp') and (components.version='4.19.0')) and ((components.type='storage') and (components.name='ceph'))) → Finds jobs with OCP 4.19.0 AND Ceph storage

5. Specify necessary fields

  • āŒ fields=[] → No data returned (only metadata)

  • āœ… fields=['id', 'status', 'created_at', 'components.name'] → Essential data

  • šŸ’” Use dot notation for nested fields: components.name, tests.testsuites.testcases.action

6. Large results = save to file

  • āŒ limit=200 without __save_to_file → Context overload

  • āœ… limit=200, __save_to_file='/tmp/jobs.json' → Saves context

Query Language (DSL)

Basic Operators:

  • field='value' - exact match

  • field!=value - not equal

  • field>value, field>=value, field<value, field<=value - comparisons

  • field=~'regex' - regex match

List Operators:

  • field in ['value1', 'value2'] - value in list

  • field not_in ['value1', 'value2'] - value not in list

Logical Operators:

  • and, or - combine criteria

  • () - group criteria with parentheses (ALWAYS REQUIRED)

Simple Examples (1-2 conditions):

  • Single condition: (remoteci.name='telco-cilab-bos2')

  • Failing daily jobs: ((tags in ['daily']) and (status in ['failure', 'error']))

  • OpenShift 4.19 jobs: ((components.type='ocp') and (components.version='4.19.0'))

  • Jobs with workarounds: ((keys_values.key='workarounds') and (keys_values.value>0))

  • Date range: ((created_at>='2024-09-16') and (created_at<='2025-09-20'))

Complex Examples (3+ conditions - note the extra grouping parentheses):

  • Success jobs in date range: (((status='success') and (created_at>='2024-01-01')) and (duration>=1000))

  • Failed test with specific firmware: (((tests.testsuites.testcases.name=~'PTP.*') and (tests.testsuites.testcases.action='failure')) and (nodes.hardware.network_interfaces.firmware_version='2.50'))

  • Multiple criteria: (((tags in ['daily']) and (status='failure')) and (created_at>='2024-01-01'))

  • Nested fields combo: (((components.type='ocp') and (components.version=~'4.1?.*')) and (team.name='my-team'))

Available Fields

Basic Job Information:

  • id: unique job identifier

  • name: job name (just a label, don't over-interpret)

  • status: current state (new, running, success, failure, error, killed)

  • state: internal job state

  • status_reason: explanation for failed jobs (free text)

  • comment: free text, may contain JIRA ticket numbers

  • configuration: job configuration (free text)

  • duration: execution time in seconds

Timestamps:

  • created_at: job creation time

  • updated_at: last update time

  • Use today or now tools for relative dates

  • Use >, <, >=, <= operators (NEVER use = for dates)

  • Format: 2025-09-12 or 2025-09-12T21:47:02.908617

  • For a period: ((created_at>='2024-09-16') and (created_at<='2025-09-20'))

Components & Software:

  • components.(type, name, version, tags): list of software components tested

  • Component types: ocp (OpenShift), storage, cnf, hwcert

  • Build tags: build:ga (GA release), build:candidate (RC), build:dev (EC), build:nightly

  • Example: ((components.type='ocp') and (components.version='4.19.0'))

  • Multiple components: (((components.type='ocp') and (components.version='4.19.0')) and ((components.type='storage') and (components.name='ceph')))

Infrastructure:

  • remoteci.(name, id): lab/environment where job ran (prefer remoteci.name)

  • product.(name, id): product being tested (prefer product.name)

  • team.(name, id): team owning the job (prefer team.name)

  • topic.(name, id): topic/category (prefer topic.name)

Pipeline Information:

  • pipeline.(name, id): pipeline details

  • previous_job_id: previous job in same pipeline

Tags & Classification:

  • tags: list of tags for categorization (ALWAYS use in operator)

  • Common tags:

  • daily - daily jobs

  • agent:openshift - OpenShift/OCP install jobs

  • agent:openshift-app - OpenShift/OCP application/workload jobs

  • connected - connected mode jobs

  • disconnected - disconnected mode jobs

  • use-dci-container - containerized jobs

  • install_type:ipi - IPI install

  • install_type:abi - Agent-Based Installer

  • install_type:acm - ACM install

  • install_type:sno - Single Node OpenShift

  • install_type:upi - UPI install

Files & Artifacts:

  • files.(id, name, size, state, mime): job artifacts

  • Use download_dci_file tool to download files

  • Example: Get file IDs with fields=['id', 'files.id', 'files.name'], then download

Metrics & Measurements:

  • keys_values.(key, value): job metrics

  • Common metrics: install_time (seconds), workarounds (count), test_count, failure_count

  • Query: ((keys_values.key='workarounds') and (keys_values.value>0))

Node Information:

  • nodes: list of nodes involved in the job

  • nodes.(node, role): hostname and role (sno, master, worker, control-plane)

  • nodes.kernel.(version, params): kernel details

  • nodes.hardware.system_(vendor, model, family, sku): system info

  • nodes.hardware.cpu_(model, vendor, sockets, total_cores, total_threads, frequency_mhz): CPU info

  • nodes.hardware.memory_(total_gb, dimm_count): memory info

  • nodes.hardware.bios_(vendor, version, date, type): BIOS info

  • nodes.hardware.(network_interfaces, pci_accelerators, pci_network_controllers, storage_devices): device lists

  • Example: ((nodes.role='sno') and (nodes.hardware.cpu_vendor='Intel'))

Test Results (3-level nested structure):

  • tests: complex nested structure with test results

  • Structure:

  • Level 1: tests.(file_id, name) - test file/suite files

  • Level 2: tests.testsuites.(name, testcases) - test suites

  • Level 3: tests.testsuites.testcases.(name, action, classname, time, type, properties, message, stdout, stderr) - individual test cases

  • Actions: run (success), skip (skipped), error (error), failure (failed)

  • Types: junit, robot

  • Examples:

  • All jobs with at least 1 failed test: (tests.testsuites.testcases.action='failure')

  • Failed tests in specific suite file: ((tests.name='test_suite.xml') and (tests.testsuites.testcases.action='failure'))

  • Specific test by name: ((tests.testsuites.testcases.name='test_install') and (tests.testsuites.testcases.action='failure'))

  • Test matching pattern: ((tests.testsuites.testcases.name=~'.*43336-V-BR.*') and (tests.testsuites.testcases.action='success'))

URLs:

  • url: GitHub PR or Gerrit change URL

Other:

  • jobstates: internal job state information

  • results: job results data

  • user_agent: client information

Common Use Cases

Find Failing Jobs: (status in ['failure', 'error']) Daily Jobs: (tags in ['daily']) OpenShift Jobs: (product.name='OpenShift') OpenShift Install Jobs: (tags in ['agent:openshift']) OpenShift Application/Workload Jobs: (tags in ['agent:openshift-app']) Jobs with Specific Component Version: ((components.type='ocp') and (components.version='4.19.0')) Jobs with Multiple Components: (((components.type='ocp') and (components.version='4.19.0')) and ((components.type='storage') and (components.name='ceph'))) Jobs by Date Range: ((created_at>='2024-09-16') and (created_at<='2025-09-16')) Jobs with Specific Metrics: ((keys_values.key='install_time') and (keys_values.value>3600)) Compare Jobs: Look for jobs with same name, topic, remoteci, configuration, and url

ElasticSearch Aggregations (for Statistics & Analysis)

When to use aggregations (aggs parameter):

  • User asks for counts, statistics, trends, distributions, or averages

  • Examples: "How many jobs failed?", "Show daily trend", "Average duration", "Count by status"

  • Aggregations compute stats server-side (much faster than fetching all documents)

  • Use limit=1 with fields=['id'] for aggregations to minimize bandwidth (limit=0 is auto-set to 1)

Aggregation syntax (ElasticSearch 7.16): The aggs parameter takes a dict with aggregation definitions: {"<agg_name>": {"<agg_type>": {...}}}

Simple field aggregations (keyword, date, numeric fields):

  • Terms (group by): {"by_status": {"terms": {"field": "status", "size": 10}}}

  • Date histogram: {"daily": {"date_histogram": {"field": "created_at", "calendar_interval": "day"}}}

  • Stats (avg, min, max, sum): {"duration_stats": {"stats": {"field": "duration"}}}

  • Count: {"total": {"value_count": {"field": "id"}}}

Nested field aggregations (components, tests, team, remoteci, pipeline, topic, files, keys_values, nodes): Nested fields require special nested aggregation syntax:

  • Step 1: Wrap in nested aggregation with path

  • Step 2: Add filter or terms aggregation inside

  • Example for components.version:

    {
      "components_agg": {
        "nested": {"path": "components"},
        "aggs": {
          "ocp_only": {
            "filter": {"term": {"components.type": "ocp"}},
            "aggs": {
              "versions": {"terms": {"field": "components.version", "size": 50}}
            }
          }
        }
      }
    }

Triple-nested: tests.testsuites.testcases (test results): Test data requires three levels of nested aggregations:

{
  "tests_agg": {
    "nested": {"path": "tests"},
    "aggs": {
      "testsuites_agg": {
        "nested": {"path": "tests.testsuites"},
        "aggs": {
          "testcases_agg": {
            "nested": {"path": "tests.testsuites.testcases"},
            "aggs": {
              "by_action": {"terms": {"field": "tests.testsuites.testcases.action"}}
            }
          }
        }
      }
    }
  }
}

Available aggregation fields by type:

  • Simple fields (direct aggregation): status, tags, team_id, remoteci_id, pipeline_id, topic_id, product_id, created_at, updated_at, duration, state, name

  • Nested fields (need nested agg):

    • components: type, name, version, tags, canonical_project_name

    • tests → testsuites → testcases: name, action (success/failure/error/skip), classname, time, type

    • team: id, name, state, external, has_pre_release_access

    • remoteci: id, name, state, public

    • pipeline: id, name, state

    • topic: id, name, component_types, export_control

    • files: id, name, mime, size, state

    • keys_values: key, value

    • nodes → hardware: (nested within nested)

    • nodes → kernel: (nested within nested)

Common aggregation patterns:

  • "How many jobs by status?" → {"by_status": {"terms": {"field": "status"}}}

  • "Daily job count last week" → {"daily": {"date_histogram": {"field": "created_at", "calendar_interval": "day"}}}

  • "Average job duration" → {"avg_duration": {"avg": {"field": "duration"}}}

  • "Count by team" → {"by_team": {"terms": {"field": "team_id"}}}

  • "OCP version distribution" → Use nested aggregation on components (see example above)

  • "Test failure rate" → Use triple-nested aggregation on tests.testsuites.testcases (see example above)

Combining aggregations with sub-aggregations: You can nest aggregations for multi-dimensional analysis:

{
  "daily": {
    "date_histogram": {"field": "created_at", "calendar_interval": "day"},
    "aggs": {
      "by_status": {"terms": {"field": "status"}},
      "avg_duration": {"avg": {"field": "duration"}}
    }
  }
}

Response format with aggregations: When aggregations are provided, the response includes an "aggregations" field with the computed statistics. The "hits" field will contain 1 job document (auto-set when aggs provided), or more if limit is explicitly set higher.

Function Parameters

query (required): Query DSL string - see examples above

fields (optional, default: []): List of fields to return

  • []: NO data returned (only metadata: count, total)

  • ['id', 'status']: only these fields

  • Use dot notation for nested fields: components.name, tests.testsuites.testcases.action

  • Recommended minimum: ['id', 'status', 'created_at']

  • For components: ['components.type', 'components.name', 'components.version']

  • For tests: ['tests.testsuites.testcases.name', 'tests.testsuites.testcases.action']

limit (optional, default: 20, max: 200): Page size — maximum job documents in hits for this call. Not repeated in the JSON response; you must remember what you passed. If limit > 50, use __save_to_file.

offset (optional, default: 0): Number of matching jobs to skip (same sort as sort). Page 1: offset=0. Next page: offset = previous offset + limit. Not repeated in the JSON response.

sort (optional, default: '-created_at'): Sort criteria

  • -created_at: newest to oldest (default)

  • created_at: oldest to newest

  • -duration: longest to shortest

  • duration: shortest to longest

  • āš ļø WARNING: Only date and numeric fields are sortable (created_at, updated_at, duration)

  • Text fields like name or status are NOT sortable and will return empty results

__save_to_file (optional, available on ALL tools): Path to save complete result

  • Use systematically if: limit > 50, many fields, multiple pagination, bulk analysis

  • Example: __save_to_file='/tmp/dci/jobs.json'

Field Filtering

The fields parameter filters which fields are returned in the response:

  • If fields is empty [], no job data is returned (only metadata)

  • If fields contains field names, only those fields are returned

  • Use dot notation for nested fields: components.name, topic.id, tests.testsuites.testcases.name

  • Common field combinations:

  • Basic info: ['id', 'name', 'status', 'created_at']

  • Component details: ['components.name', 'components.version', 'components.tags']

  • Test results: ['tests.testsuites.testcases.name', 'tests.testsuites.testcases.action']

Response format and pagination

The return value is a JSON string. Parse it once; the top-level object has at least:

  • hits: array of job objects for this page (up to limit items). Shape matches your fields (nested objects only where you requested them). If fields=[], this is always [] — you still get total for counting.

  • total: hit metadata for the query. Either a non-negative integer (exact match count) or an Elasticsearch-style object with:

  • value (int): number of matching jobs, or a lower bound when relation is gte (see below).

  • relation (string, when present): eq means value is the exact total. gte means there are at least value matches; the true count may be higher (Elasticsearch did not track the full total). If relation is omitted, treat value as exact unless your deployment documents otherwise.

Let N = total if total is an int, else N = total["value"]. Let rel be None if total is an int, else total.get("relation").

There is no limit or offset key in the response; pagination is driven only by the tool arguments on the next call.

How to paginate: Keep the same query, sort, and fields. Start with offset=0. After each page, advance offset by limit while there may be more rows:

  • If rel == "gte": the only reliable stop rule is len(hits) < limit (no more full pages). Do not assume N is the full count.

  • Otherwise (rel is eq, None, or total is an int): stop when len(hits) < limit or offset + len(hits) >= N.

Quick count: Exact total only when total is an int or relation == "eq" (or relation absent and your stack guarantees exact value). If relation == "gte", value is a lower bound only — you must paginate through all pages (or accept an approximate count) for a true total.

Example (illustrative; field names depend on fields):

{
  "hits": [
    {
      "id": "job-abc-123",
      "status": "failure",
      "created_at": "2026-03-30T10:00:00",
      "components": [
        {
          "type": "ocp",
          "name": "OpenShift",
          "version": "4.19.0",
          "tags": ["build:ga"]
        }
      ]
    }
  ],
  "total": {"value": 150, "relation": "eq"}
}
ParametersJSON Schema
NameRequiredDescriptionDefault
queryYessearch criteria (e.g., (((components.type='ocp') and (components.version='4.19.0')) and ((components.type='storage') and (components.name='my-storage'))))
sortNoSort criteria. Use a minus prefix for descending order (e.g., '-created_at'). Only date and numeric fields are sortable: 'created_at', 'updated_at', 'duration'. Text fields like 'name' or 'status' are NOT sortable and will return empty results. Default is '-created_at'.-created_at
limitNoPage size: max job rows in the response `hits` array (default 20, max 200). When using aggregations, limit is auto-set to 1 if 0 (DCI server requires limit >= 1 for aggregations). For a cheap global count, use limit=1 with minimal fields and read the match count from `total` (integer, or `total['value']` if `total` is an object).
offsetNoSkip this many matching jobs (same query/sort). Next page: previous offset + limit. Not echoed in the JSON.
fieldsNoList of fields to return. Fields are the one listed in the query description and responses. Must be specified as a list of strings, you can use 'components.name' or 'topic.id' to get only nested fields. If empty, no fields are returned.
aggsNoElasticSearch 7.16 aggregation JSON (dict). Use this when the user asks for statistics, counts, trends, or aggregated data instead of individual job documents. When provided, response includes 'aggregations' field. Set limit=1 with fields=['id'] for minimal bandwidth (1 job document + aggregation results).

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavioral traits: Elasticsearch query nature, response format (JSON string with 'hits' and 'total'), pagination details (no limit/offset in response, stop rules), sortability constraints (only date/numeric fields), and aggregation syntax requirements. No contradictions present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

While well-organized with sections and examples, the description is extremely verbose (over 1000 words). For AI agent use, it could be more concise; the 'Common Mistakes' section and many examples add redundancy. The structure is effective but length detracts from quick comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 parameters, DSL, nested fields, aggregations, pagination) and the presence of an output schema, the description covers all necessary aspects: query syntax, parameter usage, response format with pagination rules, aggregation examples, and common pitfalls. It is fully self-contained for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with all 6 parameters described. The description adds significant value beyond the schema, including query DSL syntax, field filtering examples, sort notices, aggregation patterns, and __save_to_file usage. It explains nested field dot-notation and parameter interactions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches DCI job documents from Elasticsearch, and explains what DCI jobs represent (CI/CD pipeline executions). It distinguishes itself from sibling tools (e.g., download_dci_file, query_dci_components) by focusing on jobs and providing extensive query capabilities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description offers comprehensive usage guidelines, including when to use aggregations (user asks for statistics), when to paginate, and common mistakes (e.g., wrapping conditions in parentheses, using 'in' for lists, specifying necessary fields). It also advises on handling large results with __save_to_file and provides query examples for common use cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

todayA

Get today's date.

Returns: JSON string with today's date in this format: "YYYY-MM-DD"

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It discloses that the tool returns a JSON string with today's date and the format. It does not mention timezone or side effects, but for a simple read-only tool this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, clearly structured with a summary and a return format explanation. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters and an output schema exists, the description fully explains what the tool returns. It is complete for its simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters exist. The description adds value by explaining the return format, which is not provided by the input schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the verb 'Get' and the resource 'today's date', and specifies the output format as a JSON string with 'YYYY-MM-DD'. This distinguishes it from sibling tools like 'now' which likely returns a datetime.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives. The description only states what it does without any context about when it is appropriate or when to avoid it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.3.0
    • First observeddownload_dci_file
    • First observednow
    • First observedquery_dci_components
    • First observedquery_dci_remotecis
    • First observedquery_dci_teams
    • First observedsearch_dci_jobs
    • First observedtoday

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

Related MCP Connectors

Related MCP Servers