Skip to main content
Glama
SlanyCukr

Bug Bounty MCP Server

by SlanyCukr

nmap_scan

Execute enhanced Nmap scans on targets with real-time logging for version detection, script execution, and custom port scanning to identify network vulnerabilities and services.

Instructions

Execute an enhanced Nmap scan against a target with real-time logging.

Args: target: The IP address or hostname to scan scan_type: Scan type (e.g., -sV for version detection, -sC for scripts) ports: Comma-separated list of ports or port ranges additional_args: Additional Nmap arguments

Returns: Scan results with enhanced telemetry

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
additional_argsNo
portsNo
scan_typeNo-sV
targetYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • MCP tool 'nmap_scan' handler: defines the tool interface, parameters, and proxies execution to the REST API server endpoint '/api/nmap' with logging.
    @mcp.tool()
    def nmap_scan(
        target: str, scan_type: str = "-sV", ports: str = "", additional_args: str = ""
    ) -> dict[str, Any]:
        """Execute an enhanced Nmap scan against a target with real-time logging.
    
        Args:
            target: The IP address or hostname to scan
            scan_type: Scan type (e.g., -sV for version detection, -sC for scripts)
            ports: Comma-separated list of ports or port ranges
            additional_args: Additional Nmap arguments
    
        Returns:
            Scan results with enhanced telemetry
        """
        data = {
            "target": target,
            "scan_type": scan_type,
            "ports": ports,
            "additional_args": additional_args,
        }
    
        logger.info(f"🔍 Starting Nmap scan on {target}")
        result = api_client.safe_post("api/nmap", data)
    
        if result.get("success"):
            logger.info(f"✅ Nmap scan completed on {target}")
        else:
            logger.error("❌ Nmap scan failed")
    
        return result
  • REST API handler 'execute_nmap' for '/api/nmap': builds and executes the nmap command securely, parses XML output into structured findings.
    @tool(required_fields=["target"])
    def execute_nmap():
        """Execute Nmap scan against a target."""
        data = request.get_json()
    
        params = extract_nmap_params(data)
    
        logger.info(f"Executing Nmap scan on {params['target']}")
    
        started_at = datetime.now()
        command = build_nmap_command(params)
        execution_result = execute_command(
            command, timeout=1800
        )  # 30 minute timeout for nmap
        ended_at = datetime.now()
    
        return parse_nmap_result(execution_result, params, command, started_at, ended_at)
  • Helper function to securely construct the nmap command line with shell escaping and XML output.
    def build_nmap_command(params: dict) -> str:
        """Build nmap command from parameters with proper security escaping."""
        cmd_parts = ["nmap"]
    
        # Add scan type
        if params["scan_type"]:
            for scan_arg in params["scan_type"].split():
                cmd_parts.append(shlex.quote(scan_arg))
    
        # Add timing
        if params["timing"]:
            cmd_parts.append(shlex.quote(params["timing"]))
    
        # Add ports if specified
        if params["ports"]:
            cmd_parts.extend(["-p", shlex.quote(params["ports"])])
    
        # Add host timeout
        if params["host_timeout"]:
            cmd_parts.extend(["--host-timeout", shlex.quote(params["host_timeout"])])
    
        # Add max retries
        if params["max_retries"]:
            cmd_parts.extend(["--max-retries", str(params["max_retries"])])
    
        # Force XML output for structured parsing
        cmd_parts.extend(["-oX", "-"])
    
        # Add additional arguments if provided
        if params["additional_args"]:
            try:
                # Split and quote each argument properly
                additional_parts = shlex.split(params["additional_args"])
                for part in additional_parts:
                    cmd_parts.append(shlex.quote(part))
            except ValueError as e:
                # Invalid shell syntax - reject
                raise ValueError("Invalid additional arguments format") from e
    
        # Add target
        cmd_parts.append(shlex.quote(params["target"]))
    
        return " ".join(cmd_parts)
  • Helper function to parse Nmap XML output into structured findings with host/port/service details and deduplication logic.
    def parse_nmap_output(xml_output: str) -> list[dict[str, Any]]:
        """Parse nmap XML output into basic findings."""
        findings = []
    
        if not xml_output.strip():
            return findings
    
        try:
            # Parse XML
            root = ET.fromstring(xml_output)
    
            # Iterate through hosts
            for host in root.findall("host"):
                # Get host information
                address_elem = host.find("address")
                if address_elem is None:
                    continue
    
                host_ip = address_elem.get("addr", "")
                if not host_ip:
                    continue
    
                # Get hostname if available
                hostname = host_ip
                hostnames_elem = host.find("hostnames")
                if hostnames_elem is not None:
                    hostname_elem = hostnames_elem.find("hostname")
                    if hostname_elem is not None:
                        hostname = hostname_elem.get("name", host_ip)
    
                # Get host state
                status_elem = host.find("status")
                host_state = (
                    status_elem.get("state", "unknown")
                    if status_elem is not None
                    else "unknown"
                )
    
                # Parse ports
                ports_elem = host.find("ports")
                if ports_elem is not None:
                    for port_elem in ports_elem.findall("port"):
                        port_id = int(port_elem.get("portid", 0))
                        protocol = port_elem.get("protocol", "tcp")
    
                        # Get port state
                        state_elem = port_elem.find("state")
                        port_state = (
                            state_elem.get("state", "unknown")
                            if state_elem is not None
                            else "unknown"
                        )
    
                        # Get service information
                        service_elem = port_elem.find("service")
                        service_name = ""
                        service_product = ""
                        service_version = ""
                        service_extra = ""
    
                        if service_elem is not None:
                            service_name = service_elem.get("name", "")
                            service_product = service_elem.get("product", "")
                            service_version = service_elem.get("version", "")
                            service_extra = service_elem.get("extrainfo", "")
    
                        # Get scripts output if available
                        scripts = []
                        for script_elem in port_elem.findall("script"):
                            script_id = script_elem.get("id", "")
                            script_output = script_elem.get("output", "")
                            if script_id and script_output:
                                scripts.append({"id": script_id, "output": script_output})
    
                        # Basic confidence mapping
                        confidence = "high" if port_state == "open" else "medium"
    
                        # Build basic tags
                        tags = ["port", "scan", protocol, port_state]
                        if service_name:
                            tags.append(service_name)
                        if scripts:
                            tags.append("scripted")
    
                        # Create basic finding without severity calculation
                        finding = create_finding(
                            finding_type="port",
                            target=hostname,
                            evidence={
                                "host_ip": host_ip,
                                "hostname": hostname,
                                "port": port_id,
                                "protocol": protocol,
                                "state": port_state,
                                "service_name": service_name,
                                "service_product": service_product,
                                "service_version": service_version,
                                "service_extra": service_extra,
                                "scripts": scripts,
                                "discovered_by": "nmap",
                                "host_state": host_state,
                            },
                            severity="info",  # Default to info for all findings
                            confidence=confidence,
                            tags=tags,
                            raw_ref=ET.tostring(port_elem, encoding="unicode"),
                        )
                        findings.append(finding)
    
                # If no ports found but host is up, create a host discovery finding
                if host_state == "up" and ports_elem is None:
                    finding = create_finding(
                        finding_type="port",
                        target=hostname,
                        evidence={
                            "host_ip": host_ip,
                            "hostname": hostname,
                            "state": host_state,
                            "discovered_by": "nmap",
                            "scan_type": "host_discovery",
                        },
                        severity="info",
                        confidence="high",
                        tags=["host", "discovery", host_state],
                        raw_ref=ET.tostring(host, encoding="unicode"),
                    )
                    findings.append(finding)
    
        except ET.ParseError as e:
            logger.error(f"Failed to parse nmap XML output: {e}")
            # No text fallback - return empty list
            return []
    
        return findings
Behavior2/5

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

No annotations are provided, so the description must fully disclose behavioral traits. It mentions 'enhanced Nmap scan' and 'real-time logging,' but lacks critical details such as required permissions, potential network impact, rate limits, or error handling. For a network scanning tool with no annotation coverage, this is a significant gap in safety and operational context.

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

Conciseness4/5

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

The description is well-structured and appropriately sized, with a clear opening sentence followed by Args and Returns sections. It avoids unnecessary fluff, though the 'enhanced telemetry' in the Returns section is vague and could be more specific to improve clarity without adding length.

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

Completeness3/5

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

Given the tool's complexity (network scanning with 4 parameters), no annotations, and an output schema present, the description is moderately complete. It covers the basic purpose and parameters but lacks behavioral context and usage guidelines. The output schema likely handles return values, so the description's vague 'enhanced telemetry' is acceptable, though more detail would help.

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?

Schema description coverage is 0%, so the description must compensate. It lists and briefly explains the four parameters (target, scan_type, ports, additional_args), adding basic meaning beyond the schema's property names. However, it does not provide detailed semantics (e.g., format examples for ports, common scan_type values), leaving some ambiguity for proper usage.

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

Purpose4/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 as 'Execute an enhanced Nmap scan against a target with real-time logging,' which specifies the verb (execute scan), resource (target), and enhancement (real-time logging). However, it does not explicitly differentiate from sibling tools like 'nmap_advanced_scan' or 'smart_scan,' leaving some ambiguity about when to choose this specific Nmap tool.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. With multiple scanning-related siblings (e.g., nmap_advanced_scan, masscan_high_speed, rustscan_fast_scan), there is no indication of this tool's specific context, prerequisites, or exclusions, which could lead to incorrect tool selection by an AI agent.

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/SlanyCukr/bugbounty-mcp-server'

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