@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.
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerHotspotTools = registerHotspotTools;
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 registerHotspotTools(server, client, readOnly = false) {
9
+ server.tool("unifi_list_vouchers", "List all hotspot vouchers 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
+ .default(0)
17
+ .describe("Number of records to skip (default: 0)"),
18
+ limit: zod_1.z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(1000)
23
+ .optional()
24
+ .default(100)
25
+ .describe("Number of records to return (default: 100, max: 1000)"),
26
+ filter: zod_1.z
27
+ .string()
28
+ .optional()
29
+ .describe("Filter expression (e.g., 'expired.eq(true)')"),
30
+ }, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
31
+ try {
32
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
33
+ const data = await client.get(`/sites/${siteId}/hotspot/vouchers${query}`);
34
+ return (0, responses_js_1.formatSuccess)(data);
35
+ }
36
+ catch (err) {
37
+ return (0, responses_js_1.formatError)(err);
38
+ }
39
+ });
40
+ server.tool("unifi_get_voucher", "Get a specific hotspot voucher by ID", {
41
+ siteId: zod_1.z.string().describe("Site ID"),
42
+ voucherId: zod_1.z.string().describe("Voucher ID"),
43
+ }, safety_js_1.READ_ONLY, async ({ siteId, voucherId }) => {
44
+ try {
45
+ const data = await client.get(`/sites/${siteId}/hotspot/vouchers/${voucherId}`);
46
+ return (0, responses_js_1.formatSuccess)(data);
47
+ }
48
+ catch (err) {
49
+ return (0, responses_js_1.formatError)(err);
50
+ }
51
+ });
52
+ if (readOnly)
53
+ return;
54
+ server.tool("unifi_create_voucher", "Create hotspot vouchers", {
55
+ siteId: zod_1.z.string().describe("Site ID"),
56
+ name: zod_1.z
57
+ .string()
58
+ .describe("Voucher note/name (duplicated across all generated vouchers)"),
59
+ timeLimitMinutes: zod_1.z
60
+ .number()
61
+ .int()
62
+ .min(1)
63
+ .max(1000000)
64
+ .describe("How long the voucher provides access (1-1000000 minutes)"),
65
+ count: zod_1.z
66
+ .number()
67
+ .int()
68
+ .min(1)
69
+ .max(1000)
70
+ .optional()
71
+ .default(1)
72
+ .describe("Number of vouchers to create (1-1000, default: 1)"),
73
+ authorizedGuestLimit: zod_1.z
74
+ .number()
75
+ .int()
76
+ .min(1)
77
+ .optional()
78
+ .describe("How many guests can use this voucher"),
79
+ dataUsageLimitMBytes: zod_1.z
80
+ .number()
81
+ .int()
82
+ .min(1)
83
+ .max(1048576)
84
+ .optional()
85
+ .describe("Data usage limit in megabytes (1-1048576)"),
86
+ rxRateLimitKbps: zod_1.z
87
+ .number()
88
+ .int()
89
+ .min(2)
90
+ .max(100000)
91
+ .optional()
92
+ .describe("Download rate limit in kbps (2-100000)"),
93
+ txRateLimitKbps: zod_1.z
94
+ .number()
95
+ .int()
96
+ .min(2)
97
+ .max(100000)
98
+ .optional()
99
+ .describe("Upload rate limit in kbps (2-100000)"),
100
+ dryRun: zod_1.z
101
+ .boolean()
102
+ .optional()
103
+ .describe("Preview this action without executing it"),
104
+ }, safety_js_1.WRITE_NOT_IDEMPOTENT, async ({ siteId, name, timeLimitMinutes, count, authorizedGuestLimit, dataUsageLimitMBytes, rxRateLimitKbps, txRateLimitKbps, dryRun, }) => {
105
+ try {
106
+ const body = {
107
+ name,
108
+ timeLimitMinutes,
109
+ };
110
+ if (count !== undefined)
111
+ body.count = count;
112
+ if (authorizedGuestLimit !== undefined)
113
+ body.authorizedGuestLimit = authorizedGuestLimit;
114
+ if (dataUsageLimitMBytes !== undefined)
115
+ body.dataUsageLimitMBytes = dataUsageLimitMBytes;
116
+ if (rxRateLimitKbps !== undefined)
117
+ body.rxRateLimitKbps = rxRateLimitKbps;
118
+ if (txRateLimitKbps !== undefined)
119
+ body.txRateLimitKbps = txRateLimitKbps;
120
+ if (dryRun)
121
+ return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/hotspot/vouchers`, body);
122
+ const data = await client.post(`/sites/${siteId}/hotspot/vouchers`, body);
123
+ return (0, responses_js_1.formatSuccess)(data);
124
+ }
125
+ catch (err) {
126
+ return (0, responses_js_1.formatError)(err);
127
+ }
128
+ });
129
+ server.tool("unifi_delete_voucher", "DESTRUCTIVE: Delete a hotspot voucher", {
130
+ siteId: zod_1.z.string().describe("Site ID"),
131
+ voucherId: zod_1.z.string().describe("Voucher ID"),
132
+ confirm: zod_1.z
133
+ .boolean()
134
+ .optional()
135
+ .describe("Must be true to execute this destructive action"),
136
+ dryRun: zod_1.z
137
+ .boolean()
138
+ .optional()
139
+ .describe("Preview this action without executing it"),
140
+ }, safety_js_1.DESTRUCTIVE, async ({ siteId, voucherId, confirm, dryRun }) => {
141
+ const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will permanently delete the voucher");
142
+ if (guard)
143
+ return guard;
144
+ try {
145
+ const path = `/sites/${siteId}/hotspot/vouchers/${voucherId}`;
146
+ if (dryRun)
147
+ return (0, safety_js_1.formatDryRun)("DELETE", path);
148
+ const data = await client.delete(path);
149
+ return (0, responses_js_1.formatSuccess)(data);
150
+ }
151
+ catch (err) {
152
+ return (0, responses_js_1.formatError)(err);
153
+ }
154
+ });
155
+ server.tool("unifi_bulk_delete_vouchers", "DESTRUCTIVE: Bulk delete hotspot vouchers based on filter criteria", {
156
+ siteId: zod_1.z.string().describe("Site ID"),
157
+ filter: zod_1.z
158
+ .string()
159
+ .describe("Required filter expression (e.g., 'expired.eq(true)', 'name.like(guest*)')"),
160
+ confirm: zod_1.z
161
+ .boolean()
162
+ .optional()
163
+ .describe("Must be true to execute this destructive action"),
164
+ dryRun: zod_1.z
165
+ .boolean()
166
+ .optional()
167
+ .describe("Preview this action without executing it"),
168
+ }, safety_js_1.DESTRUCTIVE, async ({ siteId, filter, confirm, dryRun }) => {
169
+ try {
170
+ const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete all vouchers matching the filter");
171
+ if (guard)
172
+ return guard;
173
+ const query = (0, query_js_1.buildQuery)({ filter });
174
+ const path = `/sites/${siteId}/hotspot/vouchers${query}`;
175
+ if (dryRun)
176
+ return (0, safety_js_1.formatDryRun)("DELETE", path);
177
+ const data = await client.delete(path);
178
+ return (0, responses_js_1.formatSuccess)(data);
179
+ }
180
+ catch (err) {
181
+ return (0, responses_js_1.formatError)(err);
182
+ }
183
+ });
184
+ }
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NetworkClient } from "../client.js";
3
+ export declare function registerAllTools(server: McpServer, client: NetworkClient, readOnly?: boolean): void;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerAllTools = registerAllTools;
4
+ const system_js_1 = require("./system.js");
5
+ const sites_js_1 = require("./sites.js");
6
+ const devices_js_1 = require("./devices.js");
7
+ const clients_js_1 = require("./clients.js");
8
+ const networks_js_1 = require("./networks.js");
9
+ const wifi_js_1 = require("./wifi.js");
10
+ const hotspot_js_1 = require("./hotspot.js");
11
+ const firewall_js_1 = require("./firewall.js");
12
+ const acl_js_1 = require("./acl.js");
13
+ const dns_policies_js_1 = require("./dns-policies.js");
14
+ const traffic_matching_js_1 = require("./traffic-matching.js");
15
+ const supporting_js_1 = require("./supporting.js");
16
+ function registerAllTools(server, client, readOnly = false) {
17
+ (0, system_js_1.registerSystemTools)(server, client);
18
+ (0, sites_js_1.registerSiteTools)(server, client);
19
+ (0, devices_js_1.registerDeviceTools)(server, client, readOnly);
20
+ (0, clients_js_1.registerClientTools)(server, client, readOnly);
21
+ (0, networks_js_1.registerNetworkTools)(server, client, readOnly);
22
+ (0, wifi_js_1.registerWifiTools)(server, client, readOnly);
23
+ (0, hotspot_js_1.registerHotspotTools)(server, client, readOnly);
24
+ (0, firewall_js_1.registerFirewallTools)(server, client, readOnly);
25
+ (0, acl_js_1.registerAclTools)(server, client, readOnly);
26
+ (0, dns_policies_js_1.registerDnsPolicyTools)(server, client, readOnly);
27
+ (0, traffic_matching_js_1.registerTrafficMatchingTools)(server, client, readOnly);
28
+ (0, supporting_js_1.registerSupportingTools)(server, client);
29
+ }
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NetworkClient } from "../client.js";
3
+ export declare function registerNetworkTools(server: McpServer, client: NetworkClient, readOnly?: boolean): void;
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerNetworkTools = registerNetworkTools;
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 registerNetworkTools(server, client, readOnly = false) {
9
+ server.tool("unifi_list_networks", "List all networks 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}/networks${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_network", "Get a specific network by ID", {
39
+ siteId: zod_1.z.string().describe("Site ID"),
40
+ networkId: zod_1.z.string().describe("Network ID"),
41
+ }, safety_js_1.READ_ONLY, async ({ siteId, networkId }) => {
42
+ try {
43
+ const data = await client.get(`/sites/${siteId}/networks/${networkId}`);
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_get_network_references", "Get references to a network (what WiFi broadcasts, firewall zones, etc. use this network)", {
51
+ siteId: zod_1.z.string().describe("Site ID"),
52
+ networkId: zod_1.z.string().describe("Network ID"),
53
+ }, safety_js_1.READ_ONLY, async ({ siteId, networkId }) => {
54
+ try {
55
+ const data = await client.get(`/sites/${siteId}/networks/${networkId}/references`);
56
+ return (0, responses_js_1.formatSuccess)(data);
57
+ }
58
+ catch (err) {
59
+ return (0, responses_js_1.formatError)(err);
60
+ }
61
+ });
62
+ if (readOnly)
63
+ return;
64
+ server.tool("unifi_create_network", "Create a new network", {
65
+ siteId: zod_1.z.string().describe("Site ID"),
66
+ name: zod_1.z.string().describe("Network name"),
67
+ management: zod_1.z
68
+ .enum(["UNMANAGED", "GATEWAY", "SWITCH"])
69
+ .describe("Network management type"),
70
+ enabled: zod_1.z.boolean().describe("Enable the network"),
71
+ vlanId: zod_1.z
72
+ .number()
73
+ .int()
74
+ .min(1)
75
+ .max(4009)
76
+ .describe("VLAN ID (1 for default, 2+ for additional)"),
77
+ dryRun: zod_1.z
78
+ .boolean()
79
+ .optional()
80
+ .describe("Preview this action without executing it"),
81
+ }, safety_js_1.WRITE_NOT_IDEMPOTENT, async ({ siteId, name, management, enabled, vlanId, dryRun }) => {
82
+ try {
83
+ const body = { name, management, enabled, vlanId };
84
+ if (dryRun)
85
+ return (0, safety_js_1.formatDryRun)("POST", `/sites/${siteId}/networks`, body);
86
+ const data = await client.post(`/sites/${siteId}/networks`, body);
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_update_network", "Update an existing network", {
94
+ siteId: zod_1.z.string().describe("Site ID"),
95
+ networkId: zod_1.z.string().describe("Network ID"),
96
+ name: zod_1.z.string().describe("Network name"),
97
+ management: zod_1.z
98
+ .enum(["UNMANAGED", "GATEWAY", "SWITCH"])
99
+ .describe("Network management type"),
100
+ enabled: zod_1.z.boolean().describe("Enable the network"),
101
+ vlanId: zod_1.z
102
+ .number()
103
+ .int()
104
+ .min(1)
105
+ .max(4009)
106
+ .describe("VLAN ID (1-4009)"),
107
+ dryRun: zod_1.z
108
+ .boolean()
109
+ .optional()
110
+ .describe("Preview this action without executing it"),
111
+ }, safety_js_1.WRITE, async ({ siteId, networkId, name, management, enabled, vlanId, dryRun }) => {
112
+ try {
113
+ const body = { name, management, enabled, vlanId };
114
+ if (dryRun)
115
+ return (0, safety_js_1.formatDryRun)("PUT", `/sites/${siteId}/networks/${networkId}`, body);
116
+ const data = await client.put(`/sites/${siteId}/networks/${networkId}`, body);
117
+ return (0, responses_js_1.formatSuccess)(data);
118
+ }
119
+ catch (err) {
120
+ return (0, responses_js_1.formatError)(err);
121
+ }
122
+ });
123
+ server.tool("unifi_delete_network", "DESTRUCTIVE: Delete a network — all clients on this network will be disconnected", {
124
+ siteId: zod_1.z.string().describe("Site ID"),
125
+ networkId: zod_1.z.string().describe("Network ID"),
126
+ force: zod_1.z
127
+ .boolean()
128
+ .optional()
129
+ .default(false)
130
+ .describe("Force delete (default: false)"),
131
+ confirm: zod_1.z
132
+ .boolean()
133
+ .optional()
134
+ .describe("Must be true to execute this destructive action"),
135
+ dryRun: zod_1.z
136
+ .boolean()
137
+ .optional()
138
+ .describe("Preview this action without executing it"),
139
+ }, safety_js_1.DESTRUCTIVE, async ({ siteId, networkId, force, confirm, dryRun }) => {
140
+ const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete the network and disconnect all clients on it");
141
+ if (guard)
142
+ return guard;
143
+ try {
144
+ let path = `/sites/${siteId}/networks/${networkId}`;
145
+ if (force) {
146
+ path += "?force=true";
147
+ }
148
+ if (dryRun)
149
+ return (0, safety_js_1.formatDryRun)("DELETE", path);
150
+ const data = await client.delete(path);
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,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NetworkClient } from "../client.js";
3
+ export declare function registerSiteTools(server: McpServer, client: NetworkClient): void;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSiteTools = registerSiteTools;
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 registerSiteTools(server, client) {
9
+ server.tool("unifi_list_sites", "List all sites available to the API key", {
10
+ offset: zod_1.z
11
+ .number()
12
+ .int()
13
+ .nonnegative()
14
+ .optional()
15
+ .describe("Number of records to skip (default: 0)"),
16
+ limit: zod_1.z
17
+ .number()
18
+ .int()
19
+ .min(1)
20
+ .max(200)
21
+ .optional()
22
+ .describe("Number of records to return (default: 25, max: 200)"),
23
+ filter: zod_1.z
24
+ .string()
25
+ .optional()
26
+ .describe("Filter expression (e.g., 'name.like(office*)')"),
27
+ }, safety_js_1.READ_ONLY, async ({ offset, limit, filter }) => {
28
+ try {
29
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
30
+ const data = await client.get(`/sites${query}`);
31
+ return (0, responses_js_1.formatSuccess)(data);
32
+ }
33
+ catch (err) {
34
+ return (0, responses_js_1.formatError)(err);
35
+ }
36
+ });
37
+ }
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NetworkClient } from "../client.js";
3
+ export declare function registerSupportingTools(server: McpServer, client: NetworkClient): void;
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSupportingTools = registerSupportingTools;
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 registerSupportingTools(server, client) {
9
+ server.tool("unifi_list_wans", "List all WAN interfaces 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
+ }, safety_js_1.READ_ONLY, async ({ siteId, offset, limit }) => {
25
+ try {
26
+ const query = (0, query_js_1.buildQuery)({ offset, limit });
27
+ const data = await client.get(`/sites/${siteId}/wan-interfaces${query}`);
28
+ return (0, responses_js_1.formatSuccess)(data);
29
+ }
30
+ catch (err) {
31
+ return (0, responses_js_1.formatError)(err);
32
+ }
33
+ });
34
+ server.tool("unifi_list_vpn_tunnels", "List all site-to-site VPN tunnels at a site", {
35
+ siteId: zod_1.z.string().describe("Site ID"),
36
+ offset: zod_1.z
37
+ .number()
38
+ .int()
39
+ .nonnegative()
40
+ .optional()
41
+ .describe("Number of records to skip (default: 0)"),
42
+ limit: zod_1.z
43
+ .number()
44
+ .int()
45
+ .min(1)
46
+ .max(200)
47
+ .optional()
48
+ .describe("Number of records to return (default: 25, max: 200)"),
49
+ filter: zod_1.z
50
+ .string()
51
+ .optional()
52
+ .describe("Filter expression"),
53
+ }, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
54
+ try {
55
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
56
+ const data = await client.get(`/sites/${siteId}/vpn-tunnels${query}`);
57
+ return (0, responses_js_1.formatSuccess)(data);
58
+ }
59
+ catch (err) {
60
+ return (0, responses_js_1.formatError)(err);
61
+ }
62
+ });
63
+ server.tool("unifi_list_vpn_servers", "List all VPN servers at a site", {
64
+ siteId: zod_1.z.string().describe("Site ID"),
65
+ offset: zod_1.z
66
+ .number()
67
+ .int()
68
+ .nonnegative()
69
+ .optional()
70
+ .describe("Number of records to skip (default: 0)"),
71
+ limit: zod_1.z
72
+ .number()
73
+ .int()
74
+ .min(1)
75
+ .max(200)
76
+ .optional()
77
+ .describe("Number of records to return (default: 25, max: 200)"),
78
+ filter: zod_1.z
79
+ .string()
80
+ .optional()
81
+ .describe("Filter expression"),
82
+ }, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
83
+ try {
84
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
85
+ const data = await client.get(`/sites/${siteId}/vpn-servers${query}`);
86
+ return (0, responses_js_1.formatSuccess)(data);
87
+ }
88
+ catch (err) {
89
+ return (0, responses_js_1.formatError)(err);
90
+ }
91
+ });
92
+ server.tool("unifi_list_radius_profiles", "List all RADIUS profiles at a site", {
93
+ siteId: zod_1.z.string().describe("Site ID"),
94
+ offset: zod_1.z
95
+ .number()
96
+ .int()
97
+ .nonnegative()
98
+ .optional()
99
+ .describe("Number of records to skip (default: 0)"),
100
+ limit: zod_1.z
101
+ .number()
102
+ .int()
103
+ .min(1)
104
+ .max(200)
105
+ .optional()
106
+ .describe("Number of records to return (default: 25, max: 200)"),
107
+ filter: zod_1.z
108
+ .string()
109
+ .optional()
110
+ .describe("Filter expression"),
111
+ }, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
112
+ try {
113
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
114
+ const data = await client.get(`/sites/${siteId}/radius-profiles${query}`);
115
+ return (0, responses_js_1.formatSuccess)(data);
116
+ }
117
+ catch (err) {
118
+ return (0, responses_js_1.formatError)(err);
119
+ }
120
+ });
121
+ server.tool("unifi_list_device_tags", "List all device tags at a site (used for WiFi broadcast assignments)", {
122
+ siteId: zod_1.z.string().describe("Site ID"),
123
+ offset: zod_1.z
124
+ .number()
125
+ .int()
126
+ .nonnegative()
127
+ .optional()
128
+ .describe("Number of records to skip (default: 0)"),
129
+ limit: zod_1.z
130
+ .number()
131
+ .int()
132
+ .min(1)
133
+ .max(200)
134
+ .optional()
135
+ .describe("Number of records to return (default: 25, max: 200)"),
136
+ filter: zod_1.z
137
+ .string()
138
+ .optional()
139
+ .describe("Filter expression"),
140
+ }, safety_js_1.READ_ONLY, async ({ siteId, offset, limit, filter }) => {
141
+ try {
142
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
143
+ const data = await client.get(`/sites/${siteId}/device-tags${query}`);
144
+ return (0, responses_js_1.formatSuccess)(data);
145
+ }
146
+ catch (err) {
147
+ return (0, responses_js_1.formatError)(err);
148
+ }
149
+ });
150
+ server.tool("unifi_list_dpi_categories", "List all DPI (Deep Packet Inspection) categories for traffic identification", {
151
+ offset: zod_1.z
152
+ .number()
153
+ .int()
154
+ .nonnegative()
155
+ .optional()
156
+ .describe("Number of records to skip (default: 0)"),
157
+ limit: zod_1.z
158
+ .number()
159
+ .int()
160
+ .min(1)
161
+ .max(200)
162
+ .optional()
163
+ .describe("Number of records to return (default: 25, max: 200)"),
164
+ filter: zod_1.z
165
+ .string()
166
+ .optional()
167
+ .describe("Filter expression"),
168
+ }, safety_js_1.READ_ONLY, async ({ offset, limit, filter }) => {
169
+ try {
170
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
171
+ const data = await client.get(`/dpi/categories${query}`);
172
+ return (0, responses_js_1.formatSuccess)(data);
173
+ }
174
+ catch (err) {
175
+ return (0, responses_js_1.formatError)(err);
176
+ }
177
+ });
178
+ server.tool("unifi_list_dpi_applications", "List all DPI applications for traffic identification and filtering", {
179
+ offset: zod_1.z
180
+ .number()
181
+ .int()
182
+ .nonnegative()
183
+ .optional()
184
+ .describe("Number of records to skip (default: 0)"),
185
+ limit: zod_1.z
186
+ .number()
187
+ .int()
188
+ .min(1)
189
+ .max(200)
190
+ .optional()
191
+ .describe("Number of records to return (default: 25, max: 200)"),
192
+ filter: zod_1.z
193
+ .string()
194
+ .optional()
195
+ .describe("Filter expression"),
196
+ }, safety_js_1.READ_ONLY, async ({ offset, limit, filter }) => {
197
+ try {
198
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
199
+ const data = await client.get(`/dpi/applications${query}`);
200
+ return (0, responses_js_1.formatSuccess)(data);
201
+ }
202
+ catch (err) {
203
+ return (0, responses_js_1.formatError)(err);
204
+ }
205
+ });
206
+ server.tool("unifi_list_countries", "List all countries/regions for geo-based rules (ISO codes and names)", {
207
+ offset: zod_1.z
208
+ .number()
209
+ .int()
210
+ .nonnegative()
211
+ .optional()
212
+ .describe("Number of records to skip (default: 0)"),
213
+ limit: zod_1.z
214
+ .number()
215
+ .int()
216
+ .min(1)
217
+ .max(200)
218
+ .optional()
219
+ .describe("Number of records to return (default: 25, max: 200)"),
220
+ filter: zod_1.z
221
+ .string()
222
+ .optional()
223
+ .describe("Filter expression (e.g., 'name.like(United*)')"),
224
+ }, safety_js_1.READ_ONLY, async ({ offset, limit, filter }) => {
225
+ try {
226
+ const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
227
+ const data = await client.get(`/countries${query}`);
228
+ return (0, responses_js_1.formatSuccess)(data);
229
+ }
230
+ catch (err) {
231
+ return (0, responses_js_1.formatError)(err);
232
+ }
233
+ });
234
+ }
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NetworkClient } from "../client.js";
3
+ export declare function registerSystemTools(server: McpServer, client: NetworkClient): void;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSystemTools = registerSystemTools;
4
+ const responses_js_1 = require("../utils/responses.js");
5
+ const safety_js_1 = require("../utils/safety.js");
6
+ function registerSystemTools(server, client) {
7
+ server.tool("unifi_get_info", "Get application information including version and whether it's a UniFi OS Console", {}, safety_js_1.READ_ONLY, async () => {
8
+ try {
9
+ const data = await client.get("/info");
10
+ return (0, responses_js_1.formatSuccess)(data);
11
+ }
12
+ catch (err) {
13
+ return (0, responses_js_1.formatError)(err);
14
+ }
15
+ });
16
+ }