@owine/unifi-network-mcp 0.9.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 +241 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.js +53 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +29 -0
- package/dist/tools/acl.d.ts +3 -0
- package/dist/tools/acl.js +164 -0
- package/dist/tools/clients.d.ts +3 -0
- package/dist/tools/clients.js +119 -0
- package/dist/tools/devices.d.ts +3 -0
- package/dist/tools/devices.js +157 -0
- package/dist/tools/dns-policies.d.ts +3 -0
- package/dist/tools/dns-policies.js +118 -0
- package/dist/tools/firewall.d.ts +3 -0
- package/dist/tools/firewall.js +271 -0
- package/dist/tools/hotspot.d.ts +3 -0
- package/dist/tools/hotspot.js +184 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +29 -0
- package/dist/tools/networks.d.ts +3 -0
- package/dist/tools/networks.js +157 -0
- package/dist/tools/sites.d.ts +3 -0
- package/dist/tools/sites.js +37 -0
- package/dist/tools/supporting.d.ts +3 -0
- package/dist/tools/supporting.js +234 -0
- package/dist/tools/system.d.ts +3 -0
- package/dist/tools/system.js +16 -0
- package/dist/tools/traffic-matching.d.ts +3 -0
- package/dist/tools/traffic-matching.js +126 -0
- package/dist/tools/wifi.d.ts +3 -0
- package/dist/tools/wifi.js +140 -0
- package/dist/utils/query.d.ts +5 -0
- package/dist/utils/query.js +14 -0
- package/dist/utils/responses.d.ts +13 -0
- package/dist/utils/responses.js +18 -0
- package/dist/utils/safety.d.ts +18 -0
- package/dist/utils/safety.js +47 -0
- package/package.json +50 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDeviceTools = registerDeviceTools;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const responses_js_1 = require("../utils/responses.js");
|
|
6
|
+
const query_js_1 = require("../utils/query.js");
|
|
7
|
+
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
function registerDeviceTools(server, client, readOnly = false) {
|
|
9
|
+
server.tool("unifi_list_devices", "List all adopted devices at a site", {
|
|
10
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
11
|
+
offset: zod_1.z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.nonnegative()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Number of records to skip (default: 0)"),
|
|
17
|
+
limit: zod_1.z
|
|
18
|
+
.number()
|
|
19
|
+
.int()
|
|
20
|
+
.min(1)
|
|
21
|
+
.max(200)
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Number of records to return (default: 25, max: 200)"),
|
|
24
|
+
filter: zod_1.z.string().optional().describe("Filter expression"),
|
|
25
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
|
|
26
|
+
try {
|
|
27
|
+
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
28
|
+
const data = await client.get(`/sites/${siteId}/devices${query}`);
|
|
29
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return (0, responses_js_1.formatError)(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
server.tool("unifi_get_device", "Get a specific device by ID", {
|
|
36
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
37
|
+
deviceId: zod_1.z.string().describe("Device ID"),
|
|
38
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, deviceId }) => {
|
|
39
|
+
try {
|
|
40
|
+
const data = await client.get(`/sites/${siteId}/devices/${deviceId}`);
|
|
41
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return (0, responses_js_1.formatError)(err);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
server.tool("unifi_get_device_statistics", "Get latest statistics for a device", {
|
|
48
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
49
|
+
deviceId: zod_1.z.string().describe("Device ID"),
|
|
50
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, deviceId }) => {
|
|
51
|
+
try {
|
|
52
|
+
const data = await client.get(`/sites/${siteId}/devices/${deviceId}/statistics`);
|
|
53
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
return (0, responses_js_1.formatError)(err);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
server.tool("unifi_list_pending_devices", "List devices pending adoption (global, not site-specific)", {
|
|
60
|
+
offset: zod_1.z
|
|
61
|
+
.number()
|
|
62
|
+
.int()
|
|
63
|
+
.nonnegative()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("Number of records to skip (default: 0)"),
|
|
66
|
+
limit: zod_1.z
|
|
67
|
+
.number()
|
|
68
|
+
.int()
|
|
69
|
+
.min(1)
|
|
70
|
+
.max(200)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Number of records to return (default: 25, max: 200)"),
|
|
73
|
+
filter: zod_1.z.string().optional().describe("Filter expression"),
|
|
74
|
+
}, safety_js_1.READ_ONLY, async ({ offset, limit, filter }) => {
|
|
75
|
+
try {
|
|
76
|
+
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
77
|
+
const data = await client.get(`/devices/pending${query}`);
|
|
78
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
return (0, responses_js_1.formatError)(err);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
if (readOnly)
|
|
85
|
+
return;
|
|
86
|
+
server.tool("unifi_adopt_device", "Adopt a pending device", {
|
|
87
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
88
|
+
macAddress: zod_1.z.string().describe("MAC address of the device"),
|
|
89
|
+
dryRun: zod_1.z.boolean().optional().describe("Preview this action without executing it"),
|
|
90
|
+
}, safety_js_1.WRITE_NOT_IDEMPOTENT, async ({ siteId, macAddress, dryRun }) => {
|
|
91
|
+
const body = {
|
|
92
|
+
macAddress,
|
|
93
|
+
ignoreDeviceLimit: false,
|
|
94
|
+
};
|
|
95
|
+
if (dryRun)
|
|
96
|
+
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/devices`, body);
|
|
97
|
+
try {
|
|
98
|
+
const data = await client.post(`/sites/${siteId}/devices`, body);
|
|
99
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return (0, responses_js_1.formatError)(err);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
server.tool("unifi_remove_device", "DESTRUCTIVE: Remove (unadopt) a device from a site. If the device is online, it will be reset to factory defaults", {
|
|
106
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
107
|
+
deviceId: zod_1.z.string().describe("Device ID"),
|
|
108
|
+
confirm: zod_1.z.boolean().optional().describe("Must be true to execute this destructive action"),
|
|
109
|
+
dryRun: zod_1.z.boolean().optional().describe("Preview this action without executing it"),
|
|
110
|
+
}, safety_js_1.DESTRUCTIVE, async ({ siteId, deviceId, confirm, dryRun }) => {
|
|
111
|
+
const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will remove the device from the site. If the device is online, it will be reset to factory defaults");
|
|
112
|
+
if (guard)
|
|
113
|
+
return guard;
|
|
114
|
+
if (dryRun)
|
|
115
|
+
return (0, safety_js_1.formatDryRun)("DELETE", `/sites/${siteId}/devices/${deviceId}`, {});
|
|
116
|
+
try {
|
|
117
|
+
const data = await client.delete(`/sites/${siteId}/devices/${deviceId}`);
|
|
118
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
return (0, responses_js_1.formatError)(err);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
server.tool("unifi_restart_device", "Restart a device", {
|
|
125
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
126
|
+
deviceId: zod_1.z.string().describe("Device ID"),
|
|
127
|
+
dryRun: zod_1.z.boolean().optional().describe("Preview this action without executing it"),
|
|
128
|
+
}, safety_js_1.WRITE, async ({ siteId, deviceId, dryRun }) => {
|
|
129
|
+
const body = { action: "RESTART" };
|
|
130
|
+
if (dryRun)
|
|
131
|
+
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/devices/${deviceId}/actions`, body);
|
|
132
|
+
try {
|
|
133
|
+
const data = await client.post(`/sites/${siteId}/devices/${deviceId}/actions`, body);
|
|
134
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
return (0, responses_js_1.formatError)(err);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
server.tool("unifi_power_cycle_port", "Power cycle a specific port on a device (PoE restart)", {
|
|
141
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
142
|
+
deviceId: zod_1.z.string().describe("Device ID"),
|
|
143
|
+
portIdx: zod_1.z.number().int().describe("Port index number"),
|
|
144
|
+
dryRun: zod_1.z.boolean().optional().describe("Preview this action without executing it"),
|
|
145
|
+
}, safety_js_1.WRITE, async ({ siteId, deviceId, portIdx, dryRun }) => {
|
|
146
|
+
const body = { action: "POWER_CYCLE" };
|
|
147
|
+
if (dryRun)
|
|
148
|
+
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/devices/${deviceId}/ports/${portIdx}/actions`, body);
|
|
149
|
+
try {
|
|
150
|
+
const data = await client.post(`/sites/${siteId}/devices/${deviceId}/ports/${portIdx}/actions`, body);
|
|
151
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
return (0, responses_js_1.formatError)(err);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDnsPolicyTools = registerDnsPolicyTools;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const responses_js_1 = require("../utils/responses.js");
|
|
6
|
+
const query_js_1 = require("../utils/query.js");
|
|
7
|
+
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
function registerDnsPolicyTools(server, client, readOnly = false) {
|
|
9
|
+
server.tool("unifi_list_dns_policies", "List all DNS policies at a site", {
|
|
10
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
11
|
+
offset: zod_1.z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.nonnegative()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Number of records to skip (default: 0)"),
|
|
17
|
+
limit: zod_1.z
|
|
18
|
+
.number()
|
|
19
|
+
.int()
|
|
20
|
+
.min(1)
|
|
21
|
+
.max(200)
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Number of records to return (default: 25, max: 200)"),
|
|
24
|
+
filter: zod_1.z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Filter expression"),
|
|
28
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
|
|
29
|
+
try {
|
|
30
|
+
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
31
|
+
const data = await client.get(`/sites/${siteId}/dns-policies${query}`);
|
|
32
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return (0, responses_js_1.formatError)(err);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
server.tool("unifi_get_dns_policy", "Get a specific DNS policy by ID", {
|
|
39
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
40
|
+
dnsPolicyId: zod_1.z.string().describe("DNS policy ID"),
|
|
41
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, dnsPolicyId }) => {
|
|
42
|
+
try {
|
|
43
|
+
const data = await client.get(`/sites/${siteId}/dns-policies/${dnsPolicyId}`);
|
|
44
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return (0, responses_js_1.formatError)(err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
if (readOnly)
|
|
51
|
+
return;
|
|
52
|
+
server.tool("unifi_create_dns_policy", "Create a new DNS policy", {
|
|
53
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
54
|
+
policy: zod_1.z
|
|
55
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
56
|
+
.describe("DNS policy configuration (JSON object)"),
|
|
57
|
+
dryRun: zod_1.z
|
|
58
|
+
.boolean()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Preview this action without executing it"),
|
|
61
|
+
}, safety_js_1.WRITE_NOT_IDEMPOTENT, async ({ siteId, policy, dryRun }) => {
|
|
62
|
+
try {
|
|
63
|
+
if (dryRun)
|
|
64
|
+
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/dns-policies`, policy);
|
|
65
|
+
const data = await client.post(`/sites/${siteId}/dns-policies`, policy);
|
|
66
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
return (0, responses_js_1.formatError)(err);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
server.tool("unifi_update_dns_policy", "Update a DNS policy", {
|
|
73
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
74
|
+
dnsPolicyId: zod_1.z.string().describe("DNS policy ID"),
|
|
75
|
+
policy: zod_1.z
|
|
76
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
77
|
+
.describe("DNS policy configuration (JSON object)"),
|
|
78
|
+
dryRun: zod_1.z
|
|
79
|
+
.boolean()
|
|
80
|
+
.optional()
|
|
81
|
+
.describe("Preview this action without executing it"),
|
|
82
|
+
}, safety_js_1.WRITE, async ({ siteId, dnsPolicyId, policy, dryRun }) => {
|
|
83
|
+
try {
|
|
84
|
+
if (dryRun)
|
|
85
|
+
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/dns-policies/${dnsPolicyId}`, policy);
|
|
86
|
+
const data = await client.put(`/sites/${siteId}/dns-policies/${dnsPolicyId}`, policy);
|
|
87
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return (0, responses_js_1.formatError)(err);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
server.tool("unifi_delete_dns_policy", "DESTRUCTIVE: Delete a DNS policy", {
|
|
94
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
95
|
+
dnsPolicyId: zod_1.z.string().describe("DNS policy ID"),
|
|
96
|
+
confirm: zod_1.z
|
|
97
|
+
.boolean()
|
|
98
|
+
.optional()
|
|
99
|
+
.describe("Must be true to execute this destructive action"),
|
|
100
|
+
dryRun: zod_1.z
|
|
101
|
+
.boolean()
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("Preview this action without executing it"),
|
|
104
|
+
}, safety_js_1.DESTRUCTIVE, async ({ siteId, dnsPolicyId, confirm, dryRun }) => {
|
|
105
|
+
const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete the DNS policy");
|
|
106
|
+
if (guard)
|
|
107
|
+
return guard;
|
|
108
|
+
try {
|
|
109
|
+
if (dryRun)
|
|
110
|
+
return (0, safety_js_1.formatDryRun)("DELETE", `/sites/${siteId}/dns-policies/${dnsPolicyId}`, {});
|
|
111
|
+
const data = await client.delete(`/sites/${siteId}/dns-policies/${dnsPolicyId}`);
|
|
112
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return (0, responses_js_1.formatError)(err);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerFirewallTools = registerFirewallTools;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const responses_js_1 = require("../utils/responses.js");
|
|
6
|
+
const query_js_1 = require("../utils/query.js");
|
|
7
|
+
const safety_js_1 = require("../utils/safety.js");
|
|
8
|
+
function registerFirewallTools(server, client, readOnly = false) {
|
|
9
|
+
server.tool("unifi_list_firewall_zones", "List all firewall zones at a site", {
|
|
10
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
11
|
+
offset: zod_1.z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.nonnegative()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Number of records to skip (default: 0)"),
|
|
17
|
+
limit: zod_1.z
|
|
18
|
+
.number()
|
|
19
|
+
.int()
|
|
20
|
+
.min(1)
|
|
21
|
+
.max(200)
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Number of records to return (default: 25, max: 200)"),
|
|
24
|
+
filter: zod_1.z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Filter expression"),
|
|
28
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
|
|
29
|
+
try {
|
|
30
|
+
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
31
|
+
const data = await client.get(`/sites/${siteId}/firewall/zones${query}`);
|
|
32
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return (0, responses_js_1.formatError)(err);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
server.tool("unifi_get_firewall_zone", "Get a specific firewall zone by ID", {
|
|
39
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
40
|
+
firewallZoneId: zod_1.z.string().describe("Firewall zone ID"),
|
|
41
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, firewallZoneId }) => {
|
|
42
|
+
try {
|
|
43
|
+
const data = await client.get(`/sites/${siteId}/firewall/zones/${firewallZoneId}`);
|
|
44
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return (0, responses_js_1.formatError)(err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
server.tool("unifi_list_firewall_policies", "List all firewall policies at a site", {
|
|
51
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
52
|
+
offset: zod_1.z
|
|
53
|
+
.number()
|
|
54
|
+
.int()
|
|
55
|
+
.nonnegative()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Number of records to skip (default: 0)"),
|
|
58
|
+
limit: zod_1.z
|
|
59
|
+
.number()
|
|
60
|
+
.int()
|
|
61
|
+
.min(1)
|
|
62
|
+
.max(200)
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Number of records to return (default: 25, max: 200)"),
|
|
65
|
+
filter: zod_1.z
|
|
66
|
+
.string()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Filter expression"),
|
|
69
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
|
|
70
|
+
try {
|
|
71
|
+
const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
|
|
72
|
+
const data = await client.get(`/sites/${siteId}/firewall/policies${query}`);
|
|
73
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
return (0, responses_js_1.formatError)(err);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
server.tool("unifi_get_firewall_policy", "Get a specific firewall policy by ID", {
|
|
80
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
81
|
+
firewallPolicyId: zod_1.z.string().describe("Firewall policy ID"),
|
|
82
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, firewallPolicyId }) => {
|
|
83
|
+
try {
|
|
84
|
+
const data = await client.get(`/sites/${siteId}/firewall/policies/${firewallPolicyId}`);
|
|
85
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
return (0, responses_js_1.formatError)(err);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
server.tool("unifi_get_firewall_policy_ordering", "Get user-defined firewall policy ordering for a zone pair", {
|
|
92
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
93
|
+
sourceFirewallZoneId: zod_1.z.string().describe("Source firewall zone ID"),
|
|
94
|
+
destinationFirewallZoneId: zod_1.z
|
|
95
|
+
.string()
|
|
96
|
+
.describe("Destination firewall zone ID"),
|
|
97
|
+
}, safety_js_1.READ_ONLY, async ({ siteId, sourceFirewallZoneId, destinationFirewallZoneId }) => {
|
|
98
|
+
try {
|
|
99
|
+
const query = `?sourceFirewallZoneId=${encodeURIComponent(sourceFirewallZoneId)}&destinationFirewallZoneId=${encodeURIComponent(destinationFirewallZoneId)}`;
|
|
100
|
+
const data = await client.get(`/sites/${siteId}/firewall/policies/ordering${query}`);
|
|
101
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
return (0, responses_js_1.formatError)(err);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (readOnly)
|
|
108
|
+
return;
|
|
109
|
+
server.tool("unifi_create_firewall_zone", "Create a new custom firewall zone", {
|
|
110
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
111
|
+
name: zod_1.z.string().describe("Zone name"),
|
|
112
|
+
networkIds: zod_1.z
|
|
113
|
+
.array(zod_1.z.string())
|
|
114
|
+
.describe("Network IDs to include in this zone"),
|
|
115
|
+
dryRun: zod_1.z
|
|
116
|
+
.boolean()
|
|
117
|
+
.optional()
|
|
118
|
+
.describe("Preview this action without executing it"),
|
|
119
|
+
}, safety_js_1.WRITE_NOT_IDEMPOTENT, async ({ siteId, name, networkIds, dryRun }) => {
|
|
120
|
+
try {
|
|
121
|
+
const body = { name, networkIds };
|
|
122
|
+
if (dryRun)
|
|
123
|
+
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/firewall/zones`, body);
|
|
124
|
+
const data = await client.post(`/sites/${siteId}/firewall/zones`, body);
|
|
125
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return (0, responses_js_1.formatError)(err);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
server.tool("unifi_update_firewall_zone", "Update a firewall zone", {
|
|
132
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
133
|
+
firewallZoneId: zod_1.z.string().describe("Firewall zone ID"),
|
|
134
|
+
name: zod_1.z.string().describe("Zone name"),
|
|
135
|
+
networkIds: zod_1.z
|
|
136
|
+
.array(zod_1.z.string())
|
|
137
|
+
.describe("Network IDs to include in this zone"),
|
|
138
|
+
dryRun: zod_1.z
|
|
139
|
+
.boolean()
|
|
140
|
+
.optional()
|
|
141
|
+
.describe("Preview this action without executing it"),
|
|
142
|
+
}, safety_js_1.WRITE, async ({ siteId, firewallZoneId, name, networkIds, dryRun }) => {
|
|
143
|
+
try {
|
|
144
|
+
const body = { name, networkIds };
|
|
145
|
+
if (dryRun)
|
|
146
|
+
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/firewall/zones/${firewallZoneId}`, body);
|
|
147
|
+
const data = await client.put(`/sites/${siteId}/firewall/zones/${firewallZoneId}`, body);
|
|
148
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
return (0, responses_js_1.formatError)(err);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
server.tool("unifi_delete_firewall_zone", "DESTRUCTIVE: Delete a custom firewall zone", {
|
|
155
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
156
|
+
firewallZoneId: zod_1.z.string().describe("Firewall zone ID"),
|
|
157
|
+
confirm: zod_1.z
|
|
158
|
+
.boolean()
|
|
159
|
+
.optional()
|
|
160
|
+
.describe("Must be true to execute this destructive action"),
|
|
161
|
+
dryRun: zod_1.z
|
|
162
|
+
.boolean()
|
|
163
|
+
.optional()
|
|
164
|
+
.describe("Preview this action without executing it"),
|
|
165
|
+
}, safety_js_1.DESTRUCTIVE, async ({ siteId, firewallZoneId, confirm, dryRun }) => {
|
|
166
|
+
const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete the firewall zone");
|
|
167
|
+
if (guard)
|
|
168
|
+
return guard;
|
|
169
|
+
try {
|
|
170
|
+
if (dryRun)
|
|
171
|
+
return (0, safety_js_1.formatDryRun)("DELETE", `/sites/${siteId}/firewall/zones/${firewallZoneId}`, {});
|
|
172
|
+
const data = await client.delete(`/sites/${siteId}/firewall/zones/${firewallZoneId}`);
|
|
173
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
return (0, responses_js_1.formatError)(err);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
server.tool("unifi_create_firewall_policy", "Create a new firewall policy", {
|
|
180
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
181
|
+
policy: zod_1.z
|
|
182
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
183
|
+
.describe("Firewall policy configuration (JSON object)"),
|
|
184
|
+
dryRun: zod_1.z
|
|
185
|
+
.boolean()
|
|
186
|
+
.optional()
|
|
187
|
+
.describe("Preview this action without executing it"),
|
|
188
|
+
}, safety_js_1.WRITE_NOT_IDEMPOTENT, async ({ siteId, policy, dryRun }) => {
|
|
189
|
+
try {
|
|
190
|
+
if (dryRun)
|
|
191
|
+
return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/firewall/policies`, policy);
|
|
192
|
+
const data = await client.post(`/sites/${siteId}/firewall/policies`, policy);
|
|
193
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
return (0, responses_js_1.formatError)(err);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
server.tool("unifi_update_firewall_policy", "Update a firewall policy", {
|
|
200
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
201
|
+
firewallPolicyId: zod_1.z.string().describe("Firewall policy ID"),
|
|
202
|
+
policy: zod_1.z
|
|
203
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
204
|
+
.describe("Firewall policy configuration (JSON object)"),
|
|
205
|
+
dryRun: zod_1.z
|
|
206
|
+
.boolean()
|
|
207
|
+
.optional()
|
|
208
|
+
.describe("Preview this action without executing it"),
|
|
209
|
+
}, safety_js_1.WRITE, async ({ siteId, firewallPolicyId, policy, dryRun }) => {
|
|
210
|
+
try {
|
|
211
|
+
if (dryRun)
|
|
212
|
+
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/firewall/policies/${firewallPolicyId}`, policy);
|
|
213
|
+
const data = await client.put(`/sites/${siteId}/firewall/policies/${firewallPolicyId}`, policy);
|
|
214
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
return (0, responses_js_1.formatError)(err);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
server.tool("unifi_delete_firewall_policy", "DESTRUCTIVE: Delete a firewall policy", {
|
|
221
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
222
|
+
firewallPolicyId: zod_1.z.string().describe("Firewall policy ID"),
|
|
223
|
+
confirm: zod_1.z
|
|
224
|
+
.boolean()
|
|
225
|
+
.optional()
|
|
226
|
+
.describe("Must be true to execute this destructive action"),
|
|
227
|
+
dryRun: zod_1.z
|
|
228
|
+
.boolean()
|
|
229
|
+
.optional()
|
|
230
|
+
.describe("Preview this action without executing it"),
|
|
231
|
+
}, safety_js_1.DESTRUCTIVE, async ({ siteId, firewallPolicyId, confirm, dryRun }) => {
|
|
232
|
+
const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete the firewall policy");
|
|
233
|
+
if (guard)
|
|
234
|
+
return guard;
|
|
235
|
+
try {
|
|
236
|
+
if (dryRun)
|
|
237
|
+
return (0, safety_js_1.formatDryRun)("DELETE", `/sites/${siteId}/firewall/policies/${firewallPolicyId}`, {});
|
|
238
|
+
const data = await client.delete(`/sites/${siteId}/firewall/policies/${firewallPolicyId}`);
|
|
239
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
return (0, responses_js_1.formatError)(err);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
server.tool("unifi_reorder_firewall_policies", "Reorder user-defined firewall policies for a zone pair", {
|
|
246
|
+
siteId: zod_1.z.string().describe("Site ID"),
|
|
247
|
+
sourceFirewallZoneId: zod_1.z.string().describe("Source firewall zone ID"),
|
|
248
|
+
destinationFirewallZoneId: zod_1.z
|
|
249
|
+
.string()
|
|
250
|
+
.describe("Destination firewall zone ID"),
|
|
251
|
+
orderedFirewallPolicyIds: zod_1.z
|
|
252
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
253
|
+
.describe("Ordered policy IDs object with beforeSystemDefined and afterSystemDefined arrays"),
|
|
254
|
+
dryRun: zod_1.z
|
|
255
|
+
.boolean()
|
|
256
|
+
.optional()
|
|
257
|
+
.describe("Preview this action without executing it"),
|
|
258
|
+
}, safety_js_1.WRITE, async ({ siteId, sourceFirewallZoneId, destinationFirewallZoneId, orderedFirewallPolicyIds, dryRun, }) => {
|
|
259
|
+
try {
|
|
260
|
+
const query = `?sourceFirewallZoneId=${encodeURIComponent(sourceFirewallZoneId)}&destinationFirewallZoneId=${encodeURIComponent(destinationFirewallZoneId)}`;
|
|
261
|
+
const body = { orderedFirewallPolicyIds };
|
|
262
|
+
if (dryRun)
|
|
263
|
+
return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/firewall/policies/ordering${query}`, body);
|
|
264
|
+
const data = await client.put(`/sites/${siteId}/firewall/policies/ordering${query}`, body);
|
|
265
|
+
return (0, responses_js_1.formatSuccess)(data);
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
return (0, responses_js_1.formatError)(err);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|