@owine/unifi-network-mcp 2.6.0 → 2.7.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.
@@ -0,0 +1,507 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listPendingDevicesOutputSchema = exports.listCountriesOutputSchema = exports.listDpiApplicationsOutputSchema = exports.listDpiCategoriesOutputSchema = exports.listDeviceTagsOutputSchema = exports.listRadiusProfilesOutputSchema = exports.listVpnTunnelsOutputSchema = exports.listVpnServersOutputSchema = exports.listWansOutputSchema = exports.getWifiOutputSchema = exports.listWifiOutputSchema = exports.getClientOutputSchema = exports.listClientsOutputSchema = exports.getDeviceStatisticsOutputSchema = exports.getDeviceOutputSchema = exports.listDevicesOutputSchema = exports.listTrafficMatchingListsOutputSchema = exports.trafficMatchingListOutputSchema = exports.listDnsPoliciesOutputSchema = exports.dnsPolicyOutputSchema = exports.listLagsOutputSchema = exports.lagOutputSchema = exports.listMcLagDomainsOutputSchema = exports.mcLagDomainOutputSchema = exports.listSwitchStacksOutputSchema = exports.switchStackOutputSchema = exports.aclRuleOrderingOutputSchema = exports.listAclRulesOutputSchema = exports.aclRuleOutputSchema = exports.firewallPolicyOrderingOutputSchema = exports.listFirewallPoliciesOutputSchema = exports.firewallPolicyOutputSchema = exports.listFirewallZonesOutputSchema = exports.firewallZoneOutputSchema = exports.createVouchersOutputSchema = exports.listVouchersOutputSchema = exports.voucherOutputSchema = exports.getNetworkReferencesOutputSchema = exports.listNetworksOutputSchema = exports.networkOutputSchema = exports.listSitesOutputSchema = exports.getInfoOutputSchema = void 0;
4
+ /**
5
+ * Output schemas for high-value read tools (loose strategy: every non-key
6
+ * field optional, every nested object uses .passthrough() to allow
7
+ * firmware/hardware-specific fields to flow through unchanged).
8
+ *
9
+ * Verified against UniFi Network API 10.4.55. Where the docs collapse
10
+ * nested arrays/objects (e.g. interfaces.ports[], radios[]), the schema
11
+ * uses passthrough records so the contract doesn't lock to fields we
12
+ * haven't verified.
13
+ */
14
+ const zod_1 = require("zod");
15
+ const Metadata = zod_1.z
16
+ .object({ origin: zod_1.z.string().optional() })
17
+ .passthrough();
18
+ const PaginationFields = {
19
+ offset: zod_1.z.number().int().optional(),
20
+ limit: zod_1.z.number().int().optional(),
21
+ count: zod_1.z.number().int().optional(),
22
+ totalCount: zod_1.z.number().int().optional(),
23
+ };
24
+ // Shared device identity fields. NOTE: the list endpoint returns
25
+ // `features` and `interfaces` as string arrays (capability tags, e.g.
26
+ // ["switching"], ["ports"]); the get-by-id endpoint expands them into
27
+ // objects. Hence two distinct schemas below.
28
+ const DeviceCommon = {
29
+ id: zod_1.z.string(),
30
+ name: zod_1.z.string().optional(),
31
+ model: zod_1.z.string().optional(),
32
+ macAddress: zod_1.z.string().optional(),
33
+ ipAddress: zod_1.z.string().optional(),
34
+ state: zod_1.z.string().optional(),
35
+ supported: zod_1.z.boolean().optional(),
36
+ firmwareVersion: zod_1.z.string().optional(),
37
+ firmwareUpdatable: zod_1.z.boolean().optional(),
38
+ };
39
+ const DeviceListItem = zod_1.z
40
+ .object({
41
+ ...DeviceCommon,
42
+ adoptedAt: zod_1.z.string().optional(),
43
+ features: zod_1.z.array(zod_1.z.string()).optional(),
44
+ interfaces: zod_1.z.array(zod_1.z.string()).optional(),
45
+ })
46
+ .passthrough();
47
+ const DevicePort = zod_1.z
48
+ .object({
49
+ idx: zod_1.z.number(),
50
+ name: zod_1.z.string().optional(),
51
+ state: zod_1.z.string().optional(),
52
+ connector: zod_1.z.string().optional(),
53
+ maxSpeedMbps: zod_1.z.number().optional(),
54
+ speedMbps: zod_1.z.number().optional(),
55
+ poe: zod_1.z
56
+ .object({
57
+ standard: zod_1.z.string().optional(),
58
+ type: zod_1.z.number().optional(),
59
+ enabled: zod_1.z.boolean().optional(),
60
+ state: zod_1.z.string().optional(),
61
+ })
62
+ .passthrough()
63
+ .optional(),
64
+ })
65
+ .passthrough();
66
+ const DeviceRadio = zod_1.z
67
+ .object({
68
+ wlanStandard: zod_1.z.string().optional(),
69
+ frequencyGHz: zod_1.z.number().optional(),
70
+ channelWidthMHz: zod_1.z.number().optional(),
71
+ channel: zod_1.z.number().optional(),
72
+ })
73
+ .passthrough();
74
+ const DeviceDetail = zod_1.z
75
+ .object({
76
+ ...DeviceCommon,
77
+ adoptedAt: zod_1.z.string().optional(),
78
+ provisionedAt: zod_1.z.string().optional(),
79
+ configurationId: zod_1.z.string().optional(),
80
+ uplink: zod_1.z
81
+ .object({ deviceId: zod_1.z.string().optional() })
82
+ .passthrough()
83
+ .optional(),
84
+ // Detail view: object keyed by capability (switching/accessPoint).
85
+ features: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
86
+ interfaces: zod_1.z
87
+ .object({
88
+ ports: zod_1.z.array(DevicePort).optional(),
89
+ radios: zod_1.z.array(DeviceRadio).optional(),
90
+ })
91
+ .passthrough()
92
+ .optional(),
93
+ })
94
+ .passthrough();
95
+ const DeviceStatistics = zod_1.z
96
+ .object({
97
+ uptimeSec: zod_1.z.number().optional(),
98
+ lastHeartbeatAt: zod_1.z.string().optional(),
99
+ nextHeartbeatAt: zod_1.z.string().optional(),
100
+ loadAverage1Min: zod_1.z.number().optional(),
101
+ loadAverage5Min: zod_1.z.number().optional(),
102
+ loadAverage15Min: zod_1.z.number().optional(),
103
+ cpuUtilizationPct: zod_1.z.number().optional(),
104
+ memoryUtilizationPct: zod_1.z.number().optional(),
105
+ uplink: zod_1.z
106
+ .object({
107
+ txRateBps: zod_1.z.number().optional(),
108
+ rxRateBps: zod_1.z.number().optional(),
109
+ })
110
+ .passthrough()
111
+ .optional(),
112
+ interfaces: zod_1.z
113
+ .object({
114
+ radios: zod_1.z
115
+ .array(zod_1.z
116
+ .object({
117
+ frequencyGHz: zod_1.z.number().optional(),
118
+ txRetriesPct: zod_1.z.number().optional(),
119
+ })
120
+ .passthrough())
121
+ .optional(),
122
+ })
123
+ .passthrough()
124
+ .optional(),
125
+ })
126
+ .passthrough();
127
+ const Client = zod_1.z
128
+ .object({
129
+ id: zod_1.z.string(),
130
+ type: zod_1.z.string().optional(),
131
+ name: zod_1.z.string().optional(),
132
+ macAddress: zod_1.z.string().optional(),
133
+ ipAddress: zod_1.z.string().optional(),
134
+ connectedAt: zod_1.z.string().optional(),
135
+ uplinkDeviceId: zod_1.z.string().optional(),
136
+ access: zod_1.z
137
+ .object({ type: zod_1.z.string().optional() })
138
+ .passthrough()
139
+ .optional(),
140
+ })
141
+ .passthrough();
142
+ const WifiBroadcast = zod_1.z
143
+ .object({
144
+ id: zod_1.z.string(),
145
+ name: zod_1.z.string().optional(),
146
+ enabled: zod_1.z.boolean().optional(),
147
+ type: zod_1.z.string().optional(),
148
+ // Nested shapes not live-verified — z.unknown() avoids over-asserting
149
+ // object-vs-array (the SDK enforces outputSchema and a wrong type
150
+ // makes the tool hard-fail, not just mislead).
151
+ broadcastingFrequenciesGHz: zod_1.z.array(zod_1.z.unknown()).optional(),
152
+ securityConfiguration: zod_1.z.unknown().optional(),
153
+ hideName: zod_1.z.boolean().optional(),
154
+ bandSteeringEnabled: zod_1.z.boolean().optional(),
155
+ mloEnabled: zod_1.z.boolean().optional(),
156
+ network: zod_1.z.unknown().optional(),
157
+ broadcastingDeviceFilter: zod_1.z.unknown().optional(),
158
+ metadata: Metadata.optional(),
159
+ })
160
+ .passthrough();
161
+ const ApplicationInfo = zod_1.z
162
+ .object({
163
+ // Live-verified (10.4.55): only applicationVersion is returned.
164
+ applicationVersion: zod_1.z.string().optional(),
165
+ })
166
+ .passthrough();
167
+ const Site = zod_1.z
168
+ .object({
169
+ id: zod_1.z.string(),
170
+ internalReference: zod_1.z.string().optional(),
171
+ name: zod_1.z.string().optional(),
172
+ })
173
+ .passthrough();
174
+ const Network = zod_1.z
175
+ .object({
176
+ id: zod_1.z.string(),
177
+ name: zod_1.z.string().optional(),
178
+ management: zod_1.z.string().optional(),
179
+ enabled: zod_1.z.boolean().optional(),
180
+ vlanId: zod_1.z.number().int().optional(),
181
+ default: zod_1.z.boolean().optional(),
182
+ zoneId: zod_1.z.string().optional(),
183
+ isolationEnabled: zod_1.z.boolean().optional(),
184
+ internetAccessEnabled: zod_1.z.boolean().optional(),
185
+ mdnsForwardingEnabled: zod_1.z.boolean().optional(),
186
+ cellularBackupEnabled: zod_1.z.boolean().optional(),
187
+ dhcpGuarding: zod_1.z.unknown().optional(),
188
+ // get-by-id only (absent in list view); nested shape left loose.
189
+ ipv4Configuration: zod_1.z.unknown().optional(),
190
+ metadata: Metadata.optional(),
191
+ })
192
+ .passthrough();
193
+ const NetworkReferences = zod_1.z
194
+ .object({
195
+ referenceResources: zod_1.z.array(zod_1.z.unknown()).optional(),
196
+ })
197
+ .passthrough();
198
+ const Voucher = zod_1.z
199
+ .object({
200
+ id: zod_1.z.string(),
201
+ code: zod_1.z.string().optional(),
202
+ name: zod_1.z.string().optional(),
203
+ createdAt: zod_1.z.string().optional(),
204
+ activatedAt: zod_1.z.string().optional(),
205
+ expiresAt: zod_1.z.string().optional(),
206
+ timeLimitMinutes: zod_1.z.number().optional(),
207
+ dataUsageLimitMBytes: zod_1.z.number().optional(),
208
+ rxRateLimitKbps: zod_1.z.number().optional(),
209
+ txRateLimitKbps: zod_1.z.number().optional(),
210
+ authorizedGuestLimit: zod_1.z.number().optional(),
211
+ authorizedGuestCount: zod_1.z.number().optional(),
212
+ expired: zod_1.z.boolean().optional(),
213
+ })
214
+ .passthrough();
215
+ const FirewallZone = zod_1.z
216
+ .object({
217
+ id: zod_1.z.string(),
218
+ name: zod_1.z.string().optional(),
219
+ networkIds: zod_1.z.array(zod_1.z.string()).optional(),
220
+ metadata: Metadata.optional(),
221
+ })
222
+ .passthrough();
223
+ const FirewallPolicy = zod_1.z
224
+ .object({
225
+ id: zod_1.z.string(),
226
+ name: zod_1.z.string().optional(),
227
+ enabled: zod_1.z.boolean().optional(),
228
+ // connectionStateFilter is live-verified to be an ARRAY, not an
229
+ // object — the rest are not live-verified, so leave all loose.
230
+ action: zod_1.z.unknown().optional(),
231
+ source: zod_1.z.unknown().optional(),
232
+ destination: zod_1.z.unknown().optional(),
233
+ ipProtocolScope: zod_1.z.unknown().optional(),
234
+ connectionStateFilter: zod_1.z.unknown().optional(),
235
+ ipsecFilter: zod_1.z.unknown().optional(),
236
+ schedule: zod_1.z.unknown().optional(),
237
+ loggingEnabled: zod_1.z.boolean().optional(),
238
+ index: zod_1.z.number().optional(),
239
+ description: zod_1.z.string().optional(),
240
+ metadata: Metadata.optional(),
241
+ })
242
+ .passthrough();
243
+ const FirewallPolicyOrdering = zod_1.z
244
+ .object({
245
+ orderedFirewallPolicyIds: zod_1.z
246
+ .object({
247
+ beforeSystemDefined: zod_1.z.array(zod_1.z.string()).optional(),
248
+ afterSystemDefined: zod_1.z.array(zod_1.z.string()).optional(),
249
+ })
250
+ .passthrough()
251
+ .optional(),
252
+ })
253
+ .passthrough();
254
+ const AclRule = zod_1.z
255
+ .object({
256
+ id: zod_1.z.string(),
257
+ type: zod_1.z.string().optional(),
258
+ name: zod_1.z.string().optional(),
259
+ enabled: zod_1.z.boolean().optional(),
260
+ action: zod_1.z.string().optional(),
261
+ description: zod_1.z.string().optional(),
262
+ protocolFilter: zod_1.z.array(zod_1.z.string()).optional(),
263
+ sourceFilter: zod_1.z.unknown().optional(),
264
+ destinationFilter: zod_1.z.unknown().optional(),
265
+ metadata: Metadata.optional(),
266
+ })
267
+ .passthrough();
268
+ const AclRuleOrdering = zod_1.z
269
+ .object({
270
+ orderedAclRuleIds: zod_1.z.array(zod_1.z.string()).optional(),
271
+ })
272
+ .passthrough();
273
+ const SwitchStack = zod_1.z
274
+ .object({
275
+ id: zod_1.z.string(),
276
+ name: zod_1.z.string().optional(),
277
+ members: zod_1.z.array(zod_1.z.unknown()).optional(),
278
+ lags: zod_1.z.array(zod_1.z.unknown()).optional(),
279
+ metadata: Metadata.optional(),
280
+ })
281
+ .passthrough();
282
+ const McLagDomain = zod_1.z
283
+ .object({
284
+ id: zod_1.z.string(),
285
+ name: zod_1.z.string().optional(),
286
+ peers: zod_1.z.array(zod_1.z.unknown()).optional(),
287
+ lags: zod_1.z.array(zod_1.z.unknown()).optional(),
288
+ metadata: Metadata.optional(),
289
+ })
290
+ .passthrough();
291
+ const Lag = zod_1.z
292
+ .object({
293
+ id: zod_1.z.string(),
294
+ type: zod_1.z.string().optional(),
295
+ members: zod_1.z
296
+ .array(zod_1.z
297
+ .object({
298
+ deviceId: zod_1.z.string().optional(),
299
+ portIdxs: zod_1.z.array(zod_1.z.number()).optional(),
300
+ })
301
+ .passthrough())
302
+ .optional(),
303
+ metadata: Metadata.optional(),
304
+ })
305
+ .passthrough();
306
+ const DnsPolicy = zod_1.z
307
+ .object({
308
+ id: zod_1.z.string(),
309
+ type: zod_1.z.string().optional(),
310
+ enabled: zod_1.z.boolean().optional(),
311
+ domain: zod_1.z.string().optional(),
312
+ ipv4Address: zod_1.z.string().optional(),
313
+ ttlSeconds: zod_1.z.number().optional(),
314
+ metadata: Metadata.optional(),
315
+ })
316
+ .passthrough();
317
+ const TrafficMatchingList = zod_1.z
318
+ .object({
319
+ id: zod_1.z.string(),
320
+ type: zod_1.z.string().optional(),
321
+ name: zod_1.z.string().optional(),
322
+ items: zod_1.z.array(zod_1.z.unknown()).optional(),
323
+ metadata: Metadata.optional(),
324
+ })
325
+ .passthrough();
326
+ // Verified against the live Integration API (10.4.55). The WAN and
327
+ // site-to-site-tunnel list rows are intentionally minimal in the API.
328
+ const Wan = zod_1.z
329
+ .object({
330
+ id: zod_1.z.string(),
331
+ name: zod_1.z.string().optional(),
332
+ })
333
+ .passthrough();
334
+ const VpnServer = zod_1.z
335
+ .object({
336
+ id: zod_1.z.string(),
337
+ type: zod_1.z.string().optional(),
338
+ name: zod_1.z.string().optional(),
339
+ enabled: zod_1.z.boolean().optional(),
340
+ metadata: Metadata.optional(),
341
+ })
342
+ .passthrough();
343
+ // No tunnels present in the verification environment — keep loose.
344
+ const VpnTunnel = zod_1.z
345
+ .object({
346
+ id: zod_1.z.string(),
347
+ name: zod_1.z.string().optional(),
348
+ })
349
+ .passthrough();
350
+ const RadiusProfile = zod_1.z
351
+ .object({
352
+ id: zod_1.z.string(),
353
+ name: zod_1.z.string().optional(),
354
+ metadata: Metadata.optional(),
355
+ })
356
+ .passthrough();
357
+ // No tags present in the verification environment — documented shape.
358
+ const DeviceTag = zod_1.z
359
+ .object({
360
+ id: zod_1.z.string(),
361
+ name: zod_1.z.string().optional(),
362
+ deviceIds: zod_1.z.array(zod_1.z.string()).optional(),
363
+ })
364
+ .passthrough();
365
+ // DPI category/application ids are NUMERIC (verified live).
366
+ const DpiCategory = zod_1.z
367
+ .object({
368
+ id: zod_1.z.number(),
369
+ name: zod_1.z.string().optional(),
370
+ })
371
+ .passthrough();
372
+ const DpiApplication = zod_1.z
373
+ .object({
374
+ id: zod_1.z.number(),
375
+ name: zod_1.z.string().optional(),
376
+ })
377
+ .passthrough();
378
+ // Countries key on `code` (ISO alpha-2), NOT `id` (verified live).
379
+ const Country = zod_1.z
380
+ .object({
381
+ code: zod_1.z.string(),
382
+ name: zod_1.z.string().optional(),
383
+ })
384
+ .passthrough();
385
+ // No pending devices in the verification environment — keep loose.
386
+ const PendingDevice = zod_1.z
387
+ .object({
388
+ macAddress: zod_1.z.string().optional(),
389
+ model: zod_1.z.string().optional(),
390
+ ipAddress: zod_1.z.string().optional(),
391
+ firmwareVersion: zod_1.z.string().optional(),
392
+ })
393
+ .passthrough();
394
+ exports.getInfoOutputSchema = ApplicationInfo.shape;
395
+ exports.listSitesOutputSchema = {
396
+ ...PaginationFields,
397
+ data: zod_1.z.array(Site),
398
+ };
399
+ exports.networkOutputSchema = Network.shape;
400
+ exports.listNetworksOutputSchema = {
401
+ ...PaginationFields,
402
+ data: zod_1.z.array(Network),
403
+ };
404
+ exports.getNetworkReferencesOutputSchema = NetworkReferences.shape;
405
+ exports.voucherOutputSchema = Voucher.shape;
406
+ exports.listVouchersOutputSchema = {
407
+ ...PaginationFields,
408
+ data: zod_1.z.array(Voucher),
409
+ };
410
+ exports.createVouchersOutputSchema = {
411
+ ...PaginationFields,
412
+ data: zod_1.z.array(Voucher),
413
+ };
414
+ exports.firewallZoneOutputSchema = FirewallZone.shape;
415
+ exports.listFirewallZonesOutputSchema = {
416
+ ...PaginationFields,
417
+ data: zod_1.z.array(FirewallZone),
418
+ };
419
+ exports.firewallPolicyOutputSchema = FirewallPolicy.shape;
420
+ exports.listFirewallPoliciesOutputSchema = {
421
+ ...PaginationFields,
422
+ data: zod_1.z.array(FirewallPolicy),
423
+ };
424
+ exports.firewallPolicyOrderingOutputSchema = FirewallPolicyOrdering.shape;
425
+ exports.aclRuleOutputSchema = AclRule.shape;
426
+ exports.listAclRulesOutputSchema = {
427
+ ...PaginationFields,
428
+ data: zod_1.z.array(AclRule),
429
+ };
430
+ exports.aclRuleOrderingOutputSchema = AclRuleOrdering.shape;
431
+ exports.switchStackOutputSchema = SwitchStack.shape;
432
+ exports.listSwitchStacksOutputSchema = {
433
+ ...PaginationFields,
434
+ data: zod_1.z.array(SwitchStack),
435
+ };
436
+ exports.mcLagDomainOutputSchema = McLagDomain.shape;
437
+ exports.listMcLagDomainsOutputSchema = {
438
+ ...PaginationFields,
439
+ data: zod_1.z.array(McLagDomain),
440
+ };
441
+ exports.lagOutputSchema = Lag.shape;
442
+ exports.listLagsOutputSchema = {
443
+ ...PaginationFields,
444
+ data: zod_1.z.array(Lag),
445
+ };
446
+ exports.dnsPolicyOutputSchema = DnsPolicy.shape;
447
+ exports.listDnsPoliciesOutputSchema = {
448
+ ...PaginationFields,
449
+ data: zod_1.z.array(DnsPolicy),
450
+ };
451
+ exports.trafficMatchingListOutputSchema = TrafficMatchingList.shape;
452
+ exports.listTrafficMatchingListsOutputSchema = {
453
+ ...PaginationFields,
454
+ data: zod_1.z.array(TrafficMatchingList),
455
+ };
456
+ exports.listDevicesOutputSchema = {
457
+ ...PaginationFields,
458
+ data: zod_1.z.array(DeviceListItem),
459
+ };
460
+ exports.getDeviceOutputSchema = DeviceDetail.shape;
461
+ exports.getDeviceStatisticsOutputSchema = DeviceStatistics.shape;
462
+ exports.listClientsOutputSchema = {
463
+ ...PaginationFields,
464
+ data: zod_1.z.array(Client),
465
+ };
466
+ exports.getClientOutputSchema = Client.shape;
467
+ exports.listWifiOutputSchema = {
468
+ ...PaginationFields,
469
+ data: zod_1.z.array(WifiBroadcast),
470
+ };
471
+ exports.getWifiOutputSchema = WifiBroadcast.shape;
472
+ exports.listWansOutputSchema = {
473
+ ...PaginationFields,
474
+ data: zod_1.z.array(Wan),
475
+ };
476
+ exports.listVpnServersOutputSchema = {
477
+ ...PaginationFields,
478
+ data: zod_1.z.array(VpnServer),
479
+ };
480
+ exports.listVpnTunnelsOutputSchema = {
481
+ ...PaginationFields,
482
+ data: zod_1.z.array(VpnTunnel),
483
+ };
484
+ exports.listRadiusProfilesOutputSchema = {
485
+ ...PaginationFields,
486
+ data: zod_1.z.array(RadiusProfile),
487
+ };
488
+ exports.listDeviceTagsOutputSchema = {
489
+ ...PaginationFields,
490
+ data: zod_1.z.array(DeviceTag),
491
+ };
492
+ exports.listDpiCategoriesOutputSchema = {
493
+ ...PaginationFields,
494
+ data: zod_1.z.array(DpiCategory),
495
+ };
496
+ exports.listDpiApplicationsOutputSchema = {
497
+ ...PaginationFields,
498
+ data: zod_1.z.array(DpiApplication),
499
+ };
500
+ exports.listCountriesOutputSchema = {
501
+ ...PaginationFields,
502
+ data: zod_1.z.array(Country),
503
+ };
504
+ exports.listPendingDevicesOutputSchema = {
505
+ ...PaginationFields,
506
+ data: zod_1.z.array(PendingDevice),
507
+ };
@@ -1,8 +1,11 @@
1
- export declare function formatSuccess(data: unknown): {
1
+ export declare function formatSuccess(data: unknown, opts?: {
2
+ structured?: boolean;
3
+ }): {
2
4
  content: {
3
5
  type: "text";
4
6
  text: string;
5
7
  }[];
8
+ structuredContent?: Record<string, unknown>;
6
9
  };
7
10
  export declare function formatError(err: unknown): {
8
11
  content: {
@@ -2,12 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatSuccess = formatSuccess;
4
4
  exports.formatError = formatError;
5
- function formatSuccess(data) {
6
- return {
7
- content: [
8
- { type: "text", text: JSON.stringify(data, null, 2) },
9
- ],
5
+ function formatSuccess(data, opts) {
6
+ const result = {
7
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
10
8
  };
9
+ if (opts?.structured &&
10
+ data !== null &&
11
+ typeof data === "object" &&
12
+ !Array.isArray(data)) {
13
+ result.structuredContent = data;
14
+ }
15
+ return result;
11
16
  }
12
17
  function formatError(err) {
13
18
  const message = err instanceof Error ? err.message : String(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owine/unifi-network-mcp",
3
- "version": "2.6.0",
3
+ "version": "2.7.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@11.1.1",
25
+ "packageManager": "pnpm@11.1.2",
26
26
  "repository": {
27
27
  "type": "git",
28
28
  "url": "https://github.com/owine/unifi-network-mcp.git"
@@ -44,7 +44,7 @@
44
44
  "@eslint/js": "10.0.1",
45
45
  "@types/node": "24.12.4",
46
46
  "@vitest/coverage-v8": "4.1.6",
47
- "eslint": "10.3.0",
47
+ "eslint": "10.4.0",
48
48
  "lefthook": "2.1.6",
49
49
  "typescript": "6.0.3",
50
50
  "typescript-eslint": "8.59.3",