@owine/unifi-network-mcp 2.0.1 → 2.0.2

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.
@@ -6,28 +6,32 @@ 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
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 }) => {
9
+ server.registerTool("unifi_list_vouchers", {
10
+ description: "List all hotspot vouchers at a site",
11
+ inputSchema: {
12
+ siteId: zod_1.z.string().describe("Site ID"),
13
+ offset: zod_1.z
14
+ .number()
15
+ .int()
16
+ .nonnegative()
17
+ .optional()
18
+ .default(0)
19
+ .describe("Number of records to skip (default: 0)"),
20
+ limit: zod_1.z
21
+ .number()
22
+ .int()
23
+ .min(1)
24
+ .max(1000)
25
+ .optional()
26
+ .default(100)
27
+ .describe("Number of records to return (default: 100, max: 1000)"),
28
+ filter: zod_1.z
29
+ .string()
30
+ .optional()
31
+ .describe("Filter expression (e.g., 'expired.eq(true)')"),
32
+ },
33
+ annotations: safety_js_1.READ_ONLY,
34
+ }, async ({ siteId, offset, limit, filter }) => {
31
35
  try {
32
36
  const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
33
37
  const data = await client.get(`/sites/${siteId}/hotspot/vouchers${query}`);
@@ -37,10 +41,14 @@ function registerHotspotTools(server, client, readOnly = false) {
37
41
  return (0, responses_js_1.formatError)(err);
38
42
  }
39
43
  });
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
+ server.registerTool("unifi_get_voucher", {
45
+ description: "Get a specific hotspot voucher by ID",
46
+ inputSchema: {
47
+ siteId: zod_1.z.string().describe("Site ID"),
48
+ voucherId: zod_1.z.string().describe("Voucher ID"),
49
+ },
50
+ annotations: safety_js_1.READ_ONLY,
51
+ }, async ({ siteId, voucherId }) => {
44
52
  try {
45
53
  const data = await client.get(`/sites/${siteId}/hotspot/vouchers/${voucherId}`);
46
54
  return (0, responses_js_1.formatSuccess)(data);
@@ -51,57 +59,61 @@ function registerHotspotTools(server, client, readOnly = false) {
51
59
  });
52
60
  if (readOnly)
53
61
  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, }) => {
62
+ server.registerTool("unifi_create_voucher", {
63
+ description: "Create hotspot vouchers",
64
+ inputSchema: {
65
+ siteId: zod_1.z.string().describe("Site ID"),
66
+ name: zod_1.z
67
+ .string()
68
+ .describe("Voucher note/name (duplicated across all generated vouchers)"),
69
+ timeLimitMinutes: zod_1.z
70
+ .number()
71
+ .int()
72
+ .min(1)
73
+ .max(1000000)
74
+ .describe("How long the voucher provides access (1-1000000 minutes)"),
75
+ count: zod_1.z
76
+ .number()
77
+ .int()
78
+ .min(1)
79
+ .max(1000)
80
+ .optional()
81
+ .default(1)
82
+ .describe("Number of vouchers to create (1-1000, default: 1)"),
83
+ authorizedGuestLimit: zod_1.z
84
+ .number()
85
+ .int()
86
+ .min(1)
87
+ .optional()
88
+ .describe("How many guests can use this voucher"),
89
+ dataUsageLimitMBytes: zod_1.z
90
+ .number()
91
+ .int()
92
+ .min(1)
93
+ .max(1048576)
94
+ .optional()
95
+ .describe("Data usage limit in megabytes (1-1048576)"),
96
+ rxRateLimitKbps: zod_1.z
97
+ .number()
98
+ .int()
99
+ .min(2)
100
+ .max(100000)
101
+ .optional()
102
+ .describe("Download rate limit in kbps (2-100000)"),
103
+ txRateLimitKbps: zod_1.z
104
+ .number()
105
+ .int()
106
+ .min(2)
107
+ .max(100000)
108
+ .optional()
109
+ .describe("Upload rate limit in kbps (2-100000)"),
110
+ dryRun: zod_1.z
111
+ .boolean()
112
+ .optional()
113
+ .describe("Preview this action without executing it"),
114
+ },
115
+ annotations: safety_js_1.WRITE_NOT_IDEMPOTENT,
116
+ }, async ({ siteId, name, timeLimitMinutes, count, authorizedGuestLimit, dataUsageLimitMBytes, rxRateLimitKbps, txRateLimitKbps, dryRun, }) => {
105
117
  try {
106
118
  const body = {
107
119
  name,
@@ -126,18 +138,22 @@ function registerHotspotTools(server, client, readOnly = false) {
126
138
  return (0, responses_js_1.formatError)(err);
127
139
  }
128
140
  });
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
+ server.registerTool("unifi_delete_voucher", {
142
+ description: "DESTRUCTIVE: Delete a hotspot voucher",
143
+ inputSchema: {
144
+ siteId: zod_1.z.string().describe("Site ID"),
145
+ voucherId: zod_1.z.string().describe("Voucher ID"),
146
+ confirm: zod_1.z
147
+ .boolean()
148
+ .optional()
149
+ .describe("Must be true to execute this destructive action"),
150
+ dryRun: zod_1.z
151
+ .boolean()
152
+ .optional()
153
+ .describe("Preview this action without executing it"),
154
+ },
155
+ annotations: safety_js_1.DESTRUCTIVE,
156
+ }, async ({ siteId, voucherId, confirm, dryRun }) => {
141
157
  const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will permanently delete the voucher");
142
158
  if (guard)
143
159
  return guard;
@@ -152,20 +168,24 @@ function registerHotspotTools(server, client, readOnly = false) {
152
168
  return (0, responses_js_1.formatError)(err);
153
169
  }
154
170
  });
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 }) => {
171
+ server.registerTool("unifi_bulk_delete_vouchers", {
172
+ description: "DESTRUCTIVE: Bulk delete hotspot vouchers based on filter criteria",
173
+ inputSchema: {
174
+ siteId: zod_1.z.string().describe("Site ID"),
175
+ filter: zod_1.z
176
+ .string()
177
+ .describe("Required filter expression (e.g., 'expired.eq(true)', 'name.like(guest*)')"),
178
+ confirm: zod_1.z
179
+ .boolean()
180
+ .optional()
181
+ .describe("Must be true to execute this destructive action"),
182
+ dryRun: zod_1.z
183
+ .boolean()
184
+ .optional()
185
+ .describe("Preview this action without executing it"),
186
+ },
187
+ annotations: safety_js_1.DESTRUCTIVE,
188
+ }, async ({ siteId, filter, confirm, dryRun }) => {
169
189
  try {
170
190
  const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete all vouchers matching the filter");
171
191
  if (guard)
@@ -6,26 +6,30 @@ 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
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 }) => {
9
+ server.registerTool("unifi_list_networks", {
10
+ description: "List all networks at a site",
11
+ inputSchema: {
12
+ siteId: zod_1.z.string().describe("Site ID"),
13
+ offset: zod_1.z
14
+ .number()
15
+ .int()
16
+ .nonnegative()
17
+ .optional()
18
+ .describe("Number of records to skip (default: 0)"),
19
+ limit: zod_1.z
20
+ .number()
21
+ .int()
22
+ .min(1)
23
+ .max(200)
24
+ .optional()
25
+ .describe("Number of records to return (default: 25, max: 200)"),
26
+ filter: zod_1.z
27
+ .string()
28
+ .optional()
29
+ .describe("Filter expression"),
30
+ },
31
+ annotations: safety_js_1.READ_ONLY,
32
+ }, async ({ siteId, offset, limit, filter }) => {
29
33
  try {
30
34
  const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
31
35
  const data = await client.get(`/sites/${siteId}/networks${query}`);
@@ -35,10 +39,14 @@ function registerNetworkTools(server, client, readOnly = false) {
35
39
  return (0, responses_js_1.formatError)(err);
36
40
  }
37
41
  });
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
+ server.registerTool("unifi_get_network", {
43
+ description: "Get a specific network by ID",
44
+ inputSchema: {
45
+ siteId: zod_1.z.string().describe("Site ID"),
46
+ networkId: zod_1.z.string().describe("Network ID"),
47
+ },
48
+ annotations: safety_js_1.READ_ONLY,
49
+ }, async ({ siteId, networkId }) => {
42
50
  try {
43
51
  const data = await client.get(`/sites/${siteId}/networks/${networkId}`);
44
52
  return (0, responses_js_1.formatSuccess)(data);
@@ -47,10 +55,14 @@ function registerNetworkTools(server, client, readOnly = false) {
47
55
  return (0, responses_js_1.formatError)(err);
48
56
  }
49
57
  });
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 }) => {
58
+ server.registerTool("unifi_get_network_references", {
59
+ description: "Get references to a network (what WiFi broadcasts, firewall zones, etc. use this network)",
60
+ inputSchema: {
61
+ siteId: zod_1.z.string().describe("Site ID"),
62
+ networkId: zod_1.z.string().describe("Network ID"),
63
+ },
64
+ annotations: safety_js_1.READ_ONLY,
65
+ }, async ({ siteId, networkId }) => {
54
66
  try {
55
67
  const data = await client.get(`/sites/${siteId}/networks/${networkId}/references`);
56
68
  return (0, responses_js_1.formatSuccess)(data);
@@ -61,24 +73,28 @@ function registerNetworkTools(server, client, readOnly = false) {
61
73
  });
62
74
  if (readOnly)
63
75
  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 }) => {
76
+ server.registerTool("unifi_create_network", {
77
+ description: "Create a new network",
78
+ inputSchema: {
79
+ siteId: zod_1.z.string().describe("Site ID"),
80
+ name: zod_1.z.string().describe("Network name"),
81
+ management: zod_1.z
82
+ .enum(["UNMANAGED", "GATEWAY", "SWITCH"])
83
+ .describe("Network management type"),
84
+ enabled: zod_1.z.boolean().describe("Enable the network"),
85
+ vlanId: zod_1.z
86
+ .number()
87
+ .int()
88
+ .min(1)
89
+ .max(4009)
90
+ .describe("VLAN ID (1 for default, 2+ for additional)"),
91
+ dryRun: zod_1.z
92
+ .boolean()
93
+ .optional()
94
+ .describe("Preview this action without executing it"),
95
+ },
96
+ annotations: safety_js_1.WRITE_NOT_IDEMPOTENT,
97
+ }, async ({ siteId, name, management, enabled, vlanId, dryRun }) => {
82
98
  try {
83
99
  const body = { name, management, enabled, vlanId };
84
100
  if (dryRun)
@@ -90,25 +106,29 @@ function registerNetworkTools(server, client, readOnly = false) {
90
106
  return (0, responses_js_1.formatError)(err);
91
107
  }
92
108
  });
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 }) => {
109
+ server.registerTool("unifi_update_network", {
110
+ description: "Update an existing network",
111
+ inputSchema: {
112
+ siteId: zod_1.z.string().describe("Site ID"),
113
+ networkId: zod_1.z.string().describe("Network ID"),
114
+ name: zod_1.z.string().describe("Network name"),
115
+ management: zod_1.z
116
+ .enum(["UNMANAGED", "GATEWAY", "SWITCH"])
117
+ .describe("Network management type"),
118
+ enabled: zod_1.z.boolean().describe("Enable the network"),
119
+ vlanId: zod_1.z
120
+ .number()
121
+ .int()
122
+ .min(1)
123
+ .max(4009)
124
+ .describe("VLAN ID (1-4009)"),
125
+ dryRun: zod_1.z
126
+ .boolean()
127
+ .optional()
128
+ .describe("Preview this action without executing it"),
129
+ },
130
+ annotations: safety_js_1.WRITE,
131
+ }, async ({ siteId, networkId, name, management, enabled, vlanId, dryRun }) => {
112
132
  try {
113
133
  const body = { name, management, enabled, vlanId };
114
134
  if (dryRun)
@@ -120,23 +140,27 @@ function registerNetworkTools(server, client, readOnly = false) {
120
140
  return (0, responses_js_1.formatError)(err);
121
141
  }
122
142
  });
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 }) => {
143
+ server.registerTool("unifi_delete_network", {
144
+ description: "DESTRUCTIVE: Delete a network — all clients on this network will be disconnected",
145
+ inputSchema: {
146
+ siteId: zod_1.z.string().describe("Site ID"),
147
+ networkId: zod_1.z.string().describe("Network ID"),
148
+ force: zod_1.z
149
+ .boolean()
150
+ .optional()
151
+ .default(false)
152
+ .describe("Force delete (default: false)"),
153
+ confirm: zod_1.z
154
+ .boolean()
155
+ .optional()
156
+ .describe("Must be true to execute this destructive action"),
157
+ dryRun: zod_1.z
158
+ .boolean()
159
+ .optional()
160
+ .describe("Preview this action without executing it"),
161
+ },
162
+ annotations: safety_js_1.DESTRUCTIVE,
163
+ }, async ({ siteId, networkId, force, confirm, dryRun }) => {
140
164
  const guard = (0, safety_js_1.requireConfirmation)(confirm, "This will delete the network and disconnect all clients on it");
141
165
  if (guard)
142
166
  return guard;
@@ -6,25 +6,29 @@ 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
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 }) => {
9
+ server.registerTool("unifi_list_sites", {
10
+ description: "List all sites available to the API key",
11
+ inputSchema: {
12
+ offset: zod_1.z
13
+ .number()
14
+ .int()
15
+ .nonnegative()
16
+ .optional()
17
+ .describe("Number of records to skip (default: 0)"),
18
+ limit: zod_1.z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(200)
23
+ .optional()
24
+ .describe("Number of records to return (default: 25, max: 200)"),
25
+ filter: zod_1.z
26
+ .string()
27
+ .optional()
28
+ .describe("Filter expression (e.g., 'name.like(office*)')"),
29
+ },
30
+ annotations: safety_js_1.READ_ONLY,
31
+ }, async ({ offset, limit, filter }) => {
28
32
  try {
29
33
  const query = (0, query_js_1.buildQuery)({ offset, limit, filter });
30
34
  const data = await client.get(`/sites${query}`);