@owine/unifi-protect-mcp 2.12.0 → 2.13.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # UniFi Protect MCP Server
2
2
 
3
- An MCP (Model Context Protocol) server that exposes UniFi Protect's Integration REST API as tools for Claude Code and other MCP clients. Aligned with UniFi Protect API **7.1.83** — 73 tools covering cameras, lights, sensors, chimes, viewers, sirens, fobs, relays, speakers, bridges, link stations, alarm hubs, arm profiles, live views, files, users, NVR status, and WebSocket subscriptions.
3
+ An MCP (Model Context Protocol) server that exposes UniFi Protect's Integration REST API as tools for Claude Code and other MCP clients. Aligned with UniFi Protect API **7.3.47** — 74 tools covering cameras, lights, sensors, chimes, viewers, sirens, fobs, relays, speakers, bridges, link stations, alarm hubs, arm profiles, live views, files, users, point-of-sale events, NVR status, and WebSocket subscriptions.
4
4
 
5
5
  ## Prerequisites
6
6
 
@@ -225,6 +225,11 @@ This server provides layered safety controls for responsible operation:
225
225
  | `protect_list_ulp_users` | List UniFi Identity (ULP) users with enrolled credentials |
226
226
  | `protect_get_ulp_user` | Get a UniFi Identity user by ID |
227
227
 
228
+ ### Point of Sale (1)
229
+ | Tool | Description |
230
+ |---|---|
231
+ | `protect_ingest_pos_transaction` | Record a POS transaction as a camera event so it can be overlaid on recorded footage |
232
+
228
233
  ## Development
229
234
 
230
235
  The Node version used for development is pinned in `.nvmrc`. With [fnm](https://github.com/Schniz/fnm) installed, `fnm use` reads it automatically on `cd`.
@@ -1,4 +1,6 @@
1
1
  export declare const cameraSchema: import("zod").ZodObject<{
2
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
3
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
2
4
  id: import("zod").ZodOptional<import("zod").ZodString>;
3
5
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
4
6
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -43,6 +45,8 @@ export declare const cameraSchema: import("zod").ZodObject<{
43
45
  }, import("zod/v4/core").$loose>>;
44
46
  }, import("zod/v4/core").$loose>;
45
47
  export declare const cameraOutputSchema: {
48
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
49
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
46
50
  id: import("zod").ZodOptional<import("zod").ZodString>;
47
51
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
48
52
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -88,6 +92,8 @@ export declare const cameraOutputSchema: {
88
92
  };
89
93
  export declare const cameraListOutputSchema: {
90
94
  result: import("zod").ZodArray<import("zod").ZodObject<{
95
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
96
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
91
97
  id: import("zod").ZodOptional<import("zod").ZodString>;
92
98
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
93
99
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.talkbackSessionOutputSchema = exports.rtspStreamOutputSchema = exports.rtspStreamSchema = exports.cameraListOutputSchema = exports.cameraOutputSchema = exports.cameraSchema = void 0;
4
4
  const common_js_1 = require("./common.js");
5
5
  /**
6
- * Verified against live UniFi Protect Integration API 7.1.83 (2026-06-20).
6
+ * Verified against live UniFi Protect Integration API 7.3.47 (2026-09-14).
7
7
  * The Integration API camera object is far smaller than the internal Protect
8
8
  * app's camera model — no isRecording/lastMotion/channels/firmwareVersion/etc.
9
9
  * `list` and `get-by-id` return the same field set (confirmed live).
@@ -47,6 +47,7 @@ exports.cameraSchema = (0, common_js_1.passthroughObject)({
47
47
  name: (0, common_js_1.nullableString)("Camera name"),
48
48
  modelKey: (0, common_js_1.nullableString)('Always "camera"'),
49
49
  state: (0, common_js_1.nullableString)("CONNECTED | DISCONNECTED | ..."),
50
+ ...(0, common_js_1.hardwareModelFields)(),
50
51
  activePatrolSlot: (0, common_js_1.unknownField)("Active PTZ patrol slot, or null (number|null)"),
51
52
  hasPackageCamera: (0, common_js_1.unknownField)("Has a secondary package camera (boolean)"),
52
53
  hdrType: (0, common_js_1.nullableString)('HDR mode, e.g. "auto"'),
@@ -32,6 +32,19 @@ export declare function idField(description?: string): z.ZodOptional<z.ZodString
32
32
  * type hint to clients while never failing validation on an API null.
33
33
  */
34
34
  export declare function nullableString(description: string): z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
+ /**
36
+ * Hardware-model fields that Protect 7.3.x added to every device resource and
37
+ * to the NVR.
38
+ *
39
+ * VERIFIED LIVE (7.3.47): `guid` identifies the hardware MODEL, not the unit.
40
+ * Three "UVC G6 Turret" cameras on the test console all return the same guid,
41
+ * as do two "UP Chime PoE" chimes. Despite the name, it is NOT a per-device
42
+ * identifier — `id` remains the only device identity.
43
+ */
44
+ export declare function hardwareModelFields(): {
45
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
46
+ guid: z.ZodOptional<z.ZodNullable<z.ZodString>>;
47
+ };
35
48
  /** Output-schema shape for list endpoints that return a top-level array. */
36
49
  export declare function listResultSchema<T extends z.ZodTypeAny>(itemSchema: T): {
37
50
  result: z.ZodArray<T>;
@@ -4,6 +4,7 @@ exports.passthroughObject = passthroughObject;
4
4
  exports.unknownField = unknownField;
5
5
  exports.idField = idField;
6
6
  exports.nullableString = nullableString;
7
+ exports.hardwareModelFields = hardwareModelFields;
7
8
  exports.listResultSchema = listResultSchema;
8
9
  const zod_1 = require("zod");
9
10
  /**
@@ -47,6 +48,22 @@ function idField(description = "Resource ID") {
47
48
  function nullableString(description) {
48
49
  return zod_1.z.string().nullable().optional().describe(description);
49
50
  }
51
+ /**
52
+ * Hardware-model fields that Protect 7.3.x added to every device resource and
53
+ * to the NVR.
54
+ *
55
+ * VERIFIED LIVE (7.3.47): `guid` identifies the hardware MODEL, not the unit.
56
+ * Three "UVC G6 Turret" cameras on the test console all return the same guid,
57
+ * as do two "UP Chime PoE" chimes. Despite the name, it is NOT a per-device
58
+ * identifier — `id` remains the only device identity.
59
+ */
60
+ function hardwareModelFields() {
61
+ return {
62
+ type: nullableString('Hardware model name, e.g. "UVC G6 Turret", "UP Chime PoE", "UNVR-PRO"'),
63
+ guid: nullableString("Hardware MODEL GUID, shared by every unit of the same model. NOT a " +
64
+ "per-device identifier — use `id` to identify a device."),
65
+ };
66
+ }
50
67
  /** Output-schema shape for list endpoints that return a top-level array. */
51
68
  function listResultSchema(itemSchema) {
52
69
  return {
@@ -1,4 +1,6 @@
1
1
  export declare const lightSchema: import("zod").ZodObject<{
2
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
3
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
2
4
  id: import("zod").ZodOptional<import("zod").ZodString>;
3
5
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
4
6
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -14,12 +16,15 @@ export declare const lightSchema: import("zod").ZodObject<{
14
16
  camera: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
15
17
  }, import("zod/v4/core").$loose>;
16
18
  export declare const sensorSchema: import("zod").ZodObject<{
19
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
20
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
17
21
  id: import("zod").ZodOptional<import("zod").ZodString>;
18
22
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
19
23
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
20
24
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
21
25
  state: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
22
26
  mountType: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
27
+ featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
23
28
  batteryStatus: import("zod").ZodOptional<import("zod").ZodUnknown>;
24
29
  stats: import("zod").ZodOptional<import("zod").ZodUnknown>;
25
30
  lightSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
@@ -43,6 +48,8 @@ export declare const sensorSchema: import("zod").ZodObject<{
43
48
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
44
49
  }, import("zod/v4/core").$loose>;
45
50
  export declare const chimeSchema: import("zod").ZodObject<{
51
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
52
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
46
53
  id: import("zod").ZodOptional<import("zod").ZodString>;
47
54
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
48
55
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -52,6 +59,8 @@ export declare const chimeSchema: import("zod").ZodObject<{
52
59
  ringSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
53
60
  }, import("zod/v4/core").$loose>;
54
61
  export declare const viewerSchema: import("zod").ZodObject<{
62
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
63
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
55
64
  id: import("zod").ZodOptional<import("zod").ZodString>;
56
65
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
57
66
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -61,6 +70,8 @@ export declare const viewerSchema: import("zod").ZodObject<{
61
70
  streamLimit: import("zod").ZodOptional<import("zod").ZodUnknown>;
62
71
  }, import("zod/v4/core").$loose>;
63
72
  export declare const sirenSchema: import("zod").ZodObject<{
73
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
74
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
64
75
  id: import("zod").ZodOptional<import("zod").ZodString>;
65
76
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
66
77
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -73,6 +84,8 @@ export declare const sirenSchema: import("zod").ZodObject<{
73
84
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
74
85
  }, import("zod/v4/core").$loose>;
75
86
  export declare const fobSchema: import("zod").ZodObject<{
87
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
88
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
76
89
  id: import("zod").ZodOptional<import("zod").ZodString>;
77
90
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
78
91
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -81,9 +94,14 @@ export declare const fobSchema: import("zod").ZodObject<{
81
94
  awayState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
82
95
  buttonLabels: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
83
96
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
97
+ hasKeypad: import("zod").ZodOptional<import("zod").ZodUnknown>;
98
+ armControlSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
99
+ keypadSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
84
100
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
85
101
  }, import("zod/v4/core").$loose>;
86
102
  export declare const relaySchema: import("zod").ZodObject<{
103
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
104
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
87
105
  id: import("zod").ZodOptional<import("zod").ZodString>;
88
106
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
89
107
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -95,6 +113,8 @@ export declare const relaySchema: import("zod").ZodObject<{
95
113
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
96
114
  }, import("zod/v4/core").$loose>;
97
115
  export declare const speakerSchema: import("zod").ZodObject<{
116
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
117
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
98
118
  id: import("zod").ZodOptional<import("zod").ZodString>;
99
119
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
100
120
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -107,6 +127,8 @@ export declare const speakerSchema: import("zod").ZodObject<{
107
127
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
108
128
  }, import("zod/v4/core").$loose>;
109
129
  export declare const bridgeSchema: import("zod").ZodObject<{
130
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
131
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
110
132
  id: import("zod").ZodOptional<import("zod").ZodString>;
111
133
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
112
134
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -117,6 +139,8 @@ export declare const bridgeSchema: import("zod").ZodObject<{
117
139
  maxClients: import("zod").ZodOptional<import("zod").ZodUnknown>;
118
140
  }, import("zod/v4/core").$loose>;
119
141
  export declare const linkStationSchema: import("zod").ZodObject<{
142
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
143
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
120
144
  id: import("zod").ZodOptional<import("zod").ZodString>;
121
145
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
122
146
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -126,8 +150,12 @@ export declare const linkStationSchema: import("zod").ZodObject<{
126
150
  ledSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
127
151
  lastEvent: import("zod").ZodOptional<import("zod").ZodUnknown>;
128
152
  alarmHub: import("zod").ZodOptional<import("zod").ZodUnknown>;
153
+ deviceTamperStatus: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
154
+ threadState: import("zod").ZodOptional<import("zod").ZodUnknown>;
129
155
  }, import("zod/v4/core").$loose>;
130
156
  export declare const alarmHubSchema: import("zod").ZodObject<{
157
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
158
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
131
159
  id: import("zod").ZodOptional<import("zod").ZodString>;
132
160
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
133
161
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -137,9 +165,13 @@ export declare const alarmHubSchema: import("zod").ZodObject<{
137
165
  ledSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
138
166
  lastEvent: import("zod").ZodOptional<import("zod").ZodUnknown>;
139
167
  alarmHub: import("zod").ZodOptional<import("zod").ZodUnknown>;
168
+ deviceTamperStatus: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
169
+ threadState: import("zod").ZodOptional<import("zod").ZodUnknown>;
140
170
  }, import("zod/v4/core").$loose>;
141
171
  export declare const DEVICE_SCHEMAS: {
142
172
  readonly light: import("zod").ZodObject<{
173
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
174
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
143
175
  id: import("zod").ZodOptional<import("zod").ZodString>;
144
176
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
145
177
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -155,12 +187,15 @@ export declare const DEVICE_SCHEMAS: {
155
187
  camera: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
156
188
  }, import("zod/v4/core").$loose>;
157
189
  readonly sensor: import("zod").ZodObject<{
190
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
191
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
158
192
  id: import("zod").ZodOptional<import("zod").ZodString>;
159
193
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
160
194
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
161
195
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
162
196
  state: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
163
197
  mountType: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
198
+ featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
164
199
  batteryStatus: import("zod").ZodOptional<import("zod").ZodUnknown>;
165
200
  stats: import("zod").ZodOptional<import("zod").ZodUnknown>;
166
201
  lightSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
@@ -184,6 +219,8 @@ export declare const DEVICE_SCHEMAS: {
184
219
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
185
220
  }, import("zod/v4/core").$loose>;
186
221
  readonly chime: import("zod").ZodObject<{
222
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
223
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
187
224
  id: import("zod").ZodOptional<import("zod").ZodString>;
188
225
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
189
226
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -193,6 +230,8 @@ export declare const DEVICE_SCHEMAS: {
193
230
  ringSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
194
231
  }, import("zod/v4/core").$loose>;
195
232
  readonly viewer: import("zod").ZodObject<{
233
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
234
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
196
235
  id: import("zod").ZodOptional<import("zod").ZodString>;
197
236
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
198
237
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -202,6 +241,8 @@ export declare const DEVICE_SCHEMAS: {
202
241
  streamLimit: import("zod").ZodOptional<import("zod").ZodUnknown>;
203
242
  }, import("zod/v4/core").$loose>;
204
243
  readonly siren: import("zod").ZodObject<{
244
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
245
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
205
246
  id: import("zod").ZodOptional<import("zod").ZodString>;
206
247
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
207
248
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -214,6 +255,8 @@ export declare const DEVICE_SCHEMAS: {
214
255
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
215
256
  }, import("zod/v4/core").$loose>;
216
257
  readonly fob: import("zod").ZodObject<{
258
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
259
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
217
260
  id: import("zod").ZodOptional<import("zod").ZodString>;
218
261
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
219
262
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -222,9 +265,14 @@ export declare const DEVICE_SCHEMAS: {
222
265
  awayState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
223
266
  buttonLabels: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
224
267
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
268
+ hasKeypad: import("zod").ZodOptional<import("zod").ZodUnknown>;
269
+ armControlSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
270
+ keypadSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
225
271
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
226
272
  }, import("zod/v4/core").$loose>;
227
273
  readonly relay: import("zod").ZodObject<{
274
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
275
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
228
276
  id: import("zod").ZodOptional<import("zod").ZodString>;
229
277
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
230
278
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -236,6 +284,8 @@ export declare const DEVICE_SCHEMAS: {
236
284
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
237
285
  }, import("zod/v4/core").$loose>;
238
286
  readonly speaker: import("zod").ZodObject<{
287
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
288
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
239
289
  id: import("zod").ZodOptional<import("zod").ZodString>;
240
290
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
241
291
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -248,6 +298,8 @@ export declare const DEVICE_SCHEMAS: {
248
298
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
249
299
  }, import("zod/v4/core").$loose>;
250
300
  readonly bridge: import("zod").ZodObject<{
301
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
302
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
251
303
  id: import("zod").ZodOptional<import("zod").ZodString>;
252
304
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
253
305
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -258,6 +310,8 @@ export declare const DEVICE_SCHEMAS: {
258
310
  maxClients: import("zod").ZodOptional<import("zod").ZodUnknown>;
259
311
  }, import("zod/v4/core").$loose>;
260
312
  readonly link_station: import("zod").ZodObject<{
313
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
314
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
261
315
  id: import("zod").ZodOptional<import("zod").ZodString>;
262
316
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
263
317
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -267,8 +321,12 @@ export declare const DEVICE_SCHEMAS: {
267
321
  ledSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
268
322
  lastEvent: import("zod").ZodOptional<import("zod").ZodUnknown>;
269
323
  alarmHub: import("zod").ZodOptional<import("zod").ZodUnknown>;
324
+ deviceTamperStatus: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
325
+ threadState: import("zod").ZodOptional<import("zod").ZodUnknown>;
270
326
  }, import("zod/v4/core").$loose>;
271
327
  readonly alarm_hub: import("zod").ZodObject<{
328
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
329
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
272
330
  id: import("zod").ZodOptional<import("zod").ZodString>;
273
331
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
274
332
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -278,9 +336,13 @@ export declare const DEVICE_SCHEMAS: {
278
336
  ledSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
279
337
  lastEvent: import("zod").ZodOptional<import("zod").ZodUnknown>;
280
338
  alarmHub: import("zod").ZodOptional<import("zod").ZodUnknown>;
339
+ deviceTamperStatus: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
340
+ threadState: import("zod").ZodOptional<import("zod").ZodUnknown>;
281
341
  }, import("zod/v4/core").$loose>;
282
342
  };
283
343
  export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
344
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
345
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
284
346
  id: import("zod").ZodOptional<import("zod").ZodString>;
285
347
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
286
348
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -295,12 +357,15 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
295
357
  isPirMotionDetected: import("zod").ZodOptional<import("zod").ZodUnknown>;
296
358
  camera: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
297
359
  } | {
360
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
361
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
298
362
  id: import("zod").ZodOptional<import("zod").ZodString>;
299
363
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
300
364
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
301
365
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
302
366
  state: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
303
367
  mountType: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
368
+ featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
304
369
  batteryStatus: import("zod").ZodOptional<import("zod").ZodUnknown>;
305
370
  stats: import("zod").ZodOptional<import("zod").ZodUnknown>;
306
371
  lightSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
@@ -323,6 +388,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
323
388
  tamperingDetectedAt: import("zod").ZodOptional<import("zod").ZodUnknown>;
324
389
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
325
390
  } | {
391
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
392
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
326
393
  id: import("zod").ZodOptional<import("zod").ZodString>;
327
394
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
328
395
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -331,6 +398,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
331
398
  cameraIds: import("zod").ZodOptional<import("zod").ZodUnknown>;
332
399
  ringSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
333
400
  } | {
401
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
402
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
334
403
  id: import("zod").ZodOptional<import("zod").ZodString>;
335
404
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
336
405
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -339,6 +408,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
339
408
  liveview: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
340
409
  streamLimit: import("zod").ZodOptional<import("zod").ZodUnknown>;
341
410
  } | {
411
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
412
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
342
413
  id: import("zod").ZodOptional<import("zod").ZodString>;
343
414
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
344
415
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -350,6 +421,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
350
421
  connectionType: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
351
422
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
352
423
  } | {
424
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
425
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
353
426
  id: import("zod").ZodOptional<import("zod").ZodString>;
354
427
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
355
428
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -358,8 +431,13 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
358
431
  awayState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
359
432
  buttonLabels: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
360
433
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
434
+ hasKeypad: import("zod").ZodOptional<import("zod").ZodUnknown>;
435
+ armControlSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
436
+ keypadSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
361
437
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
362
438
  } | {
439
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
440
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
363
441
  id: import("zod").ZodOptional<import("zod").ZodString>;
364
442
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
365
443
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -370,6 +448,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
370
448
  inputs: import("zod").ZodOptional<import("zod").ZodUnknown>;
371
449
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
372
450
  } | {
451
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
452
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
373
453
  id: import("zod").ZodOptional<import("zod").ZodString>;
374
454
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
375
455
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -381,6 +461,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
381
461
  speakerState: import("zod").ZodOptional<import("zod").ZodUnknown>;
382
462
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
383
463
  } | {
464
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
465
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
384
466
  id: import("zod").ZodOptional<import("zod").ZodString>;
385
467
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
386
468
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -390,6 +472,8 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
390
472
  clients: import("zod").ZodOptional<import("zod").ZodUnknown>;
391
473
  maxClients: import("zod").ZodOptional<import("zod").ZodUnknown>;
392
474
  } | {
475
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
476
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
393
477
  id: import("zod").ZodOptional<import("zod").ZodString>;
394
478
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
395
479
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -399,9 +483,13 @@ export declare function itemOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
399
483
  ledSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
400
484
  lastEvent: import("zod").ZodOptional<import("zod").ZodUnknown>;
401
485
  alarmHub: import("zod").ZodOptional<import("zod").ZodUnknown>;
486
+ deviceTamperStatus: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
487
+ threadState: import("zod").ZodOptional<import("zod").ZodUnknown>;
402
488
  };
403
489
  export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
404
490
  result: import("zod").ZodArray<import("zod").ZodObject<{
491
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
492
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
405
493
  id: import("zod").ZodOptional<import("zod").ZodString>;
406
494
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
407
495
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -416,12 +504,15 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
416
504
  isPirMotionDetected: import("zod").ZodOptional<import("zod").ZodUnknown>;
417
505
  camera: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
418
506
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
507
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
508
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
419
509
  id: import("zod").ZodOptional<import("zod").ZodString>;
420
510
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
421
511
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
422
512
  mac: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
423
513
  state: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
424
514
  mountType: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
515
+ featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
425
516
  batteryStatus: import("zod").ZodOptional<import("zod").ZodUnknown>;
426
517
  stats: import("zod").ZodOptional<import("zod").ZodUnknown>;
427
518
  lightSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
@@ -444,6 +535,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
444
535
  tamperingDetectedAt: import("zod").ZodOptional<import("zod").ZodUnknown>;
445
536
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
446
537
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
538
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
539
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
447
540
  id: import("zod").ZodOptional<import("zod").ZodString>;
448
541
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
449
542
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -452,6 +545,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
452
545
  cameraIds: import("zod").ZodOptional<import("zod").ZodUnknown>;
453
546
  ringSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
454
547
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
548
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
549
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
455
550
  id: import("zod").ZodOptional<import("zod").ZodString>;
456
551
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
457
552
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -460,6 +555,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
460
555
  liveview: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
461
556
  streamLimit: import("zod").ZodOptional<import("zod").ZodUnknown>;
462
557
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
558
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
559
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
463
560
  id: import("zod").ZodOptional<import("zod").ZodString>;
464
561
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
465
562
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -471,6 +568,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
471
568
  connectionType: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
472
569
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
473
570
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
571
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
572
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
474
573
  id: import("zod").ZodOptional<import("zod").ZodString>;
475
574
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
476
575
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -479,8 +578,13 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
479
578
  awayState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
480
579
  buttonLabels: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
481
580
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
581
+ hasKeypad: import("zod").ZodOptional<import("zod").ZodUnknown>;
582
+ armControlSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
583
+ keypadSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
482
584
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
483
585
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
586
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
587
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
484
588
  id: import("zod").ZodOptional<import("zod").ZodString>;
485
589
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
486
590
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -491,6 +595,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
491
595
  inputs: import("zod").ZodOptional<import("zod").ZodUnknown>;
492
596
  wirelessConnectionState: import("zod").ZodOptional<import("zod").ZodUnknown>;
493
597
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
598
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
599
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
494
600
  id: import("zod").ZodOptional<import("zod").ZodString>;
495
601
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
496
602
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -502,6 +608,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
502
608
  speakerState: import("zod").ZodOptional<import("zod").ZodUnknown>;
503
609
  featureFlags: import("zod").ZodOptional<import("zod").ZodUnknown>;
504
610
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
611
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
612
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
505
613
  id: import("zod").ZodOptional<import("zod").ZodString>;
506
614
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
507
615
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -511,6 +619,8 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
511
619
  clients: import("zod").ZodOptional<import("zod").ZodUnknown>;
512
620
  maxClients: import("zod").ZodOptional<import("zod").ZodUnknown>;
513
621
  }, import("zod/v4/core").$loose> | import("zod").ZodObject<{
622
+ type: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
623
+ guid: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
514
624
  id: import("zod").ZodOptional<import("zod").ZodString>;
515
625
  modelKey: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
516
626
  name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
@@ -520,5 +630,7 @@ export declare function listOutputShape(key: keyof typeof DEVICE_SCHEMAS): {
520
630
  ledSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
521
631
  lastEvent: import("zod").ZodOptional<import("zod").ZodUnknown>;
522
632
  alarmHub: import("zod").ZodOptional<import("zod").ZodUnknown>;
633
+ deviceTamperStatus: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
634
+ threadState: import("zod").ZodOptional<import("zod").ZodUnknown>;
523
635
  }, import("zod/v4/core").$loose>>;
524
636
  };
@@ -7,9 +7,9 @@ const common_js_1 = require("./common.js");
7
7
  /**
8
8
  * Device schemas for the config-driven Protect device types.
9
9
  *
10
- * Field sets are derived from the UniFi Protect Integration API 7.1.83 docs
10
+ * Field sets are derived from the UniFi Protect Integration API 7.3.47 docs
11
11
  * (per-type response samples). Chimes were additionally verified against live
12
- * console responses (2026-06-20); the rest have no instances on the available
12
+ * console responses (2026-09-14); the rest have no instances on the available
13
13
  * console, so their TOP-LEVEL fields are typed from the published docs while
14
14
  * every nested object/array is left as `unknownField()` (z.unknown()) — naming
15
15
  * the field for the LLM without risking SDK output-validation failures on a
@@ -26,6 +26,7 @@ const deviceIdentity = () => ({
26
26
  name: (0, common_js_1.nullableString)("Device name"),
27
27
  mac: (0, common_js_1.nullableString)("MAC address"),
28
28
  state: (0, common_js_1.nullableString)("CONNECTED | DISCONNECTED | ..."),
29
+ ...(0, common_js_1.hardwareModelFields)(),
29
30
  });
30
31
  exports.lightSchema = (0, common_js_1.passthroughObject)({
31
32
  ...deviceIdentity(),
@@ -41,6 +42,8 @@ exports.lightSchema = (0, common_js_1.passthroughObject)({
41
42
  exports.sensorSchema = (0, common_js_1.passthroughObject)({
42
43
  ...deviceIdentity(),
43
44
  mountType: (0, common_js_1.nullableString)('Mount type, e.g. "door", "leak", "garage"'),
45
+ featureFlags: (0, common_js_1.unknownField)("Sensor capability flags, added in 7.3.x (object: temperature, humidity, " +
46
+ "light, motion, waterLeak, open, tamper, smoke — each { channelCount })"),
44
47
  batteryStatus: (0, common_js_1.unknownField)("Battery status (object: percentage, isLow)"),
45
48
  stats: (0, common_js_1.unknownField)("Environmental stats (object: light, humidity, temperature)"),
46
49
  lightSettings: (0, common_js_1.unknownField)("Light threshold settings (object)"),
@@ -88,6 +91,10 @@ exports.fobSchema = (0, common_js_1.passthroughObject)({
88
91
  awayState: (0, common_js_1.nullableString)('Away state, e.g. "ONLINE"'),
89
92
  buttonLabels: (0, common_js_1.nullableString)('Button label preset, e.g. "securityActions"'),
90
93
  featureFlags: (0, common_js_1.unknownField)("Feature flags (object: buttons[])"),
94
+ hasKeypad: (0, common_js_1.unknownField)("Whether this fob has a keypad, added in 7.3.x (boolean)"),
95
+ armControlSettings: (0, common_js_1.unknownField)("Arm-control config, added in 7.3.x (object: enabled, armProfileId, nightProfileId)"),
96
+ keypadSettings: (0, common_js_1.unknownField)("Keypad config, added in 7.3.x (object: beepEnabled, beepVolume, " +
97
+ "backlightEnabled, backlightBrightness)"),
91
98
  wirelessConnectionState: (0, common_js_1.unknownField)("Wireless link state (object)"),
92
99
  });
93
100
  exports.relaySchema = (0, common_js_1.passthroughObject)({
@@ -119,6 +126,10 @@ const linkStationLikeSchema = () => (0, common_js_1.passthroughObject)({
119
126
  ledSettings: (0, common_js_1.unknownField)("LED settings (object: isEnabled)"),
120
127
  lastEvent: (0, common_js_1.unknownField)("Last event timestamp in epoch ms (number)"),
121
128
  alarmHub: (0, common_js_1.unknownField)("Alarm hub status (object: armed, battery, connector, cover, output, input, …)"),
129
+ deviceTamperStatus: (0, common_js_1.nullableString)('Tamper status, added in 7.3.x, e.g. "tampered"'),
130
+ threadState: (0, common_js_1.unknownField)("Thread radio state, added in 7.3.x (object: network — status, role, " +
131
+ "networkName, channel, panId, extendedPanId, joinedDeviceCount, " +
132
+ "errorReason, lastUpdatedAt)"),
122
133
  });
123
134
  exports.linkStationSchema = linkStationLikeSchema();
124
135
  exports.alarmHubSchema = linkStationLikeSchema();
@@ -1,8 +1,8 @@
1
1
  import { z } from "zod";
2
2
  /**
3
- * Schemas below are verified against live UniFi Protect Integration API 7.1.83
4
- * responses (Melrose NVR Pro console, 2026-06-20) where instances exist, and
5
- * against the 7.1.83 published docs otherwise (arm profiles, files — no
3
+ * Schemas below are verified against live UniFi Protect Integration API 7.3.47
4
+ * responses (Melrose NVR Pro console, 2026-09-14) where instances exist, and
5
+ * against the 7.3.47 published docs otherwise (arm profiles, files — no
6
6
  * instances on the console). The Integration API surface is much thinner than
7
7
  * the internal Protect app API — only observed/documented fields are typed;
8
8
  * `.passthrough()` still allows anything extra a firmware/hardware mix adds.
@@ -11,9 +11,12 @@ export declare const infoOutputSchema: {
11
11
  applicationVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
12
12
  };
13
13
  export declare const nvrSchema: z.ZodObject<{
14
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
15
+ guid: z.ZodOptional<z.ZodNullable<z.ZodString>>;
14
16
  id: z.ZodOptional<z.ZodString>;
15
17
  modelKey: z.ZodOptional<z.ZodNullable<z.ZodString>>;
16
18
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
19
+ mac: z.ZodOptional<z.ZodNullable<z.ZodString>>;
17
20
  doorbellSettings: z.ZodOptional<z.ZodObject<{
18
21
  defaultMessageText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
19
22
  defaultMessageResetTimeoutMs: z.ZodOptional<z.ZodUnknown>;
@@ -32,9 +35,12 @@ export declare const nvrSchema: z.ZodObject<{
32
35
  }, z.core.$loose>>;
33
36
  }, z.core.$loose>;
34
37
  export declare const nvrOutputSchema: {
38
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
39
+ guid: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
40
  id: z.ZodOptional<z.ZodString>;
36
41
  modelKey: z.ZodOptional<z.ZodNullable<z.ZodString>>;
37
42
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
43
+ mac: z.ZodOptional<z.ZodNullable<z.ZodString>>;
38
44
  doorbellSettings: z.ZodOptional<z.ZodObject<{
39
45
  defaultMessageText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
40
46
  defaultMessageResetTimeoutMs: z.ZodOptional<z.ZodUnknown>;
@@ -87,6 +93,7 @@ export declare const ulpUserSchema: z.ZodObject<{
87
93
  firstName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
88
94
  lastName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
89
95
  fullName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
96
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
90
97
  status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
91
98
  }, z.core.$loose>;
92
99
  export declare const ulpUserOutputSchema: {
@@ -95,6 +102,7 @@ export declare const ulpUserOutputSchema: {
95
102
  firstName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
96
103
  lastName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
97
104
  fullName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
105
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
98
106
  status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
99
107
  };
100
108
  export declare const ulpUserListOutputSchema: {
@@ -104,6 +112,7 @@ export declare const ulpUserListOutputSchema: {
104
112
  firstName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
105
113
  lastName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
106
114
  fullName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
115
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
107
116
  status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
108
117
  }, z.core.$loose>>;
109
118
  };
@@ -4,9 +4,9 @@ exports.subscriptionOutputSchema = exports.fileListOutputSchema = exports.fileSc
4
4
  const zod_1 = require("zod");
5
5
  const common_js_1 = require("./common.js");
6
6
  /**
7
- * Schemas below are verified against live UniFi Protect Integration API 7.1.83
8
- * responses (Melrose NVR Pro console, 2026-06-20) where instances exist, and
9
- * against the 7.1.83 published docs otherwise (arm profiles, files — no
7
+ * Schemas below are verified against live UniFi Protect Integration API 7.3.47
8
+ * responses (Melrose NVR Pro console, 2026-09-14) where instances exist, and
9
+ * against the 7.3.47 published docs otherwise (arm profiles, files — no
10
10
  * instances on the console). The Integration API surface is much thinner than
11
11
  * the internal Protect app API — only observed/documented fields are typed;
12
12
  * `.passthrough()` still allows anything extra a firmware/hardware mix adds.
@@ -36,6 +36,8 @@ exports.nvrSchema = (0, common_js_1.passthroughObject)({
36
36
  id: (0, common_js_1.idField)("NVR ID"),
37
37
  modelKey: (0, common_js_1.nullableString)('Always "nvr"'),
38
38
  name: (0, common_js_1.nullableString)("NVR name"),
39
+ ...(0, common_js_1.hardwareModelFields)(),
40
+ mac: (0, common_js_1.nullableString)("MAC address, added in 7.3.x"),
39
41
  doorbellSettings: doorbellSettingsSchema.optional(),
40
42
  armMode: armModeSchema.optional(),
41
43
  });
@@ -59,6 +61,8 @@ exports.ulpUserSchema = (0, common_js_1.passthroughObject)({
59
61
  firstName: (0, common_js_1.nullableString)("First name"),
60
62
  lastName: (0, common_js_1.nullableString)("Last name"),
61
63
  fullName: (0, common_js_1.nullableString)("Full name"),
64
+ email: (0, common_js_1.nullableString)("Email address, added in 7.3.x. Empty string for service accounts " +
65
+ "(verified live 7.3.47)"),
62
66
  status: (0, common_js_1.nullableString)("Account status, e.g. ACTIVE"),
63
67
  });
64
68
  exports.ulpUserOutputSchema = { ...exports.ulpUserSchema.shape };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Point-of-sale event ingestion, added in UniFi Protect 7.3.x
3
+ * (POST /v1/pos/cameras/{id}/transactions).
4
+ *
5
+ * Shape taken from the 7.3.47 published docs with the response sample expanded
6
+ * — there is no POS-capable register on the available console, so this is
7
+ * doc-verified rather than live-verified. `created` stays `unknownField()`
8
+ * because we have not observed the boolean live; `eventId` publishes the string
9
+ * hint via `nullableString()`.
10
+ */
11
+ export declare const posTransactionOutputSchema: {
12
+ created: import("zod").ZodOptional<import("zod").ZodUnknown>;
13
+ eventId: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
14
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.posTransactionOutputSchema = void 0;
4
+ const common_js_1 = require("./common.js");
5
+ /**
6
+ * Point-of-sale event ingestion, added in UniFi Protect 7.3.x
7
+ * (POST /v1/pos/cameras/{id}/transactions).
8
+ *
9
+ * Shape taken from the 7.3.47 published docs with the response sample expanded
10
+ * — there is no POS-capable register on the available console, so this is
11
+ * doc-verified rather than live-verified. `created` stays `unknownField()`
12
+ * because we have not observed the boolean live; `eventId` publishes the string
13
+ * hint via `nullableString()`.
14
+ */
15
+ exports.posTransactionOutputSchema = {
16
+ created: (0, common_js_1.unknownField)("Whether the transaction event was recorded (boolean)"),
17
+ eventId: (0, common_js_1.nullableString)("ID of the created Protect camera event"),
18
+ };
@@ -9,7 +9,7 @@ const cameras_js_1 = require("../schemas/cameras.js");
9
9
  function registerCameraTools(server, client, readOnly) {
10
10
  // --- Read-only tools (always registered) ---
11
11
  server.registerTool("protect_list_cameras", {
12
- description: "List all cameras managed by UniFi Protect. Returns array; each camera includes (Integration API 7.1.83-verified fields): id, mac, name, modelKey, state (CONNECTED/DISCONNECTED), activePatrolSlot, hasPackageCamera, hdrType, isMicEnabled, micVolume, videoMode, featureFlags (hasHdr, hasMic, hasSpeaker, hasLedStatus, smartDetectTypes[], smartDetectAudioTypes[], videoModes[], supportFullHdSnapshot), lcdMessage (type, resetAt, text), ledSettings (isEnabled, floodLed, welcomeLed), osdSettings (isNameEnabled, isDateEnabled, isLogoEnabled, isDebugEnabled, overlayLocation), smartDetectSettings (objectTypes[], audioTypes[]). The Integration API does NOT expose recording state, motion timestamps, connection/last-seen, firmware, host, or per-channel stream config.",
12
+ description: "List all cameras managed by UniFi Protect. Returns array; each camera includes (Integration API 7.3.47-verified fields): id, mac, name, modelKey, state (CONNECTED/DISCONNECTED), type (hardware model name, e.g. UVC G6 Turret), guid (hardware MODEL GUID — every camera of the same model returns the same value, so it is NOT a per-camera identifier; use id), activePatrolSlot, hasPackageCamera, hdrType, isMicEnabled, micVolume, videoMode, featureFlags (hasHdr, hasMic, hasSpeaker, hasLedStatus, smartDetectTypes[], smartDetectAudioTypes[], videoModes[], supportFullHdSnapshot), lcdMessage (type, resetAt, text), ledSettings (isEnabled, floodLed, welcomeLed), osdSettings (isNameEnabled, isDateEnabled, isLogoEnabled, isDebugEnabled, overlayLocation), smartDetectSettings (objectTypes[], audioTypes[]). The Integration API does NOT expose recording state, motion timestamps, connection/last-seen, firmware, host, or per-channel stream config.",
13
13
  outputSchema: cameras_js_1.cameraListOutputSchema,
14
14
  annotations: safety_js_1.READ_ONLY,
15
15
  }, async () => {
@@ -22,7 +22,7 @@ function registerCameraTools(server, client, readOnly) {
22
22
  }
23
23
  });
24
24
  server.registerTool("protect_get_camera", {
25
- description: "Get details for a specific camera by ID. The Protect Integration API returns the SAME field set as protect_list_cameras entries (id, mac, name, modelKey, state, activePatrolSlot, hasPackageCamera, hdrType, isMicEnabled, micVolume, videoMode, featureFlags, lcdMessage, ledSettings, osdSettings, smartDetectSettings) — there is no extended/by-id-only payload (confirmed live on 7.1.83). Recording state, motion events, zones, and channel/RTSP config are NOT exposed by this API surface.",
25
+ description: "Get details for a specific camera by ID. The Protect Integration API returns the SAME field set as protect_list_cameras entries (id, mac, name, modelKey, state, type, guid, activePatrolSlot, hasPackageCamera, hdrType, isMicEnabled, micVolume, videoMode, featureFlags, lcdMessage, ledSettings, osdSettings, smartDetectSettings) — there is no extended/by-id-only payload (confirmed live on 7.3.47). Recording state, motion events, zones, and channel/RTSP config are NOT exposed by this API surface.",
26
26
  inputSchema: { id: zod_1.z.string().describe("Camera ID") },
27
27
  outputSchema: cameras_js_1.cameraOutputSchema,
28
28
  annotations: safety_js_1.READ_ONLY,
@@ -7,7 +7,10 @@ const responses_js_1 = require("../utils/responses.js");
7
7
  const safety_js_1 = require("../utils/safety.js");
8
8
  const url_js_1 = require("../utils/url.js");
9
9
  const devices_js_1 = require("../schemas/devices.js");
10
- // Field lists below are from the UniFi Protect Integration API 7.1.83 docs.
10
+ // Field lists below are from the UniFi Protect Integration API 7.3.47 docs.
11
+ // 7.3.x added `type` (hardware model name) and `guid` to every device. NOTE:
12
+ // `guid` identifies the hardware MODEL, not the unit — every camera of the same
13
+ // model returns the same guid (verified live 7.3.47). `id` is the device identity.
11
14
  // Chimes are additionally verified against live console responses; the rest
12
15
  // have no instances on the available console (top-level fields documented,
13
16
  // nested shapes intentionally left opaque in the output schema).
@@ -18,7 +21,7 @@ const DEVICES = [
18
21
  plural: "lights",
19
22
  label: "Light",
20
23
  hint: "Known fields: name (string), isLightForceEnabled (boolean), lightModeSettings (object with mode, enableAt), lightDeviceSettings (object with isIndicatorEnabled, pirDuration, pirSensitivity, ledLevel)",
21
- returns: "id, modelKey, name, mac, state, lightModeSettings (mode, enableAt), lightDeviceSettings (isIndicatorEnabled, pirDuration, pirSensitivity, ledLevel), isDark, isLightOn, isLightForceEnabled, lastMotion, isPirMotionDetected, camera (7.1.83 docs)",
24
+ returns: "id, modelKey, name, mac, state, type, guid, lightModeSettings (mode, enableAt), lightDeviceSettings (isIndicatorEnabled, pirDuration, pirSensitivity, ledLevel), isDark, isLightOn, isLightForceEnabled, lastMotion, isPirMotionDetected, camera (7.3.47 docs)",
22
25
  },
23
26
  {
24
27
  urlPath: "sensors",
@@ -26,7 +29,7 @@ const DEVICES = [
26
29
  plural: "sensors",
27
30
  label: "Sensor",
28
31
  hint: "Known fields: name (string), motionSettings (object), humiditySettings (object), temperatureSettings (object), lightSettings (object), alarmSettings (object), glassBreakSettings (object), leakSettings (object), scheduleMode (\"always\" | \"when_armed\"), armProfileIds (array of up to 32 strings), hasCustomSensitivityWhenArmed (boolean)",
29
- returns: "id, modelKey, name, mac, state, mountType, batteryStatus (percentage, isLow), stats (light, humidity, temperature), lightSettings, humiditySettings, temperatureSettings, isOpened, openStatusChangedAt, isMotionDetected, motionDetectedAt, motionSettings, glassBreakSettings, scheduleMode, armProfileIds, hasCustomSensitivityWhenArmed, alarmTriggeredAt, alarmSettings, leakDetectedAt, externalLeakDetectedAt, leakSettings, tamperingDetectedAt, wirelessConnectionState (7.1.83 docs)",
32
+ returns: "id, modelKey, name, mac, state, type, guid, mountType, featureFlags (temperature, humidity, light, motion, waterLeak, open, tamper, smoke — each {channelCount}), batteryStatus (percentage, isLow), stats (light, humidity, temperature), lightSettings, humiditySettings, temperatureSettings, isOpened, openStatusChangedAt, isMotionDetected, motionDetectedAt, motionSettings, glassBreakSettings, scheduleMode, armProfileIds, hasCustomSensitivityWhenArmed, alarmTriggeredAt, alarmSettings, leakDetectedAt, externalLeakDetectedAt, leakSettings, tamperingDetectedAt, wirelessConnectionState (7.3.47 docs)",
30
33
  },
31
34
  {
32
35
  urlPath: "chimes",
@@ -34,7 +37,7 @@ const DEVICES = [
34
37
  plural: "chimes",
35
38
  label: "Chime",
36
39
  hint: "Known fields: name (string), cameraIds (array of camera IDs linked to the chime), ringSettings (array of objects: cameraId, volume, ringtoneId, repeatTimes)",
37
- returns: "id, modelKey, name, mac, state, cameraIds (array of camera IDs), ringSettings (array of objects: cameraId, volume, ringtoneId, repeatTimes) — verified live 7.1.83",
40
+ returns: "id, modelKey, name, mac, state, type, guid, cameraIds (array of camera IDs), ringSettings (array of objects: cameraId, volume, ringtoneId, repeatTimes) — verified live 7.3.47",
38
41
  },
39
42
  {
40
43
  urlPath: "viewers",
@@ -42,7 +45,7 @@ const DEVICES = [
42
45
  plural: "viewers",
43
46
  label: "Viewer",
44
47
  hint: "Known fields: name (string), liveview (string, liveview ID to display, or null)",
45
- returns: "id, modelKey, name, mac, state, liveview, streamLimit (7.1.83 docs)",
48
+ returns: "id, modelKey, name, mac, state, type, guid, liveview, streamLimit (7.3.47 docs)",
46
49
  },
47
50
  {
48
51
  urlPath: "sirens",
@@ -50,7 +53,7 @@ const DEVICES = [
50
53
  plural: "sirens",
51
54
  label: "Siren",
52
55
  hint: "Known fields: name (string), volume (integer 1-100), ledSettings (object with isEnabled boolean)",
53
- returns: "id, modelKey, name, mac, state, volume, ledSettings (isEnabled), sirenStatus (isActive, activatedAt, duration), connectionType, wirelessConnectionState (7.1.83 docs)",
56
+ returns: "id, modelKey, name, mac, state, type, guid, volume, ledSettings (isEnabled), sirenStatus (isActive, activatedAt, duration), connectionType, wirelessConnectionState (7.3.47 docs)",
54
57
  },
55
58
  {
56
59
  urlPath: "fobs",
@@ -58,7 +61,7 @@ const DEVICES = [
58
61
  plural: "fobs",
59
62
  label: "Fob",
60
63
  hint: "Known fields: name (string)",
61
- returns: "id, modelKey, name, mac, state, awayState, buttonLabels, featureFlags (buttons[]), wirelessConnectionState (7.1.83 docs)",
64
+ returns: "id, modelKey, name, mac, state, type, guid, awayState, buttonLabels, featureFlags (buttons[]), hasKeypad, armControlSettings (enabled, armProfileId, nightProfileId), keypadSettings (beepEnabled, beepVolume, backlightEnabled, backlightBrightness), wirelessConnectionState (7.3.47 docs)",
62
65
  },
63
66
  {
64
67
  urlPath: "relays",
@@ -66,7 +69,7 @@ const DEVICES = [
66
69
  plural: "relays",
67
70
  label: "Relay",
68
71
  hint: "Known fields: name (string), ledSettings (object with isEnabled boolean)",
69
- returns: "id, modelKey, name, mac, state, ledSettings (isEnabled), outputs (array), inputs (array), wirelessConnectionState (7.1.83 docs)",
72
+ returns: "id, modelKey, name, mac, state, type, guid, ledSettings (isEnabled), outputs (array), inputs (array), wirelessConnectionState (7.3.47 docs)",
70
73
  },
71
74
  {
72
75
  urlPath: "speakers",
@@ -74,7 +77,7 @@ const DEVICES = [
74
77
  plural: "speakers",
75
78
  label: "Speaker",
76
79
  hint: "Known fields: name (string), volume (integer 0-100), micVolume (integer 0-100), isMicEnabled (boolean)",
77
- returns: "id, modelKey, name, mac, state, volume, micVolume, isMicEnabled, speakerState (status, mode), featureFlags (hasMic) (7.1.83 docs)",
80
+ returns: "id, modelKey, name, mac, state, type, guid, volume, micVolume, isMicEnabled, speakerState (status, mode), featureFlags (hasMic) (7.3.47 docs)",
78
81
  },
79
82
  {
80
83
  urlPath: "bridges",
@@ -82,7 +85,7 @@ const DEVICES = [
82
85
  plural: "bridges",
83
86
  label: "Bridge",
84
87
  hint: "Known fields: name (string)",
85
- returns: "id, modelKey, name, mac, state, platform, clients (array of MACs), maxClients (7.1.83 docs)",
88
+ returns: "id, modelKey, name, mac, state, type, guid, platform, clients (array of MACs), maxClients (7.3.47 docs)",
86
89
  },
87
90
  {
88
91
  urlPath: "link-stations",
@@ -90,7 +93,7 @@ const DEVICES = [
90
93
  plural: "link_stations",
91
94
  label: "Link station",
92
95
  hint: "Known fields: name (string)",
93
- returns: "id, modelKey (\"linkstation\"), name, mac, state, isAlarmHub, ledSettings (isEnabled), lastEvent, alarmHub (object) (7.1.83 docs)",
96
+ returns: "id, modelKey (\"linkstation\"), name, mac, state, type, guid, isAlarmHub, ledSettings (isEnabled), lastEvent, alarmHub (object), deviceTamperStatus, threadState (network: status, role, networkName, channel, panId, extendedPanId, joinedDeviceCount, errorReason, lastUpdatedAt) (7.3.47 docs)",
94
97
  },
95
98
  {
96
99
  urlPath: "alarm-hubs",
@@ -98,7 +101,7 @@ const DEVICES = [
98
101
  plural: "alarm_hubs",
99
102
  label: "Alarm hub",
100
103
  hint: "Known fields: name (string)",
101
- returns: "id, modelKey (\"linkstation\"), name, mac, state, isAlarmHub, ledSettings (isEnabled), lastEvent, alarmHub (object) (7.1.83 docs)",
104
+ returns: "id, modelKey (\"linkstation\"), name, mac, state, type, guid, isAlarmHub, ledSettings (isEnabled), lastEvent, alarmHub (object), deviceTamperStatus, threadState (network: status, role, networkName, channel, panId, extendedPanId, joinedDeviceCount, errorReason, lastUpdatedAt) (7.3.47 docs)",
102
105
  },
103
106
  ];
104
107
  function registerDeviceCrud(server, client, cfg, readOnly) {
@@ -10,6 +10,7 @@ const files_js_1 = require("./files.js");
10
10
  const subscriptions_js_1 = require("./subscriptions.js");
11
11
  const arm_profiles_js_1 = require("./arm-profiles.js");
12
12
  const users_js_1 = require("./users.js");
13
+ const pos_js_1 = require("./pos.js");
13
14
  function registerAllTools(server, client, readOnly) {
14
15
  (0, system_js_1.registerSystemTools)(server, client);
15
16
  (0, subscriptions_js_1.registerSubscriptionTools)(server, client);
@@ -20,4 +21,5 @@ function registerAllTools(server, client, readOnly) {
20
21
  (0, files_js_1.registerFileTools)(server, client, readOnly);
21
22
  (0, arm_profiles_js_1.registerArmProfileTools)(server, client, readOnly);
22
23
  (0, users_js_1.registerUserTools)(server, client);
24
+ (0, pos_js_1.registerPosTools)(server, client, readOnly);
23
25
  }
@@ -0,0 +1,10 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { ProtectClient } from "../client.js";
3
+ /**
4
+ * Point-of-sale event ingestion (added in Protect 7.3.x).
5
+ *
6
+ * `lineItems` entries use `.passthrough()` because the 7.3.47 docs render the
7
+ * item schema collapsed — the request sample shows `{ title, quantity }`, but
8
+ * an undocumented extra field should reach the API rather than be stripped.
9
+ */
10
+ export declare function registerPosTools(server: McpServer, client: ProtectClient, readOnly: boolean): void;
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerPosTools = registerPosTools;
4
+ const zod_1 = require("zod");
5
+ const responses_js_1 = require("../utils/responses.js");
6
+ const safety_js_1 = require("../utils/safety.js");
7
+ const url_js_1 = require("../utils/url.js");
8
+ const pos_js_1 = require("../schemas/pos.js");
9
+ /**
10
+ * Point-of-sale event ingestion (added in Protect 7.3.x).
11
+ *
12
+ * `lineItems` entries use `.passthrough()` because the 7.3.47 docs render the
13
+ * item schema collapsed — the request sample shows `{ title, quantity }`, but
14
+ * an undocumented extra field should reach the API rather than be stripped.
15
+ */
16
+ function registerPosTools(server, client, readOnly) {
17
+ if (readOnly)
18
+ return;
19
+ const lineItemSchema = zod_1.z
20
+ .object({
21
+ title: zod_1.z.string().describe("Line item name"),
22
+ quantity: zod_1.z.number().min(1).describe("Quantity purchased (>= 1)"),
23
+ })
24
+ .passthrough();
25
+ server.registerTool("protect_ingest_pos_transaction", {
26
+ description: "Record a point-of-sale transaction as a camera event so the transaction " +
27
+ "details can be overlaid on recorded footage. Requires write access to the " +
28
+ "target camera. Footage capture is best-effort: the overlay only appears " +
29
+ "where the camera was actually recording the transaction window, and a " +
30
+ "backdated timestamp may fall outside retained footage — a success response " +
31
+ "confirms the event was recorded, NOT that video exists for that window. " +
32
+ "A 409 means a transaction with the same externalId is already being " +
33
+ "processed for this camera; retry shortly. " +
34
+ "Returns: created (boolean), eventId (string).",
35
+ inputSchema: {
36
+ id: zod_1.z.string().describe("Camera ID to attach the transaction event to"),
37
+ type: zod_1.z.enum(["sale", "refund"]).describe("Transaction type"),
38
+ externalId: zod_1.z
39
+ .string()
40
+ .min(1)
41
+ .max(255)
42
+ .describe("Caller-supplied transaction ID, unique per camera. Used for " +
43
+ "best-effort idempotency within a short window only — the dedupe " +
44
+ "cache is in-memory and per-process, so a retry after a Protect " +
45
+ "restart or after the window elapses may create a duplicate event."),
46
+ amount: zod_1.z.number().min(0).describe("Transaction total amount (>= 0)"),
47
+ currency: zod_1.z
48
+ .string()
49
+ .regex(/^[A-Z]{3}$/)
50
+ .optional()
51
+ .describe('Uppercase ISO 4217 currency code, e.g. "USD"'),
52
+ lineItems: zod_1.z
53
+ .array(lineItemSchema)
54
+ .max(200)
55
+ .optional()
56
+ .describe("Purchased line items (max 200)"),
57
+ location: zod_1.z
58
+ .object({
59
+ id: zod_1.z.string().optional().describe("Store/location ID"),
60
+ name: zod_1.z.string().optional().describe("Store/location name"),
61
+ })
62
+ .passthrough()
63
+ .optional()
64
+ .describe("Point-of-sale location"),
65
+ paymentTypes: zod_1.z
66
+ .array(zod_1.z.string().min(1).max(255))
67
+ .max(20)
68
+ .optional()
69
+ .describe("Payment method names (max 20)"),
70
+ timestamp: zod_1.z
71
+ .number()
72
+ .int()
73
+ .min(1)
74
+ .optional()
75
+ .describe("Transaction time in epoch milliseconds. Protect validates this " +
76
+ "against the NVR clock: it must be within the last 24 hours and no " +
77
+ "more than 5 minutes ahead of server time. Protect rejects an " +
78
+ "out-of-range value with a 400 and clamps an in-skew value to now. " +
79
+ "This tool forwards the value unchanged rather than pre-checking it, " +
80
+ "because the window is relative to NVR time, not this process clock."),
81
+ dryRun: zod_1.z
82
+ .boolean()
83
+ .optional()
84
+ .describe("If true, return what would happen without making changes"),
85
+ },
86
+ outputSchema: pos_js_1.posTransactionOutputSchema,
87
+ annotations: safety_js_1.WRITE,
88
+ }, async ({ id, dryRun, ...transaction }) => {
89
+ try {
90
+ const path = (0, url_js_1.safePath) `/pos/cameras/${id}/transactions`;
91
+ if (dryRun) {
92
+ return (0, safety_js_1.formatDryRun)("POST", path, transaction);
93
+ }
94
+ const data = await client.post(path, transaction);
95
+ return (0, responses_js_1.formatSuccess)(data);
96
+ }
97
+ catch (err) {
98
+ return (0, responses_js_1.formatError)(err);
99
+ }
100
+ });
101
+ }
@@ -19,7 +19,7 @@ function registerSystemTools(server, client) {
19
19
  }
20
20
  });
21
21
  server.registerTool("protect_list_nvrs", {
22
- description: "Get the NVR (Network Video Recorder) console info. NOTE: despite the name, the Protect Integration API's /nvrs endpoint returns a SINGLE NVR object, not an array. Returns: id, modelKey, name, doorbellSettings (defaultMessageText, defaultMessageResetTimeoutMs, customMessages[], customImages[]), armMode (status, armedAt, willBeArmedAt, breachDetectedAt, breachEventCount, breachTriggerEventId, breachEventId).",
22
+ description: "Get the NVR (Network Video Recorder) console info. NOTE: despite the name, the Protect Integration API's /nvrs endpoint returns a SINGLE NVR object, not an array. Returns: id, modelKey, name, type (e.g. UNVR-PRO), guid, mac, doorbellSettings (defaultMessageText, defaultMessageResetTimeoutMs, customMessages[], customImages[]), armMode (status, armedAt, willBeArmedAt, breachDetectedAt, breachEventCount, breachTriggerEventId, breachEventId).",
23
23
  outputSchema: misc_js_1.nvrOutputSchema,
24
24
  annotations: safety_js_1.READ_ONLY,
25
25
  }, async () => {
@@ -8,7 +8,7 @@ const url_js_1 = require("../utils/url.js");
8
8
  const misc_js_1 = require("../schemas/misc.js");
9
9
  function registerUserTools(server, client) {
10
10
  server.registerTool("protect_list_users", {
11
- description: "List all Protect users (filtered by the API key's access permissions). Returns array; each user includes (Integration API 7.1.83-verified): id, modelKey, name, firstName, lastName, email, ucoreUserId. The Integration API does NOT expose roles, permissions, login history, groups, or notification settings.",
11
+ description: "List all Protect users (filtered by the API key's access permissions). Returns array; each user includes (Integration API 7.3.47-verified): id, modelKey, name, firstName, lastName, email, ucoreUserId. The Integration API does NOT expose roles, permissions, login history, groups, or notification settings.",
12
12
  outputSchema: misc_js_1.userListOutputSchema,
13
13
  annotations: safety_js_1.READ_ONLY,
14
14
  }, async () => {
@@ -35,7 +35,7 @@ function registerUserTools(server, client) {
35
35
  }
36
36
  });
37
37
  server.registerTool("protect_list_ulp_users", {
38
- description: "List all UniFi Identity (ULP) users. Returns array; each ULP user includes (Integration API 7.1.83-verified): id, modelKey, firstName, lastName, fullName, status (e.g. ACTIVE). Enrolled-credential detail (NFC cards, fingerprints) is NOT exposed by this API surface.",
38
+ description: "List all UniFi Identity (ULP) users. Returns array; each ULP user includes (Integration API 7.3.47-verified): id, modelKey, firstName, lastName, fullName, email (empty string for service accounts), status (e.g. ACTIVE). Enrolled-credential detail (NFC cards, fingerprints) is NOT exposed by this API surface.",
39
39
  outputSchema: misc_js_1.ulpUserListOutputSchema,
40
40
  annotations: safety_js_1.READ_ONLY,
41
41
  }, async () => {
@@ -48,7 +48,7 @@ function registerUserTools(server, client) {
48
48
  }
49
49
  });
50
50
  server.registerTool("protect_get_ulp_user", {
51
- description: "Get details for a specific UniFi Identity (ULP) user by ID. Returns: id, modelKey, firstName, lastName, fullName, status.",
51
+ description: "Get details for a specific UniFi Identity (ULP) user by ID. Returns: id, modelKey, firstName, lastName, fullName, email, status.",
52
52
  inputSchema: { id: zod_1.z.string().describe("ULP user ID") },
53
53
  outputSchema: misc_js_1.ulpUserOutputSchema,
54
54
  annotations: safety_js_1.READ_ONLY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owine/unifi-protect-mcp",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "MCP server for UniFi Protect Integration API",
5
5
  "main": "dist/index.js",
6
6
  "bin": {