rhombus-node-mcp 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +109 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,6 +28,12 @@ async function postApi(url, body) {
|
|
|
28
28
|
try {
|
|
29
29
|
const response = await fetch(url, { method: "POST", headers, body });
|
|
30
30
|
if (!response.ok) {
|
|
31
|
+
if (response.status === 401 || response.status === 403) {
|
|
32
|
+
return {
|
|
33
|
+
error: true,
|
|
34
|
+
status: "Sorry, I don't have permission to help with this request. Consider upgrading my permissions by changing the role of the API Key I am using.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
31
37
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
32
38
|
}
|
|
33
39
|
return await response.json();
|
|
@@ -133,6 +139,41 @@ async function rebootCameras(cameraUuids) {
|
|
|
133
139
|
return { status, successCount, errorCount };
|
|
134
140
|
}
|
|
135
141
|
}
|
|
142
|
+
async function getImageForCameraAtTime(cameraUuid, timestampMs) {
|
|
143
|
+
const url = BASE_URL + "/video/getExactFrameUri";
|
|
144
|
+
const body = JSON.stringify({
|
|
145
|
+
cameraUuid: cameraUuid,
|
|
146
|
+
downscaleFactor: 10,
|
|
147
|
+
jpgQuality: 70,
|
|
148
|
+
permyriadCropHeight: 10000,
|
|
149
|
+
permyriadCropWidth: 5625,
|
|
150
|
+
permyriadCropX: 2188,
|
|
151
|
+
permyriadCropY: 0,
|
|
152
|
+
timestampMs: timestampMs,
|
|
153
|
+
});
|
|
154
|
+
const base64Image = await postApi(url, body).then(async (res) => {
|
|
155
|
+
return await fetch(res.frameUri, { method: "GET", headers: headers }).then(async (res) => {
|
|
156
|
+
if (!res.ok)
|
|
157
|
+
return null;
|
|
158
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
159
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
160
|
+
const base64 = buffer.toString("base64");
|
|
161
|
+
return base64;
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
if (!base64Image) {
|
|
165
|
+
return {
|
|
166
|
+
success: false,
|
|
167
|
+
status: "failed to fetch image",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
success: true,
|
|
172
|
+
status: "successfully fetched image",
|
|
173
|
+
imageType: "base64",
|
|
174
|
+
imageData: base64Image,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
136
177
|
server.tool("get-org-information", "Get general information about the organization including org name, camera configuration defaults, contact information, and org settings.", {}, async ({}) => {
|
|
137
178
|
const org = await getOrg();
|
|
138
179
|
return {
|
|
@@ -144,9 +185,9 @@ server.tool("get-org-information", "Get general information about the organizati
|
|
|
144
185
|
],
|
|
145
186
|
};
|
|
146
187
|
});
|
|
147
|
-
server.tool("get-entity-tool", "get a list of entities like cameras, access controlled doors, sensors, etc.", {
|
|
188
|
+
server.tool("get-entity-tool", "get a list of entities like cameras, access controlled doors, sensors, images from cameras, etc.", {
|
|
148
189
|
entityType: z
|
|
149
|
-
.enum(["camera", "access-controlled-doors"])
|
|
190
|
+
.enum(["camera", "access-controlled-doors", "image-frame"])
|
|
150
191
|
.describe("The entity type to retreive. Example: cameras."),
|
|
151
192
|
}, async ({ entityType }) => {
|
|
152
193
|
let ret;
|
|
@@ -170,6 +211,72 @@ server.tool("get-entity-tool", "get a list of entities like cameras, access cont
|
|
|
170
211
|
],
|
|
171
212
|
};
|
|
172
213
|
});
|
|
214
|
+
server.tool("camera-tool", "get specific requested information about a camera such as an image snapshot, or detailed analytics info", {
|
|
215
|
+
requestType: z.enum(["image"]),
|
|
216
|
+
timestampMs: z.optional(z.number()).describe("the timestamp in milliseconds"),
|
|
217
|
+
cameraUuid: z.optional(z.string()).describe("the camera uuid requested"),
|
|
218
|
+
}, async ({ cameraUuid, timestampMs, requestType }) => {
|
|
219
|
+
if (!cameraUuid) {
|
|
220
|
+
return {
|
|
221
|
+
content: [
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: JSON.stringify({
|
|
225
|
+
needUserInput: true,
|
|
226
|
+
commandForUser: "Which camera are you talking about?",
|
|
227
|
+
}),
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (!timestampMs) {
|
|
233
|
+
return {
|
|
234
|
+
content: [
|
|
235
|
+
{
|
|
236
|
+
type: "text",
|
|
237
|
+
text: JSON.stringify({
|
|
238
|
+
needUserInput: true,
|
|
239
|
+
commandForUser: "At what time?",
|
|
240
|
+
}),
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
let response;
|
|
246
|
+
switch (requestType) {
|
|
247
|
+
case "image":
|
|
248
|
+
response = await getImageForCameraAtTime(cameraUuid, timestampMs);
|
|
249
|
+
if (!response.success || !response.imageData) {
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
content: [
|
|
256
|
+
{
|
|
257
|
+
type: "image",
|
|
258
|
+
data: response.imageData,
|
|
259
|
+
mimeType: "image/jpeg",
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
};
|
|
263
|
+
break;
|
|
264
|
+
default:
|
|
265
|
+
response = {
|
|
266
|
+
error: true,
|
|
267
|
+
status: "mising unknown type from tool call",
|
|
268
|
+
};
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
content: [
|
|
273
|
+
{
|
|
274
|
+
type: "text",
|
|
275
|
+
text: JSON.stringify({ response }),
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
});
|
|
173
280
|
server.tool("events-tool", "event data for certain types of information like faces and license plates", {
|
|
174
281
|
eventType: z.enum(["faces", "people", "access-control"]),
|
|
175
282
|
locationUuid: z.optional(z.string()),
|