@yawlabs/tailscale-mcp 0.10.7 → 0.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -210,7 +210,7 @@ MCP Resources expose read-only data clients can browse without a tool call.
210
210
  | ACL Policy | `tailscale://tailnet/acl` | Full ACL policy (HuJSON preserved) |
211
211
  | DNS Config | `tailscale://tailnet/dns` | Nameservers, search paths, split DNS, MagicDNS |
212
212
 
213
- ## Tools (88)
213
+ ## Tools (89)
214
214
 
215
215
  <details>
216
216
  <summary><strong>Status</strong> (1 tool)</summary>
package/dist/index.js CHANGED
@@ -31141,19 +31141,16 @@ function compute429DelayMs(retryAfter, attempt) {
31141
31141
  const base = Math.min(DEFAULT_429_DELAY_MS * 2 ** attempt, MAX_429_DELAY_MS);
31142
31142
  return base + Math.floor(Math.random() * 250);
31143
31143
  }
31144
- async function executeFetch(method, url2, headers, body) {
31144
+ async function executeFetch(method, url2, headers, body, timeoutMs) {
31145
31145
  return fetch(url2, {
31146
31146
  method,
31147
31147
  headers,
31148
31148
  body,
31149
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
31149
+ signal: AbortSignal.timeout(timeoutMs)
31150
31150
  });
31151
31151
  }
31152
31152
  async function apiRequest(method, path, body, options) {
31153
- const auth = await getAuthHeader();
31154
- const headers = {
31155
- Authorization: auth
31156
- };
31153
+ const headers = {};
31157
31154
  if (options?.accept) {
31158
31155
  headers.Accept = options.accept;
31159
31156
  }
@@ -31174,9 +31171,19 @@ async function apiRequest(method, path, body, options) {
31174
31171
  const isRetryable = RETRYABLE_METHODS.has(method.toUpperCase());
31175
31172
  const requestBudgetMs = getRequestBudgetMs();
31176
31173
  return withConcurrencyLimit(async () => {
31174
+ headers.Authorization = await getAuthHeader();
31177
31175
  let res;
31178
31176
  for (let attempt = 0; attempt <= MAX_429_RETRIES; attempt++) {
31179
- res = await executeFetch(method, url2, headers, fetchBody);
31177
+ const remaining = requestBudgetMs - (Date.now() - startedAt);
31178
+ if (remaining <= 0) {
31179
+ return {
31180
+ ok: false,
31181
+ status: 0,
31182
+ error: `Request budget of ${requestBudgetMs}ms exhausted before attempt could begin.`
31183
+ };
31184
+ }
31185
+ const attemptTimeoutMs = Math.min(REQUEST_TIMEOUT_MS, remaining);
31186
+ res = await executeFetch(method, url2, headers, fetchBody, attemptTimeoutMs);
31180
31187
  if (res.status !== 429 || attempt === MAX_429_RETRIES || !isRetryable) break;
31181
31188
  const delay = compute429DelayMs(res.headers.get("retry-after"), attempt);
31182
31189
  const elapsed2 = Date.now() - startedAt;
@@ -31363,7 +31370,11 @@ async function tailnetDevicesResource(uri) {
31363
31370
  }
31364
31371
  async function tailnetAclResource(uri) {
31365
31372
  const res = await apiGet(`/tailnet/${getTailnet()}/acl`, { acceptRaw: true, accept: "application/hujson" });
31366
- const text = res.ok ? res.rawBody ?? "" : `// Error: ${res.error ?? `HTTP ${res.status}`}
31373
+ if (res.ok) {
31374
+ return { contents: [{ uri: uri.href, text: res.rawBody ?? "", mimeType: "application/hujson" }] };
31375
+ }
31376
+ const lines = `Error: ${res.error ?? `HTTP ${res.status}`}`.split("\n");
31377
+ const text = `${lines.map((l) => `// ${l}`).join("\n")}
31367
31378
  `;
31368
31379
  return { contents: [{ uri: uri.href, text, mimeType: "application/hujson" }] };
31369
31380
  }
@@ -32451,6 +32462,14 @@ var keyTools = [
32451
32462
  if (wrongFields.length > 0) {
32452
32463
  throw new Error(`${wrongFields.join(", ")} can only be used with keyType 'auth', not '${keyType}'`);
32453
32464
  }
32465
+ } else {
32466
+ const nonAuthFields = ["scopes", "issuer", "subject", "audience", "customClaimRules"];
32467
+ const wrongFields = nonAuthFields.filter((f) => input[f] !== void 0);
32468
+ if (wrongFields.length > 0) {
32469
+ throw new Error(
32470
+ `${wrongFields.join(", ")} cannot be used with keyType 'auth'. Set keyType to 'client' or 'federated'.`
32471
+ );
32472
+ }
32454
32473
  }
32455
32474
  const body = {};
32456
32475
  if (keyType !== "auth") body.keyType = keyType;
@@ -33448,7 +33467,7 @@ var webhookTools = [
33448
33467
  ];
33449
33468
 
33450
33469
  // src/index.ts
33451
- var version2 = true ? "0.10.7" : (await null).createRequire(import.meta.url)("../package.json").version;
33470
+ var version2 = true ? "0.10.9" : (await null).createRequire(import.meta.url)("../package.json").version;
33452
33471
  var subcommand = process.argv[2];
33453
33472
  if (subcommand === "deploy-acl") {
33454
33473
  const filePath = process.argv[3];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/tailscale-mcp",
3
- "version": "0.10.7",
3
+ "version": "0.10.9",
4
4
  "description": "Tailscale MCP server for managing your tailnet from AI assistants",
5
5
  "license": "MIT",
6
6
  "author": "YawLabs <contact@yaw.sh>",