tailscale-mcp
This server provides safe, structured programmatic access to the local Tailscale daemon for tailnet discovery, SSH configuration, port sharing, and network diagnostics.
tailnet_status: Retrieve a trimmed view of the tailnet, including your own node and peers (hostname, MagicDNS name, Tailscale IPs, OS, online status, exit-node flags, tags). Optionally filter to online-only peers.generate_ssh_config: Generate SSHHostblocks for tailnet nodes, preferring MagicDNS names with Tailscale IP as fallback. Dry-run by default; can write to a dedicated~/.ssh/tailscale_dev_configfile or idempotently integrate into~/.ssh/configbetween managed markers. Supports custom remote users and online-only filtering.share_port: Share a local port over the tailnet via Tailscale Serve (tailnet-only by default) or to the public internet via Funnel (public: true, with explicit exposure warning). Supports custom HTTPS mount paths and returns the resulting URL(s).share_status: View all currently active Tailscale Serve/Funnel sessions on the local node.stop_share: Stop port sharing — either clear the entire Serve/Funnel configuration or selectively stop a specific HTTPS endpoint by port number.ping_all: Concurrently ping tailnet peers (bounded to 5 at a time) and return a latency matrix with reachability, latency in milliseconds, and connection path (direct or DERP relay). Configurable ping count, timeout, and online-only filtering.
Provides tools for tailnet discovery, SSH config generation, port sharing via Serve/Funnel, and latency matrices through the local Tailscale daemon.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@tailscale-mcpshare port 3000"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Tailscale MCP
MCP server for safe programmatic access to the local Tailscale daemon: tailnet discovery, SSH config generation, port sharing via Serve/Funnel, and latency matrices.
Gives agents and developer tools a safe, structured window into the local Tailscale daemon over stdio. It shells out to the tailscale CLI (resolved from PATH, with a Windows fallback to the default install location) and never handles auth keys or tailnet credentials: the CLI talks to the already-authenticated local daemon.
When the binary is missing, the daemon is stopped, or the device needs login, every tool returns a structured error with a code and the exact remedy command instead of throwing.
Installation
npx -y @tmhs/tailscale-mcpAdd to your MCP client configuration (Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"tailscale": {
"command": "npx",
"args": ["-y", "@tmhs/tailscale-mcp"]
}
}
}Requires Node 20+ and an installed, logged-in Tailscale client.
Related MCP server: mcp-tailscale
Tools
tailnet_status
Trimmed view of tailscale status --json: self node plus peers with hostname, MagicDNS name, Tailscale IPv4/IPv6, OS, online flag, last seen, exit-node flags, and tags. Input: optional onlineOnly.
{
"backendState": "Running",
"tailnet": "user@example.com",
"magicDNSSuffix": "tail1234.ts.net",
"self": {"hostname": "DEVPC", "dnsName": "devpc.tail1234.ts.net", "ipv4": "100.101.1.10"},
"peerCount": 3,
"peers": [
{"hostname": "raspi", "dnsName": "raspi.tail1234.ts.net", "ipv4": "100.101.1.20", "os": "linux", "online": true, "exitNodeOption": true, "tags": []}
]
}generate_ssh_config
Emits ssh-config Host blocks for tailnet nodes (MagicDNS name preferred, Tailscale IP fallback). Dry-run by default: returns the generated text only. Inputs: write, target, onlineOnly, user.
write: truewrites the dedicated file~/.ssh/tailscale_dev_configand returns theInclude tailscale_dev_configinstruction for~/.ssh/config(never applied automatically).target: "user_ssh_config"(withwrite: true) edits~/.ssh/configdirectly, idempotently, between# BEGIN tailscale-mcpand# END tailscale-mcpmarkers. Content outside the markers is never touched.
{
"dryRun": true,
"hostCount": 2,
"configText": "# BEGIN tailscale-mcp\nHost raspi\n HostName raspi.tail1234.ts.net\n\nHost devbox\n HostName devbox.tail1234.ts.net\n# END tailscale-mcp"
}share_port
Shares a local port via Tailscale Serve. Tailnet-only by default. Inputs: port (required), public, path.
{"port": 3000, "public": false, "scope": "tailnet-only (Serve)", "urls": ["https://devpc.tail1234.ts.net/"]}public: true switches to Funnel and exposes the port to the open internet. See the security notes below.
share_status
Reports active Serve/Funnel sessions: {"active": false, "status": "No serve config"}.
stop_share
Without arguments clears the entire serve/funnel configuration. With httpsPort it turns off one HTTPS endpoint (the serve port shown in share_status, typically 443, not the proxied local port).
ping_all
Concurrent tailscale ping against peers (bounded to 5 in flight, one ping each with a timeout). Inputs: count, timeoutMs, onlineOnly (default true).
{
"pinged": 2,
"reachable": 1,
"matrix": [
{"hostname": "raspi", "target": "100.101.1.20", "reachable": true, "latencyMs": 3, "path": "direct", "via": "192.168.1.20:41641"},
{"hostname": "exitbox", "target": "100.101.1.40", "reachable": false, "latencyMs": null, "path": null, "via": null}
]
}path distinguishes a direct peer-to-peer connection from a DERP relay, so an agent can tell "works but relayed" from "fast direct path".
Agentic workflow example
An agent asked to "deploy this to my dev VPS and show me the result" can do the whole discovery leg through this server:
tailnet_status {"onlineOnly": true}finds the VPS node and its MagicDNS name (devbox.tail1234.ts.net), with no hardcoded IPs.generate_ssh_config {"write": true, "user": "deploy"}writes~/.ssh/tailscale_dev_config; the agent shows the returned one-lineIncludeinstruction, and after the user adds it,ssh devboxresolves through the tailnet.ping_allconfirms the node is reachable and whether the path is direct or relayed before starting a large transfer.After deploying,
share_port {"port": 8080}returns a tailnet-only URL teammates on the tailnet can open. Nothing touches the public internet unless the agent is explicitly told to passpublic: true.
Security notes on Funnel
share_portdefaults to tailnet-only Serve. Nothing is reachable from outside your tailnet.public: trueuses Tailscale Funnel: the URL is reachable by anyone on the internet, not just your tailnet. The tool description carries this warning so agents surface it before acting.Serve and Funnel must be enabled per-tailnet in the admin console. When they are not, the tool returns a structured
SERVE_NOT_ENABLEDerror containing the exact enablement URL and changes nothing.stop_share(no arguments) is the kill switch: it clears the entire serve/funnel configuration.This server never reads or stores
TS_AUTHKEYor any other credential.
Development
npm install
npm run build # tsc
npm test # vitest, fully offline (fixture-driven, no live tailnet)
npm run typecheckProvider adapter pattern: src/providers/types.ts defines the TailscaleProvider interface; CliProvider (the only v0.1 implementation) spawns the CLI through an injectable process runner so tests never launch a real binary. The interface leaves room for a future LocalAPI provider speaking HTTP over the local socket or named pipe.
Project Structure
tailscale-mcp/
src/ Source code
src/providers/ TailscaleProvider interface + CliProvider
src/tools/ MCP tool registrations
test/fixtures/ Sanitized CLI output captured from a real tailnet
.github/ CI/CD workflowsRoadmap
See ROADMAP.md for the full project roadmap.
Contributing
See CONTRIBUTING.md for guidelines.
License
CC-BY-NC-ND-4.0 -- see LICENSE for details.
Built by TMHSDigital
Available Tools
6 toolsgenerate_ssh_configA
Generate ssh-config Host blocks for tailnet nodes (MagicDNS name preferred, Tailscale IP fallback). Dry-run by default: returns the generated config text only and writes nothing. With write=true it writes a dedicated file (~/.ssh/tailscale_dev_config) and returns instructions for adding an Include line to ~/.ssh/config (never applied automatically). Direct editing of ~/.ssh/config itself additionally requires target="user_ssh_config" and is idempotent between managed markers, never touching content outside them.
| Name | Required | Description | Default |
|---|---|---|---|
| user | No | Remote user to set on every Host block | |
| write | No | Actually write the config (default: false = dry-run, text only) | |
| target | No | Write target: "dedicated_file" (default, ~/.ssh/tailscale_dev_config) or "user_ssh_config" (edit ~/.ssh/config between managed markers) | |
| onlineOnly | No | Only include peers that are currently online (default: false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It covers dry-run default, write behavior, target differences, idempotency of user_ssh_config edits, and never touching outside markers. However, it does not detail file overwrite behavior or prerequisites (e.g., tailscale running).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three concise sentences, front-loaded with the main purpose. Every sentence adds essential information without redundancy or verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description explains return values for both dry-run (config text) and write (instructions). It covers all parameters and key behaviors (idempotency, marker boundaries). Minor gaps exist (e.g., config format details, prerequisites), but overall it is well-rounded.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (baseline 3). The description adds meaningful context beyond the schema, especially for 'write' (explains dry-run vs write) and 'target' (dedicated file vs user_ssh_config with markers). It does not elaborate on 'user' or 'onlineOnly', but the schema descriptions suffice.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it generates SSH config Host blocks for tailnet nodes, with a specific verb ('Generate') and resource ('ssh-config Host blocks'). It distinguishes from sibling tools like ping_all or share_port, which are unrelated. The MagicDNS vs IP fallback adds specificity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for use (generating SSH config for tailnet nodes) and explains the default dry-run, write behavior, and different targets. It does not explicitly list when not to use or compare to siblings, but the purpose is clear enough to avoid misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ping_allA
Ping tailnet peers concurrently (bounded to 5 at a time, one ping each with a timeout) and return a latency matrix: node, latency ms, path (direct vs DERP relay), or unreachable. Defaults to online peers only.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Ping attempts per peer (default: 1) | |
| timeoutMs | No | Per-ping timeout in milliseconds (default: 5000) | |
| onlineOnly | No | Only ping peers reported online (default: true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, but description fully discloses behavioral traits: concurrent pings bounded to 5 at a time, one ping each with timeout, default timeout 5000ms, defaults to online peers only. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, highly efficient. First sentence states action, constraints, and output format. Second adds default scope. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, description provides sufficient context: concurrency, timeout, result structure, default scope. Covers key behavioral aspects for agent invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. Description restates defaults and adds context about concurrency limit but does not significantly enhance parameter meaning beyond schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the tool pings tailnet peers, describes the output as a latency matrix with latency ms, path, and unreachability. It distinguishes from sibling tools like generate_ssh_config and share_port.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Description implies use case for checking latency and connectivity among peers. It notes defaults (online only) but does not explicitly state when to use vs alternatives or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tailnet_statusA
Report the state of the local tailnet: this node plus all peers with hostname, MagicDNS name, Tailscale IPv4/IPv6, OS, online flag, last seen, exit-node flags, and tags. Returns a structured error with the exact fix command when the tailscale binary is missing, the daemon is stopped, or the device needs login.
| Name | Required | Description | Default |
|---|---|---|---|
| onlineOnly | No | Only include peers that are currently online (default: false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. It discloses structured error returns with fix commands for common failures (missing binary, stopped daemon, need login), which is helpful behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two focused sentences: first lists output fields, second details error handling. No unnecessary words, front-loaded with purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one optional parameter and no output schema, the description adequately covers output fields and error conditions, making it complete for a status tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter 'onlineOnly' is fully described in the input schema with a clear description. The tool description adds no further semantic value, meeting but not exceeding baseline expectations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reports tailnet state with specific fields (hostname, MagicDNS name, IPs, OS, online flag, etc.), distinguishing it from sibling tools like ping_all or share_port.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implicitly guides usage by listing what it reports and error conditions, but doesn't explicitly state when to use this tool over alternatives. The context from siblings makes it clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v0.1.0- First observed
generate_ssh_config - First observed
ping_all - First observed
share_port - First observed
share_status - First observed
stop_share - First observed
tailnet_status
TDQS
Each tool has a clearly distinct purpose: SSH config generation, ping testing, port sharing management, and tailnet status. No overlaps.
All tool names follow a consistent verb_noun pattern using snake_case (e.g., generate_ssh_config, ping_all, stop_share).
6 tools cover the core functionalities of tailnet management without being excessive or insufficient.
Covers SSH config, latency testing, and port sharing comprehensively. Minor gaps like setting exit nodes or managing ACLs, but fits a focused scope.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Tailscale device, route, DNS, key, user, and ACL management over MCP and CLI.
Read devices, users, keys, ACLs and DNS for a tailnet; manage devices, routes and auth keys.
Run commands and read/write files on your servers over Termalin's keyless tunnels (hosted MCP).
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
111
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceAn MCP (Model Context Protocol) server for managing Tailscale resources using the official Tailscale Go client library v2. This server provides complete coverage of the Tailscale API with enhanced, self-descriptive tools powered by OpenAPI documentation.2MIT
- AlicenseAqualityCmaintenanceAn MCP server for managing and monitoring Tailscale networks through natural language. It enables users to list devices, check connection status, monitor for client updates, and retrieve detailed tailnet summaries.6157MIT
- AlicenseAqualityCmaintenanceProduction-ready MCP server for Tailscale management with 48 tools across 9 domains: Devices, DNS/Split DNS, ACL policies, Auth Keys, Users, Webhooks, Posture Integrations, Tailnet Settings, and Diagnostics. Supports stdio and SSE transport with Bearer token authentication. Built with TypeScript strict mode, Zod validation, and zero shell execution. AGPL-3.0 + Commercial dual-licensed.49931AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceWraps the Tailscale CLI to enable MCP-capable AI agents to manage devices, serve configurations, and diagnose connectivity.3MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/TMHSDigital/tailscale-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server