@node-i3x/mcp 0.11.2 → 0.12.0
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/cli.js +518 -220
- package/dist/cli.js.map +1 -1
- package/dist/in-process.d.ts +18 -0
- package/dist/in-process.js +280 -0
- package/dist/in-process.js.map +1 -0
- package/dist/index.d.ts +47 -114
- package/dist/index.js +514 -345
- package/dist/index.js.map +1 -1
- package/dist/rest-binding-DPjLoyyg.d.ts +133 -0
- package/package.json +16 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/similarity.ts","../src/bindings/rest-binding.ts","../src/bindings/connector-binding.ts"],"sourcesContent":["/**\n * Computes a normalized similarity score between two strings (0.0 to 1.0)\n * using Levenshtein edit distance and substring matching.\n */\nexport function computeSimilarity(a: string, b: string): number {\n const s1 = a.toLowerCase().trim();\n const s2 = b.toLowerCase().trim();\n\n if (s1 === s2) return 1.0;\n if (!s1 || !s2) return 0.0;\n\n // Exact substring boost\n if (s1.includes(s2) || s2.includes(s1)) {\n const ratio = Math.min(s1.length, s2.length) / Math.max(s1.length, s2.length);\n return Math.max(0.7, ratio);\n }\n\n // Levenshtein distance calculation\n const m = s1.length;\n const n = s2.length;\n const dp: number[] = Array.from({ length: n + 1 }, (_, i) => i);\n\n for (let i = 1; i <= m; i++) {\n let prev = dp[0]!;\n dp[0] = i;\n for (let j = 1; j <= n; j++) {\n const temp = dp[j]!;\n const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;\n dp[j] = Math.min(dp[j]! + 1, dp[j - 1]! + 1, prev + cost);\n prev = temp;\n }\n }\n\n const distance = dp[n]!;\n const maxLen = Math.max(m, n);\n return Math.max(0, 1 - distance / maxLen);\n}\n\n/**\n * Ranks candidate strings by similarity against a target query,\n * returning the top N matches with score >= minScore.\n */\nexport function rankSuggestions(\n query: string,\n candidates: string[],\n topN = 5,\n minScore = 0.4,\n): string[] {\n return candidates\n .map((candidate) => ({\n candidate,\n score: computeSimilarity(query, candidate),\n }))\n .filter((item) => item.score >= minScore)\n .sort((a, b) => b.score - a.score)\n .slice(0, topN)\n .map((item) => item.candidate);\n}\n\n/** Longer queries are not ids or names someone typed: no fuzzy matching (O(n·m) each). */\nexport const MAX_FUZZY_QUERY_LENGTH = 128;\n\n/**\n * computeSimilarity, or 0 without running Levenshtein when the length difference\n * alone keeps the score under `minScore` (distance >= |m - n|) and neither string\n * contains the other.\n */\nfunction boundedSimilarity(query: string, candidate: string, minScore: number): number {\n const q = query.toLowerCase().trim();\n const c = candidate.toLowerCase().trim();\n if (!q || !c) return 0;\n if (q.includes(c) || c.includes(q)) return computeSimilarity(q, c);\n const lengthBound = 1 - Math.abs(q.length - c.length) / Math.max(q.length, c.length);\n return lengthBound < minScore ? 0 : computeSimilarity(q, c);\n}\n\n/**\n * Ranks objects against a query by the better of their elementId and displayName\n * scores: elementIds are often opaque hashes, so names are what users type.\n */\nexport function rankObjectSuggestions(\n query: string,\n objects: ReadonlyArray<{ elementId: string; displayName?: string }>,\n topN = 5,\n minScore = 0.4,\n): Array<{ elementId: string; displayName?: string }> {\n if (query.trim().length > MAX_FUZZY_QUERY_LENGTH) return [];\n return objects\n .map(({ elementId, displayName }) => ({\n elementId,\n displayName,\n score: Math.max(\n boundedSimilarity(query, elementId, minScore),\n displayName ? boundedSimilarity(query, displayName, minScore) : 0,\n ),\n }))\n .filter((item) => item.score >= minScore)\n .sort((a, b) => b.score - a.score)\n .slice(0, topN)\n .map(({ elementId, displayName }) => ({ elementId, displayName }));\n}\n","import type {\n BulkResponse,\n BulkResultItem,\n CurrentValueResult,\n HistoricalValueResult,\n Namespace,\n ObjectInstanceResponse,\n ObjectType,\n RelatedObjectResult,\n RelationshipType,\n ServerInfo,\n SuccessResponse,\n} from '@node-i3x/core';\nimport { MAX_FUZZY_QUERY_LENGTH, rankObjectSuggestions } from '../utils/similarity.js';\nimport type { ElementResult, I3XClientBinding, Suggestion } from './types.js';\n\n/** How long the full object list used for suggestions is reused. */\nconst OBJECT_CACHE_TTL_MS = 60_000;\n\nexport class RestClientBinding implements I3XClientBinding {\n private readonly baseUrl: string;\n private readonly headers: Record<string, string>;\n private readonly requestTimeoutMs: number;\n private readonly fetchImpl?: typeof fetch;\n private readonly token?: string;\n private objectCache?: { at: number; objects: Promise<ObjectInstanceResponse[]> };\n\n /**\n * @param fetchImpl - replaces the global fetch, e.g. to route requests into an\n * in-process server (see InProcessConnectorBinding).\n */\n constructor(\n baseUrl = 'http://localhost:3000',\n token?: string,\n timeoutMs = 15_000,\n fetchImpl?: typeof fetch,\n ) {\n let cleanUrl = baseUrl.trim().replace(/\\/+$/, '');\n if (!cleanUrl.startsWith('http://') && !cleanUrl.startsWith('https://')) {\n cleanUrl = `http://${cleanUrl}`;\n }\n // i3X base URLs are usually given with the /v1 suffix; every path below adds it.\n cleanUrl = cleanUrl.replace(/\\/v1$/i, '');\n this.baseUrl = cleanUrl;\n this.requestTimeoutMs = timeoutMs;\n this.fetchImpl = fetchImpl;\n this.token = token;\n this.headers = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n if (token) {\n this.headers.Authorization = `Bearer ${token}`;\n }\n }\n\n /** Normalized base URL, without a trailing /v1. */\n getBaseUrl(): string {\n return this.baseUrl;\n }\n\n get hasToken(): boolean {\n return Boolean(this.token);\n }\n\n /**\n * A binding to `baseUrl`. Without `token`, the current token is kept when the URL\n * is this binding's own (re-connecting must not silently drop the configured token).\n */\n connectTo(baseUrl: string, token?: string): RestClientBinding {\n // No fetchImpl: a connect targets the network, even from an in-process binding.\n const next = new RestClientBinding(baseUrl, token, this.requestTimeoutMs);\n if (token !== undefined || next.baseUrl !== this.baseUrl || !this.token) return next;\n return new RestClientBinding(baseUrl, this.token, this.requestTimeoutMs);\n }\n\n private async request<T>(path: string, options: RequestInit = {}): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const signal = options.signal || AbortSignal.timeout(this.requestTimeoutMs);\n\n try {\n const response = await (this.fetchImpl ?? fetch)(url, {\n ...options,\n signal,\n headers: {\n ...this.headers,\n ...(options.headers || {}),\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n const truncated =\n errorText.length > 300 ? `${errorText.slice(0, 300)}...` : errorText;\n throw new Error(`HTTP ${response.status} from ${path}: ${truncated}`);\n }\n\n return (await response.json()) as T;\n } catch (err) {\n if ((err as Error).name === 'TimeoutError') {\n throw new Error(\n `i3X Gateway request timed out after ${this.requestTimeoutMs}ms for ${path}`,\n );\n }\n throw err;\n }\n }\n\n /** Unwrap a `{ success, result }` envelope; a `success: false` envelope becomes an error. */\n private async get<T>(path: string): Promise<T> {\n const res = await this.request<Partial<SuccessResponse<T>> & ErrorEnvelope>(path);\n if (res?.success !== true || !('result' in res)) {\n throw new Error(`i3X request ${path} failed: ${describeFailure(res)}`);\n }\n return res.result as T;\n }\n\n /**\n * POST a bulk request and return its `results` items, one per requested elementId.\n * `success` is false on the envelope as soon as one item failed, so items are\n * returned as they are; only a body without `results` is an error here.\n */\n private async postBulk<T>(path: string, body: unknown): Promise<BulkResultItem<T>[]> {\n const res = await this.request<Partial<BulkResponse<T>> & ErrorEnvelope>(path, {\n method: 'POST',\n body: JSON.stringify(body),\n });\n if (!Array.isArray(res?.results)) {\n throw new Error(`i3X request ${path} failed: ${describeFailure(res)}`);\n }\n return res.results;\n }\n\n /** Bulk items as per-element results: a failed item keeps its elementId and error. */\n private async postBulkPerElement<T>(\n path: string,\n elementIds: string[],\n body: Record<string, unknown>,\n ): Promise<ElementResult<T>[]> {\n const items = await this.postBulk<T>(path, { elementIds, ...body });\n return items.map((item, idx) => {\n const elementId = item.elementId ?? elementIds[idx] ?? `element_${idx}`;\n if (!item.success) return { elementId, error: describeFailure(item) };\n // A success without a result would otherwise read as \"no data\" with no warning.\n if (item.result == null) return { elementId, error: 'Server returned no result' };\n return { elementId, result: item.result as T };\n });\n }\n\n /** The single item of a one-element bulk request. */\n private async postBulkOne<T>(\n path: string,\n body: { elementIds: [string] } & Record<string, unknown>,\n ): Promise<BulkResultItem<T>> {\n const [item] = await this.postBulk<T>(path, body);\n if (!item) throw new Error(`i3X request ${path} returned no result`);\n return item;\n }\n\n async getInfo(): Promise<ServerInfo> {\n return this.get<ServerInfo>('/v1/info');\n }\n\n async getNamespaces(): Promise<Namespace[]> {\n return this.get<Namespace[]>('/v1/namespaces');\n }\n\n async getObjectTypes(namespaceUri?: string): Promise<ObjectType[]> {\n const query = namespaceUri ? `?namespaceUri=${encodeURIComponent(namespaceUri)}` : '';\n return this.get<ObjectType[]>(`/v1/objecttypes${query}`);\n }\n\n async getRelationshipTypes(): Promise<RelationshipType[]> {\n return this.get<RelationshipType[]>('/v1/relationshiptypes');\n }\n\n async getObjects(options?: {\n rootOnly?: boolean;\n typeElementId?: string;\n }): Promise<ObjectInstanceResponse[]> {\n const params = new URLSearchParams();\n if (options?.rootOnly) params.set('root', 'true');\n if (options?.typeElementId) params.set('typeElementId', options.typeElementId);\n\n const query = params.toString() ? `?${params.toString()}` : '';\n return this.get<ObjectInstanceResponse[]>(`/v1/objects${query}`);\n }\n\n /** `null` only when the server reports the element as not found (404). */\n async getObjectById(elementId: string): Promise<ObjectInstanceResponse | null> {\n const path = '/v1/objects/list';\n const item = await this.postBulkOne<ObjectInstanceResponse>(path, {\n elementIds: [elementId],\n });\n if (item.success) return item.result ?? null;\n if (item.responseDetail?.status === 404) return null;\n throw new Error(\n `i3X request ${path} failed for '${elementId}': ${describeFailure(item)}`,\n );\n }\n\n async getRelatedObjects(\n elementId: string,\n relationshipType?: string,\n ): Promise<RelatedObjectResult[]> {\n const path = '/v1/objects/related';\n const body: { elementIds: [string] } & Record<string, unknown> = {\n elementIds: [elementId],\n };\n if (relationshipType) body.relationshipType = relationshipType;\n\n const item = await this.postBulkOne<RelatedObjectResult[]>(path, body);\n if (!item.success) {\n throw new Error(\n `i3X request ${path} failed for '${elementId}': ${describeFailure(item)}`,\n );\n }\n // Servers may ignore relationshipType, so filter here as well.\n return (item.result ?? []).filter(\n (r) => !relationshipType || r.sourceRelationship === relationshipType,\n );\n }\n\n async getRelatedObjectsBulk(\n elementIds: string[],\n ): Promise<ElementResult<RelatedObjectResult[]>[]> {\n return this.postBulkPerElement<RelatedObjectResult[]>(\n '/v1/objects/related',\n elementIds,\n {},\n );\n }\n\n async getObjectValues(\n elementIds: string[],\n maxDepth = 1,\n ): Promise<ElementResult<CurrentValueResult>[]> {\n return this.postBulkPerElement<CurrentValueResult>('/v1/objects/value', elementIds, {\n maxDepth,\n });\n }\n\n async getHistoricalValues(\n elementIds: string[],\n startTime: string,\n endTime: string,\n maxDepth = 1,\n ): Promise<ElementResult<HistoricalValueResult>[]> {\n return this.postBulkPerElement<HistoricalValueResult>(\n '/v1/objects/history',\n elementIds,\n { startTime, endTime, maxDepth },\n );\n }\n\n /** Closest objects by elementId or displayName; a failure to list objects propagates. */\n async findSuggestions(query: string): Promise<Suggestion[]> {\n if (query.trim().length > MAX_FUZZY_QUERY_LENGTH) return [];\n const now = Date.now();\n if (!this.objectCache || now - this.objectCache.at > OBJECT_CACHE_TTL_MS) {\n const objects = this.getObjects();\n this.objectCache = { at: now, objects };\n objects.catch(() => {\n if (this.objectCache?.objects === objects) this.objectCache = undefined;\n });\n }\n return rankObjectSuggestions(query, await this.objectCache.objects);\n }\n}\n\ninterface ErrorEnvelope {\n success?: boolean;\n responseDetail?: { title?: string; status?: number; detail?: string } | null;\n}\n\nfunction describeFailure(res: ErrorEnvelope | null | undefined): string {\n const d = res?.responseDetail;\n if (d) return [d.status, d.title, d.detail].filter(Boolean).join(' ');\n return `unexpected response ${JSON.stringify(res)?.slice(0, 200)}`;\n}\n","import type { RestServerDeps } from '@node-i3x/rest-server';\nimport { RestClientBinding } from './rest-binding.js';\n\ntype InjectableApp = Awaited<\n ReturnType<typeof import('@node-i3x/rest-server').createApp>\n>;\n\n/**\n * Binding to an i3X stack running in this process.\n *\n * Requests go through the real rest-server routes (Fastify `inject()`, no socket),\n * so in-process answers are exactly what a remote node-i3x server would send:\n * same parentId, roots, related objects, values and server info.\n */\nexport class InProcessConnectorBinding extends RestClientBinding {\n constructor(deps: RestServerDeps) {\n super('http://in-process', undefined, 15_000, injectFetch(deps));\n }\n}\n\n/** A fetch that answers from an in-process rest-server instead of the network. */\nexport function injectFetch(deps: RestServerDeps): typeof fetch {\n let app: Promise<InjectableApp> | undefined;\n return async (input, init) => {\n // Loaded lazily so the REST-only CLI never pulls in Fastify. No request logging:\n // Fastify logs to stdout, which is the MCP stdio channel.\n app ??= import('@node-i3x/rest-server').then(({ createApp }) =>\n createApp({ ...deps, requireAuth: false }, { logger: false }),\n );\n const url = new URL(String(input));\n const res = await (await app).inject({\n method: (init?.method ?? 'GET') as 'GET' | 'POST',\n url: `${url.pathname}${url.search}`,\n headers: init?.headers as Record<string, string> | undefined,\n payload: typeof init?.body === 'string' ? init.body : undefined,\n });\n return new Response(res.body, {\n status: res.statusCode,\n headers: {\n 'content-type': String(res.headers['content-type'] ?? 'application/json'),\n },\n });\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,106 +1,19 @@
|
|
|
1
|
+
import { I as I3XClientBinding, S as Suggestion, H as HierarchyNode, E as ElementResult } from './rest-binding-DPjLoyyg.js';
|
|
2
|
+
export { A as AssetDiagnosticReport, R as RestClientBinding, T as TelemetrySummary } from './rest-binding-DPjLoyyg.js';
|
|
1
3
|
import * as _node_i3x_core from '@node-i3x/core';
|
|
2
|
-
import { ServerInfo, Namespace, ObjectType, RelationshipType, ObjectInstanceResponse, CurrentValueResult, HistoricalValueResult, I3xStack } from '@node-i3x/core';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
|
|
5
|
-
interface AssetDiagnosticReport {
|
|
6
|
-
elementId: string;
|
|
7
|
-
displayName?: string;
|
|
8
|
-
description?: string;
|
|
9
|
-
typeElementId?: string;
|
|
10
|
-
typeSchema?: Record<string, unknown>;
|
|
11
|
-
parentId?: string;
|
|
12
|
-
subComponents?: Array<{
|
|
13
|
-
elementId: string;
|
|
14
|
-
displayName?: string;
|
|
15
|
-
relationshipType?: string;
|
|
16
|
-
}>;
|
|
17
|
-
currentValues?: Record<string, {
|
|
18
|
-
value: unknown;
|
|
19
|
-
quality: string;
|
|
20
|
-
timestamp: string;
|
|
21
|
-
}>;
|
|
22
|
-
diagnosticTips?: string[];
|
|
23
|
-
}
|
|
24
|
-
interface HierarchyNode {
|
|
25
|
-
elementId: string;
|
|
26
|
-
displayName?: string;
|
|
27
|
-
typeElementId?: string;
|
|
28
|
-
children?: HierarchyNode[];
|
|
29
|
-
}
|
|
30
|
-
interface TelemetrySummary {
|
|
31
|
-
elementId: string;
|
|
32
|
-
values: Array<{
|
|
33
|
-
timestamp: string;
|
|
34
|
-
value: unknown;
|
|
35
|
-
quality: string;
|
|
36
|
-
}>;
|
|
37
|
-
statistics?: {
|
|
38
|
-
min?: number;
|
|
39
|
-
max?: number;
|
|
40
|
-
mean?: number;
|
|
41
|
-
count: number;
|
|
42
|
-
badQualityCount: number;
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
interface I3XClientBinding {
|
|
46
|
-
getInfo(): Promise<ServerInfo>;
|
|
47
|
-
getNamespaces(): Promise<Namespace[]>;
|
|
48
|
-
getObjectTypes(namespaceUri?: string): Promise<ObjectType[]>;
|
|
49
|
-
getRelationshipTypes(): Promise<RelationshipType[]>;
|
|
50
|
-
getObjects(options?: {
|
|
51
|
-
rootOnly?: boolean;
|
|
52
|
-
typeElementId?: string;
|
|
53
|
-
}): Promise<ObjectInstanceResponse[]>;
|
|
54
|
-
getObjectById(elementId: string): Promise<ObjectInstanceResponse | null>;
|
|
55
|
-
getRelatedObjects(elementId: string, relationshipType?: string): Promise<ObjectInstanceResponse[]>;
|
|
56
|
-
getObjectValues(elementIds: string[], maxDepth?: number): Promise<CurrentValueResult[]>;
|
|
57
|
-
getHistoricalValues(elementIds: string[], startTime: string, endTime: string, maxDepth?: number): Promise<HistoricalValueResult[]>;
|
|
58
|
-
findSuggestions(unknownId: string): Promise<string[]>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
declare class InProcessConnectorBinding implements I3XClientBinding {
|
|
62
|
-
private readonly stack;
|
|
63
|
-
constructor(stack: I3xStack);
|
|
64
|
-
getInfo(): Promise<ServerInfo>;
|
|
65
|
-
getNamespaces(): Promise<Namespace[]>;
|
|
66
|
-
getObjectTypes(namespaceUri?: string): Promise<ObjectType[]>;
|
|
67
|
-
getRelationshipTypes(): Promise<RelationshipType[]>;
|
|
68
|
-
getObjects(options?: {
|
|
69
|
-
rootOnly?: boolean;
|
|
70
|
-
typeElementId?: string;
|
|
71
|
-
}): Promise<ObjectInstanceResponse[]>;
|
|
72
|
-
getObjectById(elementId: string): Promise<ObjectInstanceResponse | null>;
|
|
73
|
-
getRelatedObjects(elementId: string): Promise<ObjectInstanceResponse[]>;
|
|
74
|
-
getObjectValues(elementIds: string[], maxDepth?: number): Promise<CurrentValueResult[]>;
|
|
75
|
-
getHistoricalValues(elementIds: string[], startTime: string, endTime: string, maxDepth?: number): Promise<HistoricalValueResult[]>;
|
|
76
|
-
findSuggestions(unknownId: string): Promise<string[]>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
declare class RestClientBinding implements I3XClientBinding {
|
|
80
|
-
private readonly baseUrl;
|
|
81
|
-
private readonly headers;
|
|
82
|
-
private readonly requestTimeoutMs;
|
|
83
|
-
constructor(baseUrl?: string, token?: string, timeoutMs?: number);
|
|
84
|
-
private request;
|
|
85
|
-
getInfo(): Promise<ServerInfo>;
|
|
86
|
-
getNamespaces(): Promise<Namespace[]>;
|
|
87
|
-
getObjectTypes(namespaceUri?: string): Promise<ObjectType[]>;
|
|
88
|
-
getRelationshipTypes(): Promise<RelationshipType[]>;
|
|
89
|
-
getObjects(options?: {
|
|
90
|
-
rootOnly?: boolean;
|
|
91
|
-
typeElementId?: string;
|
|
92
|
-
}): Promise<ObjectInstanceResponse[]>;
|
|
93
|
-
getObjectById(elementId: string): Promise<ObjectInstanceResponse | null>;
|
|
94
|
-
getRelatedObjects(elementId: string, relationshipType?: string): Promise<ObjectInstanceResponse[]>;
|
|
95
|
-
getObjectValues(elementIds: string[], maxDepth?: number): Promise<CurrentValueResult[]>;
|
|
96
|
-
getHistoricalValues(elementIds: string[], startTime: string, endTime: string, maxDepth?: number): Promise<HistoricalValueResult[]>;
|
|
97
|
-
findSuggestions(unknownId: string): Promise<string[]>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
6
|
declare class NodeI3xMcpServer {
|
|
101
7
|
private readonly server;
|
|
102
8
|
private binding;
|
|
103
|
-
|
|
9
|
+
private readonly maxResultChars;
|
|
10
|
+
/**
|
|
11
|
+
* @param options.maxResultChars - cap on a serialized tool result (default
|
|
12
|
+
* I3X_MCP_MAX_RESULT_CHARS, else 100 000 characters).
|
|
13
|
+
*/
|
|
14
|
+
constructor(binding?: I3XClientBinding, options?: {
|
|
15
|
+
maxResultChars?: number;
|
|
16
|
+
});
|
|
104
17
|
setBinding(binding: I3XClientBinding): void;
|
|
105
18
|
getBinding(): I3XClientBinding;
|
|
106
19
|
private setupHandlers;
|
|
@@ -151,17 +64,20 @@ declare function handleDiscoverTypes(binding: I3XClientBinding, args: z.infer<ty
|
|
|
151
64
|
declare const exploreHierarchySchema: z.ZodObject<{
|
|
152
65
|
rootElementId: z.ZodOptional<z.ZodString>;
|
|
153
66
|
maxDepth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
67
|
+
maxNodes: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
154
68
|
}, z.core.$strip>;
|
|
155
69
|
declare function handleExploreHierarchy(binding: I3XClientBinding, args: z.infer<typeof exploreHierarchySchema>): Promise<{
|
|
156
70
|
error: string;
|
|
157
|
-
suggestions:
|
|
158
|
-
totalRoots?: undefined;
|
|
159
|
-
traversalDepth?: undefined;
|
|
160
|
-
plantTopology?: undefined;
|
|
71
|
+
suggestions: Suggestion[];
|
|
161
72
|
} | {
|
|
162
|
-
totalRoots: number;
|
|
163
|
-
traversalDepth: number;
|
|
164
73
|
plantTopology: HierarchyNode[];
|
|
74
|
+
truncated?: {
|
|
75
|
+
maxNodes: number;
|
|
76
|
+
hint: string;
|
|
77
|
+
} | undefined;
|
|
78
|
+
totalRoots: number;
|
|
79
|
+
traversalDepth: string | number;
|
|
80
|
+
nodeCount: number;
|
|
165
81
|
error?: undefined;
|
|
166
82
|
suggestions?: undefined;
|
|
167
83
|
}>;
|
|
@@ -170,34 +86,52 @@ declare const inspectAssetSchema: z.ZodObject<{
|
|
|
170
86
|
elementId: z.ZodString;
|
|
171
87
|
includeValues: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
172
88
|
includeSchema: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
89
|
+
maxDepth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
173
90
|
}, z.core.$strip>;
|
|
174
91
|
declare function handleInspectAsset(binding: I3XClientBinding, args: z.infer<typeof inspectAssetSchema>): Promise<Record<string, unknown>>;
|
|
175
92
|
|
|
176
93
|
declare const monitorEventsSchema: z.ZodObject<{
|
|
177
|
-
elementIds: z.ZodArray<z.ZodString
|
|
178
|
-
|
|
94
|
+
elementIds: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string[], string[]>>;
|
|
95
|
+
maxDepth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
179
96
|
}, z.core.$strip>;
|
|
97
|
+
/**
|
|
98
|
+
* One-shot health snapshot: current values plus every series whose quality is not Good.
|
|
99
|
+
* It does not subscribe: MCP tool calls are request/response, so call it again to re-check.
|
|
100
|
+
*/
|
|
180
101
|
declare function handleMonitorEvents(binding: I3XClientBinding, args: z.infer<typeof monitorEventsSchema>): Promise<{
|
|
102
|
+
snapshot: ElementResult<_node_i3x_core.CurrentValueResult>[];
|
|
103
|
+
note: string;
|
|
104
|
+
alertsOmitted?: number | undefined;
|
|
181
105
|
status: string;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
106
|
+
checkedAt: string;
|
|
107
|
+
summary: {
|
|
108
|
+
bad: number;
|
|
109
|
+
uncertain: number;
|
|
110
|
+
readErrors: number;
|
|
111
|
+
};
|
|
112
|
+
alerts: {
|
|
113
|
+
elementId: string;
|
|
114
|
+
quality?: string;
|
|
115
|
+
error?: string;
|
|
116
|
+
}[];
|
|
186
117
|
}>;
|
|
187
118
|
|
|
188
119
|
declare const queryTelemetrySchema: z.ZodObject<{
|
|
189
|
-
elementIds: z.ZodArray<z.ZodString
|
|
120
|
+
elementIds: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string[], string[]>>;
|
|
190
121
|
mode: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
191
122
|
current: "current";
|
|
192
123
|
history: "history";
|
|
193
124
|
}>>>;
|
|
194
125
|
startTime: z.ZodOptional<z.ZodString>;
|
|
195
126
|
endTime: z.ZodOptional<z.ZodString>;
|
|
127
|
+
maxDepth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
196
128
|
aggregateStats: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
197
129
|
}, z.core.$strip>;
|
|
130
|
+
/** ISO 8601 or relative ('-2h') time to ISO; an unparseable value is an error, not a default. */
|
|
131
|
+
declare function parseTime(input: string | undefined, fallback: Date, name: string): string;
|
|
198
132
|
declare function handleQueryTelemetry(binding: I3XClientBinding, args: z.infer<typeof queryTelemetrySchema>): Promise<{
|
|
199
133
|
mode: string;
|
|
200
|
-
telemetry: _node_i3x_core.CurrentValueResult[];
|
|
134
|
+
telemetry: ElementResult<_node_i3x_core.CurrentValueResult>[];
|
|
201
135
|
timeRange?: undefined;
|
|
202
136
|
history?: undefined;
|
|
203
137
|
telemetryReports?: undefined;
|
|
@@ -207,7 +141,7 @@ declare function handleQueryTelemetry(binding: I3XClientBinding, args: z.infer<t
|
|
|
207
141
|
startTime: string;
|
|
208
142
|
endTime: string;
|
|
209
143
|
};
|
|
210
|
-
history: _node_i3x_core.HistoricalValueResult[];
|
|
144
|
+
history: ElementResult<_node_i3x_core.HistoricalValueResult>[];
|
|
211
145
|
telemetry?: undefined;
|
|
212
146
|
telemetryReports?: undefined;
|
|
213
147
|
} | {
|
|
@@ -221,5 +155,4 @@ declare function handleQueryTelemetry(binding: I3XClientBinding, args: z.infer<t
|
|
|
221
155
|
history?: undefined;
|
|
222
156
|
}>;
|
|
223
157
|
|
|
224
|
-
export {
|
|
225
|
-
export type { AssetDiagnosticReport, HierarchyNode, I3XClientBinding, TelemetrySummary };
|
|
158
|
+
export { ElementResult, HierarchyNode, I3XClientBinding, NodeI3xMcpServer, Suggestion, discoverTypesSchema, exploreHierarchySchema, handleDiscoverTypes, handleExploreHierarchy, handleInspectAsset, handleMonitorEvents, handleQueryTelemetry, inspectAssetSchema, monitorEventsSchema, parseTime, queryTelemetrySchema };
|