MCP server for LibreNMS management exposing tools that interact with the LibreNMS API, supporting both read and write operations if not in read-only mode.
Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
LibreNMS MCP server demonstrates solid definition quality with consistent tool naming, comprehensive parameter schemas, and descriptions across all 20 tools. All tools follow verb_noun conventions (alerts_get, device_add, bill_graph, etc.). Parameter descriptions are generally present and specific. However, several tools lack output schema documentation, some descriptions could be more detailed regarding when to use the tool vs alternatives, and error handling guidance is absent. The server correctly uses type annotations in parameters (int, str, bool, dict) and includes pagination support (limit/offset) where appropriate. Tool composition is sound, each tool has a single responsibility. Descriptions average 120-180 chars, which is in the acceptable range but could be richer with context on state-mutating operations and recovery guidance.
Output schemas not documented in source. Tools lack explicit return type specifications that would help LLMs understand what fields to expect and enable downstream tool chaining. No visible field definitions for alert objects, bill objects, device objects, or port objects.
Define explicit JSON Schema output types for all tools. For alerts_get, return {"alerts": [{"id": int, "status": string, "severity": string, "timestamp": string, ...}], "total": int, "limit": int, "offset": int}. Include all fields the LLM needs for downstream calls (IDs, references, state).
Convert free-form string parameters (graph_type, state, severity, order) to enum definitions in the schema. Replace description text 'Valid values: bits, monthly, hour, day' with a JSON Schema enum constraint: {"type": "string", "enum": ["bits", "monthly", "hour", "day"]}.
Enhance descriptions for state-mutating tools with explicit recovery guidance. For device_delete: 'Permanently removes a device from LibreNMS. This action cannot be undone. Verify the hostname before calling. On error, check if the device exists with device_get(hostname).'
Document payload schemas for alert_rule_add and device_add. Define required vs optional fields explicitly in the schema, not in prose. For device_add, clarify which parameters are mutually exclusive (SNMP v1/v2c vs v3 auth combinations).
Add context to tool descriptions distinguishing similar tools. For alerts_get vs alert_get_by_id: 'Use alerts_get with filters to discover alerts matching criteria (state, severity, rule). Use alert_get_by_id only if you already know the alert ID.' This guides LLM selection.
Document the response structure for each tool (e.g., 'Returns a list of bill objects, each containing: bill_id, bill_name, bill_amount, bill_date, bill_type. Includes pagination metadata: total, limit, offset.').
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Score history
Overall score trend
↑ 14 points across a rubric change (v1 → v2)
73/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-21
B
73
<=2025-11-25
v2
2026-03-09
D
59
-
v1
bill_getread onlyauthsource verified83/100
Get a specific bill from LibreNMS by ID.
bill_graphread onlyauthsource verified79/100
Render a bill graph as an image. For the underlying numbers rather than a picture, use bill_graph_data.
Payload parameters (alert_rule_add, device_add) accept generic dict types with inline documentation of optional/required fields. No JSON Schema object definition is visible for the nested payload structure, making validation and discovery impossible. LLMs cannot infer required fields or valid nested structures.
Tool descriptions lack context on when to use one tool vs a similar alternative. For example, alerts_get vs alert_get_by_id: when should an LLM choose list with filters vs direct ID lookup? No explicit guidance on filter combinations or expected query performance.
devices_list query parameter description lists valid type values inline but does not explain mutual exclusivity or dependency relationships. For example, if 'type' is 'os', what format must 'query' take? No validation constraints visible.
Graph tools (bill_graph, bill_history_graph, bill_graph_data) accept free-form 'graph_type' string parameter. Description lists valid values as 'bits, monthly, hour, or day' but does not enforce enum constraint. LLMs may hallucinate invalid graph types like 'daily' or 'weekly'.
Add error handling guidance to all tools. Example for device_delete: 'Error: Device not found, verify hostname with devices_list() or device_get(). Error: Permission denied, check agent scope permissions. Retryable: network timeout (can retry once).'
Clarify parameter relationships in devices_list. Document that query['type'] determines valid query['query'] formats. Example: 'If type=os, query must be a valid OS string (e.g., "Linux", "ios"). If type=location, query must match a location name.'
For bill_graph and similar tools, add descriptions clarifying the difference between rendered images and data. Example: 'bill_graph returns a PNG image of the billing graph. If you need the raw data (usage, rates, totals) for calculations, use bill_graph_data instead.'
Add dependency hints to discovery tools. For alerts_get: 'If you only have a device hostname, call device_get(hostname) first to find the device ID, then filter alerts by severity or state. Use alert_rules_list() to find applicable rule IDs for filtering.'
Document any defaults or fallbacks in parameter descriptions. Example: 'order defaults to timestamp descending. Valid format: "field_name ASC|DESC" (e.g., "created_at DESC", "severity ASC").'
Ensure all state-mutating tools include idempotency guidance. For alert_acknowledge: 'Safe to call multiple times with the same alert_id and note, acknowledging an already-acknowledged alert is a no-op. Timestamp of first acknowledgment is preserved.'