Security
- 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.mjsbundles the SDK intodist/index.js, so this ships in the package, and the dependency floor is now^1.32.1. Itsfast-uri, also bundled through ajv, moves from 3.1.7 to 3.1.8 (GHSA-hrr3-gc8f-f4qj). Development-scope only, since the bundle never imports express:proxy-addr2.0.8 (GHSA-jqcg-44mw-7w3h) andip-address10.7.3 (GHSA-j6r3-76f7-8jcv, GHSA-h3mg-xc3c-68pw). Theoverridesfloors forfast-uriandip-addressmove to the patched versions,^3.1.8and^10.7.3.npm auditreports 0 vulnerabilities.
Changed
- The oam floor moves from 0.15.2 to 0.18.0, so the
tailscale-mcplauncher no longer runs the server on an older oam. This server is verified on one oam release at a time, and the floor keeps the launcher off anything older than that release. 0.18.0 is verified on the published aarch64-pc-windows-msvc binary, checksum matched against the release SHA256SUMS, through the launcher withOAM_BINpointing at it andTAILSCALE_MCP_RUNTIME=oam: a full MCP handshake listing all 98 tools (97 admin-API tools plustailscale_tool_groups, the same 98 names as on Node) and all 4 resources,tailscale_tool_groupsanswering byte-for-byte as it does on Node, an API call with a deliberately invalid key returning the same HTTP 401 error text as on Node, no non-JSON line on stdout, and the server process confirmed as that binary (oam-aarch64-pc-windows-msvc.exe run .../dist/index.jsas the launcher's child; it reportsoam 0.18.0). The same session answers identically straight from the TypeScript source (oam run src/index.ts, no build step). The opt-in sandbox the README documents was re-measured on it: withTAILSCALE_MCP_SANDBOX=1 TAILSCALE_MCP_RUNTIME=oamthe launcher spawnsoam --permission --allow-net=api.tailscale.com --allow-env=... --allow-child-process run, the same 98 tools answer as on Node, the invalid-key call still reaches api.tailscale.com for its 401, and a one-linereadFileSyncunder the same flags is refused withERR_ACCESS_DENIED. If the launcher finds only an oam from 0.15.2 to 0.17.x, it now falls back to Node under the defaultTAILSCALE_MCP_RUNTIME=auto, and exits with an error underTAILSCALE_MCP_RUNTIME=oam-- it says so on stderr, naming the version it found and the floor (measured with oam 0.17.0:is oam 0.17.0, older than 0.18.0; using Node instead.). On Node every tool answers the same; what is lost isTAILSCALE_MCP_SANDBOX=1, which needs a fresh oam at the floor, so underautothe server then runs without--permission, and underTAILSCALE_MCP_RUNTIME=oamit does not start. A client that runsoam run /path/to/tailscale-mcp/dist/index.jsdirectly bypasses the launcher and keeps the oam it names. Runoam self-update, or setTAILSCALE_MCP_RUNTIME=nodeto make the choice explicit.
Fixed
release.shwaits up to 600 s, not 300, for npm to serve a new version before the MCP Registry step, gives the post-publishnpxsmoke 60 attempts 10 s apart, not 30, and polls npm up to 120 times 5 s apart in its final check instead of reading once after 3 s. On 2026-09-29 the @yawlabs/fetch-mcp 0.8.2 release spent 295 s of its 300 s gate waiting for npm to serve the new version, andnpxneeded 313 s, 24 of its 30 attempts, to install @yawlabs/lemonsqueezy-mcp 1.0.1. Release tooling only; the server itself is unchanged.release.shruns every mcp-publisher call to the MCP Registry, each login and each publish attempt, under coreutilstimeout(MCP_PUBLISH_TIMEOUT_S, default 90 s) where one (or Homebrew'sgtimeout) is on PATH -- without one the call runs unbounded, and a warning says so -- because mcp-publisher waits for the registry's answer with no limit of its own and a registry that never answered would have hung the release. A publish attempt that gets no answer is retried on the same 30, 60 and 90 s clock as the registry's own 429-504: one the limit stopped, which used to hang the step, and one whose connection failed or dropped (the client'serror sending requestorerror reading response), which used to fail it at once. A login the limit stopped says the registry did not answer; one that failed any other way says how to read mcp-publisher's output (a 401 is the registry refusing the token exchange; a 429, a 5xx or a connection error is the registry or the network) instead of naming token scopes, which never fail a login: the registry reads the org role at login and refuses only at publish. A publish refused with a 403 says what the io.github.YawLabs namespace takes: a YawLabs org Owner whose token can read org roles. Release tooling only; the server itself is unchanged.