The server demonstrates good fundamentals: all 9 tools have descriptive names following verb_noun patterns (access_get_list, clients_search, blocked_services_update), clear descriptions (range 50-180 chars), and complete input schemas with type declarations and parameter descriptions. Tool annotations (readOnlyHint) are present and properly configured. However, several patterns are incompletely implemented: output schemas are not documented anywhere in the codebase, error handling lacks recovery guidance (errors are simply sanitized and returned as text), and there are no examples of pagination support for list operations. The blocked_services_update tool has a complex nested schema with per-day scheduling that could benefit from clearer constraints. Most critically, there is no visible documentation of what these tools return, LLMs cannot plan downstream calls or extract structured data from unspecified output.
Retrieve access control lists: allowed clients, disallowed clients, and blocked hosts
Set access control lists for allowed clients, disallowed clients, and blocked hosts
Retrieve currently blocked services list and schedule
List all available services that can be blocked, organized by group
Update the list of blocked services and optional schedule
Add a new persistent client with per-client settings
Output schemas are completely undocumented. The codebase defines tool input schemas but provides no specification of what these tools return to the LLM. This violates the pattern:tool-description and pattern:response-shaper requirements. Without documented outputs, LLMs cannot plan multi-step workflows or extract the data they need for follow-up calls.
Error handling lacks recovery guidance. In src/core/tools.ts, errors are caught and sanitized but never categorized or accompanied by actionable next steps. An LLM receiving 'Invalid client ID' has no idea whether to retry, call search_clients(), or ask the user. This violates pattern:recovery-guide and pattern:error-classification.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 68 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 48 | - | v1 |
Retrieve all configured and auto-detected clients with their settings
Search for specific clients by their IDs (IP, MAC, CIDR, or client ID)
Update an existing persistent client by name
No pagination support visible for list operations. clients_get and blocked_services_get_all likely return all results with no limit or offset parameters. If these return hundreds of items, context windows will be exhausted. Pattern requires pagination with limit/offset and total count for any list operation.
blocked_services_update has a deeply nested schedule schema (sun/mon/tue/wed/thu/fri/sat each with start/end properties). The description mentions this is 'by day of week' but does not clarify: (1) What timezone interpretation is used? (2) Are start/end times in milliseconds from midnight (unusual, typically seconds)? (3) What happens if start > end? (4) Can schedule be omitted (null) to disable scheduling? These ambiguities invite LLM misuse.
clients_add and clients_update accept a 'tags' array but no description of what tags are valid, what they do, or how many are allowed. An LLM will hallucinate arbitrary tags. Either restrict tags via enum or document format constraints (e.g., 'lowercase alphanumeric, max 50 chars, max 5 tags per client').
No idempotency guidance. Tools like clients_add and access_set_list have side effects but no documentation of whether they are idempotent or what happens if called twice with the same input. Agents retry on failure, non-idempotent tools risk duplicates or data loss.
clients_search expects an 'ids' array but the description ('Client identifiers to search for') does not clarify the format. Are these IP addresses, MAC addresses, CIDR ranges, or internal client IDs? The tool name search_* suggests lookup but the parameter name 'ids' is confusing. Should be 'client_ids' or parameter description should list valid formats explicitly.