rhombus-node-mcp 0.1.56 → 0.1.57

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.
Files changed (102) hide show
  1. package/dist/api/access-control-tool-api.js +231 -32
  2. package/dist/api/alarm-monitoring-tool-api.js +50 -1
  3. package/dist/api/automated-prompts-tool-api.js +9 -17
  4. package/dist/api/camera-policy-tool-api.js +122 -0
  5. package/dist/api/camera-tool-api.js +3 -5
  6. package/dist/api/camera-uptime-tool-api.js +62 -25
  7. package/dist/api/clips-tool-api.js +45 -9
  8. package/dist/api/create-tool-api.js +55 -7
  9. package/dist/api/door-tool-api.js +74 -13
  10. package/dist/api/entity-lookup-tool-api.js +8 -1
  11. package/dist/api/events-tool-api.js +79 -6
  12. package/dist/api/faces-tool-api.js +112 -7
  13. package/dist/api/get-accessible-apps.js +68 -6
  14. package/dist/api/get-entity-tool-api.js +12 -12
  15. package/dist/api/get-org-information-tool-api.js +2 -2
  16. package/dist/api/guest-management-tool-api.js +75 -1
  17. package/dist/api/location-tool-api.js +120 -28
  18. package/dist/api/lpr-tool-api.js +71 -16
  19. package/dist/api/policy-alerts-tool-api.js +7 -3
  20. package/dist/api/report-tool-api.js +4 -1
  21. package/dist/api/rules-tool-api.js +6 -16
  22. package/dist/api/schedule-tool-api.js +107 -0
  23. package/dist/api/search-tool-api.js +5 -13
  24. package/dist/api/update-tool-api.js +96 -1
  25. package/dist/api/user-tool-api.js +58 -13
  26. package/dist/createServer.js +18 -6
  27. package/dist/filtering-utils.js +421 -29
  28. package/dist/index.js +1 -1
  29. package/dist/network/network.js +122 -10
  30. package/dist/network/org-reference-cache.js +74 -0
  31. package/dist/telemetry/tracingProxy.js +4 -0
  32. package/dist/tools/entity-lookup-tool.js +6 -4
  33. package/dist/tools/get-entity-tool.js +40 -20
  34. package/dist/tools/get-org-information-tool.js +30 -2
  35. package/dist/tools/time-conversion-tool.js +59 -36
  36. package/dist/tools/time-tool.js +12 -3
  37. package/dist/tools/user-tool.js +100 -2
  38. package/dist/tools-console/access-anomaly-tool.js +2 -19
  39. package/dist/tools-console/access-control-tool.js +328 -2
  40. package/dist/tools-console/alarm-monitoring-tool.js +72 -2
  41. package/dist/tools-console/analytics-tool.js +2 -2
  42. package/dist/tools-console/badge-timeline-tool.js +2 -21
  43. package/dist/tools-console/camera-policy-tool.js +252 -0
  44. package/dist/tools-console/camera-tool.js +111 -89
  45. package/dist/tools-console/clips-tool.js +21 -31
  46. package/dist/tools-console/count-tool.js +8 -0
  47. package/dist/tools-console/create-camera-policy-tool.js +302 -122
  48. package/dist/tools-console/door-schedule-exception-tool.js +2 -33
  49. package/dist/tools-console/door-tool.js +130 -2
  50. package/dist/tools-console/elements-access-anomaly-tool.js +2 -19
  51. package/dist/tools-console/elements-badge-timeline-tool.js +2 -21
  52. package/dist/tools-console/elements-lost-badge-tool.js +2 -17
  53. package/dist/tools-console/elements-tool.js +2 -29
  54. package/dist/tools-console/events-tool.js +22 -101
  55. package/dist/tools-console/faces-tool.js +254 -28
  56. package/dist/tools-console/guest-management-tool.js +127 -2
  57. package/dist/tools-console/location-tool.js +156 -35
  58. package/dist/tools-console/lost-badge-tool.js +2 -17
  59. package/dist/tools-console/lpr-tool.js +89 -23
  60. package/dist/tools-console/netbox-access-anomaly-tool.js +2 -19
  61. package/dist/tools-console/netbox-badge-timeline-tool.js +2 -21
  62. package/dist/tools-console/netbox-lost-badge-tool.js +2 -17
  63. package/dist/tools-console/netbox-tool.js +2 -29
  64. package/dist/tools-console/onguard-tool.js +2 -30
  65. package/dist/tools-console/person-tracking-tool.js +2 -2
  66. package/dist/tools-console/policy-alerts-tool.js +5 -29
  67. package/dist/tools-console/reboot-cameras-tool.js +17 -2
  68. package/dist/tools-console/report-tool.js +10 -40
  69. package/dist/tools-console/schedule-tool.js +190 -0
  70. package/dist/tools-console/update-tool.js +298 -168
  71. package/dist/tools-console/video-walls-tool.js +93 -21
  72. package/dist/types/access-anomaly-tool-types.js +22 -2
  73. package/dist/types/access-control-tool-types.js +116 -1
  74. package/dist/types/alarm-monitoring-tool-types.js +42 -1
  75. package/dist/types/badge-timeline-tool-types.js +18 -3
  76. package/dist/types/camera-policy-tool-types.js +104 -0
  77. package/dist/types/camera-tool-types.js +80 -1
  78. package/dist/types/clips-tool-types.js +27 -3
  79. package/dist/types/create-camera-policy-tool-types.js +275 -26
  80. package/dist/types/door-schedule-exception-tool-types.js +20 -6
  81. package/dist/types/door-tool-types.js +36 -4
  82. package/dist/types/entity-lookup-tool-types.js +6 -1
  83. package/dist/types/events-tools-types.js +24 -16
  84. package/dist/types/faces-tools-types.js +106 -3
  85. package/dist/types/get-entity-tool-types.js +76 -12
  86. package/dist/types/guest-management-tool-types.js +103 -1
  87. package/dist/types/location-tool-types.js +100 -14
  88. package/dist/types/lost-badge-tool-types.js +17 -2
  89. package/dist/types/lpr-tool-types.js +47 -8
  90. package/dist/types/onguard-tool-types.js +21 -1
  91. package/dist/types/policy-alerts-tool-types.js +1 -1
  92. package/dist/types/report-tool-types.js +29 -1
  93. package/dist/types/schedule-tool-types.js +370 -0
  94. package/dist/types/schema.js +479 -9
  95. package/dist/types/time-conversion-tool-types.js +3 -4
  96. package/dist/types/update-tool-types.js +40 -18
  97. package/dist/types/user-tool-types.js +44 -1
  98. package/dist/types/video-walls-tool-types.js +30 -2
  99. package/dist/types/zod-schemas.js +5128 -996
  100. package/dist/util.js +62 -3
  101. package/dist/utils/entity-name-match.js +11 -0
  102. package/package.json +3 -1
@@ -1,8 +1,7 @@
1
1
  import { z } from "zod";
2
2
  export const TOOL_ARGS = {
3
- time_to_convert: z.union([
4
- z.string(),
5
- z.number(),
6
- ]).describe("The time to convert. This can be either an ISO 8601 timestamp string (e.g., '2023-10-05T14:48:00.000Z') or a Unix timestamp in milliseconds."),
3
+ time_to_convert: z
4
+ .union([z.string(), z.number()])
5
+ .describe("The time(s) to convert. Either an ISO 8601 timestamp string (e.g. '2023-10-05T14:48:00.000Z' or '2023-10-05T14:48:00-07:00'), a Unix timestamp in milliseconds, or a comma-separated list of several such values (converted in order)."),
7
6
  };
8
7
  const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
@@ -1,14 +1,15 @@
1
1
  import { z } from "zod";
2
- // Define the entity types that can be updated
3
- export const ENTITY_TYPE = z.enum([
4
- "camera",
5
- "climate-sensor",
6
- "door-controller",
7
- "environmental-gateway",
8
- "audio-gateway",
9
- "doorbell-camera",
10
- "badge-reader",
11
- ]);
2
+ /**
3
+ * The entity types this tool can actually update.
4
+ *
5
+ * Deliberately narrow. It previously listed climate-sensor, door-controller,
6
+ * environmental-gateway, audio-gateway and badge-reader, none of which had a
7
+ * handler — every one returned "not yet implemented. Coming soon!". Because the
8
+ * chatbot adapts MCP tools with `strict: false`, an enum is advisory: nothing
9
+ * stopped the model picking one of those, and each attempt burned a turn on a
10
+ * guaranteed dead end. Add a value here only once its handler exists.
11
+ */
12
+ export const ENTITY_TYPE = z.enum(["camera", "doorbell-camera"]);
12
13
  // Camera-specific update schemas
13
14
  export const CameraVideoSettings = z.object({
14
15
  hdr_enabled: z.boolean().optional().describe("Enable HDR (High Dynamic Range)"),
@@ -20,7 +21,7 @@ export const CameraVideoSettings = z.object({
20
21
  .describe("Image brightness adjustment (-255 to 255)"),
21
22
  img_contrast: z.number().min(0).max(128).optional().describe("Image contrast (0 to 128)"),
22
23
  img_saturation: z.number().min(0).max(255).optional().describe("Image saturation (0 to 255)"),
23
- img_sharpness: z.number().min(0).max(255).optional().describe("Image sharpness (0 to 255)"),
24
+ img_sharpness: z.number().min(0).max(11).optional().describe("Image sharpness (0 to 11; 6 works for most situations)"),
24
25
  resolution: z
25
26
  .object({
26
27
  width: z.number().int().positive().optional(),
@@ -59,9 +60,9 @@ export const CameraVideoSettings = z.object({
59
60
  night_img_sharpness: z
60
61
  .number()
61
62
  .min(0)
62
- .max(255)
63
+ .max(11)
63
64
  .optional()
64
- .describe("Night mode sharpness (0 to 255)"),
65
+ .describe("Night mode sharpness (0 to 11; 6 works for most situations)"),
65
66
  });
66
67
  export const CameraAudioSettings = z.object({
67
68
  audio_record: z.boolean().optional().describe("Enable audio recording"),
@@ -95,21 +96,37 @@ export const CameraDeviceSettings = z.object({
95
96
  });
96
97
  // Input schema for the tool
97
98
  export const TOOL_ARGS = {
98
- entityType: ENTITY_TYPE.describe("Type of entity to update"),
99
- entityUuid: z.string().nullable().describe("UUID of the entity to update"),
99
+ entityType: ENTITY_TYPE.describe("Type of entity to update. Only 'camera' and 'doorbell-camera' can be updated through this tool; " +
100
+ "for climate sensors, door controllers, environmental gateways, audio gateways and badge readers, tell the " +
101
+ "user the change has to be made in the Rhombus Console rather than attempting it here."),
102
+ entityUuid: z
103
+ .string()
104
+ .nullable()
105
+ .describe('UUID of the entity to update. Faceted UUIDs are supported (e.g. "cameraUuid.v0" / "cameraUuid.v1") to target a specific camera facet; defaults to "v0" when no facet is given.'),
100
106
  // Camera-specific update fields
107
+ // These three arrive as free-form JSON strings, so the field schemas below are
108
+ // NOT part of the input schema the model sees — this description text is the
109
+ // only range guidance it ever gets. Keep it in sync with CameraVideoSettings /
110
+ // CameraAudioSettings / CameraDeviceSettings.
111
+ //
112
+ // Promoting them to real object schemas would NOT make out-of-range values
113
+ // impossible: the chatbot sends MCP tools to OpenAI with `strict: false`
114
+ // (chatbot src/mcp/toolAdapters.ts), so there is no constrained decoding, and
115
+ // even under `strict: true` JSON Schema `minimum`/`maximum` are not enforced
116
+ // keywords. Range checking is therefore ALWAYS the tool's job — which is why
117
+ // parseSettingsBlock reports the field, the bound, and the received value.
101
118
  cameraVideoSettings: z
102
119
  .string()
103
120
  .nullable()
104
- .describe("JSON string of video settings to update for camera"),
121
+ .describe(`JSON string of video settings to update for camera. Values outside these ranges are REJECTED — img_brightness: -255 to 255 · img_contrast: 0 to 128 · img_saturation: 0 to 255 · img_sharpness: 0 to 11 (6 is typical — NOT a 0-100 scale) · wdr_strength: 0 to 128 (64 is typical) · zero_motion_video_bitrate_percent: 0 to 100 · hdr_enabled / wdr_enabled / video_persist_disabled: booleans · resolution: {"width": n, "height": n}. The night-mode fields (night_img_brightness, night_img_contrast, night_img_saturation, night_img_sharpness) take the same ranges as their daytime counterparts. Example for a dark image: '{"img_brightness": 0, "wdr_strength": 64}'; for a washed-out image: '{"img_brightness": -50, "img_contrast": 80}'; for a blurry image: '{"img_sharpness": 8}'. Saturation matters — 0 yields grayscale; most cameras look best mid-range, tune from there.`),
105
122
  cameraAudioSettings: z
106
123
  .string()
107
124
  .nullable()
108
- .describe("JSON string of audio settings to update for camera"),
125
+ .describe(`JSON string of audio settings to update for camera. audio_record / device_mic_enabled / device_speaker_enabled: booleans · audio_internal_mic_volume: 0 to 100 · audio_internal_speaker_volume: 0 to 100. Example: '{"audio_record": true, "audio_internal_mic_volume": 80}'.`),
109
126
  cameraDeviceSettings: z
110
127
  .string()
111
128
  .nullable()
112
- .describe("JSON string of device settings to update for camera"),
129
+ .describe(`JSON string of device settings to update for camera (name, timezone, LED). camera_name / camera_timezone: strings · led_intensity: 0 to 100 · led_mode: one of "auto", "always_on", "always_off" · led_stealth_mode: boolean. LED control uses EXACTLY these underscore field names (not camelCase): LED off = '{"led_stealth_mode": true}' (recommended) or '{"led_mode": "always_off"}'; LED on = '{"led_stealth_mode": false}' or '{"led_mode": "always_on"}' or '{"led_mode": "auto"}'.`),
113
130
  // Step tracking for multi-step updates
114
131
  step: z
115
132
  .enum(["entity-selection", "settings-configuration", "confirmation"])
@@ -129,6 +146,11 @@ export const OUTPUT_SCHEMA = z.object({
129
146
  success: z.boolean().optional(),
130
147
  error: z.string().optional(),
131
148
  updatedSettings: z.any().optional(),
149
+ // Doorbell writes are verified by reading /doorbellcamera/getConfig back;
150
+ // these carry the before values and anything the read-back contradicted.
151
+ previousSettings: z.any().optional(),
152
+ settingsNotApplied: z.any().optional(),
153
+ settingsNotVerified: z.any().optional(),
132
154
  });
133
155
  // API payload types
134
156
  export const UpdateCameraConfigPayload = z.object({
@@ -5,6 +5,9 @@ export var UserToolRequestType;
5
5
  UserToolRequestType["FIND_BY_EMAIL"] = "find-by-email";
6
6
  UserToolRequestType["GET_PERMISSIONS"] = "get-permissions";
7
7
  UserToolRequestType["GET_PERMISSION_GROUPS"] = "get-permission-groups";
8
+ UserToolRequestType["CREATE_USER"] = "create-user";
9
+ UserToolRequestType["UPDATE_USER"] = "update-user";
10
+ UserToolRequestType["DELETE_USER"] = "delete-user";
8
11
  })(UserToolRequestType || (UserToolRequestType = {}));
9
12
  // NOTE: `includeFields` and `filterBy` are NOT declared here — the
10
13
  // `createFilteringProxy` wrapper automatically injects them into every tool's
@@ -15,7 +18,27 @@ export const TOOL_ARGS = {
15
18
  email: z
16
19
  .string()
17
20
  .nullable()
18
- .describe("The email address of the user to find. Required for 'find-by-email'."),
21
+ .describe("The email address of the user. Required for 'find-by-email' and 'create-user'. For 'create-user' this is where the invitation is sent, so read it back to the user before creating — a typo invites a stranger into the organization."),
22
+ userUuid: z
23
+ .string()
24
+ .nullable()
25
+ .describe("The UUID of the user. Required for 'update-user' and 'delete-user'. Get it from 'list-users' or 'find-by-email' — do not guess one."),
26
+ userName: z
27
+ .string()
28
+ .nullable()
29
+ .describe("The user's display name. Required for 'create-user'; for 'update-user' it is the new name (omit to leave it unchanged)."),
30
+ permissionGroupUuid: z
31
+ .string()
32
+ .nullable()
33
+ .describe("UUID of the permission group (role) to assign. Required for 'create-user'; for 'update-user' it is the new role (omit to leave the role unchanged). Get it from 'get-permission-groups' with includeFields ['permissionGroups.uuid','permissionGroups.name','permissionGroups.description']. A role decides what the person can see and do, so confirm the role NAME with the user rather than picking one."),
34
+ suppressWelcomeEmail: z
35
+ .boolean()
36
+ .nullable()
37
+ .describe("Only for 'create-user'. Creating a user emails them an invitation by default. Set true only when the user explicitly asks not to notify the new person."),
38
+ confirmDelete: z
39
+ .boolean()
40
+ .nullable()
41
+ .describe("Required to be true for 'delete-user'. Deleting a user revokes their console access and their credentials, and cannot be undone, so it refuses without explicit confirmation."),
19
42
  };
20
43
  const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
21
44
  // Permission level assigned to a resource for a role. Typed loosely as string
@@ -106,5 +129,25 @@ export const OUTPUT_SCHEMA = z.object({
106
129
  .array(PermissionGroupSchema)
107
130
  .optional()
108
131
  .describe("List of permission groups in the organization."),
132
+ created: z
133
+ .object({ success: z.boolean().optional(), uuid: z.string().optional() })
134
+ .optional()
135
+ .describe("Result of 'create-user'."),
136
+ updated: z
137
+ .object({ success: z.boolean().optional(), uuid: z.string().optional() })
138
+ .optional()
139
+ .describe("Result of 'update-user'."),
140
+ deleted: z
141
+ .object({ success: z.boolean().optional(), uuid: z.string().optional() })
142
+ .optional()
143
+ .describe("Result of 'delete-user'."),
144
+ note: z
145
+ .string()
146
+ .optional()
147
+ .describe("A caveat about this result that the user needs to be told."),
148
+ warningMsg: z
149
+ .string()
150
+ .optional()
151
+ .describe("A warning from the Rhombus API — the call succeeded, but with a caveat."),
109
152
  error: z.string().optional().describe("An error message if the request failed."),
110
153
  });
@@ -28,9 +28,21 @@ export const CreateVideoWallOptions = z
28
28
  .describe("The options for creating a video wall. This is required if your requestType === `create`");
29
29
  export const TOOL_ARGS = {
30
30
  requestType: z
31
- .enum(["list", "create"])
31
+ .enum(["list", "create", "update", "delete"])
32
32
  .describe("The type of request to make."),
33
33
  videoWallCreateOptions: CreateVideoWallOptions,
34
+ videoWallUuid: z
35
+ .string()
36
+ .nullable()
37
+ .describe("The uuid of the video wall to act on. Required for `update` and `delete`. Get it from `list` — do not guess one."),
38
+ displayName: z
39
+ .string()
40
+ .nullable()
41
+ .describe("Only for `update`: a new name for the wall. Omit to leave the name unchanged."),
42
+ deviceList: z
43
+ .array(z.string())
44
+ .nullable()
45
+ .describe("Only for `update`: the camera uuids the wall should contain AFTER the update. This REPLACES the wall's current cameras rather than adding to them, so include the ones being kept. To add or remove a few, read the wall with `list` first and send the full resulting set. The grid layout is recomputed from the new count."),
34
46
  includeFields: INCLUDE_FIELDS_ARG,
35
47
  filterBy: FILTER_BY_ARG,
36
48
  };
@@ -53,7 +65,23 @@ export const OUTPUT_SCHEMA = z.object({
53
65
  .optional(),
54
66
  videoWall: z
55
67
  .array(z.any())
56
- .describe("If requestType is `get`, then this field will be populated with the video wall.")
68
+ .describe("Unused no current requestType populates this field. Use `videoWalls` (from 'list') or `uuid` (from 'create').")
57
69
  .optional(),
58
70
  uuid: z.string().describe("The uuid of the created video wall.").optional(),
71
+ updated: z
72
+ .object({ success: z.boolean().optional(), uuid: z.string().optional() })
73
+ .optional()
74
+ .describe("Result of an `update` request."),
75
+ deleted: z
76
+ .object({ success: z.boolean().optional(), uuid: z.string().optional() })
77
+ .optional()
78
+ .describe("Result of a `delete` request."),
79
+ note: z
80
+ .string()
81
+ .optional()
82
+ .describe("A caveat about this result that the user needs to be told."),
83
+ warningMsg: z
84
+ .string()
85
+ .optional()
86
+ .describe("A warning from the Rhombus API — the call succeeded, but with a caveat."),
59
87
  });