Skip to main content
Glama
gjenkins20

webmin-mcp-server

get_system_info

Retrieve detailed system information: OS, kernel, CPU, memory, disk usage, and update status. Gain a clear overview of your system's state for monitoring and diagnostics.

Instructions

Get comprehensive system information including OS, kernel, CPU, memory, disk usage, and update status. This is a good starting point for understanding system state.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
serverNoServer alias (e.g., 'pi1', 'web-server'). Uses default server if not specified.

Implementation Reference

  • The main handler function for get_system_info. Calls multiple Webmin endpoints (get_webmin_version, get_system_hostname, detect_operating_system, collect_system_info) and assembles them into a comprehensive ToolResult with OS, kernel, CPU, memory, disk, process count, updates, and reboot status.
    async def get_system_info(client: WebminClient) -> ToolResult:
        """Get comprehensive system information.
    
        Combines data from multiple Webmin endpoints to provide a complete
        system overview including OS, kernel, CPU, memory, and disk info.
    
        Args:
            client: Authenticated WebminClient instance.
    
        Returns:
            ToolResult with system information.
        """
        try:
            # Gather data from multiple sources
            version = await client.call("webmin", "get_webmin_version")
            hostname = await client.call("webmin", "get_system_hostname")
            os_info = await client.call("webmin", "detect_operating_system")
            system_info = await client.call("system-status", "collect_system_info")
    
            # Parse OS info (returns flat list of key-value pairs)
            os_data = {}
            if isinstance(os_info, list):
                for i in range(0, len(os_info) - 1, 2):
                    os_data[os_info[i]] = os_info[i + 1]
    
            # Parse CPU info from load array
            load = system_info.get("load", [])
            cpu_info = {
                "load_1min": load[0] if len(load) > 0 else None,
                "load_5min": load[1] if len(load) > 1 else None,
                "load_15min": load[2] if len(load) > 2 else None,
                "running_processes": load[3] if len(load) > 3 else None,
                "model": load[4] if len(load) > 4 else None,
                "vendor": load[5] if len(load) > 5 else None,
                "cache_kb": load[6] if len(load) > 6 else None,
                "cores": load[7] if len(load) > 7 else None,
            }
    
            # Parse memory info
            mem = system_info.get("mem", [])
            mem_info = {
                "total_kb": mem[0] if len(mem) > 0 else None,
                "used_kb": mem[1] if len(mem) > 1 else None,
                "buffers_kb": mem[2] if len(mem) > 2 else None,
                "cached_kb": mem[3] if len(mem) > 3 else None,
                "free_kb": mem[4] if len(mem) > 4 else None,
            }
    
            # Parse kernel info
            kernel = system_info.get("kernel", {})
    
            return ToolResult.ok({
                "hostname": hostname,
                "webmin_version": str(version),
                "os": {
                    "type": os_data.get("os_type"),
                    "name": os_data.get("real_os_type"),
                    "version": os_data.get("real_os_version"),
                },
                "kernel": {
                    "os": kernel.get("os"),
                    "version": kernel.get("version"),
                    "arch": kernel.get("arch"),
                },
                "cpu": cpu_info,
                "memory": mem_info,
                "disk": {
                    "total_bytes": system_info.get("disk_total"),
                    "used_bytes": system_info.get("disk_used"),
                    "free_bytes": system_info.get("disk_free"),
                },
                "process_count": system_info.get("procs"),
                "updates_available": len(system_info.get("poss", [])),
                "reboot_required": bool(system_info.get("reboot")),
            })
    
        except Exception as e:
            return ToolResult.fail(
                code="SYSTEM_INFO_ERROR",
                message=f"Failed to get system info: {e}",
            )
  • src/server.py:108-132 (registration)
    Registration of the get_system_info MCP tool in the TOOLS list with its name, description, and inputSchema (accepts optional 'server' parameter for multi-server support).
    Tool(
        name="get_webmin_version",
        description=(
            "Get the version of the connected Webmin server. "
            "Returns the version string and hostname."
        ),
        inputSchema={
            "type": "object",
            "properties": {**SERVER_PARAM},
            "required": [],
        },
    ),
    Tool(
        name="get_system_info",
        description=(
            "Get comprehensive system information including OS, kernel, "
            "CPU, memory, disk usage, and update status. "
            "This is a good starting point for understanding system state."
        ),
        inputSchema={
            "type": "object",
            "properties": {**SERVER_PARAM},
            "required": [],
        },
    ),
  • Dispatch routing in call_tool: maps the 'get_system_info' tool name to system.get_system_info(client) call.
    if name == "get_system_info":
        return await system.get_system_info(client)
  • ToolResult model used by the handler to return structured success/failure results via ToolResult.ok() and ToolResult.fail() class methods.
    class ToolResult(BaseModel):
        """Generic result wrapper for MCP tool responses."""
    
        success: bool = Field(
            description="Whether the operation succeeded",
        )
        data: dict[str, Any] | None = Field(
            default=None,
            description="Result data on success",
        )
        error: WebminError | None = Field(
            default=None,
            description="Error details on failure",
        )
    
        @classmethod
        def ok(cls, data: dict[str, Any]) -> "ToolResult":
            """Create a successful result."""
            return cls(success=True, data=data)
    
        @classmethod
        def fail(
            cls,
            code: str,
            message: str,
            details: dict[str, Any] | None = None,
        ) -> "ToolResult":
            """Create a failure result."""
            return cls(
                success=False,
                error=WebminError(code=code, message=message, details=details),
            )
  • Unit tests for get_system_info covering both success (verifying returned data structure) and error (verifying SYSTEM_INFO_ERROR code) scenarios.
    class TestGetSystemInfo:
        """Tests for get_system_info tool."""
    
        async def test_get_system_info_success(self, mock_client: AsyncMock) -> None:
            """Test successful system info retrieval."""
            # Setup mock responses
            mock_client.call.side_effect = [
                "2.105",  # webmin::get_webmin_version
                "testhost",  # webmin::get_system_hostname
                ["real_os_type", "Ubuntu Linux", "real_os_version", "24.04"],  # detect_operating_system
                {  # collect_system_info
                    "load": [0.5, 0.3, 0.2, 100, "Test CPU", "TestVendor", 1024, 4],
                    "mem": [4000000, 2000000, 100000, 500000, 1400000],
                    "disk_total": 100000000000,
                    "disk_used": 50000000000,
                    "disk_free": 50000000000,
                    "kernel": {"os": "Linux", "version": "6.1.0", "arch": "x86_64"},
                    "procs": 150,
                    "poss": [{"name": "pkg1"}, {"name": "pkg2"}],
                    "reboot": 0,
                },
            ]
    
            result = await system.get_system_info(mock_client)
    
            assert result.success
            assert result.data["hostname"] == "testhost"
            assert result.data["webmin_version"] == "2.105"
            assert result.data["os"]["name"] == "Ubuntu Linux"
            assert result.data["cpu"]["cores"] == 4
            assert result.data["updates_available"] == 2
    
        async def test_get_system_info_error(self, mock_client: AsyncMock) -> None:
            """Test system info error handling."""
            mock_client.call.side_effect = Exception("Connection failed")
    
            result = await system.get_system_info(mock_client)
    
            assert not result.success
            assert result.error.code == "SYSTEM_INFO_ERROR"
Behavior3/5

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

No annotations are provided, so the description must convey safety and side effects. It describes what is returned but does not explicitly state it is read-only, safe, or whether authentication is needed. Partial but adequate for a read operation.

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?

Two sentences, no wasted words. The first conveys the core action and contents, the second adds strategic guidance. Ideal length and front-loaded structure.

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?

Given the tool's simplicity (one optional param, no output schema) and sibling context, the description covers what it offers and provides starting-point guidance. It could mention output format or more details but is sufficient for a high-level diagnostic tool.

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 coverage is 100% with the single parameter 'server' fully described. The tool description adds no additional information about the parameter, so it meets baseline but does not exceed.

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 verb 'get' and resource 'comprehensive system information' listing specific categories (OS, kernel, CPU, memory, disk usage, update status). It distinguishes from siblings like get_memory_usage by emphasizing comprehensiveness.

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 includes 'good starting point for understanding system state,' implying initial use before more specific tools. It provides context but does not explicitly state when not to use or name alternatives.

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/gjenkins20/webmin-mcp-server'

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