Skip to main content
Glama
washyu
by washyu

update_device_fingerprint_preview

Read-onlyIdempotent

Preview the result of updating a device fingerprint without saving. Applies top-level overwrite and capabilities one-level overwrite merge rules to return the would-be fingerprint.

Instructions

Preview the merge result of update_device_fingerprint without persisting. Returns the would-be merged fingerprint dict using the same merge rules: top-level overwrite + capabilities one-level overwrite (incoming capability keys replace stored entries entirely; not recursive). Read-only — no DB write, no last_seen or updated_at mutation. Phase 38 D-05c.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
hostnameYesHostname of the device to preview-fingerprint
fingerprintYesSame shape as update_device_fingerprint.fingerprint. Recognized top-level keys: kernel_name, kernel_version, os_name, os_version, package_fingerprint, capabilities.

Implementation Reference

  • Main handler function for update_device_fingerprint_preview. A read-only thin wrapper around merge_fingerprint: fetches device, computes would-be merge result, returns it without persisting. Validates hostname, normalizes fingerprint input, retrieves current stored fingerprint, and returns the merged result with preview=True.
    async def handle_update_device_fingerprint_preview(arguments: dict[str, Any]) -> dict[str, Any]:
        """Handle update_device_fingerprint_preview tool (Phase 38 D-05c, Plan 05).
    
        Read-only thin wrapper around merge_fingerprint: fetches the device row via
        get_all_devices, computes the would-be merge result, and returns it WITHOUT
        persisting. The adapter's update_device_fingerprint method is NOT called.
    
        Mirrors the validation/filtering of handle_update_device_fingerprint so the
        preview shape exactly matches what the real call would write.
    
        Side-effect contract (Phase 43 WR-03 clarification):
          * Preview path (this function): pure read — no DB write, no last_seen
            mutation, no updated_at mutation. Safe to call repeatedly.
          * Persist path (handle_update_device_fingerprint → adapter.update_device_fingerprint):
            bumps updated_at on the device row; preserves last_seen as set by the most
            recent discover_and_map run (Phase 38 REVIEW-FIX commit f53365c). Consumers
            of analyze_network_topology row ordering (which keys off last_seen) are
            NOT disturbed by fingerprint updates.
        """
        from ..database import merge_fingerprint  # local import — avoids circular issues
    
        RECOGNIZED_TOP_LEVEL = {
            "kernel_name",
            "kernel_version",
            "os_name",
            "os_version",
            "package_fingerprint",
            "capabilities",
        }
        validate_hostname(arguments["hostname"])
        fp_in = arguments.get("fingerprint", {})
        if not isinstance(fp_in, dict):
            result_str = json.dumps(
                {
                    "status": "error",
                    "error": f"`fingerprint` must be an object (got {type(fp_in).__name__})",
                    "hint": "Provide fingerprint as a JSON object with recognized top-level keys.",
                }
            )
            return {"content": [{"type": "text", "text": result_str}]}
        cleaned = {k: v for k, v in fp_in.items() if k in RECOGNIZED_TOP_LEVEL}
    
        sitemap = NetworkSiteMap()
        devices = sitemap.db_adapter.get_all_devices()
        target = next((d for d in devices if d.get("hostname") == arguments["hostname"]), None)
        if target is None:
            result_str = json.dumps(
                {
                    "status": "error",
                    "error": f"Hostname not in sitemap: {arguments['hostname']!r}.",
                    "hint": "Run discover_and_map for this hostname first to add it to the sitemap.",
                }
            )
            return {"content": [{"type": "text", "text": result_str}]}
    
        stored = target.get("fingerprint") or {}
        if isinstance(stored, str):
            # Some adapters may still surface a JSON string; normalize to dict before merge.
            try:
                stored = json.loads(stored)
            except json.JSONDecodeError:
                stored = {}
        if not isinstance(stored, dict):
            stored = {}
    
        merged = merge_fingerprint(stored, cleaned)
        result_str = json.dumps(
            {
                "status": "success",
                "hostname": arguments["hostname"],
                "fingerprint": merged,
                "preview": True,
            },
            indent=2,
        )
        return {"content": [{"type": "text", "text": result_str}]}
  • Input schema definition for the tool. Defines hostname (string, required) and fingerprint (object, required) with recognized top-level keys: kernel_name, kernel_version, os_name, os_version, package_fingerprint, capabilities.
        "update_device_fingerprint_preview": {
            "description": (
                "Preview the merge result of update_device_fingerprint without persisting. "
                "Returns the would-be merged fingerprint dict using the same merge rules: "
                "top-level overwrite + capabilities one-level overwrite (incoming capability "
                "keys replace stored entries entirely; not recursive). Read-only — no DB "
                "write, no last_seen or updated_at mutation. Phase 38 D-05c."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "hostname": {
                        "type": "string",
                        "description": "Hostname of the device to preview-fingerprint",
                    },
                    "fingerprint": {
                        "type": "object",
                        "description": (
                            "Same shape as update_device_fingerprint.fingerprint. Recognized top-level "
                            "keys: kernel_name, kernel_version, os_name, os_version, package_fingerprint, "
                            "capabilities."
                        ),
                        "properties": {
                            "kernel_name": {"type": "string"},
                            "kernel_version": {"type": "string"},
                            "os_name": {"type": "string"},
                            "os_version": {"type": "string"},
                            "package_fingerprint": {"type": "string"},
                            "capabilities": {"type": "object", "additionalProperties": True},
                        },
                        "additionalProperties": False,
                    },
                },
                "required": ["hostname", "fingerprint"],
            },
        },
    }
  • Import of handle_update_device_fingerprint_preview from network_handlers.
        handle_update_device_fingerprint_preview,  # Phase 38 D-05c (Plan 05)
    )
    from .proxmox_handlers import (
        handle_clone_proxmox_vm,
        handle_create_proxmox_lxc,
        handle_create_proxmox_vm,
        handle_delete_proxmox_vm,
        handle_delete_proxmox_vm_preview,
        handle_get_proxmox_node_status,
        handle_get_proxmox_script_info,
        handle_get_proxmox_vm_status,
        handle_list_proxmox_resources,
        handle_manage_proxmox_vm,
        handle_search_proxmox_scripts,
    )
    from .service_handlers import (
        handle_check_ansible_service,
        handle_check_service_requirements,
        handle_destroy_terraform_service,
        handle_destroy_terraform_service_preview,
        handle_get_service_info,
        handle_get_service_status,
        handle_install_service,
        handle_list_available_services,
        handle_plan_terraform_service,
        handle_refresh_terraform_service,
        handle_run_ansible_playbook,
    )
    from .ssh_handlers import (
        handle_ssh_discover,
        handle_ssh_execute_command,
        handle_start_interactive_shell,
    )
    from .vm_handlers import (
        handle_control_vm,
        handle_deploy_vm,
        handle_get_vm_logs,
        handle_get_vm_status,
        handle_list_vms,
        handle_remove_vm,
        handle_remove_vm_preview,
    )
    
    # Type alias for handler functions
    ToolHandler = Callable[[dict[str, Any]], Awaitable[dict[str, Any]]]
    
    # Tool handler registry mapping tool names to their handler functions
    TOOL_HANDLERS: dict[str, ToolHandler] = {
        # SSH tools
        "ssh_discover": handle_ssh_discover,
        "ssh_execute_command": handle_ssh_execute_command,
        "start_interactive_shell": handle_start_interactive_shell,
        # Network tools
        "discover_and_map": handle_discover_and_map,
        "bulk_discover_and_map": handle_bulk_discover_and_map,
        "get_network_sitemap": handle_get_network_sitemap,
        "analyze_network_topology": handle_analyze_network_topology,
        "suggest_deployments": handle_suggest_deployments,
        "get_device_changes": handle_get_device_changes,
        "purge_failed_discoveries": handle_purge_failed_discoveries,
        "purge_devices": handle_purge_devices,
        "purge_devices_preview": handle_purge_devices_preview,
        "remove_device": handle_remove_device,
        "remove_device_preview": handle_remove_device_preview,
        "update_device_fingerprint": handle_update_device_fingerprint,  # Phase 38
        "update_device_fingerprint_preview": handle_update_device_fingerprint_preview,  # Phase 38 D-05c (Plan 05)
  • Registration of 'update_device_fingerprint_preview' tool name to its handler function in the TOOL_HANDLERS registry.
    "update_device_fingerprint_preview": handle_update_device_fingerprint_preview,  # Phase 38 D-05c (Plan 05)
  • Listed as a read-only tool (readOnlyHint=True) in tool_annotations, confirming it is a non-destructive preview tool.
    "update_device_fingerprint_preview",  # Phase 38 D-05c (Plan 05)
    "remove_device_preview",  # Phase 44 D-11
    "purge_devices_preview",  # Phase 44 D-11
Behavior5/5

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

Description explicitly states read-only, no DB write, no last_seen or updated_at mutation, aligning with annotations. It adds value beyond annotations by detailing merge rules (top-level overwrite, capabilities one-level overwrite) and idempotency implied.

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?

Description is a single paragraph but packs essential information: purpose, merge rules, read-only nature, and phase reference. Slightly front-loaded but effective.

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 simplicity of the tool (two params, clear behavior), the description covers merge behavior and read-only guarantee. No output schema but description hints at return type. Annotations complement well.

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

Parameters4/5

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

Schema provides full coverage with descriptions for both parameters. Description adds minimal extra semantics (e.g., shape of fingerprint referencing update_device_fingerprint). Baseline adjusted for high schema coverage.

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 name and description clearly state this is a preview of updating device fingerprint without persistence. It distinguishes itself from the sibling update_device_fingerprint by explicitly mentioning 'Preview' and 'without persisting', and specifies merge rules.

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 explains when to use (to preview merge result before committing) and that it is read-only. It does not explicitly contrast with other preview tools, but the context is clear enough for an AI agent to decide.

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/washyu/homelab_mcp'

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