Atlas / MCP servers / yawlabs / tailscale-mcp

tailscale-mcpBLOCK

mcp/yawlabs/tailscale-mcp

Tailscale MCP server for managing your tailnet from AI assistants

Verdict
BLOCK
Grade
D
Trust score
69 /100
Exposed tools
102 58r · 32w · 12d
Transport
stdio
License
MIT
Stars
30
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://yaw.sh/mcp/install?name=Tailscale&command=npx&args=-y%2C%40yawlabs%2Ftailscale-mcp&description=Manage%20your%20Tailscale%20tailnet%20-%20devices%2C%20ACLs%2C%20DNS%2C%20keys&source=https%3A%2F%2Fgithub.com%2FYawLabs%2Ftailscale-mcp)

One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.

[](https://www.npmjs.com/package/@yawlabs/tailscale-mcp) [](https://opensource.org/licenses/MIT) [](https://github.com/YawLabs/tailscale-mcp/stargazers) [](./release.sh)

Ask your agent questions about your tailnet and have it act on the answers. 97 admin-API tools + 6 optional local-CLI diagnostics + 1 always-on catalog tool + 4 resources spanning the Tailscale v2 API — devices, ACLs, DNS, keys and trust credentials, users, invites, webhooks, log streaming, posture, services, and organization tailnets. Backed by 1900+ unit tests and an opt-in live-tailnet integration suite.

Built and maintained by Yaw Labs.

What's the point if the API already exists?

You could curl the Tailscale API. The point isn't replacing curl — it's letting an agent compose multi-endpoint workflows in one turn without writing a script:

  • "Which devices haven't checked in for 30 days and have key expiry disabled?" — lists devices, filters by lastSeen (online devices carry none), filters by keyExpiryDisabled, returns a table. Three endpoints, one question.
  • "Someone broke DNS at 2am — who changed what in the last 24 hours?" — pulls the audit log, filters by DNS-related actors and endpoints, reads each change's before/aft
Read from source at commit 98d127786619OBSERVED · 2026-10-08
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add tailscale-mcp -- npx -y @yawlabs/[email protected]
03

Exposed tools (102)

58 read · 32 write · 12 destructive. Blast radius: 12 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
tailscale_accept_device_invitereadAccept a device share invitation using the invite URL or code.
tailscale_approve_userreadApprove a pending user, granting them access to the tailnet.
tailscale_authorize_devicereadAuthorize a device that is pending authorization.
tailscale_batch_update_posture_attributeswriteBatch update custom posture attributes across multiple devices. Each attribute key must start with
tailscale_create_aws_external_idwriteCreate or get the AWS external ID Tailscale presents when assuming your IAM role for S3 log streaming. Put it in the role trust policy
tailscale_create_device_invitewriteCreate a device share invitation that allows an external user to access a specific device in your tailnet.
tailscale_create_oauth_appwriteCreate an OAuth App for device provisioning (Tailscale alpha). Lets a third-party application enroll a device into your tailnet via the authorization-code flow, after a user consents. Returns the app
tailscale_create_org_tailnetwriteCreate a new API-only tailnet in your organization. Returns the tailnet (id, displayName, orgId, dnsName, createdAt) AND a freshly-minted OAuth client for it.\n\nSECURITY: the response body contains that OAuth client
tailscale_create_posture_integrationwriteCreate a new device posture integration.
tailscale_create_user_invitewriteCreate a new user invite that allows someone to join your tailnet.
tailscale_create_webhookwriteCreate a new webhook. The response includes the webhook
tailscale_deauthorize_devicereadDeauthorize a device, immediately removing its access to the tailnet. The device will need to be re-authorized to reconnect.
tailscale_delete_devicedestructivePermanently remove a device from the tailnet. This is irreversible — the device must re-authenticate to rejoin.
tailscale_delete_device_invitedestructiveDelete a device invite. This is irreversible — the invite link will stop working.
tailscale_delete_device_posture_attributedestructiveDelete a custom posture attribute from a device. This is irreversible.
tailscale_delete_log_stream_configdestructiveDelete a log streaming configuration. Logs will stop being sent to the configured destination.
tailscale_delete_oauth_appdestructiveDelete an OAuth App (Tailscale alpha). This is irreversible: the app
tailscale_delete_posture_integrationdestructiveDelete a posture integration. This is irreversible.
tailscale_delete_servicedestructiveDelete a Tailscale Service. This is irreversible — the service
tailscale_delete_tailnetdestructivePermanently delete a tailnet. This is IRREVERSIBLE and removes every device, user, ACL, and key in it.\n\nBy default it acts on the tailnet the current credentials point at (TAILSCALE_TAILNET, or TAILSCALE_OAUTH_TAILNET when targeting an API-only tailnet). Pass
tailscale_delete_userdestructiveDelete a user from the tailnet. This is irreversible — the user and all their devices will be removed.
tailscale_delete_user_invitedestructiveDelete a user invite. This is irreversible — the invite link will stop working.
tailscale_delete_webhookdestructiveDelete a webhook. This is irreversible — the webhook secret cannot be recovered.
tailscale_diff_acl_accessreadAnswer
tailscale_expire_devicereadExpire a device
tailscale_get_aclreadGet the current ACL policy for your tailnet. Returns the raw policy text with original formatting preserved, including comments and trailing commas (HuJSON). Also returns an ETag — you must pass it to tailscale_update_acl to safely update the policy.
tailscale_get_audit_logreadGet the tailnet audit/configuration log. Shows who changed what and when -- useful for troubleshooting and compliance. Optional actor, target and event filters narrow the query server-side, so a targeted question doesn
tailscale_get_contactsreadGet the tailnet contact information (security, support, admin emails).
tailscale_get_devicereadGet detailed information about a specific device by its ID. Returns the default field subset unless fields:
tailscale_get_device_invitereadGet details for a specific device invite.
tailscale_get_device_posture_attributesreadGet all posture attributes for a device, including custom and system-managed attributes.
tailscale_get_device_routesreadGet the subnet routes a device advertises and which are enabled.
tailscale_get_dns_configurationreadGet the unified DNS configuration for your tailnet, including nameservers, search paths, split DNS, and MagicDNS preference in a single call.
tailscale_get_dns_preferencesreadGet DNS preferences for your tailnet, including whether MagicDNS is enabled.
tailscale_get_keyreadGet details for a specific key (auth key, API access token, OAuth client, or federated identity). A revoked or expired key is still returned, with
tailscale_get_log_stream_configreadGet the log streaming configuration for a specific log type.
tailscale_get_log_stream_statusreadGet the status of log streaming for a specific log type. Shows whether logs are being delivered successfully.
tailscale_get_nameserversreadGet the DNS nameservers configured for your tailnet.
tailscale_get_network_flow_logsreadGet network traffic flow logs showing connections between devices. Shows source/destination nodes, timestamps, and traffic metadata — useful for security monitoring and debugging connectivity.
tailscale_get_oauth_appreadGet an OAuth App
tailscale_get_posture_integrationreadGet details for a specific device posture integration.
tailscale_get_search_pathsreadGet the DNS search paths configured for your tailnet.
tailscale_get_servicereadGet details for a specific Tailscale Service, including its MagicDNS name, virtual IP, and configuration.
tailscale_get_service_device_approvalreadGet the approval status of a specific device for a Tailscale Service.
tailscale_get_split_dnsreadGet the split DNS configuration for your tailnet.
tailscale_get_tailnet_settingsreadGet your tailnet settings (device approval, key expiry, HTTPS certificates, etc.).
tailscale_get_userreadGet details for a specific user.
tailscale_get_user_invitereadGet details for a specific user invite.
tailscale_get_webhookreadGet details for a specific webhook.
tailscale_list_device_invitesreadList all device invites for a specific device.
tailscale_list_devicesreadList all devices in your tailnet with their status, IP addresses, OS, and last seen time.${DEVICE_LAST_SEEN_NOTE}
tailscale_list_keysreadList keys in your tailnet: auth keys, API access tokens, OAuth clients and federated identities. Without
tailscale_list_log_stream_configsreadList all log streaming configurations for your tailnet. Fetches both
tailscale_list_oauth_appsreadList the OAuth Apps registered in your tailnet (Tailscale alpha). Returns an
tailscale_list_org_tailnetsreadList the tailnets in your organization, including API-only tailnets created via the API. Paginated: returns at most
tailscale_list_posture_integrationsreadList all device posture integrations configured for your tailnet.
tailscale_list_service_hostsreadList devices hosting a specific Tailscale Service.
tailscale_list_servicesreadList all Tailscale Services in your tailnet. Services provide stable MagicDNS names and virtual IPs, decoupled from individual devices. Note: services are created implicitly when a node first advertises one (
tailscale_list_user_invitesreadList the open (not yet accepted) user invites for your tailnet. Accepted invites are not returned.
tailscale_list_usersreadList all users in your tailnet.
tailscale_list_webhooksreadList all webhooks configured for your tailnet.
tailscale_local_service_listreadList the Tailscale Services visible to THIS node. Complements the admin-side service tools (tailscale_list_services etc.), which report what the tailnet has configured -- this reports what this machine can actually see and reach, which is the difference that matters when debugging a service that
tailscale_local_statusreadGet this machine
tailscale_local_versionreadGet the version of the local
tailscale_local_whoamireadShow which Tailscale user and device this machine is currently authenticated as. Useful for confirming an agent host is enrolled under the identity you expect before trusting its access. Requires tailscale >= 1.102.1; returns the CLI
tailscale_netcheckwriteRun Tailscale
tailscale_pingreadProbe latency to another tailnet node from this machine. Useful for connectivity debugging -- shows whether the path is direct or DERP-relayed, plus RTT. Returns the CLI
tailscale_preview_aclwritePreview the ACL rules that would apply to a specific user or IP address if a proposed policy were applied.
tailscale_rename_devicedestructiveSet the name of a device in the tailnet, or reset it to its OS hostname.
tailscale_resend_contact_verificationreadResend the verification email for a tailnet contact.
tailscale_resend_device_invitereadResend a device invite email.
tailscale_resend_user_invitereadResend a user invite email.
tailscale_restore_userreadRestore a previously suspended user, re-granting them access to the tailnet.
tailscale_rotate_webhook_secretreadRotate a webhook
tailscale_set_contactswriteUpdate tailnet contact information. Each provided contact type (account/support/security) is PATCHed in parallel; per-type errors are returned alongside the successes so a partial failure doesn
tailscale_set_device_ipwriteSet the Tailscale IPv4 address for a device.
tailscale_set_device_posture_attributewriteSet a custom posture attribute on a device. Creates or updates the attribute. Attribute keys must start with
tailscale_set_device_routeswriteSet the enabled subnet routes for a device. Replaces all currently enabled routes — pass the full list of routes you want enabled.
tailscale_set_device_tagswriteSet ACL tags on a device. Replaces all existing tags — pass the full list of tags you want applied.
tailscale_set_devices_authorizedwriteAuthorize or deauthorize multiple devices in one call. Each device
tailscale_set_dns_configurationwriteSet the unified DNS configuration for your tailnet in a single call. Replaces all DNS settings (nameservers, search paths, split DNS, MagicDNS preference).
tailscale_set_dns_preferenceswriteSet DNS preferences for your tailnet, such as enabling or disabling MagicDNS. The API reference says enabling can fail when the tailnet has no nameservers; if it does, add one with tailscale_set_nameservers first.
tailscale_set_log_stream_configwriteSet the log streaming configuration for a specific log type. Configures where logs are sent (e.g. Axiom, Datadog, Splunk, Elasticsearch, S3).\n\n
tailscale_set_nameserverswriteSet the DNS nameservers for your tailnet. Replaces all existing nameservers. Removing every nameserver may also change MagicDNS: the API reference says it is switched off, while Tailscale
tailscale_set_search_pathswriteSet the DNS search paths for your tailnet. Replaces all existing search paths.
tailscale_set_service_device_approvalwriteApprove or reject a device to host a Tailscale Service.
tailscale_set_split_dnswriteSet split DNS configuration. Maps domains to specific nameservers. Replaces the entire split DNS configuration: a domain you leave out is removed, and an empty object clears every domain. Per the API reference, setting a domain to null clears that domain
tailscale_statusreadCheck that the Tailscale API connection is working. Returns your tailnet name, device count, and confirms authentication is valid. Use this to verify setup.
tailscale_suspend_userreadSuspend a user, immediately revoking their access to the tailnet. Their devices will be disconnected. Can be reversed with tailscale_restore_user.
tailscale_test_webhookwriteSend a test event to a webhook endpoint to verify it is configured correctly and receiving events.
tailscale_tool_groupsreadExplain which of this server
tailscale_update_aclwriteUpdate the ACL policy for your tailnet. Accepts the full policy as a string to preserve formatting, comments, and trailing commas (HuJSON). You MUST pass the ETag from tailscale_get_acl to prevent overwriting concurrent changes, or
tailscale_update_device_keywriteUpdate a device
tailscale_update_keywriteUpdate an existing key. Supported fields depend on the key type: all key types accept
tailscale_update_posture_integrationwriteUpdate an existing posture integration
tailscale_update_servicewriteUpdate a Tailscale Service
tailscale_update_tailnet_settingswriteUpdate tailnet settings (device approval, auto-updates, key expiry, HTTPS certificates, network flow logging, regional routing, posture identity collection).
tailscale_update_user_rolewriteUpdate a user
tailscale_update_webhookwriteUpdate an existing webhook
tailscale_validate_aclreadValidate an ACL policy without applying it. Returns any errors found, or confirms the policy is valid.
tailscale_validate_aws_trust_policyreadValidate that an AWS IAM role trust policy is correctly configured with the Tailscale external ID. Use this after setting up the IAM role for S3 log streaming.
yaw-probe-c9-breadyaw probe c9
04

Trust audit

BLOCKgrade D · trust 69/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (4 observation(s))
Network
declared (9 observation(s))
Shell
declared (5 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (16)

HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
scripts/update-manifests.mjs:213
const SSH = "ssh -i ~/.ssh/gh_woods -o IdentitiesOnly=yes";
Why it matters. touches a credential store
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
src/live-fixtures.test.ts:408
const token = "eyJhbGciOiJIUzI1NiJ9.aaaabbbbccccddddeeeeffff.gggghhhhiiiijjjj";
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
tailscale_delete_device, tailscale_delete_device_invite, tailscale_delete_device_posture_attribute, tailscale_delete_log_stream_config, tailscale_delete_oauth_app, tailscale_delete_posture_integration
Why it matters. 12 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/launcher.test.ts:31
const factory = new Function("process", `${match[0]}; return sandboxFlags();`) as (p: {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/launcher.test.ts:123
const factory = new Function(`${pieces.join("\n")}\nreturn ${name};`) as () => T;
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/node-floor.test.ts:184
const nodeFloorFailure = new Function(`${extracts.join("\n")}\nreturn nodeFloorFailure;`)() as (versions: {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/index.ts:63
for (const rel of ["../package.json", "../../package.json", "../../../package.json"]) {
LOWObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
src/cli.test.ts:651
writeFileSync(aclFile, `{ "acls": [{ "action": "accept", "src": ["*"], "dst": ["*:*"] }] }`);
LOWObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
src/cli.test.ts:666
assert.ok(!body.startsWith(""), `the BOM reached the wire: ${JSON.stringify(body.slice(0, 8))}`);
LOWObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
src/live-fixtures.test.ts:1889
writeFileSync(path, `${JSON.stringify({ targets: {}, journal: [] })}`, "utf-8");
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@biomejs/biome, @modelcontextprotocol/sdk, @types/node, esbuild, postject, typescript, zod
Why it matters. 7 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
CHANGELOG.md:73
- **`tailscale_list_keys` said the default listing is "auth keys only"; per the OpenAPI spec it is whatever the credential owns.** The spec's listing returns "active auth keys, API access tokens and t
Why it matters. asks the agent to read credentials
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
README.md:24
- **"Create an OAuth client for our CI pipeline scoped to `devices:core:read` and `dns:read`"** — creates a trust credential via `tailscale_create_key` with `keyType=client`, returns the credentials o
Why it matters. asks the agent to read credentials
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
README.md:355
| `keys` | `auth_keys:read`, `oauth_keys:read`, `federated_keys:read`, `api_access_tokens:read`, `oauth_apps:read` | `auth_keys`, `oauth_keys`, `federated_keys`, `api_access_tokens`, `oauth_apps` | Ke
Why it matters. asks the agent to read credentials
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
README.md:413
| Windows | — | The installer puts `tailscale.exe` on the machine `PATH`. If you set `TAILSCALE_BINARY`, use a Windows path (`C:/Program Files/Tailscale/tailscale.exe`), not a Git Bash one (`/c/...`)
Why it matters. asks the agent to read credentials
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
CHANGELOG.md:32
- **The bundled MCP SDK moves from 1.30.0 to 1.32.1** (GHSA-6qxp-vccf-f47h, high: the SDK's OAuth client could send credentials to an authorization server chosen by the MCP server). `build.mjs` bundle
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha 98d127786619full audit observations/trust-audit/mcp-server/yawlabs__tailscale-mcp.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-0898d127786619BLOCKD69first audit
06

Questions

What is the tailscale-mcp MCP server?

Tailscale MCP server for managing your tailnet from AI assistants

What tools does tailscale-mcp expose?

102 in total: 58 read-only, 32 that write, and 12 that can delete or overwrite (tailscale_delete_device, tailscale_delete_device_invite, tailscale_delete_device_posture_attribute, tailscale_delete_log_stream_config, tailscale_delete_oauth_app). Every one is listed on this page with its risk.

Is tailscale-mcp safe to connect to an agent?

No — not without reading the findings first. The audit graded it D (69/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 12 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does tailscale-mcp need?

It reads TAILSCALE_API_KEY, TAILSCALE_OAUTH_CLIENT_ID, TAILSCALE_OAUTH_CLIENT_SECRET and TAILSCALE_OAUTH_TAILNET from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does tailscale-mcp run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as @yawlabs/tailscale-mcp at 0.21.2.

How current is this page?

The grade is for one exact copy of the source (98d127786619), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement