Skip to main content
Glama
detection-forge

agentic-detection-lookups

Check Parent-Child Process

detection_check_parent_child
Read-onlyIdempotent

Evaluate parent-child process relationships to detect suspicious chains. Identifies risks, maps to MITRE techniques, and provides triage notes.

Instructions

Check if a process parent-child relationship is expected or suspicious.

Provide parent and child process filenames (e.g., parent='winword.exe', child='cmd.exe'). Returns whether the relationship is expected, the risk if unexpected, MITRE technique, and triage notes.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
parentYes
childYes
os_filterNowindows

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The `detection_check_parent_child` function is the actual tool handler. It takes parent and child process filenames plus an optional OS filter (default 'windows'), normalizes them, looks up the relationship in the parent-child baselines CSV data, and returns whether the relationship is expected, suspicious, or unknown. It supports glob matching via `_match_filename` and wildcard child matching.
    def detection_check_parent_child(
        parent: str,
        child: str,
        os_filter: str = "windows",
    ) -> dict[str, Any]:
        """Check if a process parent-child relationship is expected or suspicious.
    
        Provide parent and child process filenames (e.g., parent='winword.exe', child='cmd.exe').
        Returns whether the relationship is expected, the risk if unexpected, MITRE technique, and triage notes.
        """
        parent_lower = parent.lower().strip()
        child_lower = child.lower().strip()
    
        # Strip paths
        if "\\" in parent_lower or "/" in parent_lower:
            parent_lower = parent_lower.replace("\\", "/").split("/")[-1]
        if "\\" in child_lower or "/" in child_lower:
            child_lower = child_lower.replace("\\", "/").split("/")[-1]
    
        matches = []
        for row in _get_parent_child():
            if row.get("os", "").lower() != os_filter.lower():
                continue
    
            row_parent = row.get("parent", "").lower()
            row_child = row.get("child", "").lower()
    
            # Check parent match (exact or glob)
            parent_match = _match_filename(row_parent, parent_lower)
            # Check child match (exact, glob, or wildcard)
            child_match = row_child == "*" or _match_filename(row_child, child_lower)
    
            if parent_match and child_match:
                matches.append({
                    "parent": row.get("parent", ""),
                    "child": row.get("child", ""),
                    "os": row.get("os", ""),
                    "expected": row.get("expected", ""),
                    "risk_if_unexpected": row.get("risk_if_unexpected", ""),
                    "mitre_id": row.get("mitre_id", ""),
                    "context": row.get("context", ""),
                    "notes": row.get("notes", ""),
                })
    
        if not matches:
            return {
                "found": False,
                "parent": parent_lower,
                "child": child_lower,
                "os": os_filter,
                "assessment": (
                    "No baseline entry found. This may be suspicious — "
                    "undocumented parent-child relationships warrant investigation."
                ),
                "suggestion": (
                    "Try checking each process individually with "
                    "detection_lookup_binary to see if either is a known LOLBin."
                ),
            }
    
        # Return most specific match (prefer exact child over wildcard)
        best = sorted(matches, key=lambda m: (m["child"] == "*", m["expected"] == "true"))
        return {"found": True, "matches": best}
  • The `@mcp.tool` decorator on `detection_check_parent_child` registers the tool with FastMCP, providing annotations (title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint) that serve as the tool's schema/metadata.
    @mcp.tool(
        annotations={
            "title": "Check Parent-Child Process",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": False,
        },
    )
    def detection_check_parent_child(
        parent: str,
        child: str,
        os_filter: str = "windows",
    ) -> dict[str, Any]:
  • The `@mcp.tool()` decorator on line 142 registers `detection_check_parent_child` as an MCP tool with the FastMCP server instance.
    @mcp.tool(
        annotations={
            "title": "Check Parent-Child Process",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": False,
        },
    )
    def detection_check_parent_child(
        parent: str,
        child: str,
        os_filter: str = "windows",
    ) -> dict[str, Any]:
  • The `_match_filename` helper function provides glob-based filename matching (case-insensitive via `fnmatch`), used by the handler to match parent and child process names against CSV baseline entries.
    def _match_filename(pattern: str, value: str) -> bool:
        """Match with glob support (e.g., 'tomcat*.exe')."""
        return fnmatch(value.lower(), pattern.lower())
  • The `_get_parent_child` helper function lazily loads and caches the parent-child baselines CSV data (`parent_child_baselines.csv`) used by the handler for lookups.
    def _get_parent_child() -> list[dict[str, str]]:
        global _parent_child_cache
        if _parent_child_cache is None:
            _parent_child_cache = _load_csv("parent_child_baselines.csv")
        return _parent_child_cache
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes beyond the annotations (readOnlyHint=true, destructiveHint=false, idempotentHint=true) by detailing what the tool returns: 'whether the relationship is expected, the risk if unexpected, MITRE technique, and triage notes.' No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise: three sentences with no wasted words. The first sentence states the purpose, the second gives usage guidance, and the third lists the output fields. All information is front-loaded and relevant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter tool with an output schema (not shown but mentioned), the description covers inputs and outputs reasonably well. The only gap is the undocumented 'os_filter' parameter. The description provides enough context for an agent to use the tool effectively in most cases.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description explains the 'parent' and 'child' parameters with an example, which adds meaning beyond the schema (which has no descriptions). However, the 'os_filter' parameter is not mentioned at all, despite being optional with a default. Since schema description coverage is 0%, the description should cover all parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Check if a process parent-child relationship is expected or suspicious.' The verb 'check' combined with the resource 'parent-child relationship' is specific. It is distinct from sibling tools like 'detection_search' or 'detection_list_by_category' which handle listing or searching, not verification of relationships.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to provide parent and child process filenames, with an example ('parent='winword.exe', child='cmd.exe''). This gives clear context on how to use the tool. However, it does not mention when not to use it or suggest alternatives from the sibling list, such as 'detection_search' for broader queries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/detection-forge/agentic-detection-lookups'

If you have feedback or need assistance with the MCP directory API, please join our Discord server