{
  "version": "6.0.3",
  "tools": [
    {
      "name": "ssh_alert_setup",
      "description": "Read/save CPU, memory and disk thresholds, or compare one fresh POSIX metrics snapshot against them. It does not install a notification service.\nInputs: server; action defaults get. set overwrites configPath (default /etc/ssh-manager-alerts.json), needs write permission, and accepts percent thresholds 0–100 plus enabled. check reads thresholds and samples mountPoint.\nResult: set means the threshold file was saved. check returns alert_count and individual alerts for this call only. Verify a separately configured notification mechanism before claiming recurring alerts.\nExample: {\"server\":\"web-a\",\"action\":\"get\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "get",
            "server": "web-a"
          }
        ],
        "properties": {
          "action": {
            "description": "Default get. set overwrites the threshold file; check compares one fresh snapshot. No notification daemon is installed.",
            "enum": [
              "set",
              "get",
              "check"
            ],
            "type": "string"
          },
          "configPath": {
            "description": "Threshold JSON file on the remote server; default /etc/ssh-manager-alerts.json. set needs write permission.",
            "type": "string"
          },
          "cpuThreshold": {
            "default": 80.0,
            "description": "Usage threshold in percent, 0–100, for a one-shot alert check.",
            "maximum": 100,
            "minimum": 0,
            "type": "number"
          },
          "diskThreshold": {
            "default": 85.0,
            "description": "Usage threshold in percent, 0–100, for a one-shot alert check.",
            "maximum": 100,
            "minimum": 0,
            "type": "number"
          },
          "enabled": {
            "default": true,
            "description": "Saved threshold-check flag; not proof of a running notification service.",
            "type": "boolean"
          },
          "memoryThreshold": {
            "default": 90.0,
            "description": "Usage threshold in percent, 0–100, for a one-shot alert check.",
            "maximum": 100,
            "minimum": 0,
            "type": "number"
          },
          "mountPoint": {
            "description": "Filesystem sampled for check; default /.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_alias",
      "description": "Store server-name shortcuts for this MCP computer. They do not create servers or synchronize with the central catalog.\nInputs: action defaults list. set/add need name and server from ssh_list_servers; update changes the saved value. remove/delete need name. list/get return the whole map; get is not a single-item lookup.\nResult: Returns saved items. Use real names from ssh_list_servers for remote calls; a stored alias is not proof that an SSH target is reachable.\nExample: {\"action\":\"list\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "list"
          }
        ],
        "properties": {
          "action": {
            "description": "Default list. list/get reads the whole map; set/add replaces one entry; update merges object values; remove/delete deletes one entry. See tool description for specialized actions.",
            "enum": [
              "list",
              "get",
              "set",
              "add",
              "update",
              "remove",
              "delete"
            ],
            "type": "string"
          },
          "alias": {
            "description": "Compatibility item-name alias for name.",
            "type": "string"
          },
          "description": {
            "description": "Optional saved note; no execution effect.",
            "type": "string"
          },
          "name": {
            "description": "Saved item name. Required for writes/removal unless the tool-specific alias/hook/profile name is supplied.",
            "type": "string"
          },
          "server": {
            "description": "Catalog server name stored as the shortcut value; it does not create the server.",
            "type": "string"
          },
          "value": {
            "description": "Explicit saved JSON value. set/add replaces the entry; update merges object fields when both sides are objects. Read/saving alone does not execute commands."
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_backup_create",
      "description": "Create one backup on a POSIX catalog server. File backups use tar; database backups need the matching installed dump utility.\nInputs: server, type=mysql|postgresql|mongodb|files, name. files requires nonempty remote paths; database types require database. backupDir defaults /var/backups/ssh-manager; compress defaults true. The output name is deterministic and an existing same-name backup can be overwritten. full and retention cleanup are unsupported.\nResult: Read success/code and output_file, then verify the archive/dump separately. A returned path is remote, not a local download. Interrupted backup may be incomplete; inspect it before reuse.\nExample: {\"server\":\"web-a\",\"type\":\"files\",\"name\":\"before-change-20260911\",\"paths\":[\"/srv/app/config\"],\"backupDir\":\"/var/backups/app\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "backupDir": "/var/backups/app",
            "name": "before-change-20260911",
            "paths": [
              "/srv/app/config"
            ],
            "server": "web-a",
            "type": "files"
          }
        ],
        "properties": {
          "backupDir": {
            "description": "Remote backup directory; default /var/backups/ssh-manager. It must be writable for backup creation.",
            "type": "string"
          },
          "compress": {
            "default": true,
            "description": "gzip compression. MongoDB without compression writes a dump directory; PostgreSQL without compression writes pg_restore custom format.",
            "type": "boolean"
          },
          "database": {
            "description": "Database name reached from the selected SSH server, not a server profile name.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "exclude": {
            "description": "tar --exclude patterns for a files backup; not used by database dump modes.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "name": {
            "description": "Backup label used in a deterministic output filename. Choose a unique label to avoid overwriting a previous backup.",
            "type": "string"
          },
          "paths": {
            "description": "Nonempty list of existing paths on the remote server to archive; not local computer paths.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "files requires paths; database engines require database. Full-machine backup is not implemented.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb",
              "files"
            ],
            "type": "string"
          }
        },
        "required": [
          "server",
          "type",
          "name"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_backup_list",
      "description": "List backup filenames and sizes in one remote POSIX directory. Use before selecting an existing file to inspect or restore.\nInputs: server; backupDir defaults /var/backups/ssh-manager; optional type filters the filename prefix.\nResult: Returns remote directory/output. A listed filename or successful directory listing does not prove backup integrity. Use the exact file path, not an invented backupId.\nExample: {\"server\":\"web-a\",\"backupDir\":\"/var/backups/app\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "backupDir": "/var/backups/app",
            "server": "web-a"
          }
        ],
        "properties": {
          "backupDir": {
            "description": "Remote backup directory; default /var/backups/ssh-manager. It must be writable for backup creation.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "Optional filename-prefix filter; full may match a legacy file but cannot create a full backup.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb",
              "files",
              "full"
            ],
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_backup_restore",
      "description": "Extract a verified gzip tar file into a remote directory. Existing files may be overwritten; use only for the user's intended restore scope.\nInputs: server and exact backupFile from a verified backup; set destination explicitly. Default destination is the remote working directory. For database dumps use ssh_db_import with its engine/format; backupId requires separately existing legacy .gz/.meta.json files and is not produced by native backup_create.\nResult: Read success/code and verify restored content/application state. Restore has no automatic rollback. Partial extraction can remain after a failure; do not blindly retry into live data.\nExample: {\"server\":\"web-a\",\"backupFile\":\"/var/backups/app/files_before-change.tar.gz\",\"destination\":\"/srv/restore-check\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "backupFile": "/var/backups/app/files_before-change.tar.gz",
            "destination": "/srv/restore-check",
            "server": "web-a"
          }
        ],
        "properties": {
          "backupDir": {
            "description": "Remote backup directory; default /var/backups/ssh-manager. It must be writable for backup creation.",
            "type": "string"
          },
          "backupFile": {
            "description": "Exact verified gzip tar file on the server. Preferred file restore input; required unless inputFile or legacy backupId is supplied.",
            "type": "string"
          },
          "backupId": {
            "description": "Legacy ID only when matching backupDir/<id>.gz and .meta.json already exist. Native backup_create does not create these metadata IDs; prefer backupFile or ssh_db_import.",
            "type": "string"
          },
          "database": {
            "description": "Legacy metadata restore only. Use ssh_db_import for a new explicit database dump restore.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "destination": {
            "description": "Remote extraction directory, default remote working directory. Set explicitly; existing files can be overwritten.",
            "type": "string"
          },
          "inputFile": {
            "description": "Compatibility alias for backupFile; supply one explicit file path.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "targetPath": {
            "description": "Alias for destination; takes precedence if both are supplied.",
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_backup_schedule",
      "description": "Inspect or edit the SSH account's POSIX crontab backup entries. This is a persistent remote configuration change when adding/removing.\nInputs: Use explicit action=list|add|set|remove. add/set requires a five-field schedule and command, or backup type/name with remote paths/database. set appends like add; it is not a replacement. remove deletes every crontab line containing ssh-manager, not one named backup.\nResult: Read the crontab and verify the saved command/schedule. A saved cron entry is not a successful backup run. Prefer explicit command for a reviewed backup workflow; do not use remove for an individual schedule.\nExample: {\"server\":\"web-a\",\"action\":\"list\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "list",
            "server": "web-a"
          }
        ],
        "properties": {
          "action": {
            "description": "Use explicitly. Omitted defaults add when schedule is supplied, otherwise list. add/set both append; remove deletes all crontab lines containing ssh-manager.",
            "enum": [
              "list",
              "add",
              "set",
              "remove"
            ],
            "type": "string"
          },
          "command": {
            "description": "Explicit reviewed remote backup command. Cron quoting/environment applies; the tool appends it with an ssh-manager marker.",
            "type": "string"
          },
          "database": {
            "description": "Database name reached from the selected SSH server, not a server profile name.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "name": {
            "description": "Backup filename label when command is omitted.",
            "type": "string"
          },
          "paths": {
            "description": "Nonempty list of existing paths on the remote server to archive; not local computer paths.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "schedule": {
            "description": "Five-field cron expression in the REMOTE server's timezone; required for add/set. Example: 0 2 * * *.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "Required with name and paths/database when command is omitted.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb",
              "files"
            ],
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_cluster_inspect",
      "description": "Read native cluster/policy state, member observations, executor heartbeats, jobs and events. This is a snapshot; it does not trigger a probe.\nInputs: section defaults clusters; also policies/jobs/events/history. id optionally filters that section. limit defaults 30, maximum 256. IDs and revisions from this response are inputs to cluster save/task operations.\nResult: Use timestamps and states: unknown/stale differs from failed. Native RTT and fresh SSH-auth duration are separate, both reported in microseconds; timestamp/interval fields use milliseconds. Probe failure rate is not measured physical packet loss.\nExample: {\"section\":\"jobs\",\"limit\":20}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "limit": 20,
            "section": "jobs"
          }
        ],
        "properties": {
          "id": {
            "description": "Optional filter: cluster/policy ID; jobs also accepts a job ID, history also accepts a member device ID.",
            "type": "string"
          },
          "limit": {
            "default": 30,
            "description": "Maximum recent jobs/events/history records, newest first. Bounded history is retained at the authority.",
            "maximum": 256,
            "minimum": 1,
            "type": "integer"
          },
          "section": {
            "default": "clusters",
            "description": "Snapshot section: clusters (default), policies, jobs, events or history. Does not trigger measurements.",
            "enum": [
              "clusters",
              "policies",
              "jobs",
              "events",
              "history"
            ],
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_cluster_manage",
      "description": "Save, disable or retire a hierarchy of native device clusters for background collection. This is separate from ssh_group_manage command groups.\nInputs: First inspect registered devices and existing clusters. action=save needs spec and expectedRevision (0 creates a new ID). spec.members uses device UUIDs; executors must be reachable companion devices, not node-only devices. To retire, save enabled=false, wait for probe retirement, then delete with id/current revision.\nResult: Saving is not proof that jobs ran: inspect cluster appliedRevision, member timestamps and executor heartbeats. Enabled jobs can keep companions alive; OS boot persistence still needs a startup policy. Deletion refuses children and policy references.\nExample: {\"action\":\"save\",\"expectedRevision\":0,\"spec\":{\"id\":\"lab\",\"members\":[],\"executors\":[\"11111111-1111-4111-8111-111111111111\"],\"enabled\":false}}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "save",
            "expectedRevision": 0,
            "spec": {
              "enabled": false,
              "executors": [
                "11111111-1111-4111-8111-111111111111"
              ],
              "id": "lab",
              "members": []
            }
          }
        ],
        "properties": {
          "action": {
            "description": "save requires spec; expectedRevision=0 creates a new ID, otherwise use the inspected current revision. delete requires id after disabling/retiring dependencies.",
            "enum": [
              "save",
              "delete"
            ],
            "type": "string"
          },
          "expectedRevision": {
            "description": "Current configuration revision from ssh_cluster_inspect; 0 creates a new ID. State observations do not increment this revision.",
            "minimum": 0,
            "type": "integer"
          },
          "id": {
            "description": "delete only: ID from ssh_cluster_inspect. Disable first and wait for active jobs and probe retirement.",
            "type": "string"
          },
          "spec": {
            "additionalProperties": false,
            "description": "Complete cluster configuration for save; use inspected device UUIDs and explicitly assigned companion executors. Saving replaces this configuration, not just one member.",
            "properties": {
              "enabled": {
                "default": true,
                "description": "False retires this cluster's probes after existing jobs finish. Disable referencing policies first. Other node configuration and services remain owned independently.",
                "type": "boolean"
              },
              "executors": {
                "description": "Primary device IDs of companion daemons allowed to collect/manage these members. Their SSH management paths must be reachable. A native node alone cannot act as an executor; it never receives center credentials.",
                "items": {
                  "description": "Stable device ID from ssh_node_manage/ssh_route_inspect. A server display name is not a device ID.",
                  "format": "uuid",
                  "type": "string"
                },
                "maxItems": 8,
                "minItems": 1,
                "type": "array",
                "uniqueItems": true
              },
              "gateways": {
                "description": "Members (including descendants) allowed as policy gateway choices. Does not itself grant forwarding privileges.",
                "items": {
                  "description": "Stable device ID from ssh_node_manage/ssh_route_inspect. A server display name is not a device ID.",
                  "format": "uuid",
                  "type": "string"
                },
                "maxItems": 64,
                "type": "array",
                "uniqueItems": true
              },
              "id": {
                "pattern": "^[a-z0-9_-]{1,24}$",
                "type": "string"
              },
              "intervalMs": {
                "default": 10000,
                "description": "Member collection interval in milliseconds; 10000 = 10 seconds. Native probe intervals are configured per probe. Slow jobs skip overlapping runs.",
                "maximum": 300000,
                "minimum": 10000,
                "type": "integer"
              },
              "members": {
                "description": "Direct members; each device belongs to one direct cluster only. Remove members only after disabling the old cluster and waiting for appliedRevision to match revision.",
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "device": {
                      "description": "Stable device ID from ssh_node_manage/ssh_route_inspect. A server display name is not a device ID.",
                      "format": "uuid",
                      "type": "string"
                    },
                    "probes": {
                      "description": "Probes run continuously on this member's native node, even without MCP calls. IDs must be unique within the member and <=32 bytes. owner is assigned automatically; omit it. Disable the cluster to retire only its probes.",
                      "items": {
                        "additionalProperties": false,
                        "properties": {
                          "id": {
                            "maxLength": 32,
                            "type": "string"
                          },
                          "intervalMs": {
                            "default": 10000,
                            "description": "Probe interval in milliseconds; 10000 = 10 seconds. Must be at least timeoutMs.",
                            "maximum": 300000,
                            "minimum": 1000,
                            "type": "integer"
                          },
                          "target": {
                            "oneOf": [
                              {
                                "additionalProperties": false,
                                "properties": {
                                  "address": {
                                    "description": "Exact numeric endpoint this device actively connects to; measures TCP connection establishment.",
                                    "type": "string"
                                  },
                                  "kind": {
                                    "const": "tcp"
                                  }
                                },
                                "required": [
                                  "kind",
                                  "address"
                                ],
                                "type": "object"
                              },
                              {
                                "additionalProperties": false,
                                "properties": {
                                  "kind": {
                                    "const": "p2p"
                                  },
                                  "link": {
                                    "description": "Configured authenticated peer link; measures application ping over its actual QUIC/TCP connection.",
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "kind",
                                  "link"
                                ],
                                "type": "object"
                              },
                              {
                                "additionalProperties": false,
                                "properties": {
                                  "kind": {
                                    "const": "forward"
                                  },
                                  "link": {
                                    "type": "string"
                                  },
                                  "target": {
                                    "description": "Exact TCP destination granted by that peer; measures the complete native open and target connection.",
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "kind",
                                  "link",
                                  "target"
                                ],
                                "type": "object"
                              }
                            ]
                          },
                          "timeoutMs": {
                            "default": 2000,
                            "description": "Milliseconds; 1000 = 1 second. Must not exceed intervalMs.",
                            "maximum": 10000,
                            "minimum": 100,
                            "type": "integer"
                          },
                          "window": {
                            "default": 30,
                            "description": "Number of recent probe samples retained, not seconds.",
                            "maximum": 60,
                            "minimum": 2,
                            "type": "integer"
                          }
                        },
                        "required": [
                          "id",
                          "target"
                        ],
                        "type": "object"
                      },
                      "maxItems": 16,
                      "type": "array"
                    }
                  },
                  "required": [
                    "device"
                  ],
                  "type": "object"
                },
                "maxItems": 64,
                "type": "array"
              },
              "parent": {
                "description": "Existing parent cluster ID. At most 8 levels; cycles are rejected. Parent views include descendants.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "staleAfterMs": {
                "default": 60000,
                "description": "Observations older than this are stale, excluded from gateway selection. Must be >=3 * intervalMs. Milliseconds; 60000 = 1 minute.",
                "maximum": 3600000,
                "minimum": 30000,
                "type": "integer"
              }
            },
            "required": [
              "id",
              "members",
              "executors"
            ],
            "type": "object"
          }
        },
        "required": [
          "action",
          "expectedRevision"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_cluster_policy",
      "description": "Configure source-device route measurements and optional automatic switching/repair among preauthorized paths. Inspect devices/clusters and apply a matching device-scoped route first.\nInputs: save requires spec and expectedRevision (0 for a new ID). spec identifies sourceDevice/sourceCluster/targetCluster and 2–8 candidates. autoSwitch and autoRepair default false; enabling them grants ongoing changes within those paths and budgets. delete uses id/current revision after disabling.\nResult: Read fresh source-side measurements, proposals and job receipts with ssh_cluster_inspect. Saved policy alone is not running acceptance. Stale data is excluded; external route edits pause the policy. No new permissions, arbitrary shell jobs, hidden fallback or command replay.\nExample: {\"action\":\"delete\",\"id\":\"policy-from-inspect\",\"expectedRevision\":3}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "delete",
            "expectedRevision": 3,
            "id": "policy-from-inspect"
          }
        ],
        "properties": {
          "action": {
            "description": "save requires spec; expectedRevision=0 creates a new ID, otherwise use the inspected current revision. delete requires id after disabling/retiring dependencies.",
            "enum": [
              "save",
              "delete"
            ],
            "type": "string"
          },
          "expectedRevision": {
            "description": "Current configuration revision from ssh_cluster_inspect; 0 creates a new ID. State observations do not increment this revision.",
            "minimum": 0,
            "type": "integer"
          },
          "id": {
            "description": "delete only: ID from ssh_cluster_inspect. Disable first and wait for active jobs and probe retirement.",
            "type": "string"
          },
          "spec": {
            "additionalProperties": false,
            "description": "Complete route policy for save. Register clusters and apply a matching source-device route first. autoSwitch/autoRepair authorize ongoing changes only when explicitly enabled.",
            "properties": {
              "autoRepair": {
                "default": false,
                "description": "Authorizes bounded repair of the current route's existing resources if all candidates fail. Node permission/configuration changes require a separate reviewed route plan.",
                "type": "boolean"
              },
              "autoSwitch": {
                "default": false,
                "description": "Authorizes automatic route replacement after fresh source-side SSH authentication, confirmations and cooldown. False still measures candidates and shows proposals.",
                "type": "boolean"
              },
              "candidates": {
                "description": "Preauthorized alternatives from the primary source companion. Apply an explicit device-scoped route matching one complete candidate before enabling this policy. Automatic switch changes the route only; it cannot invent grants, skip hops or replay active commands.",
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "gatewayDevice": {
                      "description": "Optional gateway device declared in sourceCluster or targetCluster. Requires fresh native load telemetry below maxGatewayLoadPercent before this candidate is selected.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "id": {
                      "pattern": "^[a-z0-9_-]{1,24}$",
                      "type": "string"
                    },
                    "route": {
                      "additionalProperties": false,
                      "properties": {
                        "description": {
                          "default": "",
                          "type": "string"
                        },
                        "enabled": {
                          "const": true,
                          "default": true,
                          "type": "boolean"
                        },
                        "ingress": {
                          "description": "Transport to the first SSH hop (or final server when via=[]). It preserves SSH login, target host-key and command permissions. null removes an ingress. target is a numeric socket address as seen on device. Existing explicit SSH hops are still honored.",
                          "oneOf": [
                            {
                              "type": "null"
                            },
                            {
                              "additionalProperties": false,
                              "properties": {
                                "coordinator": {
                                  "description": "Optional registered introduction node ID. Never carries application bytes unless independently selected as a gateway.",
                                  "type": [
                                    "string",
                                    "null"
                                  ]
                                },
                                "device": {
                                  "description": "Registered receiving node ID.",
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "fallback": {
                                  "default": false,
                                  "description": "Explicitly allow the configured SSH route if P2P cannot connect; actual fallback is reported.",
                                  "type": "boolean"
                                },
                                "kind": {
                                  "const": "p2p"
                                },
                                "protocol": {
                                  "default": "auto",
                                  "enum": [
                                    "auto",
                                    "quic",
                                    "tcp"
                                  ]
                                },
                                "target": {
                                  "description": "Authorized SSH service endpoint on the receiving device, e.g. 127.0.0.1:22.",
                                  "type": "string"
                                },
                                "timeout_ms": {
                                  "default": 8000,
                                  "description": "P2P connect timeout in milliseconds; 10000 = 10 seconds.",
                                  "maximum": 120000,
                                  "minimum": 100,
                                  "type": "integer"
                                }
                              },
                              "required": [
                                "kind",
                                "device",
                                "target"
                              ],
                              "type": "object"
                            },
                            {
                              "additionalProperties": false,
                              "properties": {
                                "device": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "gateway": {
                                  "description": "Native gateway numeric SSH listener reachable from this companion.",
                                  "type": "string"
                                },
                                "kind": {
                                  "const": "native"
                                },
                                "target": {
                                  "description": "Numeric endpoint reached by the gateway; may be its loopback reverse listener.",
                                  "type": "string"
                                }
                              },
                              "required": [
                                "kind",
                                "device",
                                "gateway",
                                "target"
                              ],
                              "type": "object"
                            }
                          ]
                        },
                        "resources": {
                          "description": "Already registered, enabled, owned resource IDs. Automatic repair can only start these existing resources, with its per-hour budget.",
                          "items": {
                            "type": "string"
                          },
                          "maxItems": 32,
                          "type": "array"
                        },
                        "server": {
                          "description": "One exact target from ssh_list_servers; identical for all candidates.",
                          "type": "string"
                        },
                        "sourceDevice": {
                          "description": "Stable device ID from ssh_node_manage/ssh_route_inspect. A server display name is not a device ID.",
                          "format": "uuid",
                          "type": "string"
                        },
                        "sourceInstance": {
                          "description": "Policies run from the primary companion device; omit or use null when copying an inspected route.",
                          "type": "null"
                        },
                        "via": {
                          "description": "Entire ordered SSH hop path. [] means direct SSH; all mandatoryVia hops must remain in order.",
                          "items": {
                            "type": "string"
                          },
                          "maxItems": 8,
                          "type": "array"
                        }
                      },
                      "required": [
                        "server",
                        "via",
                        "sourceDevice"
                      ],
                      "type": "object"
                    }
                  },
                  "required": [
                    "id",
                    "route"
                  ],
                  "type": "object"
                },
                "maxItems": 8,
                "minItems": 2,
                "type": "array"
              },
              "confirmations": {
                "default": 3,
                "description": "Distinct completed measurement rounds required before switching. Re-reading a sample never increases confirmations.",
                "maximum": 10,
                "minimum": 2,
                "type": "integer"
              },
              "cooldownMs": {
                "default": 60000,
                "description": "Minimum milliseconds between switch/repair attempts; 60000 = 1 minute.",
                "maximum": 86400000,
                "minimum": 30000,
                "type": "integer"
              },
              "enabled": {
                "default": true,
                "type": "boolean"
              },
              "failureThreshold": {
                "default": 2,
                "description": "Consecutive fresh failures needed to treat the current route as unavailable.",
                "maximum": 10,
                "minimum": 1,
                "type": "integer"
              },
              "id": {
                "pattern": "^[a-z0-9_-]{1,24}$",
                "type": "string"
              },
              "intervalMs": {
                "default": 30000,
                "description": "Period between source-side route measurements in milliseconds. 30000 = 30 seconds; no overlapping runs.",
                "maximum": 3600000,
                "minimum": 30000,
                "type": "integer"
              },
              "mandatoryVia": {
                "description": "Required ordered SSH hop names present in every candidate. No implicit direct fallback.",
                "items": {
                  "type": "string"
                },
                "maxItems": 8,
                "type": "array",
                "uniqueItems": true
              },
              "maxGatewayLoadPercent": {
                "default": 90,
                "description": "Exclude a candidate when its declared gateway's connection or stream slot usage reaches this percentage. This measures native capacity, not CPU usage.",
                "maximum": 100,
                "minimum": 1,
                "type": "integer"
              },
              "maxRepairsPerHour": {
                "default": 3,
                "description": "Maximum scheduled repair attempts in a sliding hour, including failed attempts.",
                "maximum": 10,
                "minimum": 1,
                "type": "integer"
              },
              "minImprovementPercent": {
                "default": 20,
                "description": "Required median latency reduction while the current route works. An authenticated alternative may replace a failed current route after the same confirmation rule.",
                "maximum": 90,
                "minimum": 1,
                "type": "integer"
              },
              "sourceCluster": {
                "pattern": "^[a-z0-9_-]{1,24}$",
                "type": "string"
              },
              "sourceDevice": {
                "description": "Stable device ID from ssh_node_manage/ssh_route_inspect. A server display name is not a device ID.",
                "format": "uuid",
                "type": "string"
              },
              "targetCluster": {
                "pattern": "^[a-z0-9_-]{1,24}$",
                "type": "string"
              },
              "timeoutMs": {
                "default": 5000,
                "description": "Per-candidate fresh SSH authentication deadline, milliseconds; 5000 = 5 seconds. RTT reports use microseconds and include authentication, not just packet transit.",
                "maximum": 30000,
                "minimum": 1000,
                "type": "integer"
              }
            },
            "required": [
              "id",
              "sourceDevice",
              "sourceCluster",
              "targetCluster",
              "candidates"
            ],
            "type": "object"
          }
        },
        "required": [
          "action",
          "expectedRevision"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_cluster_task",
      "description": "Queue one collection or route-probe job, cancel pending work, or reconcile an unknown write against its receipt. It is not a generic remote shell scheduler.\nInputs: enqueue needs kind=observe with a cluster id, or kind=probe_routes with a policy id; use its current expectedRevision. cancel/resolve need jobId from enqueue/inspect. cancel affects pending jobs only; resolve never reapplies a plan.\nResult: jobId means queued, not executed. Follow ssh_cluster_inspect section=jobs to finished/failed/unknown and inspect evidence. Running writes are never blindly retried.\nExample: {\"action\":\"enqueue\",\"kind\":\"observe\",\"id\":\"cluster-from-inspect\",\"expectedRevision\":3}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "enqueue",
            "expectedRevision": 3,
            "id": "cluster-from-inspect",
            "kind": "observe"
          }
        ],
        "properties": {
          "action": {
            "description": "enqueue schedules one bounded observation/route-probe job. cancel affects pending jobs only. resolve reads the saved route receipt for an unknown write; it never reapplies the plan.",
            "enum": [
              "enqueue",
              "cancel",
              "resolve"
            ],
            "type": "string"
          },
          "expectedRevision": {
            "description": "Current configuration revision from ssh_cluster_inspect; 0 creates a new ID. State observations do not increment this revision.",
            "minimum": 0,
            "type": "integer"
          },
          "id": {
            "description": "enqueue only: cluster ID for observe or policy ID for probe_routes.",
            "type": "string"
          },
          "jobId": {
            "description": "cancel/resolve only: saved job ID from ssh_cluster_inspect section=jobs.",
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "description": "enqueue only: collect/reconcile a cluster or measure a policy's candidates.",
            "enum": [
              "observe",
              "probe_routes"
            ],
            "type": "string"
          }
        },
        "required": [
          "action"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_command_alias",
      "description": "Store or search command snippets on this MCP computer. Saving a snippet never runs it.\nInputs: action=list/get reads all; set/add/update needs name and command or explicit value; remove/delete needs name. suggest searches saved names/content using command as the search text.\nResult: Returns saved items or matching snippets. To execute one, inspect its text, choose an authorized server, and call ssh_execute explicitly.\nExample: {\"action\":\"suggest\",\"command\":\"status\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "suggest",
            "command": "status"
          }
        ],
        "properties": {
          "action": {
            "description": "Default list. list/get reads the whole map; set/add replaces one entry; update merges object values; remove/delete deletes one entry. See tool description for specialized actions.",
            "enum": [
              "list",
              "get",
              "set",
              "add",
              "update",
              "remove",
              "delete",
              "suggest"
            ],
            "type": "string"
          },
          "alias": {
            "description": "Compatibility item-name alias for name.",
            "type": "string"
          },
          "command": {
            "description": "Command snippet to save; for suggest, case-insensitive text to find in saved names/content. Never executed here.",
            "type": "string"
          },
          "description": {
            "description": "Optional saved note; no execution effect.",
            "type": "string"
          },
          "name": {
            "description": "Saved item name. Required for writes/removal unless the tool-specific alias/hook/profile name is supplied.",
            "type": "string"
          },
          "value": {
            "description": "Explicit saved JSON value. set/add replaces the entry; update merges object fields when both sides are objects. Read/saving alone does not execute commands."
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_connection_status",
      "description": "Inspect the actual companion version, update state, SSH pools, sessions and tunnels. Use this first for runtime/update diagnosis; use ssh_route_inspect for path and resource diagnosis.\nInputs: action defaults status; optional server from ssh_list_servers filters pool actions. reconnect/disconnect affect shared connections used by local clients; use only for an intended forced operation. cleanup removes idle/dead entries.\nResult: Read companionVersion and update receipts separately from saved config. deferred means waiting for real work to become idle, not an update failure. Queue an enabled update check with ssh_node_manage {server:@local,action:upgrade}; do not kill clients to force it.\nExample: {\"action\":\"status\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "status"
          }
        ],
        "properties": {
          "action": {
            "description": "Default status is read-only. reconnect/disconnect force shared pool changes and can affect other local clients. cleanup evicts idle/dead entries.",
            "enum": [
              "status",
              "reconnect",
              "disconnect",
              "cleanup"
            ],
            "type": "string"
          },
          "server": {
            "description": "Optional catalog server name for pool inspection/action; omission targets the pool as a whole.",
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_db_dump",
      "description": "Export one database using a dump client already installed on the POSIX SSH server. The output stays on that server.\nInputs: server, type, database, outputFile. dbHost is reached from the SSH server. compress defaults true. MySQL emits SQL; PostgreSQL emits custom format (optionally outer gzip); MongoDB emits a directory or tar.gz. tables selects MySQL tables only. Prefer existing remote authentication.\nResult: Read success/code and verify the actual dump format/content before restore. outputFile may replace existing data. Use ssh_download to bring the verified result to this computer.\nExample: {\"server\":\"web-a\",\"type\":\"postgresql\",\"database\":\"app\",\"outputFile\":\"/var/backups/app.dump\",\"compress\":false}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "compress": false,
            "database": "app",
            "outputFile": "/var/backups/app.dump",
            "server": "web-a",
            "type": "postgresql"
          }
        ],
        "properties": {
          "compress": {
            "default": true,
            "description": "Apply gzip/tar compression. PostgreSQL restore needs outer gzip removed; MongoDB restore needs an extracted dump directory.",
            "type": "boolean"
          },
          "database": {
            "description": "Database name reached from the selected SSH server, not a server profile name.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "outputFile": {
            "description": "Output on the SSH server, possibly overwriting an existing file. Match the extension to the engine/compress format; MongoDB compress=false writes a directory.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "tables": {
            "description": "MySQL table names only; omitted dumps the whole database. Not consumed by PostgreSQL/MongoDB.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": {
            "description": "Database engine; the matching CLI must be installed on the SSH server.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb"
            ],
            "type": "string"
          }
        },
        "required": [
          "server",
          "type",
          "database",
          "outputFile"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_db_import",
      "description": "Restore a database from an existing remote dump using its matching POSIX client. This changes database data and can replace existing objects.\nInputs: server, type, database, inputFile on that SSH server. MySQL accepts SQL or .gz; PostgreSQL expects pg_restore format without outer gzip and uses --clean; MongoDB expects an extracted dump directory and drop defaults true. Extract/decompress first when needed.\nResult: Read success/code and verify restored data. No transaction/rollback spans the import; failure can leave partial changes. Preserve a usable backup and inspect state before retrying an uncertain import.\nExample: {\"server\":\"web-a\",\"type\":\"postgresql\",\"database\":\"restore_check\",\"inputFile\":\"/var/backups/app.dump\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "database": "restore_check",
            "inputFile": "/var/backups/app.dump",
            "server": "web-a",
            "type": "postgresql"
          }
        ],
        "properties": {
          "database": {
            "description": "Database name reached from the selected SSH server, not a server profile name.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "drop": {
            "default": true,
            "description": "MongoDB only: drop existing collections before restoring. PostgreSQL always uses --clean --if-exists; this flag does not disable it.",
            "type": "boolean"
          },
          "inputFile": {
            "description": "Existing input on the SSH server: MySQL SQL/.gz; PostgreSQL unwrapped pg_restore file; MongoDB extracted directory. This is not a local upload path.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "Database engine; the matching CLI must be installed on the SSH server.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb"
            ],
            "type": "string"
          }
        },
        "required": [
          "server",
          "type",
          "database",
          "inputFile"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_db_list",
      "description": "List databases, or tables/collections in one database, using clients on a POSIX catalog server.\nInputs: server and type=mysql|postgresql|mongodb. Omit database for database names; provide it for tables/collections. dbHost is reached from the SSH server, not this computer; database CLI and credentials must already be available.\nResult: Returns items/count and success/stderr. A failed query or empty catalog does not imply that the database service is healthy. It does not start/install a database.\nExample: {\"server\":\"web-a\",\"type\":\"postgresql\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "server": "web-a",
            "type": "postgresql"
          }
        ],
        "properties": {
          "database": {
            "description": "Omit to list databases; provide to list its tables/collections.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "Database engine; the matching CLI must be installed on the SSH server.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb"
            ],
            "type": "string"
          }
        },
        "required": [
          "server",
          "type"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_db_query",
      "description": "Run an inspection query through a database CLI on a POSIX catalog server. Use a database account with read-only permissions for inspection.\nInputs: server, type, database and query. SQL must pass the SELECT-only filter; include an explicit LIMIT. MongoDB additionally needs collection and a JSON find filter. The text filter is not a database permission sandbox; do not supply executable MongoDB expressions or side-effecting SQL functions.\nResult: Read success/code/output/stderr. row_count counts output lines, not a guaranteed database record count. To modify data use a separately authorized database operation; this tool is for inspection.\nExample: {\"server\":\"web-a\",\"type\":\"postgresql\",\"database\":\"app\",\"query\":\"SELECT 1 AS ok LIMIT 1\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "database": "app",
            "query": "SELECT 1 AS ok LIMIT 1",
            "server": "web-a",
            "type": "postgresql"
          }
        ],
        "properties": {
          "collection": {
            "description": "Required for MongoDB; collection name used by find. Not used by SQL engines.",
            "type": "string"
          },
          "database": {
            "description": "Database name reached from the selected SSH server, not a server profile name.",
            "type": "string"
          },
          "dbHost": {
            "description": "Database host reached from the SSH server; 127.0.0.1 refers to that server.",
            "type": "string"
          },
          "dbPassword": {
            "description": "Optional database credential. Prefer existing remote authentication; never print secrets. These wrappers may pass credentials to the remote CLI.",
            "type": "string"
          },
          "dbPort": {
            "description": "Database TCP port on dbHost; omit for the engine CLI default.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "dbUser": {
            "description": "Database login user; distinct from the SSH user. Omit to use the remote CLI's configured defaults.",
            "type": "string"
          },
          "query": {
            "description": "SQL SELECT with an explicit LIMIT, or MongoDB JSON find filter. Use read-only DB permissions: text filtering is not a security sandbox.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "Database engine; the matching CLI must be installed on the SSH server.",
            "enum": [
              "mysql",
              "postgresql",
              "mongodb"
            ],
            "type": "string"
          }
        },
        "required": [
          "server",
          "type",
          "database",
          "query"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_deploy",
      "description": "Run a deployment command, or install an explicit list of local files on a POSIX catalog server. Use upload_batch when no deployment ownership/permissions/restart is needed.\nInputs: Command mode: command and optional remote cwd/timeout in milliseconds. File mode: files:[{local,remote}] and options; local is on this computer, remote on the server. File mode ignores command. backup defaults true; owner/permissions/restart may require passwordless sudo. restart runs after each file.\nResult: Read code or per-file results. Files are applied sequentially with no automatic rollback; prior files may already be installed after a failure. Verify config and the real service outcome before claiming deployment or retrying.\nExample: {\"server\":\"web-a\",\"command\":\"systemctl is-active app\",\"timeout\":10000}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "command": "systemctl is-active app",
            "server": "web-a",
            "timeout": 10000
          }
        ],
        "properties": {
          "command": {
            "description": "Command mode only, when files is absent. Ignored when files is supplied. A missing command defaults to a no-op, not a deployment.",
            "type": "string"
          },
          "cwd": {
            "description": "Working directory on the target server; omitted uses its configured default directory or SSH login directory.",
            "type": "string"
          },
          "files": {
            "description": "File mode: sequential local-to-remote installs; command is ignored. Uses fixed 120000 ms per privileged install step, not the command-mode timeout.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "local": {
                  "description": "Complete file path on the computer running this MCP companion. Prefer an absolute path; Windows example C:/Users/me/file.txt. Not a path on the center or target server.",
                  "type": "string"
                },
                "remote": {
                  "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
                  "type": "string"
                }
              },
              "required": [
                "local",
                "remote"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "options": {
            "additionalProperties": false,
            "description": "File-mode options. owner, permissions or restart uses sudo; backups do not provide automatic rollback.",
            "properties": {
              "backup": {
                "default": true,
                "description": "Copy an existing destination to a uniquely named .bak file before replacing it.",
                "type": "boolean"
              },
              "owner": {
                "description": "Remote chown owner[:group]; requires sudo permission.",
                "type": "string"
              },
              "permissions": {
                "description": "Remote chmod mode, for example 0644; requires sudo permission.",
                "type": "string"
              },
              "restart": {
                "description": "Exact systemd service to restart after EACH file. Omit and perform one separate restart after a multi-file deployment when appropriate.",
                "type": "string"
              },
              "sudoPassword": {
                "description": "Optional sudo credential; avoid model-visible secrets. Omit when passwordless sudo is available.",
                "type": "string"
              }
            },
            "type": "object"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "timeout": {
            "default": 120000,
            "description": "Timeout in milliseconds, not seconds. Use 10000 for 10 seconds or 30000 for 30 seconds. Default 120000 ms; capped at 300000 ms. 0 disables the command deadline and remote timeout wrapper; connection-establishment limits still apply. Prefer omission for the normal bounded default. A timeout does not prove a remote write had no effect.",
            "maximum": 300000,
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_download",
      "description": "Copy one remote file to this MCP computer. Use ssh_read to inspect text without saving a local copy; use ssh_sync for directories.\nInputs: server from ssh_list_servers; remotePath is the existing source filename on that server, localPath is the complete destination filename on this computer. Windows localPath may be C:/Users/me/Downloads/file.zip.\nResult: Replaces the local destination through the configured direct/bastion route. Verify the saved file/hash as needed. A caller timeout alone does not prove that no local file was committed.\nExample: {\"server\":\"web-a\",\"remotePath\":\"/srv/app/report.txt\",\"localPath\":\"/home/me/Downloads/report.txt\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "localPath": "/home/me/Downloads/report.txt",
            "remotePath": "/srv/app/report.txt",
            "server": "web-a"
          }
        ],
        "properties": {
          "localPath": {
            "description": "Complete file path on the computer running this MCP companion. Prefer an absolute path; Windows example C:/Users/me/file.txt. Not a path on the center or target server.",
            "type": "string"
          },
          "remotePath": {
            "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "localPath",
          "remotePath"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_edit",
      "description": "Replace exact text inside an existing remote file. Read the relevant text with ssh_read first. Use ssh_write only when replacing the entire file is intended.\nInputs: server, remotePath, oldString and newString. Strings are literal, not regex. replaceAll defaults false; multiple matches otherwise fail rather than guessing. Omit displayed line numbers from oldString.\nResult: Returns a bounded change summary. A successful edit is a saved file, not a service reload; validate the config and reload only within the user's scope. On a mismatch, read again and revise the edit.\nExample: {\"server\":\"web-a\",\"remotePath\":\"/srv/app/app.conf\",\"oldString\":\"workers = 2\",\"newString\":\"workers = 4\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "newString": "workers = 4",
            "oldString": "workers = 2",
            "remotePath": "/srv/app/app.conf",
            "server": "web-a"
          }
        ],
        "properties": {
          "newString": {
            "description": "Replacement text. Empty string deletes matched text; include intended newlines exactly.",
            "type": "string"
          },
          "oldString": {
            "description": "Exact existing text from a recent ssh_read, excluding displayed line numbers. Literal match, not regex.",
            "type": "string"
          },
          "remotePath": {
            "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
            "type": "string"
          },
          "replaceAll": {
            "default": false,
            "description": "Replace every match. False requires one unambiguous match; read again if it fails instead of guessing.",
            "type": "boolean"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "remotePath",
          "oldString",
          "newString"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_execute",
      "description": "Run one command on one catalog server. Start with ssh_list_servers; use ssh_execute_group for the same command on several servers.\nInputs: server is the returned name, command uses that server's shell, cwd belongs to that server. timeout is milliseconds: 10000 = 10 seconds; omit for 120000, maximum 300000. Use ssh_execute_sudo when elevation is required.\nResult: Read code, stdout and stderr; code=0 means the command exited successfully, not that the whole deployment is verified. A timeout/disconnect may leave the outcome unknown: inspect the remote state before retrying a write.\nExample: {\"server\":\"web-a\",\"command\":\"hostname\",\"timeout\":10000}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "command": "hostname",
            "server": "web-a",
            "timeout": 10000
          }
        ],
        "properties": {
          "command": {
            "description": "Command interpreted by the target server's shell. Use POSIX syntax for POSIX targets and PowerShell for platform=windows. The command can change remote state; scope it to the user's request.",
            "type": "string"
          },
          "cwd": {
            "description": "Working directory on the target server; omitted uses its configured default directory or SSH login directory.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "timeout": {
            "default": 120000,
            "description": "Timeout in milliseconds, not seconds. Use 10000 for 10 seconds or 30000 for 30 seconds. Default 120000 ms; capped at 300000 ms. 0 disables the command deadline and remote timeout wrapper; connection-establishment limits still apply. Prefer omission for the normal bounded default. A timeout does not prove a remote write had no effect.",
            "maximum": 300000,
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "server",
          "command"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_execute_group",
      "description": "Run the same command on an explicit set of catalog servers in one call. Prefer this over separate ssh_execute calls for independent targets.\nInputs: Provide servers from ssh_list_servers, or one existing group. strategy=parallel for independent work, sequential for dependencies, rolling for a delayed sequence. timeout and delay are milliseconds. stopOnError cannot recall already dispatched parallel work.\nResult: Inspect every server result and skipped target. This is not a transaction; successful targets stay changed if another fails. Retry only targets whose state is known.\nExample: {\"servers\":[\"web-a\",\"web-b\"],\"command\":\"hostname\",\"strategy\":\"parallel\",\"timeout\":10000}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "command": "hostname",
            "servers": [
              "web-a",
              "web-b"
            ],
            "strategy": "parallel",
            "timeout": 10000
          }
        ],
        "properties": {
          "command": {
            "description": "Command interpreted by the target server's shell. Use POSIX syntax for POSIX targets and PowerShell for platform=windows. The command can change remote state; scope it to the user's request.",
            "type": "string"
          },
          "cwd": {
            "description": "Working directory on the target server; omitted uses its configured default directory or SSH login directory.",
            "type": "string"
          },
          "delay": {
            "description": "Rolling delay in milliseconds: 1000 = 1 second. Omit for group setting or 0; ignored by parallel/sequential.",
            "minimum": 0,
            "type": "integer"
          },
          "group": {
            "description": "Existing local group from ssh_group_manage. Required when servers is omitted/empty.",
            "type": "string"
          },
          "servers": {
            "description": "Explicit target names from ssh_list_servers. Prefer this for a fixed task scope; a nonempty list takes precedence over group.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "stopOnError": {
            "description": "Default false, or the group setting. Stop sending later sequential/rolling commands after failure; parallel commands have already been sent and are not cancelled.",
            "type": "boolean"
          },
          "strategy": {
            "description": "Default parallel, or the group's configured strategy. parallel starts all targets; sequential follows input order; rolling adds delay between sequential targets.",
            "enum": [
              "parallel",
              "sequential",
              "rolling"
            ],
            "type": "string"
          },
          "timeout": {
            "default": 120000,
            "description": "Timeout in milliseconds, not seconds. Use 10000 for 10 seconds or 30000 for 30 seconds. Default 120000 ms; capped at 300000 ms. 0 disables the command deadline and remote timeout wrapper; connection-establishment limits still apply. Prefer omission for the normal bounded default. A timeout does not prove a remote write had no effect.",
            "maximum": 300000,
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "command"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_execute_sudo",
      "description": "Run one authorized command with sudo on a POSIX catalog server. Use ssh_execute when elevation is unnecessary.\nInputs: server, command; cwd is remote. Uses the configured sudo credential or passwordless sudo. password is an optional override; never ask the user to paste secrets into chat. timeout uses milliseconds, default 120000, maximum 300000.\nResult: Read code/stdout/stderr and verify the intended state. Elevation or timeout failure does not authorize changing sudo policy or replaying a write.\nExample: {\"server\":\"web-a\",\"command\":\"systemctl is-active nginx\",\"timeout\":10000}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "command": "systemctl is-active nginx",
            "server": "web-a",
            "timeout": 10000
          }
        ],
        "properties": {
          "command": {
            "description": "Command interpreted by the target server's shell. Use POSIX syntax for POSIX targets and PowerShell for platform=windows. The command can change remote state; scope it to the user's request.",
            "type": "string"
          },
          "cwd": {
            "description": "Working directory on the target server; omitted uses its configured default directory or SSH login directory.",
            "type": "string"
          },
          "password": {
            "description": "Optional sudo password override. Omit to use the configured sudo credential or passwordless sudo; never copy secrets into chat or logs.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "timeout": {
            "default": 120000,
            "description": "Timeout in milliseconds, not seconds. Use 10000 for 10 seconds or 30000 for 30 seconds. Default 120000 ms; capped at 300000 ms. 0 disables the command deadline and remote timeout wrapper; connection-establishment limits still apply. Prefer omission for the normal bounded default. A timeout does not prove a remote write had no effect.",
            "maximum": 300000,
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "server",
          "command"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_group_manage",
      "description": "Maintain named server groups on this MCP computer for ssh_execute_group. Groups are not synchronized by the center and are separate from native device clusters.\nInputs: list/get reads all. set/add/update needs name and servers from ssh_list_servers; optional strategy, delay in milliseconds, stopOnError. add-servers/remove-servers changes only named membership. remove/delete needs name and removes that group only.\nResult: Returns the saved group map; it does not contact group members. To run a command, pass the group name to ssh_execute_group or supply explicit servers.\nExample: {\"action\":\"list\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "list"
          }
        ],
        "properties": {
          "action": {
            "description": "Default list. list/get reads the whole map; set/add replaces one entry; update merges object values; remove/delete deletes one entry. See tool description for specialized actions.",
            "enum": [
              "list",
              "get",
              "set",
              "add",
              "update",
              "remove",
              "delete",
              "add-servers",
              "remove-servers"
            ],
            "type": "string"
          },
          "delay": {
            "description": "Default rolling delay in milliseconds; 1000 = 1 second.",
            "minimum": 0,
            "type": "integer"
          },
          "description": {
            "description": "Optional saved note; no execution effect.",
            "type": "string"
          },
          "name": {
            "description": "Saved item name. Required for writes/removal unless the tool-specific alias/hook/profile name is supplied.",
            "type": "string"
          },
          "servers": {
            "description": "Catalog names to save, add or remove from this local command group.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "stopOnError": {
            "default": false,
            "description": "Group default for sequential/rolling fail-stop; cannot cancel already dispatched parallel commands.",
            "type": "boolean"
          },
          "strategy": {
            "description": "Default group execution strategy used by ssh_execute_group when its call omits strategy.",
            "enum": [
              "parallel",
              "sequential",
              "rolling"
            ],
            "type": "string"
          },
          "value": {
            "description": "Explicit saved JSON value. set/add replaces the entry; update merges object fields when both sides are objects. Read/saving alone does not execute commands."
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_health_check",
      "description": "Take one CPU, memory and filesystem health snapshot on a POSIX catalog server. Use ssh_service_status for a specific service.\nInputs: server from ssh_list_servers; mountPoint defaults /. Requires the server's usual POSIX monitoring commands. For Windows use ssh_execute with native PowerShell commands.\nResult: Returns metrics, timestamp and healthy/warning/critical thresholds. A healthy host does not prove that an application or network path works. This does not install a monitor.\nExample: {\"server\":\"web-a\",\"mountPoint\":\"/\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "mountPoint": "/",
            "server": "web-a"
          }
        ],
        "properties": {
          "mountPoint": {
            "description": "Remote filesystem path to inspect, default /. One snapshot; no background monitor is installed.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_history",
      "description": "Read recent command history recorded on this MCP computer. Use it to locate prior commands, not to prove current remote state.\nInputs: Optional server/command search filters, success boolean and limit (default 20, maximum 1000). Does not fetch shell history from a remote server.\nResult: Returns entries with recorded command, timestamp and outcome. Historical success may be stale; inspect the target before deciding whether a write must run again.\nExample: {\"limit\":10}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "limit": 10
          }
        ],
        "properties": {
          "limit": {
            "default": 20,
            "description": "Maximum retained history entries returned, newest window; 0 returns no entries.",
            "maximum": 1000,
            "minimum": 0,
            "type": "integer"
          },
          "search": {
            "description": "Case-insensitive substring in recorded command text; not remote shell-history search.",
            "type": "string"
          },
          "server": {
            "description": "Case-insensitive substring filter on recorded server names.",
            "type": "string"
          },
          "success": {
            "description": "Omit for all outcomes; true/false filters the recorded command success.",
            "type": "boolean"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_hooks",
      "description": "Inspect or store legacy hook metadata on this MCP computer. The native runtime does not automatically execute these saved hooks.\nInputs: list/get/status reads all. set/add/update needs hook (or name) and value. enable/disable needs hook and replaces that entry with its enabled flag. remove/delete needs hook.\nResult: Returns saved metadata only; enabled=true is not a running scheduled task or event subscription. Use explicit commands or native cluster tools for actual execution.\nExample: {\"action\":\"status\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "status"
          }
        ],
        "properties": {
          "action": {
            "description": "Default list. list/get reads the whole map; set/add replaces one entry; update merges object values; remove/delete deletes one entry. See tool description for specialized actions.",
            "enum": [
              "list",
              "get",
              "set",
              "add",
              "update",
              "remove",
              "delete",
              "enable",
              "disable",
              "status"
            ],
            "type": "string"
          },
          "command": {
            "description": "Optional stored command text; native runtime does not automatically execute this hook.",
            "type": "string"
          },
          "description": {
            "description": "Optional saved note; no execution effect.",
            "type": "string"
          },
          "hook": {
            "description": "Hook entry name; required for enable/disable. Those actions replace the entry with only an enabled flag.",
            "type": "string"
          },
          "name": {
            "description": "Saved item name. Required for writes/removal unless the tool-specific alias/hook/profile name is supplied.",
            "type": "string"
          },
          "value": {
            "description": "Explicit saved JSON value. set/add replaces the entry; update merges object fields when both sides are objects. Read/saving alone does not execute commands."
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_key_manage",
      "description": "Read this runtime's SSH known-hosts entries. This does not create, import or rotate SSH login keys.\nInputs: Use action=list or omit action. Other legacy action names do not implement key acceptance/removal in the native runtime and must not be used as a repair step.\nResult: Returns known-hosts text only. It is not a live host fingerprint verification. A host-key mismatch needs independent identity verification before an authorized trust-store change.\nExample: {\"action\":\"list\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "list"
          }
        ],
        "properties": {
          "action": {
            "description": "Read this runtime's known-hosts text. Native key acceptance/removal is not implemented by this tool.",
            "enum": [
              "list"
            ],
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_list_servers",
      "description": "Find the authoritative SSHMCP server names before any remote operation. This is the starting tool when the user names a server; do not search local SSH files to select it.\nInputs: No arguments. Use the returned name exactly in other tools; host/IP alone is not a server argument. If the target is missing, obtain its intended connection details before ssh_server_manage add.\nResult: Returns count and servers with name, platform, permission mode and configured route scope. Empty servers is a valid empty catalog, not a connection failure. Listing does not test SSH login.\nExample: {}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {}
        ],
        "properties": {},
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_monitor",
      "description": "Take one CPU, memory and disk metrics snapshot on a POSIX catalog server. This call does not stream, schedule or keep monitoring.\nInputs: server from ssh_list_servers; optional mountPoint (default /). interval/duration/type from legacy clients do not control native sampling; do not use them for continuous monitoring.\nResult: Returns cpu, memory and disk measurements from this call. For continuous native device observations use cluster/node probe configuration and inspect timestamped results.\nExample: {\"server\":\"web-a\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "server": "web-a"
          }
        ],
        "properties": {
          "mountPoint": {
            "description": "Remote filesystem path to inspect, default /. One snapshot; no background monitor is installed.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_node_manage",
      "description": "Manage an SSHMCP native node or the local companion lifecycle. Start with inspect/discover; remote control follows the catalog's independent SSH management route.\nInputs: server is a catalog name or @local; action is required. install uploads/registers without starting. configure needs update.expectedRevision and complete replacements for supplied arrays. pair needs peer, optional coordinator/protocol/forwards; inspect both installed identities first. revoke needs peer grant name from inspect. start/stop control the node. @local startup uses startup=login|boot|off|status with no instance; @local upgrade queues an enabled auto-update check.\nResult: Compare saved and loaded revisions and per-node receipts; pair/configure never implicitly starts services. Check connectivity.links for actual QUIC/TCP/NAT success. Remote upgrade preserves identity and started/stopped state. Stop/revoke can close affected streams; uninstall requires retired dependencies. Queued update is not installed: inspect ssh_connection_status.\nExample: {\"server\":\"@local\",\"action\":\"inspect\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "inspect",
            "server": "@local"
          }
        ],
        "properties": {
          "action": {
            "description": "inspect/discover reads identity/state. install prepares without starting; configure needs update.expectedRevision; pair needs peer; revoke needs an inspected peer grant name. start/stop/upgrade/uninstall affect the owned node. @local startup and upgrade control the companion.",
            "enum": [
              "install",
              "inspect",
              "configure",
              "start",
              "stop",
              "pair",
              "upgrade",
              "startup",
              "revoke",
              "uninstall",
              "discover"
            ],
            "type": "string"
          },
          "bind": {
            "default": "127.0.0.1:0",
            "description": "install only: numeric listener address:port. Port 0 allocates and saves a port. Explicit 0.0.0.0 exposes the authenticated node to the network.",
            "type": "string"
          },
          "coordinator": {
            "description": "pair only: optional third installed node with coordinate=true and advertised reachable addresses.",
            "type": "string"
          },
          "forwards": {
            "description": "pair only. Source listeners and exact TCP destinations on peer. Explicit non-loopback listen exposes this forward to the network.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "id": {
                  "description": "Unique forward ID on the initiating node.",
                  "type": "string"
                },
                "listen": {
                  "description": "Numeric bind IP:port on the source node. Non-loopback makes this listener reachable by other computers.",
                  "type": "string"
                },
                "target": {
                  "description": "Exact numeric destination IP:port as reached by the peer node, e.g. 127.0.0.1:22 refers to that peer.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "listen",
                "target"
              ],
              "type": "object"
            },
            "maxItems": 32,
            "type": "array"
          },
          "instance": {
            "description": "Optional separate named node instance on every selected server. Omit for the default node. Named instances have separate identities, ports and owned services.",
            "pattern": "^[a-z0-9-]{1,40}$",
            "type": "string"
          },
          "peer": {
            "description": "pair: other installed node server from ssh_list_servers. revoke: exact peer grant name from inspect.node.peers[].name, not a server name.",
            "type": "string"
          },
          "protocol": {
            "description": "pair only: auto negotiates supported QUIC/TCP connectivity; quic or tcp restricts the pair. Check loaded links for the actual transport and NAT reachability.",
            "enum": [
              "auto",
              "quic",
              "tcp"
            ],
            "type": "string"
          },
          "server": {
            "description": "SSH management profile from ssh_list_servers, or @local for the embedded device in this shared companion. @local uses this companion profile. action=startup with startup=login|boot|off|status manages its owned supervisor; omit instance. install initializes identity; start/stop control only the embedded node.",
            "type": "string"
          },
          "startup": {
            "description": "Startup policy. @local action=startup accepts login|boot|off|status and no instance. Remote install uses auto/login/boot as supported by the OS account; boot needs appropriate permission. A saved startup policy is not a reboot test.",
            "enum": [
              "auto",
              "login",
              "boot",
              "off",
              "status"
            ],
            "type": "string"
          },
          "update": {
            "additionalProperties": false,
            "description": "configure only. Replace only the supplied complete fields; retain omitted fields. Inspect revision first. Private identity keys are never accepted.",
            "properties": {
              "connectivity": {
                "additionalProperties": false,
                "description": "Complete native P2P configuration. UDP/QUIC and optional TCP reuse each bound port for discovery, punching and authenticated connections. Set enabled=false to stop P2P. Initial enable is hot; changing bound ports of a running engine needs a scoped node restart.",
                "properties": {
                  "advertised": {
                    "description": "Reachable UDP endpoints advertised for this node.",
                    "items": {
                      "description": "Numeric unicast IP:port with nonzero port.",
                      "type": "string"
                    },
                    "maxItems": 8,
                    "type": "array"
                  },
                  "bind": {
                    "description": "UDP bind, e.g. 0.0.0.0:0. Port 0 allocates and saves a persistent port.",
                    "type": "string"
                  },
                  "coordinate": {
                    "description": "Allow mutually granted peers to exchange candidates over authenticated connections.",
                    "type": "boolean"
                  },
                  "discovery": {
                    "description": "Answer bounded public STUN requests; not a traffic relay.",
                    "type": "boolean"
                  },
                  "enabled": {
                    "default": true,
                    "type": "boolean"
                  },
                  "forwards": {
                    "items": {
                      "additionalProperties": false,
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "link": {
                          "type": "string"
                        },
                        "listen": {
                          "type": "string"
                        },
                        "target": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "link",
                        "listen",
                        "target"
                      ],
                      "type": "object"
                    },
                    "maxItems": 32,
                    "type": "array"
                  },
                  "links": {
                    "items": {
                      "additionalProperties": false,
                      "properties": {
                        "candidates": {
                          "items": {
                            "description": "Numeric unicast IP:port with nonzero port.",
                            "type": "string"
                          },
                          "maxItems": 8,
                          "type": "array"
                        },
                        "certificate": {
                          "type": "string"
                        },
                        "coordinator": {
                          "additionalProperties": false,
                          "properties": {
                            "address": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "certificate": {
                              "type": "string"
                            },
                            "target_peer": {
                              "type": "string"
                            },
                            "tcp_address": {
                              "type": [
                                "string",
                                "null"
                              ]
                            }
                          },
                          "required": [
                            "certificate",
                            "target_peer"
                          ],
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "id": {
                          "type": "string"
                        },
                        "protocol": {
                          "default": "auto",
                          "description": "auto tries QUIC then TCP and retains a working path. tcp forces TCP. NAT success depends on the network.",
                          "enum": [
                            "auto",
                            "quic",
                            "tcp"
                          ],
                          "type": "string"
                        },
                        "tcp_candidates": {
                          "items": {
                            "description": "Numeric unicast IP:port with nonzero port.",
                            "type": "string"
                          },
                          "maxItems": 8,
                          "type": "array"
                        }
                      },
                      "required": [
                        "id",
                        "certificate"
                      ],
                      "type": "object"
                    },
                    "maxItems": 16,
                    "type": "array"
                  },
                  "stun_servers": {
                    "description": "Public STUN endpoints used for discovery; these do not carry file payloads.",
                    "items": {
                      "description": "Numeric unicast IP:port with nonzero port.",
                      "type": "string"
                    },
                    "maxItems": 4,
                    "type": "array"
                  },
                  "tcp_advertised": {
                    "description": "Reachable TCP endpoints advertised for this node; separate from UDP advertised addresses.",
                    "items": {
                      "description": "Numeric unicast IP:port with nonzero port.",
                      "type": "string"
                    },
                    "maxItems": 8,
                    "type": "array"
                  },
                  "tcp_bind": {
                    "description": "Enable TCP punching with e.g. 0.0.0.0:0; null disables TCP.",
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "bind"
                ],
                "type": "object"
              },
              "expectedRevision": {
                "description": "Required configure revision from the most recent node inspect. Do not use a cluster or route revision.",
                "minimum": 0,
                "type": "integer"
              },
              "peers": {
                "description": "Complete peer grant list when supplied. Preserve unrelated entries; [] revokes all peers and their loaded streams.",
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "certificate": {
                      "description": "Peer public TLS certificate from node inspect; required for P2P.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "connect": {
                      "description": "Exact numeric IP:port targets this identity may connect to.",
                      "items": {
                        "type": "string"
                      },
                      "maxItems": 64,
                      "type": "array"
                    },
                    "files": {
                      "description": "Limited file tasks for this authenticated peer; 64 tasks total per node. New grants are pinned by the receiving node. Empty array revokes file access and active streams. Native identity directories cannot be granted.",
                      "items": {
                        "additionalProperties": false,
                        "properties": {
                          "delete": {
                            "description": "Deletion requires write=true and exact expected content versions.",
                            "type": "boolean"
                          },
                          "expiresAt": {
                            "description": "Unix timestamp in seconds, at most 24 hours ahead. Expiry cancels file operations; it is not a millisecond timeout.",
                            "type": "integer"
                          },
                          "pin": {
                            "description": "Omit for a new grant; preserve the returned pin when retaining a grant. A changed anchor identity is rejected.",
                            "oneOf": [
                              {
                                "type": "null"
                              },
                              {
                                "additionalProperties": false,
                                "properties": {
                                  "anchor": {
                                    "type": "string"
                                  },
                                  "identity": {
                                    "type": "string"
                                  },
                                  "relative": {
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "anchor",
                                  "relative",
                                  "identity"
                                ],
                                "type": "object"
                              }
                            ]
                          },
                          "read": {
                            "const": true,
                            "description": "Required for content and version checks."
                          },
                          "root": {
                            "description": "Absolute directory on this receiving node. Relative protocol paths stay inside it; symlinks, hardlinks and Windows reserved names are rejected.",
                            "type": "string"
                          },
                          "sources": {
                            "description": "Exact source link/task pairs this receiver may pull. Empty prevents delegated source reads.",
                            "items": {
                              "additionalProperties": false,
                              "properties": {
                                "link": {
                                  "type": "string"
                                },
                                "task": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "link",
                                "task"
                              ],
                              "type": "object"
                            },
                            "maxItems": 32,
                            "type": "array"
                          },
                          "task": {
                            "description": "Unpredictable task ID shared only with its participants; letters, digits, - and _.",
                            "maxLength": 128,
                            "minLength": 8,
                            "type": "string"
                          },
                          "write": {
                            "type": "boolean"
                          }
                        },
                        "required": [
                          "task",
                          "root",
                          "read",
                          "write",
                          "delete",
                          "expiresAt"
                        ],
                        "type": "object"
                      },
                      "maxItems": 64,
                      "type": "array"
                    },
                    "introduce": {
                      "description": "On a coordinator, other registered peer names this identity may discover. Both sides must grant each other. Gives no business forwarding permission.",
                      "items": {
                        "type": "string"
                      },
                      "maxItems": 64,
                      "type": "array"
                    },
                    "listen": {
                      "description": "Exact numeric IP:port reverse listeners this identity may create.",
                      "items": {
                        "type": "string"
                      },
                      "maxItems": 64,
                      "type": "array"
                    },
                    "name": {
                      "description": "Stable local grant name for this peer; revoke uses this exact name, not necessarily a server name.",
                      "type": "string"
                    },
                    "public_key": {
                      "description": "Peer OpenSSH public key from node inspect.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "name",
                    "public_key"
                  ],
                  "type": "object"
                },
                "maxItems": 256,
                "type": "array"
              },
              "probes": {
                "description": "Complete periodic probe list on this node; empty disables probes. Two concurrent probes maximum. Targets are explicit; no subnet scan. Preserve other owners when editing. RTT is endpoint-specific; failure rate is probe failure, not physical packet loss.",
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "id": {
                      "maxLength": 96,
                      "type": "string"
                    },
                    "intervalMs": {
                      "default": 10000,
                      "description": "Probe interval in milliseconds; 10000 = 10 seconds. Must be at least timeoutMs.",
                      "maximum": 300000,
                      "minimum": 1000,
                      "type": "integer"
                    },
                    "owner": {
                      "maxLength": 64,
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "target": {
                      "oneOf": [
                        {
                          "additionalProperties": false,
                          "properties": {
                            "address": {
                              "description": "Exact numeric endpoint this device actively connects to; measures TCP connection establishment.",
                              "type": "string"
                            },
                            "kind": {
                              "const": "tcp"
                            }
                          },
                          "required": [
                            "kind",
                            "address"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "kind": {
                              "const": "p2p"
                            },
                            "link": {
                              "description": "Configured authenticated peer link; measures application ping over its actual QUIC/TCP connection.",
                              "type": "string"
                            }
                          },
                          "required": [
                            "kind",
                            "link"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "kind": {
                              "const": "forward"
                            },
                            "link": {
                              "type": "string"
                            },
                            "target": {
                              "description": "Exact TCP destination granted by that peer; measures the complete native open and target connection.",
                              "type": "string"
                            }
                          },
                          "required": [
                            "kind",
                            "link",
                            "target"
                          ],
                          "type": "object"
                        }
                      ]
                    },
                    "timeoutMs": {
                      "default": 2000,
                      "description": "Milliseconds; 1000 = 1 second. Must not exceed intervalMs.",
                      "maximum": 10000,
                      "minimum": 100,
                      "type": "integer"
                    },
                    "window": {
                      "default": 30,
                      "description": "Number of recent probe samples retained, not seconds.",
                      "maximum": 60,
                      "minimum": 2,
                      "type": "integer"
                    }
                  },
                  "required": [
                    "id",
                    "target"
                  ],
                  "type": "object"
                },
                "maxItems": 16,
                "type": "array"
              },
              "reverse": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "gateway": {
                      "type": "string"
                    },
                    "gateway_public_key": {
                      "type": "string"
                    },
                    "generation": {
                      "description": "Increment to reconnect this reverse link.",
                      "minimum": 0,
                      "type": "integer"
                    },
                    "id": {
                      "type": "string"
                    },
                    "listen": {
                      "type": "string"
                    },
                    "target": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "gateway",
                    "gateway_public_key",
                    "listen",
                    "target"
                  ],
                  "type": "object"
                },
                "maxItems": 64,
                "type": "array"
              }
            },
            "required": [
              "expectedRevision"
            ],
            "type": "object"
          }
        },
        "required": [
          "action",
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_process_manager",
      "description": "List, inspect or signal processes on a POSIX catalog server. Inspect the PID and command before an authorized kill action.\nInputs: server; action defaults list. list uses limit (default 20, cap 200), sortBy=cpu|memory and optional literal filter applied to that bounded list. info/kill require pid. kill signal defaults TERM; KILL cannot allow graceful cleanup.\nResult: Read code/stdout/stderr. A signal can affect other users or services and does not prove the process stopped; verify the exact PID/state afterward. Windows uses ssh_execute native commands.\nExample: {\"server\":\"web-a\",\"action\":\"list\",\"limit\":10}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "list",
            "limit": 10,
            "server": "web-a"
          }
        ],
        "properties": {
          "action": {
            "description": "Default list. info/kill need pid; kill sends a signal and changes the remote process state.",
            "enum": [
              "list",
              "info",
              "kill"
            ],
            "type": "string"
          },
          "filter": {
            "description": "Literal text applied after selecting the top limit rows; not a complete search across all processes.",
            "type": "string"
          },
          "limit": {
            "default": 20,
            "description": "Maximum rows selected by ps/head before applying filter.",
            "maximum": 200,
            "minimum": 0,
            "type": "integer"
          },
          "pid": {
            "description": "Exact remote PID from a fresh process inspection; required by info/kill. Verify command/owner before signalling.",
            "minimum": 1,
            "type": "integer"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "signal": {
            "description": "kill only; default TERM. KILL prevents graceful process cleanup.",
            "enum": [
              "TERM",
              "KILL",
              "HUP",
              "INT",
              "QUIT"
            ],
            "type": "string"
          },
          "sortBy": {
            "description": "list ordering, default cpu.",
            "enum": [
              "cpu",
              "memory"
            ],
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_profile",
      "description": "Inspect or store legacy profile metadata on this MCP computer. This does not change the active connection.json or reload the native server catalog.\nInputs: list/get/current reads saved metadata. set/add/update needs name (or profile) and value. switch needs profile and replaces saved state with an active label; it is not a runtime mode switch. remove/delete needs name/profile.\nResult: Returns saved metadata. To change local/center installation mode or the active endpoint, use the native installer with the user's explicit selection.\nExample: {\"action\":\"list\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "list"
          }
        ],
        "properties": {
          "action": {
            "description": "Default list. list/get reads the whole map; set/add replaces one entry; update merges object values; remove/delete deletes one entry. See tool description for specialized actions.",
            "enum": [
              "list",
              "get",
              "set",
              "add",
              "update",
              "remove",
              "delete",
              "current",
              "switch"
            ],
            "type": "string"
          },
          "description": {
            "description": "Optional saved note; no execution effect.",
            "type": "string"
          },
          "name": {
            "description": "Saved item name. Required for writes/removal unless the tool-specific alias/hook/profile name is supplied.",
            "type": "string"
          },
          "profile": {
            "description": "Profile metadata label. switch requires this field and replaces saved metadata with an active label; it does not switch connection.json or the runtime catalog.",
            "type": "string"
          },
          "value": {
            "description": "Explicit saved JSON value. set/add replaces the entry; update merges object fields when both sides are objects. Read/saving alone does not execute commands."
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_read",
      "description": "Read a page of a remote text file with line numbers. Use ssh_download for binary files or a full local copy.\nInputs: server from ssh_list_servers, remotePath on that server. offset is a 1-based starting line; limit is a line count. Neither is a byte offset.\nResult: Returns a bounded text page, not a saved local file. Before ssh_edit, read the relevant page and use exact original text without the displayed line-number prefixes.\nExample: {\"server\":\"web-a\",\"remotePath\":\"/srv/app/app.conf\",\"offset\":1,\"limit\":80}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "limit": 80,
            "offset": 1,
            "remotePath": "/srv/app/app.conf",
            "server": "web-a"
          }
        ],
        "properties": {
          "limit": {
            "default": 2000,
            "description": "Maximum lines in this page; default 2000, 0 returns no lines. Use a small page such as 80 for inspection.",
            "minimum": 0,
            "type": "integer"
          },
          "offset": {
            "default": 1,
            "description": "First line, 1-based; 1 starts at the file beginning. Not a byte offset.",
            "minimum": 1,
            "type": "integer"
          },
          "remotePath": {
            "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "remotePath"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_route_apply",
      "description": "Apply a reviewed ssh_route_plan and verify target SSH authentication before committing the authority revision.\nInputs: Use the exact planId and expectedRevision returned together by ssh_route_plan; never guess a revision or rebuild a plan from an error message. Existing SSH permissions and mandatory hops remain in force.\nResult: Returns verified, rolled_back or recovery_required with step evidence. A repeat of a verified plan returns its receipt. Failure can leave partial runtime effects: inspect this planId before any repair; active commands are never replayed.\nExample: {\"planId\":\"plan_id_from_route_plan\",\"expectedRevision\":3}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "expectedRevision": 3,
            "planId": "plan_id_from_route_plan"
          }
        ],
        "properties": {
          "expectedRevision": {
            "description": "Exact expectedRevision returned with that plan.",
            "minimum": 0,
            "type": "integer"
          },
          "planId": {
            "description": "Exact planId returned by ssh_route_plan; never invent it.",
            "type": "string"
          }
        },
        "required": [
          "planId",
          "expectedRevision"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_route_inspect",
      "description": "Inspect configured SSH routes, native devices, owned resources and observations before changing a route or repairing connectivity.\nInputs: server is optional and comes from ssh_list_servers. probe=true makes fresh SSH and read-only resource checks; omit for a snapshot. resourceIds narrows probes. planId instead reads a prior apply receipt without probing.\nResult: Distinguish desired config from timestamped observations; cached/stale is not live proof. Use returned device/resource IDs and current revisions in ssh_route_plan. After an interrupted apply, query its planId before retrying.\nExample: {\"server\":\"web-a\",\"probe\":true}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "probe": true,
            "server": "web-a"
          }
        ],
        "properties": {
          "planId": {
            "description": "Read the durable receipt of an apply operation, including partial failure or rollback. Omit server/probe when supplied.",
            "type": "string"
          },
          "probe": {
            "default": false,
            "description": "Perform fresh SSH authentication and read-only native/service/listener probes for selected resources. Resource observations are timestamped and saved without changing desired topology.",
            "type": "boolean"
          },
          "resourceIds": {
            "description": "Optional resource IDs from previous inspect. With probe=true, refresh only these resources. Otherwise server selects its route resources; omitted server selects the graph, capped at 64 probes.",
            "items": {
              "type": "string"
            },
            "maxItems": 64,
            "type": "array"
          },
          "server": {
            "description": "Optional target name from ssh_list_servers. Omit to inspect all registered targets.",
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_route_plan",
      "description": "Prepare a five-minute route/resource change plan. This saves a plan but does not apply live route or service changes. Inspect the existing route first.\nInputs: operation and server are required. via is the entire ordered SSH hop list; [] means direct, never an implicit fallback. Native ingress also needs inspected sourceDevice/receiving device UUIDs. resources replace exact owned definitions; resourceIds references dependencies. rollback needs rollbackPlanId.\nResult: Review the returned changes, then pass its exact planId and expectedRevision to ssh_route_apply. Shared dependencies and self-severing management paths are protected. Expired/stale plans require fresh inspection and a new plan.\nExample: {\"operation\":\"create\",\"server\":\"web-a\",\"via\":[\"bastion\"]}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "operation": "create",
            "server": "web-a",
            "via": [
              "bastion"
            ]
          }
        ],
        "properties": {
          "description": {
            "description": "Optional route note; does not define the route or replace structured resource fields.",
            "type": "string"
          },
          "ingress": {
            "description": "Transport to the first SSH hop (or final server when via=[]). It preserves SSH login, target host-key and command permissions. null removes an ingress. target is a numeric socket address as seen on device. Existing explicit SSH hops are still honored.",
            "oneOf": [
              {
                "type": "null"
              },
              {
                "additionalProperties": false,
                "properties": {
                  "coordinator": {
                    "description": "Optional registered introduction node ID. Never carries application bytes unless independently selected as a gateway.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "device": {
                    "description": "Registered receiving node ID.",
                    "format": "uuid",
                    "type": "string"
                  },
                  "fallback": {
                    "default": false,
                    "description": "Explicitly allow the configured SSH route if P2P cannot connect; actual fallback is reported.",
                    "type": "boolean"
                  },
                  "kind": {
                    "const": "p2p"
                  },
                  "protocol": {
                    "default": "auto",
                    "enum": [
                      "auto",
                      "quic",
                      "tcp"
                    ]
                  },
                  "target": {
                    "description": "Authorized SSH service endpoint on the receiving device, e.g. 127.0.0.1:22.",
                    "type": "string"
                  },
                  "timeout_ms": {
                    "default": 8000,
                    "description": "P2P connect timeout in milliseconds; 10000 = 10 seconds.",
                    "maximum": 120000,
                    "minimum": 100,
                    "type": "integer"
                  }
                },
                "required": [
                  "kind",
                  "device",
                  "target"
                ],
                "type": "object"
              },
              {
                "additionalProperties": false,
                "properties": {
                  "device": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "gateway": {
                    "description": "Native gateway numeric SSH listener reachable from this companion.",
                    "type": "string"
                  },
                  "kind": {
                    "const": "native"
                  },
                  "target": {
                    "description": "Numeric endpoint reached by the gateway; may be its loopback reverse listener.",
                    "type": "string"
                  }
                },
                "required": [
                  "kind",
                  "device",
                  "gateway",
                  "target"
                ],
                "type": "object"
              }
            ]
          },
          "operation": {
            "description": "Desired plan operation. Creates a saved plan only; inspect and apply its returned planId/revision separately. remove omits via; rollback needs rollbackPlanId.",
            "enum": [
              "create",
              "update",
              "adopt",
              "repair",
              "disable",
              "remove",
              "rollback",
              "set"
            ],
            "type": "string"
          },
          "removeResources": {
            "description": "Owned resource IDs to retire. Refused while another route or resource still needs them.",
            "items": {
              "type": "string"
            },
            "maxItems": 32,
            "type": "array"
          },
          "resourceIds": {
            "description": "Existing or planned resource IDs this route depends on; shared dependencies prevent implicit removal.",
            "items": {
              "type": "string"
            },
            "maxItems": 32,
            "type": "array"
          },
          "resources": {
            "description": "Exact resource replacements in this plan. Native node identities must already be installed and inspected. Changes preserve unmentioned resources and peer permissions.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "dependencies": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "enabled": {
                  "type": "boolean"
                },
                "evidence": {
                  "type": "null"
                },
                "id": {
                  "description": "Stable resource ID, unique in this authority.",
                  "type": "string"
                },
                "owner": {
                  "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                  "format": "uuid",
                  "type": "string"
                },
                "persistent": {
                  "description": "Whether the node supervisor must survive client exit; startup scope is visible in the node installation.",
                  "type": "boolean"
                },
                "revision": {
                  "description": "Resource generation; increment when replacing a native reverse link.",
                  "minimum": 0,
                  "type": "integer"
                },
                "spec": {
                  "oneOf": [
                    {
                      "additionalProperties": false,
                      "properties": {
                        "device": {
                          "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                          "format": "uuid",
                          "type": "string"
                        },
                        "kind": {
                          "const": "node"
                        }
                      },
                      "required": [
                        "kind",
                        "device"
                      ],
                      "type": "object"
                    },
                    {
                      "additionalProperties": false,
                      "properties": {
                        "client": {
                          "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                          "format": "uuid",
                          "type": "string"
                        },
                        "gateway": {
                          "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                          "format": "uuid",
                          "type": "string"
                        },
                        "gateway_address": {
                          "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                          "type": "string"
                        },
                        "kind": {
                          "const": "reverse"
                        },
                        "link_id": {
                          "description": "Owned native reverse link ID on client.",
                          "type": "string"
                        },
                        "listen": {
                          "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                          "type": "string"
                        },
                        "target": {
                          "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                          "type": "string"
                        }
                      },
                      "required": [
                        "kind",
                        "client",
                        "gateway",
                        "gateway_address",
                        "listen",
                        "target",
                        "link_id"
                      ],
                      "type": "object"
                    },
                    {
                      "additionalProperties": false,
                      "properties": {
                        "kind": {
                          "const": "forward"
                        },
                        "link_id": {
                          "description": "Owned P2P forward ID on source.",
                          "type": "string"
                        },
                        "listen": {
                          "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                          "type": "string"
                        },
                        "peer": {
                          "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                          "format": "uuid",
                          "type": "string"
                        },
                        "source": {
                          "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                          "format": "uuid",
                          "type": "string"
                        },
                        "target": {
                          "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                          "type": "string"
                        }
                      },
                      "required": [
                        "kind",
                        "source",
                        "peer",
                        "listen",
                        "target",
                        "link_id"
                      ],
                      "type": "object"
                    },
                    {
                      "additionalProperties": false,
                      "properties": {
                        "backend": {
                          "enum": [
                            "systemd",
                            "windows-service",
                            "windows-task",
                            "process"
                          ]
                        },
                        "configuration_files": {
                          "description": "Absolute service script/config paths whose hashes and declared mapping must be verified, e.g. a scheduled task's PowerShell script. Content is never returned.",
                          "items": {
                            "type": "string"
                          },
                          "maxItems": 8,
                          "type": "array"
                        },
                        "executable": {
                          "description": "Executable recorded in the service or its configuration script.",
                          "type": "string"
                        },
                        "kind": {
                          "const": "external"
                        },
                        "listener": {
                          "additionalProperties": false,
                          "properties": {
                            "address": {
                              "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                              "type": "string"
                            },
                            "device": {
                              "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                              "format": "uuid",
                              "type": "string"
                            }
                          },
                          "required": [
                            "device",
                            "address"
                          ],
                          "type": "object"
                        },
                        "manager": {
                          "description": "Catalog SSH profile controlling this service; may differ from the target SSH server.",
                          "type": "string"
                        },
                        "mappings": {
                          "description": "Additional listeners owned by this same service. Their presence protects the shared service from stop/removal.",
                          "items": {
                            "additionalProperties": false,
                            "properties": {
                              "address": {
                                "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                                "type": "string"
                              },
                              "device": {
                                "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                                "format": "uuid",
                                "type": "string"
                              }
                            },
                            "required": [
                              "device",
                              "address"
                            ],
                            "type": "object"
                          },
                          "maxItems": 64,
                          "type": "array"
                        },
                        "service": {
                          "description": "Exact supervisor name; for backend=process, a descriptive observation label. Process observations require persistent=false and are read-only: no start, stop or repair; removal forgets only the record.",
                          "type": "string"
                        },
                        "target": {
                          "additionalProperties": false,
                          "properties": {
                            "address": {
                              "description": "Numeric IP:port interpreted on the named device; IPv6 must use [address]:port.",
                              "type": "string"
                            },
                            "device": {
                              "description": "Registered node device ID, from ssh_node_manage or ssh_route_inspect.",
                              "format": "uuid",
                              "type": "string"
                            }
                          },
                          "required": [
                            "device",
                            "address"
                          ],
                          "type": "object"
                        }
                      },
                      "required": [
                        "kind",
                        "manager",
                        "service",
                        "backend",
                        "executable",
                        "listener",
                        "target"
                      ],
                      "type": "object"
                    }
                  ]
                }
              },
              "required": [
                "id",
                "owner",
                "spec",
                "persistent",
                "enabled",
                "revision"
              ],
              "type": "object"
            },
            "maxItems": 32,
            "type": "array"
          },
          "rollbackPlanId": {
            "description": "rollback only: exact prior applied plan ID whose previous route will be restored.",
            "type": "string"
          },
          "server": {
            "description": "Target SSH profile from ssh_list_servers.",
            "type": "string"
          },
          "sourceDevice": {
            "description": "Stable ID of the initiating companion from ssh_node_manage @local. Required for native/P2P ingress. Omit only for an unscoped SSH override.",
            "format": "uuid",
            "type": "string"
          },
          "sourceInstance": {
            "description": "Named local instance, if used when installing sourceDevice.",
            "type": "string"
          },
          "via": {
            "description": "Entire ordered path from this device to target. [] means direct; omitted only for remove.",
            "items": {
              "type": "string"
            },
            "maxItems": 8,
            "type": "array"
          }
        },
        "required": [
          "operation",
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_server_manage",
      "description": "Add, update, remove or reload server entries in the authority: the center in center mode, otherwise this computer. Use after ssh_list_servers; no MCP restart is needed.\nInputs: action=add needs a new server name and config.host/config.user plus the intended authentication. update needs an existing server and only changed config fields; null clears nullable credentials. remove needs server. reload needs no server. install_helper installs the file helper on one server. installHelper defaults true for add, false otherwise.\nResult: A saved catalog entry is not proof of SSH login: run a read-only ssh_execute next. Helper failure can coexist with a saved entry; do not repeat add. key_path refers to a file on the catalog authority, not automatically this connecting computer.\nExample: {\"action\":\"reload\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "action": "reload"
          }
        ],
        "properties": {
          "action": {
            "description": "add: new server and connection config; update: existing server and changed fields; remove: server; reload: no server needed; install_helper: install on server without changing the catalog.",
            "enum": [
              "add",
              "update",
              "remove",
              "reload",
              "install_helper"
            ],
            "type": "string"
          },
          "config": {
            "additionalProperties": false,
            "description": "Changed catalog fields only. add requires host and user; update preserves omitted fields. Paths are interpreted on the authority (center in center mode, this computer in local mode). null clears nullable credential fields.",
            "properties": {
              "allow_patterns": {
                "description": "Allowed command patterns for restricted mode; an empty restricted allowlist rejects commands.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "audit_log": {
                "description": "Audit path owned by the configured runtime; omit to preserve existing audit configuration.",
                "type": "string"
              },
              "default_dir": {
                "description": "Default working directory on this server for command execution.",
                "type": "string"
              },
              "deny_patterns": {
                "description": "Denied command patterns; cannot grant OS permissions.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "description": {
                "description": "Human-readable catalog note; not a connection or route configuration.",
                "type": "string"
              },
              "host": {
                "description": "SSH target hostname/address in its configured route scope; with proxy_jump, loopback/private addresses belong behind that hop.",
                "type": "string"
              },
              "key_path": {
                "description": "Existing private-key file path on the authority. Center mode cannot read a connecting computer's local path. null clears the path.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "mode": {
                "description": "Command policy combined with the SSH account's real OS permissions. restricted also needs allow_patterns; it is not an OS sandbox.",
                "enum": [
                  "unrestricted",
                  "readonly",
                  "restricted"
                ],
                "type": "string"
              },
              "passphrase": {
                "description": "Passphrase for the configured private key; null clears it. Secret.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "password": {
                "description": "SSH login password. null clears it; do not print it or copy it into chat/logs.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "platform": {
                "description": "windows selects Windows command/path handling; omit for POSIX targets.",
                "enum": [
                  "linux",
                  "windows"
                ],
                "type": "string"
              },
              "port": {
                "default": 22,
                "description": "SSH TCP port on the target.",
                "maximum": 65535,
                "minimum": 1,
                "type": "integer"
              },
              "proxy_jump": {
                "description": "Configured SSH jump server name/path; preserve required hops. Use route inspect/plan/apply for managed topology changes.",
                "type": "string"
              },
              "ssh_key": {
                "description": "Legacy alias for key_path: an authority-local file PATH, never private-key content. Prefer key_path.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "sudo_password": {
                "description": "Optional remote sudo password; distinct from SSH login password. Secret; omit to preserve the existing value.",
                "type": "string"
              },
              "user": {
                "description": "Remote SSH login account, not this MCP client account.",
                "type": "string"
              }
            },
            "type": "object"
          },
          "description": {
            "description": "Compatibility alias for config.description.",
            "type": "string"
          },
          "host": {
            "description": "Compatibility top-level alias for config.host. Prefer config and do not mix both forms.",
            "type": "string"
          },
          "installHelper": {
            "description": "Attempt remote file-helper installation after add/update. Default true for add, false for update. A helper failure can occur after a successful catalog save; inspect both results.",
            "type": "boolean"
          },
          "key_path": {
            "description": "Compatibility alias for config.key_path; authority-local path, not automatically this computer.",
            "type": [
              "string",
              "null"
            ]
          },
          "mode": {
            "description": "Compatibility alias for config.mode.",
            "enum": [
              "unrestricted",
              "readonly",
              "restricted"
            ],
            "type": "string"
          },
          "password": {
            "description": "Compatibility alias for config.password; null clears it. Secret.",
            "type": [
              "string",
              "null"
            ]
          },
          "port": {
            "description": "Compatibility alias for config.port.",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "server": {
            "description": "Exact existing name for update/remove/install_helper, or the user's chosen new name for add. Omit for reload.",
            "type": "string"
          },
          "user": {
            "description": "Compatibility top-level alias for config.user.",
            "type": "string"
          }
        },
        "required": [
          "action"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_service_status",
      "description": "Inspect systemd/service status on a POSIX catalog server without starting or restarting it. For Windows use ssh_execute with Get-Service.\nInputs: server plus either service or a nonempty services list. If both are given, services wins. Names are OS service names, not SSH server names.\nResult: Read each service's output: active/enabled/MainPID when systemd is present. The wrapper's success only means inspection ran; output=inactive/failed is not a healthy service.\nExample: {\"server\":\"web-a\",\"service\":\"nginx\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "server": "web-a",
            "service": "nginx"
          }
        ],
        "properties": {
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "service": {
            "description": "One remote OS service name; required unless services is a nonempty list.",
            "type": "string"
          },
          "services": {
            "description": "Remote OS service names. A nonempty list takes precedence over service.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_session_close",
      "description": "Release one command context owned by this MCP client when its work is finished.\nInputs: sessionId from ssh_session_start/list. The special value all closes all of this client's contexts; use it only when that scope is intended.\nResult: success reports whether the context existed. This releases update blocking; it does not undo prior commands or terminate arbitrary remote processes.\nExample: {\"sessionId\":\"session_id_from_start\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "sessionId": "session_id_from_start"
          }
        ],
        "properties": {
          "session": {
            "description": "Compatibility alias for sessionId; use one of the two fields.",
            "type": "string"
          },
          "sessionId": {
            "description": "Exact session_id from start/list. all closes every context owned by this client, so use only for that intended scope.",
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_session_list",
      "description": "List command contexts owned by this MCP client. Use this to recover a returned session ID or identify contexts delaying an update.\nInputs: No arguments lists this client's contexts; server optionally filters their server names.\nResult: Returns sessions with IDs, server, fixed cwd and last command. Other clients' contexts are not included; no persistent shell process is implied.\nExample: {}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {}
        ],
        "properties": {
          "server": {
            "description": "Optional server-name filter for resources owned by this MCP client.",
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_session_send",
      "description": "Run a command using a context returned by ssh_session_start.\nInputs: sessionId is the exact returned session_id; command is required. timeout is milliseconds, default 120000, maximum 300000. The context supplies server and fixed cwd; it is not a persistent shell.\nResult: Read code/stdout/stderr. If the connection dies during a write, inspect its effect before retrying. Close the context with ssh_session_close after the work.\nExample: {\"sessionId\":\"session_id_from_start\",\"command\":\"pwd\",\"timeout\":10000}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "command": "pwd",
            "sessionId": "session_id_from_start",
            "timeout": 10000
          }
        ],
        "properties": {
          "command": {
            "description": "Command interpreted by the target server's shell. Use POSIX syntax for POSIX targets and PowerShell for platform=windows. The command can change remote state; scope it to the user's request.",
            "type": "string"
          },
          "session": {
            "description": "Compatibility alias for sessionId; prefer sessionId and do not supply both.",
            "type": "string"
          },
          "sessionId": {
            "description": "Required unless session alias is used: exact session_id from this client's ssh_session_start/list. Never invent an ID.",
            "type": "string"
          },
          "timeout": {
            "default": 120000,
            "description": "Timeout in milliseconds, not seconds. Use 10000 for 10 seconds or 30000 for 30 seconds. Default 120000 ms; capped at 300000 ms. 0 disables the command deadline and remote timeout wrapper; connection-establishment limits still apply. Prefer omission for the normal bounded default. A timeout does not prove a remote write had no effect.",
            "maximum": 300000,
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "command"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_session_start",
      "description": "Create a client-owned command context for repeated commands with one server and fixed cwd. This is not an interactive terminal or a persistent shell.\nInputs: server from ssh_list_servers; optional remote cwd and display name. For a single command, use ssh_execute directly.\nResult: Save session_id for ssh_session_send/close. Shell variables, cd and background processes do not persist between sends. An open context defers automatic updates; close it when finished.\nExample: {\"server\":\"web-a\",\"cwd\":\"/srv/app\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "cwd": "/srv/app",
            "server": "web-a"
          }
        ],
        "properties": {
          "cwd": {
            "description": "Fixed remote working directory used for every send. A cd command in one send does not change later sends.",
            "type": "string"
          },
          "name": {
            "description": "Optional label for this client's context.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_sync",
      "description": "Distribute a directory from one source to 1–7 targets, or reconcile a saved bidirectional sync set. Use upload/download for single files.\nInputs: Distribution: source and targets; each endpoint has id, server from ssh_list_servers (or @local), and absolute root on that device. Start with options.dryRun=true. Bidirectional: action=create with name/participants, then action=run with returned syncSet. inspect/list are read-only. timeout is inside options, in milliseconds (default 300000).\nResult: Read per-endpoint changes/conflicts/failures. delete and propagateDeletes default false; enabling either propagates deletion in its documented scope. Conflicts retain copies. Remote-to-remote uses receiver pull; relay through this computer needs allowRelay=true. Interrupted verified chunks may resume; do not infer success from partial progress.\nExample: {\"source\":{\"id\":\"src\",\"server\":\"@local\",\"root\":\"/home/me/site\"},\"targets\":[{\"id\":\"dst\",\"server\":\"web-a\",\"root\":\"/srv/site\"}],\"options\":{\"dryRun\":true}}",
      "inputSchema": {
        "additionalProperties": false,
        "examples": [
          {
            "options": {
              "dryRun": true
            },
            "source": {
              "id": "src",
              "root": "/home/me/site",
              "server": "@local"
            },
            "targets": [
              {
                "id": "dst",
                "root": "/srv/site",
                "server": "web-a"
              }
            ]
          }
        ],
        "oneOf": [
          {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "syncSet"
                  ]
                },
                {
                  "required": [
                    "name"
                  ]
                },
                {
                  "required": [
                    "participants"
                  ]
                },
                {
                  "required": [
                    "propagateDeletes"
                  ]
                },
                {
                  "required": [
                    "exclude"
                  ]
                }
              ]
            },
            "properties": {
              "action": {
                "const": "run"
              }
            },
            "required": [
              "source",
              "targets"
            ]
          },
          {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "source"
                  ]
                },
                {
                  "required": [
                    "targets"
                  ]
                },
                {
                  "required": [
                    "name"
                  ]
                },
                {
                  "required": [
                    "participants"
                  ]
                },
                {
                  "required": [
                    "propagateDeletes"
                  ]
                },
                {
                  "required": [
                    "exclude"
                  ]
                }
              ]
            },
            "properties": {
              "action": {
                "const": "run"
              }
            },
            "required": [
              "syncSet"
            ]
          },
          {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "source"
                  ]
                },
                {
                  "required": [
                    "targets"
                  ]
                },
                {
                  "required": [
                    "syncSet"
                  ]
                },
                {
                  "required": [
                    "options"
                  ]
                }
              ]
            },
            "properties": {
              "action": {
                "const": "create"
              }
            },
            "required": [
              "action",
              "name",
              "participants"
            ]
          },
          {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "source"
                  ]
                },
                {
                  "required": [
                    "targets"
                  ]
                },
                {
                  "required": [
                    "name"
                  ]
                },
                {
                  "required": [
                    "participants"
                  ]
                },
                {
                  "required": [
                    "propagateDeletes"
                  ]
                },
                {
                  "required": [
                    "exclude"
                  ]
                },
                {
                  "required": [
                    "options"
                  ]
                }
              ]
            },
            "properties": {
              "action": {
                "const": "inspect"
              }
            },
            "required": [
              "action",
              "syncSet"
            ]
          },
          {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "source"
                  ]
                },
                {
                  "required": [
                    "targets"
                  ]
                },
                {
                  "required": [
                    "syncSet"
                  ]
                },
                {
                  "required": [
                    "name"
                  ]
                },
                {
                  "required": [
                    "participants"
                  ]
                },
                {
                  "required": [
                    "propagateDeletes"
                  ]
                },
                {
                  "required": [
                    "exclude"
                  ]
                },
                {
                  "required": [
                    "options"
                  ]
                }
              ]
            },
            "properties": {
              "action": {
                "const": "list"
              }
            },
            "required": [
              "action"
            ]
          }
        ],
        "properties": {
          "action": {
            "default": "run",
            "description": "run distributes source contents to targets, or reconciles an existing syncSet; create saves a bidirectional set without copying files; list/inspect read durable state.",
            "enum": [
              "run",
              "create",
              "list",
              "inspect"
            ],
            "type": "string"
          },
          "exclude": {
            "description": "For create: relative /-separated globs; excluded subtrees are neither copied nor deleted.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "name": {
            "description": "Human-readable name for create.",
            "type": "string"
          },
          "options": {
            "additionalProperties": false,
            "description": "Run options only. Begin with dryRun=true; timeout is nested here in milliseconds. Deletions and controller relay require explicit flags.",
            "properties": {
              "allowRelay": {
                "default": false,
                "description": "Explicitly allow remote-to-remote file payloads through this companion when native pull is unavailable. The management center never receives payloads.",
                "type": "boolean"
              },
              "compression": {
                "default": "auto",
                "description": "Content-aware zstd compression; auto samples chunks, and expanded output is sent raw.",
                "enum": [
                  "auto",
                  "never",
                  "zstd"
                ],
                "type": "string"
              },
              "delete": {
                "default": false,
                "description": "Distribution only: delete destination files absent from source, after validating all manifests. Excluded files are protected.",
                "type": "boolean"
              },
              "dryRun": {
                "default": false,
                "description": "Read manifests and show up to 200 planned operations; creates no target directories, stages, grants or sync baseline. Requires the native helper already installed.",
                "type": "boolean"
              },
              "exclude": {
                "description": "Distribution only: relative globs such as .git or **/*.tmp; excluded trees are protected from deletion.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "timeout": {
                "default": 300000,
                "description": "Whole operation deadline in milliseconds: 10000 = 10 seconds. Validated partial chunks survive interruption for resume.",
                "maximum": 86400000,
                "minimum": 1000,
                "type": "integer"
              },
              "transport": {
                "default": "auto",
                "description": "auto prefers paired native file streams; ssh follows each configured SSH route; p2p requires native connectivity. Native apply uses the primary @local node (omit instance when installing/starting the controller), paired with each endpoint; remote endpoints must also be paired with one another for receiver-side pull.",
                "enum": [
                  "auto",
                  "ssh",
                  "p2p"
                ],
                "type": "string"
              }
            },
            "type": "object"
          },
          "participants": {
            "description": "For create: equal writable peers. Concurrent edits retain deterministic conflict copies; delete/edit retains the edit. Up to 4096 tracked files per set.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "deviceId": {
                  "description": "Registered stable device identity from ssh_node_manage. Persisted sets pin it to prevent using another companion's @local root.",
                  "type": "string"
                },
                "id": {
                  "description": "Stable participant label, 1-40 ASCII letters/digits/_/-. Unique within this operation or set.",
                  "type": "string"
                },
                "instance": {
                  "description": "Installed native node instance on this endpoint; omit for primary.",
                  "type": "string"
                },
                "root": {
                  "description": "Absolute directory on that device, e.g. /srv/data or C:\\Data. Synchronizes its contents, without adding the root folder name. No tilde, relative paths or remote: prefix.",
                  "type": "string"
                },
                "server": {
                  "description": "Exact ssh_list_servers profile, or @local for this companion computer. A path always belongs to this named device.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "server",
                "root"
              ],
              "type": "object"
            },
            "maxItems": 8,
            "minItems": 2,
            "type": "array"
          },
          "propagateDeletes": {
            "default": false,
            "description": "For create: true propagates causally observed deletion and retains versioned tombstones for offline peers; false restores local deletions from live copies. This set policy is immutable.",
            "type": "boolean"
          },
          "source": {
            "additionalProperties": false,
            "description": "Distribution source endpoint; required with targets and mutually exclusive with syncSet. root is an absolute directory on this named server or @local.",
            "properties": {
              "deviceId": {
                "description": "Registered stable device identity from ssh_node_manage. Persisted sets pin it to prevent using another companion's @local root.",
                "type": "string"
              },
              "id": {
                "description": "Stable participant label, 1-40 ASCII letters/digits/_/-. Unique within this operation or set.",
                "type": "string"
              },
              "instance": {
                "description": "Installed native node instance on this endpoint; omit for primary.",
                "type": "string"
              },
              "root": {
                "description": "Absolute directory on that device, e.g. /srv/data or C:\\Data. Synchronizes its contents, without adding the root folder name. No tilde, relative paths or remote: prefix.",
                "type": "string"
              },
              "server": {
                "description": "Exact ssh_list_servers profile, or @local for this companion computer. A path always belongs to this named device.",
                "type": "string"
              }
            },
            "required": [
              "id",
              "server",
              "root"
            ],
            "type": "object"
          },
          "syncSet": {
            "description": "UUID returned by create/list. Participants, exclusion and deletion policy come from that authority. Mutually exclusive with source/targets.",
            "type": "string"
          },
          "targets": {
            "description": "Distribution destinations, 1–7 distinct endpoint objects. Each root belongs to its named server; no implicit controller relay.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "deviceId": {
                  "description": "Registered stable device identity from ssh_node_manage. Persisted sets pin it to prevent using another companion's @local root.",
                  "type": "string"
                },
                "id": {
                  "description": "Stable participant label, 1-40 ASCII letters/digits/_/-. Unique within this operation or set.",
                  "type": "string"
                },
                "instance": {
                  "description": "Installed native node instance on this endpoint; omit for primary.",
                  "type": "string"
                },
                "root": {
                  "description": "Absolute directory on that device, e.g. /srv/data or C:\\Data. Synchronizes its contents, without adding the root folder name. No tilde, relative paths or remote: prefix.",
                  "type": "string"
                },
                "server": {
                  "description": "Exact ssh_list_servers profile, or @local for this companion computer. A path always belongs to this named device.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "server",
                "root"
              ],
              "type": "object"
            },
            "maxItems": 7,
            "minItems": 1,
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "name": "ssh_tail",
      "description": "Read the latest lines of one remote POSIX log file. Use ssh_read for line-numbered paging from a known location.\nInputs: server, file on that server; lines defaults 10, cap 10000. Optional grep is a remote grep pattern applied after tail. follow=true is unsupported; this tool does not create a live subscription.\nResult: Returns the bounded log text. Empty output may mean no matching lines; do not treat it as proof of a healthy service. Use a deliberately bounded ssh_execute for live-follow work.\nExample: {\"server\":\"web-a\",\"file\":\"/var/log/app.log\",\"lines\":50}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "file": "/var/log/app.log",
            "lines": 50,
            "server": "web-a"
          }
        ],
        "properties": {
          "file": {
            "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
            "type": "string"
          },
          "follow": {
            "const": false,
            "default": false,
            "description": "Only false is supported. For a live follow use a separately bounded ssh_execute.",
            "type": "boolean"
          },
          "grep": {
            "description": "Remote grep regular expression applied to the trailing lines; omit for all selected lines.",
            "type": "string"
          },
          "lines": {
            "default": 10,
            "description": "Number of trailing lines read before applying grep.",
            "maximum": 10000,
            "minimum": 0,
            "type": "integer"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "file"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_tunnel_close",
      "description": "Close temporary SSH tunnels owned by this MCP client. Closing a tunnel disconnects traffic using it.\nInputs: Prefer id from ssh_tunnel_create/list. tunnelId is an alias. Supplying server instead closes this client's tunnels for that server, so use it only when the broader scope is intended.\nResult: Returns close results. It does not remove persistent native routes, revoke peer grants or affect unrelated service configuration.\nExample: {\"id\":\"tunnel_id_from_create\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "id": "tunnel_id_from_create"
          }
        ],
        "properties": {
          "id": {
            "description": "Exact tunnel id from create/list; preferred for closing one tunnel.",
            "type": "string"
          },
          "server": {
            "description": "Use only without id/tunnelId: closes this client's tunnels for this server. Broader than closing one id.",
            "type": "string"
          },
          "tunnelId": {
            "description": "Compatibility alias for id. Supply only one ID field.",
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_tunnel_create",
      "description": "Open a temporary SSH TCP tunnel owned by this MCP client. Use native node/routes for persistent managed forwarding.\nInputs: server from ssh_list_servers, type and localPort. local: listener on this computer -> remoteHost:remotePort reached by server. remote: listener on server -> localHost:localPort reached by this computer. dynamic: SOCKS listener on this computer. Bind loopback unless broader exposure is intended. Port 0 allocates the listening side.\nResult: Use the returned id and actual address/remote_port. Keep this client attached and test the intended traffic; a listener alone does not prove destination reachability. Close with ssh_tunnel_close when done.\nExample: {\"server\":\"web-a\",\"type\":\"local\",\"localHost\":\"127.0.0.1\",\"localPort\":0,\"remoteHost\":\"127.0.0.1\",\"remotePort\":8080}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "localHost": "127.0.0.1",
            "localPort": 0,
            "remoteHost": "127.0.0.1",
            "remotePort": 8080,
            "server": "web-a",
            "type": "local"
          }
        ],
        "properties": {
          "localHost": {
            "description": "local/dynamic: listener bind on this computer. remote: destination host reached from this computer. Default 127.0.0.1; broader listener binds expose the tunnel.",
            "type": "string"
          },
          "localPort": {
            "description": "local/dynamic: listener port here, 0 allocates one. remote: destination port reached from this computer (use the actual destination port).",
            "maximum": 65535,
            "minimum": 0,
            "type": "integer"
          },
          "remoteHost": {
            "description": "local: destination reached from the SSH server. remote: listener bind on that server. Default 127.0.0.1. The remote SSH daemon must permit the requested forwarding/bind.",
            "type": "string"
          },
          "remotePort": {
            "description": "local: required destination port on the server side. remote: listener port on server, 0 allocates one and returns remote_port. Not used for dynamic.",
            "maximum": 65535,
            "minimum": 0,
            "type": "integer"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          },
          "type": {
            "description": "local listens here and connects from server; remote listens on server and connects from here; dynamic is a local SOCKS listener.",
            "enum": [
              "local",
              "remote",
              "dynamic"
            ],
            "type": "string"
          }
        },
        "required": [
          "server",
          "type",
          "localPort"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_tunnel_list",
      "description": "List temporary SSH tunnels owned by this MCP client; this does not list native persistent forwards or other clients' tunnels.\nInputs: No arguments, or optional server filter from ssh_list_servers.\nResult: Returns owned tunnel IDs (and server when filtered). Listener addresses come from the create receipt. Reuse the exact id to close one tunnel; inspect native resources with ssh_route_inspect.\nExample: {}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {}
        ],
        "properties": {
          "server": {
            "description": "Optional server-name filter for resources owned by this MCP client.",
            "type": "string"
          }
        },
        "required": [],
        "type": "object"
      }
    },
    {
      "name": "ssh_upload",
      "description": "Copy one existing file from this MCP computer to one catalog server. Use ssh_upload_batch for several files, ssh_write for text you are composing, ssh_sync for directories.\nInputs: server from ssh_list_servers; localPath is an existing file on this computer, remotePath is the complete destination filename on that server. Prefer absolute paths; do not swap the two endpoints.\nResult: Transfers through this computer's configured route and replaces the destination file. Check the result and destination/hash as required. After timeout, inspect before retrying; the transfer may have finished.\nExample: {\"server\":\"web-a\",\"localPath\":\"/home/me/app.conf\",\"remotePath\":\"/srv/app/app.conf\"}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "localPath": "/home/me/app.conf",
            "remotePath": "/srv/app/app.conf",
            "server": "web-a"
          }
        ],
        "properties": {
          "localPath": {
            "description": "Complete file path on the computer running this MCP companion. Prefer an absolute path; Windows example C:/Users/me/file.txt. Not a path on the center or target server.",
            "type": "string"
          },
          "remotePath": {
            "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "localPath",
          "remotePath"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_upload_batch",
      "description": "Copy 1–256 existing local files to one catalog server in one call. Use ssh_sync for a directory or multiple destination devices.\nInputs: server from ssh_list_servers. Each files item has localPath on this computer and a complete remotePath on that server. Destinations must be unique. concurrency defaults to 4, range 1–8.\nResult: Returns ordered per-file results. Replacement is atomic per file; a batch has no rollback. Check every item and retry only failed items after checking their destination state.\nExample: {\"server\":\"web-a\",\"files\":[{\"localPath\":\"/home/me/a.txt\",\"remotePath\":\"/srv/app/a.txt\"},{\"localPath\":\"/home/me/b.txt\",\"remotePath\":\"/srv/app/b.txt\"}]}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "files": [
              {
                "localPath": "/home/me/a.txt",
                "remotePath": "/srv/app/a.txt"
              },
              {
                "localPath": "/home/me/b.txt",
                "remotePath": "/srv/app/b.txt"
              }
            ],
            "server": "web-a"
          }
        ],
        "properties": {
          "concurrency": {
            "default": 4,
            "description": "Maximum simultaneous uploads to this one server; 1 is serial, 4 is the default.",
            "maximum": 8,
            "minimum": 1,
            "type": "integer"
          },
          "files": {
            "description": "Existing local source files and unique remote destination filenames. Atomic per file; the entire batch is not rolled back.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "localPath": {
                  "description": "Complete file path on the computer running this MCP companion. Prefer an absolute path; Windows example C:/Users/me/file.txt. Not a path on the center or target server.",
                  "type": "string"
                },
                "remotePath": {
                  "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
                  "type": "string"
                }
              },
              "required": [
                "localPath",
                "remotePath"
              ],
              "type": "object"
            },
            "maxItems": 256,
            "minItems": 1,
            "type": "array"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "files"
        ],
        "type": "object"
      }
    },
    {
      "name": "ssh_write",
      "description": "Create or replace a whole remote text file from supplied content. Use ssh_edit for a small change or ssh_upload for an existing local file.\nInputs: server from ssh_list_servers, remotePath is the complete remote filename, content is the full replacement text. createDirs controls creation of missing parent directories.\nResult: Existing content is replaced, not appended. Check the write result and validate the consuming application separately; writing a config does not reload it.\nExample: {\"server\":\"web-a\",\"remotePath\":\"/srv/app/note.txt\",\"content\":\"hello\\n\",\"createDirs\":true}",
      "inputSchema": {
        "additionalProperties": true,
        "examples": [
          {
            "content": "hello\n",
            "createDirs": true,
            "remotePath": "/srv/app/note.txt",
            "server": "web-a"
          }
        ],
        "properties": {
          "content": {
            "description": "Entire new text content; overwrites the existing file rather than appending. Empty string intentionally empties it.",
            "type": "string"
          },
          "createDirs": {
            "default": true,
            "description": "Create missing parent directories on the target before writing. False requires them to exist.",
            "type": "boolean"
          },
          "remotePath": {
            "description": "Complete path on the selected remote server, not this MCP computer. Prefer an absolute path.",
            "type": "string"
          },
          "server": {
            "description": "Exact server name returned by ssh_list_servers. Do not pass a host/IP unless it is the registered name.",
            "type": "string"
          }
        },
        "required": [
          "server",
          "remotePath",
          "content"
        ],
        "type": "object"
      }
    }
  ]
}
