rhombus-node-mcp 0.1.43 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ import { postApi } from "../network/network.js";
2
+ import { formatTimestamp } from "../util.js";
3
+ /**
4
+ * Calls the webservice OnGuard event search (POST /eventSearchV2/searchOnGuardEvents) and maps the
5
+ * raw seekpoints to an agent-friendly shape. Typed against the generated public OpenAPI schema.
6
+ */
7
+ export async function searchOnGuardEvents(args, timeZone, requestModifiers, sessionId) {
8
+ const body = {
9
+ deviceUuids: args.deviceUuids,
10
+ locationUuids: args.locationUuids,
11
+ afterMs: args.afterMs,
12
+ beforeMs: args.beforeMs,
13
+ cardholderQuery: args.cardholderQuery,
14
+ badgeStatus: args.badgeStatus,
15
+ badgeType: args.badgeType,
16
+ area: args.area,
17
+ anomalyOnly: args.anomalyOnly,
18
+ entryMade: args.entryMade,
19
+ limit: args.limit ?? 200,
20
+ };
21
+ const res = await postApi({
22
+ route: "/eventSearchV2/searchOnGuardEvents",
23
+ body,
24
+ modifiers: requestModifiers,
25
+ sessionId,
26
+ });
27
+ if (res.error) {
28
+ throw new Error(res.status ?? res.errorMsg ?? "OnGuard event search failed");
29
+ }
30
+ const events = (res.events ?? []).map((e) => ({
31
+ timestampMs: e.timestampMs ?? undefined,
32
+ datetime: e.timestampMs != null ? formatTimestamp(e.timestampMs, timeZone) : undefined,
33
+ deviceUuid: e.deviceUuid ?? undefined,
34
+ label: e.customDisplayName ?? undefined,
35
+ cardholderName: e.customDescription ?? undefined,
36
+ badgeStatus: e.badgeStatus ?? undefined,
37
+ badgeType: e.badgeType ?? undefined,
38
+ areaEntering: e.areaEntering ?? undefined,
39
+ areaExiting: e.areaExiting ?? undefined,
40
+ entryMade: e.entryMade ?? undefined,
41
+ isAnomaly: e.alert ?? undefined,
42
+ }));
43
+ return { events };
44
+ }
@@ -0,0 +1,55 @@
1
+ import { searchOnGuardEvents } from "../api/onguard-tool-api.js";
2
+ import { OUTPUT_SCHEMA, TOOL_ARGS } from "../types/onguard-tool-types.js";
3
+ import { createToolStructuredContent, extractFromToolExtra } from "../util.js";
4
+ const TOOL_NAME = "onguard-events-tool";
5
+ const TOOL_DESCRIPTION = `
6
+ Searches Honeywell OnGuard (Lenel) badge / access-control events for the organization. Use this to answer
7
+ "who entered WHERE and WHEN" questions, e.g. "who entered the back office yesterday".
8
+
9
+ Each returned event includes:
10
+ - cardholderName: the person's name
11
+ - deviceUuid: the camera that saw the event
12
+ - timestampMs / datetime: when it happened
13
+ - label: e.g. "OnGuard: Badge Authorized" (a grant) or an anomaly label
14
+ - badgeStatus, badgeType, areaEntering, areaExiting, entryMade, isAnomaly
15
+
16
+ Filters (all optional): area, locationUuids, deviceUuids, cardholderQuery, badgeStatus, badgeType,
17
+ anomalyOnly, entryMade, startTime, endTime, limit. Resolve relative times like "yesterday" to ISO 8601
18
+ first (use the timestamp tool), then pass startTime/endTime.
19
+
20
+ IMPORTANT — to show pictures and video of each person so the user can visually identify them: after this
21
+ returns, for each event (or the most relevant ones) call the camera-tool (requestType "image",
22
+ cameraUuid = the event's deviceUuid, timestamp = the event's time) to get a still you can see, and/or the
23
+ clips-tool (requestType "createClip") with a short window around the timestamp for video. Issue those
24
+ per-event media calls in PARALLEL.
25
+ `;
26
+ const TOOL_HANDLER = async (args, _extra) => {
27
+ const { requestModifiers, sessionId } = extractFromToolExtra(_extra);
28
+ try {
29
+ const result = await searchOnGuardEvents({
30
+ area: args.area ?? undefined,
31
+ locationUuids: args.locationUuids ?? undefined,
32
+ deviceUuids: args.deviceUuids ?? undefined,
33
+ cardholderQuery: args.cardholderQuery ?? undefined,
34
+ badgeStatus: args.badgeStatus ?? undefined,
35
+ badgeType: args.badgeType ?? undefined,
36
+ anomalyOnly: args.anomalyOnly ?? undefined,
37
+ entryMade: args.entryMade ?? undefined,
38
+ afterMs: args.startTime ? new Date(args.startTime).getTime() : undefined,
39
+ beforeMs: args.endTime ? new Date(args.endTime).getTime() : undefined,
40
+ limit: args.limit ?? undefined,
41
+ }, args.timeZone ?? "UTC", requestModifiers, sessionId);
42
+ return createToolStructuredContent(result);
43
+ }
44
+ catch (error) {
45
+ const message = error instanceof Error ? error.message : "Unknown error";
46
+ return createToolStructuredContent({ error: message });
47
+ }
48
+ };
49
+ export function createTool(server) {
50
+ server.registerTool(TOOL_NAME, {
51
+ description: TOOL_DESCRIPTION,
52
+ inputSchema: TOOL_ARGS,
53
+ outputSchema: OUTPUT_SCHEMA.shape,
54
+ }, TOOL_HANDLER);
55
+ }
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ import { createUuidSchema } from "../types.js";
3
+ import { ISOTimestampFormatDescription } from "../utils/timestampInput.js";
4
+ export const TOOL_ARGS = {
5
+ area: z
6
+ .string()
7
+ .nullable()
8
+ .describe('Filter to events whose entered area matches this, e.g. "back office". Full-text match.'),
9
+ locationUuids: z
10
+ .array(createUuidSchema())
11
+ .nullable()
12
+ .describe("Filter to these Rhombus location UUIDs. Use the location-tool to resolve names to UUIDs."),
13
+ deviceUuids: z
14
+ .array(createUuidSchema())
15
+ .nullable()
16
+ .describe("Filter to these camera UUIDs (the camera that saw the badge event)."),
17
+ cardholderQuery: z
18
+ .string()
19
+ .nullable()
20
+ .describe("Match the cardholder's name (full-text), e.g. a person you are looking for."),
21
+ badgeStatus: z.string().nullable().describe("Filter by badge status, e.g. Active or Lost."),
22
+ badgeType: z.string().nullable().describe("Filter by badge type."),
23
+ anomalyOnly: z
24
+ .boolean()
25
+ .nullable()
26
+ .describe("Only return anomaly events: an inactive/lost badge was used, or access was granted but no entry was made (possible tailgating)."),
27
+ entryMade: z
28
+ .boolean()
29
+ .nullable()
30
+ .describe("Filter by whether access was granted AND entry was actually made."),
31
+ startTime: z
32
+ .string()
33
+ .datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
34
+ .nullable()
35
+ .describe("Only events at or after this time (inclusive). " + ISOTimestampFormatDescription),
36
+ endTime: z
37
+ .string()
38
+ .datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
39
+ .nullable()
40
+ .describe("Only events at or before this time (inclusive). " + ISOTimestampFormatDescription),
41
+ limit: z
42
+ .number()
43
+ .nullable()
44
+ .describe("Maximum number of events to return (default 200; the server caps at 1000)."),
45
+ timeZone: z
46
+ .string()
47
+ .nullable()
48
+ .describe("IANA timezone used to format event times, e.g. America/New_York. Defaults to UTC."),
49
+ };
50
+ const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
51
+ export const OnGuardEventSchema = z.object({
52
+ timestampMs: z.number().optional(),
53
+ datetime: z.string().optional().describe("Human-readable event time in the requested timezone."),
54
+ deviceUuid: z
55
+ .string()
56
+ .optional()
57
+ .describe("The camera that saw this event. Pass to camera-tool (requestType image) or clips-tool (createClip) to get a still/video."),
58
+ label: z.string().optional().describe('Event label, e.g. "OnGuard: Badge Authorized" or an anomaly label.'),
59
+ cardholderName: z.string().optional().describe("The cardholder (person) name."),
60
+ badgeStatus: z.string().optional(),
61
+ badgeType: z.string().optional(),
62
+ areaEntering: z.string().optional(),
63
+ areaExiting: z.string().optional(),
64
+ entryMade: z.boolean().optional(),
65
+ isAnomaly: z.boolean().optional().describe("True if this is an alerting/anomalous event."),
66
+ });
67
+ export const OUTPUT_SCHEMA = z.object({
68
+ events: z.array(OnGuardEventSchema).optional(),
69
+ error: z.string().optional(),
70
+ });
@@ -5855,6 +5855,12 @@ const Camera_GetCustomFootageSeekpointsV2WSRequest = z.object({
5855
5855
  });
5856
5856
  const SeekpointType = z.string();
5857
5857
  const SeekpointIndexType = z.object({
5858
+ alert: z.boolean().optional(),
5859
+ areaEntering: z.string().optional(),
5860
+ areaExiting: z.string().optional(),
5861
+ badgeStatus: z.string().optional(),
5862
+ badgeType: z.string().optional(),
5863
+ entryMade: z.boolean().optional(),
5858
5864
  compositComponentUuid: z.string().optional(),
5859
5865
  customDescription: z.string().optional(),
5860
5866
  customDisplayName: z.string().optional(),
@@ -10818,6 +10824,25 @@ const Eventsearch_GetEventSeekpointsWSResponse = z.object({
10818
10824
  errorMsg: z.string().optional(),
10819
10825
  warningMsg: z.string().optional()
10820
10826
  });
10827
+ const Eventsearch_SearchOnGuardEventsWSRequest = z.object({
10828
+ afterMs: z.number().int().optional(),
10829
+ anomalyOnly: z.boolean().optional(),
10830
+ area: z.string().optional(),
10831
+ badgeStatus: z.string().optional(),
10832
+ badgeType: z.string().optional(),
10833
+ beforeMs: z.number().int().optional(),
10834
+ cardholderQuery: z.string().optional(),
10835
+ deviceUuids: z.array(z.string()).optional(),
10836
+ entryMade: z.boolean().optional(),
10837
+ limit: z.number().int().optional(),
10838
+ locationUuids: z.array(z.string()).optional()
10839
+ });
10840
+ const Eventsearch_SearchOnGuardEventsWSResponse = z.object({
10841
+ error: z.boolean().optional(),
10842
+ errorMsg: z.string().optional(),
10843
+ events: z.array(SeekpointIndexType).optional(),
10844
+ warningMsg: z.string().optional()
10845
+ });
10821
10846
  const Export_ExportAuditEventsWSRequest = z.object({
10822
10847
  endInterval: z.number().int().optional(),
10823
10848
  excludeActions: z.array(z.string()).optional(),
@@ -21985,6 +22010,8 @@ export const schemas = {
21985
22010
  Eventsearch_VideoFootageWSRequest,
21986
22011
  Eventsearch_GetEventSeekpointsWSRequest,
21987
22012
  Eventsearch_GetEventSeekpointsWSResponse,
22013
+ Eventsearch_SearchOnGuardEventsWSRequest,
22014
+ Eventsearch_SearchOnGuardEventsWSResponse,
21988
22015
  Export_ExportAuditEventsWSRequest,
21989
22016
  Export_ExportClimateEventsWSRequest,
21990
22017
  Export_ExportCountReportsWSRequest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rhombus-node-mcp",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "description": "MCP server for Rhombus API",
5
5
  "keywords": [
6
6
  "ai",