rhombus-node-mcp 0.1.21 → 0.1.23
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/README.md +8 -0
- package/dist/api/access-control-tool-api.js +256 -0
- package/dist/api/alarm-monitoring-tool-api.js +65 -0
- package/dist/api/camera-tool-api.js +35 -15
- package/dist/api/camera-uptime-tool-api.js +112 -0
- package/dist/api/clips-tool-api.js +110 -21
- package/dist/api/create-tool-api.js +143 -16
- package/dist/api/door-tool-api.js +66 -0
- package/dist/api/events-tool-api.js +151 -28
- package/dist/api/faces-tool-api.js +118 -91
- package/dist/api/get-entity-tool-api.js +2 -0
- package/dist/api/guest-management-tool-api.js +75 -0
- package/dist/api/location-tool-api.js +48 -1
- package/dist/api/lpr-tool-api.js +26 -0
- package/dist/api/policy-alerts-tool-api.js +54 -0
- package/dist/api/report-tool-api.js +345 -23
- package/dist/api/rules-tool-api.js +78 -0
- package/dist/api/search-tool-api.js +93 -0
- package/dist/api/time-tool-api.js +3 -1
- package/dist/api/update-tool-api.js +204 -0
- package/dist/api/user-access-trail-tool-api.js +45 -0
- package/dist/api/user-audit-tool-api.js +47 -0
- package/dist/api/user-tool-api.js +77 -0
- package/dist/createServer.js +3 -1
- package/dist/filtering-utils.js +298 -0
- package/dist/index.js +0 -9
- package/dist/logger.js +6 -5
- package/dist/network.js +18 -4
- package/dist/tools/access-control-tool.js +97 -0
- package/dist/tools/alarm-monitoring-tool.js +50 -0
- package/dist/tools/analytics-tool.js +383 -0
- package/dist/tools/camera-tool.js +27 -9
- package/dist/tools/camera-uptime-tool.js +50 -0
- package/dist/tools/clips-tool.js +46 -16
- package/dist/tools/door-tool.js +66 -0
- package/dist/tools/events-tool.js +103 -81
- package/dist/tools/faces-tool.js +175 -32
- package/dist/tools/get-entity-tool.js +6 -1
- package/dist/tools/guest-management-tool.js +50 -0
- package/dist/tools/location-tool.js +23 -4
- package/dist/tools/lpr-tool.js +26 -20
- package/dist/tools/policy-alerts-tool.js +34 -4
- package/dist/tools/report-tool.js +183 -46
- package/dist/tools/rules-tool.js +76 -0
- package/dist/tools/search-tool.js +69 -0
- package/dist/tools/update-tool.js +63 -2
- package/dist/tools/user-access-trail-tool.js +64 -0
- package/dist/tools/user-audit-tool.js +53 -0
- package/dist/tools/user-tool.js +55 -0
- package/dist/tools/video-walls-tool.js +41 -0
- package/dist/transports/streamable-http.js +25 -15
- package/dist/types/access-control-tool-types.js +120 -0
- package/dist/types/alarm-monitoring-tool-types.js +60 -0
- package/dist/types/analytics-tool-types.js +190 -0
- package/dist/types/camera-tool-types.js +3 -2
- package/dist/types/camera-uptime-tool-types.js +52 -0
- package/dist/types/clips-tool-types.js +60 -11
- package/dist/types/door-tool-types.js +64 -0
- package/dist/types/events-tools-types.js +71 -3
- package/dist/types/faces-tools-types.js +36 -0
- package/dist/types/guest-management-tool-types.js +57 -0
- package/dist/types/location-tool-types.js +10 -1
- package/dist/types/lpr-tool-types.js +14 -0
- package/dist/types/policy-alerts-tool-types.js +38 -3
- package/dist/types/report-tool-types.js +284 -42
- package/dist/types/rules-tool-types.js +58 -0
- package/dist/types/schema.js +3123 -1
- package/dist/types/search-tool-types.js +82 -0
- package/dist/types/update-tool-types.js +4 -1
- package/dist/types/user-access-trail-tool-types.js +54 -0
- package/dist/types/user-audit-tool-types.js +48 -0
- package/dist/types/user-tool-types.js +61 -0
- package/dist/types/video-walls-tool-types.js +59 -0
- package/dist/types/zod-schemas.js +3237 -986
- package/dist/types.js +0 -21
- package/dist/util.js +34 -57
- package/package.json +7 -5
- package/dist/disabled-tools/semantic-search-tool.js +0 -90
- package/dist/tools/create-tool.js +0 -30
- package/dist/types/create-tool-types.js +0 -8
- package/dist/types/schema-components.js +0 -7211
- package/dist/types/semantic-search-tool-types.js +0 -5
package/dist/types.js
CHANGED
|
@@ -9,24 +9,3 @@ export function createUuidSchema() {
|
|
|
9
9
|
It contains only alphanumeric characters, digits, hyphens, and underscores.`);
|
|
10
10
|
}
|
|
11
11
|
export const UUID = createUuidSchema();
|
|
12
|
-
export const VideoWallSettings = z.object({
|
|
13
|
-
rowCount: z.number(),
|
|
14
|
-
columnCount: z.number(),
|
|
15
|
-
intervalSeconds: z.number().nullable(),
|
|
16
|
-
rotateStrategy: z.enum(["none", "motion", "interval"]),
|
|
17
|
-
});
|
|
18
|
-
export const CreateVideoWallOptions = z
|
|
19
|
-
.object({
|
|
20
|
-
displayName: z.string().nullable().describe("What to call the video wall"),
|
|
21
|
-
orgUuid: z.string().describe("The uuid of the organization"),
|
|
22
|
-
deviceList: z
|
|
23
|
-
.array(z.string())
|
|
24
|
-
.min(1)
|
|
25
|
-
.describe("The list of camera uuids (unique identifiers) to exist in the video wall. You must provide this manually by prompting the user at least once."),
|
|
26
|
-
othersCanEdit: z
|
|
27
|
-
.boolean()
|
|
28
|
-
.nullable()
|
|
29
|
-
.describe("Whether or not other users can edit the wall, defaults to false"),
|
|
30
|
-
settings: VideoWallSettings,
|
|
31
|
-
})
|
|
32
|
-
.nullable();
|
package/dist/util.js
CHANGED
|
@@ -2,6 +2,8 @@ import { z } from "zod";
|
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { DateTime } from "luxon";
|
|
5
|
+
import { filterIncludedFields, applyFilterBy } from "./filtering-utils.js";
|
|
6
|
+
export { INCLUDE_FIELDS_ARG, FILTER_BY_ARG, filterIncludedFields, applyFilterBy, zodToDotNotationPaths, createFilteringProxy } from "./filtering-utils.js";
|
|
5
7
|
export function generateRandomString(length) {
|
|
6
8
|
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
7
9
|
let result = "";
|
|
@@ -24,6 +26,9 @@ export function extractFromToolExtra(_extra) {
|
|
|
24
26
|
sessionId: extra.sessionId,
|
|
25
27
|
};
|
|
26
28
|
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// File utilities
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
27
32
|
/**
|
|
28
33
|
* Get all file paths in a directory in a directory
|
|
29
34
|
*
|
|
@@ -52,6 +57,9 @@ export function getFilePathsInDirectory(dirPath) {
|
|
|
52
57
|
}
|
|
53
58
|
return filePaths;
|
|
54
59
|
}
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Tool content helpers
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
55
63
|
/**
|
|
56
64
|
* Returns an object in the form expected by `server.tool`
|
|
57
65
|
*/
|
|
@@ -66,20 +74,38 @@ export function createToolTextContent(content) {
|
|
|
66
74
|
};
|
|
67
75
|
}
|
|
68
76
|
/**
|
|
69
|
-
* Returns
|
|
70
|
-
*
|
|
77
|
+
* Returns structured content expected by `server.tool`.
|
|
78
|
+
* Optionally applies programmatic field projection (includeFields) and
|
|
79
|
+
* row filtering (filterBy) before serialising.
|
|
80
|
+
*
|
|
81
|
+
* The generic type T allows for type safety. Set T to the output schema of the
|
|
82
|
+
* tool and your content will be type-checked.
|
|
83
|
+
*
|
|
84
|
+
* filterBy is applied first (prune rows), then includeFields (prune columns),
|
|
85
|
+
* which minimises output size optimally.
|
|
71
86
|
*/
|
|
72
|
-
export function createToolStructuredContent(content) {
|
|
87
|
+
export function createToolStructuredContent(content, opts) {
|
|
88
|
+
// biome-ignore lint/suspicious/noExplicitAny: intentional runtime manipulation
|
|
89
|
+
let result = content;
|
|
90
|
+
if (opts?.filterBy?.length) {
|
|
91
|
+
result = applyFilterBy(result, opts.filterBy) ?? result;
|
|
92
|
+
}
|
|
93
|
+
if (opts?.includeFields?.length) {
|
|
94
|
+
result = filterIncludedFields(result, opts.includeFields) ?? result;
|
|
95
|
+
}
|
|
73
96
|
return {
|
|
74
97
|
content: [
|
|
75
98
|
{
|
|
76
99
|
type: "text",
|
|
77
|
-
text: JSON.stringify(
|
|
100
|
+
text: JSON.stringify(result),
|
|
78
101
|
},
|
|
79
102
|
],
|
|
80
|
-
structuredContent:
|
|
103
|
+
structuredContent: result,
|
|
81
104
|
};
|
|
82
105
|
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// removeNullFields
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
83
109
|
/**
|
|
84
110
|
* Recursively removes fields with null values from a JavaScript object.
|
|
85
111
|
* If a nested object becomes empty after removing nulls, it will also be removed.
|
|
@@ -124,58 +150,9 @@ export function removeNullFields(obj) {
|
|
|
124
150
|
}
|
|
125
151
|
return Object.keys(cleanedObject).length > 0 ? cleanedObject : undefined;
|
|
126
152
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
if (Array.isArray(obj)) {
|
|
132
|
-
return obj
|
|
133
|
-
.map(item => filterIncludedFields(item, fieldsToInclude))
|
|
134
|
-
.filter(item => {
|
|
135
|
-
if (item === undefined || item === null) {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
if (Array.isArray(item)) {
|
|
139
|
-
return item.length > 0;
|
|
140
|
-
}
|
|
141
|
-
if (typeof item === "object") {
|
|
142
|
-
return Object.keys(item).length > 0;
|
|
143
|
-
}
|
|
144
|
-
// Keep primitives
|
|
145
|
-
return true;
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
if (typeof obj === "object" && obj !== null) {
|
|
149
|
-
const newObj = {};
|
|
150
|
-
for (const key in obj) {
|
|
151
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
152
|
-
if (fieldsToInclude.includes(key)) {
|
|
153
|
-
newObj[key] = obj[key];
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
const result = filterIncludedFields(obj[key], fieldsToInclude);
|
|
157
|
-
if (result !== undefined && result !== null) {
|
|
158
|
-
if (Array.isArray(result)) {
|
|
159
|
-
if (result.length > 0) {
|
|
160
|
-
newObj[key] = result;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
else if (typeof result === "object") {
|
|
164
|
-
if (Object.keys(result).length > 0) {
|
|
165
|
-
newObj[key] = result;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
newObj[key] = result;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return Object.keys(newObj).length > 0 ? newObj : undefined;
|
|
176
|
-
}
|
|
177
|
-
return undefined;
|
|
178
|
-
}
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// formatTimestamp
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
179
156
|
/**
|
|
180
157
|
* Formats a timestamp in milliseconds to a human-readable date string
|
|
181
158
|
* Format: "February 24, 2025 at 3:23 PM"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rhombus-node-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"description": "MCP server for Rhombus API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
],
|
|
11
11
|
"homepage": "https://modelcontextprotocol.io",
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/
|
|
13
|
+
"url": "https://github.com/RhombusSystems/rhombus-node-mcp/issues"
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/
|
|
17
|
+
"url": "git+https://github.com/RhombusSystems/rhombus-node-mcp.git"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"author": "Model Context Protocol (https://modelcontextprotocol.io)",
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
"build": "rm -rf dist && tsc && chmod +x dist/*.js",
|
|
29
29
|
"docker:build": "docker build -t rhombussystems/mcp-server-rhombus .",
|
|
30
30
|
"start": "node dist/index.js",
|
|
31
|
+
"start:http": "TRANSPORT_TYPE=streamable-http node dist/index.js",
|
|
32
|
+
"start:stdio": "TRANSPORT_TYPE=stdio node dist/index.js",
|
|
31
33
|
"prepare": "npm run build",
|
|
32
34
|
"watch": "npm run clean && tsc --watch",
|
|
33
35
|
"generate-schemas": "npx tsx scripts/generate-zod-schemas.ts",
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
"dist"
|
|
46
48
|
],
|
|
47
49
|
"dependencies": {
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.21.
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.21.2",
|
|
49
51
|
"axios": "^1.11.0",
|
|
50
52
|
"cheerio": "^1.1.2",
|
|
51
53
|
"chrono-node": "^2.8.0",
|
|
@@ -76,4 +78,4 @@
|
|
|
76
78
|
"engines": {
|
|
77
79
|
"node": ">=18"
|
|
78
80
|
}
|
|
79
|
-
}
|
|
81
|
+
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { FaissSearchService } from '../services/faiss-search-service.js';
|
|
2
|
-
import { createToolTextContent } from '../util.js';
|
|
3
|
-
import { logger } from '../logger.js';
|
|
4
|
-
import { TOOL_ARGS } from '../types/semantic-search-tool-types.js';
|
|
5
|
-
// Constants following coding style guidelines
|
|
6
|
-
const DEFAULT_SEARCH_LIMIT = 3;
|
|
7
|
-
const DEFAULT_MIN_SIMILARITY = 0.3;
|
|
8
|
-
const TOOL_NAME = "semantic-search";
|
|
9
|
-
const TOOL_DESCRIPTION = `
|
|
10
|
-
This tool performs semantic search across the Rhombus knowledge base using AI embeddings and vector similarity.
|
|
11
|
-
|
|
12
|
-
It searches through documentation, blog posts, support articles, and other content to find the most relevant
|
|
13
|
-
information based on the meaning of your query, not just keyword matching.
|
|
14
|
-
|
|
15
|
-
The tool returns an array of search results, each containing:
|
|
16
|
-
- sourceTitle: The title of the source document
|
|
17
|
-
- sourceUrl: The URL where the content can be found
|
|
18
|
-
- chunkText: The relevant text snippet that matches your query
|
|
19
|
-
|
|
20
|
-
Use this tool when you need to find information about:
|
|
21
|
-
- Camera features, specifications, or comparisons
|
|
22
|
-
- Installation and setup procedures
|
|
23
|
-
- Technical troubleshooting
|
|
24
|
-
- Product capabilities and benefits
|
|
25
|
-
- Access control and security features
|
|
26
|
-
- Cloud storage and management
|
|
27
|
-
- Any other Rhombus-related topics
|
|
28
|
-
`;
|
|
29
|
-
// Singleton instance for reuse across searches
|
|
30
|
-
let globalSearchService = null;
|
|
31
|
-
let isGlobalServiceInitialized = false;
|
|
32
|
-
async function getSearchService() {
|
|
33
|
-
if (!globalSearchService) {
|
|
34
|
-
globalSearchService = new FaissSearchService();
|
|
35
|
-
}
|
|
36
|
-
if (!isGlobalServiceInitialized) {
|
|
37
|
-
await globalSearchService.loadEmbeddings();
|
|
38
|
-
await globalSearchService.loadIndex();
|
|
39
|
-
isGlobalServiceInitialized = true;
|
|
40
|
-
}
|
|
41
|
-
return globalSearchService;
|
|
42
|
-
}
|
|
43
|
-
const TOOL_HANDLER = async (args, extra) => {
|
|
44
|
-
const { query } = args;
|
|
45
|
-
try {
|
|
46
|
-
if (!query || query.trim().length === 0) {
|
|
47
|
-
return createToolTextContent(JSON.stringify({ error: "Query cannot be empty" }));
|
|
48
|
-
}
|
|
49
|
-
const searchService = await getSearchService();
|
|
50
|
-
const searchOptions = {
|
|
51
|
-
query: query.trim(),
|
|
52
|
-
limit: DEFAULT_SEARCH_LIMIT,
|
|
53
|
-
minSimilarity: DEFAULT_MIN_SIMILARITY,
|
|
54
|
-
urlPattern: undefined,
|
|
55
|
-
};
|
|
56
|
-
const { results, stats } = await searchService.search(searchOptions);
|
|
57
|
-
const searchResults = results.map(result => ({
|
|
58
|
-
sourceTitle: result.sourceTitle,
|
|
59
|
-
sourceUrl: result.sourceUrl,
|
|
60
|
-
chunkText: result.chunkText,
|
|
61
|
-
}));
|
|
62
|
-
logger.info('Semantic search results:', results);
|
|
63
|
-
// Log search statistics for debugging
|
|
64
|
-
logger.info('Semantic search stats:', {
|
|
65
|
-
searchTime: stats.searchTime,
|
|
66
|
-
totalVectors: stats.totalVectors,
|
|
67
|
-
resultsReturned: stats.resultsReturned,
|
|
68
|
-
resultsFiltered: stats.resultsFiltered,
|
|
69
|
-
query: query.trim()
|
|
70
|
-
});
|
|
71
|
-
return createToolTextContent(JSON.stringify(searchResults));
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
return createToolTextContent(JSON.stringify({
|
|
75
|
-
error: `Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
76
|
-
}));
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
export async function createTool(server) {
|
|
80
|
-
try {
|
|
81
|
-
// Verify search service can be initialized and also save it into the cached variable
|
|
82
|
-
await getSearchService();
|
|
83
|
-
server.tool(TOOL_NAME, TOOL_DESCRIPTION, TOOL_ARGS, TOOL_HANDLER);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
logger.error('Failed to initialize semantic search tool:', error);
|
|
87
|
-
logger.error('Make sure you have the index and embeddings files in rhombus-node-mcp/data/embeddings/');
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { requireConfirmation } from "../utils/confirmation.js";
|
|
2
|
-
import { handleCreateVideoWallRequest } from "../api/create-tool-api.js";
|
|
3
|
-
import { TOOL_ARGS } from "../types/create-tool-types.js";
|
|
4
|
-
const TOOL_NAME = "create-tool";
|
|
5
|
-
const TOOL_DESCRIPTION = "Tool for creating many entity types such as video walls.";
|
|
6
|
-
const TOOL_HANDLER = async (args, extra) => {
|
|
7
|
-
const { entityType, videoWallCreateOptions, confirmationId } = args;
|
|
8
|
-
const confirmation = requireConfirmation(confirmationId);
|
|
9
|
-
if (confirmation === true) {
|
|
10
|
-
switch (entityType) {
|
|
11
|
-
case "video-wall":
|
|
12
|
-
return await handleCreateVideoWallRequest(videoWallCreateOptions, extra._meta?.requestModifiers, extra.sessionId);
|
|
13
|
-
default:
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
content: [
|
|
17
|
-
{
|
|
18
|
-
type: "text",
|
|
19
|
-
text: "",
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
return confirmation;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
export function createTool(server) {
|
|
29
|
-
server.tool(TOOL_NAME, TOOL_DESCRIPTION, TOOL_ARGS, TOOL_HANDLER);
|
|
30
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { CreateVideoWallOptions } from "../types.js";
|
|
3
|
-
import { addConfirmationParams } from "../utils/confirmation.js";
|
|
4
|
-
export const TOOL_ARGS = addConfirmationParams({
|
|
5
|
-
entityType: z.enum(["video-wall"]).describe("The entity type to create. Example: video wall."),
|
|
6
|
-
videoWallCreateOptions: CreateVideoWallOptions,
|
|
7
|
-
});
|
|
8
|
-
const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
|