@owine/unifi-network-mcp 2.14.2 → 2.15.0
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 +12 -10
- package/dist/tools/acl.js +3 -3
- package/dist/tools/client-history.js +1 -1
- package/dist/tools/clients.js +4 -4
- package/dist/tools/devices.js +9 -9
- package/dist/tools/dns-policies.js +96 -49
- package/dist/tools/firewall.js +53 -13
- package/dist/tools/networks.js +117 -36
- package/dist/tools/sites.js +1 -1
- package/dist/tools/supporting.js +9 -9
- package/dist/tools/switching.js +6 -6
- package/dist/tools/traffic-matching.js +10 -9
- package/dist/tools/wifi.js +164 -293
- package/dist/utils/full-put.d.ts +23 -0
- package/dist/utils/full-put.js +51 -0
- package/dist/utils/output-schemas.d.ts +51 -5
- package/dist/utils/output-schemas.js +26 -6
- package/dist/utils/secrets.d.ts +24 -0
- package/dist/utils/secrets.js +89 -0
- package/package.json +6 -6
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* field optional, every nested object uses .passthrough() to allow
|
|
4
4
|
* firmware/hardware-specific fields to flow through unchanged).
|
|
5
5
|
*
|
|
6
|
-
* Verified against UniFi Network API
|
|
6
|
+
* Verified against UniFi Network API 11.0.83. Where the docs collapse
|
|
7
7
|
* nested arrays/objects (e.g. interfaces.ports[], radios[]), the schema
|
|
8
8
|
* uses passthrough records so the contract doesn't lock to fields we
|
|
9
9
|
* haven't verified.
|
|
@@ -40,6 +40,7 @@ export declare const networkOutputSchema: {
|
|
|
40
40
|
ipv6Configuration: z.ZodOptional<z.ZodUnknown>;
|
|
41
41
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
42
42
|
origin: z.ZodOptional<z.ZodString>;
|
|
43
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
43
44
|
}, z.core.$loose>>;
|
|
44
45
|
};
|
|
45
46
|
export declare const listNetworksOutputSchema: {
|
|
@@ -64,6 +65,7 @@ export declare const listNetworksOutputSchema: {
|
|
|
64
65
|
ipv6Configuration: z.ZodOptional<z.ZodUnknown>;
|
|
65
66
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
66
67
|
origin: z.ZodOptional<z.ZodString>;
|
|
68
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
67
69
|
}, z.core.$loose>>;
|
|
68
70
|
}, z.core.$loose>>;
|
|
69
71
|
};
|
|
@@ -129,6 +131,7 @@ export declare const firewallZoneOutputSchema: {
|
|
|
129
131
|
networkIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
130
132
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
131
133
|
origin: z.ZodOptional<z.ZodString>;
|
|
134
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
132
135
|
}, z.core.$loose>>;
|
|
133
136
|
};
|
|
134
137
|
export declare const listFirewallZonesOutputSchema: {
|
|
@@ -142,6 +145,7 @@ export declare const listFirewallZonesOutputSchema: {
|
|
|
142
145
|
networkIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
143
146
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
144
147
|
origin: z.ZodOptional<z.ZodString>;
|
|
148
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
145
149
|
}, z.core.$loose>>;
|
|
146
150
|
}, z.core.$loose>>;
|
|
147
151
|
};
|
|
@@ -157,10 +161,12 @@ export declare const firewallPolicyOutputSchema: {
|
|
|
157
161
|
ipsecFilter: z.ZodOptional<z.ZodUnknown>;
|
|
158
162
|
schedule: z.ZodOptional<z.ZodUnknown>;
|
|
159
163
|
loggingEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
164
|
+
reportFlowEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
160
165
|
index: z.ZodOptional<z.ZodNumber>;
|
|
161
166
|
description: z.ZodOptional<z.ZodString>;
|
|
162
167
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
163
168
|
origin: z.ZodOptional<z.ZodString>;
|
|
169
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
164
170
|
}, z.core.$loose>>;
|
|
165
171
|
};
|
|
166
172
|
export declare const listFirewallPoliciesOutputSchema: {
|
|
@@ -180,10 +186,12 @@ export declare const listFirewallPoliciesOutputSchema: {
|
|
|
180
186
|
ipsecFilter: z.ZodOptional<z.ZodUnknown>;
|
|
181
187
|
schedule: z.ZodOptional<z.ZodUnknown>;
|
|
182
188
|
loggingEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
189
|
+
reportFlowEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
183
190
|
index: z.ZodOptional<z.ZodNumber>;
|
|
184
191
|
description: z.ZodOptional<z.ZodString>;
|
|
185
192
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
186
193
|
origin: z.ZodOptional<z.ZodString>;
|
|
194
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
187
195
|
}, z.core.$loose>>;
|
|
188
196
|
}, z.core.$loose>>;
|
|
189
197
|
};
|
|
@@ -199,14 +207,15 @@ export declare const aclRuleOutputSchema: {
|
|
|
199
207
|
name: z.ZodOptional<z.ZodString>;
|
|
200
208
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
201
209
|
action: z.ZodOptional<z.ZodString>;
|
|
202
|
-
description: z.ZodOptional<z.ZodString
|
|
203
|
-
protocolFilter: z.ZodOptional<z.ZodArray<z.ZodString
|
|
210
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
211
|
+
protocolFilter: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
204
212
|
sourceFilter: z.ZodOptional<z.ZodUnknown>;
|
|
205
213
|
destinationFilter: z.ZodOptional<z.ZodUnknown>;
|
|
206
214
|
enforcingDeviceFilter: z.ZodOptional<z.ZodUnknown>;
|
|
207
215
|
index: z.ZodOptional<z.ZodNumber>;
|
|
208
216
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
209
217
|
origin: z.ZodOptional<z.ZodString>;
|
|
218
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
210
219
|
}, z.core.$loose>>;
|
|
211
220
|
};
|
|
212
221
|
export declare const listAclRulesOutputSchema: {
|
|
@@ -220,14 +229,15 @@ export declare const listAclRulesOutputSchema: {
|
|
|
220
229
|
name: z.ZodOptional<z.ZodString>;
|
|
221
230
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
222
231
|
action: z.ZodOptional<z.ZodString>;
|
|
223
|
-
description: z.ZodOptional<z.ZodString
|
|
224
|
-
protocolFilter: z.ZodOptional<z.ZodArray<z.ZodString
|
|
232
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
233
|
+
protocolFilter: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
225
234
|
sourceFilter: z.ZodOptional<z.ZodUnknown>;
|
|
226
235
|
destinationFilter: z.ZodOptional<z.ZodUnknown>;
|
|
227
236
|
enforcingDeviceFilter: z.ZodOptional<z.ZodUnknown>;
|
|
228
237
|
index: z.ZodOptional<z.ZodNumber>;
|
|
229
238
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
230
239
|
origin: z.ZodOptional<z.ZodString>;
|
|
240
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
231
241
|
}, z.core.$loose>>;
|
|
232
242
|
}, z.core.$loose>>;
|
|
233
243
|
};
|
|
@@ -243,6 +253,7 @@ export declare const switchStackOutputSchema: {
|
|
|
243
253
|
lags: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
244
254
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
245
255
|
origin: z.ZodOptional<z.ZodString>;
|
|
256
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
246
257
|
}, z.core.$loose>>;
|
|
247
258
|
};
|
|
248
259
|
export declare const listSwitchStacksOutputSchema: {
|
|
@@ -259,6 +270,7 @@ export declare const listSwitchStacksOutputSchema: {
|
|
|
259
270
|
lags: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
260
271
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
261
272
|
origin: z.ZodOptional<z.ZodString>;
|
|
273
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
262
274
|
}, z.core.$loose>>;
|
|
263
275
|
}, z.core.$loose>>;
|
|
264
276
|
};
|
|
@@ -269,6 +281,7 @@ export declare const mcLagDomainOutputSchema: {
|
|
|
269
281
|
lags: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
270
282
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
271
283
|
origin: z.ZodOptional<z.ZodString>;
|
|
284
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
272
285
|
}, z.core.$loose>>;
|
|
273
286
|
};
|
|
274
287
|
export declare const listMcLagDomainsOutputSchema: {
|
|
@@ -283,6 +296,7 @@ export declare const listMcLagDomainsOutputSchema: {
|
|
|
283
296
|
lags: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
284
297
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
285
298
|
origin: z.ZodOptional<z.ZodString>;
|
|
299
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
286
300
|
}, z.core.$loose>>;
|
|
287
301
|
}, z.core.$loose>>;
|
|
288
302
|
};
|
|
@@ -295,6 +309,7 @@ export declare const lagOutputSchema: {
|
|
|
295
309
|
}, z.core.$loose>>>;
|
|
296
310
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
297
311
|
origin: z.ZodOptional<z.ZodString>;
|
|
312
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
298
313
|
}, z.core.$loose>>;
|
|
299
314
|
};
|
|
300
315
|
export declare const listLagsOutputSchema: {
|
|
@@ -311,6 +326,7 @@ export declare const listLagsOutputSchema: {
|
|
|
311
326
|
}, z.core.$loose>>>;
|
|
312
327
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
313
328
|
origin: z.ZodOptional<z.ZodString>;
|
|
329
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
314
330
|
}, z.core.$loose>>;
|
|
315
331
|
}, z.core.$loose>>;
|
|
316
332
|
};
|
|
@@ -321,8 +337,20 @@ export declare const dnsPolicyOutputSchema: {
|
|
|
321
337
|
domain: z.ZodOptional<z.ZodString>;
|
|
322
338
|
ipv4Address: z.ZodOptional<z.ZodString>;
|
|
323
339
|
ttlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
340
|
+
ipv6Address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
341
|
+
targetDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
342
|
+
mailServerDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
343
|
+
text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
344
|
+
serverDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
345
|
+
service: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
346
|
+
protocol: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
347
|
+
port: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
348
|
+
priority: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
349
|
+
weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
350
|
+
ipAddress: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
324
351
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
325
352
|
origin: z.ZodOptional<z.ZodString>;
|
|
353
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
326
354
|
}, z.core.$loose>>;
|
|
327
355
|
};
|
|
328
356
|
export declare const listDnsPoliciesOutputSchema: {
|
|
@@ -337,8 +365,20 @@ export declare const listDnsPoliciesOutputSchema: {
|
|
|
337
365
|
domain: z.ZodOptional<z.ZodString>;
|
|
338
366
|
ipv4Address: z.ZodOptional<z.ZodString>;
|
|
339
367
|
ttlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
368
|
+
ipv6Address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
369
|
+
targetDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
370
|
+
mailServerDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
371
|
+
text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
372
|
+
serverDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
373
|
+
service: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
374
|
+
protocol: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
375
|
+
port: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
376
|
+
priority: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
377
|
+
weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
378
|
+
ipAddress: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
340
379
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
341
380
|
origin: z.ZodOptional<z.ZodString>;
|
|
381
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
342
382
|
}, z.core.$loose>>;
|
|
343
383
|
}, z.core.$loose>>;
|
|
344
384
|
};
|
|
@@ -349,6 +389,7 @@ export declare const trafficMatchingListOutputSchema: {
|
|
|
349
389
|
items: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
350
390
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
351
391
|
origin: z.ZodOptional<z.ZodString>;
|
|
392
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
352
393
|
}, z.core.$loose>>;
|
|
353
394
|
};
|
|
354
395
|
export declare const listTrafficMatchingListsOutputSchema: {
|
|
@@ -363,6 +404,7 @@ export declare const listTrafficMatchingListsOutputSchema: {
|
|
|
363
404
|
items: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
364
405
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
365
406
|
origin: z.ZodOptional<z.ZodString>;
|
|
407
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
366
408
|
}, z.core.$loose>>;
|
|
367
409
|
}, z.core.$loose>>;
|
|
368
410
|
};
|
|
@@ -495,6 +537,7 @@ export declare const listWifiOutputSchema: {
|
|
|
495
537
|
broadcastingDeviceFilter: z.ZodOptional<z.ZodUnknown>;
|
|
496
538
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
497
539
|
origin: z.ZodOptional<z.ZodString>;
|
|
540
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
498
541
|
}, z.core.$loose>>;
|
|
499
542
|
}, z.core.$loose>>;
|
|
500
543
|
};
|
|
@@ -512,6 +555,7 @@ export declare const getWifiOutputSchema: {
|
|
|
512
555
|
broadcastingDeviceFilter: z.ZodOptional<z.ZodUnknown>;
|
|
513
556
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
514
557
|
origin: z.ZodOptional<z.ZodString>;
|
|
558
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
515
559
|
}, z.core.$loose>>;
|
|
516
560
|
};
|
|
517
561
|
export declare const listWansOutputSchema: {
|
|
@@ -536,6 +580,7 @@ export declare const listVpnServersOutputSchema: {
|
|
|
536
580
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
537
581
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
538
582
|
origin: z.ZodOptional<z.ZodString>;
|
|
583
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
539
584
|
}, z.core.$loose>>;
|
|
540
585
|
}, z.core.$loose>>;
|
|
541
586
|
};
|
|
@@ -559,6 +604,7 @@ export declare const listRadiusProfilesOutputSchema: {
|
|
|
559
604
|
name: z.ZodOptional<z.ZodString>;
|
|
560
605
|
metadata: z.ZodOptional<z.ZodObject<{
|
|
561
606
|
origin: z.ZodOptional<z.ZodString>;
|
|
607
|
+
configurable: z.ZodOptional<z.ZodBoolean>;
|
|
562
608
|
}, z.core.$loose>>;
|
|
563
609
|
}, z.core.$loose>>;
|
|
564
610
|
};
|
|
@@ -6,14 +6,16 @@ exports.listClientSessionsOutputSchema = exports.listClientHistoryOutputSchema =
|
|
|
6
6
|
* field optional, every nested object uses .passthrough() to allow
|
|
7
7
|
* firmware/hardware-specific fields to flow through unchanged).
|
|
8
8
|
*
|
|
9
|
-
* Verified against UniFi Network API
|
|
9
|
+
* Verified against UniFi Network API 11.0.83. Where the docs collapse
|
|
10
10
|
* nested arrays/objects (e.g. interfaces.ports[], radios[]), the schema
|
|
11
11
|
* uses passthrough records so the contract doesn't lock to fields we
|
|
12
12
|
* haven't verified.
|
|
13
13
|
*/
|
|
14
14
|
const zod_1 = require("zod");
|
|
15
|
+
// configurable is live-verified (11.0.83) on system-defined zones, policies,
|
|
16
|
+
// networks and RADIUS profiles; it is absent on user-defined resources.
|
|
15
17
|
const Metadata = zod_1.z
|
|
16
|
-
.object({ origin: zod_1.z.string().optional() })
|
|
18
|
+
.object({ origin: zod_1.z.string().optional(), configurable: zod_1.z.boolean().optional() })
|
|
17
19
|
.passthrough();
|
|
18
20
|
const PaginationFields = {
|
|
19
21
|
offset: zod_1.z.number().int().optional(),
|
|
@@ -160,7 +162,7 @@ const WifiBroadcast = zod_1.z
|
|
|
160
162
|
.passthrough();
|
|
161
163
|
const ApplicationInfo = zod_1.z
|
|
162
164
|
.object({
|
|
163
|
-
// Live-verified (
|
|
165
|
+
// Live-verified (11.0.83): only applicationVersion is returned.
|
|
164
166
|
applicationVersion: zod_1.z.string().optional(),
|
|
165
167
|
})
|
|
166
168
|
.passthrough();
|
|
@@ -236,6 +238,8 @@ const FirewallPolicy = zod_1.z
|
|
|
236
238
|
ipsecFilter: zod_1.z.unknown().optional(),
|
|
237
239
|
schedule: zod_1.z.unknown().optional(),
|
|
238
240
|
loggingEnabled: zod_1.z.boolean().optional(),
|
|
241
|
+
// New in 11.0.83; live-verified as a boolean on every policy.
|
|
242
|
+
reportFlowEnabled: zod_1.z.boolean().optional(),
|
|
239
243
|
index: zod_1.z.number().optional(),
|
|
240
244
|
description: zod_1.z.string().optional(),
|
|
241
245
|
metadata: Metadata.optional(),
|
|
@@ -259,8 +263,11 @@ const AclRule = zod_1.z
|
|
|
259
263
|
name: zod_1.z.string().optional(),
|
|
260
264
|
enabled: zod_1.z.boolean().optional(),
|
|
261
265
|
action: zod_1.z.string().optional(),
|
|
262
|
-
|
|
263
|
-
|
|
266
|
+
// The docs give null a meaning ("When null, the rule will be applied to
|
|
267
|
+
// all protocols") and ACL samples already carry explicit nulls, so both
|
|
268
|
+
// must accept null or a protocol-agnostic rule hard-fails with -32602.
|
|
269
|
+
description: zod_1.z.string().nullable().optional(),
|
|
270
|
+
protocolFilter: zod_1.z.array(zod_1.z.string()).nullable().optional(),
|
|
264
271
|
sourceFilter: zod_1.z.unknown().optional(),
|
|
265
272
|
destinationFilter: zod_1.z.unknown().optional(),
|
|
266
273
|
enforcingDeviceFilter: zod_1.z.unknown().optional(),
|
|
@@ -322,6 +329,19 @@ const DnsPolicy = zod_1.z
|
|
|
322
329
|
domain: zod_1.z.string().optional(),
|
|
323
330
|
ipv4Address: zod_1.z.string().optional(),
|
|
324
331
|
ttlSeconds: zod_1.z.number().optional(),
|
|
332
|
+
// Type-specific fields from the 11.0.83 response samples (no live DNS
|
|
333
|
+
// policies to sample), so nullable to be safe.
|
|
334
|
+
ipv6Address: zod_1.z.string().nullable().optional(),
|
|
335
|
+
targetDomain: zod_1.z.string().nullable().optional(),
|
|
336
|
+
mailServerDomain: zod_1.z.string().nullable().optional(),
|
|
337
|
+
text: zod_1.z.string().nullable().optional(),
|
|
338
|
+
serverDomain: zod_1.z.string().nullable().optional(),
|
|
339
|
+
service: zod_1.z.string().nullable().optional(),
|
|
340
|
+
protocol: zod_1.z.string().nullable().optional(),
|
|
341
|
+
port: zod_1.z.number().nullable().optional(),
|
|
342
|
+
priority: zod_1.z.number().nullable().optional(),
|
|
343
|
+
weight: zod_1.z.number().nullable().optional(),
|
|
344
|
+
ipAddress: zod_1.z.string().nullable().optional(),
|
|
325
345
|
metadata: Metadata.optional(),
|
|
326
346
|
})
|
|
327
347
|
.passthrough();
|
|
@@ -334,7 +354,7 @@ const TrafficMatchingList = zod_1.z
|
|
|
334
354
|
metadata: Metadata.optional(),
|
|
335
355
|
})
|
|
336
356
|
.passthrough();
|
|
337
|
-
// Verified against the live Integration API (
|
|
357
|
+
// Verified against the live Integration API (11.0.83). The WAN and
|
|
338
358
|
// site-to-site-tunnel list rows are intentionally minimal in the API.
|
|
339
359
|
const Wan = zod_1.z
|
|
340
360
|
.object({
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WiFi broadcasts come back from the API with their passphrases in plaintext
|
|
3
|
+
* (`securityConfiguration.passphrase`, and one per VLAN in
|
|
4
|
+
* `securityConfiguration.presharedKeys[].passphrase` on PPSK SSIDs). None of
|
|
5
|
+
* this is in the published docs. Tools redact these values by default so they
|
|
6
|
+
* do not land in LLM transcripts; callers opt in with `includeSecrets: true`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const REDACTED = "[REDACTED]";
|
|
9
|
+
/** Deep copy of `data` with every secret-named string value replaced by REDACTED. */
|
|
10
|
+
export declare function redactSecrets<T>(data: T): T;
|
|
11
|
+
/**
|
|
12
|
+
* Replace each REDACTED placeholder in `value` with the real value found at the
|
|
13
|
+
* same path in `current`. This lets a caller echo back a redacted object from a
|
|
14
|
+
* read tool without overwriting the passphrase with the placeholder text.
|
|
15
|
+
* Throws if a placeholder has no real value to restore (e.g. on create, or when
|
|
16
|
+
* a new PPSK entry is added without its passphrase).
|
|
17
|
+
*
|
|
18
|
+
* Array items are matched by index, which is only safe while the item is
|
|
19
|
+
* otherwise unchanged: a reordered `presharedKeys[]` must not hand one VLAN's
|
|
20
|
+
* passphrase to another. So a placeholder inside an array item is restored only
|
|
21
|
+
* when that item equals the current item at the same index apart from secrets.
|
|
22
|
+
*/
|
|
23
|
+
export declare function restoreRedacted(value: unknown, current: unknown, path?: string): unknown;
|
|
24
|
+
export declare function containsRedacted(value: unknown): boolean;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WiFi broadcasts come back from the API with their passphrases in plaintext
|
|
4
|
+
* (`securityConfiguration.passphrase`, and one per VLAN in
|
|
5
|
+
* `securityConfiguration.presharedKeys[].passphrase` on PPSK SSIDs). None of
|
|
6
|
+
* this is in the published docs. Tools redact these values by default so they
|
|
7
|
+
* do not land in LLM transcripts; callers opt in with `includeSecrets: true`.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.REDACTED = void 0;
|
|
11
|
+
exports.redactSecrets = redactSecrets;
|
|
12
|
+
exports.restoreRedacted = restoreRedacted;
|
|
13
|
+
exports.containsRedacted = containsRedacted;
|
|
14
|
+
exports.REDACTED = "[REDACTED]";
|
|
15
|
+
const SECRET_KEYS = new Set(["passphrase", "password", "secret", "sharedSecret"]);
|
|
16
|
+
/** Deep copy of `data` with every secret-named string value replaced by REDACTED. */
|
|
17
|
+
function redactSecrets(data) {
|
|
18
|
+
return redact(data);
|
|
19
|
+
}
|
|
20
|
+
function redact(value) {
|
|
21
|
+
if (Array.isArray(value))
|
|
22
|
+
return value.map(redact);
|
|
23
|
+
if (value === null || typeof value !== "object")
|
|
24
|
+
return value;
|
|
25
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
26
|
+
key,
|
|
27
|
+
SECRET_KEYS.has(key) && typeof entry === "string" ? exports.REDACTED : redact(entry),
|
|
28
|
+
]));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Replace each REDACTED placeholder in `value` with the real value found at the
|
|
32
|
+
* same path in `current`. This lets a caller echo back a redacted object from a
|
|
33
|
+
* read tool without overwriting the passphrase with the placeholder text.
|
|
34
|
+
* Throws if a placeholder has no real value to restore (e.g. on create, or when
|
|
35
|
+
* a new PPSK entry is added without its passphrase).
|
|
36
|
+
*
|
|
37
|
+
* Array items are matched by index, which is only safe while the item is
|
|
38
|
+
* otherwise unchanged: a reordered `presharedKeys[]` must not hand one VLAN's
|
|
39
|
+
* passphrase to another. So a placeholder inside an array item is restored only
|
|
40
|
+
* when that item equals the current item at the same index apart from secrets.
|
|
41
|
+
*/
|
|
42
|
+
function restoreRedacted(value, current, path = "body") {
|
|
43
|
+
if (value === exports.REDACTED) {
|
|
44
|
+
if (typeof current === "string")
|
|
45
|
+
return current;
|
|
46
|
+
throw new Error(`${path} is "${exports.REDACTED}" with no existing value to keep — pass the real secret, or omit the field`);
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
const currentItems = Array.isArray(current) ? current : [];
|
|
50
|
+
return value.map((item, i) => {
|
|
51
|
+
const itemPath = `${path}[${i}]`;
|
|
52
|
+
if (!containsRedacted(item))
|
|
53
|
+
return item;
|
|
54
|
+
if (stableStringify(redact(item)) !== stableStringify(redact(currentItems[i]))) {
|
|
55
|
+
throw new Error(`${itemPath} contains "${exports.REDACTED}" but differs from the existing entry at that position — pass the real secret for changed or reordered entries`);
|
|
56
|
+
}
|
|
57
|
+
return restoreRedacted(item, currentItems[i], itemPath);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (value === null || typeof value !== "object")
|
|
61
|
+
return value;
|
|
62
|
+
const currentObject = current !== null && typeof current === "object" && !Array.isArray(current)
|
|
63
|
+
? current
|
|
64
|
+
: {};
|
|
65
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
66
|
+
key,
|
|
67
|
+
restoreRedacted(entry, currentObject[key], `${path}.${key}`),
|
|
68
|
+
]));
|
|
69
|
+
}
|
|
70
|
+
function containsRedacted(value) {
|
|
71
|
+
if (value === exports.REDACTED)
|
|
72
|
+
return true;
|
|
73
|
+
if (Array.isArray(value))
|
|
74
|
+
return value.some(containsRedacted);
|
|
75
|
+
if (value === null || typeof value !== "object")
|
|
76
|
+
return false;
|
|
77
|
+
return Object.values(value).some(containsRedacted);
|
|
78
|
+
}
|
|
79
|
+
function stableStringify(value) {
|
|
80
|
+
if (Array.isArray(value))
|
|
81
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
82
|
+
if (value === null || typeof value !== "object")
|
|
83
|
+
return JSON.stringify(value) ?? "undefined";
|
|
84
|
+
const entries = Object.entries(value)
|
|
85
|
+
.filter(([, entry]) => entry !== undefined)
|
|
86
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
87
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`);
|
|
88
|
+
return `{${entries.join(",")}}`;
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owine/unifi-network-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "MCP server for the UniFi Network API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": "^22.13.0 || ^24.0.0"
|
|
24
24
|
},
|
|
25
|
-
"packageManager": "pnpm@12.
|
|
25
|
+
"packageManager": "pnpm@12.11.2",
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "git+https://github.com/owine/unifi-network-mcp.git"
|
|
@@ -37,18 +37,18 @@
|
|
|
37
37
|
"author": "owine",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "1.32.
|
|
40
|
+
"@modelcontextprotocol/sdk": "1.32.1",
|
|
41
41
|
"zod": "4.6.5"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@eslint/js": "10.0.1",
|
|
45
|
-
"@types/node": "24.19.
|
|
45
|
+
"@types/node": "24.19.2",
|
|
46
46
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
47
47
|
"@vitest/coverage-v8": "5.0.3",
|
|
48
48
|
"eslint": "10.12.0",
|
|
49
|
-
"lefthook": "2.1
|
|
49
|
+
"lefthook": "2.2.1",
|
|
50
50
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
51
|
-
"typescript-eslint": "8.71.
|
|
51
|
+
"typescript-eslint": "8.71.1",
|
|
52
52
|
"vitest": "5.0.3"
|
|
53
53
|
}
|
|
54
54
|
}
|