v0.1.1 - Content, actions, resources, and an opt-in write surface
Adds the content, computer and action tool surface, MCP resources and prompts, and a small opt-in write surface. The read-only default is unchanged: nothing that mutates a root server is registered unless it is explicitly enabled.
New read tools
Computers — get_computer, find_computers
Content — get_content, find_content, applicable_fixlets
Actions — list_actions, get_action, get_action_status
Operators and roles — list_operators, list_roles
XML — validate_bes_xml
Action support is new code rather than a besapi wrapper: besapi has no action support at all. It is written in the upstreamable shape (conn first, no fastmcp imports, besapi-style exceptions), with paths confirmed against a live BigFix 11 root server via /api/help/action.
Resources and prompts
Three MCP resources the model can pull on demand — bigfix://relevance/session-cookbook, bigfix://relevance/client-cookbook, and bigfix://guide/tools — and four prompts: diagnose_computer, patch_status, find_stale_agents, troubleshoot_relevance.
Opt-in write surface
Registered only when BIGFIX_ALLOW_WRITES is set. Three tools: stop_action, set_dashboard_variable, import_bes_content. Each defaults to dry_run=true and emits a structured audit line to stderr on every attempt.
The scope rule is that only operations whose blast radius is reversible or nil qualify. Creating content is not the same as running it — an imported fixlet does nothing until somebody takes an action on it in the console, which is why import is included and deploying an action is not.
Deliberately absent, and not to be added without their own design round: POST /api/actions (arbitrary code as root, fleet-wide), any DELETE, operator creation, uploads, and site creation.
XML handling
New besxml module, used instead of besapi's RESTResult.besdict, which has two defects confirmed against a live BigFix 11 root server: it crashes on repeated sibling elements holding text (elem2dict calls .copy() on a str), and it discards attributes. Since GET /api/computer/{id} returns repeated <Property Name="...">value</Property> elements, besdict raises AttributeError on any real computer record — and for a computer record the dropped Name attribute is what identifies which property each value belongs to.
Bounded responses
Every tool that can return an unbounded amount of data now routes its payload through a single bounding layer, so a large fleet produces a truncated answer that says it was truncated rather than megabytes of JSON in the client's context window. Nothing rewrites the caller's query to bound it server-side: silently answering a different question than the one asked is worse than returning a big answer and admitting it was cut.
New documentation
docs/security-review.md— threat model and findings for the tool surface.docs/rest-endpoints.md— live-verified REST paths, site-path rules, and relevance findings, including the operators that don't exist.
Development
Adds a pre-commit configuration along with .editorconfig, .yamllint.yaml, and linter configs.
190 tests, running entirely offline against a scripted fake BESConnection, including in-memory end-to-end MCP calls via fastmcp.Client.