From 9450c44be443e15b1ca329cf33790ece3900f58c Mon Sep 17 00:00:00 2001 From: Khauneesh Saigal Date: Thu, 23 Oct 2025 23:19:12 +0530 Subject: [PATCH 1/2] minor document changes cml to cai --- CONTRIBUTING.md | 2 +- cai_workbench_mcp_server/src/functions/upload_file.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 001a196..f545d90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,7 +110,7 @@ uv run pytest tests/ -v uv run pytest tests/test_all_functions.py::test_no_subprocess_vulnerabilities -v # FastMCP test -uv run python tests/test_cml_mcp_client.py --quick +uv run python tests/test_cai_mcp_client.py --quick ``` ### Add Tests diff --git a/cai_workbench_mcp_server/src/functions/upload_file.py b/cai_workbench_mcp_server/src/functions/upload_file.py index 5067f52..537f20f 100644 --- a/cai_workbench_mcp_server/src/functions/upload_file.py +++ b/cai_workbench_mcp_server/src/functions/upload_file.py @@ -11,7 +11,7 @@ def upload_file_to_root(host, api_key, project_id, file_path, target_name=None, Upload a file to the project using direct PUT request Args: - host: CML host URL + host: CAI host URL api_key: API key for authentication project_id: ID of the project to upload to file_path: Full path to the file to upload From bb8554c2ca136990785f565f6bad3c6e4fb74422 Mon Sep 17 00:00:00 2001 From: Khauneesh Saigal Date: Thu, 23 Oct 2025 23:29:10 +0530 Subject: [PATCH 2/2] Release v1.0.0: Initial public release with security enhancements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎉 First Public Release This release represents the initial stable version of the Cloudera AI Workbench MCP Server with comprehensive security fixes, testing infrastructure, and public repository setup. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Security Enhancements (Critical) Fixed critical security vulnerability affecting 46 functions: • Replaced subprocess.run() calls with secure requests library • API keys no longer exposed in process lists (ps/top) • All HTTP calls now use secure header-based authentication • Added 30-second timeouts to prevent hanging requests • Impact: Eliminated API key exposure vulnerability across entire codebase Files affected: • All create_* functions (7 files) • All delete_* functions (10 files) • All update_* functions (10 files) • All get_* functions (9 files) • All list_* functions (8 files) • All stop_/restart_ functions (4 files) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Testing Infrastructure Added comprehensive test suite for CI/CD: • test_all_functions.py: 11 unit tests covering all 47+ MCP tools • test_cai_mcp_client.py: FastMCP integration tests • Security vulnerability detection tests • Function signature validation tests • Response structure validation tests • Error handling tests CI/CD Automation Added GitHub Actions workflow: • Automated testing on all PRs • Security scanning • Multi-version Python testing (3.10, 3.11, 3.12) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Features 47+ MCP tools for Cloudera ML operations: • Project management (list, create, update, delete) • Job orchestration (create, run, monitor, stop) • Model lifecycle (build, deploy, manage) • Experiment tracking (create, log, query) • Application management (create, start, stop, restart) • File operations (upload, download, list, delete) Protocols supported: • FastMCP-based HTTP server (experimental) • FastMCP-based stdio server (recommended) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Core dependencies: • fastmcp>=2.11.0 (MCP protocol implementation) • requests>=2.28.0 (secure HTTP client) • python-dotenv>=1.0.0 (configuration management) • fastapi>=0.115.0 (HTTP server) • pyjwt>=2.8.0 (OAuth 2.1 support) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Ready For • Production deployment • CI/CD pipeline integration • Public contributions • Security audits • Docker/Claude Desktop integration License: Apache-2.0 --- CHANGELOG.md | 74 ------- CONTRIBUTING.md | 8 +- DOCKER.md | 36 ++-- Dockerfile | 30 +-- Makefile | 18 +- NOTICE.txt | 4 +- README.md | 56 ++--- SETUP.md | 28 +-- .../__init__.py | 0 .../http_server.py | 12 +- .../src/__init__.py | 0 .../src/functions/__init__.py | 0 .../src/functions/batch_list_projects.py | 0 .../src/functions/create_application.py | 0 .../src/functions/create_experiment.py | 0 .../src/functions/create_experiment_run.py | 0 .../src/functions/create_job.py | 2 +- .../src/functions/create_job_run.py | 0 .../src/functions/create_model_build.py | 0 .../src/functions/create_model_deployment.py | 0 .../src/functions/delete_all_jobs.py | 0 .../src/functions/delete_application.py | 0 .../src/functions/delete_experiment.py | 0 .../src/functions/delete_experiment_run.py | 0 .../functions/delete_experiment_run_batch.py | 0 .../src/functions/delete_job.py | 0 .../src/functions/delete_model.py | 0 .../src/functions/delete_project_file.py | 0 .../src/functions/get_application.py | 0 .../src/functions/get_experiment.py | 0 .../src/functions/get_experiment_run.py | 0 .../src/functions/get_job.py | 0 .../src/functions/get_job_run.py | 0 .../src/functions/get_model.py | 0 .../src/functions/get_model_build.py | 0 .../src/functions/get_model_deployment.py | 0 .../src/functions/get_project_id.py | 0 .../src/functions/get_runtimes.py | 0 .../src/functions/list_applications.py | 0 .../src/functions/list_experiments.py | 0 .../src/functions/list_job_runs.py | 0 .../src/functions/list_jobs.py | 0 .../src/functions/list_model_builds.py | 0 .../src/functions/list_model_deployments.py | 0 .../src/functions/list_models.py | 0 .../src/functions/list_project_files.py | 0 .../src/functions/log_experiment_run_batch.py | 0 .../src/functions/restart_application.py | 0 .../src/functions/stop_application.py | 0 .../src/functions/stop_job_run.py | 0 .../src/functions/stop_model_deployment.py | 0 .../src/functions/update_application.py | 0 .../src/functions/update_experiment.py | 0 .../src/functions/update_experiment_run.py | 0 .../src/functions/update_job.py | 0 .../src/functions/update_project.py | 0 .../functions/update_project_file_metadata.py | 0 .../src/functions/upload_file.py | 2 +- .../src/functions/upload_folder.py | 14 +- .../stdio_server.py | 14 +- docker-compose.secrets.yml | 24 +-- pyproject.toml | 16 +- tests/README.md | 20 +- tests/test_all_functions.py | 200 +++++++++--------- ...l_mcp_client.py => test_cai_mcp_client.py} | 10 +- uv.lock | 108 +++++----- 66 files changed, 301 insertions(+), 375 deletions(-) delete mode 100644 CHANGELOG.md rename {cml_mcp_server => cai_workbench_mcp_server}/__init__.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/http_server.py (97%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/__init__.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/__init__.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/batch_list_projects.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_application.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_experiment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_experiment_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_job.py (98%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_job_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_model_build.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/create_model_deployment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_all_jobs.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_application.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_experiment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_experiment_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_experiment_run_batch.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_job.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_model.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/delete_project_file.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_application.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_experiment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_experiment_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_job.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_job_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_model.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_model_build.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_model_deployment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_project_id.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/get_runtimes.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_applications.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_experiments.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_job_runs.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_jobs.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_model_builds.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_model_deployments.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_models.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/list_project_files.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/log_experiment_run_batch.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/restart_application.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/stop_application.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/stop_job_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/stop_model_deployment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/update_application.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/update_experiment.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/update_experiment_run.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/update_job.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/update_project.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/update_project_file_metadata.py (100%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/upload_file.py (99%) rename {cml_mcp_server => cai_workbench_mcp_server}/src/functions/upload_folder.py (95%) rename {cml_mcp_server => cai_workbench_mcp_server}/stdio_server.py (98%) rename tests/{test_cml_mcp_client.py => test_cai_mcp_client.py} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index aa39d44..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,74 +0,0 @@ -# Changelog - -All notable changes to the CML MCP Server will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -### Added -- Comprehensive test suite (`test_all_functions.py`) with 11 unit tests -- FastMCP integration tests (`test_cml_mcp_client.py`) -- Security vulnerability detection tests -- Comprehensive test documentation in `tests/README.md` - -### Changed -- **SECURITY**: Replaced all `subprocess.run` calls with secure `requests` library (46 files) -- API keys now transmitted securely in HTTPS headers instead of process arguments -- Updated all function error handling to use `requests.RequestException` -- Improved timeout handling (30s timeout on all API calls) - -### Fixed -- **CRITICAL**: API key exposure vulnerability in process list (CVE-pending) -- Error messages now properly report HTTP status codes -- JSON parsing errors now provide better debugging information - -### Security -- Eliminated subprocess-based API calls that exposed credentials -- All HTTP requests now use proper header-based authentication -- Added comprehensive security testing in CI/CD pipeline - ---- - -## [1.0.0] - 2025-10-22 - -### Added -- Initial public release -- Apache 2.0 license -- NOTICE.txt with third-party attributions -- 47+ MCP tools for Cloudera AI operations -- Support for: - - Project management - - Job creation and management - - Model building and deployment - - Experiment tracking - - File operations - - Application management -- FastMCP-based HTTP and stdio servers -- OAuth 2.1 support -- Comprehensive README documentation - -### Changed -- Migrated from private to public repository -- Updated all repository URLs to `github.com/cloudera/CML_MCP_Server` -- Updated license from MIT to Apache 2.0 -- Added legal notices for third-party dependencies - ---- - -## Types of Changes - -- `Added` for new features -- `Changed` for changes in existing functionality -- `Deprecated` for soon-to-be removed features -- `Removed` for now removed features -- `Fixed` for any bug fixes -- `Security` for vulnerability fixes - ---- - -## Release Links - -- [Unreleased](https://github.com/cloudera/CML_MCP_Server/compare/v1.0.0...HEAD) -- [1.0.0](https://github.com/cloudera/CML_MCP_Server/releases/tag/v1.0.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5dac685..f545d90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to CML MCP Server +# Contributing to CAI MCP Workbench Server Thanks for contributing! Keep it simple. @@ -6,8 +6,8 @@ Thanks for contributing! Keep it simple. ```bash # 1. Fork and clone -git clone https://github.com/YOUR_USERNAME/CML_MCP_Server.git -cd CML_MCP_Server +git clone https://github.com/YOUR_USERNAME/CAI_Workbench_MCP_Server.git +cd CAI_Workbench_MCP_Server # 2. Install pip install uv @@ -110,7 +110,7 @@ uv run pytest tests/ -v uv run pytest tests/test_all_functions.py::test_no_subprocess_vulnerabilities -v # FastMCP test -uv run python tests/test_cml_mcp_client.py --quick +uv run python tests/test_cai_mcp_client.py --quick ``` ### Add Tests diff --git a/DOCKER.md b/DOCKER.md index 863b365..4f17da0 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -11,7 +11,7 @@ ```bash # Set your Cloudera AI host -export CLOUDERA_ML_HOST=https://your-cml-instance.cloudera.site +export CAI_WORKBENCH_HOST=https://your-cai-instance.cloudera.site ``` ### 2. Build and Run @@ -33,12 +33,12 @@ make run ```json { "mcpServers": { - "cml": { + "cai_workbench": { "command": "docker-compose", "args": [ "-f", - "/absolute/path/to/cml_mcp_server/docker-compose.secrets.yml", - "run", "--rm", "cml-mcp-server" + "/absolute/path/to/cai_workbench_mcp_server/docker-compose.secrets.yml", + "run", "--rm", "cai-workbench-mcp-server" ] } } @@ -49,13 +49,13 @@ make run ```json { "mcpServers": { - "cml": { + "cai_workbench": { "command": "docker", "args": [ "run", "-i", "--rm", - "-e", "CLOUDERA_ML_HOST=https://your-instance.site", - "-e", "CLOUDERA_ML_API_KEY=your-api-key", - "cml-mcp-server" + "-e", "CAI_WORKBENCH_HOST=https://your-instance.site", + "-e", "CAI_WORKBENCH_API_KEY=your-api-key", + "cai-workbench-mcp-server" ] } } @@ -73,9 +73,9 @@ For production use, avoid environment variables by using Docker secrets: mkdir -p secrets # Add your credentials (these files are not committed to git) -echo "https://your-cml-instance.cloudera.site" > secrets/cloudera_ml_host -echo "your-api-key-here" > secrets/cloudera_ml_api_key -echo "your-project-id" > secrets/cloudera_ml_project_id +echo "https://your-cai-instance.cloudera.site" > secrets/cai_workbench_host +echo "your-api-key-here" > secrets/cai_workbench_api_key +echo "your-project-id" > secrets/cai_workbench_project_id # Secure the files chmod 600 secrets/* @@ -84,8 +84,8 @@ chmod 600 secrets/* ### Build and Run with Secrets ```bash -# Build (still needs CLOUDERA_ML_HOST for cmlapi installation) -export CLOUDERA_ML_HOST=https://your-cml-instance.cloudera.site +# Build (still needs CAI_WORKBENCH_HOST for cmlapi installation) +export CAI_WORKBENCH_HOST=https://your-cai-instance.cloudera.site make build # Run with secrets @@ -97,14 +97,14 @@ make run-secrets ```json { "mcpServers": { - "cml": { + "cai_workbench": { "command": "docker-compose", "args": [ "-f", - "/absolute/path/to/cml_mcp_server/docker-compose.secrets.yml", + "/absolute/path/to/cai_workbench_mcp_server/docker-compose.secrets.yml", "run", "--rm", - "cml-mcp-server" + "cai-workbench-mcp-server" ] } } @@ -125,8 +125,8 @@ make run-secrets ## Troubleshooting ### Module not found errors -- Check that your CML_DOMAIN is correct in the Makefile -- Ensure your CML instance is accessible +- Check that your CAI_DOMAIN is correct in the Makefile +- Ensure your CAI instance is accessible ### Claude Desktop connection issues - Make sure you're using STDIO mode (`make run`) diff --git a/Dockerfile b/Dockerfile index 3d9a8fc..4d3ecac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ # Simple, fast Dockerfile using UV FROM python:3.12-slim -# Build argument for Cloudera ML host URL -ARG CLOUDERA_ML_HOST +# Build argument for Cloudera AI Workbench host URL +ARG CAI_WORKBENCH_HOST # Install system dependencies and UV RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -12,31 +12,31 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && mv /root/.local/bin/uv /usr/local/bin/uv \ && mv /root/.local/bin/uvx /usr/local/bin/uvx -# Create non-root user -RUN groupadd -r cml && useradd -r -g cml cml +# Create non-root user (cai for Cloudera AI) +RUN groupadd -r cai && useradd -r -g cai cai # Set working directory WORKDIR /app # Copy project files -COPY --chown=cml:cml pyproject.toml uv.lock ./ -COPY --chown=cml:cml cml_mcp_server/ ./cml_mcp_server/ +COPY --chown=cai:cai pyproject.toml uv.lock ./ +COPY --chown=cai:cai cai_workbench_mcp_server/ ./cai_workbench_mcp_server/ # Install dependencies with UV (much faster than pip!) RUN uv sync --frozen -# Install Cloudera ML API (required dependency not in pyproject.toml) -# Extract domain from CLOUDERA_ML_HOST (strip https://) -RUN if [ -n "${CLOUDERA_ML_HOST}" ]; then \ - CML_DOMAIN=$(echo "${CLOUDERA_ML_HOST}" | sed 's|https\?://||' | sed 's|/$||'); \ - uv pip install https://${CML_DOMAIN}/api/v2/python.tar.gz; \ +# Install Cloudera AI Workbench API (cmlapi - required for upload_folder) +# Extract domain from CAI_WORKBENCH_HOST (strip https:// and trailing /) +RUN if [ -n "${CAI_WORKBENCH_HOST}" ]; then \ + WORKBENCH_DOMAIN=$(echo "${CAI_WORKBENCH_HOST}" | sed 's|https\?://||' | sed 's|/$||'); \ + echo "Installing cmlapi from https://${WORKBENCH_DOMAIN}/api/v2/python.tar.gz"; \ + uv pip install https://${WORKBENCH_DOMAIN}/api/v2/python.tar.gz; \ else \ - echo "Error: CLOUDERA_ML_HOST build argument required"; \ - exit 1; \ + echo "Warning: CAI_WORKBENCH_HOST not provided, skipping cmlapi installation"; \ fi # Switch to non-root user -USER cml +USER cai # Activate UV environment ENV VIRTUAL_ENV=/app/.venv @@ -46,4 +46,4 @@ ENV PATH="/app/.venv/bin:$PATH" EXPOSE 8080 # Default to stdio mode (like Terraform MCP server) -CMD ["python", "-m", "cml_mcp_server.stdio_server"] \ No newline at end of file +CMD ["python", "-m", "cai_workbench_mcp_server.stdio_server"] \ No newline at end of file diff --git a/Makefile b/Makefile index 89098f6..5562f7a 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,28 @@ -# CML MCP Server +# CAI Workbench MCP Server .DEFAULT_GOAL := help -IMAGE_NAME := cml-mcp-server +IMAGE_NAME := cai-workbench-mcp-server .PHONY: build -build: ## Build Docker image - requires CLOUDERA_ML_HOST env var - @if [ -z "$$CLOUDERA_ML_HOST" ]; then \ - echo "Error: CLOUDERA_ML_HOST environment variable required"; \ - echo "Usage: CLOUDERA_ML_HOST=https://your-cml-instance.cloudera.site make build"; \ +build: ## Build Docker image - requires CAI_WORKBENCH_HOST env var + @if [ -z "$$CAI_WORKBENCH_HOST" ]; then \ + echo "Error: CAI_WORKBENCH_HOST environment variable required"; \ + echo "Usage: CAI_WORKBENCH_HOST=https://your-cai-instance.cloudera.site make build"; \ exit 1; \ fi - docker build --build-arg CLOUDERA_ML_HOST=$$CLOUDERA_ML_HOST -t $(IMAGE_NAME) . + docker build --build-arg CAI_WORKBENCH_HOST=$$CAI_WORKBENCH_HOST -t $(IMAGE_NAME) . .PHONY: run run: ## Run in STDIO mode (for Claude Desktop) docker run -i --rm $(IMAGE_NAME) .PHONY: run-secrets run-secrets: ## Run with Docker secrets - docker-compose -f docker-compose.secrets.yml run --rm cml-mcp-server + docker-compose -f docker-compose.secrets.yml run --rm cai-workbench-mcp-server .PHONY: test test: ## Test STDIO transport - .venv/bin/python tests/test_cml_mcp_client.py --quick + .venv/bin/python tests/test_cai_mcp_client.py --quick .PHONY: clean clean: ## Remove Docker image diff --git a/NOTICE.txt b/NOTICE.txt index f2330bf..8e7ffc6 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -2,11 +2,11 @@ ================================================================================ -Third-Party Software for cml_mcp_server +Third-Party Software for cai_workbench_mcp_server -------------------------------------------------------------------------------- -The following 3rd-party software packages may be used by or distributed with cml_mcp_server. Any information relevant to third-party vendors listed below are collected using common, reasonable means. +The following 3rd-party software packages may be used by or distributed with cai_workbench_mcp_server. Any information relevant to third-party vendors listed below are collected using common, reasonable means. Date generated: 2025-10-16 diff --git a/README.md b/README.md index 2d1a731..897fae6 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ The easiest way to use this MCP server is through [Cloudera Agent Studio](https: "command": "uvx", "args": [ "--from", - "git+https://github.com/cloudera/CML_MCP_Server.git", - "cml-mcp-stdio" + "git+https://github.com/cloudera/CAI_Workbench_MCP_Server.git", + "cai-workbench-mcp-stdio" ], "env": { - "CLOUDERA_ML_HOST": "${CLOUDERA_ML_HOST}", - "CLOUDERA_ML_API_KEY": "${CLOUDERA_ML_API_KEY}", - "CLOUDERA_ML_PROJECT_ID": "${CLOUDERA_ML_PROJECT_ID}" + "CAI_WORKBENCH_HOST": "${CAI_WORKBENCH_HOST}", + "CAI_WORKBENCH_API_KEY": "${CAI_WORKBENCH_API_KEY}", + "CAI_WORKBENCH_PROJECT_ID": "${CAI_WORKBENCH_PROJECT_ID}" } } } @@ -55,9 +55,9 @@ The easiest way to use this MCP server is through [Cloudera Agent Studio](https: ``` 4. **Set environment variables** in Agent Studio settings: - - `CLOUDERA_ML_HOST`: Your Cloudera AI instance URL (e.g., `https://ml-xxxx.cloudera.site`) - - `CLOUDERA_ML_API_KEY`: Your API key from Cloudera AI - - `CLOUDERA_ML_PROJECT_ID`: Your default project ID (optional) + - `CAI_WORKBENCH_HOST`: Your Cloudera AI instance URL (e.g., `https://ml-xxxx.cloudera.site`) + - `CAI_WORKBENCH_API_KEY`: Your API key from Cloudera AI + - `CAI_WORKBENCH_PROJECT_ID`: Your default project ID (optional) 5. **Save and test** - Your agent now has access to all 47 Cloudera AI tools! @@ -70,10 +70,10 @@ Configure your Cloudera AI domain first - see [SETUP.md](./SETUP.md). ```bash # Clone repository -git clone https://github.com/cloudera/CML_MCP_Server.git -cd cml_mcp_server +git clone https://github.com/cloudera/CAI_Workbench_MCP_Server.git +cd cai_workbench_mcp_server -# Configure your CML domain in Makefile +# Configure your CAI domain in Makefile # Build and test make build make test @@ -86,8 +86,8 @@ See [DOCKER.md](./DOCKER.md) for Docker documentation. #### 1. Clone and setup ```bash -git clone https://github.com/cloudera/CML_MCP_Server.git -cd cml_mcp_server +git clone https://github.com/cloudera/CAI_Workbench_MCP_Server.git +cd cai_workbench_mcp_server uv sync ``` @@ -105,11 +105,11 @@ Create a `.env` file or export: ```bash # Required -export CLOUDERA_ML_HOST="https://ml-xxxx.cloudera.site" -export CLOUDERA_ML_API_KEY="your-api-key" +export CAI_WORKBENCH_HOST="https://ml-xxxx.cloudera.site" +export CAI_WORKBENCH_API_KEY="your-api-key" # Optional -export CLOUDERA_ML_PROJECT_ID="your-default-project-id" +export CAI_WORKBENCH_PROJECT_ID="your-default-project-id" ``` ## Usage @@ -120,10 +120,10 @@ Best for Claude Desktop and secure local usage: ```bash # Run the STDIO server -uv run -m cml_mcp_server.stdio_server +uv run -m cai_workbench_mcp_server.stdio_server # Or use the shortcut -uvx --from . cml-mcp-stdio +uvx --from . cai-workbench-mcp-stdio ``` #### Configure Claude Desktop @@ -134,12 +134,12 @@ Add to your Claude Desktop configuration: ```json { "mcpServers": { - "cml": { + "cai_workbench_mcp": { "command": "docker-compose", "args": [ "-f", - "/absolute/path/to/cml_mcp_server/docker-compose.secrets.yml", - "run", "--rm", "cml-mcp-server" + "/absolute/path/to/cai_workbench_mcp_server/docker-compose.secrets.yml", + "run", "--rm", "cai-workbench-mcp-server" ] } } @@ -150,13 +150,13 @@ Add to your Claude Desktop configuration: ```json { "mcpServers": { - "cml": { + "cai_workbench_mcp": { "command": "docker", "args": [ "run", "-i", "--rm", - "-e", "CLOUDERA_ML_HOST=https://your-instance.site", - "-e", "CLOUDERA_ML_API_KEY=your-api-key", - "cml-mcp-server" + "-e", "CAI_WORKBENCH_HOST=https://your-instance.site", + "-e", "CAI_WORKBENCH_API_KEY=your-api-key", + "cai-workbench-mcp-server" ] } } @@ -169,10 +169,10 @@ Add to your Claude Desktop configuration: ```bash # Start HTTP server on port 8000 -uv run -m cml_mcp_server.http_server +uv run -m cai_workbench_mcp_server.http_server # Or use the shortcut -uvx --from . cml-mcp-http +uvx --from . cai-workbench-mcp-http ``` #### Available Endpoints @@ -333,7 +333,7 @@ create_model_deployment_tool( ## Troubleshooting -1. **"Missing required configuration"**: Set CLOUDERA_ML_HOST and CLOUDERA_ML_API_KEY +1. **"Missing required configuration"**: Set CAI_WORKBENCH_HOST and CAI_WORKBENCH_API_KEY 2. **"cmlapi not found"**: Install from your Cloudera AI instance 3. **HTTP connection issues**: Ensure server is running on correct port 4. **Tool not found**: Check tool name spelling (use `list_tools`) diff --git a/SETUP.md b/SETUP.md index bcd449b..6e5b06f 100644 --- a/SETUP.md +++ b/SETUP.md @@ -2,13 +2,13 @@ ## Required Configuration -Set the `CLOUDERA_ML_HOST` environment variable before building. +Set the `CAI_WORKBENCH_HOST` environment variable before building. ### Step 1: Set Environment Variable ```bash # Set your Cloudera ML host URL -export CLOUDERA_ML_HOST=https://your-cml-instance.cloudera.site +export CAI_WORKBENCH_HOST=https://your-cai-instance.cloudera.site ``` ### Step 2: Build and Test @@ -26,11 +26,11 @@ make run ## Environment Variables -For the server to connect to CML, set these environment variables: +For the server to connect to CAI, set these environment variables: -- `CLOUDERA_ML_HOST` - Full URL to your CML instance (https://your-domain.com) -- `CLOUDERA_ML_API_KEY` - Your CML API key -- `CLOUDERA_ML_PROJECT_ID` - Your project ID (optional) +- `CAI_WORKBENCH_HOST` - Full URL to your CAI workbench instance (https://your-domain.com) +- `CAI_WORKBENCH_API_KEY` - Your CAI API key +- `CAI_WORKBENCH_PROJECT_ID` - Your project ID (optional) ## Claude Desktop Setup @@ -39,12 +39,12 @@ For the server to connect to CML, set these environment variables: ```json { "mcpServers": { - "cml": { + "cai_workbench_mcp": { "command": "docker", - "args": ["run", "-i", "--rm", "cml-mcp-server"], + "args": ["run", "-i", "--rm", "cai-workbench-mcp-server"], "env": { - "CLOUDERA_ML_HOST": "https://your-cml-domain.com", - "CLOUDERA_ML_API_KEY": "your-api-key-here" + "CAI_WORKBENCH_HOST": "https://your-cai-domain.com", + "CAI_WORKBENCH_API_KEY": "your-api-key-here" } } } @@ -56,13 +56,13 @@ For the server to connect to CML, set these environment variables: ## Common Issues **Build fails with "No module named 'cmlapi'"** -- Your CML_DOMAIN is incorrect or unreachable -- Check network connectivity to your CML instance +- CAI workbench domain is not reachable. +- Check network connectivity. **Claude Desktop shows JSON parse errors** - Make sure you built the latest Docker image after fixes - Use STDIO mode, not HTTP mode for Claude Desktop **API authentication errors** -- Check your CLOUDERA_ML_API_KEY is valid -- Verify CLOUDERA_ML_HOST includes https:// prefix \ No newline at end of file +- Check your CAI_WORKBENCH_API_KEY is valid +- Verify CAI_WORKBENCH_HOST includes https:// prefix \ No newline at end of file diff --git a/cml_mcp_server/__init__.py b/cai_workbench_mcp_server/__init__.py similarity index 100% rename from cml_mcp_server/__init__.py rename to cai_workbench_mcp_server/__init__.py diff --git a/cml_mcp_server/http_server.py b/cai_workbench_mcp_server/http_server.py similarity index 97% rename from cml_mcp_server/http_server.py rename to cai_workbench_mcp_server/http_server.py index cfb792c..7db6f4b 100644 --- a/cml_mcp_server/http_server.py +++ b/cai_workbench_mcp_server/http_server.py @@ -72,9 +72,9 @@ def read_secret_or_env(secret_name: str, env_var: str) -> str: return os.environ.get(env_var, "") return { - "host": read_secret_or_env("cloudera_ml_host", "CLOUDERA_ML_HOST"), - "api_key": read_secret_or_env("cloudera_ml_api_key", "CLOUDERA_ML_API_KEY"), - "project_id": read_secret_or_env("cloudera_ml_project_id", "CLOUDERA_ML_PROJECT_ID") + "host": read_secret_or_env("cai_workbench_host", "CAI_WORKBENCH_HOST"), + "api_key": read_secret_or_env("cai_workbench_api_key", "CAI_WORKBENCH_API_KEY"), + "project_id": read_secret_or_env("cai_workbench_project_id", "CAI_WORKBENCH_PROJECT_ID") } @@ -345,12 +345,12 @@ def main(): # Check configuration if not config.get("host") or not config.get("api_key"): print("Error: Missing required configuration") - print("Please set CLOUDERA_ML_HOST and CLOUDERA_ML_API_KEY") + print("Please set CAI_WORKBENCH_HOST and CAI_WORKBENCH_API_KEY") return # Get host and port from environment or use defaults - host = os.getenv("CML_MCP_HOST", "0.0.0.0") - port = int(os.getenv("CML_MCP_PORT", "8000")) + host = os.getenv("CAI_MCP_HOST", "0.0.0.0") + port = int(os.getenv("CAI_MCP_PORT", "8000")) print("Starting Cloudera AI HTTP Server...") print(f"Connected to: {config['host']}") diff --git a/cml_mcp_server/src/__init__.py b/cai_workbench_mcp_server/src/__init__.py similarity index 100% rename from cml_mcp_server/src/__init__.py rename to cai_workbench_mcp_server/src/__init__.py diff --git a/cml_mcp_server/src/functions/__init__.py b/cai_workbench_mcp_server/src/functions/__init__.py similarity index 100% rename from cml_mcp_server/src/functions/__init__.py rename to cai_workbench_mcp_server/src/functions/__init__.py diff --git a/cml_mcp_server/src/functions/batch_list_projects.py b/cai_workbench_mcp_server/src/functions/batch_list_projects.py similarity index 100% rename from cml_mcp_server/src/functions/batch_list_projects.py rename to cai_workbench_mcp_server/src/functions/batch_list_projects.py diff --git a/cml_mcp_server/src/functions/create_application.py b/cai_workbench_mcp_server/src/functions/create_application.py similarity index 100% rename from cml_mcp_server/src/functions/create_application.py rename to cai_workbench_mcp_server/src/functions/create_application.py diff --git a/cml_mcp_server/src/functions/create_experiment.py b/cai_workbench_mcp_server/src/functions/create_experiment.py similarity index 100% rename from cml_mcp_server/src/functions/create_experiment.py rename to cai_workbench_mcp_server/src/functions/create_experiment.py diff --git a/cml_mcp_server/src/functions/create_experiment_run.py b/cai_workbench_mcp_server/src/functions/create_experiment_run.py similarity index 100% rename from cml_mcp_server/src/functions/create_experiment_run.py rename to cai_workbench_mcp_server/src/functions/create_experiment_run.py diff --git a/cml_mcp_server/src/functions/create_job.py b/cai_workbench_mcp_server/src/functions/create_job.py similarity index 98% rename from cml_mcp_server/src/functions/create_job.py rename to cai_workbench_mcp_server/src/functions/create_job.py index 564d094..7b601ff 100644 --- a/cml_mcp_server/src/functions/create_job.py +++ b/cai_workbench_mcp_server/src/functions/create_job.py @@ -118,7 +118,7 @@ def create_job(config: Dict[str, str], params: Dict[str, Any]) -> Dict[str, Any] # Print environment variables for debugging (don't print API key) print(f"Environment variables:") for key, value in os.environ.items(): - if key.startswith("CLOUDERA_ML") and "API_KEY" not in key: + if key.startswith("CAI_WORKBENCH") and "API_KEY" not in key: print(f" {key}: {value}") # Send API request diff --git a/cml_mcp_server/src/functions/create_job_run.py b/cai_workbench_mcp_server/src/functions/create_job_run.py similarity index 100% rename from cml_mcp_server/src/functions/create_job_run.py rename to cai_workbench_mcp_server/src/functions/create_job_run.py diff --git a/cml_mcp_server/src/functions/create_model_build.py b/cai_workbench_mcp_server/src/functions/create_model_build.py similarity index 100% rename from cml_mcp_server/src/functions/create_model_build.py rename to cai_workbench_mcp_server/src/functions/create_model_build.py diff --git a/cml_mcp_server/src/functions/create_model_deployment.py b/cai_workbench_mcp_server/src/functions/create_model_deployment.py similarity index 100% rename from cml_mcp_server/src/functions/create_model_deployment.py rename to cai_workbench_mcp_server/src/functions/create_model_deployment.py diff --git a/cml_mcp_server/src/functions/delete_all_jobs.py b/cai_workbench_mcp_server/src/functions/delete_all_jobs.py similarity index 100% rename from cml_mcp_server/src/functions/delete_all_jobs.py rename to cai_workbench_mcp_server/src/functions/delete_all_jobs.py diff --git a/cml_mcp_server/src/functions/delete_application.py b/cai_workbench_mcp_server/src/functions/delete_application.py similarity index 100% rename from cml_mcp_server/src/functions/delete_application.py rename to cai_workbench_mcp_server/src/functions/delete_application.py diff --git a/cml_mcp_server/src/functions/delete_experiment.py b/cai_workbench_mcp_server/src/functions/delete_experiment.py similarity index 100% rename from cml_mcp_server/src/functions/delete_experiment.py rename to cai_workbench_mcp_server/src/functions/delete_experiment.py diff --git a/cml_mcp_server/src/functions/delete_experiment_run.py b/cai_workbench_mcp_server/src/functions/delete_experiment_run.py similarity index 100% rename from cml_mcp_server/src/functions/delete_experiment_run.py rename to cai_workbench_mcp_server/src/functions/delete_experiment_run.py diff --git a/cml_mcp_server/src/functions/delete_experiment_run_batch.py b/cai_workbench_mcp_server/src/functions/delete_experiment_run_batch.py similarity index 100% rename from cml_mcp_server/src/functions/delete_experiment_run_batch.py rename to cai_workbench_mcp_server/src/functions/delete_experiment_run_batch.py diff --git a/cml_mcp_server/src/functions/delete_job.py b/cai_workbench_mcp_server/src/functions/delete_job.py similarity index 100% rename from cml_mcp_server/src/functions/delete_job.py rename to cai_workbench_mcp_server/src/functions/delete_job.py diff --git a/cml_mcp_server/src/functions/delete_model.py b/cai_workbench_mcp_server/src/functions/delete_model.py similarity index 100% rename from cml_mcp_server/src/functions/delete_model.py rename to cai_workbench_mcp_server/src/functions/delete_model.py diff --git a/cml_mcp_server/src/functions/delete_project_file.py b/cai_workbench_mcp_server/src/functions/delete_project_file.py similarity index 100% rename from cml_mcp_server/src/functions/delete_project_file.py rename to cai_workbench_mcp_server/src/functions/delete_project_file.py diff --git a/cml_mcp_server/src/functions/get_application.py b/cai_workbench_mcp_server/src/functions/get_application.py similarity index 100% rename from cml_mcp_server/src/functions/get_application.py rename to cai_workbench_mcp_server/src/functions/get_application.py diff --git a/cml_mcp_server/src/functions/get_experiment.py b/cai_workbench_mcp_server/src/functions/get_experiment.py similarity index 100% rename from cml_mcp_server/src/functions/get_experiment.py rename to cai_workbench_mcp_server/src/functions/get_experiment.py diff --git a/cml_mcp_server/src/functions/get_experiment_run.py b/cai_workbench_mcp_server/src/functions/get_experiment_run.py similarity index 100% rename from cml_mcp_server/src/functions/get_experiment_run.py rename to cai_workbench_mcp_server/src/functions/get_experiment_run.py diff --git a/cml_mcp_server/src/functions/get_job.py b/cai_workbench_mcp_server/src/functions/get_job.py similarity index 100% rename from cml_mcp_server/src/functions/get_job.py rename to cai_workbench_mcp_server/src/functions/get_job.py diff --git a/cml_mcp_server/src/functions/get_job_run.py b/cai_workbench_mcp_server/src/functions/get_job_run.py similarity index 100% rename from cml_mcp_server/src/functions/get_job_run.py rename to cai_workbench_mcp_server/src/functions/get_job_run.py diff --git a/cml_mcp_server/src/functions/get_model.py b/cai_workbench_mcp_server/src/functions/get_model.py similarity index 100% rename from cml_mcp_server/src/functions/get_model.py rename to cai_workbench_mcp_server/src/functions/get_model.py diff --git a/cml_mcp_server/src/functions/get_model_build.py b/cai_workbench_mcp_server/src/functions/get_model_build.py similarity index 100% rename from cml_mcp_server/src/functions/get_model_build.py rename to cai_workbench_mcp_server/src/functions/get_model_build.py diff --git a/cml_mcp_server/src/functions/get_model_deployment.py b/cai_workbench_mcp_server/src/functions/get_model_deployment.py similarity index 100% rename from cml_mcp_server/src/functions/get_model_deployment.py rename to cai_workbench_mcp_server/src/functions/get_model_deployment.py diff --git a/cml_mcp_server/src/functions/get_project_id.py b/cai_workbench_mcp_server/src/functions/get_project_id.py similarity index 100% rename from cml_mcp_server/src/functions/get_project_id.py rename to cai_workbench_mcp_server/src/functions/get_project_id.py diff --git a/cml_mcp_server/src/functions/get_runtimes.py b/cai_workbench_mcp_server/src/functions/get_runtimes.py similarity index 100% rename from cml_mcp_server/src/functions/get_runtimes.py rename to cai_workbench_mcp_server/src/functions/get_runtimes.py diff --git a/cml_mcp_server/src/functions/list_applications.py b/cai_workbench_mcp_server/src/functions/list_applications.py similarity index 100% rename from cml_mcp_server/src/functions/list_applications.py rename to cai_workbench_mcp_server/src/functions/list_applications.py diff --git a/cml_mcp_server/src/functions/list_experiments.py b/cai_workbench_mcp_server/src/functions/list_experiments.py similarity index 100% rename from cml_mcp_server/src/functions/list_experiments.py rename to cai_workbench_mcp_server/src/functions/list_experiments.py diff --git a/cml_mcp_server/src/functions/list_job_runs.py b/cai_workbench_mcp_server/src/functions/list_job_runs.py similarity index 100% rename from cml_mcp_server/src/functions/list_job_runs.py rename to cai_workbench_mcp_server/src/functions/list_job_runs.py diff --git a/cml_mcp_server/src/functions/list_jobs.py b/cai_workbench_mcp_server/src/functions/list_jobs.py similarity index 100% rename from cml_mcp_server/src/functions/list_jobs.py rename to cai_workbench_mcp_server/src/functions/list_jobs.py diff --git a/cml_mcp_server/src/functions/list_model_builds.py b/cai_workbench_mcp_server/src/functions/list_model_builds.py similarity index 100% rename from cml_mcp_server/src/functions/list_model_builds.py rename to cai_workbench_mcp_server/src/functions/list_model_builds.py diff --git a/cml_mcp_server/src/functions/list_model_deployments.py b/cai_workbench_mcp_server/src/functions/list_model_deployments.py similarity index 100% rename from cml_mcp_server/src/functions/list_model_deployments.py rename to cai_workbench_mcp_server/src/functions/list_model_deployments.py diff --git a/cml_mcp_server/src/functions/list_models.py b/cai_workbench_mcp_server/src/functions/list_models.py similarity index 100% rename from cml_mcp_server/src/functions/list_models.py rename to cai_workbench_mcp_server/src/functions/list_models.py diff --git a/cml_mcp_server/src/functions/list_project_files.py b/cai_workbench_mcp_server/src/functions/list_project_files.py similarity index 100% rename from cml_mcp_server/src/functions/list_project_files.py rename to cai_workbench_mcp_server/src/functions/list_project_files.py diff --git a/cml_mcp_server/src/functions/log_experiment_run_batch.py b/cai_workbench_mcp_server/src/functions/log_experiment_run_batch.py similarity index 100% rename from cml_mcp_server/src/functions/log_experiment_run_batch.py rename to cai_workbench_mcp_server/src/functions/log_experiment_run_batch.py diff --git a/cml_mcp_server/src/functions/restart_application.py b/cai_workbench_mcp_server/src/functions/restart_application.py similarity index 100% rename from cml_mcp_server/src/functions/restart_application.py rename to cai_workbench_mcp_server/src/functions/restart_application.py diff --git a/cml_mcp_server/src/functions/stop_application.py b/cai_workbench_mcp_server/src/functions/stop_application.py similarity index 100% rename from cml_mcp_server/src/functions/stop_application.py rename to cai_workbench_mcp_server/src/functions/stop_application.py diff --git a/cml_mcp_server/src/functions/stop_job_run.py b/cai_workbench_mcp_server/src/functions/stop_job_run.py similarity index 100% rename from cml_mcp_server/src/functions/stop_job_run.py rename to cai_workbench_mcp_server/src/functions/stop_job_run.py diff --git a/cml_mcp_server/src/functions/stop_model_deployment.py b/cai_workbench_mcp_server/src/functions/stop_model_deployment.py similarity index 100% rename from cml_mcp_server/src/functions/stop_model_deployment.py rename to cai_workbench_mcp_server/src/functions/stop_model_deployment.py diff --git a/cml_mcp_server/src/functions/update_application.py b/cai_workbench_mcp_server/src/functions/update_application.py similarity index 100% rename from cml_mcp_server/src/functions/update_application.py rename to cai_workbench_mcp_server/src/functions/update_application.py diff --git a/cml_mcp_server/src/functions/update_experiment.py b/cai_workbench_mcp_server/src/functions/update_experiment.py similarity index 100% rename from cml_mcp_server/src/functions/update_experiment.py rename to cai_workbench_mcp_server/src/functions/update_experiment.py diff --git a/cml_mcp_server/src/functions/update_experiment_run.py b/cai_workbench_mcp_server/src/functions/update_experiment_run.py similarity index 100% rename from cml_mcp_server/src/functions/update_experiment_run.py rename to cai_workbench_mcp_server/src/functions/update_experiment_run.py diff --git a/cml_mcp_server/src/functions/update_job.py b/cai_workbench_mcp_server/src/functions/update_job.py similarity index 100% rename from cml_mcp_server/src/functions/update_job.py rename to cai_workbench_mcp_server/src/functions/update_job.py diff --git a/cml_mcp_server/src/functions/update_project.py b/cai_workbench_mcp_server/src/functions/update_project.py similarity index 100% rename from cml_mcp_server/src/functions/update_project.py rename to cai_workbench_mcp_server/src/functions/update_project.py diff --git a/cml_mcp_server/src/functions/update_project_file_metadata.py b/cai_workbench_mcp_server/src/functions/update_project_file_metadata.py similarity index 100% rename from cml_mcp_server/src/functions/update_project_file_metadata.py rename to cai_workbench_mcp_server/src/functions/update_project_file_metadata.py diff --git a/cml_mcp_server/src/functions/upload_file.py b/cai_workbench_mcp_server/src/functions/upload_file.py similarity index 99% rename from cml_mcp_server/src/functions/upload_file.py rename to cai_workbench_mcp_server/src/functions/upload_file.py index 5067f52..537f20f 100644 --- a/cml_mcp_server/src/functions/upload_file.py +++ b/cai_workbench_mcp_server/src/functions/upload_file.py @@ -11,7 +11,7 @@ def upload_file_to_root(host, api_key, project_id, file_path, target_name=None, Upload a file to the project using direct PUT request Args: - host: CML host URL + host: CAI host URL api_key: API key for authentication project_id: ID of the project to upload to file_path: Full path to the file to upload diff --git a/cml_mcp_server/src/functions/upload_folder.py b/cai_workbench_mcp_server/src/functions/upload_folder.py similarity index 95% rename from cml_mcp_server/src/functions/upload_folder.py rename to cai_workbench_mcp_server/src/functions/upload_folder.py index 8bdecb6..54f04ca 100644 --- a/cml_mcp_server/src/functions/upload_folder.py +++ b/cai_workbench_mcp_server/src/functions/upload_folder.py @@ -11,14 +11,14 @@ def setup_client(host, api_key): """ - Setup the CML API client + Setup the CAI Workbench API client Args: - host: CML host URL + host: CAI Workbench host URL api_key: API key for authentication Returns: - Configured CML API client + Configured CAI Workbench API client """ # Lazy import cmlapi (optional dependency, only needed when function is called) try: @@ -51,7 +51,7 @@ def delete_file_if_exists(client, project_id, file_path): Try to delete a file if it exists to avoid conflicts Args: - client: CML API client + client: CAI Workbench API client project_id: ID of the project file_path: Path of the file to delete """ @@ -67,10 +67,10 @@ def delete_file_if_exists(client, project_id, file_path): def upload_file_to_project(host, api_key, project_id, file_path, relative_path): """ - Upload a single file to Cloudera AI using direct PUT request + Upload a single file to Cloudera AI Workbench project using direct PUT request Args: - host: CML host URL + host: CAI Workbench host URL api_key: API key for authentication project_id: ID of the project to upload to file_path: Full path to the file to upload @@ -120,7 +120,7 @@ def upload_file_to_project(host, api_key, project_id, file_path, relative_path): def upload_folder(config: Dict[str, str], params: Dict[str, Any]) -> Dict[str, Any]: """ - Upload a folder to Cloudera AI using direct PUT request + Upload a folder to Cloudera AI Workbench project using direct PUT request Args: config: MCP configuration diff --git a/cml_mcp_server/stdio_server.py b/cai_workbench_mcp_server/stdio_server.py similarity index 98% rename from cml_mcp_server/stdio_server.py rename to cai_workbench_mcp_server/stdio_server.py index 0ae2a6e..609dd0b 100644 --- a/cml_mcp_server/stdio_server.py +++ b/cai_workbench_mcp_server/stdio_server.py @@ -66,7 +66,7 @@ from .src.functions.update_project import update_project from .src.functions.update_project_file_metadata import update_project_file_metadata except ImportError: - # Direct execution (python cml_mcp_server/stdio_server.py) + # Direct execution (python cai_workbench_mcp_server/stdio_server.py) from src.functions.upload_folder import upload_folder from src.functions.upload_file import upload_file from src.functions.create_job import create_job @@ -126,9 +126,9 @@ def read_secret_or_env(secret_name: str, env_var: str) -> str: return os.environ.get(env_var, "") return { - "host": read_secret_or_env("cloudera_ml_host", "CLOUDERA_ML_HOST"), - "api_key": read_secret_or_env("cloudera_ml_api_key", "CLOUDERA_ML_API_KEY"), - "project_id": read_secret_or_env("cloudera_ml_project_id", "CLOUDERA_ML_PROJECT_ID") + "host": read_secret_or_env("cai_workbench_host", "CAI_WORKBENCH_HOST"), + "api_key": read_secret_or_env("cai_workbench_api_key", "CAI_WORKBENCH_API_KEY"), + "project_id": read_secret_or_env("cai_workbench_project_id", "CAI_WORKBENCH_PROJECT_ID") } @@ -1596,9 +1596,9 @@ def main(): print(f"Error: Missing required configuration: {', '.join(missing)}", file=sys.stderr) print("", file=sys.stderr) print("Please set the following environment variables:", file=sys.stderr) - print(" CLOUDERA_ML_HOST=https://ml-xxxx.cloudera.site", file=sys.stderr) - print(" CLOUDERA_ML_API_KEY=your-api-key", file=sys.stderr) - print(" CLOUDERA_ML_PROJECT_ID=your-project-id # Optional", file=sys.stderr) + print(" CAI_WORKBENCH_HOST=https://ml-xxxx.cloudera.site", file=sys.stderr) + print(" CAI_WORKBENCH_API_KEY=your-api-key", file=sys.stderr) + print(" CAI_WORKBENCH_PROJECT_ID=your-project-id # Optional", file=sys.stderr) exit(1) # For STDIO, only log to stderr diff --git a/docker-compose.secrets.yml b/docker-compose.secrets.yml index 8757d3c..4d9ff62 100644 --- a/docker-compose.secrets.yml +++ b/docker-compose.secrets.yml @@ -1,22 +1,22 @@ services: - cml-mcp-server: + cai-workbench-mcp-server: build: context: . args: - CLOUDERA_ML_HOST: ${CLOUDERA_ML_HOST} - image: cml-mcp-server + CAI_WORKBENCH_HOST: ${CAI_WORKBENCH_HOST} + image: cai-workbench-mcp-server stdin_open: true tty: true secrets: - - cloudera_ml_host - - cloudera_ml_api_key - - cloudera_ml_project_id + - cai_workbench_host + - cai_workbench_api_key + - cai_workbench_project_id secrets: - cloudera_ml_host: - file: ./secrets/cloudera_ml_host - cloudera_ml_api_key: - file: ./secrets/cloudera_ml_api_key - cloudera_ml_project_id: - file: ./secrets/cloudera_ml_project_id + cai_workbench_host: + file: ./secrets/cai_workbench_host + cai_workbench_api_key: + file: ./secrets/cai_workbench_api_key + cai_workbench_project_id: + file: ./secrets/cai_workbench_project_id diff --git a/pyproject.toml b/pyproject.toml index f327ede..5946846 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "cml-mcp-server" +name = "cai-workbench-mcp-server" version = "1.0.0" description = "Cloudera AI Workbench Model Context Protocol (MCP) Server" readme = "README.md" @@ -53,14 +53,14 @@ dev = [ # FastMCP provides the MCP protocol implementation with built-in HTTP support [project.urls] -Homepage = "https://github.com/cloudera/CML_MCP_Server" -Documentation = "https://github.com/cloudera/CML_MCP_Server#readme" -Repository = "https://github.com/cloudera/CML_MCP_Server.git" -"Bug Tracker" = "https://github.com/cloudera/CML_MCP_Server/issues" +Homepage = "https://github.com/cloudera/CAI_Workbench_MCP_Server" +Documentation = "https://github.com/cloudera/CAI_Workbench_MCP_Server#readme" +Repository = "https://github.com/cloudera/CAI_Workbench_MCP_Server.git" +"Bug Tracker" = "https://github.com/cloudera/CAI_Workbench_MCP_Server/issues" [project.scripts] -cml-mcp-stdio = "cml_mcp_server.stdio_server:main" -cml-mcp-http = "cml_mcp_server.http_server:main" +cai-workbench-mcp-stdio = "cai_workbench_mcp_server.stdio_server:main" +cai-workbench-mcp-http = "cai_workbench_mcp_server.http_server:main" [build-system] requires = ["setuptools>=61.0", "wheel"] @@ -68,7 +68,7 @@ build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["."] -include = ["cml_mcp_server*"] +include = ["cai_workbench_mcp_server*"] [tool.setuptools.package-data] "*" = ["*.md", "*.txt", "*.json"] diff --git a/tests/README.md b/tests/README.md index 1f7c1d7..5badffc 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ -# CML MCP Server Test Suite +# CAI Workbench MCP Server Test Suite -Comprehensive test suite for all CML MCP Server functions, suitable for CI/CD pipelines. +Comprehensive test suite for all CAI Workbench MCP Server functions, suitable for CI/CD pipelines. ## Test Files @@ -8,7 +8,7 @@ Comprehensive test suite for all CML MCP Server functions, suitable for CI/CD pi **Main test suite covering all 47+ functions in the repository** - CI/CD Ready -### `test_cml_mcp_client.py` - FastMCP Integration Test Suite ⭐ +### `test_cai_mcp_client.py` - FastMCP Integration Test Suite ⭐ **End-to-end integration tests using FastMCP client** - Tests actual MCP protocol @@ -75,13 +75,13 @@ uv run pytest tests/test_all_functions.py -v uv run pytest tests/ -v ``` -### Option 2: FastMCP Integration Tests (test_cml_mcp_client.py) +### Option 2: FastMCP Integration Tests (test_cai_mcp_client.py) ```bash # Run full integration test suite -uv run python tests/test_cml_mcp_client.py +uv run python tests/test_cai_mcp_client.py # Run quick smoke test (faster) -uv run python tests/test_cml_mcp_client.py --quick +uv run python tests/test_cai_mcp_client.py --quick ``` ### Quick Test @@ -96,7 +96,7 @@ uv run pytest tests/test_all_functions.py::test_create_job_with_parameters -v ### CI/CD Integration ```bash # Run with coverage (add pytest-cov to dev dependencies) -uv run pytest tests/ --cov=cml_mcp_server --cov-report=term-missing +uv run pytest tests/ --cov=cai_workbench_mcp_server --cov-report=term-missing # Run with JUnit XML output for CI systems uv run pytest tests/ --junit-xml=test-results.xml @@ -151,9 +151,9 @@ This is **expected** and validates that: ### With Valid Credentials Set these environment variables for full functional testing: ```bash -export CLOUDERA_ML_HOST="https://your-cml-instance.cloudera.site" -export CLOUDERA_ML_API_KEY="your-api-key" -export CLOUDERA_ML_PROJECT_ID="your-project-id" +export CAI_WORKBENCH_HOST="https://your-cai-instance.cloudera.site" +export CAI_WORKBENCH_API_KEY="your-api-key" +export CAI_WORKBENCH_PROJECT_ID="your-project-id" ``` ## Test Requirements diff --git a/tests/test_all_functions.py b/tests/test_all_functions.py index e218601..7e7a4f7 100644 --- a/tests/test_all_functions.py +++ b/tests/test_all_functions.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Comprehensive test suite for all CML MCP Server functions +Comprehensive test suite for all CAI Workbench MCP Server functions Suitable for CI/CD pipeline unit testing This test suite covers all 47+ tools/functions in the repository with: @@ -19,56 +19,56 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # Import all functions -from cml_mcp_server.src.functions.batch_list_projects import batch_list_projects -from cml_mcp_server.src.functions.create_application import create_application -from cml_mcp_server.src.functions.create_experiment import create_experiment -from cml_mcp_server.src.functions.create_experiment_run import create_experiment_run -from cml_mcp_server.src.functions.create_job import create_job -from cml_mcp_server.src.functions.create_job_run import create_job_run -from cml_mcp_server.src.functions.create_model_build import create_model_build -from cml_mcp_server.src.functions.create_model_deployment import create_model_deployment -from cml_mcp_server.src.functions.delete_all_jobs import delete_all_jobs -from cml_mcp_server.src.functions.delete_application import delete_application -from cml_mcp_server.src.functions.delete_experiment import delete_experiment -from cml_mcp_server.src.functions.delete_experiment_run import delete_experiment_run -from cml_mcp_server.src.functions.delete_experiment_run_batch import delete_experiment_run_batch -from cml_mcp_server.src.functions.delete_job import delete_job -from cml_mcp_server.src.functions.delete_model import delete_model -from cml_mcp_server.src.functions.delete_project_file import delete_project_file -from cml_mcp_server.src.functions.get_application import get_application -from cml_mcp_server.src.functions.get_experiment import get_experiment -from cml_mcp_server.src.functions.get_experiment_run import get_experiment_run -from cml_mcp_server.src.functions.get_job import get_job -from cml_mcp_server.src.functions.get_job_run import get_job_run -from cml_mcp_server.src.functions.get_model import get_model -from cml_mcp_server.src.functions.get_model_build import get_model_build -from cml_mcp_server.src.functions.get_model_deployment import get_model_deployment -from cml_mcp_server.src.functions.get_project_id import get_project_id -from cml_mcp_server.src.functions.get_runtimes import get_runtimes -from cml_mcp_server.src.functions.list_applications import list_applications -from cml_mcp_server.src.functions.list_experiments import list_experiments -from cml_mcp_server.src.functions.list_job_runs import list_job_runs -from cml_mcp_server.src.functions.list_jobs import list_jobs -from cml_mcp_server.src.functions.list_model_builds import list_model_builds -from cml_mcp_server.src.functions.list_model_deployments import list_model_deployments -from cml_mcp_server.src.functions.list_models import list_models -from cml_mcp_server.src.functions.list_project_files import list_project_files -from cml_mcp_server.src.functions.log_experiment_run_batch import log_experiment_run_batch -from cml_mcp_server.src.functions.restart_application import restart_application -from cml_mcp_server.src.functions.stop_application import stop_application -from cml_mcp_server.src.functions.stop_job_run import stop_job_run -from cml_mcp_server.src.functions.stop_model_deployment import stop_model_deployment -from cml_mcp_server.src.functions.update_application import update_application -from cml_mcp_server.src.functions.update_experiment import update_experiment -from cml_mcp_server.src.functions.update_experiment_run import update_experiment_run -from cml_mcp_server.src.functions.update_job import update_job -from cml_mcp_server.src.functions.update_project import update_project -from cml_mcp_server.src.functions.update_project_file_metadata import update_project_file_metadata -from cml_mcp_server.src.functions.upload_file import upload_file +from cai_workbench_mcp_server.src.functions.batch_list_projects import batch_list_projects +from cai_workbench_mcp_server.src.functions.create_application import create_application +from cai_workbench_mcp_server.src.functions.create_experiment import create_experiment +from cai_workbench_mcp_server.src.functions.create_experiment_run import create_experiment_run +from cai_workbench_mcp_server.src.functions.create_job import create_job +from cai_workbench_mcp_server.src.functions.create_job_run import create_job_run +from cai_workbench_mcp_server.src.functions.create_model_build import create_model_build +from cai_workbench_mcp_server.src.functions.create_model_deployment import create_model_deployment +from cai_workbench_mcp_server.src.functions.delete_all_jobs import delete_all_jobs +from cai_workbench_mcp_server.src.functions.delete_application import delete_application +from cai_workbench_mcp_server.src.functions.delete_experiment import delete_experiment +from cai_workbench_mcp_server.src.functions.delete_experiment_run import delete_experiment_run +from cai_workbench_mcp_server.src.functions.delete_experiment_run_batch import delete_experiment_run_batch +from cai_workbench_mcp_server.src.functions.delete_job import delete_job +from cai_workbench_mcp_server.src.functions.delete_model import delete_model +from cai_workbench_mcp_server.src.functions.delete_project_file import delete_project_file +from cai_workbench_mcp_server.src.functions.get_application import get_application +from cai_workbench_mcp_server.src.functions.get_experiment import get_experiment +from cai_workbench_mcp_server.src.functions.get_experiment_run import get_experiment_run +from cai_workbench_mcp_server.src.functions.get_job import get_job +from cai_workbench_mcp_server.src.functions.get_job_run import get_job_run +from cai_workbench_mcp_server.src.functions.get_model import get_model +from cai_workbench_mcp_server.src.functions.get_model_build import get_model_build +from cai_workbench_mcp_server.src.functions.get_model_deployment import get_model_deployment +from cai_workbench_mcp_server.src.functions.get_project_id import get_project_id +from cai_workbench_mcp_server.src.functions.get_runtimes import get_runtimes +from cai_workbench_mcp_server.src.functions.list_applications import list_applications +from cai_workbench_mcp_server.src.functions.list_experiments import list_experiments +from cai_workbench_mcp_server.src.functions.list_job_runs import list_job_runs +from cai_workbench_mcp_server.src.functions.list_jobs import list_jobs +from cai_workbench_mcp_server.src.functions.list_model_builds import list_model_builds +from cai_workbench_mcp_server.src.functions.list_model_deployments import list_model_deployments +from cai_workbench_mcp_server.src.functions.list_models import list_models +from cai_workbench_mcp_server.src.functions.list_project_files import list_project_files +from cai_workbench_mcp_server.src.functions.log_experiment_run_batch import log_experiment_run_batch +from cai_workbench_mcp_server.src.functions.restart_application import restart_application +from cai_workbench_mcp_server.src.functions.stop_application import stop_application +from cai_workbench_mcp_server.src.functions.stop_job_run import stop_job_run +from cai_workbench_mcp_server.src.functions.stop_model_deployment import stop_model_deployment +from cai_workbench_mcp_server.src.functions.update_application import update_application +from cai_workbench_mcp_server.src.functions.update_experiment import update_experiment +from cai_workbench_mcp_server.src.functions.update_experiment_run import update_experiment_run +from cai_workbench_mcp_server.src.functions.update_job import update_job +from cai_workbench_mcp_server.src.functions.update_project import update_project +from cai_workbench_mcp_server.src.functions.update_project_file_metadata import update_project_file_metadata +from cai_workbench_mcp_server.src.functions.upload_file import upload_file # upload_folder requires cmlapi (optional dependency) try: - from cml_mcp_server.src.functions.upload_folder import upload_folder + from cai_workbench_mcp_server.src.functions.upload_folder import upload_folder HAS_UPLOAD_FOLDER = True except ImportError: HAS_UPLOAD_FOLDER = False @@ -168,11 +168,11 @@ def test_no_subprocess_vulnerabilities(): Verify that NO functions use subprocess.run for API calls This is critical for security - prevents API key exposure in process list """ - import cml_mcp_server.src.functions.delete_application as delete_app_mod - import cml_mcp_server.src.functions.create_job_run as create_job_run_mod - import cml_mcp_server.src.functions.get_job as get_job_mod - import cml_mcp_server.src.functions.list_experiments as list_exp_mod - import cml_mcp_server.src.functions.create_experiment_run as create_exp_run_mod + import cai_workbench_mcp_server.src.functions.delete_application as delete_app_mod + import cai_workbench_mcp_server.src.functions.create_job_run as create_job_run_mod + import cai_workbench_mcp_server.src.functions.get_job as get_job_mod + import cai_workbench_mcp_server.src.functions.list_experiments as list_exp_mod + import cai_workbench_mcp_server.src.functions.create_experiment_run as create_exp_run_mod critical_modules = [ delete_app_mod, @@ -394,56 +394,56 @@ def test_list_operations_return_consistent_structure(mock_config): def test_all_modules_import_successfully(): """Verify all function modules can be imported""" - import cml_mcp_server.src.functions.batch_list_projects - import cml_mcp_server.src.functions.create_application - import cml_mcp_server.src.functions.create_experiment - import cml_mcp_server.src.functions.create_experiment_run - import cml_mcp_server.src.functions.create_job - import cml_mcp_server.src.functions.create_job_run - import cml_mcp_server.src.functions.create_model_build - import cml_mcp_server.src.functions.create_model_deployment - import cml_mcp_server.src.functions.delete_all_jobs - import cml_mcp_server.src.functions.delete_application - import cml_mcp_server.src.functions.delete_experiment - import cml_mcp_server.src.functions.delete_experiment_run - import cml_mcp_server.src.functions.delete_experiment_run_batch - import cml_mcp_server.src.functions.delete_job - import cml_mcp_server.src.functions.delete_model - import cml_mcp_server.src.functions.delete_project_file - import cml_mcp_server.src.functions.get_application - import cml_mcp_server.src.functions.get_experiment - import cml_mcp_server.src.functions.get_experiment_run - import cml_mcp_server.src.functions.get_job - import cml_mcp_server.src.functions.get_job_run - import cml_mcp_server.src.functions.get_model - import cml_mcp_server.src.functions.get_model_build - import cml_mcp_server.src.functions.get_model_deployment - import cml_mcp_server.src.functions.get_project_id - import cml_mcp_server.src.functions.get_runtimes - import cml_mcp_server.src.functions.list_applications - import cml_mcp_server.src.functions.list_experiments - import cml_mcp_server.src.functions.list_job_runs - import cml_mcp_server.src.functions.list_jobs - import cml_mcp_server.src.functions.list_model_builds - import cml_mcp_server.src.functions.list_model_deployments - import cml_mcp_server.src.functions.list_models - import cml_mcp_server.src.functions.list_project_files - import cml_mcp_server.src.functions.log_experiment_run_batch - import cml_mcp_server.src.functions.restart_application - import cml_mcp_server.src.functions.stop_application - import cml_mcp_server.src.functions.stop_job_run - import cml_mcp_server.src.functions.stop_model_deployment - import cml_mcp_server.src.functions.update_application - import cml_mcp_server.src.functions.update_experiment - import cml_mcp_server.src.functions.update_experiment_run - import cml_mcp_server.src.functions.update_job - import cml_mcp_server.src.functions.update_project - import cml_mcp_server.src.functions.update_project_file_metadata - import cml_mcp_server.src.functions.upload_file + import cai_workbench_mcp_server.src.functions.batch_list_projects + import cai_workbench_mcp_server.src.functions.create_application + import cai_workbench_mcp_server.src.functions.create_experiment + import cai_workbench_mcp_server.src.functions.create_experiment_run + import cai_workbench_mcp_server.src.functions.create_job + import cai_workbench_mcp_server.src.functions.create_job_run + import cai_workbench_mcp_server.src.functions.create_model_build + import cai_workbench_mcp_server.src.functions.create_model_deployment + import cai_workbench_mcp_server.src.functions.delete_all_jobs + import cai_workbench_mcp_server.src.functions.delete_application + import cai_workbench_mcp_server.src.functions.delete_experiment + import cai_workbench_mcp_server.src.functions.delete_experiment_run + import cai_workbench_mcp_server.src.functions.delete_experiment_run_batch + import cai_workbench_mcp_server.src.functions.delete_job + import cai_workbench_mcp_server.src.functions.delete_model + import cai_workbench_mcp_server.src.functions.delete_project_file + import cai_workbench_mcp_server.src.functions.get_application + import cai_workbench_mcp_server.src.functions.get_experiment + import cai_workbench_mcp_server.src.functions.get_experiment_run + import cai_workbench_mcp_server.src.functions.get_job + import cai_workbench_mcp_server.src.functions.get_job_run + import cai_workbench_mcp_server.src.functions.get_model + import cai_workbench_mcp_server.src.functions.get_model_build + import cai_workbench_mcp_server.src.functions.get_model_deployment + import cai_workbench_mcp_server.src.functions.get_project_id + import cai_workbench_mcp_server.src.functions.get_runtimes + import cai_workbench_mcp_server.src.functions.list_applications + import cai_workbench_mcp_server.src.functions.list_experiments + import cai_workbench_mcp_server.src.functions.list_job_runs + import cai_workbench_mcp_server.src.functions.list_jobs + import cai_workbench_mcp_server.src.functions.list_model_builds + import cai_workbench_mcp_server.src.functions.list_model_deployments + import cai_workbench_mcp_server.src.functions.list_models + import cai_workbench_mcp_server.src.functions.list_project_files + import cai_workbench_mcp_server.src.functions.log_experiment_run_batch + import cai_workbench_mcp_server.src.functions.restart_application + import cai_workbench_mcp_server.src.functions.stop_application + import cai_workbench_mcp_server.src.functions.stop_job_run + import cai_workbench_mcp_server.src.functions.stop_model_deployment + import cai_workbench_mcp_server.src.functions.update_application + import cai_workbench_mcp_server.src.functions.update_experiment + import cai_workbench_mcp_server.src.functions.update_experiment_run + import cai_workbench_mcp_server.src.functions.update_job + import cai_workbench_mcp_server.src.functions.update_project + import cai_workbench_mcp_server.src.functions.update_project_file_metadata + import cai_workbench_mcp_server.src.functions.upload_file # upload_folder requires cmlapi (optional), only import if available if HAS_UPLOAD_FOLDER: - import cml_mcp_server.src.functions.upload_folder + import cai_workbench_mcp_server.src.functions.upload_folder # If we got here, all imports succeeded assert True diff --git a/tests/test_cml_mcp_client.py b/tests/test_cai_mcp_client.py similarity index 96% rename from tests/test_cml_mcp_client.py rename to tests/test_cai_mcp_client.py index 0552e4b..6dd7109 100644 --- a/tests/test_cml_mcp_client.py +++ b/tests/test_cai_mcp_client.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 """ -Test CML MCP Server using FastMCP Client +Test CAI Workbench MCP Server using FastMCP Client Simple, clean approach - testing representative tools from each category Note: These tests use mock project IDs. For real testing with actual Cloudera AI: -- Set environment variables: CLOUDERA_ML_HOST, CLOUDERA_ML_API_KEY, CLOUDERA_ML_PROJECT_ID +- Set environment variables: CAI_WORKBENCH_HOST, CAI_WORKBENCH_API_KEY, CAI_WORKBENCH_PROJECT_ID - Use real project IDs in format: xxxx-xxxx-xxxx-xxxx (e.g., "9er0-ooi9-uopm-8i8o") """ @@ -17,7 +17,7 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from fastmcp import Client -from cml_mcp_server.stdio_server import mcp +from cai_workbench_mcp_server.stdio_server import mcp def parse_tool_result(result): @@ -265,7 +265,7 @@ async def test_experiment_tools(): async def run_all_tests(): """Run all test categories""" print("\n" + "=" * 60) - print("🚀 CML MCP Server Test Suite") + print("🚀 CAI Workbehcnk MCP Server Test Suite") print("=" * 60) test_functions = [ @@ -317,7 +317,7 @@ async def quick_smoke_test(): if __name__ == "__main__": import argparse - parser = argparse.ArgumentParser(description="Test CML MCP Server") + parser = argparse.ArgumentParser(description="Test CAI Workbench MCP Server") parser.add_argument("--quick", action="store_true", help="Run quick smoke test only") args = parser.parse_args() diff --git a/uv.lock b/uv.lock index 7d3e7b6..9bed992 100644 --- a/uv.lock +++ b/uv.lock @@ -90,6 +90,60 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] +[[package]] +name = "cai-workbench-mcp-server" +version = "1.0.0" +source = { editable = "." } +dependencies = [ + { name = "cryptography" }, + { name = "fastapi" }, + { name = "fastmcp" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "pyjwt" }, + { name = "python-dotenv" }, + { name = "requests" }, + { name = "sse-starlette" }, + { name = "typing-extensions" }, + { name = "uvicorn" }, +] + +[package.optional-dependencies] +dev = [ + { name = "black" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "black", marker = "extra == 'dev'", specifier = ">=23.0.0" }, + { name = "cryptography", specifier = ">=41.0.0" }, + { name = "fastapi", specifier = ">=0.115.0" }, + { name = "fastmcp", specifier = ">=2.11.0" }, + { name = "httpx", specifier = ">=0.28.0" }, + { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pyjwt", specifier = ">=2.8.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, + { name = "python-dotenv", specifier = ">=1.0.0" }, + { name = "requests", specifier = ">=2.28.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, + { name = "sse-starlette", specifier = ">=2.0.0" }, + { name = "typing-extensions", specifier = ">=4.0.0" }, + { name = "uvicorn", specifier = ">=0.30.0" }, +] +provides-extras = ["dev"] + +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=8.4.1" }] + [[package]] name = "certifi" version = "2025.8.3" @@ -232,60 +286,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215 }, ] -[[package]] -name = "cml-mcp-server" -version = "1.0.0" -source = { editable = "." } -dependencies = [ - { name = "cryptography" }, - { name = "fastapi" }, - { name = "fastmcp" }, - { name = "httpx" }, - { name = "pydantic" }, - { name = "pyjwt" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "sse-starlette" }, - { name = "typing-extensions" }, - { name = "uvicorn" }, -] - -[package.optional-dependencies] -dev = [ - { name = "black" }, - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "ruff" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, -] - -[package.metadata] -requires-dist = [ - { name = "black", marker = "extra == 'dev'", specifier = ">=23.0.0" }, - { name = "cryptography", specifier = ">=41.0.0" }, - { name = "fastapi", specifier = ">=0.115.0" }, - { name = "fastmcp", specifier = ">=2.11.0" }, - { name = "httpx", specifier = ">=0.28.0" }, - { name = "pydantic", specifier = ">=2.0.0" }, - { name = "pyjwt", specifier = ">=2.8.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, - { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, - { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "requests", specifier = ">=2.28.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, - { name = "sse-starlette", specifier = ">=2.0.0" }, - { name = "typing-extensions", specifier = ">=4.0.0" }, - { name = "uvicorn", specifier = ">=0.30.0" }, -] -provides-extras = ["dev"] - -[package.metadata.requires-dev] -dev = [{ name = "pytest", specifier = ">=8.4.1" }] - [[package]] name = "colorama" version = "0.4.6"