diff --git a/claude_plugins/prowler/.claude-plugin/plugin.json b/claude_plugins/prowler/.claude-plugin/plugin.json index 7bf822e2e7..c77187c3b0 100644 --- a/claude_plugins/prowler/.claude-plugin/plugin.json +++ b/claude_plugins/prowler/.claude-plugin/plugin.json @@ -22,7 +22,7 @@ "api_key": { "type": "string", "title": "Prowler API key", - "description": "API key token used to authenticate with Prowler Cloud / Prowler App via the Prowler MCP server. Create one at https://cloud.prowler.com.", + "description": "API key token used to authenticate with Prowler (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server) via the Prowler MCP server. Create one at https://cloud.prowler.com.", "sensitive": true, "required": true } diff --git a/claude_plugins/prowler/skills/framework-compliance-triage/SKILL.md b/claude_plugins/prowler/skills/framework-compliance-triage/SKILL.md index 1af29f82b9..f8a9ded0c6 100644 --- a/claude_plugins/prowler/skills/framework-compliance-triage/SKILL.md +++ b/claude_plugins/prowler/skills/framework-compliance-triage/SKILL.md @@ -38,12 +38,12 @@ If the framework is not supported, tell the user, suggest they request it or con ### 1.1 Connect to Prowler Cloud -Verify the Prowler MCP connection by calling `prowler_app_search_providers` — a successful response returns the list of providers. If the call fails, walk the user through troubleshooting: internet connectivity, Prowler Cloud credentials, and permissions on the Prowler Cloud account. +Verify the Prowler MCP connection by calling `prowler_search_providers` — a successful response returns the list of providers. If the call fails, walk the user through troubleshooting: internet connectivity, Prowler Cloud credentials, and permissions on the Prowler Cloud account. For getting accurate information about configurations use `prowler_docs_search` to pull relevant instructions from the Prowler documentation. ### 1.2 Verify the provider is configured (or configure it) -Call `prowler_app_search_providers` to check whether the target provider (AWS account, Azure Subscription, GitHub Account...) exists in the user's Prowler Cloud account. Handle the result based on what's found: +Call `prowler_search_providers` to check whether the target provider (AWS account, Azure Subscription, GitHub Account...) exists in the user's Prowler Cloud account. Handle the result based on what's found: - **Provider not present.** Guide the user through adding and configuring it. Retrieve the relevant connection, credential, and permission instructions with `prowler_docs_search`. - **Provider present but misconfigured** (missing credentials, insufficient permissions, etc.). Walk the user through fixing the configuration, pulling the relevant guidance with `prowler_docs_search`. @@ -57,15 +57,15 @@ Call `prowler_app_search_providers` to check whether the target provider (AWS ac The flow needs at least one completed scan with a compliance report available. -Look for a completed scan first: call `prowler_app_list_scans` with the selected `provider_id` and `state: ["completed"]`, then call `prowler_app_get_compliance_overview` with each `scan_id` to find one whose compliance report is available. If one is found, continue to the next section. +Look for a completed scan first: call `prowler_list_scans` with the selected `provider_id` and `state: ["completed"]`, then call `prowler_get_compliance_overview` with each `scan_id` to find one whose compliance report is available. If one is found, continue to the next section. -If no completed scan has a report, call `prowler_app_list_scans` again with `state: ["available", "executing"]` to detect a scan in progress. +If no completed scan has a report, call `prowler_list_scans` again with `state: ["available", "executing"]` to detect a scan in progress. > **Checkpoint — Scan-in-progress decision** *(conditional: an in-progress scan was detected)* > > Tell the user a scan is already running and ask whether to wait for it to complete or start a fresh one. Wait for the answer. -If no scan is running (or the user chose to start a fresh one), trigger a new scan with `prowler_app_trigger_scan` and the `provider_id`. The link `https://cloud.prowler.com/scans?filter%5Bprovider_uid__in%5D={provider_id}` lets the user monitor progress. +If no scan is running (or the user chose to start a fresh one), trigger a new scan with `prowler_trigger_scan` and the `provider_id`. The link `https://cloud.prowler.com/scans?filter%5Bprovider_uid__in%5D={provider_id}` lets the user monitor progress. When a scan is in progress (either pre-existing and elected to wait, or just triggered), stop the flow and ask the user to return when it's completed — restart this section to re-check the results. @@ -85,7 +85,7 @@ Status taxonomy for failed requirements and their findings: ### Report template -A fresh report is rendered like this (substituting values from the `prowler_app_get_compliance_framework_state_details` Prowler MCP tool response): +A fresh report is rendered like this (substituting values from the `prowler_get_compliance_framework_state_details` Prowler MCP tool response): ````markdown # Compliance report: @@ -120,7 +120,7 @@ A fresh report is rendered like this (substituting values from the `prowler_app_ Resolve the report path for the current `compliance_id` and provider account. -If the file does not exist, call `prowler_app_get_compliance_framework_state_details` for the target scan, render the template above, and write the file with one initialization entry in the activity log. +If the file does not exist, call `prowler_get_compliance_framework_state_details` for the target scan, render the template above, and write the file with one initialization entry in the activity log. If the file exists, read it and compare its `Scan ID` to the target scan from section 1.3. When the scan matches, reuse the file and summarize remaining `[FAIL]` and `[IN PROGRESS]` items in chat. @@ -128,7 +128,7 @@ If the file exists, read it and compare its `Scan ID` to the target scan from se > > Tell the user the report on disk was generated from a different scan and ask whether to refresh it from the new scan. Wait for the answer. -On confirmation, regenerate the failed-requirements section from the new `prowler_app_get_compliance_framework_state_details` response, carry forward the **Global remediation approach** block and the full activity log, and append an activity-log entry noting the scan change. +On confirmation, regenerate the failed-requirements section from the new `prowler_get_compliance_framework_state_details` response, carry forward the **Global remediation approach** block and the full activity log, and append an activity-log entry noting the scan change. Once the file is current, surface the top failing requirements in chat: sort by finding count descending, show the top 5 with their codes and counts, and point to the file path for the full list. @@ -174,7 +174,7 @@ Once approved, the loop proceeds through the batch without further prompts unles Pick the first `[FAIL]` requirement at the top of the failed-requirements section. Move its status and every finding under it to `[IN PROGRESS]`, and add a `**Fix plan**:` sub-bullet describing what will be done. -Call `prowler_app_get_finding_details` for each `finding_id` to retrieve the failing resource and the Prowler Hub's remediation guidance for that check using the tool `prowler_hub_get_check_details` with the `check_id` from the finding details. Summarize the guidance in chat, and append it to the `**Fix plan**` note for each finding. +Call `prowler_get_finding_details` for each `finding_id` to retrieve the failing resource and the Prowler Hub's remediation guidance for that check using the tool `prowler_hub_get_check_details` with the `check_id` from the finding details. Summarize the guidance in chat, and append it to the `**Fix plan**` note for each finding. If a finding does not apply to the target resource (Organization-only check on a User account, paid-tier feature, missing resource type, etc.), set the requirement status to `[SKIPPED]` with the reason, log it in the activity log, and move on without attempting the fix — even if it was missed during §3.2. @@ -194,6 +194,6 @@ Move to the next `[FAIL]` requirement and repeat from section 3.3. > **Checkpoint — Rescan trigger** *(conditional: no `[FAIL]` requirements remain; all are `[FIXED-UNVERIFIED]` or `[SKIPPED]`)* > -> Summarize what was applied, list any `[SKIPPED]` items with reasons, and ask whether to trigger a fresh scan with `prowler_app_trigger_scan` to verify the fixes end-to-end. Wait for the answer. +> Summarize what was applied, list any `[SKIPPED]` items with reasons, and ask whether to trigger a fresh scan with `prowler_trigger_scan` to verify the fixes end-to-end. Wait for the answer. On confirmation, trigger the rescan. When it completes, restart section 2.1 with the carry-forward path — requirements no longer in the new FAIL list move to `[PASS]`, anything still failing reverts to `[FAIL]` with the previous fix attempt visible in the activity log. diff --git a/docs/developer-guide/lighthouse-architecture.mdx b/docs/developer-guide/lighthouse-architecture.mdx index 631e0e7ae4..e12eff9549 100644 --- a/docs/developer-guide/lighthouse-architecture.mdx +++ b/docs/developer-guide/lighthouse-architecture.mdx @@ -132,7 +132,7 @@ The MCP client manages connections to the Prowler MCP Server using a singleton p - **Connection Management**: Retry logic with configurable attempts and delays - **Tool Discovery**: Fetches available tools from MCP server on initialization -- **Authentication Injection**: Automatically adds JWT tokens to `prowler_app_*` tool calls +- **Authentication Injection**: Automatically adds JWT tokens to `prowler_*` tool calls - **Reconnection**: Supports forced reconnection after server restarts Key constants: @@ -141,10 +141,14 @@ Key constants: - `RECONNECT_INTERVAL_MS`: 5 minutes before retry after failure ```typescript -// Authentication injection for prowler_app tools +// Authentication injection for core prowler_ tools (Hub/Docs excluded) private handleBeforeToolCall = ({ name, args }) => { - // Only inject auth for prowler_app_* tools (user-specific data) - if (!name.startsWith("prowler_app_")) { + // Only inject auth for prowler_* tools (user-specific data). + // The legacy prowler_app_ prefix is also accepted for a resilient rollout. + if ( + !name.startsWith("prowler_") && + !name.startsWith("prowler_app_") + ) { return { args }; } @@ -307,7 +311,7 @@ MCP tools are organized into three namespaces based on authentication requiremen | Namespace | Auth Required | Description | |-----------|---------------|-------------| -| `prowler_app_*` | Yes (JWT) | Prowler Cloud and Prowler Local Server tools for findings, providers, scans, resources | +| `prowler_*` | Yes (JWT) | Prowler Cloud, Prowler Private Cloud, and Prowler Local Server tools for findings, providers, scans, resources | | `prowler_hub_*` | No | Security checks catalog, compliance frameworks | | `prowler_docs_*` | No | Documentation search and retrieval | @@ -315,7 +319,7 @@ MCP tools are organized into three namespaces based on authentication requiremen 1. User authenticates with Prowler Local Server, receiving a JWT token 2. Token is stored in session and propagated via `authContextStorage` -3. MCP client injects `Authorization: Bearer ` header for `prowler_app_*` calls +3. MCP client injects `Authorization: Bearer ` header for `prowler_*` calls 4. MCP Server validates token and applies RLS filtering ### Tool Execution Pattern @@ -323,7 +327,7 @@ MCP tools are organized into three namespaces based on authentication requiremen The agent uses meta-tools rather than direct tool registration: ``` -Agent needs data → describe_tool("prowler_app_search_findings") +Agent needs data → describe_tool("prowler_search_findings") → Returns parameter schema → execute_tool with parameters → MCP client adds auth header → MCP Server executes → Results returned to agent → Agent continues reasoning diff --git a/docs/developer-guide/mcp-server.mdx b/docs/developer-guide/mcp-server.mdx index 1b9c49a18b..6d409ccc02 100644 --- a/docs/developer-guide/mcp-server.mdx +++ b/docs/developer-guide/mcp-server.mdx @@ -18,11 +18,15 @@ The Prowler MCP Server brings the entire Prowler ecosystem to AI assistants thro The server follows a modular architecture with three independent sub-servers: -| Sub-Server | Auth Required | Description | -|------------|---------------|-------------| -| `prowler_app` | Yes | Full access to Prowler Cloud and Prowler Local Server features | -| Prowler Hub | No | Security checks catalog with **over 2,000 checks**, fixers, and **70+ compliance frameworks** | -| Prowler Documentation | No | Full-text search and retrieval of official documentation | +| Sub-Server | Tool Prefix | Auth Required | Description | +|------------|-------------|---------------|-------------| +| Prowler | `prowler_` | Yes | Full access to Prowler Cloud, Prowler Private Cloud, and Prowler Local Server features | +| Prowler Hub | `prowler_hub_` | No | Security checks catalog with **over 2,000 checks**, fixers, and **70+ compliance frameworks** | +| Prowler Documentation | `prowler_docs_` | No | Full-text search and retrieval of official documentation | + + +The core Prowler sub-server is served under the `prowler_` tool prefix, while its source lives in the `prowler_app/` module for historical reasons. Tool names use the prefix; import paths use the module. + For a complete list of tools and their descriptions, see the [Tools Reference](/getting-started/basic-usage/prowler-mcp-tools). @@ -413,7 +417,7 @@ uv run prowler-mcp uv run prowler-mcp --transport http --host 0.0.0.0 --port 8000 # Run with environment variables -PROWLER_APP_API_KEY="pk_xxx" uv run prowler-mcp +PROWLER_API_KEY="pk_xxx" uv run prowler-mcp ``` For complete installation and deployment options, see: diff --git a/docs/docs.json b/docs/docs.json index d9ac4c2bd8..b9bc195182 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -72,9 +72,9 @@ "group": "Prowler MCP", "pages": [ "getting-started/products/prowler-mcp", - "getting-started/installation/prowler-mcp", "getting-started/basic-usage/prowler-mcp", - "getting-started/basic-usage/prowler-mcp-tools" + "getting-started/basic-usage/prowler-mcp-tools", + "getting-started/installation/prowler-mcp" ] }, { diff --git a/docs/getting-started/basic-usage/prowler-mcp-tools.mdx b/docs/getting-started/basic-usage/prowler-mcp-tools.mdx index d225617f0e..acb50c9e81 100644 --- a/docs/getting-started/basic-usage/prowler-mcp-tools.mdx +++ b/docs/getting-started/basic-usage/prowler-mcp-tools.mdx @@ -10,7 +10,7 @@ Complete reference guide for all tools available in the Prowler MCP Server. Tool |----------|------------|------------------------| | Prowler Hub | 10 tools | No | | Prowler Documentation | 2 tools | No | -| Prowler Cloud & Prowler Local Server | 32 tools | Yes | +| Prowler Cloud, Private Cloud & Local Server | 32 tools | Yes | ## Tool Naming Convention @@ -18,11 +18,11 @@ All tools follow a consistent naming pattern with prefixes: - `prowler_hub_*` - Prowler Hub catalog and compliance tools - `prowler_docs_*` - Prowler documentation search and retrieval -- `prowler_app_*` - Prowler Cloud and App (Self-Managed) management tools +- `prowler_*` - Prowler Cloud, Prowler Private Cloud & Prowler Local Server management tools -## Prowler Cloud and Prowler Local Server Tools +## Prowler Tools -Manage Prowler Cloud or Prowler Local Server features. **Requires authentication.** +Manage your Prowler deployment — Prowler Cloud, Prowler Private Cloud, or Prowler Local Server. **Requires authentication.** These tools require a valid API key. See the [Configuration Guide](/getting-started/basic-usage/prowler-mcp) for authentication setup. @@ -32,44 +32,44 @@ These tools require a valid API key. See the [Configuration Guide](/getting-star Tools for searching, viewing, and analyzing security findings across all cloud providers. -- **`prowler_app_search_security_findings`** - Search and filter security findings with advanced filtering options (severity, status, provider, region, service, check ID, date range, muted status) -- **`prowler_app_get_finding_details`** - Get comprehensive details about a specific finding including remediation guidance, check metadata, and resource relationships -- **`prowler_app_get_findings_overview`** - Get aggregate statistics and trends about security findings as a markdown report +- **`prowler_search_security_findings`** - Search and filter security findings with advanced filtering options (severity, status, provider, region, service, check ID, date range, muted status) +- **`prowler_get_finding_details`** - Get comprehensive details about a specific finding including remediation guidance, check metadata, and resource relationships +- **`prowler_get_findings_overview`** - Get aggregate statistics and trends about security findings as a markdown report ### Finding Groups Management Tools for listing finding groups aggregated by check ID, viewing complete group counters, and drilling down into affected resources. -- **`prowler_app_list_finding_groups`** - List latest or historical finding groups with filters for provider, region, service, resource, category, check, severity, status, muted state, delta, date range, and sorting -- **`prowler_app_get_finding_group_details`** - Get complete details for a specific finding group including counters, description, timestamps, and impacted providers -- **`prowler_app_list_finding_group_resources`** - List actionable unmuted resources affected by a finding group by default, including nested resource and provider data plus the `finding_id` for remediation details. Set `include_muted` to include suppressed resources +- **`prowler_list_finding_groups`** - List latest or historical finding groups with filters for provider, region, service, resource, category, check, severity, status, muted state, delta, date range, and sorting +- **`prowler_get_finding_group_details`** - Get complete details for a specific finding group including counters, description, timestamps, and impacted providers +- **`prowler_list_finding_group_resources`** - List actionable unmuted resources affected by a finding group by default, including nested resource and provider data plus the `finding_id` for remediation details. Set `include_muted` to include suppressed resources ### Provider Management Tools for managing cloud provider connections in Prowler. -- **`prowler_app_search_providers`** - Search and view configured providers with their connection status -- **`prowler_app_connect_provider`** - Register and connect a provider with credentials for security scanning -- **`prowler_app_delete_provider`** - Permanently remove a provider from Prowler +- **`prowler_search_providers`** - Search and view configured providers with their connection status +- **`prowler_connect_provider`** - Register and connect a provider with credentials for security scanning +- **`prowler_delete_provider`** - Permanently remove a provider from Prowler ### Scan Management Tools for managing and monitoring security scans. -- **`prowler_app_list_scans`** - List and filter security scans across all providers -- **`prowler_app_get_scan`** - Get comprehensive details about a specific scan (progress, duration, resource counts) -- **`prowler_app_trigger_scan`** - Trigger a manual security scan for a provider -- **`prowler_app_schedule_daily_scan`** - Schedule automated daily scans for continuous monitoring -- **`prowler_app_update_scan`** - Update scan name for better organization +- **`prowler_list_scans`** - List and filter security scans across all providers +- **`prowler_get_scan`** - Get comprehensive details about a specific scan (progress, duration, resource counts) +- **`prowler_trigger_scan`** - Trigger a manual security scan for a provider +- **`prowler_schedule_daily_scan`** - Schedule automated daily scans for continuous monitoring +- **`prowler_update_scan`** - Update scan name for better organization ### Resources Management Tools for searching, viewing, and analyzing cloud resources discovered by Prowler. -- **`prowler_app_list_resources`** - List and filter cloud resources with advanced filtering options (provider, region, service, resource type, tags) -- **`prowler_app_get_resource`** - Get comprehensive details about a specific resource including configuration, metadata, and finding relationships -- **`prowler_app_get_resource_events`** - Get the timeline of cloud API actions performed on a resource (AWS CloudTrail). Shows who did what and when, with full request/response payloads -- **`prowler_app_get_resources_overview`** - Get aggregate statistics about cloud resources as a markdown report +- **`prowler_list_resources`** - List and filter cloud resources with advanced filtering options (provider, region, service, resource type, tags) +- **`prowler_get_resource`** - Get comprehensive details about a specific resource including configuration, metadata, and finding relationships +- **`prowler_get_resource_events`** - Get the timeline of cloud API actions performed on a resource (AWS CloudTrail). Shows who did what and when, with full request/response payloads +- **`prowler_get_resources_overview`** - Get aggregate statistics about cloud resources as a markdown report ### Muting Management @@ -77,33 +77,33 @@ Tools for managing finding muting, including pattern-based bulk muting (mutelist #### Mutelist (Pattern-Based Muting) -- **`prowler_app_get_mutelist`** - Retrieve the current mutelist configuration for the tenant -- **`prowler_app_set_mutelist`** - Create or update the mutelist configuration for pattern-based bulk muting -- **`prowler_app_delete_mutelist`** - Remove the mutelist configuration from the tenant +- **`prowler_get_mutelist`** - Retrieve the current mutelist configuration for the tenant +- **`prowler_set_mutelist`** - Create or update the mutelist configuration for pattern-based bulk muting +- **`prowler_delete_mutelist`** - Remove the mutelist configuration from the tenant #### Mute Rules (Finding-Specific Muting) -- **`prowler_app_list_mute_rules`** - Search and filter mute rules with pagination support -- **`prowler_app_get_mute_rule`** - Retrieve comprehensive details about a specific mute rule -- **`prowler_app_create_mute_rule`** - Create a new mute rule to mute specific findings with documentation and audit trail -- **`prowler_app_update_mute_rule`** - Update a mute rule's name, reason, or enabled status -- **`prowler_app_delete_mute_rule`** - Delete a mute rule from the system +- **`prowler_list_mute_rules`** - Search and filter mute rules with pagination support +- **`prowler_get_mute_rule`** - Retrieve comprehensive details about a specific mute rule +- **`prowler_create_mute_rule`** - Create a new mute rule to mute specific findings with documentation and audit trail +- **`prowler_update_mute_rule`** - Update a mute rule's name, reason, or enabled status +- **`prowler_delete_mute_rule`** - Delete a mute rule from the system ### Attack Paths Analysis Tools for analyzing privilege escalation chains and security misconfigurations using graph-based analysis. Attack Paths maps relationships between cloud resources, permissions, and security findings to detect how privileges can be escalated and how misconfigurations can be exploited. -- **`prowler_app_list_attack_paths_scans`** - List Attack Paths scans with filtering by provider, provider type, and scan state (available, scheduled, executing, completed, failed, cancelled) -- **`prowler_app_list_attack_paths_queries`** - Discover available Attack Paths queries for a completed scan, including query names, descriptions, and required parameters -- **`prowler_app_run_attack_paths_query`** - Execute an Attack Paths query against a completed scan and retrieve graph results with nodes (cloud resources, findings, virtual nodes) and relationships (access paths, role assumptions, security group memberships) -- **`prowler_app_get_attack_paths_cartography_schema`** - Retrieve the Cartography graph schema (node labels, relationships, properties) for writing accurate custom openCypher queries +- **`prowler_list_attack_paths_scans`** - List Attack Paths scans with filtering by provider, provider type, and scan state (available, scheduled, executing, completed, failed, cancelled) +- **`prowler_list_attack_paths_queries`** - Discover available Attack Paths queries for a completed scan, including query names, descriptions, and required parameters +- **`prowler_run_attack_paths_query`** - Execute an Attack Paths query against a completed scan and retrieve graph results with nodes (cloud resources, findings, virtual nodes) and relationships (access paths, role assumptions, security group memberships) +- **`prowler_get_attack_paths_cartography_schema`** - Retrieve the Cartography graph schema (node labels, relationships, properties) for writing accurate custom openCypher queries ### Compliance Management Tools for viewing compliance status and framework details across all cloud providers. -- **`prowler_app_get_compliance_overview`** - Get high-level compliance status across all frameworks for a specific scan or provider, including pass/fail statistics per framework -- **`prowler_app_get_compliance_framework_state_details`** - Get detailed requirement-level breakdown for a specific compliance framework, including failed requirements and associated finding IDs +- **`prowler_get_compliance_overview`** - Get high-level compliance status across all frameworks for a specific scan or provider, including pass/fail statistics per framework +- **`prowler_get_compliance_framework_state_details`** - Get detailed requirement-level breakdown for a specific compliance framework, including failed requirements and associated finding IDs ## Prowler Hub Tools @@ -145,7 +145,7 @@ Search and access official Prowler documentation. **No authentication required.* - Use natural language to interact with the tools through your AI assistant - Tools can be combined for complex workflows - Filter options are available on most list tools -- Authentication is only required for Prowler Cloud and Prowler Local Server tools +- Authentication is only required for Prowler tools (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server) ## Additional Resources diff --git a/docs/getting-started/basic-usage/prowler-mcp.mdx b/docs/getting-started/basic-usage/prowler-mcp.mdx index a06f54375e..120e5c038b 100644 --- a/docs/getting-started/basic-usage/prowler-mcp.mdx +++ b/docs/getting-started/basic-usage/prowler-mcp.mdx @@ -7,10 +7,10 @@ Configure your MCP client to connect to Prowler MCP Server. ## Step 1: Get Your API Key -**Authentication is optional**: Prowler Hub and Prowler Documentation features work without authentication. An API key is only required for Prowler Cloud and Prowler Local Server features. +**Authentication is optional**: Prowler Hub and Prowler Documentation features work without authentication. An API key is only required for Prowler tools (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server). -To use Prowler Cloud or Prowler Local Server features. To get the API key, please refer to the [API Keys](/user-guide/tutorials/prowler-app-api-keys) guide. +An API key authenticates the Prowler tools (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server). To get the API key, please refer to the [API Keys](/user-guide/tutorials/prowler-app-api-keys) guide. Keep the API key secure. Never share it publicly or commit it to version control. @@ -18,12 +18,14 @@ Keep the API key secure. Never share it publicly or commit it to version control ## Step 2: Configure Your MCP Host/Client -Choose the configuration based on your deployment: +Most users should use the **Cloud MCP Server** — it needs no installation and is maintained by Prowler. The [Local MCP Server](#local-mcp-server-configuration) configuration is provided afterwards for users who run the server themselves. -- **HTTP Mode**: Prowler Cloud MCP Server or self-hosted Prowler MCP Server. -- **STDIO Mode**: Local installation only (runs as subprocess of your MCP client). +- **Cloud MCP Server (HTTP)**: the managed server at `https://mcp.prowler.com/mcp` (or your own self-hosted HTTP server). +- **Local MCP Server (STDIO)**: local installation only (runs as a subprocess of your MCP client). -### HTTP Mode +## Cloud MCP Server Configuration (Recommended) + +Connect to the **Cloud MCP Server** at `https://mcp.prowler.com/mcp` over HTTP. This is the recommended path — no installation, always up to date. The same configuration works for a self-hosted HTTP server: just swap the URL. @@ -61,10 +63,10 @@ Choose the configuration based on your deployment: "args": [ "https://mcp.prowler.com/mcp", // or your self-hosted Prowler MCP Server URL "--header", - "Authorization: Bearer ${PROWLER_APP_API_KEY}" + "Authorization: Bearer ${PROWLER_API_KEY}" ], "env": { - "PROWLER_APP_API_KEY": "" + "PROWLER_API_KEY": "" } } } @@ -96,10 +98,10 @@ Choose the configuration based on your deployment: "args": [ "https://mcp.prowler.com/mcp", "--header", - "Authorization: Bearer ${PROWLER_APP_API_KEY}" + "Authorization: Bearer ${PROWLER_API_KEY}" ], "env": { - "PROWLER_APP_API_KEY": "" + "PROWLER_API_KEY": "" } } } @@ -110,8 +112,8 @@ Choose the configuration based on your deployment: Run the following command: ```bash - export PROWLER_APP_API_KEY="" - claude mcp add --transport http prowler https://mcp.prowler.com/mcp --header "Authorization: Bearer $PROWLER_APP_API_KEY" --scope user + export PROWLER_API_KEY="" + claude mcp add --transport http prowler https://mcp.prowler.com/mcp --header "Authorization: Bearer $PROWLER_API_KEY" --scope user ``` @@ -137,9 +139,9 @@ Choose the configuration based on your deployment: -### STDIO Mode +## Local MCP Server Configuration -STDIO mode is only available when running the MCP server locally. +STDIO mode is only available when running the **Local MCP Server** on your own machine. See the [Installation guide](/getting-started/installation/prowler-mcp) to set it up first. @@ -152,7 +154,7 @@ STDIO mode is only available when running the MCP server locally. "command": "uvx", "args": ["/absolute/path/to/prowler/mcp_server/"], "env": { - "PROWLER_APP_API_KEY": "", + "PROWLER_API_KEY": "", "API_BASE_URL": "https://api.prowler.com/api/v1" } } @@ -179,7 +181,7 @@ STDIO mode is only available when running the MCP server locally. "--rm", "-i", "--env", - "PROWLER_APP_API_KEY=", + "PROWLER_API_KEY=", "--env", "API_BASE_URL=https://api.prowler.com/api/v1", "prowlercloud/prowler-mcp" @@ -205,7 +207,7 @@ Restart your MCP client and start asking questions: ## Authentication Methods -Prowler MCP Server supports two authentication methods to connect to Prowler Cloud or Prowler Local Server: +Prowler MCP Server supports two authentication methods to connect to Prowler (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server): ### API Key (Recommended) diff --git a/docs/getting-started/installation/prowler-mcp.mdx b/docs/getting-started/installation/prowler-mcp.mdx index 06f204da6a..5be469b5b2 100644 --- a/docs/getting-started/installation/prowler-mcp.mdx +++ b/docs/getting-started/installation/prowler-mcp.mdx @@ -5,12 +5,12 @@ title: "Installation" There are **two ways** to use Prowler MCP Server: - + **No installation required** - Just configuration Use `https://mcp.prowler.com/mcp` - + **Local installation** - Full control Install via Docker, PyPI, or source code @@ -18,8 +18,8 @@ There are **two ways** to use Prowler MCP Server: -For "Option 1: Managed by Prowler", go directly to the [Configuration Guide](/getting-started/basic-usage/prowler-mcp#hosted-server-configuration-recommended) to set up your Claude Desktop, Cursor, or other MCP client. -**This guide is focused on local installation, "Option 2: Run Locally"**. +For the Cloud MCP Server, go directly to the [Configuration Guide](/getting-started/basic-usage/prowler-mcp#cloud-mcp-server-configuration-recommended) to set up your Claude Desktop, Cursor, or other MCP client. +**This guide is focused on local installation, the Local MCP Server**. ## Installation Methods @@ -51,7 +51,7 @@ Choose one of the following installation methods: ```bash docker run --rm -i \ - -e PROWLER_APP_API_KEY="pk_your_api_key" \ + -e PROWLER_API_KEY="pk_your_api_key" \ -e API_BASE_URL="https://api.prowler.com/api/v1" \ prowlercloud/prowler-mcp ``` @@ -143,7 +143,7 @@ Choose one of the following installation methods: ## Updating Prowler MCP Server -When running Prowler MCP Server locally ("Option 2: Run Locally"), upgrade to the latest version using the same method chosen for installation. The hosted server (`https://mcp.prowler.com/mcp`) is always kept up to date by Prowler and requires no action. +When running the Local MCP Server, upgrade to the latest version using the same method chosen for installation. The Cloud MCP Server (`https://mcp.prowler.com/mcp`) is always kept up to date by Prowler and requires no action. @@ -219,19 +219,19 @@ Configure the server using environment variables: | Variable | Description | Required | Default | |----------|-------------|----------|---------| -| `PROWLER_APP_API_KEY` | Prowler API key | Only for STDIO mode | - | +| `PROWLER_API_KEY` | Prowler API key | Only for STDIO mode | - | | `API_BASE_URL` | Custom Prowler API endpoint | No | `https://api.prowler.com/api/v1` | | `PROWLER_MCP_TRANSPORT_MODE` | Default transport mode (overwritten by `--transport` argument) | No | `stdio` | ```bash macOS/Linux -export PROWLER_APP_API_KEY="pk_your_api_key_here" +export PROWLER_API_KEY="pk_your_api_key_here" export API_BASE_URL="https://api.prowler.com/api/v1" export PROWLER_MCP_TRANSPORT_MODE="http" ``` ```bash Windows PowerShell -$env:PROWLER_APP_API_KEY="pk_your_api_key_here" +$env:PROWLER_API_KEY="pk_your_api_key_here" $env:API_BASE_URL="https://api.prowler.com/api/v1" $env:PROWLER_MCP_TRANSPORT_MODE="http" ``` @@ -246,7 +246,7 @@ Never commit your API key to version control. Use environment variables or secur For convenience, create a `.env` file in the `mcp_server` directory: ```bash .env -PROWLER_APP_API_KEY=pk_your_api_key_here +PROWLER_API_KEY=pk_your_api_key_here API_BASE_URL=https://api.prowler.com/api/v1 PROWLER_MCP_TRANSPORT_MODE=stdio ``` diff --git a/docs/getting-started/products/prowler-mcp.mdx b/docs/getting-started/products/prowler-mcp.mdx index b35ac3d611..93159b2e7d 100644 --- a/docs/getting-started/products/prowler-mcp.mdx +++ b/docs/getting-started/products/prowler-mcp.mdx @@ -8,8 +8,29 @@ title: "Overview" **Preview Feature**: This MCP server is currently under active development. Features and functionality may change. We welcome your feedback—please report any issues on [GitHub](https://github.com/prowler-cloud/prowler/issues) or join our [Slack community](https://goto.prowler.com/slack) to discuss and share your thoughts. +## Quickest Way to Connect: Cloud MCP Server + +The fastest way to get started is the **Cloud MCP Server** at `https://mcp.prowler.com/mcp` — no installation, always up to date, and maintained by Prowler. Just point your MCP client at the URL and authenticate with a [Prowler API key](/user-guide/tutorials/prowler-app-api-keys) as a Bearer token: + +```json +{ + "mcpServers": { + "prowler": { + "url": "https://mcp.prowler.com/mcp", + "headers": { + "Authorization": "Bearer " + } + } + } +} +``` + + + Step-by-step setup for Claude Desktop, Claude Code, Cursor, and other clients. + + -Prowler MCP Server can run as a local instance, or as the hosted **Prowler MCP** at `https://mcp.prowler.com/mcp`. The hosted server also provides tools for Prowler Cloud-specific features such as [Alerts](/user-guide/tutorials/prowler-alerts), [Scan Scheduling](/user-guide/tutorials/prowler-scan-scheduling), and [Findings Triage](/user-guide/tutorials/prowler-app-findings-triage). See [Deployment Options](#deployment-options). +Prefer to run it yourself? The **Local MCP Server** runs on your own machine or infrastructure. The Cloud MCP Server additionally provides tools for Prowler Cloud-specific features such as [Alerts](/user-guide/tutorials/prowler-alerts), [Scan Scheduling](/user-guide/tutorials/prowler-scan-scheduling), and [Findings Triage](/user-guide/tutorials/prowler-app-findings-triage). See [Cloud vs Local MCP Server](#cloud-vs-local-mcp-server). ## What is the Model Context Protocol? @@ -20,9 +41,9 @@ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is an open s The Prowler MCP Server provides three main integration points: -### 1. Prowler Cloud and Prowler Local Server +### 1. Prowler Cloud, Private Cloud & Local Server -Full access to Prowler Cloud and Prowler Local Server for: +Full access to your Prowler deployment — Prowler Cloud, Prowler Private Cloud, or Prowler Local Server — for: - **Findings Analysis**: Query, filter, and analyze security findings across all your cloud environments - **Provider Management**: Create, configure, and manage your configured Prowler providers (AWS, Azure, GCP, etc.) - **Scan Orchestration**: Trigger on-demand scans and schedule recurring security assessments @@ -48,12 +69,53 @@ Search and retrieve official Prowler documentation: ## MCP Server Architecture -The following diagram illustrates the Prowler MCP Server architecture and its integration points: +The following diagram illustrates the Prowler MCP Server architecture and its integration points. MCP clients connect to either the **Cloud MCP Server** (recommended) or a **Local MCP Server**; both expose the same tools and reach the same Prowler backends: -![Prowler MCP Server Schema](/images/prowler_mcp_schema.png) +```mermaid +flowchart LR + subgraph HOSTS["MCP Clients"] + chat["Chat Interfaces
(Claude Desktop, LobeChat)"] + ide["IDEs and Code Editors
(Claude Code, Cursor)"] + apps["Other AI Applications
(5ire, custom agents)"] + end + + subgraph SERVERS["Prowler MCP Server"] + direction TB + cloud["☁️ Cloud MCP Server (Recommended)
mcp.prowler.com/mcp · HTTP
Managed by Prowler · always up to date
Adds Cloud-only tools (Alerts,
Scan Scheduling, Findings Triage)"] + local["💻 Local MCP Server
Self-run · STDIO or HTTP
Python 3.12+ or Docker
You manage updates"] + end + + subgraph TOOLS["Prowler MCP Tools"] + prowler_tools["prowler_* tools
(API key or JWT auth)
Findings · Providers · Scans
Resources · Muting · Compliance
Attack Paths"] + hub_tools["prowler_hub_* tools
(no auth)
Checks Catalog · Check Code
Fixers · Compliance Frameworks"] + docs_tools["prowler_docs_* tools
(no auth)
Search · Document Retrieval"] + end + + api["Prowler API (REST)
Cloud · Private Cloud · Local Server"] + hub["hub.prowler.com
(REST)"] + docs["docs.prowler.com
(Mintlify)"] + + chat -->|HTTP| cloud + ide -->|HTTP| cloud + apps -->|HTTP| cloud + chat -->|STDIO or HTTP| local + ide -->|STDIO or HTTP| local + apps -->|STDIO or HTTP| local + + cloud --> prowler_tools + cloud --> hub_tools + cloud --> docs_tools + local --> prowler_tools + local --> hub_tools + local --> docs_tools + + prowler_tools -->|REST| api + hub_tools -->|REST| hub + docs_tools -->|REST| docs +``` The architecture shows how AI assistants connect through the MCP protocol to access Prowler's three main components: -- Prowler Cloud and Prowler Local Server for security operations +- Prowler Cloud, Prowler Private Cloud, or Prowler Local Server for security operations - Prowler Hub for security knowledge - Prowler Documentation for guidance and reference. @@ -92,8 +154,8 @@ REQUIREMENTS: DATA TO FETCH: Use these MCP tools in this order: -1. Prowler app list providers - To get all available configured provider in the account -2. Prowler app get latest findings - To get findings information, if there are so many you can use the filter_fields to get less information, or pagination to get in different batches +1. Prowler list providers - To get all available configured provider in the account +2. Prowler get latest findings - To get findings information, if there are so many you can use the filter_fields to get less information, or pagination to get in different batches 3. For most critical findings you can get more context and remediation with Prowler Hub to get remediations for example DESIGN REQUIREMENTS: @@ -130,66 +192,48 @@ Generate the complete HTML file and display it > -## Deployment Options +## Cloud vs Local MCP Server -Prowler MCP Server can be used in three ways: +There are two ways to run the Prowler MCP Server. For almost everyone, the **Cloud MCP Server** is the right choice — it needs no installation and is maintained by Prowler. The **Local MCP Server** exists for users who need to run it on their own machine or infrastructure. -### 1. Prowler Cloud MCP Server +| | ☁️ **Cloud MCP Server** (Recommended) | 💻 **Local MCP Server** | +|---|---|---| +| **Endpoint** | `https://mcp.prowler.com/mcp` | Runs on your machine or infrastructure | +| **Setup** | Just configure your MCP client | Install via Docker, or source | +| **Transport** | HTTP | STDIO (subprocess) or self-hosted HTTP | +| **Maintenance** | Managed by Prowler, always up to date | You manage updates | +| **Requirements** | None (just an MCP client) | Python 3.12+ or Docker | +| **Cloud-only tools** | ✅ Alerts, Scan Scheduling, Findings Triage | ❌ Not available | +| **Authentication** | API key or JWT token | API key/JWT (HTTP) or env vars (STDIO) | -**Use Prowler's managed MCP server at `https://mcp.prowler.com/mcp`** +### ☁️ Cloud MCP Server (Recommended) -- No installation required. -- Managed and maintained by Prowler team. -- Authentication to Prowler Cloud or Prowler Local Server via API key or JWT token. -- Includes tools for Prowler Cloud-specific features such as Alerts, Scan Scheduling, and Findings Triage. +Prowler's managed MCP server at `https://mcp.prowler.com/mcp`. No installation, always up to date, and it includes tools for Prowler Cloud-specific features such as Alerts, Scan Scheduling, and Findings Triage. This is the path we recommend for nearly all users — go straight to the [Configuration guide](/getting-started/basic-usage/prowler-mcp#cloud-mcp-server-configuration-recommended). -### 2. Local STDIO Mode +### 💻 Local MCP Server -**Run the server locally on your machine** +Run the server yourself when you need full control over the deployment. It connects to Prowler Cloud, Prowler Private Cloud, or Prowler Local Server and can run in two modes: -- Runs as a subprocess of the MCP client. -- Possibility to connect to Prowler Local Server. -- Authentication to Prowler Cloud or Prowler Local Server via environment variables. -- Requires Python 3.12+ or Docker. +- **STDIO mode** — the server runs as a subprocess of your MCP client. Authentication via environment variables. +- **Self-hosted HTTP mode** — deploy your own remote HTTP server. Authentication via API key or JWT token. -### 3. Self-Hosted HTTP Mode - -**Deploy your own remote MCP server** - -- Full control over deployment. -- Possibility to connect to Prowler Local Server. -- Authentication to Prowler Local Server via API key or JWT token. -- Requires Python 3.12+ or Docker. - -## Requirements - -Requirements vary based on deployment option: - -**For Prowler Cloud MCP Server:** -- Prowler Cloud account and API key (only for Prowler Cloud and Prowler Local Server features) - -**For self-hosted STDIO/HTTP Mode:** -- Python 3.12+ or Docker -- Network access to: - - `https://hub.prowler.com` (for Prowler Hub) - - `https://docs.prowler.com` (for Prowler Documentation) - - Prowler Cloud API or Prowler Local Server API (for Prowler Cloud and Prowler Local Server features) +Both require Python 3.12+ or Docker, plus network access to `https://hub.prowler.com` (Prowler Hub), `https://docs.prowler.com` (Prowler Documentation), and the Prowler API or Prowler Local Server API (Prowler features). See the [Installation guide](/getting-started/installation/prowler-mcp) to get started. -**No Authentication Required**: Prowler Hub and Prowler Documentation features work without authentication in both deployment options. A Prowler API key is only required to access Prowler Cloud or Prowler Local Server features. +**No Authentication Required**: Prowler Hub and Prowler Documentation features work without authentication on both the Cloud and Local MCP Server. A Prowler API key is only required to access Prowler features (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server). ## Next Steps - - Install the Prowler MCP Server using uv or Docker - - Configure your MCP client to connect to the server + Connect your MCP client to the Cloud MCP Server + + + Explore all available tools and capabilities - - Explore all available tools and capabilities + + Run the Local MCP Server yourself using Docker, source, or uvx diff --git a/docs/images/lighthouse-architecture.mmd b/docs/images/lighthouse-architecture.mmd index 47407544e9..6798801fb8 100644 --- a/docs/images/lighthouse-architecture.mmd +++ b/docs/images/lighthouse-architecture.mmd @@ -15,7 +15,7 @@ flowchart TB llm["LLM Provider
(OpenAI / Bedrock / OpenAI-compatible)"] subgraph MCP["Prowler MCP Server"] - app_tools["prowler_app_* tools
(auth required)"] + app_tools["prowler_* tools
(auth required)"] hub_tools["prowler_hub_* tools
(no auth)"] docs_tools["prowler_docs_* tools
(no auth)"] end @@ -29,7 +29,7 @@ flowchart TB agent <-->|LLM API| llm agent --> metatools metatools --> mcpclient - mcpclient -->|MCP HTTP · Bearer token
for prowler_app_* only| app_tools + mcpclient -->|MCP HTTP · Bearer token
for prowler_* only| app_tools mcpclient -->|MCP HTTP| hub_tools mcpclient -->|MCP HTTP| docs_tools app_tools -->|REST| api diff --git a/docs/images/prowler_mcp_schema.mmd b/docs/images/prowler_mcp_schema.mmd index 96973546f6..2b8508cd18 100644 --- a/docs/images/prowler_mcp_schema.mmd +++ b/docs/images/prowler_mcp_schema.mmd @@ -1,29 +1,40 @@ flowchart LR - subgraph HOSTS["MCP Hosts"] + subgraph HOSTS["MCP Clients"] chat["Chat Interfaces
(Claude Desktop, LobeChat)"] ide["IDEs and Code Editors
(Claude Code, Cursor)"] apps["Other AI Applications
(5ire, custom agents)"] end - subgraph MCP["Prowler MCP Server"] - app_tools["prowler_app_* tools
(JWT or API key auth)
Findings · Providers · Scans
Resources · Muting · Compliance
Attack Paths"] + subgraph SERVERS["Prowler MCP Server"] + direction TB + cloud["☁️ Cloud MCP Server (Recommended)
mcp.prowler.com/mcp · HTTP
Managed by Prowler · always up to date
Adds Cloud-only tools (Alerts,
Scan Scheduling, Findings Triage)"] + local["💻 Local MCP Server
Self-run · STDIO or HTTP
Python 3.12+ or Docker
You manage updates"] + end + + subgraph TOOLS["Prowler MCP Tools"] + prowler_tools["prowler_* tools
(API key or JWT auth)
Findings · Providers · Scans
Resources · Muting · Compliance
Attack Paths"] hub_tools["prowler_hub_* tools
(no auth)
Checks Catalog · Check Code
Fixers · Compliance Frameworks"] docs_tools["prowler_docs_* tools
(no auth)
Search · Document Retrieval"] end - api["Prowler API
(REST)"] + api["Prowler API (REST)
Cloud · Private Cloud · Local Server"] hub["hub.prowler.com
(REST)"] docs["docs.prowler.com
(Mintlify)"] - chat -->|STDIO or HTTP| app_tools - chat -->|STDIO or HTTP| hub_tools - chat -->|STDIO or HTTP| docs_tools - ide -->|STDIO or HTTP| app_tools - ide -->|STDIO or HTTP| hub_tools - ide -->|STDIO or HTTP| docs_tools - apps -->|STDIO or HTTP| app_tools - apps -->|STDIO or HTTP| hub_tools - apps -->|STDIO or HTTP| docs_tools - app_tools -->|REST| api + chat -->|HTTP| cloud + ide -->|HTTP| cloud + apps -->|HTTP| cloud + chat -->|STDIO or HTTP| local + ide -->|STDIO or HTTP| local + apps -->|STDIO or HTTP| local + + cloud --> prowler_tools + cloud --> hub_tools + cloud --> docs_tools + local --> prowler_tools + local --> hub_tools + local --> docs_tools + + prowler_tools -->|REST| api hub_tools -->|REST| hub docs_tools -->|REST| docs diff --git a/docs/images/prowler_mcp_schema.png b/docs/images/prowler_mcp_schema.png deleted file mode 100644 index 8a8884fa5e..0000000000 Binary files a/docs/images/prowler_mcp_schema.png and /dev/null differ diff --git a/docs/user-guide/tutorials/prowler-app-attack-paths.mdx b/docs/user-guide/tutorials/prowler-app-attack-paths.mdx index 32df3c50ba..22e56e5634 100644 --- a/docs/user-guide/tutorials/prowler-app-attack-paths.mdx +++ b/docs/user-guide/tutorials/prowler-app-attack-paths.mdx @@ -283,7 +283,7 @@ In addition to the upstream schema, Prowler enriches the graph with: AI assistants connected through Prowler MCP Server can fetch the exact Cartography schema for the active scan via the - `prowler_app_get_attack_paths_cartography_schema` tool. This guarantees that + `prowler_get_attack_paths_cartography_schema` tool. This guarantees that generated queries match the schema version pinned by the running Prowler release. @@ -427,10 +427,10 @@ Attack Paths capabilities are also available through the [Prowler MCP Server](/g The following MCP tools are available for Attack Paths: -- **`prowler_app_list_attack_paths_scans`** - List and filter Attack Paths scans. -- **`prowler_app_list_attack_paths_queries`** - Discover available queries for a completed scan. -- **`prowler_app_run_attack_paths_query`** - Execute a query and retrieve graph results with nodes and relationships. -- **`prowler_app_get_attack_paths_cartography_schema`** - Retrieve the Cartography graph schema for custom openCypher queries. +- **`prowler_list_attack_paths_scans`** - List and filter Attack Paths scans. +- **`prowler_list_attack_paths_queries`** - Discover available queries for a completed scan. +- **`prowler_run_attack_paths_query`** - Execute a query and retrieve graph results with nodes and relationships. +- **`prowler_get_attack_paths_cartography_schema`** - Retrieve the Cartography graph schema for custom openCypher queries. ### Example Questions diff --git a/mcp_server/.env.template b/mcp_server/.env.template index 11b8caa724..10aabd84cf 100644 --- a/mcp_server/.env.template +++ b/mcp_server/.env.template @@ -1,3 +1,3 @@ -PROWLER_APP_API_KEY="pk_your_api_key_here" +PROWLER_API_KEY="pk_your_api_key_here" API_BASE_URL="https://api.prowler.com/api/v1" PROWLER_MCP_TRANSPORT_MODE="stdio" diff --git a/mcp_server/AGENTS.md b/mcp_server/AGENTS.md index a82cc42e33..1d3d808e6a 100644 --- a/mcp_server/AGENTS.md +++ b/mcp_server/AGENTS.md @@ -25,7 +25,7 @@ The Prowler MCP Server provides AI agents access to the Prowler ecosystem throug ## CRITICAL RULES ### Tool Implementation -- ALWAYS: Extend `BaseTool` ABC for Prowler App tools (auto-registration) +- ALWAYS: Extend `BaseTool` ABC for Prowler tools (auto-registration) - ALWAYS: Use `@mcp.tool()` decorator for Hub/Docs tools - NEVER: Manually register BaseTool subclasses - NEVER: Import tools directly in server.py @@ -56,7 +56,7 @@ await prowler_mcp_server.import_server(docs_mcp_server, prefix="prowler_docs") ### Tool Naming - `prowler_hub_*` - Catalog and compliance (no auth) - `prowler_docs_*` - Documentation search (no auth) -- `prowler_app_*` - Cloud/App management (auth required) +- `prowler_*` - Prowler Cloud, Private Cloud & Local Server management (auth required) --- diff --git a/mcp_server/README.md b/mcp_server/README.md index e990f0f363..c0e4fdb0fe 100644 --- a/mcp_server/README.md +++ b/mcp_server/README.md @@ -6,9 +6,9 @@ ## Key Capabilities -### Prowler Cloud and Prowler App (Self-Managed) +### Prowler Cloud, Prowler Private Cloud & Prowler Local Server -Full access to Prowler Cloud platform and self-managed Prowler App for: +Full access to your Prowler data (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server) for: - **Findings Analysis**: Query, filter, and analyze security findings across all your cloud environments - **Finding Groups Analysis**: Triage findings grouped by check ID and drill down into affected resources - **Provider Management**: Create, configure, and manage your configured Prowler providers (AWS, Azure, GCP, etc.) @@ -49,7 +49,7 @@ For comprehensive guides and tutorials, see the official documentation: Prowler MCP Server can be used in three ways: -### 1. Prowler Cloud MCP Server (Recommended) +### 1. Hosted Prowler MCP (Recommended) **Use Prowler's managed MCP server at `https://mcp.prowler.com/mcp`** @@ -126,7 +126,7 @@ For complete tool descriptions and parameters, see the [Tools Reference](https:/ ### Tool Naming Convention All tools follow a consistent naming pattern with prefixes: -- `prowler_app_*` - Prowler Cloud and App (Self-Managed) management tools +- `prowler_*` - Prowler Cloud, Prowler Private Cloud & Prowler Local Server management tools - `prowler_hub_*` - Prowler Hub catalog and compliance tools - `prowler_docs_*` - Prowler documentation search and retrieval @@ -146,7 +146,7 @@ prowler_mcp_server/ **Key Features:** - **Modular Design**: Three independent sub-servers with prefixed namespacing -- **Auto-Discovery**: Prowler App tools are automatically discovered and registered +- **Auto-Discovery**: Prowler tools are automatically discovered and registered - **LLM Optimization**: Response models minimize token usage by excluding empty values - **Dual Transport**: Supports both STDIO (local) and HTTP (remote) modes @@ -174,17 +174,17 @@ The Prowler MCP Server enables powerful workflows through AI assistants: ## Requirements -**For Prowler Cloud MCP Server:** -- Prowler Cloud account and API key (only for Prowler Cloud/App features) +**For the hosted Prowler MCP:** +- Prowler Cloud account and API key (only for Prowler features) **For self-hosted STDIO/HTTP Mode:** - Python 3.12+ or Docker - Network access to: - `https://hub.prowler.com` (for Prowler Hub) - `https://docs.prowler.com` (for Prowler Documentation) - - Prowler Cloud API or self-hosted Prowler App API (for Prowler Cloud/App features) + - Prowler Cloud API or Prowler Local Server API (for Prowler features) -> **No Authentication Required**: Prowler Hub and Prowler Documentation features work without authentication. A Prowler API key is only required to access Prowler Cloud or Prowler App (Self-Managed) features. +> **No Authentication Required**: Prowler Hub and Prowler Documentation features work without authentication. A Prowler API key is only required to access Prowler features (Prowler Cloud, Prowler Private Cloud, or Prowler Local Server). ## Configuring MCP Hosts @@ -200,7 +200,7 @@ For developers looking to extend the MCP server with new tools or features: ## Related Products - **[Prowler Hub](https://hub.prowler.com)**: Browse security checks and compliance frameworks -- **[Prowler Cloud](https://cloud.prowler.com)**: Managed Prowler platform +- **[Prowler Cloud](https://cloud.prowler.com)**: Fully managed Prowler in the cloud - **[Lighthouse AI](https://docs.prowler.com/getting-started/products/prowler-lighthouse-ai)**: AI security analyst ## License diff --git a/mcp_server/changelog.d/prowler-tools-namespace.changed.md b/mcp_server/changelog.d/prowler-tools-namespace.changed.md new file mode 100644 index 0000000000..0ca03d15ca --- /dev/null +++ b/mcp_server/changelog.d/prowler-tools-namespace.changed.md @@ -0,0 +1 @@ +Core Prowler tool namespace from the `prowler_app_*` prefix to `prowler_*` diff --git a/mcp_server/prowler_mcp_server/__init__.py b/mcp_server/prowler_mcp_server/__init__.py index fe7af2dcea..1956a6ec41 100644 --- a/mcp_server/prowler_mcp_server/__init__.py +++ b/mcp_server/prowler_mcp_server/__init__.py @@ -5,7 +5,7 @@ This package provides MCP tools for accessing: - Prowler Hub: All security artifacts (detections, remediations and frameworks) supported by Prowler """ -__version__ = "0.5.0" +__version__ = "0.8.0" __author__ = "Prowler Team" __email__ = "engineering@prowler.com" diff --git a/mcp_server/prowler_mcp_server/prowler_app/models/__init__.py b/mcp_server/prowler_mcp_server/prowler_app/models/__init__.py index 899ab4e866..1b15e35ac9 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/models/__init__.py +++ b/mcp_server/prowler_mcp_server/prowler_app/models/__init__.py @@ -1,4 +1,4 @@ -"""Pydantic models for Prowler App MCP Server.""" +"""Pydantic models for Prowler MCP Server.""" from prowler_mcp_server.prowler_app.models.base import MinimalSerializerMixin from prowler_mcp_server.prowler_app.models.findings import ( diff --git a/mcp_server/prowler_mcp_server/prowler_app/models/finding_groups.py b/mcp_server/prowler_mcp_server/prowler_app/models/finding_groups.py index ae8431ba63..c2429012c3 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/models/finding_groups.py +++ b/mcp_server/prowler_mcp_server/prowler_app/models/finding_groups.py @@ -228,7 +228,7 @@ class FindingGroupResource(MinimalSerializerMixin): resource: FindingGroupResourceInfo = Field(description="Affected resource") provider: FindingGroupProviderInfo = Field(description="Affected provider") finding_id: str = Field( - description="Finding UUID to use with prowler_app_get_finding_details" + description="Finding UUID to use with prowler_get_finding_details" ) status: FindingStatus = Field(description="Finding status for this resource") severity: FindingSeverity = Field(description="Finding severity") diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/__init__.py b/mcp_server/prowler_mcp_server/prowler_app/tools/__init__.py index 4d740b6efe..8b5be76076 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/__init__.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/__init__.py @@ -1,4 +1,4 @@ -"""Domain-specific tools for Prowler App MCP Server. +"""Domain-specific tools for Prowler MCP Server. Each module in this package contains a BaseTool subclass that registers and implements tools for a specific domain (findings, providers, scans, etc.). diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/attack_paths.py b/mcp_server/prowler_mcp_server/prowler_app/tools/attack_paths.py index b08bbfe01f..5bd66760fa 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/attack_paths.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/attack_paths.py @@ -1,4 +1,4 @@ -"""Attack Paths tools for Prowler App MCP Server. +"""Attack Paths tools for Prowler MCP Server. This module provides tools for analyzing Attack Paths data from Neo4j graph database. Attack Paths help identify security risks by tracing potential attack vectors @@ -22,16 +22,16 @@ class AttackPathsTools(BaseTool): """Tools for Attack Paths analysis. Provides tools for: - - prowler_app_list_attack_paths_scans: Find completed scans ready for analysis - - prowler_app_list_attack_paths_queries: Discover available queries for a scan - - prowler_app_run_attack_paths_query: Execute query and analyze attack paths + - prowler_list_attack_paths_scans: Find completed scans ready for analysis + - prowler_list_attack_paths_queries: Discover available queries for a scan + - prowler_run_attack_paths_query: Execute query and analyze attack paths """ async def list_attack_paths_scans( self, provider_id: list[str] = Field( default=[], - description="Filter by Prowler's internal UUID(s) (v4) for specific provider(s). Use `prowler_app_search_providers` tool to find provider IDs", + description="Filter by Prowler's internal UUID(s) (v4) for specific provider(s). Use `prowler_search_providers` tool to find provider IDs", ), provider_type: list[str] = Field( default=[], @@ -73,8 +73,8 @@ class AttackPathsTools(BaseTool): Workflow: 1. Use this tool to find completed attack paths scans - 2. Use prowler_app_list_attack_paths_queries to see available queries for a scan - 3. Use prowler_app_run_attack_paths_query to execute analysis + 2. Use prowler_list_attack_paths_queries to see available queries for a scan + 3. Use prowler_run_attack_paths_query to execute analysis """ try: # Validate pagination @@ -113,7 +113,7 @@ class AttackPathsTools(BaseTool): async def list_attack_paths_queries( self, scan_id: str = Field( - description="UUID of a COMPLETED attack paths scan. Use `prowler_app_list_attack_paths_scans` with state=['completed'] to find scan IDs" + description="UUID of a COMPLETED attack paths scan. Use `prowler_list_attack_paths_scans` with state=['completed'] to find scan IDs" ), ) -> list[dict[str, Any]]: """Discover available Attack Paths queries for a completed scan. @@ -133,9 +133,9 @@ class AttackPathsTools(BaseTool): - aws-ec2-instances-internet-exposed: Find internet-exposed EC2 instances Workflow: - 1. Use prowler_app_list_attack_paths_scans to find a completed scan + 1. Use prowler_list_attack_paths_scans to find a completed scan 2. Use this tool to discover available queries - 3. Use prowler_app_run_attack_paths_query with query_id and any required parameters + 3. Use prowler_run_attack_paths_query with query_id and any required parameters """ try: api_response = await self.api_client.get( @@ -158,7 +158,7 @@ class AttackPathsTools(BaseTool): description="UUID of a COMPLETED attack paths scan. The scan must be in 'completed' state" ), query_id: str = Field( - description="Query ID to execute (e.g., 'aws-internet-exposed-ec2-sensitive-s3-access'). Use `prowler_app_list_attack_paths_queries` to discover available queries" + description="Query ID to execute (e.g., 'aws-internet-exposed-ec2-sensitive-s3-access'). Use `prowler_list_attack_paths_queries` to discover available queries" ), parameters: dict[str, str] = Field( default_factory=dict, @@ -194,7 +194,7 @@ class AttackPathsTools(BaseTool): Workflow: 1. Ensure scan is completed - 2. List available queries (use prowler_app_list_attack_paths_queries) + 2. List available queries (use prowler_list_attack_paths_queries) 3. Execute this tool with appropriate parameters 4. Analyze the returned graph for security insights """ @@ -231,7 +231,7 @@ class AttackPathsTools(BaseTool): async def get_attack_paths_cartography_schema( self, scan_id: str = Field( - description="UUID of a COMPLETED attack paths scan. Use `prowler_app_list_attack_paths_scans` with state=['completed'] to find scan IDs" + description="UUID of a COMPLETED attack paths scan. Use `prowler_list_attack_paths_scans` with state=['completed'] to find scan IDs" ), ) -> dict[str, Any]: """Retrieve the Cartography graph schema for a completed attack paths scan. @@ -253,10 +253,10 @@ class AttackPathsTools(BaseTool): - schema_content: Full Cartography schema markdown with node/relationship definitions Workflow: - 1. Use prowler_app_list_attack_paths_scans to find a completed scan + 1. Use prowler_list_attack_paths_scans to find a completed scan 2. Use this tool to get the schema for the scan's provider 3. Use the schema to craft custom openCypher queries - 4. Execute queries with prowler_app_run_attack_paths_query + 4. Execute queries with prowler_run_attack_paths_query """ try: api_response = await self.api_client.get( diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/compliance.py b/mcp_server/prowler_mcp_server/prowler_app/tools/compliance.py index 360dd5510d..33cdd22a69 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/compliance.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/compliance.py @@ -1,4 +1,4 @@ -"""Compliance framework tools for Prowler App MCP Server. +"""Compliance framework tools for Prowler MCP Server. This module provides tools for viewing compliance status and requirement details across all cloud providers. @@ -50,7 +50,7 @@ class ComplianceTools(BaseTool): if not scans_data: raise ValueError( f"No completed scans found for provider {provider_id}. " - "Run a scan first using prowler_app_trigger_scan." + "Run a scan first using prowler_trigger_scan." ) scan_id = scans_data[0]["id"] @@ -60,11 +60,11 @@ class ComplianceTools(BaseTool): self, scan_id: str | None = Field( default=None, - description="UUID of a specific scan to get compliance data for. Required if provider_id is not specified. Use `prowler_app_list_scans` to find scan IDs.", + description="UUID of a specific scan to get compliance data for. Required if provider_id is not specified. Use `prowler_list_scans` to find scan IDs.", ), provider_id: str | None = Field( default=None, - description="Prowler's internal UUID (v4) for a specific provider. If provided without scan_id, the tool will automatically find the latest completed scan for this provider. Use `prowler_app_search_providers` tool to find provider IDs.", + description="Prowler's internal UUID (v4) for a specific provider. If provided without scan_id, the tool will automatically find the latest completed scan for this provider. Use `prowler_search_providers` tool to find provider IDs.", ), ) -> dict[str, Any]: """Get high-level compliance overview across all frameworks for a specific scan. @@ -90,11 +90,11 @@ class ComplianceTools(BaseTool): Workflow: 1. Use this tool to get an overview of all compliance frameworks - 2. Use prowler_app_get_compliance_framework_state_details with a specific compliance_id to see which requirements failed + 2. Use prowler_get_compliance_framework_state_details with a specific compliance_id to see which requirements failed """ if not scan_id and not provider_id: return { - "error": "Either scan_id or provider_id must be provided. Use prowler_app_search_providers to find provider IDs or prowler_app_list_scans to find scan IDs." + "error": "Either scan_id or provider_id must be provided. Use prowler_search_providers to find provider IDs or prowler_list_scans to find scan IDs." } elif scan_id and provider_id: return { @@ -254,7 +254,7 @@ class ComplianceTools(BaseTool): async def get_compliance_framework_state_details( self, compliance_id: str = Field( - description="Compliance framework ID to get details for (e.g., 'cis_1.5_aws', 'pci_dss_v4.0_aws'). You can get compliance IDs from prowler_app_get_compliance_overview or consulting Prowler Hub/Prowler Documentation that you can also find in form of tools in this MCP Server", + description="Compliance framework ID to get details for (e.g., 'cis_1.5_aws', 'pci_dss_v4.0_aws'). You can get compliance IDs from prowler_get_compliance_overview or consulting Prowler Hub/Prowler Documentation that you can also find in form of tools in this MCP Server", ), scan_id: str | None = Field( default=None, @@ -262,14 +262,14 @@ class ComplianceTools(BaseTool): ), provider_id: str | None = Field( default=None, - description="Prowler's internal UUID (v4) for a specific provider. If provided without scan_id, the tool will automatically find the latest completed scan for this provider. Use `prowler_app_search_providers` tool to find provider IDs.", + description="Prowler's internal UUID (v4) for a specific provider. If provided without scan_id, the tool will automatically find the latest completed scan for this provider. Use `prowler_search_providers` tool to find provider IDs.", ), ) -> dict[str, Any]: """Get detailed requirement-level breakdown for a specific compliance framework. IMPORTANT: This tool returns DETAILED requirement information for a single compliance framework, focusing on FAILED requirements and their associated FAILED finding IDs. - Use this after prowler_app_get_compliance_overview to drill down into specific frameworks. + Use this after prowler_get_compliance_overview to drill down into specific frameworks. The markdown report includes: @@ -280,7 +280,7 @@ class ComplianceTools(BaseTool): 2. Failed Requirements Breakdown: - Each failed requirement's ID and description - Associated failed finding IDs for each failed requirement - - Use prowler_app_get_finding_details with these finding IDs for more details and remediation guidance + - Use prowler_get_finding_details with these finding IDs for more details and remediation guidance Default behavior: - Requires either scan_id OR provider_id @@ -289,14 +289,14 @@ class ComplianceTools(BaseTool): - Only shows failed requirements with their associated failed finding IDs Workflow: - 1. Use prowler_app_get_compliance_overview to identify frameworks with failures + 1. Use prowler_get_compliance_overview to identify frameworks with failures 2. Use this tool with the compliance_id to see failed requirements and their finding IDs - 3. Use prowler_app_get_finding_details with the finding IDs to get remediation guidance + 3. Use prowler_get_finding_details with the finding IDs to get remediation guidance """ # Validate that either scan_id or provider_id is provided if not scan_id and not provider_id: return { - "error": "Either scan_id or provider_id must be provided. Use prowler_app_search_providers to find provider IDs or prowler_app_list_scans to find scan IDs." + "error": "Either scan_id or provider_id must be provided. Use prowler_search_providers to find provider IDs or prowler_list_scans to find scan IDs." } # Resolve provider_id to latest scan_id if needed @@ -395,7 +395,7 @@ class ComplianceTools(BaseTool): report_lines.append("**Failed Finding IDs**: None found") report_lines.append("") report_lines.append( - "*Use `prowler_app_get_finding_details` with these finding IDs to get remediation guidance.*" + "*Use `prowler_get_finding_details` with these finding IDs to get remediation guidance.*" ) report_lines.append("") diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/finding_groups.py b/mcp_server/prowler_mcp_server/prowler_app/tools/finding_groups.py index 905a352740..05adf8db2b 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/finding_groups.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/finding_groups.py @@ -1,4 +1,4 @@ -"""Finding Groups tools for Prowler App MCP Server. +"""Finding Groups tools for Prowler MCP Server. This module provides read-only tools for finding group triage and drill-downs. """ @@ -233,8 +233,8 @@ class FindingGroupsTools(BaseTool): `date_to`, this uses `/finding-groups` with a maximum 2-day date window. Use this tool to find noisy or high-impact checks, then call - prowler_app_get_finding_group_details for complete counters or - prowler_app_list_finding_group_resources to drill into affected resources. + prowler_get_finding_group_details for complete counters or + prowler_list_finding_group_resources to drill into affected resources. """ try: self.api_client.validate_page_size(page_size) @@ -423,7 +423,7 @@ class FindingGroupsTools(BaseTool): Default behavior returns FAIL, unmuted resources so the result is actionable. Set `include_muted=True` to include accepted/suppressed resources too. Each row includes nested resource and provider data plus - `finding_id`. Use `prowler_app_get_finding_details(finding_id)` to + `finding_id`. Use `prowler_get_finding_details(finding_id)` to retrieve complete remediation guidance for a specific resource finding. """ try: diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/findings.py b/mcp_server/prowler_mcp_server/prowler_app/tools/findings.py index ec492c6a43..b556101cab 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/findings.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/findings.py @@ -1,4 +1,4 @@ -"""Security Findings tools for Prowler App MCP Server. +"""Security Findings tools for Prowler MCP Server. This module provides tools for searching, viewing, and analyzing security findings across all cloud providers. @@ -92,7 +92,7 @@ class FindingsTools(BaseTool): """Search and filter security findings across all cloud providers with rich filtering capabilities. IMPORTANT: This tool returns LIGHTWEIGHT findings. Use this for fast searching and filtering across many findings. - For complete details use prowler_app_get_finding_details on specific findings. + For complete details use prowler_get_finding_details on specific findings. Default behavior: - Returns latest findings from most recent scans (no date parameters needed) @@ -111,7 +111,7 @@ class FindingsTools(BaseTool): Workflow: 1. Use this tool to search and filter findings by severity, status, provider, service, region, etc. - 2. Use prowler_app_get_finding_details with the finding 'id' to get complete information about the finding + 2. Use prowler_get_finding_details with the finding 'id' to get complete information about the finding """ # Validate page_size parameter self.api_client.validate_page_size(page_size) @@ -187,9 +187,9 @@ class FindingsTools(BaseTool): """Retrieve comprehensive details about a specific security finding by its ID. IMPORTANT: This tool returns COMPLETE finding details. - Use this after finding a specific finding via prowler_app_search_security_findings + Use this after finding a specific finding via prowler_search_security_findings - This tool provides ALL information that prowler_app_search_security_findings returns PLUS: + This tool provides ALL information that prowler_search_security_findings returns PLUS: 1. Check Metadata (information about the check script that generated the finding): - title: Human-readable phrase used to summarize the check @@ -217,7 +217,7 @@ class FindingsTools(BaseTool): - resource_ids: List of UUIDs for cloud resources associated with this finding Workflow: - 1. Use prowler_app_search_security_findings to browse and filter findings + 1. Use prowler_search_security_findings to browse and filter findings 2. Use this tool with the finding 'id' to get remediation guidance and complete context """ params = { diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/muting.py b/mcp_server/prowler_mcp_server/prowler_app/tools/muting.py index 639f1ec3b7..37e1504165 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/muting.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/muting.py @@ -1,4 +1,4 @@ -"""Muting tools for Prowler App MCP Server. +"""Muting tools for Prowler MCP Server. This module provides tools for managing finding muting in Prowler, including: - Mutelist management (pattern-based bulk muting) @@ -43,7 +43,7 @@ class MutingTools(BaseTool): Workflow: 1. Use this tool to check if a mutelist is configured 2. Examine current muting patterns before making updates - 3. Use prowler_app_set_mutelist to create or update the configuration + 3. Use prowler_set_mutelist to create or update the configuration """ self.logger.info("Retrieving mutelist configuration...") @@ -61,7 +61,7 @@ class MutingTools(BaseTool): if len(data) == 0: return { "error": "No mutelist found", - "message": "No mutelist configuration exists for this tenant. Use prowler_app_set_mutelist to create one.", + "message": "No mutelist configuration exists for this tenant. Use prowler_set_mutelist to create one.", } # Return the first (and only) mutelist @@ -116,10 +116,10 @@ Structure: - Exceptions: Accounts, Regions, Resources to exclude from muting Workflow: - 1. Use prowler_app_get_mutelist to check existing configuration + 1. Use prowler_get_mutelist to check existing configuration 2. Build configuration object following Prowler mutelist format 3. Use this tool to create or update the mutelist - 4. Verify with prowler_app_get_mutelist + 4. Verify with prowler_get_mutelist """ self.logger.info("Setting mutelist configuration...") @@ -171,12 +171,12 @@ Structure: """Remove the mutelist configuration from the tenant. WARNING: This is a destructive operation that cannot be undone. - - The mutelist will need to be re-created with prowler_app_set_mutelist + - The mutelist will need to be re-created with prowler_set_mutelist - New findings from future scans will NOT be muted by the deleted mutelist - Previously muted findings remain muted (deletion doesn't un-mute them) Workflow: - 1. Use prowler_app_get_mutelist to confirm what will be deleted + 1. Use prowler_get_mutelist to confirm what will be deleted 2. Use this tool to permanently remove the mutelist 3. New scans will no longer apply mutelist-based muting """ @@ -229,7 +229,7 @@ Structure: """Search and filter mute rules with pagination support. IMPORTANT: This tool returns LIGHTWEIGHT mute rules without the full list of finding UIDs. - Use prowler_app_get_mute_rule to get complete details including all finding UIDs and creator information. + Use prowler_get_mute_rule to get complete details including all finding UIDs and creator information. Default behavior: - Returns all mute rules (both enabled and disabled) @@ -237,15 +237,15 @@ Structure: - Includes basic rule information without full finding UID lists Each mute rule includes: - - Core identification: id (UUID for prowler_app_get_mute_rule), name + - Core identification: id (UUID for prowler_get_mute_rule), name - Contextual information: reason, enabled status - State tracking: finding_count (number of findings currently muted) - Temporal data: inserted_at, updated_at timestamps Workflow: 1. Use this tool to search and filter mute rules by name, enabled status, or keywords - 2. Use prowler_app_get_mute_rule with the mute rule 'id' to get complete details including all finding UIDs - 3. Use prowler_app_update_mute_rule or prowler_app_delete_mute_rule to modify rules + 2. Use prowler_get_mute_rule with the mute rule 'id' to get complete details including all finding UIDs + 3. Use prowler_update_mute_rule or prowler_delete_mute_rule to modify rules """ self.logger.info("Listing mute rules...") self.api_client.validate_page_size(page_size) @@ -289,17 +289,17 @@ Structure: """Retrieve comprehensive details about a specific mute rule by its ID. IMPORTANT: This tool returns COMPLETE mute rule details including the full list of finding UIDs. - Use this after finding a rule via prowler_app_list_mute_rules. + Use this after finding a rule via prowler_list_mute_rules. - This tool provides ALL information that prowler_app_list_mute_rules returns PLUS: + This tool provides ALL information that prowler_list_mute_rules returns PLUS: - finding_uids: Complete list of finding UIDs that are muted by this rule - user_creator_id: UUID of the user who created the rule (audit trail) Workflow: - 1. Use prowler_app_list_mute_rules to find rules by name or filter criteria + 1. Use prowler_list_mute_rules to find rules by name or filter criteria 2. Use this tool with the rule 'id' to get complete details 3. Examine finding_uids list to understand which findings are muted - 4. Use prowler_app_update_mute_rule or prowler_app_delete_mute_rule to modify if needed + 4. Use prowler_update_mute_rule or prowler_delete_mute_rule to modify if needed """ self.logger.info(f"Retrieving mute rule {rule_id}...") @@ -323,7 +323,7 @@ Structure: description="Reason for muting these findings. Document why this security issue is acceptable or intentional (e.g., 'Development environment with controlled access', 'Legacy application requires IMDSv1')." ), finding_ids: list[str] = Field( - description="List of finding IDs (UUIDs) to mute. Get these from the prowler_app_search_security_findings tool. Must provide at least 1 finding ID." + description="List of finding IDs (UUIDs) to mute. Get these from the prowler_search_security_findings tool. Must provide at least 1 finding ID." ), ) -> dict[str, Any]: """Create a new mute rule to mute specific findings with documentation and audit trail. @@ -337,15 +337,15 @@ Structure: - Records creator for audit trail The mute rule includes: - - Core identification: id (UUID for prowler_app_get_mute_rule), name, reason + - Core identification: id (UUID for prowler_get_mute_rule), name, reason - Configuration: enabled status, finding_uids list - Audit trail: user_creator_id (UUID of the Prowler user from the tenant that created the rule), timestamps when the rule was created and last modified Workflow: - 1. Use prowler_app_search_security_findings to identify findings to mute + 1. Use prowler_search_security_findings to identify findings to mute 2. Use this tool with finding IDs, descriptive name, and documented reason - 3. Verify with prowler_app_get_mute_rule to confirm rule creation - 4. Check findings are muted with prowler_app_search_security_findings (filter by muted=true) + 3. Verify with prowler_get_mute_rule to confirm rule creation + 4. Check findings are muted with prowler_search_security_findings (filter by muted=true) """ self.logger.info(f"Creating mute rule '{name}'...") @@ -399,9 +399,9 @@ Structure: - enabled: Toggle rule active status (doesn't affect already-muted findings) Workflow: - 1. Use prowler_app_get_mute_rule to see current rule state + 1. Use prowler_get_mute_rule to see current rule state 2. Use this tool to update name, reason, or enabled status - 3. Verify changes with prowler_app_get_mute_rule + 3. Verify changes with prowler_get_mute_rule """ self.logger.info(f"Updating mute rule {rule_id}...") @@ -451,9 +451,9 @@ Structure: - Cannot be undone - rule must be recreated to restore Workflow: - 1. Use prowler_app_get_mute_rule to review what will be deleted + 1. Use prowler_get_mute_rule to review what will be deleted 2. Use this tool to permanently remove the rule - 3. Verify deletion with prowler_app_list_mute_rules (rule should no longer appear) + 3. Verify deletion with prowler_list_mute_rules (rule should no longer appear) """ self.logger.info(f"Deleting mute rule {rule_id}...") diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/providers.py b/mcp_server/prowler_mcp_server/prowler_app/tools/providers.py index b22d57d7b9..3ba417d677 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/providers.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/providers.py @@ -1,4 +1,4 @@ -"""Provider Management tools for Prowler App MCP Server. +"""Provider Management tools for Prowler MCP Server. This module provides tools for managing provider connections, including searching, connecting, and deleting providers. @@ -19,9 +19,9 @@ class ProvidersTools(BaseTool): """Tools for provider management operations Provides tools for: - - prowler_app_search_providers: Search and view configured providers with their connection status - - prowler_app_connect_provider: Connect or register a provider for security scanning in Prowler - - prowler_app_delete_provider: Permanently remove a provider from Prowler + - prowler_search_providers: Search and view configured providers with their connection status + - prowler_connect_provider: Connect or register a provider for security scanning in Prowler + - prowler_delete_provider: Permanently remove a provider from Prowler """ async def search_providers( @@ -145,7 +145,7 @@ class ProvidersTools(BaseTool): ) -> dict[str, Any]: """Register a provider to be scanned with Prowler. - This tool will register a provider in Prowler App, even if the UID is wrong. + This tool will register a provider in Prowler, even if the UID is wrong. If the provider is already registered, it will be updated with the new provided alias or credentials if provided. If credentials are provided, they will be added to the indicated provider, if the provider does not exist, it will be created and the credentials will be added to it. If the connection test is successful, the provider will be connected. @@ -292,13 +292,13 @@ class ProvidersTools(BaseTool): async def delete_provider( self, provider_id: str = Field( - description="Prowler's internal UUID (v4) for the provider to permanently remove, generated when the provider was registered in the system. Use `prowler_app_search_providers` tool to find the provider_id if you only know the alias or the provider's own identifier (provider_uid)" + description="Prowler's internal UUID (v4) for the provider to permanently remove, generated when the provider was registered in the system. Use `prowler_search_providers` tool to find the provider_id if you only know the alias or the provider's own identifier (provider_uid)" ), ) -> dict[str, Any]: """Permanently remove a registered provider from Prowler. WARNING: This is a destructive operation that cannot be undone. The provider will need to be - re-added with prowler_app_connect_provider if you want to scan it again. + re-added with prowler_connect_provider if you want to scan it again. The tool always returns the deletion status and message. """ diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/resources.py b/mcp_server/prowler_mcp_server/prowler_app/tools/resources.py index 011e013b91..88fcca25ae 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/resources.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/resources.py @@ -1,4 +1,4 @@ -"""Cloud Resources tools for Prowler App MCP Server. +"""Cloud Resources tools for Prowler MCP Server. This module provides tools for searching, viewing, and analyzing cloud resources across all providers. @@ -86,7 +86,7 @@ class ResourcesTools(BaseTool): IMPORTANT: This tool returns LIGHTWEIGHT resource information. Use this for fast searching and filtering across many resources. For complete configuration details, metadata, and finding - relationships, use prowler_app_get_resource on specific resources of interest. + relationships, use prowler_get_resource on specific resources of interest. This is the primary tool for browsing resources with rich filtering capabilities. Returns current state by default (latest scan per provider). Specify dates to query @@ -102,16 +102,16 @@ class ResourcesTools(BaseTool): - With dates: queries historical resource state (2-day maximum range between date_from and date_to) Each resource includes: - - Core identification: id (UUID for prowler_app_get_resource), uid, name + - Core identification: id (UUID for prowler_get_resource), uid, name - Location context: region, service, type - Security context: failed_findings_count (number of active security issues) - Tags: tags associated with the resource Useful Workflow: 1. Use this tool to search and filter resources by provider, region, service, tags, etc. - 2. Use prowler_app_get_resource with the resource 'id' to get complete configuration and metadata - 3. Use prowler_app_search_security_findings to find security issues for specific resources - 4. Use prowler_app_get_finding_details to get details about the security issues for specific resources + 2. Use prowler_get_resource with the resource 'id' to get complete configuration and metadata + 3. Use prowler_search_security_findings to find security issues for specific resources + 4. Use prowler_get_finding_details to get details about the security issues for specific resources """ # Validate page_size parameter self.api_client.validate_page_size(page_size) @@ -177,15 +177,15 @@ class ResourcesTools(BaseTool): async def get_resource( self, resource_id: str = Field( - description="Prowler's internal UUID (v4) for the resource to retrieve, generated when the resource was discovered in the system. Use `prowler_app_list_resources` tool to find the right ID" + description="Prowler's internal UUID (v4) for the resource to retrieve, generated when the resource was discovered in the system. Use `prowler_list_resources` tool to find the right ID" ), ) -> dict[str, Any]: """Retrieve comprehensive details about a specific resource by its ID. IMPORTANT: This tool provides COMPLETE resource details with all available information. - Use this after finding a specific resource via prowler_app_list_resources. + Use this after finding a specific resource via prowler_list_resources. - This tool provides ALL information that prowler_app_list_resources returns PLUS: + This tool provides ALL information that prowler_list_resources returns PLUS: 1. Configuration Details: - metadata: Provider-specific configuration (tags, policies, encryption settings, network rules) @@ -197,12 +197,12 @@ class ResourcesTools(BaseTool): 3. Security Relationships: - finding_ids: Prowler's internal UUIDs (v4) of all security findings associated with this resource - - Use prowler_app_get_finding_details on these IDs to get remediation guidance + - Use prowler_get_finding_details on these IDs to get remediation guidance Useful Workflow: - 1. Use prowler_app_list_resources to browse and filter across many resources + 1. Use prowler_list_resources to browse and filter across many resources 2. Use this tool to drill down into specific resources of interest - 3. Use prowler_app_get_finding_details to get details about the security issues for specific resources + 3. Use prowler_get_finding_details to get details about the security issues for specific resources """ params = {} @@ -348,7 +348,7 @@ class ResourcesTools(BaseTool): async def get_resource_events( self, resource_id: str = Field( - description="Prowler's internal UUID (v4) for the resource. Use `prowler_app_list_resources` to find the right ID, or get it from a finding's resource relationship via `prowler_app_get_finding_details`." + description="Prowler's internal UUID (v4) for the resource. Use `prowler_list_resources` to find the right ID, or get it from a finding's resource relationship via `prowler_get_finding_details`." ), lookback_days: int = Field( default=90, @@ -386,8 +386,8 @@ class ResourcesTools(BaseTool): - Identifying unauthorized or unexpected modifications Workflows: - 1. Resource browsing: prowler_app_list_resources → find resource → this tool for event history - 2. Incident investigation: prowler_app_get_finding_details → get resource ID from finding → this tool to identify who caused the issue, what they changed, and when + 1. Resource browsing: prowler_list_resources → find resource → this tool for event history + 2. Incident investigation: prowler_get_finding_details → get resource ID from finding → this tool to identify who caused the issue, what they changed, and when """ params = { "lookback_days": lookback_days, diff --git a/mcp_server/prowler_mcp_server/prowler_app/tools/scans.py b/mcp_server/prowler_mcp_server/prowler_app/tools/scans.py index 1df636ffc0..21d1431b71 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/tools/scans.py +++ b/mcp_server/prowler_mcp_server/prowler_app/tools/scans.py @@ -1,4 +1,4 @@ -"""Security Scans tools for Prowler App MCP Server. +"""Security Scans tools for Prowler MCP Server. This module provides tools for managing and monitoring Prowler security scans. """ @@ -20,18 +20,18 @@ class ScansTools(BaseTool): """Tools for security scan operations. Provides tools for: - - prowler_app_list_scans: Search and filter scans with rich filtering capabilities - - prowler_app_get_scan: Get comprehensive details about a specific scan - - prowler_app_trigger_scan: Trigger manual security scans for providers - - prowler_app_schedule_daily_scan: Schedule automated daily scans for continuous monitoring - - prowler_app_update_scan: Update scan names for better organization + - prowler_list_scans: Search and filter scans with rich filtering capabilities + - prowler_get_scan: Get comprehensive details about a specific scan + - prowler_trigger_scan: Trigger manual security scans for providers + - prowler_schedule_daily_scan: Schedule automated daily scans for continuous monitoring + - prowler_update_scan: Update scan names for better organization """ async def list_scans( self, provider_id: list[str] = Field( default=[], - description="Filter by Prowler's internal UUID(s) (v4) for specific provider(s), generated when the provider was registered. Use `prowler_app_search_providers` tool to find provider IDs", + description="Filter by Prowler's internal UUID(s) (v4) for specific provider(s), generated when the provider was registered. Use `prowler_search_providers` tool to find provider IDs", ), provider_type: list[str] = Field( default=[], @@ -56,7 +56,7 @@ class ScansTools(BaseTool): ), trigger: Literal["manual", "scheduled"] | None = Field( default=None, - description="Filter by how the scan was initiated. Options: 'manual' (user-initiated via prowler_app_trigger_scan), 'scheduled' (automated via prowler_app_schedule_daily_scan)", + description="Filter by how the scan was initiated. Options: 'manual' (user-initiated via prowler_trigger_scan), 'scheduled' (automated via prowler_schedule_daily_scan)", ), name: str | None = Field( default=None, @@ -75,7 +75,7 @@ class ScansTools(BaseTool): IMPORTANT: This tool returns LIGHTWEIGHT scan information. Use this for fast searching and filtering across many scans. For complete scan details including progress, duration, and resource counts, - use prowler_app_get_scan on specific scans of interest. + use prowler_get_scan on specific scans of interest. Default behavior: - Returns all scans @@ -83,15 +83,15 @@ class ScansTools(BaseTool): - Includes all scan states (available, scheduled, executing, completed, failed, cancelled) Each scan includes: - - Core identification: id (UUID for prowler_app_get_scan), name + - Core identification: id (UUID for prowler_get_scan), name - Execution context: state, trigger (manual/scheduled) - Temporal data: started_at, completed_at - Provider relationship: provider_id Workflow: 1. Use this tool to search and filter scans by provider, state, or date range - 2. Use prowler_app_get_scan with the scan 'id' to get progress, duration, and resource counts - 3. Use prowler_app_search_security_findings filtered by scan dates to analyze scan results + 2. Use prowler_get_scan with the scan 'id' to get progress, duration, and resource counts + 3. Use prowler_search_security_findings filtered by scan dates to analyze scan results """ # Validate pagination self.api_client.validate_page_size(page_size) @@ -128,15 +128,15 @@ class ScansTools(BaseTool): async def get_scan( self, scan_id: str = Field( - description="Prowler's internal UUID (v4) for the scan to retrieve, generated when the scan was created (e.g., '123e4567-e89b-12d3-a456-426614174000'). Use `prowler_app_list_scans` tool to find scan IDs" + description="Prowler's internal UUID (v4) for the scan to retrieve, generated when the scan was created (e.g., '123e4567-e89b-12d3-a456-426614174000'). Use `prowler_list_scans` tool to find scan IDs" ), ) -> dict[str, Any]: """Retrieve comprehensive details about a specific scan by its ID. IMPORTANT: This tool returns COMPLETE scan details. - Use this after finding a specific scan via prowler_app_list_scans. + Use this after finding a specific scan via prowler_list_scans. - This tool provides ALL information that prowler_app_list_scans returns PLUS: + This tool provides ALL information that prowler_list_scans returns PLUS: 1. Execution Details: - progress: Scan completion progress as percentage (0-100%) @@ -155,9 +155,9 @@ class ScansTools(BaseTool): - Understanding scan scheduling patterns Workflow: - 1. Use prowler_app_list_scans to browse and filter scans + 1. Use prowler_list_scans to browse and filter scans 2. Use this tool with the scan 'id' to monitor progress or view detailed results - 3. For completed scans, use prowler_app_search_security_findings filtered by date to analyze findings + 3. For completed scans, use prowler_search_security_findings filtered by date to analyze findings """ # Fetch scan with all fields params = { @@ -172,7 +172,7 @@ class ScansTools(BaseTool): async def trigger_scan( self, provider_id: str = Field( - description="Prowler's internal UUID (v4) for the provider to scan, generated when the provider was registered in the system (e.g., '4d0e2614-6385-4fa7-bf0b-c2e2f75c6877'). Use `prowler_app_search_providers` tool to find the provider ID" + description="Prowler's internal UUID (v4) for the provider to scan, generated when the provider was registered in the system (e.g., '4d0e2614-6385-4fa7-bf0b-c2e2f75c6877'). Use `prowler_search_providers` tool to find the provider ID" ), name: str | None = Field( default=None, @@ -182,14 +182,14 @@ class ScansTools(BaseTool): """Trigger a manual security scan for a provider. IMPORTANT: This tool returns immediately once the scan is created. - The scan will continue running in the background. Use `prowler_app_get_scan` + The scan will continue running in the background. Use `prowler_get_scan` with the returned scan ID to monitor progress and check when it completes. Example Useful Workflow: - 1. Use `prowler_app_search_providers` to find the provider_id you want to scan + 1. Use `prowler_search_providers` to find the provider_id you want to scan 2. Use this tool to trigger the scan - 3. Use `prowler_app_get_scan` with the returned scan 'id' to monitor progress - 4. Once completed, use `prowler_app_search_security_findings` to analyze results + 3. Use `prowler_get_scan` with the returned scan 'id' to monitor progress + 4. Once completed, use `prowler_search_security_findings` to analyze results """ try: # Build request data @@ -231,7 +231,7 @@ class ScansTools(BaseTool): return ScanCreationResult( scan=scan_info, status="success", - message=f"Scan {scan_id} created successfully. The scan may take some time to complete. Use prowler_app_get_scan tool with this ID to monitor progress.", + message=f"Scan {scan_id} created successfully. The scan may take some time to complete. Use prowler_get_scan tool with this ID to monitor progress.", ).model_dump() except Exception as e: @@ -245,7 +245,7 @@ class ScansTools(BaseTool): async def schedule_daily_scan( self, provider_id: str = Field( - description="Prowler's internal UUID (v4) for the provider to scan, generated when the provider was registered in the system (e.g., '4d0e2614-6385-4fa7-bf0b-c2e2f75c6877'). Use `prowler_app_search_providers` tool to find the provider ID" + description="Prowler's internal UUID (v4) for the provider to scan, generated when the provider was registered in the system (e.g., '4d0e2614-6385-4fa7-bf0b-c2e2f75c6877'). Use `prowler_search_providers` tool to find the provider ID" ), ) -> dict[str, Any]: """Schedule automated daily scans for a provider for continuous security monitoring. @@ -256,17 +256,17 @@ class ScansTools(BaseTool): you're not actively using the system. IMPORTANT: This tool returns immediately once the daily schedule is created. - The schedule will be set up in the background. Use `prowler_app_list_scans` + The schedule will be set up in the background. Use `prowler_list_scans` filtered by provider_id and trigger='scheduled' to view scheduled scans. IMPORTANT: This creates a PERSISTENT schedule. The provider will be scanned automatically every 24 hours until the provider is deleted. Example Useful Workflow: - 1. Use `prowler_app_search_providers` to find the provider_id you want to monitor + 1. Use `prowler_search_providers` to find the provider_id you want to monitor 2. Use this tool to create the daily schedule - 3. Use `prowler_app_list_scans` filtered by provider_id to view scheduled and completed scans - 4. Monitor findings over time with `prowler_app_search_security_findings` + 3. Use `prowler_list_scans` filtered by provider_id to view scheduled and completed scans + 4. Monitor findings over time with `prowler_search_security_findings` """ self.logger.info(f"Creating daily schedule for provider {provider_id}") task_response = await self.api_client.post( @@ -285,7 +285,7 @@ class ScansTools(BaseTool): ) if task_state == "available": - return_message = "Daily schedule created successfully. The schedule is being set up in the background. Use prowler_app_list_scans with provider_id filter to view scheduled scans." + return_message = "Daily schedule created successfully. The schedule is being set up in the background. Use prowler_list_scans with provider_id filter to view scheduled scans." else: return_message = "Daily schedule creation failed. Please try again later." @@ -297,7 +297,7 @@ class ScansTools(BaseTool): async def update_scan( self, scan_id: str = Field( - description="Prowler's internal UUID (v4) for the scan to update, generated when the scan was created (e.g., '123e4567-e89b-12d3-a456-426614174000'). Use `prowler_app_list_scans` tool to find the scan ID if you only know the provider or scan name. Returns an error if the scan ID is invalid or not found." + description="Prowler's internal UUID (v4) for the scan to update, generated when the scan was created (e.g., '123e4567-e89b-12d3-a456-426614174000'). Use `prowler_list_scans` tool to find the scan ID if you only know the provider or scan name. Returns an error if the scan ID is invalid or not found." ), name: str = Field( description="New human-friendly name for the scan (3-100 characters). Use descriptive names to improve organization and tracking, e.g., 'Production Security Audit - Q4 2025', 'Post-Deployment Compliance Check'. IMPORTANT: Only the scan name can be updated - other attributes (state, progress, duration) are read-only and managed by the system." @@ -309,7 +309,7 @@ class ScansTools(BaseTool): (state, progress, duration, etc.) are read-only and managed by the system. Example Useful Workflow: - 1. Use `prowler_app_list_scans` to find the scan you want to rename + 1. Use `prowler_list_scans` to find the scan you want to rename 2. Use this tool with the scan 'id' and new name """ api_response = await self.api_client.patch( diff --git a/mcp_server/prowler_mcp_server/prowler_app/utils/api_client.py b/mcp_server/prowler_mcp_server/prowler_app/utils/api_client.py index a6aacc3ce1..187364bee1 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/utils/api_client.py +++ b/mcp_server/prowler_mcp_server/prowler_app/utils/api_client.py @@ -1,4 +1,4 @@ -"""Shared API client utilities for Prowler App tools.""" +"""Shared API client utilities for Prowler tools.""" import asyncio from datetime import datetime, timedelta diff --git a/mcp_server/prowler_mcp_server/prowler_app/utils/auth.py b/mcp_server/prowler_mcp_server/prowler_app/utils/auth.py index 72c06000df..eff5d3a117 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/utils/auth.py +++ b/mcp_server/prowler_mcp_server/prowler_app/utils/auth.py @@ -10,7 +10,7 @@ from prowler_mcp_server.lib.logger import logger class ProwlerAppAuth: - """Handles authentication for Prowler App API using API keys or JWT tokens.""" + """Handles authentication for Prowler API using API keys or JWT tokens.""" def __init__( self, @@ -18,19 +18,23 @@ class ProwlerAppAuth: base_url: str = os.getenv("API_BASE_URL", "https://api.prowler.com/api/v1"), ): self.base_url = base_url.rstrip("/") - logger.info(f"Using Prowler App API base URL: {self.base_url}") + logger.info(f"Using Prowler API base URL: {self.base_url}") self.mode = mode self.access_token: str | None = None self.api_key: str | None = None if mode == "stdio": # STDIO mode - self.api_key = os.getenv("PROWLER_APP_API_KEY") + # PROWLER_API_KEY is the current variable; PROWLER_APP_API_KEY is kept + # as a backward-compatible fallback so existing setups keep working. + self.api_key = os.getenv("PROWLER_API_KEY") or os.getenv( + "PROWLER_APP_API_KEY" + ) if not self.api_key: - raise ValueError("PROWLER_APP_API_KEY environment variable is required") + raise ValueError("PROWLER_API_KEY environment variable is required") if not self.api_key.startswith("pk_"): - raise ValueError("Prowler App API key format is incorrect") + raise ValueError("Prowler API key format is incorrect") def _parse_jwt(self, token: str) -> dict | None: """Parse JWT token and return payload diff --git a/mcp_server/prowler_mcp_server/prowler_app/utils/tool_loader.py b/mcp_server/prowler_mcp_server/prowler_app/utils/tool_loader.py index b85c13af35..3a00474b5f 100644 --- a/mcp_server/prowler_mcp_server/prowler_app/utils/tool_loader.py +++ b/mcp_server/prowler_mcp_server/prowler_app/utils/tool_loader.py @@ -13,18 +13,27 @@ from prowler_mcp_server.lib.logger import logger from prowler_mcp_server.prowler_app.tools.base import BaseTool -def load_all_tools(mcp: FastMCP) -> None: - """Auto-discover and load all BaseTool subclasses from the tools package. +def load_all_tools( + mcp: FastMCP, + tools_package: str = "prowler_mcp_server.prowler_app.tools", +) -> None: + """Auto-discover and load all BaseTool subclasses from a tools package. This function: - 1. Dynamically imports all Python modules in the tools package - 2. Discovers all concrete BaseTool subclasses + 1. Dynamically imports all Python modules in the given tools package + 2. Discovers all concrete BaseTool subclasses defined in that package 3. Instantiates each tool class 4. Registers all tools with the provided FastMCP instance + ``BaseTool.__subclasses__()`` returns every subclass in the process, so the + discovered classes are filtered by ``__module__`` prefix. This keeps sibling + sub-servers (e.g. ``prowler_app`` and ``prowler_cloud``) from cross-registering + each other's tools, regardless of import order. + Args: mcp: The FastMCP instance to register tools with - TOOLS_PACKAGE: The package path containing tool modules (default: prowler_mcp_server.prowler_app.tools) + tools_package: The package path containing tool modules + (default: prowler_mcp_server.prowler_app.tools) Example: from fastmcp import FastMCP @@ -33,7 +42,7 @@ def load_all_tools(mcp: FastMCP) -> None: app = FastMCP("prowler-app") load_all_tools(app) """ - TOOLS_PACKAGE = "prowler_mcp_server.prowler_app.tools" + TOOLS_PACKAGE = tools_package logger.info(f"Auto-discovering tools from package: {TOOLS_PACKAGE}") # Import the tools package @@ -59,11 +68,14 @@ def load_all_tools(mcp: FastMCP) -> None: except Exception as e: logger.error(f"Failed to import module {module_name}: {e}") - # Discover all concrete BaseTool subclasses + # Discover all concrete BaseTool subclasses defined in this package only. + # __subclasses__() is process-wide, so filter by module to avoid sibling + # sub-servers cross-registering each other's tools. concrete_tools = [ tool_class for tool_class in BaseTool.__subclasses__() if not getattr(tool_class, "__abstractmethods__", None) + and tool_class.__module__.startswith(TOOLS_PACKAGE) ] logger.info(f"Discovered {len(concrete_tools)} tool classes") diff --git a/mcp_server/prowler_mcp_server/server.py b/mcp_server/prowler_mcp_server/server.py index 7c85641dee..a46ca12672 100644 --- a/mcp_server/prowler_mcp_server/server.py +++ b/mcp_server/prowler_mcp_server/server.py @@ -19,15 +19,15 @@ def setup_main_server(): except Exception as e: logger.error(f"Failed to mount Prowler Hub server: {e}") - # Mount Prowler App tools with prowler_app_ namespace + # Mount core Prowler tools with prowler_ namespace try: - logger.info("Mounting Prowler App server...") + logger.info("Mounting Prowler tools server...") from prowler_mcp_server.prowler_app.server import app_mcp_server - prowler_mcp_server.mount(app_mcp_server, namespace="prowler_app") - logger.info("Successfully mounted Prowler App server") + prowler_mcp_server.mount(app_mcp_server, namespace="prowler") + logger.info("Successfully mounted Prowler tools server") except Exception as e: - logger.error(f"Failed to mount Prowler App server: {e}") + logger.error(f"Failed to mount Prowler tools server: {e}") # Mount Prowler Documentation tools with prowler_docs_ namespace try: diff --git a/mcp_server/pyproject.toml b/mcp_server/pyproject.toml index 63aefdf931..f27e08b743 100644 --- a/mcp_server/pyproject.toml +++ b/mcp_server/pyproject.toml @@ -19,11 +19,13 @@ description = "MCP server for Prowler ecosystem" name = "prowler-mcp" readme = "README.md" requires-python = ">=3.12" -version = "0.5.0" +version = "0.8.0" [project.scripts] prowler-mcp = "prowler_mcp_server.main:main" +[tool.pytest] + [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/mcp_server/uv.lock b/mcp_server/uv.lock index 3258767442..a9afbeafd7 100644 --- a/mcp_server/uv.lock +++ b/mcp_server/uv.lock @@ -676,7 +676,7 @@ wheels = [ [[package]] name = "prowler-mcp" -version = "0.5.0" +version = "0.8.0" source = { editable = "." } dependencies = [ { name = "fastmcp" }, diff --git a/skills/prowler-mcp/SKILL.md b/skills/prowler-mcp/SKILL.md index af3c597771..704acf8553 100644 --- a/skills/prowler-mcp/SKILL.md +++ b/skills/prowler-mcp/SKILL.md @@ -19,7 +19,7 @@ The Prowler MCP Server uses three sub-servers with prefixed namespacing: | Sub-Server | Prefix | Auth | Purpose | |------------|--------|------|---------| -| Prowler App | `prowler_app_*` | Required | Cloud management tools | +| Prowler | `prowler_*` | Required | Prowler Cloud, Private Cloud & Local Server management tools | | Prowler Hub | `prowler_hub_*` | No | Security checks catalog | | Prowler Docs | `prowler_docs_*` | No | Documentation search | @@ -27,7 +27,7 @@ For complete architecture, patterns, and examples, see [docs/developer-guide/mcp --- -## Critical Rules (Prowler App Only) +## Critical Rules (Prowler Tools Only) ### Tool Implementation @@ -56,7 +56,7 @@ Use `@mcp.tool()` decorator directly—no BaseTool or models required. --- -## Quick Reference: New Prowler App Tool +## Quick Reference: New Prowler Tool 1. Create tool class in `prowler_app/tools/` extending `BaseTool` 2. Create models in `prowler_app/models/` using `MinimalSerializerMixin` @@ -64,7 +64,7 @@ Use `@mcp.tool()` decorator directly—no BaseTool or models required. --- -## QA Checklist (Prowler App) +## QA Checklist (Prowler Tools) - [ ] Tool docstrings describe LLM-relevant behavior - [ ] Models use `MinimalSerializerMixin` diff --git a/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx b/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx index 8b6855392f..ab11429774 100644 --- a/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx +++ b/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx @@ -51,7 +51,7 @@ describe("MessageBubble", () => { // Given const orderedMessage = buildAssistantMessage([ textPart("part-1", "Voy a buscar los findings por severidad"), - toolCallPart("part-2", "prowler_app_search_security_findings"), + toolCallPart("part-2", "prowler_search_security_findings"), textPart("part-3", "Ahora voy a buscar en los criticos"), ]); diff --git a/ui/app/(prowler)/lighthouse/_lib/event-reducer.test.ts b/ui/app/(prowler)/lighthouse/_lib/event-reducer.test.ts index 4f284a5656..89c62ef8bc 100644 --- a/ui/app/(prowler)/lighthouse/_lib/event-reducer.test.ts +++ b/ui/app/(prowler)/lighthouse/_lib/event-reducer.test.ts @@ -62,7 +62,7 @@ describe("event-reducer", () => { state = reduceLighthouseV2Event(state, { type: "tool_call.start", toolCallId: "tool-1", - toolName: "prowler_app_search_security_findings", + toolName: "prowler_search_security_findings", }); state = reduceLighthouseV2Event(state, { type: "tool_call.end", @@ -84,7 +84,7 @@ describe("event-reducer", () => { { id: "tool-1", type: "tool_call", - name: "prowler_app_search_security_findings", + name: "prowler_search_security_findings", status: "completed", outcome: "success", }, diff --git a/ui/app/(prowler)/lighthouse/_lib/tool-calls.test.ts b/ui/app/(prowler)/lighthouse/_lib/tool-calls.test.ts index 570e7cc597..5ccc2b4129 100644 --- a/ui/app/(prowler)/lighthouse/_lib/tool-calls.test.ts +++ b/ui/app/(prowler)/lighthouse/_lib/tool-calls.test.ts @@ -11,7 +11,7 @@ describe("getToolCallContent", () => { // Given const content = { tool_call_id: "call_1", - tool_name: "prowler_app_search_security_findings", + tool_name: "prowler_search_security_findings", arguments: { severity: "high" }, result: { count: 3 }, outcome: "success", @@ -23,7 +23,7 @@ describe("getToolCallContent", () => { // Then expect(parsed).toEqual({ toolCallId: "call_1", - toolName: "prowler_app_search_security_findings", + toolName: "prowler_search_security_findings", arguments: { severity: "high" }, result: { count: 3 }, outcome: "success", @@ -53,12 +53,18 @@ describe("getToolCallContent", () => { describe("formatToolName", () => { it("should strip the prowler prefix and title-case", () => { - expect(formatToolName("prowler_app_search_security_findings")).toBe( + expect(formatToolName("prowler_search_security_findings")).toBe( "Search security findings", ); expect(formatToolName("prowler_hub_list_checks")).toBe("List checks"); }); + it("should still strip the legacy prowler_app_ prefix", () => { + expect(formatToolName("prowler_app_search_security_findings")).toBe( + "Search security findings", + ); + }); + it("should humanize prefix-less tools", () => { expect(formatToolName("search_tools")).toBe("Search tools"); }); diff --git a/ui/app/(prowler)/lighthouse/_lib/tool-calls.ts b/ui/app/(prowler)/lighthouse/_lib/tool-calls.ts index 46034102d5..88e478089b 100644 --- a/ui/app/(prowler)/lighthouse/_lib/tool-calls.ts +++ b/ui/app/(prowler)/lighthouse/_lib/tool-calls.ts @@ -1,11 +1,14 @@ import type { LighthouseV2ToolCallContent } from "@/app/(prowler)/lighthouse/_types"; // Prefixes shared by the MCP-sourced tools; stripped for display so a name like -// `prowler_app_search_security_findings` reads as "Search security findings". +// `prowler_search_security_findings` reads as "Search security findings". The +// specific prefixes are listed before the bare `prowler_` catch-all so Hub, Docs, +// and legacy `prowler_app_` records match first and render cleanly. const TOOL_NAME_PREFIXES = [ - "prowler_app_", "prowler_hub_", "prowler_docs_", + "prowler_app_", + "prowler_", ] as const; // Reads the snake_case TOOL_CALL blob the backend persists and normalizes it to diff --git a/ui/changelog.d/prowler-tools-namespace.changed.md b/ui/changelog.d/prowler-tools-namespace.changed.md new file mode 100644 index 0000000000..f1affd1715 --- /dev/null +++ b/ui/changelog.d/prowler-tools-namespace.changed.md @@ -0,0 +1 @@ +Core Prowler tools in Lighthouse use the `prowler_*` namespace while preserving legacy `prowler_app_*` compatibility diff --git a/ui/lib/lighthouse-v1/allowed-tools.test.ts b/ui/lib/lighthouse-v1/allowed-tools.test.ts new file mode 100644 index 0000000000..7812a72282 --- /dev/null +++ b/ui/lib/lighthouse-v1/allowed-tools.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from "vitest"; + +import { isAllowedTool } from "./allowed-tools"; + +describe("isAllowedTool", () => { + it("should accept a whitelisted tool using the current namespace", () => { + // Given + const toolName = "prowler_search_security_findings"; + + // When + const result = isAllowedTool(toolName); + + // Then + expect(result).toBe(true); + }); + + it("should accept a whitelisted tool using the legacy namespace", () => { + // Given + const toolName = "prowler_app_search_security_findings"; + + // When + const result = isAllowedTool(toolName); + + // Then + expect(result).toBe(true); + }); + + it("should reject a non-whitelisted tool after normalizing the legacy namespace", () => { + // Given + const toolName = "prowler_app_delete_provider"; + + // When + const result = isAllowedTool(toolName); + + // Then + expect(result).toBe(false); + }); +}); diff --git a/ui/lib/lighthouse-v1/allowed-tools.ts b/ui/lib/lighthouse-v1/allowed-tools.ts new file mode 100644 index 0000000000..ebce1e40a4 --- /dev/null +++ b/ui/lib/lighthouse-v1/allowed-tools.ts @@ -0,0 +1,67 @@ +/** + * Tools explicitly allowed for the LLM to list and execute. + * Follows the principle of least privilege - only these tools are accessible. + * All other tools are blocked by default. + */ +const ALLOWED_TOOLS = new Set([ + // === Prowler Hub Tools - read-only === + "prowler_hub_list_checks", + "prowler_hub_semantic_search_checks", + "prowler_hub_get_check_details", + "prowler_hub_get_check_code", + "prowler_hub_get_check_fixer", + "prowler_hub_list_compliances", + "prowler_hub_semantic_search_compliances", + "prowler_hub_get_compliance_details", + "prowler_hub_list_providers", + "prowler_hub_get_provider_services", + // === Prowler Docs Tools - read-only === + "prowler_docs_search", + "prowler_docs_get_document", + // === Prowler platform Tools - read-only === + // Findings + "prowler_search_security_findings", + "prowler_get_finding_details", + "prowler_get_findings_overview", + // Finding Groups + "prowler_list_finding_groups", + "prowler_get_finding_group_details", + "prowler_list_finding_group_resources", + // Providers + "prowler_search_providers", + // Scans + "prowler_list_scans", + "prowler_get_scan", + // Muting + "prowler_get_mutelist", + "prowler_list_mute_rules", + "prowler_get_mute_rule", + // Compliance + "prowler_get_compliance_overview", + "prowler_get_compliance_framework_state_details", + // Resources + "prowler_list_resources", + "prowler_get_resource", + "prowler_get_resource_events", + "prowler_get_resources_overview", + // Attack Paths + "prowler_list_attack_paths_queries", + "prowler_list_attack_paths_scans", + "prowler_run_attack_paths_query", + "prowler_get_attack_paths_cartography_schema", +]); + +/** + * Check if a tool is allowed for LLM access. + * Returns true only if the tool is explicitly in the whitelist. + * + * The Prowler platform tools were renamed from the `prowler_app_` prefix to + * `prowler_`. The legacy prefix is normalized here so tools served by + * an older MCP server (or a mismatched rollout) still resolve. + */ +export function isAllowedTool(toolName: string): boolean { + const normalized = toolName.startsWith("prowler_app_") + ? toolName.replace(/^prowler_app_/, "prowler_") + : toolName; + return ALLOWED_TOOLS.has(normalized); +} diff --git a/ui/lib/lighthouse-v1/mcp-client.ts b/ui/lib/lighthouse-v1/mcp-client.ts index cbce9351a4..588ff24ac8 100644 --- a/ui/lib/lighthouse-v1/mcp-client.ts +++ b/ui/lib/lighthouse-v1/mcp-client.ts @@ -77,7 +77,7 @@ class MCPClientManager { } /** - * Injects auth headers for Prowler App tools + * Injects auth headers for the core Prowler tools */ private handleBeforeToolCall = ({ name, @@ -87,9 +87,15 @@ class MCPClientManager { name: string; args?: unknown; }) => { - // Only inject auth for Prowler App tools (user-specific data) - // Prowler Hub and Prowler Docs tools don't require authentication - if (!name.startsWith("prowler_app_")) { + // Only inject auth for the core Prowler tools (user-specific data), served + // under the bare `prowler_` prefix. Prowler Hub (`prowler_hub_`) and Prowler + // Docs (`prowler_docs_`) tools are public and need no authentication. The + // legacy `prowler_app_` prefix also starts with `prowler_`, so it is covered. + const needsAuth = + name.startsWith("prowler_") && + !name.startsWith("prowler_hub_") && + !name.startsWith("prowler_docs_"); + if (!needsAuth) { return { args }; } diff --git a/ui/lib/lighthouse-v1/skills/definitions/attack-path-custom-query.ts b/ui/lib/lighthouse-v1/skills/definitions/attack-path-custom-query.ts index 7bb2ed08a1..15a298fd2c 100644 --- a/ui/lib/lighthouse-v1/skills/definitions/attack-path-custom-query.ts +++ b/ui/lib/lighthouse-v1/skills/definitions/attack-path-custom-query.ts @@ -15,9 +15,9 @@ This skill provides openCypher syntax guidance and Cartography schema knowledge Follow these steps when the user asks you to write a custom openCypher query: -1. **Find a completed scan**: Use \`prowler_app_list_attack_paths_scans\` (filter by \`state=['completed']\`) to find a scan for the user's provider. You need the \`scan_id\` for the next step. +1. **Find a completed scan**: Use \`prowler_list_attack_paths_scans\` (filter by \`state=['completed']\`) to find a scan for the user's provider. You need the \`scan_id\` for the next step. -2. **Fetch the Cartography schema**: Use \`prowler_app_get_attack_paths_cartography_schema\` with the \`scan_id\`. This returns the full schema markdown with all node labels, relationships, and properties for the scan's provider and Cartography version. If this tool fails, use the Cartography Schema Reference section below as a fallback (AWS only). +2. **Fetch the Cartography schema**: Use \`prowler_get_attack_paths_cartography_schema\` with the \`scan_id\`. This returns the full schema markdown with all node labels, relationships, and properties for the scan's provider and Cartography version. If this tool fails, use the Cartography Schema Reference section below as a fallback (AWS only). 3. **Analyze the schema**: From \`schema_content\`, identify the node labels, properties, and relationships relevant to the user's request. Cross-reference with the Common openCypher Patterns section below. diff --git a/ui/lib/lighthouse-v1/system-prompt.ts b/ui/lib/lighthouse-v1/system-prompt.ts index c508e42ddd..317aabf7ef 100644 --- a/ui/lib/lighthouse-v1/system-prompt.ts +++ b/ui/lib/lighthouse-v1/system-prompt.ts @@ -59,7 +59,7 @@ You have access to THREE meta-tools to interact with the available tools and ski - Use empty object {} for tools with no parameters - You must always provide the toolName and toolInput keys in the JSON object - Example: execute_tool({ "toolName": "prowler_hub_list_providers", "toolInput": {} }) - - Example: execute_tool({ "toolName": "prowler_app_search_security_findings", "toolInput": { "severity": ["critical", "high"], "status": ["FAIL"] } }) + - Example: execute_tool({ "toolName": "prowler_search_security_findings", "toolInput": { "severity": ["critical", "high"], "status": ["FAIL"] } }) 3. **load_skill** - Load specialized instructions for a complex task - Use when you identify a matching skill from the skill catalog below diff --git a/ui/lib/lighthouse-v1/tools/meta-tool.ts b/ui/lib/lighthouse-v1/tools/meta-tool.ts index 4ea4e39e74..f5c2cf7f75 100644 --- a/ui/lib/lighthouse-v1/tools/meta-tool.ts +++ b/ui/lib/lighthouse-v1/tools/meta-tool.ts @@ -5,8 +5,8 @@ import { tool } from "@langchain/core/tools"; import { addBreadcrumb, captureException } from "@sentry/nextjs"; import { z } from "zod"; +import { isAllowedTool } from "@/lib/lighthouse-v1/allowed-tools"; import { getMCPTools, isMCPAvailable } from "@/lib/lighthouse-v1/mcp-client"; -import { isAllowedTool } from "@/lib/lighthouse-v1/workflow"; /** Input type for describe_tool */ interface DescribeToolInput { @@ -95,7 +95,7 @@ Use this to understand what parameters a tool requires before executing it. Tool names are listed in your system prompt - use the exact name. You must always provide the toolName key in the JSON object. -Example: describe_tool({ "toolName": "prowler_app_search_security_findings" }) +Example: describe_tool({ "toolName": "prowler_search_security_findings" }) Returns: - Full parameter schema with types and descriptions @@ -203,7 +203,7 @@ export const executeTool = tool( Provide the exact tool name and its input parameters as specified in the tool's schema. You must always provide the toolName and toolInput keys in the JSON object. -Example: execute_tool({ "toolName": "prowler_app_search_security_findings", "toolInput": {} }) +Example: execute_tool({ "toolName": "prowler_search_security_findings", "toolInput": {} }) All input to the tool must be provided in the toolInput key as a JSON object. Example: execute_tool({ "toolName": "prowler_hub_list_compliances", "toolInput": { "provider": ["aws"] } }) diff --git a/ui/lib/lighthouse-v1/workflow.ts b/ui/lib/lighthouse-v1/workflow.ts index 1c31b7f58d..77a6f4ad76 100644 --- a/ui/lib/lighthouse-v1/workflow.ts +++ b/ui/lib/lighthouse-v1/workflow.ts @@ -4,6 +4,7 @@ import { getProviderCredentials, getTenantConfig, } from "@/actions/lighthouse-v1/lighthouse"; +import { isAllowedTool } from "@/lib/lighthouse-v1/allowed-tools"; import { TOOLS_UNAVAILABLE_MESSAGE } from "@/lib/lighthouse-v1/constants"; import type { ProviderType } from "@/lib/lighthouse-v1/llm-factory"; import { createLLM } from "@/lib/lighthouse-v1/llm-factory"; @@ -42,67 +43,6 @@ function truncateDescription(desc: string | undefined, maxLen: number): string { return cleaned.substring(0, maxLen) + "..."; } -/** - * Tools explicitly allowed for the LLM to list and execute. - * Follows the principle of least privilege - only these tools are accessible. - * All other tools are blocked by default. - */ -const ALLOWED_TOOLS = new Set([ - // === Prowler Hub Tools - read-only === - "prowler_hub_list_checks", - "prowler_hub_semantic_search_checks", - "prowler_hub_get_check_details", - "prowler_hub_get_check_code", - "prowler_hub_get_check_fixer", - "prowler_hub_list_compliances", - "prowler_hub_semantic_search_compliances", - "prowler_hub_get_compliance_details", - "prowler_hub_list_providers", - "prowler_hub_get_provider_services", - // === Prowler Docs Tools - read-only === - "prowler_docs_search", - "prowler_docs_get_document", - // === Prowler App Tools - read-only === - // Findings - "prowler_app_search_security_findings", - "prowler_app_get_finding_details", - "prowler_app_get_findings_overview", - // Finding Groups - "prowler_app_list_finding_groups", - "prowler_app_get_finding_group_details", - "prowler_app_list_finding_group_resources", - // Providers - "prowler_app_search_providers", - // Scans - "prowler_app_list_scans", - "prowler_app_get_scan", - // Muting - "prowler_app_get_mutelist", - "prowler_app_list_mute_rules", - "prowler_app_get_mute_rule", - // Compliance - "prowler_app_get_compliance_overview", - "prowler_app_get_compliance_framework_state_details", - // Resources - "prowler_app_list_resources", - "prowler_app_get_resource", - "prowler_app_get_resource_events", - "prowler_app_get_resources_overview", - // Attack Paths - "prowler_app_list_attack_paths_queries", - "prowler_app_list_attack_paths_scans", - "prowler_app_run_attack_paths_query", - "prowler_app_get_attack_paths_cartography_schema", -]); - -/** - * Check if a tool is allowed for LLM access. - * Returns true only if the tool is explicitly in the whitelist. - */ -export function isAllowedTool(toolName: string): boolean { - return ALLOWED_TOOLS.has(toolName); -} - /** * Generate dynamic tool listing from MCP tools. * Only includes tools that are explicitly whitelisted.