get_detection
Retrieve detailed information about security detections in Panther, including detection bodies and test cases, to analyze and understand threat monitoring rules.
Instructions
Get detailed information about a Panther detection, including the detection body and tests.
Permissions:{'all_of': ['View Rules', 'View Policies']}
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| detection_id | Yes | The ID of the detection to fetch | |
| detection_type | No | One or more detection types - rules, scheduled_rules, simple_rules, or policies. |
Implementation Reference
- The main handler function implementing the 'get_detection' MCP tool. It fetches detailed information for a specific detection ID across specified detection types (rules, policies, etc.) using the Panther REST API, handles multiple types, 404s gracefully, and returns structured results with found/not found info.@mcp_tool( annotations={ "permissions": all_perms(Permission.RULE_READ, Permission.POLICY_READ), "readOnlyHint": True, } ) async def get_detection( detection_id: Annotated[ str, Field( description="The ID of the detection to fetch", examples=["AWS.Suspicious.S3.Activity", "GCP.K8S.Privileged.Pod.Created"], ), ], detection_type: Annotated[ list[str], Field( description="One or more detection types - rules, scheduled_rules, simple_rules, or policies.", examples=[ ["rules", "simple_rules", "scheduled_rules"], ["policies"], ], ), ] = ["rules"], ) -> dict[str, Any]: """Get detailed information about a Panther detection, including the detection body and tests.""" # Validate detection types validation_error = validate_detection_types(detection_type) if validation_error: return validation_error logger.info(f"Fetching details for ID {detection_id} in types: {detection_type}") # Use centralized field mapping field_map = SINGULAR_FIELD_MAP try: found_results = {} not_found_types = [] async with get_rest_client() as client: for dt in detection_type: # Allow 404 as a valid response to handle not found case result, status = await client.get( get_endpoint_for_detection(dt, detection_id), expected_codes=[200, 404], ) if status == 404: not_found_types.append(dt) # Use proper singular form from mapping instead of naive string manipulation singular_form = SINGULAR_FIELD_MAP[dt].replace("_", " ") logger.warning(f"No {singular_form} found with ID: {detection_id}") else: found_results[dt] = result logger.info( f"Successfully retrieved {dt} details for ID: {detection_id}" ) # If we found results in any detection type, return success if found_results: response = {"success": True} # Add results for each found type for dt, result in found_results.items(): response[field_map[dt]] = result # Add info about not found types if any if not_found_types: response["not_found_in_types"] = not_found_types response["found_in_types"] = list(found_results.keys()) return response else: # Not found in any of the specified detection types return { "success": False, "message": f"No detection found with ID {detection_id} in any of the specified types: {detection_type}", } except Exception as e: logger.error( f"Failed to get detection details for types {detection_type}: {str(e)}" ) return { "success": False, "message": f"Failed to get detection details for types {detection_type}: {str(e)}", }
- src/mcp_panther/server.py:71-76 (registration)The call to register_all_tools(mcp) which automatically registers all @mcp_tool decorated functions, including get_detection, with the FastMCP server instance.# Register all tools with MCP using the registry register_all_tools(mcp) # Register all prompts with MCP using the registry register_all_prompts(mcp) # Register all resources with MCP using the registry register_all_resources(mcp)
- Helper function used by get_detection to construct the correct REST API endpoint based on detection type and ID.def get_endpoint_for_detection( detection_type: str, detection_id: str | None = None ) -> str: """Get the API endpoint for a detection type, optionally with an ID.""" base_endpoint = DETECTION_TYPES[detection_type] return f"{base_endpoint}/{detection_id}" if detection_id else base_endpoint
- Helper function used by get_detection to validate the provided detection_types parameter.def validate_detection_types(detection_types: list[str]) -> dict[str, Any] | None: """Validate detection types and return error dict if invalid, None if valid.""" if not detection_types: return { "success": False, "message": "At least one detection type must be specified.", } invalid_types = [dt for dt in detection_types if dt not in DETECTION_TYPES] if invalid_types: valid_types = ", ".join(DETECTION_TYPES.keys()) return { "success": False, "message": f"Invalid detection_types {invalid_types}. Valid values are: {valid_types}", } return None