rhombus-node-mcp 0.1.27 → 0.1.28

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.
@@ -3,23 +3,25 @@ import { postApi } from "../network/network.js";
3
3
  import { formatTimestamp } from "../util.js";
4
4
  import { tempFunc } from "../utils/temp.js";
5
5
  export async function getCameraList(requestModifiers, sessionId) {
6
+ const body = await postApi({
7
+ route: "/camera/getMinimalCameraStateList",
8
+ body: {},
9
+ modifiers: requestModifiers,
10
+ sessionId,
11
+ });
6
12
  return {
7
- cameras: (await postApi({
8
- route: "/camera/getMinimalCameraStateList",
9
- body: {},
10
- modifiers: requestModifiers,
11
- sessionId,
12
- })).cameraStates.filter((camera) => !!camera.locationUuid),
13
+ cameras: (body.cameraStates ?? []).filter((camera) => !!camera.locationUuid),
13
14
  };
14
15
  }
15
16
  export async function getDoorbellCameras(requestModifiers, sessionId) {
17
+ const body = await postApi({
18
+ route: "/doorbellcamera/getMinimalStateList",
19
+ body: {},
20
+ modifiers: requestModifiers,
21
+ sessionId,
22
+ });
16
23
  return {
17
- doorbellCameras: (await postApi({
18
- route: "/doorbellcamera/getMinimalStateList",
19
- body: {},
20
- modifiers: requestModifiers,
21
- sessionId,
22
- })).minimalStates.filter((doorbellCamera) => !!doorbellCamera.locationUuid),
24
+ doorbellCameras: (body.minimalStates ?? []).filter((doorbellCamera) => !!doorbellCamera.locationUuid),
23
25
  };
24
26
  }
25
27
  export async function getBadgeReaders(requestModifiers, sessionId) {
@@ -30,7 +32,7 @@ export async function getBadgeReaders(requestModifiers, sessionId) {
30
32
  sessionId,
31
33
  }).then((response) => {
32
34
  return {
33
- badgeReaders: response.minimalStates.filter((badgeReader) => !!badgeReader.locationUuid),
35
+ badgeReaders: (response.minimalStates ?? []).filter((badgeReader) => !!badgeReader.locationUuid),
34
36
  };
35
37
  });
36
38
  }
@@ -65,7 +67,7 @@ export async function getAudioGateways(timeZone, requestModifiers, sessionId) {
65
67
  sessionId,
66
68
  }).then((response) => {
67
69
  return {
68
- audioGateways: response.audioGatewayStates
70
+ audioGateways: (response.audioGatewayStates ?? [])
69
71
  .filter((camera) => !!camera.locationUuid)
70
72
  .map((gateway) => ({
71
73
  ...gateway,
@@ -84,7 +86,7 @@ export async function getDoorSensors(requestModifiers, sessionId) {
84
86
  sessionId,
85
87
  }).then((response) => {
86
88
  return {
87
- doorStates: response.doorStates.filter((door) => !!door.locationUuid),
89
+ doorStates: (response.doorStates ?? []).filter((door) => !!door.locationUuid),
88
90
  };
89
91
  });
90
92
  }
@@ -97,7 +99,7 @@ export async function getEnvironmentalSensors(timeZone, tempUnit, requestModifie
97
99
  }).then((response) => {
98
100
  logger.info("Using tempUnit: ", tempUnit);
99
101
  return {
100
- climateStates: response.climateStates
102
+ climateStates: (response.climateStates ?? [])
101
103
  .filter((sensor) => !!sensor.locationUuid)
102
104
  .map((_sensor) => {
103
105
  const { temperatureCelcius, ...sensor } = _sensor;
@@ -120,7 +122,7 @@ export async function getMotionSensors(requestModifiers, sessionId) {
120
122
  sessionId,
121
123
  }).then((response) => {
122
124
  return {
123
- occupancySensorStates: response.occupancySensorStates.filter((occupancySensor) => !!occupancySensor.locationUuid),
125
+ occupancySensorStates: (response.occupancySensorStates ?? []).filter((occupancySensor) => !!occupancySensor.locationUuid),
124
126
  };
125
127
  });
126
128
  }
@@ -132,7 +134,7 @@ export async function getButtons(timeZone, requestModifiers, sessionId) {
132
134
  sessionId,
133
135
  }).then((response) => {
134
136
  return {
135
- buttonStates: response.states
137
+ buttonStates: (response.states ?? [])
136
138
  .filter((button) => !!button.locationUuid)
137
139
  .map((button) => ({
138
140
  ...button,
@@ -151,7 +153,7 @@ export async function getKeypads(requestModifiers, sessionId) {
151
153
  sessionId,
152
154
  }).then((response) => {
153
155
  return {
154
- keypadStates: response.keypads.filter((keypad) => !!keypad.locationUuid),
156
+ keypadStates: (response.keypads ?? []).filter((keypad) => !!keypad.locationUuid),
155
157
  };
156
158
  });
157
159
  }
@@ -163,7 +165,7 @@ export async function getEnvironmentalGateways(timeZone, requestModifiers, sessi
163
165
  sessionId,
164
166
  }).then((response) => {
165
167
  return {
166
- minimalEnvironmentalGatewayStates: response.minimalEnvironmentalGatewayStates
168
+ minimalEnvironmentalGatewayStates: (response.minimalEnvironmentalGatewayStates ?? [])
167
169
  .filter((gateway) => !!gateway.locationUuid)
168
170
  .map((gateway) => ({
169
171
  ...gateway,
package/dist/logger.js CHANGED
@@ -17,7 +17,7 @@ catch (error) {
17
17
  const appenders = {
18
18
  // stderr for terminal visibility (always available)
19
19
  stderr: { type: "stderr" },
20
- // only send warn+ to stderr (never stdout)
20
+ // production stderr: hide trace/debug (e.g. full response snippets); still shows info+ like [POSTAPI] REQUEST
21
21
  stderrInfo: {
22
22
  type: "logLevelFilter",
23
23
  appender: "stderr",
@@ -36,7 +36,8 @@ if (fileLoggingEnabled) {
36
36
  layout: { type: "basic" },
37
37
  };
38
38
  }
39
- const stderrAppender = process.env.DEBUG === "true" ? "stderr" : "stderrInfo";
39
+ const isProduction = process.env.NODE_ENV === "production";
40
+ const stderrAppender = isProduction ? "stderrInfo" : "stderr";
40
41
  // Configure categories based on available appenders
41
42
  const categories = {
42
43
  default: {
@@ -14,7 +14,9 @@ includes a "connected" boolean field indicating whether it is currently online (
14
14
  When asked about device health, offline devices, or connectivity issues, use this tool to fetch all device
15
15
  types and check the "connected" field to identify which devices are offline or unreachable.`;
16
16
  const TOOL_HANDLER = async (args, extra) => {
17
- const { entityTypes, timeZone, filterBy, tempUnit } = args;
17
+ const { entityTypes, timeZone, tempUnit } = args;
18
+ const filterBy = args.filterBy ?? { locationUuids: null };
19
+ const locationFilter = filterBy.locationUuids;
18
20
  const { requestModifiers, sessionId } = extractFromToolExtra(extra);
19
21
  const promises = [];
20
22
  if (entityTypes.includes(DeviceType.CAMERA)) {
@@ -61,8 +63,10 @@ const TOOL_HANDLER = async (args, extra) => {
61
63
  // then filter
62
64
  response[key] = value.filter((item) => {
63
65
  let pass = true;
64
- if (item.locationUuid && filterBy.locationUuids && filterBy.locationUuids.length > 0) {
65
- pass = pass && filterBy.locationUuids.includes(item.locationUuid);
66
+ if (item.locationUuid &&
67
+ locationFilter &&
68
+ locationFilter.length > 0) {
69
+ pass = pass && locationFilter.includes(item.locationUuid);
66
70
  }
67
71
  return pass;
68
72
  });
@@ -2,18 +2,21 @@ import { z } from "zod";
2
2
  import { createUuidSchema } from "../types.js";
3
3
  import DeviceType from "./deviceType.js";
4
4
  import { TempUnit } from "../utils/temp.js";
5
+ const filterByObjectSchema = z.object({
6
+ locationUuids: z
7
+ .array(createUuidSchema())
8
+ .nullish()
9
+ .describe("The UUIDs of the locations to filter by. Set to null or an empty array to not filter by location."),
10
+ });
5
11
  export const TOOL_ARGS = {
6
12
  entityTypes: z
7
13
  .array(z.nativeEnum(DeviceType).describe("The entity type to retreive"))
8
14
  .describe("What type of entities to retrieve."),
9
15
  filterBy: z
10
- .object({
11
- locationUuids: z
12
- .array(createUuidSchema())
13
- .nullable()
14
- .describe("The UUIDs of the locations to filter by. Set to null or an enmpty array to not filter by location."),
15
- })
16
- .describe("Additional filters that can be applied to the result."),
16
+ .union([filterByObjectSchema, z.null()])
17
+ .optional()
18
+ .transform((v) => v ?? { locationUuids: null })
19
+ .describe("Additional filters that can be applied to the result. Omit or pass null for no filtering."),
17
20
  timeZone: z
18
21
  .string()
19
22
  .describe("The timezone for formatting timestamps. This is necessary for the tool to produce accurate formatted timestamps."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rhombus-node-mcp",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "MCP server for Rhombus API",
5
5
  "keywords": [
6
6
  "ai",