UNPKG

rhombus-node-mcp

Version:
72 lines (69 loc) 4.36 kB
import { searchLicensePlates, searchObjectsByColor, searchObjectsByText, searchMotionGrid, } from "../api/search-tool-api.js"; import { SearchToolRequestType, OUTPUT_SCHEMA, TOOL_ARGS, } from "../types/search-tool-types.js"; import { createToolStructuredContent, createToolTextContent, extractFromToolExtra, } from "../util.js"; const TOOL_NAME = "search-tool"; const TOOL_DESCRIPTION = ` This tool performs visual and data searches across Rhombus camera footage and events. It has the following modes of operation, determined by the "requestType" parameter: - ${SearchToolRequestType.LICENSE_PLATE}: Search for license plate sightings by plate number. Requires query (the plate number or partial match). - ${SearchToolRequestType.OBJECT_BY_COLOR}: Search for objects by color in camera footage. Requires query (color name) and cameraUuid. - ${SearchToolRequestType.OBJECT_BY_TEXT}: Semantic search for objects in footage using a text description. Requires query (text description). - ${SearchToolRequestType.MOTION_SEARCH}: Search for motion events in a camera's field of view. Requires cameraUuid, startTime, and endTime. All search types support optional startTime and endTime to narrow the search window. Use the get-entity-tool with entityType CAMERA to get camera UUIDs. `; const TOOL_HANDLER = async (args, _extra) => { const { requestModifiers, sessionId } = extractFromToolExtra(_extra); try { const startTimeMs = args.startTime ? new Date(args.startTime).getTime() : undefined; const endTimeMs = args.endTime ? new Date(args.endTime).getTime() : undefined; switch (args.requestType) { case SearchToolRequestType.LICENSE_PLATE: { if (!args.query) { return createToolTextContent(JSON.stringify({ error: "query is required for license-plate search." })); } const licensePlateResults = await searchLicensePlates(args.query, startTimeMs, endTimeMs, args.deviceUuids, args.locationUuids, requestModifiers, sessionId); return createToolStructuredContent({ licensePlateResults }); } case SearchToolRequestType.OBJECT_BY_COLOR: { if (!args.query || !args.cameraUuid) { return createToolTextContent(JSON.stringify({ error: "query and cameraUuid are required for object-by-color search." })); } const objectColorResults = await searchObjectsByColor(args.query, args.cameraUuid, startTimeMs, endTimeMs, requestModifiers, sessionId); return createToolStructuredContent({ objectColorResults }); } case SearchToolRequestType.OBJECT_BY_TEXT: { if (!args.query) { return createToolTextContent(JSON.stringify({ error: "query is required for object-by-text search." })); } const textSearchDeviceUuids = args.deviceUuids ?? (args.cameraUuid ? [args.cameraUuid] : null); const objectTextResults = await searchObjectsByText(args.query, startTimeMs, endTimeMs, textSearchDeviceUuids, requestModifiers, sessionId); return createToolStructuredContent({ objectTextResults }); } case SearchToolRequestType.MOTION_SEARCH: { if (!args.cameraUuid || !startTimeMs || !endTimeMs) { return createToolTextContent(JSON.stringify({ error: "cameraUuid, startTime, and endTime are required for motion-search." })); } const motionResults = await searchMotionGrid(args.cameraUuid, startTimeMs, endTimeMs, requestModifiers, sessionId); return createToolStructuredContent({ motionResults }); } } } catch (error) { if (error instanceof Error) { return createToolStructuredContent({ error: error.message }); } return createToolStructuredContent({ error: "Unknown error" }); } return createToolStructuredContent({ error: "Invalid request type" }); }; export function createTool(server) { server.registerTool(TOOL_NAME, { title: "Search", description: TOOL_DESCRIPTION, inputSchema: TOOL_ARGS, outputSchema: OUTPUT_SCHEMA.shape, annotations: { readOnlyHint: true }, }, TOOL_HANDLER); }