Tailscale MCP Server
A Model Context Protocol (MCP) server for operating Tailscale from any MCP client. Supports local stdio for desktop clients and an authenticated HTTP transport for private tailnet deployments. Defaults to read-only access, localhost binding, and short-lived OAuth credentials where available.
Table of Contents
Features
- Device management — list, authorize, deauthorize, delete, expire keys, manage routes.
- Network operations — connect/disconnect host, ping peers, get CLI status and version.
- Administration — tailnet info, file sharing, exit nodes, webhooks, device tags, server version.
- ACL and policy — read/validate/update ACL, DNS settings, auth keys, policy file, network lock.
- Read-only resources — tailnet summary, device list, per-device detail, current ACL.
- Prompts — guided connectivity diagnosis and ACL change review.
- Risk-gated tools —
read, write, and admin levels via TAILSCALE_ALLOWED_TOOL_RISK.
- OAuth + API key — OAuth client credentials (preferred) or legacy API key.
- Private HTTP mode — bearer auth, Host validation, request size limits, health check endpoint.
- Docker support — pre-built images on Docker Hub and GHCR; sidecar deployment with Tailscale Serve.
Requirements
One of:
- Node.js 20+ — run via
npx or install globally (no extra runtime needed).
- Bun 1.3+ — used for development; also works as a production runtime.
- Docker — use the pre-built image (no local runtime required).
Plus one auth method:
- OAuth client credentials:
TAILSCALE_OAUTH_CLIENT_ID + TAILSCALE_OAUTH_CLIENT_SECRET (preferred).
- Legacy API key:
TAILSCALE_API_KEY.
The local Tailscale CLI is optional. It is only required for CLI-backed tools: get_network_status, connect_network, disconnect_network, ping_peer, get_version, and manage_exit_nodes (set/clear operations).
Quick Start
Claude Desktop
Edit ~/.claude/claude_desktop_config.json (create if absent).
OAuth credentials (recommended)
{
"mcpServers": {
"tailscale": {
"command": "npx",
"args": ["-y", "@hexsleeves/tailscale-mcp-server"],
"env": {
"TAILSCALE_OAUTH_CLIENT_ID": "your-client-id",
"TAILSCALE_OAUTH_CLIENT_SECRET": "your-client-secret",
"TAILSCALE_TAILNET": "-"
}
}
}
}
API key
{
"mcpServers": {
"tailscale": {
"command": "npx",
"args": ["-y", "@hexsleeves/tailscale-mcp-server"],
"env": {
"TAILSCALE_API_KEY": "tskey-api-...",
"TAILSCALE_TAILNET": "-"
}
}
}
}
Add TAILSCALE_ALLOWED_TOOL_RISK to the env block:
"TAILSCALE_ALLOWED_TOOL_RISK": "write"
Set to "admin" to unlock destructive operations (delete, deauthorize, connect/disconnect, key mutation).
Docker Hub
{
"mcpServers": {
"tailscale": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-e", "TAILSCALE_API_KEY=tskey-api-...",
"-e", "TAILSCALE_TAILNET=your-tailnet",
"hexsleeves/tailscale-mcp-server:latest"
]
}
}
}
Claude Code (CLI)
claude mcp add tailscale \
-e TAILSCALE_API_KEY=tskey-api-... \
-e TAILSCALE_TAILNET=- \
-- npx -y @hexsleeves/tailscale-mcp-server
With write access:
claude mcp add tailscale \
-e TAILSCALE_API_KEY=tskey-api-... \
-e TAILSCALE_TAILNET=- \
-e TAILSCALE_ALLOWED_TOOL_RISK=write \
-- npx -y @hexsleeves/tailscale-mcp-server
Cursor
Add to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"tailscale": {
"command": "npx",
"args": ["-y", "@hexsleeves/tailscale-mcp-server"],
"env": {
"TAILSCALE_API_KEY": "tskey-api-...",
"TAILSCALE_TAILNET": "-"
}
}
}
}
Devices
Network
Administration
ACL and Policy
Resources and Prompts
Resources (read-only)
Prompts
Configuration
Risk levels
read — list devices, inspect status, read resources, run diagnostics.
write — update ACLs, DNS, routes, policy files, webhooks, tags, and other mutating settings.
admin — destructive or host-affecting operations: delete, deauthorize, connect, disconnect, auth key mutation, file sharing changes, exit node control.
HTTP Transport
HTTP mode is intended for private tailnet access. It requires MCP_HTTP_BEARER_TOKEN and binds to 127.0.0.1 by default.
export MCP_TRANSPORT=http
export MCP_HTTP_BEARER_TOKEN="$(openssl rand -base64 32)"
export TAILSCALE_OAUTH_CLIENT_ID="your-client-id"
export TAILSCALE_OAUTH_CLIENT_SECRET="your-client-secret"
export TAILSCALE_TAILNET="-"
npx -y @hexsleeves/tailscale-mcp-server --http --host 127.0.0.1 --port 3000
Expose privately with Tailscale Serve (recommended for tailnet deployments):
tailscale serve --bg 443 localhost:3000
Do not use Tailscale Funnel for normal MCP operation. Funnel makes the endpoint publicly reachable on the internet.
A GET /health endpoint returns 200 OK when the server is running.
For full Docker sidecar deployment instructions, see docs/docker.md.
Docker
Run with Docker Hub image
docker run --rm \
-e TAILSCALE_API_KEY="tskey-api-..." \
-e TAILSCALE_TAILNET="-" \
-p 127.0.0.1:3000:3000 \
hexsleeves/tailscale-mcp-server:latest
Run with GHCR image
docker run --rm \
-e TAILSCALE_API_KEY="tskey-api-..." \
-e TAILSCALE_TAILNET="-" \
-p 127.0.0.1:3000:3000 \
ghcr.io/hexsleeves/tailscale-mcp-server:latest
Build locally
docker build -t tailscale-mcp-server .
For sidecar deployment with Tailscale Serve, see docs/docker.md.
Example Prompts
Once the server is connected to your MCP client, try these:
- "List my Tailscale devices and show which ones are offline."
- "What is the current Tailscale network status on this machine?"
- "Diagnose connectivity to my NAS at 100.64.0.5."
- "Show me the current ACL policy for my tailnet."
- "Review this ACL change before I apply it." (attach the new policy)
- "What DNS nameservers is my tailnet using?"
- "List all active webhooks in my tailnet."
Development
# Install dependencies (Bun required for development)
bun install
# Type check
bun run typecheck
# Run tests
bun test
# Lint and format
bun run check
# Build
bun run build
# Full verification (typecheck + lint + test + build)
bun run qa:full
# Security audit
bun audit
See CONTRIBUTING.md for the full development workflow, commit conventions, and release process.
Contributing
Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.