@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.
- package/dist/tools/acl.js +14 -8
- package/dist/tools/clients.js +9 -6
- package/dist/tools/devices.js +20 -12
- package/dist/tools/dns-policies.js +11 -6
- package/dist/tools/firewall.js +27 -16
- package/dist/tools/hotspot.js +10 -6
- package/dist/tools/networks.js +15 -9
- package/dist/tools/sites.js +4 -2
- package/dist/tools/supporting.js +25 -16
- package/dist/tools/switching.js +19 -12
- package/dist/tools/system.js +4 -2
- package/dist/tools/traffic-matching.js +11 -6
- package/dist/tools/wifi.js +11 -6
- package/dist/utils/output-schemas.d.ts +611 -0
- package/dist/utils/output-schemas.js +507 -0
- package/dist/utils/responses.d.ts +4 -1
- package/dist/utils/responses.js +10 -5
- package/package.json +3 -3
package/dist/tools/networks.js
CHANGED
|
@@ -5,9 +5,10 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const responses_js_1 = require("../utils/responses.js");
|
|
6
6
|
const query_js_1 = require("../utils/query.js");
|
|
7
7
|
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
8
9
|
function registerNetworkTools(server, client, readOnly = false) {
|
|
9
10
|
server.registerTool("unifi_list_networks", {
|
|
10
|
-
description: "List all networks at a site",
|
|
11
|
+
description: "List all networks (VLANs/LAN segments) at a site. Returns: id, name, management (UNMANAGED/GATEWAY/SWITCH), enabled, vlanId, default (true for the default network), dhcpGuarding, metadata.origin. NOTE: the list view is sparse — for subnet/DHCP/NTP detail (ipv4Configuration), call unifi_get_network on a specific id. Use for: VLAN inventory; pair with unifi_get_network_references to find what consumes a network.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
13
14
|
offset: zod_1.z
|
|
@@ -28,44 +29,47 @@ function registerNetworkTools(server, client, readOnly = false) {
|
|
|
28
29
|
.optional()
|
|
29
30
|
.describe("Filter expression"),
|
|
30
31
|
},
|
|
32
|
+
outputSchema: output_schemas_js_1.listNetworksOutputSchema,
|
|
31
33
|
annotations: safety_js_1.READ_ONLY,
|
|
32
34
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
33
35
|
try {
|
|
34
36
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
35
37
|
const data = await client.get(`/sites/${siteId}/networks${query}`);
|
|
36
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
38
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
37
39
|
}
|
|
38
40
|
catch (err) {
|
|
39
41
|
return (0, responses_js_1.formatError)(err);
|
|
40
42
|
}
|
|
41
43
|
});
|
|
42
44
|
server.registerTool("unifi_get_network", {
|
|
43
|
-
description: "Get a
|
|
45
|
+
description: "Get a network/VLAN by ID. Returns the list fields PLUS (live-verified) zoneId, isolationEnabled, internetAccessEnabled, mdnsForwardingEnabled, cellularBackupEnabled, and a full ipv4Configuration object (hostIpAddress, prefixLength, dhcpConfiguration with ipAddressRange/leaseTimeSeconds/domainName/ntpServerIpAddresses). NOTE: subnet/DHCP detail appears here at get-by-id but NOT in unifi_list_networks (sparse list view).",
|
|
44
46
|
inputSchema: {
|
|
45
47
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
46
48
|
networkId: zod_1.z.string().describe("Network ID"),
|
|
47
49
|
},
|
|
50
|
+
outputSchema: output_schemas_js_1.networkOutputSchema,
|
|
48
51
|
annotations: safety_js_1.READ_ONLY,
|
|
49
52
|
}, async ({ siteId, networkId }) => {
|
|
50
53
|
try {
|
|
51
54
|
const data = await client.get(`/sites/${siteId}/networks/${networkId}`);
|
|
52
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
55
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
53
56
|
}
|
|
54
57
|
catch (err) {
|
|
55
58
|
return (0, responses_js_1.formatError)(err);
|
|
56
59
|
}
|
|
57
60
|
});
|
|
58
61
|
server.registerTool("unifi_get_network_references", {
|
|
59
|
-
description: "Get
|
|
62
|
+
description: "Get all objects that reference this network (WiFi broadcasts, firewall zones, etc.). Returns: { referenceResources: [...] }. Use before deleting a network to find dependencies that need to be re-pointed or removed.",
|
|
60
63
|
inputSchema: {
|
|
61
64
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
62
65
|
networkId: zod_1.z.string().describe("Network ID"),
|
|
63
66
|
},
|
|
67
|
+
outputSchema: output_schemas_js_1.getNetworkReferencesOutputSchema,
|
|
64
68
|
annotations: safety_js_1.READ_ONLY,
|
|
65
69
|
}, async ({ siteId, networkId }) => {
|
|
66
70
|
try {
|
|
67
71
|
const data = await client.get(`/sites/${siteId}/networks/${networkId}/references`);
|
|
68
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
72
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
69
73
|
}
|
|
70
74
|
catch (err) {
|
|
71
75
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -74,7 +78,7 @@ function registerNetworkTools(server, client, readOnly = false) {
|
|
|
74
78
|
if (readOnly)
|
|
75
79
|
return;
|
|
76
80
|
server.registerTool("unifi_create_network", {
|
|
77
|
-
description: "Create a new network",
|
|
81
|
+
description: "Create a new VLAN/network. management=GATEWAY means routed via UDM/UXG; SWITCH means VLAN-only; UNMANAGED means external. Idempotency: not safe to retry — re-running creates duplicates.",
|
|
78
82
|
inputSchema: {
|
|
79
83
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
80
84
|
name: zod_1.z.string().describe("Network name"),
|
|
@@ -97,6 +101,7 @@ function registerNetworkTools(server, client, readOnly = false) {
|
|
|
97
101
|
.optional()
|
|
98
102
|
.describe("Preview this action without executing it"),
|
|
99
103
|
},
|
|
104
|
+
outputSchema: output_schemas_js_1.networkOutputSchema,
|
|
100
105
|
annotations: safety_js_1.WRITE_NOT_IDEMPOTENT,
|
|
101
106
|
}, async ({ siteId, name, management, enabled, vlanId, dhcpGuarding, dryRun }) => {
|
|
102
107
|
try {
|
|
@@ -106,7 +111,7 @@ function registerNetworkTools(server, client, readOnly = false) {
|
|
|
106
111
|
if (dryRun)
|
|
107
112
|
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/networks`, body);
|
|
108
113
|
const data = await client.post(`/sites/${siteId}/networks`, body);
|
|
109
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
114
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
110
115
|
}
|
|
111
116
|
catch (err) {
|
|
112
117
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -137,6 +142,7 @@ function registerNetworkTools(server, client, readOnly = false) {
|
|
|
137
142
|
.optional()
|
|
138
143
|
.describe("Preview this action without executing it"),
|
|
139
144
|
},
|
|
145
|
+
outputSchema: output_schemas_js_1.networkOutputSchema,
|
|
140
146
|
annotations: safety_js_1.WRITE,
|
|
141
147
|
}, async ({ siteId, networkId, name, management, enabled, vlanId, dhcpGuarding, dryRun }) => {
|
|
142
148
|
try {
|
|
@@ -146,7 +152,7 @@ function registerNetworkTools(server, client, readOnly = false) {
|
|
|
146
152
|
if (dryRun)
|
|
147
153
|
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/networks/${networkId}`, body);
|
|
148
154
|
const data = await client.put(`/sites/${siteId}/networks/${networkId}`, body);
|
|
149
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
155
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
150
156
|
}
|
|
151
157
|
catch (err) {
|
|
152
158
|
return (0, responses_js_1.formatError)(err);
|
package/dist/tools/sites.js
CHANGED
|
@@ -5,9 +5,10 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const responses_js_1 = require("../utils/responses.js");
|
|
6
6
|
const query_js_1 = require("../utils/query.js");
|
|
7
7
|
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
8
9
|
function registerSiteTools(server, client) {
|
|
9
10
|
server.registerTool("unifi_list_sites", {
|
|
10
|
-
description: "List all sites
|
|
11
|
+
description: "List all sites the API key has access to. Returns: id (the siteId every other tool requires), internalReference, name. Use for: first call in any workflow — almost every other tool needs a siteId.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
offset: zod_1.z
|
|
13
14
|
.number()
|
|
@@ -27,12 +28,13 @@ function registerSiteTools(server, client) {
|
|
|
27
28
|
.optional()
|
|
28
29
|
.describe("Filter expression (e.g., 'name.like(office*)')"),
|
|
29
30
|
},
|
|
31
|
+
outputSchema: output_schemas_js_1.listSitesOutputSchema,
|
|
30
32
|
annotations: safety_js_1.READ_ONLY,
|
|
31
33
|
}, async ({ offset, limit, filter }) => {
|
|
32
34
|
try {
|
|
33
35
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
34
36
|
const data = await client.get(`/sites${query}`);
|
|
35
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
37
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
36
38
|
}
|
|
37
39
|
catch (err) {
|
|
38
40
|
return (0, responses_js_1.formatError)(err);
|
package/dist/tools/supporting.js
CHANGED
|
@@ -5,9 +5,10 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const responses_js_1 = require("../utils/responses.js");
|
|
6
6
|
const query_js_1 = require("../utils/query.js");
|
|
7
7
|
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
8
9
|
function registerSupportingTools(server, client) {
|
|
9
10
|
server.registerTool("unifi_list_wans", {
|
|
10
|
-
description: "List
|
|
11
|
+
description: "List WAN interface definitions at a site. Returns: id, name only (verified against 10.4.55 — the Integration API exposes no live link status or throughput rates here). Use for: WAN inventory, multi-WAN topology.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
13
14
|
offset: zod_1.z
|
|
@@ -24,19 +25,20 @@ function registerSupportingTools(server, client) {
|
|
|
24
25
|
.optional()
|
|
25
26
|
.describe("Number of records to return (default: 25, max: 200)"),
|
|
26
27
|
},
|
|
28
|
+
outputSchema: output_schemas_js_1.listWansOutputSchema,
|
|
27
29
|
annotations: safety_js_1.READ_ONLY,
|
|
28
30
|
}, async ({ siteId, offset, limit }) => {
|
|
29
31
|
try {
|
|
30
32
|
const query = (0, query_js_1.buildQuery)({ offset, limit });
|
|
31
33
|
const data = await client.get(`/sites/${siteId}/wans${query}`);
|
|
32
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
34
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
33
35
|
}
|
|
34
36
|
catch (err) {
|
|
35
37
|
return (0, responses_js_1.formatError)(err);
|
|
36
38
|
}
|
|
37
39
|
});
|
|
38
40
|
server.registerTool("unifi_list_vpn_tunnels", {
|
|
39
|
-
description: "List
|
|
41
|
+
description: "List site-to-site VPN tunnels (IPsec, WireGuard, OpenVPN site-to-site) at a site. Returns: tunnel definitions per row (per-row schema not rendered in 10.4.55 docs — call to inspect). For roaming client VPN servers, see unifi_list_vpn_servers.",
|
|
40
42
|
inputSchema: {
|
|
41
43
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
42
44
|
offset: zod_1.z
|
|
@@ -57,19 +59,20 @@ function registerSupportingTools(server, client) {
|
|
|
57
59
|
.optional()
|
|
58
60
|
.describe("Filter expression"),
|
|
59
61
|
},
|
|
62
|
+
outputSchema: output_schemas_js_1.listVpnTunnelsOutputSchema,
|
|
60
63
|
annotations: safety_js_1.READ_ONLY,
|
|
61
64
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
62
65
|
try {
|
|
63
66
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
64
67
|
const data = await client.get(`/sites/${siteId}/vpn/site-to-site-tunnels${query}`);
|
|
65
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
68
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
66
69
|
}
|
|
67
70
|
catch (err) {
|
|
68
71
|
return (0, responses_js_1.formatError)(err);
|
|
69
72
|
}
|
|
70
73
|
});
|
|
71
74
|
server.registerTool("unifi_list_vpn_servers", {
|
|
72
|
-
description: "List
|
|
75
|
+
description: "List VPN servers (roaming/client-access VPNs: WireGuard, OpenVPN, L2TP, Teleport) at a site. Returns: id, type (e.g. WIREGUARD, UID), name, enabled, metadata.origin.",
|
|
73
76
|
inputSchema: {
|
|
74
77
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
75
78
|
offset: zod_1.z
|
|
@@ -90,19 +93,20 @@ function registerSupportingTools(server, client) {
|
|
|
90
93
|
.optional()
|
|
91
94
|
.describe("Filter expression"),
|
|
92
95
|
},
|
|
96
|
+
outputSchema: output_schemas_js_1.listVpnServersOutputSchema,
|
|
93
97
|
annotations: safety_js_1.READ_ONLY,
|
|
94
98
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
95
99
|
try {
|
|
96
100
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
97
101
|
const data = await client.get(`/sites/${siteId}/vpn/servers${query}`);
|
|
98
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
102
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
99
103
|
}
|
|
100
104
|
catch (err) {
|
|
101
105
|
return (0, responses_js_1.formatError)(err);
|
|
102
106
|
}
|
|
103
107
|
});
|
|
104
108
|
server.registerTool("unifi_list_radius_profiles", {
|
|
105
|
-
description: "List
|
|
109
|
+
description: "List RADIUS profiles (auth/accounting server configurations referenced by WiFi WPA-Enterprise, switch 802.1X port auth, VPN). Returns: id, name, metadata (origin, configurable).",
|
|
106
110
|
inputSchema: {
|
|
107
111
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
108
112
|
offset: zod_1.z
|
|
@@ -123,19 +127,20 @@ function registerSupportingTools(server, client) {
|
|
|
123
127
|
.optional()
|
|
124
128
|
.describe("Filter expression"),
|
|
125
129
|
},
|
|
130
|
+
outputSchema: output_schemas_js_1.listRadiusProfilesOutputSchema,
|
|
126
131
|
annotations: safety_js_1.READ_ONLY,
|
|
127
132
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
128
133
|
try {
|
|
129
134
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
130
135
|
const data = await client.get(`/sites/${siteId}/radius/profiles${query}`);
|
|
131
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
136
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
132
137
|
}
|
|
133
138
|
catch (err) {
|
|
134
139
|
return (0, responses_js_1.formatError)(err);
|
|
135
140
|
}
|
|
136
141
|
});
|
|
137
142
|
server.registerTool("unifi_list_device_tags", {
|
|
138
|
-
description: "List
|
|
143
|
+
description: "List device tags at a site. Tags group APs/switches for selective WiFi broadcast (via broadcastingDeviceFilter on a WiFi network). Returns: id, name, deviceIds[].",
|
|
139
144
|
inputSchema: {
|
|
140
145
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
141
146
|
offset: zod_1.z
|
|
@@ -156,19 +161,20 @@ function registerSupportingTools(server, client) {
|
|
|
156
161
|
.optional()
|
|
157
162
|
.describe("Filter expression"),
|
|
158
163
|
},
|
|
164
|
+
outputSchema: output_schemas_js_1.listDeviceTagsOutputSchema,
|
|
159
165
|
annotations: safety_js_1.READ_ONLY,
|
|
160
166
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
161
167
|
try {
|
|
162
168
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
163
169
|
const data = await client.get(`/sites/${siteId}/device-tags${query}`);
|
|
164
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
170
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
165
171
|
}
|
|
166
172
|
catch (err) {
|
|
167
173
|
return (0, responses_js_1.formatError)(err);
|
|
168
174
|
}
|
|
169
175
|
});
|
|
170
176
|
server.registerTool("unifi_list_dpi_categories", {
|
|
171
|
-
description: "List
|
|
177
|
+
description: "List DPI categories (global, not site-scoped) — high-level traffic groupings like 'Streaming', 'Social Networks', 'Gaming'. Returns: id (numeric), name. Use the category id when building firewall policies that match by category.",
|
|
172
178
|
inputSchema: {
|
|
173
179
|
offset: zod_1.z
|
|
174
180
|
.number()
|
|
@@ -188,19 +194,20 @@ function registerSupportingTools(server, client) {
|
|
|
188
194
|
.optional()
|
|
189
195
|
.describe("Filter expression"),
|
|
190
196
|
},
|
|
197
|
+
outputSchema: output_schemas_js_1.listDpiCategoriesOutputSchema,
|
|
191
198
|
annotations: safety_js_1.READ_ONLY,
|
|
192
199
|
}, async ({ offset, limit, filter }) => {
|
|
193
200
|
try {
|
|
194
201
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
195
202
|
const data = await client.get(`/dpi/categories${query}`);
|
|
196
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
203
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
197
204
|
}
|
|
198
205
|
catch (err) {
|
|
199
206
|
return (0, responses_js_1.formatError)(err);
|
|
200
207
|
}
|
|
201
208
|
});
|
|
202
209
|
server.registerTool("unifi_list_dpi_applications", {
|
|
203
|
-
description: "List
|
|
210
|
+
description: "List individual DPI applications (global) — specific apps/services like 'Netflix', 'Zoom', 'Steam'. Returns: id (numeric), name. More granular than unifi_list_dpi_categories.",
|
|
204
211
|
inputSchema: {
|
|
205
212
|
offset: zod_1.z
|
|
206
213
|
.number()
|
|
@@ -220,19 +227,20 @@ function registerSupportingTools(server, client) {
|
|
|
220
227
|
.optional()
|
|
221
228
|
.describe("Filter expression"),
|
|
222
229
|
},
|
|
230
|
+
outputSchema: output_schemas_js_1.listDpiApplicationsOutputSchema,
|
|
223
231
|
annotations: safety_js_1.READ_ONLY,
|
|
224
232
|
}, async ({ offset, limit, filter }) => {
|
|
225
233
|
try {
|
|
226
234
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
227
235
|
const data = await client.get(`/dpi/applications${query}`);
|
|
228
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
236
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
229
237
|
}
|
|
230
238
|
catch (err) {
|
|
231
239
|
return (0, responses_js_1.formatError)(err);
|
|
232
240
|
}
|
|
233
241
|
});
|
|
234
242
|
server.registerTool("unifi_list_countries", {
|
|
235
|
-
description: "List
|
|
243
|
+
description: "List countries/regions (global) for geo-IP firewall rules. Returns: code (ISO alpha-2, e.g. 'US'), name. Use the code when building firewall policies that match by source/destination country.",
|
|
236
244
|
inputSchema: {
|
|
237
245
|
offset: zod_1.z
|
|
238
246
|
.number()
|
|
@@ -252,12 +260,13 @@ function registerSupportingTools(server, client) {
|
|
|
252
260
|
.optional()
|
|
253
261
|
.describe("Filter expression (e.g., 'name.like(United*)')"),
|
|
254
262
|
},
|
|
263
|
+
outputSchema: output_schemas_js_1.listCountriesOutputSchema,
|
|
255
264
|
annotations: safety_js_1.READ_ONLY,
|
|
256
265
|
}, async ({ offset, limit, filter }) => {
|
|
257
266
|
try {
|
|
258
267
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
259
268
|
const data = await client.get(`/countries${query}`);
|
|
260
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
269
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
261
270
|
}
|
|
262
271
|
catch (err) {
|
|
263
272
|
return (0, responses_js_1.formatError)(err);
|
package/dist/tools/switching.js
CHANGED
|
@@ -5,9 +5,10 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const responses_js_1 = require("../utils/responses.js");
|
|
6
6
|
const query_js_1 = require("../utils/query.js");
|
|
7
7
|
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
8
9
|
function registerSwitchingTools(server, client) {
|
|
9
10
|
server.registerTool("unifi_list_switch_stacks", {
|
|
10
|
-
description: "List
|
|
11
|
+
description: "List Switch Stacks (multiple physical switches managed as one logical unit) at a site. Returns: id, name, members[], lags[] (LAGs spanning the stack), metadata.origin. Use for: identifying stacked switches; individual member configs/stats still come from unifi_get_device.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
13
14
|
offset: zod_1.z
|
|
@@ -28,35 +29,37 @@ function registerSwitchingTools(server, client) {
|
|
|
28
29
|
.optional()
|
|
29
30
|
.describe("Filter expression"),
|
|
30
31
|
},
|
|
32
|
+
outputSchema: output_schemas_js_1.listSwitchStacksOutputSchema,
|
|
31
33
|
annotations: safety_js_1.READ_ONLY,
|
|
32
34
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
33
35
|
try {
|
|
34
36
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
35
37
|
const data = await client.get(`/sites/${siteId}/switching/switch-stacks${query}`);
|
|
36
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
38
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
37
39
|
}
|
|
38
40
|
catch (err) {
|
|
39
41
|
return (0, responses_js_1.formatError)(err);
|
|
40
42
|
}
|
|
41
43
|
});
|
|
42
44
|
server.registerTool("unifi_get_switch_stack", {
|
|
43
|
-
description: "Get details of a
|
|
45
|
+
description: "Get full details of a Switch Stack including all members and stacking topology. Returns the same fields as the list response but for a single stack.",
|
|
44
46
|
inputSchema: {
|
|
45
47
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
46
48
|
switchStackId: zod_1.z.string().describe("Switch Stack ID"),
|
|
47
49
|
},
|
|
50
|
+
outputSchema: output_schemas_js_1.switchStackOutputSchema,
|
|
48
51
|
annotations: safety_js_1.READ_ONLY,
|
|
49
52
|
}, async ({ siteId, switchStackId }) => {
|
|
50
53
|
try {
|
|
51
54
|
const data = await client.get(`/sites/${siteId}/switching/switch-stacks/${switchStackId}`);
|
|
52
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
55
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
53
56
|
}
|
|
54
57
|
catch (err) {
|
|
55
58
|
return (0, responses_js_1.formatError)(err);
|
|
56
59
|
}
|
|
57
60
|
});
|
|
58
61
|
server.registerTool("unifi_list_mc_lag_domains", {
|
|
59
|
-
description: "List
|
|
62
|
+
description: "List MC-LAG (Multi-Chassis Link Aggregation) Domains — pairs of switches presenting as one for LAG redundancy. Returns: id, name, peers[], lags[] (LAGs spanning the domain), metadata.origin.",
|
|
60
63
|
inputSchema: {
|
|
61
64
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
62
65
|
offset: zod_1.z
|
|
@@ -77,35 +80,37 @@ function registerSwitchingTools(server, client) {
|
|
|
77
80
|
.optional()
|
|
78
81
|
.describe("Filter expression"),
|
|
79
82
|
},
|
|
83
|
+
outputSchema: output_schemas_js_1.listMcLagDomainsOutputSchema,
|
|
80
84
|
annotations: safety_js_1.READ_ONLY,
|
|
81
85
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
82
86
|
try {
|
|
83
87
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
84
88
|
const data = await client.get(`/sites/${siteId}/switching/mc-lag-domains${query}`);
|
|
85
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
89
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
86
90
|
}
|
|
87
91
|
catch (err) {
|
|
88
92
|
return (0, responses_js_1.formatError)(err);
|
|
89
93
|
}
|
|
90
94
|
});
|
|
91
95
|
server.registerTool("unifi_get_mc_lag_domain", {
|
|
92
|
-
description: "Get details of
|
|
96
|
+
description: "Get full details of an MC-LAG Domain (peer switches and member LAGs).",
|
|
93
97
|
inputSchema: {
|
|
94
98
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
95
99
|
mcLagDomainId: zod_1.z.string().describe("MC-LAG Domain ID"),
|
|
96
100
|
},
|
|
101
|
+
outputSchema: output_schemas_js_1.mcLagDomainOutputSchema,
|
|
97
102
|
annotations: safety_js_1.READ_ONLY,
|
|
98
103
|
}, async ({ siteId, mcLagDomainId }) => {
|
|
99
104
|
try {
|
|
100
105
|
const data = await client.get(`/sites/${siteId}/switching/mc-lag-domains/${mcLagDomainId}`);
|
|
101
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
106
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
102
107
|
}
|
|
103
108
|
catch (err) {
|
|
104
109
|
return (0, responses_js_1.formatError)(err);
|
|
105
110
|
}
|
|
106
111
|
});
|
|
107
112
|
server.registerTool("unifi_list_lags", {
|
|
108
|
-
description: "List
|
|
113
|
+
description: "List LAGs (Link Aggregation Groups — bonded switch ports) at a site. Returns: id, type (LOCAL/SWITCH_STACK/MULTI_CHASSIS), members[], metadata.origin.",
|
|
109
114
|
inputSchema: {
|
|
110
115
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
111
116
|
offset: zod_1.z
|
|
@@ -126,28 +131,30 @@ function registerSwitchingTools(server, client) {
|
|
|
126
131
|
.optional()
|
|
127
132
|
.describe("Filter expression"),
|
|
128
133
|
},
|
|
134
|
+
outputSchema: output_schemas_js_1.listLagsOutputSchema,
|
|
129
135
|
annotations: safety_js_1.READ_ONLY,
|
|
130
136
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
131
137
|
try {
|
|
132
138
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
133
139
|
const data = await client.get(`/sites/${siteId}/switching/lags${query}`);
|
|
134
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
140
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
135
141
|
}
|
|
136
142
|
catch (err) {
|
|
137
143
|
return (0, responses_js_1.formatError)(err);
|
|
138
144
|
}
|
|
139
145
|
});
|
|
140
146
|
server.registerTool("unifi_get_lag", {
|
|
141
|
-
description: "Get details of a
|
|
147
|
+
description: "Get full details of a LAG including its type (LOCAL/SWITCH_STACK/MULTI_CHASSIS) and member ports.",
|
|
142
148
|
inputSchema: {
|
|
143
149
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
144
150
|
lagId: zod_1.z.string().describe("LAG ID"),
|
|
145
151
|
},
|
|
152
|
+
outputSchema: output_schemas_js_1.lagOutputSchema,
|
|
146
153
|
annotations: safety_js_1.READ_ONLY,
|
|
147
154
|
}, async ({ siteId, lagId }) => {
|
|
148
155
|
try {
|
|
149
156
|
const data = await client.get(`/sites/${siteId}/switching/lags/${lagId}`);
|
|
150
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
157
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
151
158
|
}
|
|
152
159
|
catch (err) {
|
|
153
160
|
return (0, responses_js_1.formatError)(err);
|
package/dist/tools/system.js
CHANGED
|
@@ -3,15 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registerSystemTools = registerSystemTools;
|
|
4
4
|
const responses_js_1 = require("../utils/responses.js");
|
|
5
5
|
const safety_js_1 = require("../utils/safety.js");
|
|
6
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
6
7
|
function registerSystemTools(server, client) {
|
|
7
8
|
server.registerTool("unifi_get_info", {
|
|
8
|
-
description: "Get application
|
|
9
|
+
description: "Get UniFi Network application info. Returns: applicationVersion. NOTE: verified against 10.4.55 on a UniFi OS console — the Integration API returns ONLY applicationVersion here; there is no isUniFiOSConsole or other field. Use for: version checks before calling version-gated tools.",
|
|
9
10
|
inputSchema: {},
|
|
11
|
+
outputSchema: output_schemas_js_1.getInfoOutputSchema,
|
|
10
12
|
annotations: safety_js_1.READ_ONLY,
|
|
11
13
|
}, async () => {
|
|
12
14
|
try {
|
|
13
15
|
const data = await client.get("/info");
|
|
14
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
16
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
15
17
|
}
|
|
16
18
|
catch (err) {
|
|
17
19
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -5,9 +5,10 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const responses_js_1 = require("../utils/responses.js");
|
|
6
6
|
const query_js_1 = require("../utils/query.js");
|
|
7
7
|
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
8
9
|
function registerTrafficMatchingTools(server, client, readOnly = false) {
|
|
9
10
|
server.registerTool("unifi_list_traffic_matching_lists", {
|
|
10
|
-
description: "List
|
|
11
|
+
description: "List traffic matching lists at a site — named collections of ports or IPs reused in firewall/ACL rules. Returns: id, type (PORTS/IPV4_ADDRESSES/IPV6_ADDRESSES), name, items[]. Use for: finding the matching-list ID to reference from a firewall policy.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
13
14
|
offset: zod_1.z
|
|
@@ -28,28 +29,30 @@ function registerTrafficMatchingTools(server, client, readOnly = false) {
|
|
|
28
29
|
.optional()
|
|
29
30
|
.describe("Filter expression"),
|
|
30
31
|
},
|
|
32
|
+
outputSchema: output_schemas_js_1.listTrafficMatchingListsOutputSchema,
|
|
31
33
|
annotations: safety_js_1.READ_ONLY,
|
|
32
34
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
33
35
|
try {
|
|
34
36
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
35
37
|
const data = await client.get(`/sites/${siteId}/traffic-matching-lists${query}`);
|
|
36
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
38
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
37
39
|
}
|
|
38
40
|
catch (err) {
|
|
39
41
|
return (0, responses_js_1.formatError)(err);
|
|
40
42
|
}
|
|
41
43
|
});
|
|
42
44
|
server.registerTool("unifi_get_traffic_matching_list", {
|
|
43
|
-
description: "Get a specific traffic matching list by ID",
|
|
45
|
+
description: "Get a specific traffic matching list by ID (full items array).",
|
|
44
46
|
inputSchema: {
|
|
45
47
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
46
48
|
trafficMatchingListId: zod_1.z.string().describe("Traffic matching list ID"),
|
|
47
49
|
},
|
|
50
|
+
outputSchema: output_schemas_js_1.trafficMatchingListOutputSchema,
|
|
48
51
|
annotations: safety_js_1.READ_ONLY,
|
|
49
52
|
}, async ({ siteId, trafficMatchingListId }) => {
|
|
50
53
|
try {
|
|
51
54
|
const data = await client.get(`/sites/${siteId}/traffic-matching-lists/${trafficMatchingListId}`);
|
|
52
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
55
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
53
56
|
}
|
|
54
57
|
catch (err) {
|
|
55
58
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -74,6 +77,7 @@ function registerTrafficMatchingTools(server, client, readOnly = false) {
|
|
|
74
77
|
.optional()
|
|
75
78
|
.describe("Preview this action without executing it"),
|
|
76
79
|
},
|
|
80
|
+
outputSchema: output_schemas_js_1.trafficMatchingListOutputSchema,
|
|
77
81
|
annotations: safety_js_1.WRITE_NOT_IDEMPOTENT,
|
|
78
82
|
}, async ({ siteId, type, name, items, dryRun }) => {
|
|
79
83
|
try {
|
|
@@ -81,7 +85,7 @@ function registerTrafficMatchingTools(server, client, readOnly = false) {
|
|
|
81
85
|
if (dryRun)
|
|
82
86
|
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/traffic-matching-lists`, body);
|
|
83
87
|
const data = await client.post(`/sites/${siteId}/traffic-matching-lists`, body);
|
|
84
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
88
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
85
89
|
}
|
|
86
90
|
catch (err) {
|
|
87
91
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -102,6 +106,7 @@ function registerTrafficMatchingTools(server, client, readOnly = false) {
|
|
|
102
106
|
.optional()
|
|
103
107
|
.describe("Preview this action without executing it"),
|
|
104
108
|
},
|
|
109
|
+
outputSchema: output_schemas_js_1.trafficMatchingListOutputSchema,
|
|
105
110
|
annotations: safety_js_1.WRITE,
|
|
106
111
|
}, async ({ siteId, trafficMatchingListId, type, name, items, dryRun }) => {
|
|
107
112
|
try {
|
|
@@ -109,7 +114,7 @@ function registerTrafficMatchingTools(server, client, readOnly = false) {
|
|
|
109
114
|
if (dryRun)
|
|
110
115
|
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/traffic-matching-lists/${trafficMatchingListId}`, body);
|
|
111
116
|
const data = await client.put(`/sites/${siteId}/traffic-matching-lists/${trafficMatchingListId}`, body);
|
|
112
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
117
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
113
118
|
}
|
|
114
119
|
catch (err) {
|
|
115
120
|
return (0, responses_js_1.formatError)(err);
|
package/dist/tools/wifi.js
CHANGED
|
@@ -5,9 +5,10 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const responses_js_1 = require("../utils/responses.js");
|
|
6
6
|
const query_js_1 = require("../utils/query.js");
|
|
7
7
|
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
const output_schemas_js_1 = require("../utils/output-schemas.js");
|
|
8
9
|
function registerWifiTools(server, client, readOnly = false) {
|
|
9
10
|
server.registerTool("unifi_list_wifi", {
|
|
10
|
-
description: "List all WiFi broadcasts (SSIDs) at a site",
|
|
11
|
+
description: "List all WiFi broadcasts (SSIDs) at a site. Returns: id, name (SSID), enabled, type (STANDARD/IOT_OPTIMIZED), broadcastingFrequenciesGHz (2.4/5/6), securityConfiguration, hideName, bandSteeringEnabled, mloEnabled, network reference, broadcastingDeviceFilter (which APs broadcast it). Use for: SSID inventory. For per-AP radio state (channel, txPower), use unifi_get_device on the AP.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
13
14
|
offset: zod_1.z
|
|
@@ -28,28 +29,30 @@ function registerWifiTools(server, client, readOnly = false) {
|
|
|
28
29
|
.optional()
|
|
29
30
|
.describe("Filter expression"),
|
|
30
31
|
},
|
|
32
|
+
outputSchema: output_schemas_js_1.listWifiOutputSchema,
|
|
31
33
|
annotations: safety_js_1.READ_ONLY,
|
|
32
34
|
}, async ({ siteId, offset, limit, filter }) => {
|
|
33
35
|
try {
|
|
34
36
|
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
35
37
|
const data = await client.get(`/sites/${siteId}/wifi/broadcasts${query}`);
|
|
36
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
38
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
37
39
|
}
|
|
38
40
|
catch (err) {
|
|
39
41
|
return (0, responses_js_1.formatError)(err);
|
|
40
42
|
}
|
|
41
43
|
});
|
|
42
44
|
server.registerTool("unifi_get_wifi", {
|
|
43
|
-
description: "Get a
|
|
45
|
+
description: "Get full configuration for a WiFi broadcast (SSID), including all optional fields not always returned by list: clientFilteringPolicy, blackoutScheduleConfiguration, hotspotConfiguration, mdnsProxyConfiguration, handoffSuggestionsConfiguration, dtimPeriodByFrequencyGHzOverride, etc.",
|
|
44
46
|
inputSchema: {
|
|
45
47
|
siteId: zod_1.z.string().describe("Site ID"),
|
|
46
48
|
wifiBroadcastId: zod_1.z.string().describe("WiFi Broadcast ID"),
|
|
47
49
|
},
|
|
50
|
+
outputSchema: output_schemas_js_1.getWifiOutputSchema,
|
|
48
51
|
annotations: safety_js_1.READ_ONLY,
|
|
49
52
|
}, async ({ siteId, wifiBroadcastId }) => {
|
|
50
53
|
try {
|
|
51
54
|
const data = await client.get(`/sites/${siteId}/wifi/broadcasts/${wifiBroadcastId}`);
|
|
52
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
55
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
53
56
|
}
|
|
54
57
|
catch (err) {
|
|
55
58
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -150,6 +153,7 @@ function registerWifiTools(server, client, readOnly = false) {
|
|
|
150
153
|
.optional()
|
|
151
154
|
.describe("Preview this action without executing it"),
|
|
152
155
|
},
|
|
156
|
+
outputSchema: output_schemas_js_1.getWifiOutputSchema,
|
|
153
157
|
annotations: safety_js_1.WRITE_NOT_IDEMPOTENT,
|
|
154
158
|
}, async ({ siteId, name, enabled, type, broadcastingFrequenciesGHz, securityConfiguration, multicastToUnicastConversionEnabled, clientIsolationEnabled, hideName, uapsdEnabled, arpProxyEnabled, bssTransitionEnabled, advertiseDeviceName, channel2gLockedTo6, dtimPeriod2gLockedTo3, network, broadcastingDeviceFilter, mdnsProxyConfiguration, multicastFilteringPolicy, basicDataRateKbpsByFrequencyGHz, clientFilteringPolicy, blackoutScheduleConfiguration, hotspotConfiguration, mloEnabled, bandSteeringEnabled, dtimPeriodByFrequencyGHzOverride, dnsAssistanceConfiguration, handoffSuggestionsConfiguration, dryRun, }) => {
|
|
155
159
|
try {
|
|
@@ -198,7 +202,7 @@ function registerWifiTools(server, client, readOnly = false) {
|
|
|
198
202
|
if (dryRun)
|
|
199
203
|
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/wifi/broadcasts`, body);
|
|
200
204
|
const data = await client.post(`/sites/${siteId}/wifi/broadcasts`, body);
|
|
201
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
205
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
202
206
|
}
|
|
203
207
|
catch (err) {
|
|
204
208
|
return (0, responses_js_1.formatError)(err);
|
|
@@ -313,6 +317,7 @@ function registerWifiTools(server, client, readOnly = false) {
|
|
|
313
317
|
.optional()
|
|
314
318
|
.describe("Preview this action without executing it"),
|
|
315
319
|
},
|
|
320
|
+
outputSchema: output_schemas_js_1.getWifiOutputSchema,
|
|
316
321
|
annotations: safety_js_1.WRITE,
|
|
317
322
|
}, async ({ siteId, wifiBroadcastId, name, enabled, type, broadcastingFrequenciesGHz, securityConfiguration, multicastToUnicastConversionEnabled, clientIsolationEnabled, hideName, uapsdEnabled, arpProxyEnabled, bssTransitionEnabled, advertiseDeviceName, channel2gLockedTo6, dtimPeriod2gLockedTo3, network, broadcastingDeviceFilter, mdnsProxyConfiguration, multicastFilteringPolicy, basicDataRateKbpsByFrequencyGHz, clientFilteringPolicy, blackoutScheduleConfiguration, hotspotConfiguration, mloEnabled, bandSteeringEnabled, dtimPeriodByFrequencyGHzOverride, dnsAssistanceConfiguration, handoffSuggestionsConfiguration, dryRun, }) => {
|
|
318
323
|
try {
|
|
@@ -375,7 +380,7 @@ function registerWifiTools(server, client, readOnly = false) {
|
|
|
375
380
|
if (dryRun)
|
|
376
381
|
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/wifi/broadcasts/${wifiBroadcastId}`, body);
|
|
377
382
|
const data = await client.put(`/sites/${siteId}/wifi/broadcasts/${wifiBroadcastId}`, body);
|
|
378
|
-
return (0, responses_js_1.formatSuccess)(data);
|
|
383
|
+
return (0, responses_js_1.formatSuccess)(data, { structured: true });
|
|
379
384
|
}
|
|
380
385
|
catch (err) {
|
|
381
386
|
return (0, responses_js_1.formatError)(err);
|