@yawlabs/tailscale-mcp 0.1.1 → 0.1.2

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/api.d.ts CHANGED
@@ -23,6 +23,8 @@ export declare function apiGet<T = unknown>(path: string, options?: {
23
23
  }): Promise<ApiResponse<T>>;
24
24
  export declare function apiPost<T = unknown>(path: string, body?: unknown, options?: {
25
25
  rawBody?: string;
26
+ acceptRaw?: boolean;
27
+ accept?: string;
26
28
  contentType?: string;
27
29
  ifMatch?: string;
28
30
  }): Promise<ApiResponse<T>>;
package/dist/api.js CHANGED
@@ -2,7 +2,9 @@
2
2
  * Tailscale API client with API key and OAuth authentication.
3
3
  */
4
4
  const BASE_URL = "https://api.tailscale.com/api/v2";
5
+ const REQUEST_TIMEOUT_MS = 30_000;
5
6
  let oauthToken = null;
7
+ let oauthRefreshPromise = null;
6
8
  function getConfig() {
7
9
  const apiKey = process.env.TAILSCALE_API_KEY;
8
10
  const oauthClientId = process.env.TAILSCALE_OAUTH_CLIENT_ID;
@@ -18,25 +20,38 @@ async function getOAuthAccessToken(clientId, clientSecret) {
18
20
  if (oauthToken && Date.now() < oauthToken.expires_at - 60_000) {
19
21
  return oauthToken.access_token;
20
22
  }
21
- const res = await fetch("https://api.tailscale.com/api/v2/oauth/token", {
22
- method: "POST",
23
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
24
- body: new URLSearchParams({
25
- client_id: clientId,
26
- client_secret: clientSecret,
27
- grant_type: "client_credentials",
28
- }),
29
- });
30
- if (!res.ok) {
31
- const body = await res.text();
32
- throw new Error(`OAuth token exchange failed (${res.status}): ${body}`);
23
+ // Deduplicate concurrent refresh requests
24
+ if (oauthRefreshPromise) {
25
+ return oauthRefreshPromise;
33
26
  }
34
- const data = (await res.json());
35
- oauthToken = {
36
- access_token: data.access_token,
37
- expires_at: Date.now() + data.expires_in * 1000,
38
- };
39
- return oauthToken.access_token;
27
+ oauthRefreshPromise = (async () => {
28
+ try {
29
+ const res = await fetch("https://api.tailscale.com/api/v2/oauth/token", {
30
+ method: "POST",
31
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
32
+ body: new URLSearchParams({
33
+ client_id: clientId,
34
+ client_secret: clientSecret,
35
+ grant_type: "client_credentials",
36
+ }),
37
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
38
+ });
39
+ if (!res.ok) {
40
+ const body = await res.text();
41
+ throw new Error(`OAuth token exchange failed (${res.status}): ${body}`);
42
+ }
43
+ const data = (await res.json());
44
+ oauthToken = {
45
+ access_token: data.access_token,
46
+ expires_at: Date.now() + data.expires_in * 1000,
47
+ };
48
+ return oauthToken.access_token;
49
+ }
50
+ finally {
51
+ oauthRefreshPromise = null;
52
+ }
53
+ })();
54
+ return oauthRefreshPromise;
40
55
  }
41
56
  async function getAuthHeader() {
42
57
  const config = getConfig();
@@ -74,6 +89,7 @@ export async function apiRequest(method, path, body, options) {
74
89
  method,
75
90
  headers,
76
91
  body: fetchBody,
92
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
77
93
  });
78
94
  const etag = res.headers.get("etag") || undefined;
79
95
  if (options?.acceptRaw) {
@@ -85,13 +101,13 @@ export async function apiRequest(method, path, body, options) {
85
101
  }
86
102
  if (!res.ok) {
87
103
  const errorBody = await res.text();
88
- return { ok: false, status: res.status, error: errorBody };
104
+ return { ok: false, status: res.status, error: errorBody, etag };
89
105
  }
90
106
  if (res.status === 204 || res.headers.get("content-length") === "0") {
91
- return { ok: true, status: res.status };
107
+ return { ok: true, status: res.status, etag };
92
108
  }
93
109
  const data = (await res.json());
94
- return { ok: true, status: res.status, data };
110
+ return { ok: true, status: res.status, data, etag };
95
111
  }
96
112
  export async function apiGet(path, options) {
97
113
  return apiRequest("GET", path, undefined, options);
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,218 @@
1
+ import { describe, it, beforeEach, afterEach } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ // We need to mock fetch before importing api module, so we use dynamic imports
4
+ // and mock global.fetch
5
+ function mockFetchResponse(status, body, headers) {
6
+ const responseHeaders = new Headers(headers);
7
+ return new Response(typeof body === "string" ? body : JSON.stringify(body), { status, headers: responseHeaders });
8
+ }
9
+ describe("API client", () => {
10
+ const originalFetch = globalThis.fetch;
11
+ const originalEnv = { ...process.env };
12
+ let apiModule;
13
+ beforeEach(async () => {
14
+ // Reset env for each test
15
+ process.env.TAILSCALE_API_KEY = "tskey-api-test123";
16
+ delete process.env.TAILSCALE_OAUTH_CLIENT_ID;
17
+ delete process.env.TAILSCALE_OAUTH_CLIENT_SECRET;
18
+ process.env.TAILSCALE_TAILNET = "test.tailnet.ts.net";
19
+ // Dynamic import to get fresh module reference
20
+ apiModule = await import("./api.js");
21
+ });
22
+ afterEach(() => {
23
+ globalThis.fetch = originalFetch;
24
+ Object.keys(process.env).forEach((key) => {
25
+ if (!(key in originalEnv))
26
+ delete process.env[key];
27
+ else
28
+ process.env[key] = originalEnv[key];
29
+ });
30
+ });
31
+ describe("getTailnet", () => {
32
+ it("should return the configured tailnet", () => {
33
+ process.env.TAILSCALE_TAILNET = "my.tailnet.ts.net";
34
+ assert.equal(apiModule.getTailnet(), "my.tailnet.ts.net");
35
+ });
36
+ it("should return '-' when no tailnet is configured", () => {
37
+ delete process.env.TAILSCALE_TAILNET;
38
+ assert.equal(apiModule.getTailnet(), "-");
39
+ });
40
+ });
41
+ describe("apiGet", () => {
42
+ it("should make a GET request with correct auth header", async () => {
43
+ let capturedRequest;
44
+ globalThis.fetch = async (input, init) => {
45
+ const url = typeof input === "string" ? input : input.toString();
46
+ capturedRequest = { url, method: init?.method ?? "GET", headers: new Headers(init?.headers) };
47
+ return mockFetchResponse(200, { devices: [] });
48
+ };
49
+ const res = await apiModule.apiGet("/tailnet/test/devices");
50
+ assert.ok(res.ok);
51
+ assert.equal(res.status, 200);
52
+ assert.ok(capturedRequest);
53
+ assert.equal(capturedRequest.url, "https://api.tailscale.com/api/v2/tailnet/test/devices");
54
+ assert.ok(capturedRequest.headers.get("Authorization")?.startsWith("Basic "));
55
+ });
56
+ it("should return error on non-ok response", async () => {
57
+ globalThis.fetch = async () => mockFetchResponse(403, "Forbidden");
58
+ const res = await apiModule.apiGet("/tailnet/test/devices");
59
+ assert.equal(res.ok, false);
60
+ assert.equal(res.status, 403);
61
+ assert.equal(res.error, "Forbidden");
62
+ });
63
+ it("should return raw body when acceptRaw is true", async () => {
64
+ globalThis.fetch = async () => mockFetchResponse(200, "raw text content", { etag: '"abc123"' });
65
+ const res = await apiModule.apiGet("/tailnet/test/acl", { acceptRaw: true });
66
+ assert.ok(res.ok);
67
+ assert.equal(res.rawBody, "raw text content");
68
+ assert.equal(res.etag, '"abc123"');
69
+ });
70
+ it("should handle 204 no-content responses", async () => {
71
+ globalThis.fetch = async () => new Response(null, { status: 204 });
72
+ const res = await apiModule.apiGet("/some/endpoint");
73
+ assert.ok(res.ok);
74
+ assert.equal(res.status, 204);
75
+ assert.equal(res.data, undefined);
76
+ });
77
+ it("should include etag in all response types", async () => {
78
+ // JSON success
79
+ globalThis.fetch = async () => mockFetchResponse(200, { ok: true }, { etag: '"json-etag"' });
80
+ let res = await apiModule.apiGet("/test");
81
+ assert.equal(res.etag, '"json-etag"');
82
+ // Error response
83
+ globalThis.fetch = async () => mockFetchResponse(500, "error", { etag: '"err-etag"' });
84
+ res = await apiModule.apiGet("/test");
85
+ assert.equal(res.etag, '"err-etag"');
86
+ });
87
+ });
88
+ describe("apiPost", () => {
89
+ it("should send JSON body", async () => {
90
+ let capturedBody;
91
+ let capturedContentType;
92
+ globalThis.fetch = async (_input, init) => {
93
+ capturedBody = init?.body;
94
+ capturedContentType = new Headers(init?.headers).get("Content-Type") ?? undefined;
95
+ return mockFetchResponse(200, { success: true });
96
+ };
97
+ await apiModule.apiPost("/test", { key: "value" });
98
+ assert.equal(capturedContentType, "application/json");
99
+ assert.equal(capturedBody, '{"key":"value"}');
100
+ });
101
+ it("should send raw body with custom content type", async () => {
102
+ let capturedBody;
103
+ let capturedContentType;
104
+ globalThis.fetch = async (_input, init) => {
105
+ capturedBody = init?.body;
106
+ capturedContentType = new Headers(init?.headers).get("Content-Type") ?? undefined;
107
+ return mockFetchResponse(200, { success: true });
108
+ };
109
+ await apiModule.apiPost("/test", undefined, {
110
+ rawBody: '{ /* hujson */ }',
111
+ contentType: "application/hujson",
112
+ });
113
+ assert.equal(capturedContentType, "application/hujson");
114
+ assert.equal(capturedBody, '{ /* hujson */ }');
115
+ });
116
+ it("should send If-Match header when ifMatch is provided", async () => {
117
+ let capturedHeaders;
118
+ globalThis.fetch = async (_input, init) => {
119
+ capturedHeaders = new Headers(init?.headers);
120
+ return mockFetchResponse(200, { success: true });
121
+ };
122
+ await apiModule.apiPost("/test", undefined, {
123
+ rawBody: "body",
124
+ ifMatch: '"etag-value"',
125
+ });
126
+ assert.equal(capturedHeaders?.get("If-Match"), '"etag-value"');
127
+ });
128
+ });
129
+ describe("apiPatch", () => {
130
+ it("should make a PATCH request", async () => {
131
+ let capturedMethod;
132
+ globalThis.fetch = async (_input, init) => {
133
+ capturedMethod = init?.method;
134
+ return mockFetchResponse(200, { updated: true });
135
+ };
136
+ const res = await apiModule.apiPatch("/test", { field: "value" });
137
+ assert.ok(res.ok);
138
+ assert.equal(capturedMethod, "PATCH");
139
+ });
140
+ });
141
+ describe("apiDelete", () => {
142
+ it("should make a DELETE request", async () => {
143
+ let capturedMethod;
144
+ globalThis.fetch = async (_input, init) => {
145
+ capturedMethod = init?.method;
146
+ return mockFetchResponse(200, {});
147
+ };
148
+ const res = await apiModule.apiDelete("/test");
149
+ assert.ok(res.ok);
150
+ assert.equal(capturedMethod, "DELETE");
151
+ });
152
+ });
153
+ describe("apiRequest with absolute URL", () => {
154
+ it("should use absolute URL as-is without prepending base URL", async () => {
155
+ let capturedUrl;
156
+ globalThis.fetch = async (input, _init) => {
157
+ capturedUrl = typeof input === "string" ? input : input.toString();
158
+ return mockFetchResponse(200, {});
159
+ };
160
+ await apiModule.apiGet("https://custom.api.example.com/endpoint");
161
+ assert.equal(capturedUrl, "https://custom.api.example.com/endpoint");
162
+ });
163
+ });
164
+ describe("Authentication", () => {
165
+ it("should throw when no credentials are configured", async () => {
166
+ delete process.env.TAILSCALE_API_KEY;
167
+ delete process.env.TAILSCALE_OAUTH_CLIENT_ID;
168
+ delete process.env.TAILSCALE_OAUTH_CLIENT_SECRET;
169
+ globalThis.fetch = async () => mockFetchResponse(200, {});
170
+ await assert.rejects(() => apiModule.apiGet("/test"), { message: /No Tailscale credentials configured/ });
171
+ });
172
+ it("should use Basic auth with API key", async () => {
173
+ process.env.TAILSCALE_API_KEY = "tskey-api-mykey";
174
+ let capturedAuth;
175
+ globalThis.fetch = async (_input, init) => {
176
+ capturedAuth = new Headers(init?.headers).get("Authorization") ?? undefined;
177
+ return mockFetchResponse(200, {});
178
+ };
179
+ await apiModule.apiGet("/test");
180
+ const expected = `Basic ${Buffer.from("tskey-api-mykey:").toString("base64")}`;
181
+ assert.equal(capturedAuth, expected);
182
+ });
183
+ it("should use Bearer auth with OAuth", async () => {
184
+ delete process.env.TAILSCALE_API_KEY;
185
+ process.env.TAILSCALE_OAUTH_CLIENT_ID = "client-id";
186
+ process.env.TAILSCALE_OAUTH_CLIENT_SECRET = "client-secret";
187
+ let callCount = 0;
188
+ let capturedAuth;
189
+ globalThis.fetch = async (input, init) => {
190
+ callCount++;
191
+ const url = typeof input === "string" ? input : input.toString();
192
+ if (url.includes("/oauth/token")) {
193
+ return mockFetchResponse(200, {
194
+ access_token: "oauth-token-123",
195
+ expires_in: 3600,
196
+ });
197
+ }
198
+ capturedAuth = new Headers(init?.headers).get("Authorization") ?? undefined;
199
+ return mockFetchResponse(200, {});
200
+ };
201
+ await apiModule.apiGet("/test");
202
+ assert.equal(capturedAuth, "Bearer oauth-token-123");
203
+ assert.equal(callCount, 2); // token + actual request
204
+ });
205
+ });
206
+ describe("Request timeout", () => {
207
+ it("should pass an AbortSignal to fetch", async () => {
208
+ let capturedSignal;
209
+ globalThis.fetch = async (_input, init) => {
210
+ capturedSignal = init?.signal ?? undefined;
211
+ return mockFetchResponse(200, {});
212
+ };
213
+ await apiModule.apiGet("/test");
214
+ assert.ok(capturedSignal, "AbortSignal should be present");
215
+ });
216
+ });
217
+ });
218
+ //# sourceMappingURL=api.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.test.js","sourceRoot":"","sources":["../src/api.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,218 @@
1
+ import { describe, it, beforeEach, afterEach } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ function mockFetchResponse(status, body, headers) {
4
+ return new Response(typeof body === "string" ? body : JSON.stringify(body), { status, headers: new Headers(headers) });
5
+ }
6
+ describe("Tool handlers", () => {
7
+ const originalFetch = globalThis.fetch;
8
+ const originalEnv = { ...process.env };
9
+ beforeEach(() => {
10
+ process.env.TAILSCALE_API_KEY = "tskey-api-test";
11
+ process.env.TAILSCALE_TAILNET = "test.ts.net";
12
+ });
13
+ afterEach(() => {
14
+ globalThis.fetch = originalFetch;
15
+ Object.keys(process.env).forEach((key) => {
16
+ if (!(key in originalEnv))
17
+ delete process.env[key];
18
+ else
19
+ process.env[key] = originalEnv[key];
20
+ });
21
+ });
22
+ describe("tailscale_status", () => {
23
+ it("should make parallel requests for devices and settings", async () => {
24
+ const { statusTools } = await import("./tools/status.js");
25
+ const urls = [];
26
+ globalThis.fetch = async (input) => {
27
+ const url = typeof input === "string" ? input : input.toString();
28
+ urls.push(url);
29
+ if (url.includes("/devices")) {
30
+ return mockFetchResponse(200, { devices: [{ id: "1" }, { id: "2" }] });
31
+ }
32
+ return mockFetchResponse(200, { devicesApprovalOn: true });
33
+ };
34
+ const handler = statusTools[0].handler;
35
+ const result = await handler();
36
+ assert.ok(result.ok);
37
+ assert.equal(result.data.deviceCount, 2);
38
+ assert.equal(result.data.connected, true);
39
+ assert.ok(urls.some((u) => u.includes("/devices")));
40
+ assert.ok(urls.some((u) => u.includes("/settings")));
41
+ });
42
+ });
43
+ describe("tailscale_list_devices", () => {
44
+ it("should pass fields parameter when provided", async () => {
45
+ const { deviceTools } = await import("./tools/devices.js");
46
+ let capturedUrl = "";
47
+ globalThis.fetch = async (input) => {
48
+ capturedUrl = typeof input === "string" ? input : input.toString();
49
+ return mockFetchResponse(200, { devices: [] });
50
+ };
51
+ const handler = deviceTools[0].handler;
52
+ await handler({ fields: "id,name,addresses" });
53
+ assert.ok(capturedUrl.includes("fields=id%2Cname%2Caddresses"));
54
+ });
55
+ it("should not include fields parameter when omitted", async () => {
56
+ const { deviceTools } = await import("./tools/devices.js");
57
+ let capturedUrl = "";
58
+ globalThis.fetch = async (input) => {
59
+ capturedUrl = typeof input === "string" ? input : input.toString();
60
+ return mockFetchResponse(200, { devices: [] });
61
+ };
62
+ const handler = deviceTools[0].handler;
63
+ await handler({});
64
+ assert.ok(!capturedUrl.includes("fields="));
65
+ });
66
+ });
67
+ describe("tailscale_get_acl", () => {
68
+ it("should append ETag instructions to raw body", async () => {
69
+ const { aclTools } = await import("./tools/acl.js");
70
+ globalThis.fetch = async () => new Response('{ "acls": [] }', {
71
+ status: 200,
72
+ headers: { etag: '"acl-etag-1"' },
73
+ });
74
+ const handler = aclTools[0].handler;
75
+ const result = await handler();
76
+ assert.ok(result.ok);
77
+ assert.ok(result.rawBody.includes('{ "acls": [] }'));
78
+ assert.ok(result.rawBody.includes("ETag:"));
79
+ assert.ok(result.rawBody.includes('"acl-etag-1"'));
80
+ });
81
+ });
82
+ describe("tailscale_validate_acl", () => {
83
+ it("should return friendly message on successful validation", async () => {
84
+ const { aclTools } = await import("./tools/acl.js");
85
+ globalThis.fetch = async () => new Response(null, { status: 200, headers: { "content-length": "0" } });
86
+ const handler = aclTools[2].handler;
87
+ const result = await handler({ policy: '{ "acls": [] }' });
88
+ assert.ok(result.ok);
89
+ assert.equal(result.data?.message, "ACL policy is valid.");
90
+ });
91
+ });
92
+ describe("tailscale_update_acl", () => {
93
+ it("should send raw HuJSON body with If-Match header", async () => {
94
+ const { aclTools } = await import("./tools/acl.js");
95
+ let capturedHeaders;
96
+ let capturedBody;
97
+ globalThis.fetch = async (_input, init) => {
98
+ capturedHeaders = new Headers(init?.headers);
99
+ capturedBody = init?.body;
100
+ return mockFetchResponse(200, { success: true });
101
+ };
102
+ const handler = aclTools[1].handler;
103
+ await handler({ policy: '{ /* hujson */ "acls": [] }', etag: '"etag-1"' });
104
+ assert.equal(capturedHeaders?.get("If-Match"), '"etag-1"');
105
+ assert.equal(capturedHeaders?.get("Content-Type"), "application/hujson");
106
+ assert.equal(capturedBody, '{ /* hujson */ "acls": [] }');
107
+ });
108
+ });
109
+ describe("tailscale_create_key", () => {
110
+ it("should include expirySeconds when set to a number", async () => {
111
+ const { keyTools } = await import("./tools/keys.js");
112
+ let capturedBody;
113
+ globalThis.fetch = async (_input, init) => {
114
+ capturedBody = init?.body;
115
+ return mockFetchResponse(200, { key: "tskey-auth-test" });
116
+ };
117
+ const handler = keyTools[2].handler;
118
+ await handler({ expirySeconds: 3600, description: "test key" });
119
+ const parsed = JSON.parse(capturedBody);
120
+ assert.equal(parsed.expirySeconds, 3600);
121
+ assert.equal(parsed.description, "test key");
122
+ });
123
+ it("should include description even if empty string", async () => {
124
+ const { keyTools } = await import("./tools/keys.js");
125
+ let capturedBody;
126
+ globalThis.fetch = async (_input, init) => {
127
+ capturedBody = init?.body;
128
+ return mockFetchResponse(200, { key: "tskey-auth-test" });
129
+ };
130
+ const handler = keyTools[2].handler;
131
+ await handler({ description: "" });
132
+ const parsed = JSON.parse(capturedBody);
133
+ assert.equal(parsed.description, "");
134
+ });
135
+ });
136
+ describe("tailscale_update_tailnet_settings", () => {
137
+ it("should only send defined fields to the API", async () => {
138
+ const { tailnetTools } = await import("./tools/tailnet.js");
139
+ let capturedBody;
140
+ globalThis.fetch = async (_input, init) => {
141
+ capturedBody = init?.body;
142
+ return mockFetchResponse(200, { success: true });
143
+ };
144
+ // The update tool is index 1
145
+ const handler = tailnetTools[1].handler;
146
+ await handler({ devicesApprovalOn: true });
147
+ const parsed = JSON.parse(capturedBody);
148
+ assert.deepEqual(parsed, { devicesApprovalOn: true });
149
+ assert.ok(!("devicesAutoUpdatesOn" in parsed));
150
+ });
151
+ });
152
+ describe("tailscale_update_webhook", () => {
153
+ it("should PATCH webhook subscriptions", async () => {
154
+ const { webhookTools } = await import("./tools/webhooks.js");
155
+ let capturedMethod;
156
+ let capturedUrl;
157
+ let capturedBody;
158
+ globalThis.fetch = async (input, init) => {
159
+ capturedUrl = typeof input === "string" ? input : input.toString();
160
+ capturedMethod = init?.method;
161
+ capturedBody = init?.body;
162
+ return mockFetchResponse(200, { id: "wh-123" });
163
+ };
164
+ // The update tool is index 3
165
+ const handler = webhookTools[3].handler;
166
+ await handler({ webhookId: "wh-123", subscriptions: ["nodeCreated", "policyUpdate"] });
167
+ assert.equal(capturedMethod, "PATCH");
168
+ assert.ok(capturedUrl?.includes("/webhooks/wh-123"));
169
+ const parsed = JSON.parse(capturedBody);
170
+ assert.deepEqual(parsed.subscriptions, ["nodeCreated", "policyUpdate"]);
171
+ });
172
+ });
173
+ describe("tailscale_get_network_lock_status", () => {
174
+ it("should call the correct network-lock endpoint", async () => {
175
+ const { networkLockTools } = await import("./tools/network-lock.js");
176
+ let capturedUrl = "";
177
+ globalThis.fetch = async (input) => {
178
+ capturedUrl = typeof input === "string" ? input : input.toString();
179
+ return mockFetchResponse(200, { enabled: false });
180
+ };
181
+ const handler = networkLockTools[0].handler;
182
+ await handler();
183
+ assert.ok(capturedUrl.includes("/network-lock/status"), `Expected URL to contain /network-lock/status, got: ${capturedUrl}`);
184
+ });
185
+ });
186
+ describe("tailscale_get_audit_log", () => {
187
+ it("should pass start and end params", async () => {
188
+ const { auditTools } = await import("./tools/audit.js");
189
+ let capturedUrl = "";
190
+ globalThis.fetch = async (input) => {
191
+ capturedUrl = typeof input === "string" ? input : input.toString();
192
+ return mockFetchResponse(200, { logs: [] });
193
+ };
194
+ const handler = auditTools[0].handler;
195
+ await handler({ start: "2026-01-01T00:00:00Z", end: "2026-01-31T23:59:59Z" });
196
+ assert.ok(capturedUrl.includes("start=2026-01-01T00%3A00%3A00Z"));
197
+ assert.ok(capturedUrl.includes("end=2026-01-31T23%3A59%3A59Z"));
198
+ });
199
+ });
200
+ describe("tailscale_set_contacts", () => {
201
+ it("should only send provided contact fields", async () => {
202
+ const { tailnetTools } = await import("./tools/tailnet.js");
203
+ let capturedBody;
204
+ globalThis.fetch = async (_input, init) => {
205
+ capturedBody = init?.body;
206
+ return mockFetchResponse(200, {});
207
+ };
208
+ // set_contacts is index 3
209
+ const handler = tailnetTools[3].handler;
210
+ await handler({ security: { email: "sec@example.com" } });
211
+ const parsed = JSON.parse(capturedBody);
212
+ assert.deepEqual(parsed, { security: { email: "sec@example.com" } });
213
+ assert.ok(!("account" in parsed));
214
+ assert.ok(!("support" in parsed));
215
+ });
216
+ });
217
+ });
218
+ //# sourceMappingURL=handlers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.test.js","sourceRoot":"","sources":["../src/handlers.test.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ const allTools = [
27
27
  ];
28
28
  const server = new McpServer({
29
29
  name: "@yawlabs/tailscale-mcp",
30
- version: "0.1.0",
30
+ version: "0.1.2",
31
31
  });
32
32
  for (const tool of allTools) {
33
33
  server.tool(tool.name, tool.description, tool.inputSchema.shape, async (input) => {
@@ -23,7 +23,7 @@ export declare const aclTools: readonly [{
23
23
  }) => Promise<import("../api.js").ApiResponse<unknown>>;
24
24
  }, {
25
25
  readonly name: "tailscale_validate_acl";
26
- readonly description: "Validate an ACL policy without applying it. Returns any errors found.";
26
+ readonly description: "Validate an ACL policy without applying it. Returns any errors found, or confirms the policy is valid.";
27
27
  readonly inputSchema: z.ZodObject<{
28
28
  policy: z.ZodString;
29
29
  }, "strip", z.ZodTypeAny, {
package/dist/tools/acl.js CHANGED
@@ -40,15 +40,19 @@ export const aclTools = [
40
40
  },
41
41
  {
42
42
  name: "tailscale_validate_acl",
43
- description: "Validate an ACL policy without applying it. Returns any errors found.",
43
+ description: "Validate an ACL policy without applying it. Returns any errors found, or confirms the policy is valid.",
44
44
  inputSchema: z.object({
45
45
  policy: z.string().describe("The full ACL policy text to validate"),
46
46
  }),
47
47
  handler: async (input) => {
48
- return apiPost(`/tailnet/${getTailnet()}/acl/validate`, undefined, {
48
+ const res = await apiPost(`/tailnet/${getTailnet()}/acl/validate`, undefined, {
49
49
  rawBody: input.policy,
50
50
  contentType: "application/hujson",
51
51
  });
52
+ if (res.ok && !res.data) {
53
+ return { ...res, data: { message: "ACL policy is valid." } };
54
+ }
55
+ return res;
52
56
  },
53
57
  },
54
58
  {
@@ -1 +1 @@
1
- {"version":3,"file":"acl.js","sourceRoot":"","sources":["../../src/tools/acl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acl.js","sourceRoot":"","sources":["../../src/tools/acl.ts"],"names":[],"mappings":"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"}
@@ -40,7 +40,7 @@ export declare const deviceTools: readonly [{
40
40
  }) => Promise<import("../api.js").ApiResponse<unknown>>;
41
41
  }, {
42
42
  readonly name: "tailscale_deauthorize_device";
43
- readonly description: "Deauthorize a device, removing its access to the tailnet.";
43
+ readonly description: "Deauthorize a device, immediately removing its access to the tailnet. The device will need to be re-authorized to reconnect.";
44
44
  readonly inputSchema: z.ZodObject<{
45
45
  deviceId: z.ZodString;
46
46
  }, "strip", z.ZodTypeAny, {
@@ -53,7 +53,7 @@ export declare const deviceTools: readonly [{
53
53
  }) => Promise<import("../api.js").ApiResponse<unknown>>;
54
54
  }, {
55
55
  readonly name: "tailscale_delete_device";
56
- readonly description: "Delete a device from the tailnet. The device can re-authenticate to rejoin.";
56
+ readonly description: "Permanently remove a device from the tailnet. This is irreversible — the device must re-authenticate to rejoin.";
57
57
  readonly inputSchema: z.ZodObject<{
58
58
  deviceId: z.ZodString;
59
59
  }, "strip", z.ZodTypeAny, {
@@ -37,7 +37,7 @@ export const deviceTools = [
37
37
  },
38
38
  {
39
39
  name: "tailscale_deauthorize_device",
40
- description: "Deauthorize a device, removing its access to the tailnet.",
40
+ description: "Deauthorize a device, immediately removing its access to the tailnet. The device will need to be re-authorized to reconnect.",
41
41
  inputSchema: z.object({
42
42
  deviceId: z.string().describe("The device ID to deauthorize"),
43
43
  }),
@@ -47,7 +47,7 @@ export const deviceTools = [
47
47
  },
48
48
  {
49
49
  name: "tailscale_delete_device",
50
- description: "Delete a device from the tailnet. The device can re-authenticate to rejoin.",
50
+ description: "Permanently remove a device from the tailnet. This is irreversible — the device must re-authenticate to rejoin.",
51
51
  inputSchema: z.object({
52
52
  deviceId: z.string().describe("The device ID to delete"),
53
53
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"devices.js","sourceRoot":"","sources":["../../src/tools/devices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEnE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,2FAA2F;QACxG,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,ubAAub,CACxb;SACJ,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA0B,EAAE,EAAE;YAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,WAAW,MAAM,EAAE,CAAC,CAAC;QAC7D,CAAC;KACF;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,6DAA6D;QAC1E,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;SAC3E,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2B,EAAE,EAAE;YAC7C,OAAO,MAAM,CAAC,WAAW,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7C,CAAC;KACF;IACD;QACE,IAAI,EAAE,4BAA4B;QAClC,WAAW,EAAE,mDAAmD;QAChE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;SAC5D,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2B,EAAE,EAAE;YAC7C,OAAO,OAAO,CAAC,WAAW,KAAK,CAAC,QAAQ,aAAa,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;KACF;IACD;QACE,IAAI,EAAE,8BAA8B;QACpC,WAAW,EAAE,2DAA2D;QACxE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;SAC9D,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2B,EAAE,EAAE;YAC7C,OAAO,OAAO,CAAC,WAAW,KAAK,CAAC,QAAQ,aAAa,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QAChF,CAAC;KACF;IACD;QACE,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,6EAA6E;QAC1F,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;SACzD,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2B,EAAE,EAAE;YAC7C,OAAO,SAAS,CAAC,WAAW,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC;KACF;IACD;QACE,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,0CAA0C;QACvD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;YACxD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;SACpF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAAyC,EAAE,EAAE;YAC3D,OAAO,OAAO,CAAC,WAAW,KAAK,CAAC,QAAQ,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;KACF;IACD;QACE,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,uDAAuD;QACpE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;SACzD,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2B,EAAE,EAAE;YAC7C,OAAO,OAAO,CAAC,WAAW,KAAK,CAAC,QAAQ,SAAS,CAAC,CAAC;QACrD,CAAC;KACF;IACD;QACE,IAAI,EAAE,6BAA6B;QACnC,WAAW,EAAE,kEAAkE;QAC/E,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;SAC/C,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2B,EAAE,EAAE;YAC7C,OAAO,MAAM,CAAC,WAAW,KAAK,CAAC,QAAQ,SAAS,CAAC,CAAC;QACpD,CAAC;KACF;IACD;QACE,IAAI,EAAE,6BAA6B;QACnC,WAAW,EAAE,+CAA+C;QAC5D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC9C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,wEAAwE,CAAC;SAC/G,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA6C,EAAE,EAAE;YAC/D,OAAO,OAAO,CAAC,WAAW,KAAK,CAAC,QAAQ,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/E,CAAC;KACF;IACD;QACE,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,uDAAuD;QACpE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC9C,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,0DAA0D,CAAC;SAC/F,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA2C,EAAE,EAAE;YAC7D,OAAO,OAAO,CAAC,WAAW,KAAK,CAAC,QAAQ,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;KACF;CACO,CAAC"}
1
+ {"version":3,"file":"devices.js","sourceRoot":"","sources":["../../src/tools/devices.ts"],"names":[],"mappings":"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"}
@@ -43,9 +43,9 @@ export const keyTools = [
43
43
  },
44
44
  },
45
45
  };
46
- if (input.expirySeconds)
46
+ if (input.expirySeconds !== undefined)
47
47
  body.expirySeconds = input.expirySeconds;
48
- if (input.description)
48
+ if (input.description !== undefined)
49
49
  body.description = input.description;
50
50
  return apiPost(`/tailnet/${getTailnet()}/keys`, body);
51
51
  },
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/tools/keys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/tools/keys.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  export declare const networkLockTools: readonly [{
3
- readonly name: "tailscale_get_tailnet_keys";
4
- readonly description: "Get the tailnet's auth keys and their capabilities, including tailnet lock signing key information if tailnet lock is enabled.";
3
+ readonly name: "tailscale_get_network_lock_status";
4
+ readonly description: "Get the tailnet lock (network lock) status, including whether it is enabled and the list of trusted signing keys.";
5
5
  readonly inputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
6
6
  readonly handler: () => Promise<import("../api.js").ApiResponse<unknown>>;
7
7
  }];
@@ -2,11 +2,11 @@ import { z } from "zod";
2
2
  import { apiGet, getTailnet } from "../api.js";
3
3
  export const networkLockTools = [
4
4
  {
5
- name: "tailscale_get_tailnet_keys",
6
- description: "Get the tailnet's auth keys and their capabilities, including tailnet lock signing key information if tailnet lock is enabled.",
5
+ name: "tailscale_get_network_lock_status",
6
+ description: "Get the tailnet lock (network lock) status, including whether it is enabled and the list of trusted signing keys.",
7
7
  inputSchema: z.object({}),
8
8
  handler: async () => {
9
- return apiGet(`/tailnet/${getTailnet()}/keys`);
9
+ return apiGet(`/tailnet/${getTailnet()}/network-lock/status`);
10
10
  },
11
11
  },
12
12
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"network-lock.js","sourceRoot":"","sources":["../../src/tools/network-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;QACE,IAAI,EAAE,4BAA4B;QAClC,WAAW,EACT,gIAAgI;QAClI,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;KACF;CACO,CAAC"}
1
+ {"version":3,"file":"network-lock.js","sourceRoot":"","sources":["../../src/tools/network-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;QACE,IAAI,EAAE,mCAAmC;QACzC,WAAW,EACT,mHAAmH;QACrH,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,sBAAsB,CAAC,CAAC;QAChE,CAAC;KACF;CACO,CAAC"}
@@ -6,12 +6,14 @@ export const statusTools = [
6
6
  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.",
7
7
  inputSchema: z.object({}),
8
8
  handler: async () => {
9
- const devicesRes = await apiGet(`/tailnet/${getTailnet()}/devices?fields=id`);
9
+ const [devicesRes, settingsRes] = await Promise.all([
10
+ apiGet(`/tailnet/${getTailnet()}/devices?fields=id`),
11
+ apiGet(`/tailnet/${getTailnet()}/settings`),
12
+ ]);
10
13
  if (!devicesRes.ok) {
11
14
  return devicesRes;
12
15
  }
13
16
  const deviceCount = devicesRes.data?.devices?.length ?? 0;
14
- const settingsRes = await apiGet(`/tailnet/${getTailnet()}/settings`);
15
17
  return {
16
18
  ok: true,
17
19
  status: 200,
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/tools/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,8JAA8J;QAChK,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,UAAU,GAAG,MAAM,MAAM,CAC7B,YAAY,UAAU,EAAE,oBAAoB,CAC7C,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;gBACnB,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;YAE1D,MAAM,WAAW,GAAG,MAAM,MAAM,CAC9B,YAAY,UAAU,EAAE,WAAW,CACpC,CAAC;YAEF,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE;oBACJ,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,UAAU,EAAE;oBACrB,WAAW;oBACX,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;iBACxD;aACF,CAAC;QACJ,CAAC;KACF;CACO,CAAC"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/tools/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,8JAA8J;QAChK,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAClD,MAAM,CAAyB,YAAY,UAAU,EAAE,oBAAoB,CAAC;gBAC5E,MAAM,CAA0B,YAAY,UAAU,EAAE,WAAW,CAAC;aACrE,CAAC,CAAC;YAEH,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;gBACnB,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;YAE1D,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE;oBACJ,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,UAAU,EAAE;oBACrB,WAAW;oBACX,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;iBACxD;aACF,CAAC;QACJ,CAAC;KACF;CACO,CAAC"}
@@ -29,7 +29,14 @@ export declare const tailnetTools: readonly [{
29
29
  networkFlowLoggingOn?: boolean | undefined;
30
30
  regionalRoutingOn?: boolean | undefined;
31
31
  }>;
32
- readonly handler: (input: Record<string, unknown>) => Promise<import("../api.js").ApiResponse<unknown>>;
32
+ readonly handler: (input: {
33
+ devicesApprovalOn?: boolean;
34
+ devicesAutoUpdatesOn?: boolean;
35
+ devicesKeyDurationDays?: number;
36
+ usersApprovalOn?: boolean;
37
+ networkFlowLoggingOn?: boolean;
38
+ regionalRoutingOn?: boolean;
39
+ }) => Promise<import("../api.js").ApiResponse<unknown>>;
33
40
  }, {
34
41
  readonly name: "tailscale_get_contacts";
35
42
  readonly description: "Get the tailnet contact information (security, support, admin emails).";
@@ -81,5 +88,15 @@ export declare const tailnetTools: readonly [{
81
88
  email: string;
82
89
  } | undefined;
83
90
  }>;
84
- readonly handler: (input: Record<string, unknown>) => Promise<import("../api.js").ApiResponse<unknown>>;
91
+ readonly handler: (input: {
92
+ account?: {
93
+ email: string;
94
+ };
95
+ support?: {
96
+ email: string;
97
+ };
98
+ security?: {
99
+ email: string;
100
+ };
101
+ }) => Promise<import("../api.js").ApiResponse<unknown>>;
85
102
  }];
@@ -21,7 +21,20 @@ export const tailnetTools = [
21
21
  regionalRoutingOn: z.boolean().optional().describe("Whether regional routing is enabled"),
22
22
  }),
23
23
  handler: async (input) => {
24
- return apiPatch(`/tailnet/${getTailnet()}/settings`, input);
24
+ const body = {};
25
+ if (input.devicesApprovalOn !== undefined)
26
+ body.devicesApprovalOn = input.devicesApprovalOn;
27
+ if (input.devicesAutoUpdatesOn !== undefined)
28
+ body.devicesAutoUpdatesOn = input.devicesAutoUpdatesOn;
29
+ if (input.devicesKeyDurationDays !== undefined)
30
+ body.devicesKeyDurationDays = input.devicesKeyDurationDays;
31
+ if (input.usersApprovalOn !== undefined)
32
+ body.usersApprovalOn = input.usersApprovalOn;
33
+ if (input.networkFlowLoggingOn !== undefined)
34
+ body.networkFlowLoggingOn = input.networkFlowLoggingOn;
35
+ if (input.regionalRoutingOn !== undefined)
36
+ body.regionalRoutingOn = input.regionalRoutingOn;
37
+ return apiPatch(`/tailnet/${getTailnet()}/settings`, body);
25
38
  },
26
39
  },
27
40
  {
@@ -41,7 +54,14 @@ export const tailnetTools = [
41
54
  security: z.object({ email: z.string() }).optional().describe("Security contact email"),
42
55
  }),
43
56
  handler: async (input) => {
44
- return apiPatch(`/tailnet/${getTailnet()}/contacts`, input);
57
+ const body = {};
58
+ if (input.account !== undefined)
59
+ body.account = input.account;
60
+ if (input.support !== undefined)
61
+ body.support = input.support;
62
+ if (input.security !== undefined)
63
+ body.security = input.security;
64
+ return apiPatch(`/tailnet/${getTailnet()}/contacts`, body);
45
65
  },
46
66
  },
47
67
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"tailnet.js","sourceRoot":"","sources":["../../src/tools/tailnet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEzD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;QACE,IAAI,EAAE,gCAAgC;QACtC,WAAW,EAAE,gEAAgE;QAC7E,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,WAAW,CAAC,CAAC;QACrD,CAAC;KACF;IACD;QACE,IAAI,EAAE,mCAAmC;QACzC,WAAW,EAAE,0BAA0B;QACvC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YACzF,oBAAoB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;YACzF,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YACrF,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YACrF,oBAAoB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YAChG,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;SAC1F,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA8B,EAAE,EAAE;YAChD,OAAO,QAAQ,CAAC,YAAY,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;KACF;IACD;QACE,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,wEAAwE;QACrF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,WAAW,CAAC,CAAC;QACrD,CAAC;KACF;IACD;QACE,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,qCAAqC;QAClD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACrF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACrF,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;SACxF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA8B,EAAE,EAAE;YAChD,OAAO,QAAQ,CAAC,YAAY,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;KACF;CACO,CAAC"}
1
+ {"version":3,"file":"tailnet.js","sourceRoot":"","sources":["../../src/tools/tailnet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { deviceTools } from "./devices.js";
4
+ import { aclTools } from "./acl.js";
5
+ import { dnsTools } from "./dns.js";
6
+ import { keyTools } from "./keys.js";
7
+ import { userTools } from "./users.js";
8
+ import { tailnetTools } from "./tailnet.js";
9
+ import { webhookTools } from "./webhooks.js";
10
+ import { networkLockTools } from "./network-lock.js";
11
+ import { postureTools } from "./posture.js";
12
+ import { auditTools } from "./audit.js";
13
+ import { statusTools } from "./status.js";
14
+ const allTools = [
15
+ ...statusTools,
16
+ ...deviceTools,
17
+ ...aclTools,
18
+ ...dnsTools,
19
+ ...keyTools,
20
+ ...userTools,
21
+ ...tailnetTools,
22
+ ...webhookTools,
23
+ ...networkLockTools,
24
+ ...postureTools,
25
+ ...auditTools,
26
+ ];
27
+ describe("Tool definitions", () => {
28
+ it("should have no duplicate tool names", () => {
29
+ const names = allTools.map((t) => t.name);
30
+ const unique = new Set(names);
31
+ assert.equal(names.length, unique.size, `Duplicate tool names found: ${names.filter((n, i) => names.indexOf(n) !== i)}`);
32
+ });
33
+ it("should have the expected total tool count", () => {
34
+ assert.equal(allTools.length, 44);
35
+ });
36
+ for (const tool of allTools) {
37
+ describe(tool.name, () => {
38
+ it("should have a non-empty name", () => {
39
+ assert.ok(tool.name.length > 0);
40
+ });
41
+ it("should have a name prefixed with tailscale_", () => {
42
+ assert.ok(tool.name.startsWith("tailscale_"), `Tool name ${tool.name} should start with tailscale_`);
43
+ });
44
+ it("should have a non-empty description", () => {
45
+ assert.ok(tool.description.length > 0);
46
+ });
47
+ it("should have a Zod input schema", () => {
48
+ assert.ok(tool.inputSchema);
49
+ assert.ok(typeof tool.inputSchema.shape === "object");
50
+ });
51
+ it("should have an async handler function", () => {
52
+ assert.equal(typeof tool.handler, "function");
53
+ });
54
+ });
55
+ }
56
+ });
57
+ describe("Tool modules export correct counts", () => {
58
+ it("statusTools has 1 tool", () => assert.equal(statusTools.length, 1));
59
+ it("deviceTools has 10 tools", () => assert.equal(deviceTools.length, 10));
60
+ it("aclTools has 4 tools", () => assert.equal(aclTools.length, 4));
61
+ it("dnsTools has 8 tools", () => assert.equal(dnsTools.length, 8));
62
+ it("keyTools has 4 tools", () => assert.equal(keyTools.length, 4));
63
+ it("userTools has 2 tools", () => assert.equal(userTools.length, 2));
64
+ it("tailnetTools has 4 tools", () => assert.equal(tailnetTools.length, 4));
65
+ it("webhookTools has 5 tools", () => assert.equal(webhookTools.length, 5));
66
+ it("networkLockTools has 1 tool", () => assert.equal(networkLockTools.length, 1));
67
+ it("postureTools has 4 tools", () => assert.equal(postureTools.length, 4));
68
+ it("auditTools has 1 tool", () => assert.equal(auditTools.length, 1));
69
+ });
70
+ //# sourceMappingURL=tools.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../src/tools/tools.test.ts"],"names":[],"mappings":"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"}
@@ -34,9 +34,26 @@ export declare const webhookTools: readonly [{
34
34
  endpointUrl: string;
35
35
  subscriptions: string[];
36
36
  }) => Promise<import("../api.js").ApiResponse<unknown>>;
37
+ }, {
38
+ readonly name: "tailscale_update_webhook";
39
+ readonly description: "Update an existing webhook's subscriptions.";
40
+ readonly inputSchema: z.ZodObject<{
41
+ webhookId: z.ZodString;
42
+ subscriptions: z.ZodArray<z.ZodString, "many">;
43
+ }, "strip", z.ZodTypeAny, {
44
+ webhookId: string;
45
+ subscriptions: string[];
46
+ }, {
47
+ webhookId: string;
48
+ subscriptions: string[];
49
+ }>;
50
+ readonly handler: (input: {
51
+ webhookId: string;
52
+ subscriptions: string[];
53
+ }) => Promise<import("../api.js").ApiResponse<unknown>>;
37
54
  }, {
38
55
  readonly name: "tailscale_delete_webhook";
39
- readonly description: "Delete a webhook.";
56
+ readonly description: "Delete a webhook. This is irreversible — the webhook secret cannot be recovered.";
40
57
  readonly inputSchema: z.ZodObject<{
41
58
  webhookId: z.ZodString;
42
59
  }, "strip", z.ZodTypeAny, {
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { apiGet, apiPost, apiDelete, getTailnet } from "../api.js";
2
+ import { apiGet, apiPost, apiPatch, apiDelete, getTailnet } from "../api.js";
3
3
  export const webhookTools = [
4
4
  {
5
5
  name: "tailscale_list_webhooks",
@@ -35,9 +35,24 @@ export const webhookTools = [
35
35
  });
36
36
  },
37
37
  },
38
+ {
39
+ name: "tailscale_update_webhook",
40
+ description: "Update an existing webhook's subscriptions.",
41
+ inputSchema: z.object({
42
+ webhookId: z.string().describe("The webhook ID to update"),
43
+ subscriptions: z
44
+ .array(z.string())
45
+ .describe("Updated list of event types to subscribe to (e.g. ['nodeCreated', 'nodeDeleted', 'nodeApproved', 'policyUpdate', 'userCreated', 'userDeleted'])"),
46
+ }),
47
+ handler: async (input) => {
48
+ return apiPatch(`/webhooks/${input.webhookId}`, {
49
+ subscriptions: input.subscriptions,
50
+ });
51
+ },
52
+ },
38
53
  {
39
54
  name: "tailscale_delete_webhook",
40
- description: "Delete a webhook.",
55
+ description: "Delete a webhook. This is irreversible — the webhook secret cannot be recovered.",
41
56
  inputSchema: z.object({
42
57
  webhookId: z.string().describe("The webhook ID to delete"),
43
58
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/tools/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAY,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;QACE,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,gDAAgD;QAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,WAAW,CAAC,CAAC;QACrD,CAAC;KACF;IACD;QACE,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,qCAAqC;QAClD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;SACjD,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA4B,EAAE,EAAE;YAC9C,OAAO,MAAM,CAAC,aAAa,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QAChD,CAAC;KACF;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,uBAAuB;QACpC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YACrE,aAAa,EAAE,CAAC;iBACb,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,CACP,iIAAiI,CAClI;SACJ,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAAuD,EAAE,EAAE;YACzE,OAAO,OAAO,CAAC,YAAY,UAAU,EAAE,WAAW,EAAE;gBAClD,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;aACnC,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,mBAAmB;QAChC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;SAC3D,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA4B,EAAE,EAAE;YAC9C,OAAO,SAAS,CAAC,aAAa,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QACnD,CAAC;KACF;CACO,CAAC"}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/tools/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;QACE,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,gDAAgD;QAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,CAAC,YAAY,UAAU,EAAE,WAAW,CAAC,CAAC;QACrD,CAAC;KACF;IACD;QACE,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,qCAAqC;QAClD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;SACjD,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA4B,EAAE,EAAE;YAC9C,OAAO,MAAM,CAAC,aAAa,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QAChD,CAAC;KACF;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,uBAAuB;QACpC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YACrE,aAAa,EAAE,CAAC;iBACb,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,CACP,iIAAiI,CAClI;SACJ,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAAuD,EAAE,EAAE;YACzE,OAAO,OAAO,CAAC,YAAY,UAAU,EAAE,WAAW,EAAE;gBAClD,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;aACnC,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,6CAA6C;QAC1D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;YAC1D,aAAa,EAAE,CAAC;iBACb,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,CACP,iJAAiJ,CAClJ;SACJ,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAAqD,EAAE,EAAE;YACvE,OAAO,QAAQ,CAAC,aAAa,KAAK,CAAC,SAAS,EAAE,EAAE;gBAC9C,aAAa,EAAE,KAAK,CAAC,aAAa;aACnC,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,kFAAkF;QAC/F,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;SAC3D,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAA4B,EAAE,EAAE;YAC9C,OAAO,SAAS,CAAC,aAAa,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QACnD,CAAC;KACF;CACO,CAAC"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@yawlabs/tailscale-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Tailscale MCP server for managing your tailnet from AI assistants",
5
5
  "license": "MIT",
6
- "author": "YawLabs <hello@yaw.sh>",
6
+ "author": "YawLabs <contact@yaw.sh>",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "https://github.com/YawLabs/tailscale-mcp"