@yawlabs/tailscale-mcp 0.12.2 → 0.12.3
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/dist/index.js +52 -58
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30958,7 +30958,7 @@ var MAX_429_RETRIES = 3;
|
|
|
30958
30958
|
var DEFAULT_429_DELAY_MS = 1e3;
|
|
30959
30959
|
var MAX_429_DELAY_MS = 3e4;
|
|
30960
30960
|
var MAX_REQUEST_BUDGET_MS = 9e4;
|
|
30961
|
-
var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["GET", "
|
|
30961
|
+
var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["GET", "PUT", "DELETE"]);
|
|
30962
30962
|
var oauthToken = null;
|
|
30963
30963
|
var oauthRefreshPromise = null;
|
|
30964
30964
|
function getAuthConfig() {
|
|
@@ -31285,6 +31285,9 @@ var PROFILES = {
|
|
|
31285
31285
|
full: []
|
|
31286
31286
|
// empty = all groups
|
|
31287
31287
|
};
|
|
31288
|
+
function parseReadonlyFlag(value) {
|
|
31289
|
+
return value === "1" || value === "true";
|
|
31290
|
+
}
|
|
31288
31291
|
function filterTools(groups, options) {
|
|
31289
31292
|
const validNames = new Set(Object.keys(groups));
|
|
31290
31293
|
let profileGroups;
|
|
@@ -31305,7 +31308,7 @@ function filterTools(groups, options) {
|
|
|
31305
31308
|
const effectiveGroups = explicitTools2 ?? profileGroups ?? null;
|
|
31306
31309
|
const enabledGroups = effectiveGroups ? new Set(effectiveGroups) : null;
|
|
31307
31310
|
const unknownGroups2 = enabledGroups ? [...enabledGroups].filter((g) => !validNames.has(g)) : [];
|
|
31308
|
-
const readonly2 = options.readonly
|
|
31311
|
+
const readonly2 = parseReadonlyFlag(options.readonly);
|
|
31309
31312
|
const out = [];
|
|
31310
31313
|
for (const [name, tools] of Object.entries(groups)) {
|
|
31311
31314
|
if (enabledGroups && !enabledGroups.has(name)) continue;
|
|
@@ -31322,6 +31325,49 @@ function filterTools(groups, options) {
|
|
|
31322
31325
|
return result;
|
|
31323
31326
|
}
|
|
31324
31327
|
|
|
31328
|
+
// src/tools/status.ts
|
|
31329
|
+
function composeTailnetStatusData(devicesRes, settingsRes, extras = {}) {
|
|
31330
|
+
const { deviceCount: _deviceCount, settings: _settings, errors: _errors, ...safeExtras } = extras;
|
|
31331
|
+
const data = {
|
|
31332
|
+
...safeExtras,
|
|
31333
|
+
deviceCount: devicesRes.ok ? devicesRes.data?.devices?.length ?? null : null,
|
|
31334
|
+
settings: settingsRes.ok ? settingsRes.data : null
|
|
31335
|
+
};
|
|
31336
|
+
const errors = {};
|
|
31337
|
+
if (!devicesRes.ok) errors.devices = devicesRes.error ?? `HTTP ${devicesRes.status}`;
|
|
31338
|
+
if (!settingsRes.ok) errors.settings = settingsRes.error ?? `HTTP ${settingsRes.status}`;
|
|
31339
|
+
if (Object.keys(errors).length > 0) data.errors = errors;
|
|
31340
|
+
return data;
|
|
31341
|
+
}
|
|
31342
|
+
var statusTools = [
|
|
31343
|
+
{
|
|
31344
|
+
name: "tailscale_status",
|
|
31345
|
+
description: "Check that the Tailscale API connection is working. Returns your tailnet name, device count, and confirms authentication is valid. Use this to verify setup.",
|
|
31346
|
+
annotations: {
|
|
31347
|
+
title: "Check API status",
|
|
31348
|
+
readOnlyHint: true,
|
|
31349
|
+
destructiveHint: false,
|
|
31350
|
+
idempotentHint: true,
|
|
31351
|
+
openWorldHint: true
|
|
31352
|
+
},
|
|
31353
|
+
inputSchema: external_exports.object({}),
|
|
31354
|
+
handler: async () => {
|
|
31355
|
+
const [devicesRes, settingsRes] = await Promise.all([
|
|
31356
|
+
apiGet(`/tailnet/${getTailnet()}/devices?fields=id`),
|
|
31357
|
+
apiGet(`/tailnet/${getTailnet()}/settings`)
|
|
31358
|
+
]);
|
|
31359
|
+
if (!devicesRes.ok && !settingsRes.ok) {
|
|
31360
|
+
return devicesRes;
|
|
31361
|
+
}
|
|
31362
|
+
const data = composeTailnetStatusData(devicesRes, settingsRes, {
|
|
31363
|
+
connected: true,
|
|
31364
|
+
tailnet: getTailnet()
|
|
31365
|
+
});
|
|
31366
|
+
return { ok: true, status: 200, data };
|
|
31367
|
+
}
|
|
31368
|
+
}
|
|
31369
|
+
];
|
|
31370
|
+
|
|
31325
31371
|
// src/server-wiring.ts
|
|
31326
31372
|
function isLocalCliEnabled(env) {
|
|
31327
31373
|
return env.TAILSCALE_LOCAL_CLI === "1" || env.TAILSCALE_LOCAL_CLI === "true";
|
|
@@ -31371,19 +31417,7 @@ async function tailnetStatusResource(uri) {
|
|
|
31371
31417
|
apiGet(`/tailnet/${getTailnet()}/devices?fields=id`),
|
|
31372
31418
|
apiGet(`/tailnet/${getTailnet()}/settings`)
|
|
31373
31419
|
]);
|
|
31374
|
-
const data = {
|
|
31375
|
-
tailnet: getTailnet(),
|
|
31376
|
-
// `?? null` (not `?? 0`): the request succeeded but the body was missing
|
|
31377
|
-
// a `devices` array (204 / empty content-length / unexpected shape).
|
|
31378
|
-
// Reporting `0` in that case would be confidently wrong; null signals
|
|
31379
|
-
// "unknown" so the caller doesn't conflate it with an actually-empty tailnet.
|
|
31380
|
-
deviceCount: devicesRes.ok ? devicesRes.data?.devices?.length ?? null : null,
|
|
31381
|
-
settings: settingsRes.ok ? settingsRes.data : null
|
|
31382
|
-
};
|
|
31383
|
-
const errors = {};
|
|
31384
|
-
if (!devicesRes.ok) errors.devices = devicesRes.error ?? `HTTP ${devicesRes.status}`;
|
|
31385
|
-
if (!settingsRes.ok) errors.settings = settingsRes.error ?? `HTTP ${settingsRes.status}`;
|
|
31386
|
-
if (Object.keys(errors).length > 0) data.errors = errors;
|
|
31420
|
+
const data = composeTailnetStatusData(devicesRes, settingsRes, { tailnet: getTailnet() });
|
|
31387
31421
|
return { contents: [{ uri: uri.href, text: JSON.stringify(data, null, 2), mimeType: "application/json" }] };
|
|
31388
31422
|
}
|
|
31389
31423
|
async function tailnetDevicesResource(uri) {
|
|
@@ -31616,8 +31650,8 @@ function isCidr(s) {
|
|
|
31616
31650
|
if (slash < 0) return false;
|
|
31617
31651
|
const addr = s.slice(0, slash);
|
|
31618
31652
|
const prefix = s.slice(slash + 1);
|
|
31653
|
+
if (!/^\d+$/.test(prefix)) return false;
|
|
31619
31654
|
const prefixN = Number(prefix);
|
|
31620
|
-
if (!Number.isInteger(prefixN) || prefixN < 0) return false;
|
|
31621
31655
|
if (net.isIPv4(addr)) return prefixN <= 32;
|
|
31622
31656
|
if (net.isIPv6(addr)) return prefixN <= 128;
|
|
31623
31657
|
return false;
|
|
@@ -33197,46 +33231,6 @@ var serviceTools = [
|
|
|
33197
33231
|
}
|
|
33198
33232
|
];
|
|
33199
33233
|
|
|
33200
|
-
// src/tools/status.ts
|
|
33201
|
-
var statusTools = [
|
|
33202
|
-
{
|
|
33203
|
-
name: "tailscale_status",
|
|
33204
|
-
description: "Check that the Tailscale API connection is working. Returns your tailnet name, device count, and confirms authentication is valid. Use this to verify setup.",
|
|
33205
|
-
annotations: {
|
|
33206
|
-
title: "Check API status",
|
|
33207
|
-
readOnlyHint: true,
|
|
33208
|
-
destructiveHint: false,
|
|
33209
|
-
idempotentHint: true,
|
|
33210
|
-
openWorldHint: true
|
|
33211
|
-
},
|
|
33212
|
-
inputSchema: external_exports.object({}),
|
|
33213
|
-
handler: async () => {
|
|
33214
|
-
const [devicesRes, settingsRes] = await Promise.all([
|
|
33215
|
-
apiGet(`/tailnet/${getTailnet()}/devices?fields=id`),
|
|
33216
|
-
apiGet(`/tailnet/${getTailnet()}/settings`)
|
|
33217
|
-
]);
|
|
33218
|
-
if (!devicesRes.ok && !settingsRes.ok) {
|
|
33219
|
-
return devicesRes;
|
|
33220
|
-
}
|
|
33221
|
-
const data = {
|
|
33222
|
-
connected: true,
|
|
33223
|
-
tailnet: getTailnet(),
|
|
33224
|
-
// `?? null` (not `?? 0`): the request succeeded but the body was missing
|
|
33225
|
-
// a `devices` array (204 / empty content-length / unexpected shape).
|
|
33226
|
-
// Reporting `0` in that case would be confidently wrong; null signals
|
|
33227
|
-
// "unknown" so the caller doesn't conflate it with an actually-empty tailnet.
|
|
33228
|
-
deviceCount: devicesRes.ok ? devicesRes.data?.devices?.length ?? null : null,
|
|
33229
|
-
settings: settingsRes.ok ? settingsRes.data : null
|
|
33230
|
-
};
|
|
33231
|
-
const errors = {};
|
|
33232
|
-
if (!devicesRes.ok) errors.devices = devicesRes.error ?? `HTTP ${devicesRes.status}`;
|
|
33233
|
-
if (!settingsRes.ok) errors.settings = settingsRes.error ?? `HTTP ${settingsRes.status}`;
|
|
33234
|
-
if (Object.keys(errors).length > 0) data.errors = errors;
|
|
33235
|
-
return { ok: true, status: 200, data };
|
|
33236
|
-
}
|
|
33237
|
-
}
|
|
33238
|
-
];
|
|
33239
|
-
|
|
33240
33234
|
// src/tools/tailnet.ts
|
|
33241
33235
|
var tailnetTools = [
|
|
33242
33236
|
{
|
|
@@ -33680,7 +33674,7 @@ var webhookTools = [
|
|
|
33680
33674
|
];
|
|
33681
33675
|
|
|
33682
33676
|
// src/index.ts
|
|
33683
|
-
var version2 = true ? "0.12.
|
|
33677
|
+
var version2 = true ? "0.12.3" : (await null).createRequire(import.meta.url)("../package.json").version;
|
|
33684
33678
|
var subcommand = process.argv[2];
|
|
33685
33679
|
if (subcommand === "deploy-acl") {
|
|
33686
33680
|
const filePath = process.argv[3];
|
|
@@ -33774,7 +33768,7 @@ server.resource(
|
|
|
33774
33768
|
);
|
|
33775
33769
|
var transport = new StdioServerTransport();
|
|
33776
33770
|
await server.connect(transport);
|
|
33777
|
-
var readonlyMode = process.env.TAILSCALE_READONLY
|
|
33771
|
+
var readonlyMode = parseReadonlyFlag(process.env.TAILSCALE_READONLY);
|
|
33778
33772
|
var filterSuffix = formatBannerFilterSuffix({
|
|
33779
33773
|
unknownProfile,
|
|
33780
33774
|
explicitTools,
|