We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sandraschi/tailscale-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
MCP Prompts and Resources for Tailscale MCP Server.
This module provides reusable prompts and resources for common Tailscale operations.
Prompts are pre-configured templates that help users interact with the server.
Resources are read-only data sources accessible via URIs.
"""
from typing import Any
def register_prompts(mcp: Any) -> list[Any]:
"""Register all prompts with the MCP server.
Args:
mcp: FastMCP server instance
Returns:
List of prompt function references to keep them alive
"""
@mcp.prompt()
def list_devices_prompt(
online_only: bool = False, filter_tags: list[str] | None = None
) -> list[dict[str, Any]]:
"""List all devices in the Tailscale tailnet.
This prompt helps you list devices with optional filtering by online status and tags.
Args:
online_only: If True, only show devices that are currently online
filter_tags: Optional list of tags to filter devices (devices must have ALL tags)
Returns:
List of message dictionaries with device information
"""
tags_str = f" with tags {', '.join(filter_tags)}" if filter_tags else ""
online_str = "online " if online_only else ""
query = f"List all {online_str}devices{tags_str} in the tailnet"
return [
{
"role": "user",
"content": query,
}
]
@mcp.prompt()
def get_device_details_prompt(device_id: str) -> list[dict[str, Any]]:
"""Get detailed information about a specific device.
This prompt retrieves comprehensive information about a device including
its configuration, status, tags, and network settings.
Args:
device_id: The device ID or hostname to query
Returns:
List of message dictionaries requesting device details
"""
return [
{
"role": "user",
"content": f"Show me detailed information for device {device_id}",
}
]
@mcp.prompt()
def authorize_device_prompt(
device_id: str, reason: str | None = None
) -> list[dict[str, Any]]:
"""Authorize a device to join the Tailscale tailnet.
This prompt helps you authorize a pending device request.
Args:
device_id: The device ID to authorize
reason: Optional reason for authorization (for audit logging)
Returns:
List of message dictionaries requesting device authorization
"""
reason_str = f" (reason: {reason})" if reason else ""
return [
{
"role": "user",
"content": f"Authorize device {device_id}{reason_str}",
}
]
@mcp.prompt()
def check_network_status_prompt() -> list[dict[str, Any]]:
"""Check the overall network status and health.
This prompt retrieves comprehensive network status including device connectivity,
latency, and overall health metrics.
Returns:
List of message dictionaries requesting network status
"""
return [
{
"role": "user",
"content": "Show me the current network status and health",
}
]
@mcp.prompt()
def create_security_report_prompt() -> list[dict[str, Any]]:
"""Generate a comprehensive security report.
This prompt creates a detailed security report with vulnerabilities,
compliance status, and recommendations.
Returns:
List of message dictionaries requesting security report
"""
return [
{
"role": "user",
"content": "Generate a comprehensive security report for the tailnet",
}
]
@mcp.prompt()
def backup_configuration_prompt(
backup_name: str | None = None,
) -> list[dict[str, Any]]:
"""Create a backup of the Tailscale configuration.
This prompt helps you create a backup of device configurations, policies,
and user accounts.
Args:
backup_name: Optional name for the backup (defaults to timestamp-based name)
Returns:
List of message dictionaries requesting configuration backup
"""
name_str = f" named {backup_name}" if backup_name else ""
return [
{
"role": "user",
"content": f"Create a backup of the Tailscale configuration{name_str}",
}
]
# Return references to prevent garbage collection
# The decorators register the functions, but we need to keep references
# so they don't get garbage collected
return [
list_devices_prompt,
get_device_details_prompt,
authorize_device_prompt,
check_network_status_prompt,
create_security_report_prompt,
backup_configuration_prompt,
]
def register_resources(mcp: Any, device_manager: Any, monitor: Any) -> list[Any]:
"""Register all resources with the MCP server.
Args:
mcp: FastMCP server instance
device_manager: Device manager instance
monitor: Monitor instance
Returns:
List of resource function references to keep them alive
"""
@mcp.resource("tailscale://devices")
async def devices_resource() -> str:
"""List all devices in the tailnet.
This resource provides a read-only view of all devices in the tailnet.
Access via: tailscale://devices
Returns:
JSON string with device list
"""
import json
devices = await device_manager.list_devices()
return json.dumps(
{
"devices": devices,
"count": len(devices),
"resource": "tailscale://devices",
},
indent=2,
)
@mcp.resource("tailscale://devices/{device_id}")
async def device_resource(device_id: str) -> str:
"""Get details for a specific device.
This resource provides detailed information about a specific device.
Access via: tailscale://devices/{device_id}
Args:
device_id: The device ID or hostname
Returns:
JSON string with device details
"""
import json
device = await device_manager.get_device(device_id)
return json.dumps(
{
"device": device,
"device_id": device_id,
"resource": f"tailscale://devices/{device_id}",
},
indent=2,
)
@mcp.resource("tailscale://network/status")
async def network_status_resource() -> str:
"""Get current network status.
This resource provides real-time network status including connectivity,
latency, and health metrics.
Access via: tailscale://network/status
Returns:
JSON string with network status
"""
import json
status = await monitor.get_network_status()
return json.dumps(
{
"status": status,
"resource": "tailscale://network/status",
},
indent=2,
)
@mcp.resource("tailscale://network/topology")
async def network_topology_resource() -> str:
"""Get network topology map.
This resource provides a visual representation of the network topology
showing device connections and relationships.
Access via: tailscale://network/topology
Returns:
JSON string with topology data
"""
import json
topology = await monitor.generate_network_topology()
return json.dumps(
{
"topology": topology,
"resource": "tailscale://network/topology",
},
indent=2,
)
@mcp.resource("tailscale://security/report")
async def security_report_resource() -> str:
"""Get security report.
This resource provides a comprehensive security report with vulnerabilities,
compliance status, and recommendations.
Access via: tailscale://security/report
Returns:
JSON string with security report
"""
import json
report = await device_manager.generate_security_report()
return json.dumps(
{
"report": report,
"resource": "tailscale://security/report",
},
indent=2,
)
@mcp.resource("tailscale://monitoring/metrics")
async def metrics_resource() -> str:
"""Get Prometheus-formatted metrics.
This resource provides metrics in Prometheus exposition format.
Access via: tailscale://monitoring/metrics
Returns:
Prometheus-formatted metrics string
"""
metrics = await monitor.get_prometheus_metrics()
return metrics
@mcp.resource("tailscale://monitoring/health")
async def health_resource() -> str:
"""Get network health report.
This resource provides a comprehensive health report with status,
issues, and recommendations.
Access via: tailscale://monitoring/health
Returns:
JSON string with health report
"""
import json
health = await monitor.get_network_health_report()
return json.dumps(
{
"health": health,
"resource": "tailscale://monitoring/health",
},
indent=2,
)
# Return references to prevent garbage collection
# The decorators register the functions, but we need to keep references
# so they don't get garbage collected
return [
devices_resource,
device_resource,
network_status_resource,
network_topology_resource,
security_report_resource,
metrics_resource,
health_resource,
]
# Legacy class-based approach (kept for backwards compatibility)
class TailscalePrompts:
"""Prompts for common Tailscale operations."""
def __init__(self, mcp: Any):
"""Initialize prompts with FastMCP instance.
Args:
mcp: FastMCP server instance
"""
self.mcp = mcp
self._register_prompts()
def _register_prompts(self) -> None:
"""Register all prompts with the MCP server."""
# Store references to keep functions alive
self._prompt_functions = []
@self.mcp.prompt()
def list_devices_prompt(
online_only: bool = False, filter_tags: list[str] | None = None
) -> list[dict[str, Any]]:
"""List all devices in the Tailscale tailnet.
This prompt helps you list devices with optional filtering by online status and tags.
Args:
online_only: If True, only show devices that are currently online
filter_tags: Optional list of tags to filter devices (devices must have ALL tags)
Returns:
List of message dictionaries with device information
"""
tags_str = f" with tags {', '.join(filter_tags)}" if filter_tags else ""
online_str = "online " if online_only else ""
query = f"List all {online_str}devices{tags_str} in the tailnet"
return [
{
"role": "user",
"content": query,
}
]
@self.mcp.prompt()
def get_device_details_prompt(device_id: str) -> list[dict[str, Any]]:
"""Get detailed information about a specific device.
This prompt retrieves comprehensive information about a device including
its configuration, status, tags, and network settings.
Args:
device_id: The device ID or hostname to query
Returns:
List of message dictionaries requesting device details
"""
return [
{
"role": "user",
"content": f"Show me detailed information for device {device_id}",
}
]
@self.mcp.prompt()
def authorize_device_prompt(
device_id: str, reason: str | None = None
) -> list[dict[str, Any]]:
"""Authorize a device to join the Tailscale tailnet.
This prompt helps you authorize a pending device request.
Args:
device_id: The device ID to authorize
reason: Optional reason for authorization (for audit logging)
Returns:
List of message dictionaries requesting device authorization
"""
reason_str = f" (reason: {reason})" if reason else ""
return [
{
"role": "user",
"content": f"Authorize device {device_id}{reason_str}",
}
]
@self.mcp.prompt()
def check_network_status_prompt() -> list[dict[str, Any]]:
"""Check the overall network status and health.
This prompt retrieves comprehensive network status including device connectivity,
latency, and overall health metrics.
Returns:
List of message dictionaries requesting network status
"""
return [
{
"role": "user",
"content": "Show me the current network status and health",
}
]
@self.mcp.prompt()
def create_security_report_prompt() -> list[dict[str, Any]]:
"""Generate a comprehensive security report.
This prompt creates a detailed security report with vulnerabilities,
compliance status, and recommendations.
Returns:
List of message dictionaries requesting security report
"""
return [
{
"role": "user",
"content": "Generate a comprehensive security report for the tailnet",
}
]
@self.mcp.prompt()
def backup_configuration_prompt(
backup_name: str | None = None,
) -> list[dict[str, Any]]:
"""Create a backup of the Tailscale configuration.
This prompt helps you create a backup of device configurations, policies,
and user accounts.
Args:
backup_name: Optional name for the backup (defaults to timestamp-based name)
Returns:
List of message dictionaries requesting configuration backup
"""
name_str = f" named {backup_name}" if backup_name else ""
return [
{
"role": "user",
"content": f"Create a backup of the Tailscale configuration{name_str}",
}
]
# Store function references to prevent garbage collection
self._prompt_functions = [
list_devices_prompt,
get_device_details_prompt,
authorize_device_prompt,
check_network_status_prompt,
create_security_report_prompt,
backup_configuration_prompt,
]
class TailscaleResources:
"""Resources for Tailscale data access via URIs."""
def __init__(self, mcp: Any, device_manager: Any, monitor: Any):
"""Initialize resources with FastMCP instance and managers.
Args:
mcp: FastMCP server instance
device_manager: Device manager instance
monitor: Monitor instance
"""
self.mcp = mcp
self.device_manager = device_manager
self.monitor = monitor
self._register_resources()
def _register_resources(self) -> None:
"""Register all resources with the MCP server."""
# Capture managers in local variables for closures
device_manager = self.device_manager
monitor = self.monitor
# Store references to keep functions alive
self._resource_functions = []
@self.mcp.resource("tailscale://devices")
async def devices_resource() -> str:
"""List all devices in the tailnet.
This resource provides a read-only view of all devices in the tailnet.
Access via: tailscale://devices
Returns:
JSON string with device list
"""
import json
devices = await device_manager.list_devices()
return json.dumps(
{
"devices": devices,
"count": len(devices),
"resource": "tailscale://devices",
},
indent=2,
)
@self.mcp.resource("tailscale://devices/{device_id}")
async def device_resource(device_id: str) -> str:
"""Get details for a specific device.
This resource provides detailed information about a specific device.
Access via: tailscale://devices/{device_id}
Args:
device_id: The device ID or hostname
Returns:
JSON string with device details
"""
import json
device = await device_manager.get_device(device_id)
return json.dumps(
{
"device": device,
"device_id": device_id,
"resource": f"tailscale://devices/{device_id}",
},
indent=2,
)
@self.mcp.resource("tailscale://network/status")
async def network_status_resource() -> str:
"""Get current network status.
This resource provides real-time network status including connectivity,
latency, and health metrics.
Access via: tailscale://network/status
Returns:
JSON string with network status
"""
import json
status = await monitor.get_network_status()
return json.dumps(
{
"status": status,
"resource": "tailscale://network/status",
},
indent=2,
)
@self.mcp.resource("tailscale://network/topology")
async def network_topology_resource() -> str:
"""Get network topology map.
This resource provides a visual representation of the network topology
showing device connections and relationships.
Access via: tailscale://network/topology
Returns:
JSON string with topology data
"""
import json
topology = await monitor.generate_network_topology()
return json.dumps(
{
"topology": topology,
"resource": "tailscale://network/topology",
},
indent=2,
)
@self.mcp.resource("tailscale://security/report")
async def security_report_resource() -> str:
"""Get security report.
This resource provides a comprehensive security report with vulnerabilities,
compliance status, and recommendations.
Access via: tailscale://security/report
Returns:
JSON string with security report
"""
import json
report = await device_manager.generate_security_report()
return json.dumps(
{
"report": report,
"resource": "tailscale://security/report",
},
indent=2,
)
@self.mcp.resource("tailscale://monitoring/metrics")
async def metrics_resource() -> str:
"""Get Prometheus-formatted metrics.
This resource provides metrics in Prometheus exposition format.
Access via: tailscale://monitoring/metrics
Returns:
Prometheus-formatted metrics string
"""
metrics = await monitor.get_prometheus_metrics()
return metrics
@self.mcp.resource("tailscale://monitoring/health")
async def health_resource() -> str:
"""Get network health report.
This resource provides a comprehensive health report with status,
issues, and recommendations.
Access via: tailscale://monitoring/health
Returns:
JSON string with health report
"""
import json
health = await monitor.get_network_health_report()
return json.dumps(
{
"health": health,
"resource": "tailscale://monitoring/health",
},
indent=2,
)
# Store function references to prevent garbage collection
self._resource_functions = [
devices_resource,
device_resource,
network_status_resource,
network_topology_resource,
security_report_resource,
metrics_resource,
health_resource,
]