Metadata-Version: 2.4
Name: cai-mcp-server
Version: 0.1.1
Summary: Task-level MCP tools for Cloudera AI Workbench API v2
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.28.0
Requires-Dist: mcp<3,>=2.0.0
Requires-Dist: pydantic-settings<3,>=2.7.0
Provides-Extra: dev
Requires-Dist: mcp[cli]<3,>=2.0.0; extra == 'dev'
Requires-Dist: pytest<10,>=8.4; extra == 'dev'
Requires-Dist: ruff<1,>=0.12; extra == 'dev'
Description-Content-Type: text/markdown

# Cloudera AI Workbench MCP Server

Cloudera Agent Studio가 `uvx`로 실행하는 로컬 Python MCP 서버입니다. MCP 통신은
`stdio`만 사용하고, 서버 프로세스가 인증된 Cloudera AI Workbench API v2를 직접
호출합니다. 별도의 원격 MCP HTTP 서버는 운영하지 않습니다.

이 서버는 API 목록을 그대로 노출하지 않습니다. Agent가 실제 운영 질문과 작업을
처리할 수 있도록 여러 API 호출·이름 해석·집계를 묶은 5개 업무형 tool만 제공합니다.

## 기술 기준

- Python 3.11 이상
- 공식 [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) v2
- `mcp>=2.0.0,<3`
- MCP transport: `stdio`
- REST client: `httpx.AsyncClient`
- API prefix: 코드에 고정된 `/api/v2`

stdout은 MCP wire message 전용이며 애플리케이션 로그는 stderr로 출력됩니다. API path나
HTTP method를 모델 입력으로 받는 범용 호출 도구는 없습니다.

## 제공 tool과 API 매핑

| MCP tool | 역할 | 내부 Workbench API v2 |
|---|---|---|
| `get_workbench_overview` | 최근 workload 상태·실패·현재 실행 중 workload·자원 합계 요약 | `GET /usage` |
| `find_workloads` | 이름, 시간, 상태, 프로젝트, 유형, 생성자로 workload 검색 | `GET /usage` |
| `get_current_resource_usage` | 현재 workload의 CPU·메모리·GPU 값을 전체/프로젝트/유형별 집계 | `GET /usage` |
| `get_job_status` | job 이름을 전체 접근 가능 job에서 찾아 최근 run 상태 조회 | 내부 `GET /jobs`, `GET .../runs` |
| `run_job` | 허용 목록의 job 이름을 안전하게 해석하여 새 run 시작 | 내부 `GET /jobs`, `POST .../runs` |

`get_current_resource_usage` 결과는 `/api/v2/usage`가 현재 각 workload에 보고한 CPU,
memory, GPU 수치의 합계입니다. 사용률 퍼센트나 과거 시간 구간의 누적 소비량으로
해석하면 안 되며, 응답의 `metric_semantics`에도 이 제한을 표시합니다.

`get_workbench_overview`도 `/api/v2/usage`만 사용합니다. `/api/v2/workloads/executions`는
Cloudera Observability machine user로 구성된 환경에서만 접근 가능한 경우가 있어 기본
Workload 사용자 인증으로는 호출하지 않습니다. 따라서 overview의 `execution_summary`와
`recent_failures`는 usage 응답의 상태/생성 시각을 기준으로 계산됩니다.

job 목록은 공개 tool이 아닙니다. `get_job_status`와 `run_job`이 사람이 입력한 이름을 API
ID로 변환할 때만 내부에서 사용합니다. `project_id`, `job_id`, page token과 API filter
JSON은 어떤 MCP tool도 입력받지 않습니다.

## Tool 파라미터

| Tool | 필수 입력 | Optional 입력과 기본값 |
|---|---|---|
| `get_workbench_overview` | 없음 | `window_hours=24` (1~168) |
| `find_workloads` | 없음 | `query=null`, `project_name=null`, `status=null`, `workload_type=null`, `creator=null`, `lookback_hours=null`, `max_results=20` |
| `get_current_resource_usage` | 없음 | `project_name=null`, `workload_type=null`, `status="running"` |
| `get_job_status` | `job_name` | `project_name=null`, `recent_runs=5` |
| `run_job` | `job_name` | `project_name=null` |

`find_workloads`의 `lookback_hours`는 workload 생성 시각 필터입니다. 생략하면 시간 필터를
적용하지 않으므로 오래 실행 중인 workload도 상태 검색에서 누락되지 않습니다. `status`와
`workload_type`은 서버가 Workbench의 `/workloadstatus`, `/workloadtypes` 목록과
대소문자 무시 방식으로 검증하며, 잘못된 값이면 현재 사용할 수 있는 값을 반환합니다.

`get_job_status`는 전체 접근 가능 job을 이름으로 검색합니다. `project_name`을 생략해도
job 이름이 유일하면 자동으로 프로젝트를 찾습니다. 동일 이름이 여러 프로젝트에 있으면
ID가 아닌 프로젝트명 후보를 반환하므로 Agent가 사용자에게 선택을 요청할 수 있습니다.
조회는 유일한 대소문자 무시 일치도 허용하지만 임의의 부분 일치를 선택하지 않습니다.

## 인증 및 환경변수

`CAI_BASE_URL`에는 Workbench 도메인만 입력합니다. `CAI_TOKEN`은 Workbench에서
`audience=API`로 생성한 API Key여야 합니다. AI Inference workload의 `/tmp/jwt`는 이
API의 자격증명이 아니므로 사용하지 않습니다.

| 이름 | 필수 | 기본값 | 설명 |
|---|---:|---|---|
| `CAI_BASE_URL` | 예 | 없음 | Workbench origin. 예: `https://ml-xxxx.example.com` |
| `CAI_TOKEN` | 예 | 없음 | Workbench API v2 Bearer API Key (`audience=API`) |
| `CAI_ENABLE_JOB_RUNS` | 아니요 | `false` | `run_job` 기능의 운영자 전역 스위치 |
| `CAI_ALLOWED_JOBS` | 실행 시 | `[]` | 정확한 `project/job` 쌍의 JSON 배열 또는 comma 목록 |
| `CAI_MAX_RECORDS` | 아니요 | `100` | 내부 API 한 번에 읽는 최대 record 수(1~500) |
| `CAI_TIMEOUT_SECONDS` | 아니요 | `30` | REST timeout(초) |
| `CAI_VERIFY_TLS` | 아니요 | `true` | TLS 인증서 검증 |
| `CAI_LOG_LEVEL` | 아니요 | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |

운영 환경에서는 `CAI_VERIFY_TLS=true`를 유지하십시오. `CAI_TOKEN`은 로그와 tool 결과에
출력하지 않습니다.

## `run_job` 안전 정책

`run_job`은 MCP annotation에서 destructive/non-idempotent tool로 선언되어 있고, 다음 두
조건을 모두 만족해야 실행됩니다.

```dotenv
CAI_ENABLE_JOB_RUNS=true
CAI_ALLOWED_JOBS=["Fraud Detection/Nightly Train","Forecast/Daily Refresh"]
```

`job_name`은 항상 필수입니다. `project_name`을 생략했을 때 allowlist에 같은 job 이름이
정확히 하나면 프로젝트를 자동 선택합니다. 둘 이상의 프로젝트에 같은 job 이름이
등록되어 있을 때만 `project_name`을 요구합니다. 실행 시에는 대소문자를 포함한 정확한
allowlist 일치만 허용하고 부분 일치나 추정은 하지 않습니다.

`confirm=true` 같은 모델 입력을 보안 경계로 사용하지 않습니다. 재시도하면 새 run이
중복 생성될 수 있으므로 POST 요청은 자동 재시도하지 않습니다. 초기 버전은 임의
환경변수나 실행 인자도 모델에게 받지 않습니다.

## 로컬 개발과 테스트

[uv](https://docs.astral.sh/uv/)를 설치한 뒤 다음을 실행합니다.

```bash
cp .env.example .env
# .env의 Workbench URL과 API Key를 수정

uv sync --all-extras
uv run ruff check .
uv run pytest
```

MCP Inspector로 tool schema를 확인할 수 있습니다.

```bash
uv run --env-file .env mcp dev src/cai_mcp_server/server.py:mcp --with-editable .
```

서버 자체는 stdio peer가 연결해야 하므로 실행 중 터미널에 문자를 직접 입력하지
마십시오.

```bash
uv run --env-file .env cai-mcp-server
```

## wheel 및 uvx 검증

```bash
uv build
uvx --from ./dist/cai_mcp_server-0.1.0-py3-none-any.whl cai-mcp-server
```

개발 중에는 현재 소스를 바로 설치할 수도 있습니다.

```bash
uvx --from . cai-mcp-server
```

패키지 저장소에 배포한 뒤 Agent Studio에는 다음 형태로 등록합니다.

```json
{
  "command": "uvx",
  "args": [
    "--from",
    "cai-mcp-server==0.1.0",
    "cai-mcp-server"
  ]
}
```

환경변수를 포함한 전체 예시는 `agent-studio.json`에 있습니다. Agent Studio에는 MCP
server 정의를 등록한 뒤 workflow 설정에서 실제 secret 값을 넣어야 합니다. private
package index를 사용한다면 Agent Studio runtime에서 접근 가능한 uv/Python index도
구성해야 합니다.

## 테스트 범위와 live 검증

자동 테스트는 다음을 검증합니다.

- 필수 API Key, 실행 스위치, 정확한 job allowlist parsing
- 공식 API v2 path, JSON query filter, Bearer header, POST body
- API 응답 정규화, 실행/현재 자원 집계, 동적 status/type 검증
- project 이름 생략, 중복 후보 반환, 읽기용 대소문자 무시 해석
- 실행용 exact allowlist와 유일한 allowlisted project 추론
- upstream 오류의 민감 정보 제거
- 공개 tool이 승인된 5개뿐인지와 tool 호출 성공/차단
- 모든 공개 tool input에서 `project_id`, `job_id`가 제외되는지
- 실제 subprocess의 stdio MCP initialize 및 tool 목록 조회

Workbench 배포 버전에 따라 인스턴스의 정확한 계약은
`https://<workbench-domain>/api/v2/swagger.json`에서 확인할 수 있습니다. 실제 endpoint를
사용한 live 검증은 유효한 `CAI_BASE_URL`과 `CAI_TOKEN`이 있을 때 별도로 수행하십시오.

관련 공식 문서:

- [Cloudera AI Workbench API v2 시작 안내](https://docs.cloudera.com/machine-learning/cloud/api/index.html)
- [Cloudera AI API v2 REST reference](https://docs.cloudera.com/machine-learning/cloud/rest-api-reference/index.html)
- [Agent Studio MCP server 등록](https://docs.cloudera.com/machine-learning/cloud/use-ai-studios/topics/ml-register-mcp-server.html)
