MCP server for Tailscale network monitoring and security — devices, ACLs, DNS, keys, users, audit logs
Server has 23 tools with consistent naming (verb_noun pattern: ts_*) and descriptions present for all. However, descriptions are often terse (20-80 chars), parameter descriptions lack detail on constraints/formats, and output schemas are not documented in the tool definitions. Input schemas are visible and properly typed. Error handling exists but lacks recovery guidance. Security is reasonable (no secrets in params, write-gating via env var), but tool composition could be tighter, some tools like ts_approve_routes and ts_set_routes have overlapping semantics that could confuse LLMs.
Get the current ACL policy file.
Approve subnet routes on a device (additive: merges with existing approved routes).
Get audit logs for the tailnet, optionally filtered by action or actor.
Authorize a device (set authorized=true).
Create a new auth key with optional tags, expiry, and reusability.
Create a new webhook for tailnet events.
Deauthorize a device (set authorized=false).
Output schemas not documented in tool definitions. LLMs cannot plan downstream calls or extract required fields without knowing what each tool returns. Formatters exist (format_device_list, format_acl, etc.) but their output structure is not visible in the tool registration.
Parameter descriptions lack constraint details. E.g., 'scope' in ts_devices says 'Optional scope filter: infrastructure, personal, or home' but does not state these are the ONLY valid values (should be enum). 'limit' in ts_audit_logs lacks min/max bounds. LLMs cannot validate inputs without explicit constraints.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | <=2025-11-25 | v2 |
Delete a device from the tailnet.
Delete a webhook.
Get detailed information about a single device by nodeId.
Get advertised and enabled subnet routes for a device.
List all devices in the tailnet, optionally filtered by scope (infrastructure/personal/home).
Get full DNS configuration: nameservers, search paths, MagicDNS status, split DNS.
Force key expiry on a device (disconnects it immediately).
Expire an auth key immediately.
Tailnet health check: device/user counts, online status, key expiry, updates, settings flags.
List all auth keys in the tailnet, optionally filtered by scope.
Apply a full ACL policy file. Supports optimistic concurrency via ETag.
Set the enabled subnet routes on a device (REPLACE semantics: becomes exactly the list provided).
Set ACL tags on a device.
List all users in the tailnet.
Validate an ACL policy file for syntax and semantic errors.
List all webhooks configured for the tailnet.
Overlapping tool semantics: ts_approve_routes (additive merge) vs ts_set_routes (replace). LLMs may conflate these and call the wrong one. Descriptions should explicitly state 'ADDITIVE: merges with existing' vs 'REPLACE: becomes exactly the list provided', currently only visible in descriptions, not in names or prominent warnings.
Error handling lacks recovery guidance. TailscaleError is caught and formatted as 'Error: {e}', but LLMs receive no actionable next steps (e.g., 'Device not found. Try ts_devices() to list available devices'). Errors should categorize as retryable/user-fixable/fatal.
No pagination support visible in list tools. ts_devices, ts_keys, ts_users, ts_webhooks, ts_audit_logs accept no limit/offset/cursor parameters. Large tailnets could return thousands of items, exhausting context. Baseline: list tools should support limit (default 20-50) and pagination.