npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tmhs/tailscale-mcp

v0.1.2

Published

MCP server for safe programmatic access to the local Tailscale daemon: tailnet discovery, SSH config generation, port sharing via Serve/Funnel, and latency matrices.

Readme

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.

License: CC-BY-NC-ND-4.0 npm version CI


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-mcp

Add 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.

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": "[email protected]",
  "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: true writes the dedicated file ~/.ssh/tailscale_dev_config and returns the Include tailscale_dev_config instruction for ~/.ssh/config (never applied automatically).
  • target: "user_ssh_config" (with write: true) edits ~/.ssh/config directly, idempotently, between # BEGIN tailscale-mcp and # END tailscale-mcp markers. 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:

  1. tailnet_status {"onlineOnly": true} finds the VPS node and its MagicDNS name (devbox.tail1234.ts.net), with no hardcoded IPs.
  2. generate_ssh_config {"write": true, "user": "deploy"} writes ~/.ssh/tailscale_dev_config; the agent shows the returned one-line Include instruction, and after the user adds it, ssh devbox resolves through the tailnet.
  3. ping_all confirms the node is reachable and whether the path is direct or relayed before starting a large transfer.
  4. 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 pass public: true.

Security notes on Funnel

  • share_port defaults to tailnet-only Serve. Nothing is reachable from outside your tailnet.
  • public: true uses 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_ENABLED error 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_AUTHKEY or any other credential.

Development

npm install
npm run build     # tsc
npm test          # vitest, fully offline (fixture-driven, no live tailnet)
npm run typecheck

Provider 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 workflows

Roadmap

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