From b811b23be7cf562a1100bd413156d3e7c27bdc4b Mon Sep 17 00:00:00 2001 From: Tim Schindler Date: Sat, 7 Mar 2026 11:06:17 +0100 Subject: [PATCH 1/2] docs: streamline README with OAuth and Docker deployment sections Add auth mode overview, OAuth per-user config table, Docker deployment section, and MCP_SERVER_URL. Remove duplicated Features section, .env example block, and inline Traefik YAML. Fix Development Guide link path. --- README.md | 186 +++++++++++++++--------------------------------------- 1 file changed, 51 insertions(+), 135 deletions(-) diff --git a/README.md b/README.md index 7ce353c..ced19d4 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,14 @@ An MCP server for CyberArk Privilege Cloud, built on the official [ark-sdk-python](https://github.com/cyberark/ark-sdk-python) library. Provides 53 tools for privileged access management. +Supports two authentication modes: +- **OAuth per-user mode** (recommended) -- each user authenticates with their own CyberArk Identity credentials via OAuth. Requires [Streamable HTTP transport](#docker-deployment) and an OIDC app in CyberArk Identity ([setup guide](docs/CYBERARK_IDENTITY_SETUP.md)). +- **Legacy service account mode** -- a single shared service account authenticates all requests via stdio transport. Simpler setup, shown in [Quick Start](#quick-start) below. + ## Quick Start +> This sets up the **legacy service account mode** via stdio. For OAuth per-user mode, see [OAuth Per-User Mode](#oauth-per-user-mode). + **1. Install uv** (if not already installed): ```bash curl -LsSf https://astral.sh/uv/install.sh | sh @@ -38,51 +44,73 @@ curl -LsSf https://astral.sh/uv/install.sh | sh **3. Restart Claude Desktop** - The MCP server will appear in the tools menu (hammer icon) when connected. +### Claude Code + +```bash +claude mcp add cyberark-privilege-cloud \ + -e CYBERARK_CLIENT_ID=your-service-user-username \ + -e CYBERARK_CLIENT_SECRET=your-service-user-password \ + -- uvx --from git+https://github.com/aaearon/mcp-privilege-cloud.git mcp-privilege-cloud +``` + ## Example Prompts Once configured, you can ask Claude things like: -**Account Management:** - "List all accounts in the Production safe" - "Show me Windows accounts that are failing management" -- "Create a new local admin account for server PROD-WEB-01" -- "Which accounts haven't had their passwords changed in 90 days?" - -**Safe Management:** - "Create a new safe called 'DevOps-Credentials' with 30-day retention" - "Add the DevOps team as safe members with retrieve permissions" -- "Show me all safes and their member counts" - -**Platform & Session Monitoring:** - "List all active platforms and their account counts" - "Show me active privileged sessions" -- "Get session activity for the last hour" ## Prerequisites - [CyberArk Identity Service User](https://docs.cyberark.com/identity-administration/latest/en/content/ispss/ispss-add-service-user.htm) with: - Appropriate Identity roles for the desired operations (e.g., Privilege Cloud Administrator for platform management) - Safe permissions granting access to the safes and accounts you want to manage +- For OAuth per-user mode: an OIDC app in CyberArk Identity (see [setup guide](docs/CYBERARK_IDENTITY_SETUP.md)) -## Client Integration +## Configuration -### Claude Desktop +### OAuth Per-User Mode -See [Quick Start](#quick-start) above for configuration. +Each connecting user authenticates with their own CyberArk Identity credentials via OAuth. The server verifies user identity from the OIDC JWT, then uses a shared service account platform token for all PCloud API calls. -If the configuration file doesn't exist, create it. If it already exists with other MCP servers, add the `cyberark-privilege-cloud` entry to the existing `mcpServers` object. +Requires Streamable HTTP transport -- see [Docker Deployment](#docker-deployment) or set `MCP_TRANSPORT=streamable-http` when running locally. -### Claude Code +| Variable | Required | Description | +|----------|----------|-------------| +| `CYBERARK_IDENTITY_TENANT_URL` | Yes | CyberArk Identity tenant URL (e.g., `https://abc1234.id.cyberark.cloud`) | +| `CYBERARK_CLIENT_ID` | Yes | Service account login name (for PCloud platform token) | +| `CYBERARK_CLIENT_SECRET` | Yes | Service account password | +| `CYBERARK_OAUTH_CLIENT_ID` | Yes | OIDC app client ID from Trust tab (for DCR and JWT audience) | +| `CYBERARK_OAUTH_CLIENT_SECRET` | Yes | OIDC app client secret from Trust tab (injected server-side in /token proxy) | +| `MCP_TRANSPORT` | No | Transport protocol (default: `stdio`; set to `streamable-http` for OAuth) | +| `MCP_HOST` | No | Server bind host (default: `127.0.0.1`) | +| `MCP_PORT` | No | Server bind port (default: `8000`) | +| `MCP_SERVER_URL` | No | Public URL for OAuth metadata (default: `http://{host}:{port}`) | + +See [CyberArk Identity Setup](docs/CYBERARK_IDENTITY_SETUP.md) for full configuration instructions. + +### Legacy Service Account Mode + +| Variable | Required | Description | +|----------|----------|-------------| +| `CYBERARK_CLIENT_ID` | Yes | Your Service User username | +| `CYBERARK_CLIENT_SECRET` | Yes | Your Service User password | -Add the MCP server using the Claude Code CLI: +## Docker Deployment + +The included `Dockerfile` and `docker-compose.yml` run the server in Streamable HTTP mode, suitable for OAuth per-user authentication and remote MCP clients. ```bash -claude mcp add cyberark-privilege-cloud \ - -e CYBERARK_CLIENT_ID=your-service-user-username \ - -e CYBERARK_CLIENT_SECRET=your-service-user-password \ - -- uvx --from git+https://github.com/aaearon/mcp-privilege-cloud.git mcp-privilege-cloud +# Create .env with your credentials (see .env.example) +docker compose up -d --build ``` +When deploying behind a reverse proxy, configure it to strip trailing slashes from request paths. MCP clients may POST to `/mcp/` (trailing slash), causing a 307 redirect that strips the `Authorization` header. Set `MCP_SERVER_URL` to the public URL of your server. + ## Available Tools (53 Total) **Account Management (18 tools):** @@ -108,97 +136,6 @@ claude mcp add cyberark-privilege-cloud \ - **Session Management**: `list_sessions`, `list_sessions_by_filter`, `get_session_details`, `count_sessions` - **Activity Tracking**: `list_session_activities`, `get_session_statistics` -## Features - -- **Complete Account Lifecycle**: Create, read, update, delete accounts with advanced search and password management -- **Comprehensive Safe Operations**: Full CRUD operations plus member management with granular permissions -- **Platform Management**: Complete platform lifecycle including statistics, import/export, and target platform operations -- **Applications Management**: Full application lifecycle with authentication method management -- **Session Monitoring**: Real-time session tracking, activity monitoring, and analytics -- **Enterprise Security**: Built on official ark-sdk-python with OAuth and comprehensive error handling - -## Configuration - -The server supports two authentication modes. It auto-detects which mode to use based on the environment variables present. - -### OAuth Per-User Mode (Recommended) - -Each connecting user authenticates with their own CyberArk Identity credentials via OAuth. The server verifies user identity from the OIDC JWT, then uses a **service account platform token** for all PCloud API calls. Requires an OAuth2 app configured in CyberArk Identity (see [CyberArk Identity Setup](docs/CYBERARK_IDENTITY_SETUP.md)). - -| Variable | Required | Description | -|----------|----------|-------------| -| `CYBERARK_IDENTITY_TENANT_URL` | Yes | CyberArk Identity tenant URL (e.g., `https://abc1234.id.cyberark.cloud`) | -| `CYBERARK_CLIENT_ID` | Yes | Service account login name (used for PCloud platform token) | -| `CYBERARK_CLIENT_SECRET` | Yes | Service account password | -| `CYBERARK_OAUTH_CLIENT_ID` | Yes | OIDC app client ID from Trust tab (used for DCR and JWT audience validation) | -| `CYBERARK_OAUTH_CLIENT_SECRET` | Yes | OIDC app client secret from Trust tab (injected server-side in /token proxy) | -| `MCP_TRANSPORT` | No | Transport protocol: `stdio`, `sse`, or `streamable-http` (default: `stdio`) | -| `MCP_HOST` | No | Server bind host (default: `127.0.0.1`) | -| `MCP_PORT` | No | Server bind port (default: `8000`) | - -### Legacy Service Account Mode - -A single shared service account authenticates all requests. Simpler setup but all operations run under one identity. - -| Variable | Required | Description | -|----------|----------|-------------| -| `CYBERARK_CLIENT_ID` | Yes | Your Service User username | -| `CYBERARK_CLIENT_SECRET` | Yes | Your Service User password | -| `MCP_TRANSPORT` | No | Transport protocol: `stdio`, `sse`, or `streamable-http` (default: `stdio`) | - -**For Claude Desktop/Claude Code**: Pass these directly in the configuration (see [Client Integration](#client-integration)). No `.env` file is needed. - -**For local development/testing**: Create a `.env` file in the project root directory: - -```bash -# OAuth per-user mode (recommended) -# Service account — for PCloud API access via platform token -CYBERARK_CLIENT_ID=mcp-service@cyberark.cloud.XXXX -CYBERARK_CLIENT_SECRET=service-user-password -# OIDC app — from Trust tab, for DCR -CYBERARK_OAUTH_CLIENT_ID=your-oidc-app-client-id -CYBERARK_OAUTH_CLIENT_SECRET=your-oidc-app-client-secret -CYBERARK_IDENTITY_TENANT_URL=https://abc1234.id.cyberark.cloud - -# OR legacy service account mode -CYBERARK_CLIENT_ID=your-service-user-username -CYBERARK_CLIENT_SECRET=your-service-user-password - -# Transport: stdio (default), sse, or streamable-http -# MCP_TRANSPORT=streamable-http -``` - -## Reverse Proxy Deployment - -When deploying behind a reverse proxy with OAuth enabled, you **must** configure the proxy to strip trailing slashes from request paths. MCP clients (e.g. Copilot Studio) POST to `/mcp/` (trailing slash), which causes a 307 redirect to `/mcp`. HTTP clients strip the `Authorization` header on redirect, breaking OAuth Bearer token authentication. - -Also set `MCP_SERVER_URL` to the public URL of your server so that OAuth discovery metadata contains reachable URLs. - -**Traefik example** (dynamic config): -```yaml -http: - middlewares: - strip-trailing-slash: - replacePathRegex: - regex: "^(/.+?)/$" - replacement: "${1}" - routers: - mcp: - rule: "Host(`mcp.example.com`)" - entryPoints: - - web-secure - service: mcp - middlewares: - - strip-trailing-slash - tls: - certResolver: myresolver - services: - mcp: - loadBalancer: - servers: - - url: "http://backend:8000" -``` - ## Troubleshooting | Issue | Solution | @@ -207,7 +144,7 @@ http: | Authentication failed | Verify Service User credentials in CyberArk Identity | | Permission errors | Ensure the Service User has appropriate Identity roles and safe permissions | | Connection issues | Verify you're using the `.cloud` domain (not `.com`) | -| OAuth 401 behind reverse proxy | Ensure the proxy strips trailing slashes (see Reverse Proxy Deployment above) | +| OAuth 401 behind reverse proxy | Ensure the proxy strips trailing slashes (see [Docker Deployment](#docker-deployment)) | | `uvx` not found | Install uv: `curl -LsSf https://astral.sh/uv/install.sh \| sh` | **Verify MCP server manually:** @@ -217,43 +154,21 @@ uvx --from git+https://github.com/aaearon/mcp-privilege-cloud.git mcp-privilege- ## Development -### Installation - ```bash git clone https://github.com/aaearon/mcp-privilege-cloud.git cd mcp-privilege-cloud uv sync -``` - -### Running Tests - -```bash uv run pytest # Run all tests uv run pytest --cov=mcp_privilege_cloud # Run with coverage -uv run pytest -m integration # Integration tests only -``` - -### Running the Server Locally - -```bash -uv run mcp-privilege-cloud # With uv -python -m mcp_privilege_cloud # Direct module execution +uv run mcp-privilege-cloud # Run the server locally ``` -### Testing with MCP Inspector - -```bash -npx @modelcontextprotocol/inspector -``` - -Configure with command `uv run mcp-privilege-cloud` and your credentials. - ## Documentation - **[API Reference](docs/API_REFERENCE.md)** - Complete tool specifications and parameters - **[Architecture](docs/ARCHITECTURE.md)** - System design and components - **[CyberArk Identity Setup](docs/CYBERARK_IDENTITY_SETUP.md)** - OAuth app configuration guide -- **[Development Guide](DEVELOPMENT.md)** - Contributing and development workflows +- **[Development Guide](docs/DEVELOPMENT.md)** - Contributing and development workflows - **[Testing Guide](docs/TESTING.md)** - Detailed testing instructions ## Security @@ -261,6 +176,7 @@ Configure with command `uv run mcp-privilege-cloud` and your credentials. - Never commit credentials to version control - Use secure environment variable management - Grant minimal required permissions to Service Users +- In OAuth mode, DCR returns public clients only -- secrets are injected server-side - Official SDK provides automatic token management and secure protocols ## License From cca32e8bb1b4a1fc4121b315e5f193f50a07a638 Mon Sep 17 00:00:00 2001 From: Tim Schindler Date: Sat, 7 Mar 2026 11:12:07 +0100 Subject: [PATCH 2/2] docs: fix stale test counts, tool counts, and remove superseded investigation doc - Update all test counts to 260 tests across 14 test files - Fix MCP Inspector tool counts from 13 to 53 - Fix safe tool count from 11 to 10 in API reference - Add missing Session Monitoring Tools section to API reference - Fix Health Monitoring -> Session Monitoring in API reference ToC - Fix DCR credential descriptions in architecture doc - Remove CLAUDE_AI_OAUTH_INVESTIGATION.md (superseded, issue resolved) - Remove references to deleted test files (test_token_bridge, test_response_models, test_typed_tools, test_pcloud_url_resolution) --- CLAUDE.md | 18 +-- docs/API_REFERENCE.md | 59 ++++++++- docs/ARCHITECTURE.md | 4 +- docs/CLAUDE_AI_OAUTH_INVESTIGATION.md | 177 -------------------------- docs/DEVELOPMENT.md | 46 ++++--- docs/TESTING.md | 12 +- 6 files changed, 98 insertions(+), 218 deletions(-) delete mode 100644 docs/CLAUDE_AI_OAUTH_INVESTIGATION.md diff --git a/CLAUDE.md b/CLAUDE.md index 8400194..4f8350d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ **BEFORE CODING**: 1. **Always read this entire CLAUDE.md file first** - Contains critical patterns and constraints -2. **Check current test status** - All changes must maintain 269+ passing tests +2. **Check current test status** - All changes must maintain 260+ passing tests 3. **Follow existing patterns** - Simplified architecture patterns are established and documented 4. **Use official SDK** - All CyberArk operations MUST use ark-sdk-python (never direct HTTP) 5. **MANDATORY: Use context7 MCP tools for ALL API documentation** - Before working with any library or API, use context7 MCP server tools to get up-to-date documentation @@ -98,7 +98,7 @@ Use context7 resolve-library-id and get-library-docs tools: **Current Status**: ✅ **SERVICE ACCOUNT TOKEN BRIDGE COMPLETE** - OAuth mode verifies user identity via OIDC JWT, then uses a shared service account platform token for all PCloud API calls. **Last Updated**: February 27, 2026 -**Recent Achievement**: Technical debt cleanup — removed dead code (session_manager.py, token_auth.py, HTTP bypasses, unused server methods), simplified AppContext to use `is_oauth` flag, fixed token_verifier exception handling, updated all documentation. 276 passing tests with zero regression. +**Recent Achievement**: Technical debt cleanup — removed dead code (session_manager.py, token_auth.py, HTTP bypasses, unused server methods), simplified AppContext to use `is_oauth` flag, fixed token_verifier exception handling, updated all documentation. 260 passing tests with zero regression. ## Architecture @@ -115,7 +115,7 @@ The server provides 53 MCP tools for comprehensive CyberArk operations, built on - **Applications Management Tools (8 tools)**: Complete application lifecycle - `list_applications`, `get_application_details`, `add_application`, `delete_application`, `list_application_auth_methods`, `get_application_auth_method_details`, `add_application_auth_method`, `delete_application_auth_method`, `get_applications_stats` - **Session Monitoring Tools (6 tools)**: Privileged session monitoring and analytics - `list_sessions`, `list_sessions_by_filter`, `get_session_details`, `list_session_activities`, `count_sessions`, `get_session_statistics` -> **Complete PCloud Coverage**: All tools provide comprehensive coverage of CyberArk's 5 PCloud services with enterprise-grade CRUD operations, advanced analytics, member management, and privileged session monitoring. Built on official ark-sdk-python library with 210+ passing tests and zero regression. +> **Complete PCloud Coverage**: All tools provide comprehensive coverage of CyberArk's 5 PCloud services with enterprise-grade CRUD operations, advanced analytics, member management, and privileged session monitoring. Built on official ark-sdk-python library with 260+ passing tests and zero regression. ## Enhanced Platform Data Combination @@ -274,7 +274,7 @@ The codebase underwent a systematic simplification process achieving **~27% code - **Simplified Testing**: Cleaner test patterns with reduced mocking complexity **Performance & Reliability**: -- **Zero Functional Regression**: All 261+ tests passing with complete functionality coverage +- **Zero Functional Regression**: All 260+ tests passing with complete functionality coverage - **Preserved SDK Integration**: Official ark-sdk-python patterns maintained - **Graceful Error Handling**: Centralized error management with consistent logging - **Backward Compatibility**: No breaking changes to MCP tool interfaces @@ -332,8 +332,8 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: - `exceptions.py` - Custom exceptions: CyberArkAPIError, SDK compatibility layer ### Testing Validation ✅ **VERIFIED** -- **261+ tests passing** - Zero functionality regression across all phases -- **Test Coverage Maintained** - 16 token verifier + 14 OAuth integration tests added +- **260+ tests passing** - Zero functionality regression across all phases +- **Test Coverage Maintained** - Token verifier + OAuth integration tests added - **Integration Tests Updated** - MCP tool parameter passing verified for all 53 tools - **Performance Baseline** - No degradation in execution performance @@ -404,7 +404,7 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: ## Testing Strategy -**Test Files**: 261+ total tests across 15 test files +**Test Files**: 260 total tests across 14 test files - `tests/test_core_functionality.py` - Authentication, server core, platform management (comprehensive error handling) - `tests/test_account_operations.py` - Account lifecycle management with CRUD operations - `tests/test_applications_service.py` - Applications service testing with authentication methods @@ -482,7 +482,7 @@ async def get_account_password(account_id: str) -> Dict[str, Any]: 2. **NEVER bypass patterns** - Always use @handle_sdk_errors decorator 3. **ALWAYS follow TDD** - Write failing test first, then implementation 4. **SDK-only operations** - Never create direct HTTP requests -5. **Preserve test coverage** - All 261+ tests must continue passing +5. **Preserve test coverage** - All 260+ tests must continue passing 6. **Use existing models** - Leverage ark-sdk-python model classes **🔍 Mandatory Context7 Workflow**: @@ -493,7 +493,7 @@ async def get_account_password(account_id: str) -> Dict[str, Any]: - get-library-docs with the resolved ID 2. Write failing test using current patterns 3. Implement using up-to-date SDK methods -4. Verify all 261+ tests still pass +4. Verify all 260+ tests still pass ``` ## References diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 46761f3..842a3cd 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -12,7 +12,7 @@ Comprehensive API reference for the CyberArk Privilege Cloud MCP Server. This gu - [Platform Management Tools](#platform-management-tools) - [Applications Management Tools](#applications-management-tools) - [Password Management Tools](#password-management-tools) -- [Health Monitoring Tools](#health-monitoring-tools) +- [Session Monitoring Tools](#session-monitoring-tools) - [Error Handling](#error-handling) - [Usage Examples](#usage-examples) - [Integration Patterns](#integration-patterns) @@ -294,7 +294,7 @@ await client.call_tool("create_account", { ## Safe Management Tools -**🤖 LLM REFERENCE**: This section documents core safe tools. The server provides 11 total safe management tools including: `add_safe`, `update_safe`, `delete_safe`, `list_safe_members`, `get_safe_member_details`, `add_safe_member`, `update_safe_member`, `remove_safe_member`. For complete specifications of all tools, refer to `src/mcp_privilege_cloud/mcp_server.py` implementations using ArkPCloudSafesService. +**🤖 LLM REFERENCE**: This section documents core safe tools. The server provides 10 total safe management tools including: `add_safe`, `update_safe`, `delete_safe`, `list_safe_members`, `get_safe_member_details`, `add_safe_member`, `update_safe_member`, `remove_safe_member`. For complete specifications of all tools, refer to `src/mcp_privilege_cloud/mcp_server.py` implementations using ArkPCloudSafesService. ### `list_safes` @@ -674,6 +674,61 @@ await client.call_tool("reconcile_account_password", { } ``` +## Session Monitoring Tools + +**🤖 LLM REFERENCE**: This section documents session monitoring tools. The server provides 6 total session monitoring tools. For complete specifications of all tools, refer to `src/mcp_privilege_cloud/mcp_server.py` implementations using ArkSMService. + +### Core Operations (4 tools) + +#### `list_sessions` +**Description**: List all privileged sessions in CyberArk Privilege Cloud +**Parameters**: Standard listing parameters +**Returns**: Array of session objects with basic properties +**SDK Method**: `ArkSMService.list_sessions()` + +#### `list_sessions_by_filter` +**Description**: List sessions matching specific filter criteria +**Parameters**: `filter` (required) - Filter expression for sessions +**Returns**: Array of matching session objects +**SDK Method**: `ArkSMService.list_sessions_by_filter()` + +#### `get_session_details` +**Description**: Get detailed information about a specific session +**Parameters**: `session_id` (required) +**Returns**: Complete session object with all properties +**SDK Method**: `ArkSMService.get_session_details()` + +#### `count_sessions` +**Description**: Count sessions matching optional criteria +**Parameters**: Optional filter parameters +**Returns**: Session count +**SDK Method**: `ArkSMService.count_sessions()` + +### Activity Tracking (2 tools) + +#### `list_session_activities` +**Description**: List activities within a specific session +**Parameters**: `session_id` (required) +**Returns**: Array of session activity objects +**SDK Method**: `ArkSMService.list_session_activities()` + +#### `get_session_statistics` +**Description**: Get comprehensive session statistics and analytics +**Parameters**: None +**Returns**: Session statistics object with counts and distribution data +**SDK Method**: `ArkSMService.get_session_statistics()` + +### Usage Patterns + +```python +# Session monitoring workflow +sessions = await client.call_tool("list_sessions", {}) +active = await client.call_tool("list_sessions_by_filter", {"filter": "Status eq Active"}) +details = await client.call_tool("get_session_details", {"session_id": "sess123"}) +activities = await client.call_tool("list_session_activities", {"session_id": "sess123"}) +stats = await client.call_tool("get_session_statistics", {}) +``` + ## Error Handling ### Standard Error Responses diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 60fa5ab..526cca1 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -164,8 +164,8 @@ Server Method → SDK Service → CyberArk API → SDK Response → MCP Response - `CYBERARK_IDENTITY_TENANT_URL` - CyberArk Identity tenant URL (e.g., `https://abc1234.id.cyberark.cloud`) - `CYBERARK_CLIENT_ID` - Service account login name (for PCloud platform token) - `CYBERARK_CLIENT_SECRET` - Service account password -- `CYBERARK_OAUTH_CLIENT_ID` - OIDC app client ID from Trust tab (for DCR) -- `CYBERARK_OAUTH_CLIENT_SECRET` - OIDC app client secret from Trust tab (for DCR) +- `CYBERARK_OAUTH_CLIENT_ID` - OIDC app client ID from Trust tab (for DCR and JWT audience) +- `CYBERARK_OAUTH_CLIENT_SECRET` - OIDC app client secret from Trust tab (injected server-side in /token proxy) - `MCP_TRANSPORT` - Transport protocol: `stdio`, `sse`, or `streamable-http` (default: `stdio`) - `MCP_HOST` - Server bind host (default: `127.0.0.1`) - `MCP_PORT` - Server bind port (default: `8000`) diff --git a/docs/CLAUDE_AI_OAUTH_INVESTIGATION.md b/docs/CLAUDE_AI_OAUTH_INVESTIGATION.md deleted file mode 100644 index 3694a50..0000000 --- a/docs/CLAUDE_AI_OAUTH_INVESTIGATION.md +++ /dev/null @@ -1,177 +0,0 @@ -# Claude.ai Remote MCP OAuth Integration — Investigation Report - -## Goal - -Connect the MCP Privilege Cloud server as a **Remote MCP Server** in claude.ai using OAuth 2.1 with CyberArk Identity as the authorization server. - -## Background - -Claude.ai supports adding Remote MCP Servers that require OAuth authentication. The MCP spec (2025-03-26) defines a discovery and authorization flow based on: - -- **RFC 9728** — OAuth 2.0 Protected Resource Metadata (`/.well-known/oauth-protected-resource`) -- **RFC 8414** — OAuth 2.0 Authorization Server Metadata (`/.well-known/oauth-authorization-server`) -- **RFC 7591** — OAuth 2.0 Dynamic Client Registration (`POST /register`) -- **OAuth 2.1** — Authorization Code + PKCE - -Our server delegates authentication to CyberArk Identity (an external authorization server) rather than being its own authorization server. This creates a mismatch because: - -1. FastMCP only creates `/.well-known/oauth-authorization-server` when acting as its own auth server (via `auth_server_provider`) -2. CyberArk Identity serves `/.well-known/openid-configuration` (OIDC) but NOT `/.well-known/oauth-authorization-server` (RFC 8414) - -## What We Implemented - -### 1. RFC 8414 Authorization Server Metadata Endpoint (WORKING) - -**Problem**: claude.ai fetches `/.well-known/oauth-authorization-server` from the MCP server and gets 404. - -**Solution**: Added a `custom_route` on FastMCP that fetches CyberArk Identity's `/.well-known/openid-configuration`, caches it, and maps it to RFC 8414 format. - -``` -GET https://mcp.ams.iosharp.com/.well-known/oauth-authorization-server -→ 200 OK with authorization_endpoint, token_endpoint, registration_endpoint, etc. -``` - -**Key detail — app-specific endpoints**: CyberArk Identity's tenant-level OIDC discovery returns generic endpoints (`/Oauth/Openid`, `/Oauth/GetToken`) that don't bind to a specific OIDC app. These fail with a generic error page. The correct endpoints include the app ID in the path: - -- `/OAuth2/Authorize/{app_id}` (not `/Oauth/Openid`) -- `/OAuth2/Token/{app_id}` (not `/Oauth/GetToken`) - -### 2. Protected Resource Metadata — `authorization_servers` Fix (WORKING) - -**Problem**: FastMCP populates `authorization_servers` in `/.well-known/oauth-protected-resource` from `AuthSettings.issuer_url`. We initially set this to CyberArk Identity's tenant URL, so claude.ai fetched `/.well-known/oauth-authorization-server` from CyberArk Identity (which doesn't serve it) rather than from our server. - -**Solution**: Set `issuer_url` to our own server URL (`MCP_SERVER_URL`). This makes `authorization_servers` point to our server, where we serve the proxied metadata. - -```python -kwargs["auth"] = AuthSettings( - issuer_url=AnyHttpUrl(server_url), # our server, NOT tenant_url - resource_server_url=AnyHttpUrl(server_url), -) -``` - -### 3. Dynamic Client Registration Proxy (WORKING) - -**Problem**: claude.ai requires RFC 7591 Dynamic Client Registration to obtain `client_id` (and optionally `client_secret`) before starting the OAuth flow. Without a `registration_endpoint` in the metadata, claude.ai can't proceed. - -**Solution**: Added a `/register` custom route that returns pre-configured CyberArk Identity OIDC app credentials from environment variables. - -``` -POST https://mcp.ams.iosharp.com/register -← 201 Created { "client_id": "...", "client_secret": "...", "token_endpoint_auth_method": "client_secret_post" } -``` - -The DCR response uses: -- `CYBERARK_CLIENT_ID` env var as `client_id` (falls back to `CYBERARK_OIDC_APP_ID`) -- `CYBERARK_CLIENT_SECRET` env var as `client_secret` (if set; otherwise public client) - -### 4. Custom OIDC App in CyberArk Identity (PARTIALLY WORKING) - -**Problem**: The built-in `__idaptive_cybr_user_oidc` app doesn't allow adding redirect URIs, so claude.ai's callback URL (`https://claude.ai/api/mcp/auth_callback`) couldn't be registered. - -**Solution**: Created a custom OIDC app `mcpprivilegecloud` in CyberArk Identity with the claude.ai callback as an allowed redirect URI. - -The OIDC app ID is configurable via `CYBERARK_OIDC_APP_ID` env var (default: `mcpprivilegecloud`). - -## What Worked End-to-End - -The following steps complete successfully: - -| Step | Endpoint | Status | -|------|----------|--------| -| 1. Initial request | `POST /mcp` | 401 Unauthorized (correct) | -| 2. Protected resource discovery | `GET /.well-known/oauth-protected-resource` | 200 OK | -| 3. Authorization server discovery | `GET /.well-known/oauth-authorization-server` | 200 OK | -| 4. Dynamic Client Registration | `POST /register` | 201 Created | -| 5. Redirect to CyberArk Identity | Browser → `/OAuth2/Authorize/mcpprivilegecloud` | 302 → login page | -| 6. User authentication | CyberArk Identity login form | User authenticates successfully | -| 7. Authorization code issuance | CyberArk Identity → callback | **FAILS: `invalid_client` / `invalid client creds`** | - -## Where It Fails — The Blocking Issue - -After the user successfully authenticates with CyberArk Identity, the authorization server returns an error instead of an authorization code: - -``` -https://claude.ai/api/mcp/auth_callback?error=invalid_client&error_description=invalid%20client%20creds -``` - -This means CyberArk Identity **authenticated the user** but **rejected the OAuth client** when trying to issue the authorization code. - -### Root Cause Analysis - -CyberArk Identity's OIDC app configuration does not appear to support the standard OAuth 2.1 authorization code flow as expected by MCP clients. Specifically: - -1. **The built-in `__idaptive_cybr_user_oidc` app** — Cannot modify redirect URIs, so it can't support claude.ai's callback URL. - -2. **Custom OIDC apps** — Can be created, but CyberArk Identity returns `invalid_client` after user authentication regardless of: - - Client ID type set to "Anything" - - App set to "Confidential" with matching `client_id` and `client_secret` - - Redirect URI properly registered - - All standard OAuth parameters present (response_type, code_challenge, scope, etc.) - -3. **The `invalid client creds` error** occurs AFTER user authentication, during the authorization code issuance step. This suggests CyberArk Identity's OIDC implementation has specific requirements for client validation that differ from standard OAuth 2.1. - -### Possible Explanations - -- CyberArk Identity may require a specific client authentication method during the authorization request (not just token exchange) -- The OIDC app may need additional configuration beyond what's visible in the admin UI (e.g., API-level settings, specific OAuth profile, or trust relationships) -- The `client_id` format expected by CyberArk Identity for custom apps may differ from what we're sending -- CyberArk Identity may not fully support the public/PKCE flow that MCP clients expect, or may require additional parameters - -## Files Modified - -| File | Purpose | -|------|---------| -| `src/mcp_privilege_cloud/mcp_server.py` | Added `_fetch_oidc_discovery()`, `_build_oauth_metadata()`, `_build_dcr_response()`, `_register_oauth_routes()` with custom routes for `/.well-known/oauth-authorization-server` and `/register` | -| `src/mcp_privilege_cloud/token_verifier.py` | Made `CYBERARK_OIDC_APP_ID` configurable via env var (default: `mcpprivilegecloud`) | -| `tests/test_oauth_metadata.py` | 16 tests covering OIDC discovery fetching/caching, metadata building, DCR response, route registration | -| `CLAUDE.md` | Updated status and test file listings | - -## Environment Variables (New/Changed) - -| Variable | Purpose | Default | -|----------|---------|---------| -| `CYBERARK_OIDC_APP_ID` | OIDC app ID for URL paths and token audience validation | `mcpprivilegecloud` | -| `CYBERARK_CLIENT_ID` | OAuth client_id returned in DCR response | Falls back to `CYBERARK_OIDC_APP_ID` | -| `CYBERARK_CLIENT_SECRET` | OAuth client_secret returned in DCR (confidential client) | None (public client) | - -## Likely Resolution: DCR Client ID Fix - -**Update (2026-02-26)**: CyberArk Identity OAuth2 Client apps do NOT provide their own client_id/client_secret. Instead, the `client_id` and `client_secret` come from a **service user** marked as "OAuth 2.0 confidential client". The service user's login name IS the `client_id` (format: `@cyberark.cloud.`), and the password IS the `client_secret`. - -This means `CYBERARK_CLIENT_ID` was already the correct value for DCR all along. The `invalid_client` error from Step 7 may instead be caused by: -- Missing trusted DNS domains (most likely) -- Client ID Type misconfiguration on the OAuth2 Client app -- Service user not properly marked as OAuth 2.0 confidential client - -Code changes made: -- `CYBERARK_OAUTH_CLIENT_ID`/`CYBERARK_OAUTH_CLIENT_SECRET` added as optional overrides (for cases where different credentials are needed for DCR vs legacy mode) -- DCR priority chain: `CYBERARK_OAUTH_CLIENT_ID` > `CYBERARK_CLIENT_ID` > `CYBERARK_OIDC_APP_ID` -- Token verifier audience uses same priority chain -- `DEPLOY_ENV` removed as dead code - -**To verify**: Ensure `CYBERARK_CLIENT_ID` is a service user marked as "OAuth 2.0 confidential client", trusted DNS domains are configured, then test the full claude.ai OAuth flow. - -## Other Next Steps - -1. **CyberArk Identity investigation** — If the DCR fix doesn't fully resolve the issue, determine the exact OIDC app configuration required: - - CyberArk support engagement - - Reviewing CyberArk Identity API documentation for OIDC app configuration - - Testing with CyberArk Identity's own OAuth playground/test tools - -2. **Alternative: Token proxy approach** — Instead of delegating the OAuth flow to CyberArk Identity, our MCP server could act as its own authorization server (using FastMCP's `auth_server_provider`) that: - - Handles the OAuth flow with claude.ai directly - - Authenticates users against CyberArk Identity on the backend - - Issues its own tokens to the MCP client - - This is the "Third-Party Authorization Flow" described in the MCP spec - -3. **Alternative: mcp-remote proxy** — Use the community `mcp-remote` tool as a bridge, which handles OAuth complexity for providers that don't fully support Dynamic Client Registration. - -## References - -- [MCP Authorization Specification (2025-03-26)](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) -- [Building custom connectors via remote MCP servers (claude.ai)](https://support.claude.com/en/articles/11503834-building-custom-connectors-via-remote-mcp-servers) -- [RFC 8414 — OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) -- [RFC 7591 — OAuth 2.0 Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) -- [RFC 9728 — OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) -- [Claude OAuth requires DCR — GitHub Issue](https://github.com/anthropics/claude-code/issues/2527) -- [Evolving OAuth Client Registration in MCP](https://blog.modelcontextprotocol.io/posts/client_registration/) diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index cb5c10d..f307d7c 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -247,22 +247,19 @@ tests/ ├── test_enhanced_error_handling.py # Error handling validation ├── test_enhanced_error_messages.py # Error message consistency ├── test_token_verifier.py # JWT verification -├── test_token_bridge.py # Token bridge tests ├── test_oauth_integration.py # OAuth integration ├── test_oauth_metadata.py # RFC 8414 metadata ├── test_transport.py # Transport configuration ├── test_env_var_resolution.py # Env var priority chain -├── test_pcloud_url_resolution.py # PCloud URL resolution ├── test_context_injection.py # Context injection ├── test_lifespan.py # Lifespan management -├── test_response_models.py # Response models -└── test_typed_tools.py # Typed tool validation +└── test_account_operations.py # Account lifecycle management ``` ### Running Tests ```bash -# All tests (292 total) +# All tests (260 total) uv run pytest # Specific test categories @@ -474,7 +471,7 @@ npx @modelcontextprotocol/inspector npx @modelcontextprotocol/inspector -e CYBERARK_CLIENT_ID=your-client-id -e CYBERARK_CLIENT_SECRET=your-secret uvx --from git+https://github.com/aaearon/mcp-privilege-cloud.git mcp-privilege-cloud ``` -**List available tools (should return 13):** +**List available tools (should return 53):** ```bash npx @modelcontextprotocol/inspector --cli -e CYBERARK_CLIENT_ID=your-client-id -e CYBERARK_CLIENT_SECRET=your-secret uvx --from git+https://github.com/aaearon/mcp-privilege-cloud.git mcp-privilege-cloud --method tools/list ``` @@ -498,17 +495,28 @@ npx @modelcontextprotocol/inspector --cli -e CYBERARK_CLIENT_ID=your-client-id - #### Tool Categories and Testing ```bash -# Data Access Tools (7 tools) -list_accounts, get_account_details, search_accounts -list_safes, get_safe_details -list_platforms, get_platform_details - -# Account Management Tools (5 tools) -create_account, change_account_password, set_next_password -verify_account_password, reconcile_account_password - -# Platform Management Tools (1 tool) -import_platform_package +# Account Management Tools (18 tools) +list_accounts, get_account_details, search_accounts, create_account, +update_account, delete_account, change_account_password, set_next_password, +verify_account_password, reconcile_account_password, and 8 more analytics tools + +# Safe Management Tools (10 tools) +list_safes, get_safe_details, add_safe, update_safe, delete_safe, +list_safe_members, get_safe_member_details, add_safe_member, +update_safe_member, remove_safe_member + +# Platform Management Tools (10 tools) +list_platforms, get_platform_details, import_platform_package, +export_platform, duplicate_target_platform, activate/deactivate_target_platform, +delete_target_platform, get_platform_statistics, get_target_platform_statistics + +# Applications Management Tools (9 tools) +list_applications, get_application_details, add_application, delete_application, +list_application_auth_methods, and 4 more auth method + stats tools + +# Session Monitoring Tools (6 tools) +list_sessions, list_sessions_by_filter, get_session_details, +list_session_activities, count_sessions, get_session_statistics ``` ### Troubleshooting for LLMs @@ -529,7 +537,7 @@ npx @modelcontextprotocol/inspector --cli [env-vars] uvx --from git+https://gith **"No tools listed" or "Connection failed"** - **Cause**: Environment variables incorrect or missing -- **Solution**: Verify all 4 required environment variables are set correctly +- **Solution**: Verify all 2 required environment variables (legacy mode) or 5 (OAuth mode) are set correctly - **Debug**: Check that variable names match exactly (case-sensitive) **"401 Unauthorized"** @@ -552,7 +560,7 @@ When validating this MCP server, follow this systematic approach: #### Step 1: Basic Connectivity ```bash -# Verify 13 tools are available +# Verify 53 tools are available npx @modelcontextprotocol/inspector --cli [env-vars] uvx --from git+https://github.com/aaearon/mcp-privilege-cloud.git mcp-privilege-cloud --method tools/list ``` diff --git a/docs/TESTING.md b/docs/TESTING.md index 33e7e7d..1dc1720 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -4,7 +4,7 @@ Testing guide for LLM development of the CyberArk Privilege Cloud MCP Server. Fo ## Current Test Status ✅ **VERIFIED** -**Test Suite Results**: **269 tests passing** +**Test Suite Results**: **260 tests passing** **Code Coverage**: Comprehensive coverage across all 53 tools **Integration Testing**: All 53 MCP tools verified across all services with proper parameter passing @@ -101,9 +101,6 @@ The test suite is organized into specialized test files with comprehensive cover - CyberArkTokenVerifier JWT verification tests - JWKS endpoint validation -#### `tests/test_token_bridge.py` -- Service account token bridge testing - #### `tests/test_oauth_integration.py` - Full OAuth integration: dual-mode, execute_tool, lifespan @@ -119,9 +116,6 @@ The test suite is organized into specialized test files with comprehensive cover #### `tests/test_env_var_resolution.py` - Environment variable priority chain tests -#### `tests/test_pcloud_url_resolution.py` -- PCloud URL resolution and subdomain override tests - #### `tests/test_enhanced_error_handling.py` - Enhanced error handling validation @@ -129,7 +123,7 @@ The test suite is organized into specialized test files with comprehensive cover - Error message consistency testing ### Test Coverage Metrics -- **Total Tests**: 269 tests across 16 test files +- **Total Tests**: 260 tests across 14 test files - **Target Coverage**: Minimum 80% code coverage maintained across 53 tools - **Mock Strategy**: All external CyberArk API dependencies are mocked using official SDK patterns - **Test Types**: Unit, integration, MCP tools tests across all 5 PCloud services @@ -193,6 +187,6 @@ For interactive testing of the MCP server against a live CyberArk environment, u # Run MCP Inspector npx @modelcontextprotocol/inspector -# Run all pytest tests (269 tests) +# Run all pytest tests (260 tests) uv run pytest ``` \ No newline at end of file