Files
FabledSteward/tests/plugins/host_agent/test_mcp_tools.py
T
bvandeusenandClaude Opus 5.5 21338dbcd9
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 37s
CI / unit (push) Successful in 58s
CI / publish (push) Successful in 54s
feat(mcp): docker and host-agent tools; TLS and crash-loop cutoffs in Settings
MCP-5 of milestone 461 "MCP server: Steward as an LLM-inspectable,
LLM-operable hub". Contributed through each plugin's register_mcp_tools
hook, so they exist only while the plugin is enabled.

docker (viewer, read-only):
- list_containers: filter by host, status, compose project, or problem
  (restarting, crash_looping, unhealthy, oom_killed, exited_nonzero);
  problems sort first and each row names what is wrong.
- get_container: state, CPU/memory history across the raw/hourly seam,
  lifecycle events. A unique part of a swarm task name is enough.
- list_swarm_services: replicas per node (agent-less placements as ghosts)
  and the swarm's nodes.
- search_container_logs: text (% and _ literal), stream, range, context
  lines, paging by a full-precision `before` cursor; over-long lines keep
  both ends and say how much of the middle was cut.
- get_docker_disk_usage: bytes per host, reclaimable first.
- mcp_overview: failing containers and under-replicated swarm services
  join get_overview.

host_agent: list_agents (reporting / stale / pending, version, OS), and an
overview finding for agents registered over 30 minutes ago that never
checked in.

Settings > Thresholds gains the TLS-expiry warn/crit days (were 14/3 in
code) and the crash-loop deaths-per-hour count (3), which get_overview
and the docker tools now read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 07:47:02 -04:00

23 lines
832 B
Python

"""The host_agent plugin's MCP tools."""
from datetime import datetime, timedelta, timezone
from types import SimpleNamespace as NS
from unittest.mock import MagicMock
import plugins.host_agent as agent_plugin
from plugins.host_agent.mcp_tools import agent_state
NOW = datetime(2026, 10, 6, 12, 0, tzinfo=timezone.utc)
def test_agent_state():
assert agent_state(NS(last_seen_at=None), NOW, 180) == "pending"
assert agent_state(NS(last_seen_at=NOW - timedelta(seconds=60)), NOW, 180) == "reporting"
assert agent_state(NS(last_seen_at=NOW - timedelta(minutes=10)), NOW, 180) == "stale"
def test_plugin_exposes_the_mcp_hooks():
reg = MagicMock()
agent_plugin.register_mcp_tools(reg)
assert [c.args[0].__name__ for c in reg.call_args_list] == ["list_agents"]
assert callable(agent_plugin.mcp_overview)