@ffschrattenecker/tm1-mcp-server 7.0.1 → 8.0.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/CHANGELOG.md +102 -1
- package/README.md +5 -5
- package/dist/config.js +34 -17
- package/dist/connections.d.ts +18 -1
- package/dist/connections.js +34 -18
- package/dist/http-transport.js +51 -4
- package/dist/lib/callgraph/referenceIndex.js +2 -1
- package/dist/lib/callgraph/rulesLinter.d.ts +0 -19
- package/dist/lib/callgraph/rulesLinter.js +0 -590
- package/dist/lib/callgraph/tiParser.js +10 -5
- package/dist/lib/callgraph/tm1-adapter.d.ts +5 -1
- package/dist/lib/callgraph/tm1-adapter.js +41 -9
- package/dist/lib/callgraph/variableEnv.js +3 -2
- package/dist/lib/cell-address.d.ts +11 -1
- package/dist/lib/cell-address.js +22 -3
- package/dist/lib/complexity/antipatterns.js +3 -1
- package/dist/lib/complexity/comment-classifier.js +2 -1
- package/dist/lib/coordinate-error.js +5 -1
- package/dist/lib/feeders/element-type-cache.js +4 -6
- package/dist/lib/naming/odata-filter.js +2 -1
- package/dist/lib/pro-parser.js +13 -4
- package/dist/lib/safe-regex.d.ts +0 -13
- package/dist/lib/safe-regex.js +40 -13
- package/dist/lib/sample-cells.d.ts +6 -0
- package/dist/lib/sample-cells.js +20 -2
- package/dist/lib/ti-identifier.d.ts +11 -0
- package/dist/lib/ti-identifier.js +11 -0
- package/dist/lib/tm1-name.d.ts +9 -0
- package/dist/lib/tm1-name.js +9 -0
- package/dist/lib/v12-compat/deprecated-ti.js +2 -2
- package/dist/session-manager.d.ts +1 -0
- package/dist/session-manager.js +24 -0
- package/dist/tm1-client/connection/profile.js +2 -4
- package/dist/tm1-client/dispatcher.d.ts +1 -1
- package/dist/tm1-client/dispatcher.js +18 -6
- package/dist/tm1-client/http.d.ts +21 -0
- package/dist/tm1-client/http.js +39 -30
- package/dist/tm1-client/services/cell-service.d.ts +9 -7
- package/dist/tm1-client/services/cell-service.js +54 -25
- package/dist/tm1-client/services/chore-service.js +8 -9
- package/dist/tm1-client/services/cube-service.d.ts +14 -18
- package/dist/tm1-client/services/cube-service.js +51 -45
- package/dist/tm1-client/services/dimension-order.d.ts +13 -0
- package/dist/tm1-client/services/dimension-order.js +42 -0
- package/dist/tm1-client/services/dimension-service.js +4 -6
- package/dist/tm1-client/services/element-service.d.ts +35 -11
- package/dist/tm1-client/services/element-service.js +124 -60
- package/dist/tm1-client/services/file-service.d.ts +42 -6
- package/dist/tm1-client/services/file-service.js +225 -28
- package/dist/tm1-client/services/hierarchy-service.d.ts +19 -9
- package/dist/tm1-client/services/hierarchy-service.js +118 -12
- package/dist/tm1-client/services/monitoring-service.js +2 -5
- package/dist/tm1-client/services/odata-page.d.ts +6 -0
- package/dist/tm1-client/services/odata-page.js +8 -0
- package/dist/tm1-client/services/process-service.d.ts +1 -1
- package/dist/tm1-client/services/process-service.js +26 -26
- package/dist/tm1-client/services/security-service.js +8 -9
- package/dist/tm1-client/services/server-service.js +14 -15
- package/dist/tm1-client/services/subset-service.d.ts +23 -10
- package/dist/tm1-client/services/subset-service.js +82 -26
- package/dist/tm1-client/services/view-service.js +12 -13
- package/dist/tm1-client.js +5 -2
- package/dist/tools/analysis/check-v12-readiness.js +3 -3
- package/dist/tools/celldata/check-feeders.js +6 -6
- package/dist/tools/celldata/check-writable-coords.js +43 -25
- package/dist/tools/celldata/execute-mdx.js +19 -23
- package/dist/tools/celldata/get-cell-value.js +1 -1
- package/dist/tools/celldata/get-view.js +10 -9
- package/dist/tools/celldata/member-ref.d.ts +15 -0
- package/dist/tools/celldata/member-ref.js +67 -0
- package/dist/tools/celldata/sample-cells.js +3 -0
- package/dist/tools/celldata/trace-cell-calculation.js +6 -6
- package/dist/tools/celldata/trace-feeders.js +6 -6
- package/dist/tools/celldata/write-cells.js +62 -12
- package/dist/tools/dimension-management/create-element-attribute.js +1 -1
- package/dist/tools/dimension-management/delete-hierarchy.js +3 -4
- package/dist/tools/dimension-management/get-element-attribute-values.js +7 -2
- package/dist/tools/dimension-management/list-element-attributes.js +1 -1
- package/dist/tools/dimension-management/update-element-attribute-value.js +8 -3
- package/dist/tools/dimension-management/update-element.js +14 -7
- package/dist/tools/fileops/container.d.ts +8 -0
- package/dist/tools/fileops/container.js +11 -0
- package/dist/tools/fileops/delete-file.js +4 -2
- package/dist/tools/fileops/get-file-content.js +45 -7
- package/dist/tools/fileops/list-files.js +5 -2
- package/dist/tools/fileops/search-files.js +4 -1
- package/dist/tools/fileops/upload-file.js +5 -2
- package/dist/tools/format.d.ts +1 -0
- package/dist/tools/format.js +7 -2
- package/dist/tools/index.js +0 -2
- package/dist/tools/model-building/check-cube-rule.js +3 -2
- package/dist/tools/model-building/clear-cube.js +35 -26
- package/dist/tools/model-building/set-cube-rules.js +13 -20
- package/dist/tools/model-building/unload-cube.js +1 -1
- package/dist/tools/operations/get-cube-stats.js +1 -1
- package/dist/tools/operations/get-transaction-log.js +1 -1
- package/dist/tools/operations/list-error-logs.js +27 -2
- package/dist/tools/schemas/items-fileops.d.ts +4 -0
- package/dist/tools/schemas/items-fileops.js +1 -0
- package/dist/tools/security/list-clients.js +5 -5
- package/dist/tools/security/list-groups.js +1 -1
- package/dist/tools/subsets/create-subset.js +9 -5
- package/dist/tools/subsets/delete-subset.js +8 -3
- package/dist/tools/subsets/update-subset.js +9 -9
- package/dist/tools/ti-development/diff-process-with-file.js +4 -29
- package/dist/tools/ti-development/diff-processes.js +9 -0
- package/dist/tools/ti-development/export-process-to-git.js +9 -7
- package/dist/tools/ti-development/export-process-to-pro.js +15 -8
- package/dist/tools/ti-development/import-pro-file.js +10 -21
- package/dist/tools/ti-development/import-process-from-git.js +8 -18
- package/dist/tools/ti-development/install-pro-bundle.js +2 -2
- package/dist/tools/ti-development/upsert-process.js +26 -5
- package/npm-shrinkwrap.json +465 -500
- package/package.json +14 -10
- package/dist/tools/dimension-management/move-element.d.ts +0 -2
- package/dist/tools/dimension-management/move-element.js +0 -28
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
import { TM1Error, TM1ErrorCode } from "../../types.js";
|
|
5
5
|
import { parseProFile } from "../../lib/pro-parser.js";
|
|
6
6
|
import { withToolHint } from "../error-format.js";
|
|
7
|
-
import { IDEMPOTENT_DESTRUCTIVE
|
|
7
|
+
import { IDEMPOTENT_DESTRUCTIVE } from "../annotations.js";
|
|
8
8
|
import { ImportProFileResultSchema } from "../schemas/items.js";
|
|
9
9
|
import { defineTool } from "../define-tool.js";
|
|
10
10
|
import { OVERWRITE_CONFIRM_SCHEMA, requireOverwriteConfirm, } from "../confirm.js";
|
|
@@ -13,7 +13,7 @@ import { backupProcess } from "./process-backup.js";
|
|
|
13
13
|
export const registerImportProFile = defineTool({
|
|
14
14
|
name: "tm1_import_pro_file",
|
|
15
15
|
description: "Parse a TM1 .pro file (Tabs / Parameters / Variables / DataSource) and deploy the process in one call. Provide either filePath (absolute path on the MCP host) or content (the .pro file body as string). Modes: 'create' (fail if exists), 'update' (fail if missing), 'upsert' (default — create or update). A .pro carries an ODBC password only when it came from tm1_export_process_to_pro against a v12 database, which writes it in clear; TM1's own Datadir .pro encodes slot 565 in a form that cannot be replayed over REST, and v11 exports never contain a password at all. Pass dataSourcePassword in every other case.",
|
|
16
|
-
annotations:
|
|
16
|
+
annotations: IDEMPOTENT_DESTRUCTIVE,
|
|
17
17
|
output: ImportProFileResultSchema,
|
|
18
18
|
input: {
|
|
19
19
|
filePath: z
|
|
@@ -108,25 +108,14 @@ export const registerImportProFile = defineTool({
|
|
|
108
108
|
data: parsed.data,
|
|
109
109
|
epilog: parsed.epilog,
|
|
110
110
|
}), `Code update failed after process '${processName}' was ${exists ? "located" : "created"}. PARTIAL APPLY: the process shell exists but tabs are stale/empty. Re-run tm1_import_pro_file with mode=update once root cause fixed, or tm1_delete_process to roll back.`);
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// layout with an empty variable list — patch on either.
|
|
120
|
-
if (exists ||
|
|
121
|
-
parsed.variables.length > 0 ||
|
|
122
|
-
parsed.variablesUIData.length > 0) {
|
|
123
|
-
await withToolHint(tm1Client.processes.updateVariables(processName, parsed.variables, parsed.variablesUIData.length > 0 || parsed.variables.length === 0
|
|
124
|
-
? parsed.variablesUIData
|
|
125
|
-
: undefined), `Variable update failed for '${processName}'. Code+parameters applied but variables missing. tm1_upsert_process with mode=update + variables=[...] to recover.`);
|
|
126
|
-
}
|
|
127
|
-
if (exists || parsed.dataSource.type !== "None") {
|
|
128
|
-
await withToolHint(tm1Client.processes.updateDataSource(processName, parsed.dataSource), `Datasource update failed for '${processName}' (type=${parsed.dataSource.type}). Code+params+vars applied. Verify datasource credentials/path (ASCII file existence, ODBC DSN, view name) and re-run tm1_upsert_process with mode=update + dataSource={...} to recover.`);
|
|
129
|
-
}
|
|
111
|
+
// The file is the whole truth: an empty list or a None source is sent as
|
|
112
|
+
// well, because TM1 applies both (measured on 11.8 and 12.5) and skipping
|
|
113
|
+
// them left the removed parameters, variables and source on the server.
|
|
114
|
+
await withToolHint(tm1Client.processes.updateParameters(processName, parsed.parameters), `Parameter update failed for '${processName}'. Code applied but parameters missing. Inspect parsed parameters and re-run tm1_upsert_process with mode=update + parameters=[...] to recover.`);
|
|
115
|
+
// A file without a column-layout block leaves the server's layout as it
|
|
116
|
+
// is; one that carries it replaces it.
|
|
117
|
+
await withToolHint(tm1Client.processes.updateVariables(processName, parsed.variables, parsed.variablesUIData.length > 0 ? parsed.variablesUIData : undefined), `Variable update failed for '${processName}'. Code+parameters applied but variables missing. tm1_upsert_process with mode=update + variables=[...] to recover.`);
|
|
118
|
+
await withToolHint(tm1Client.processes.updateDataSource(processName, parsed.dataSource), `Datasource update failed for '${processName}' (type=${parsed.dataSource.type}). Code+params+vars applied. Verify datasource credentials/path (ASCII file existence, ODBC DSN, view name) and re-run tm1_upsert_process with mode=update + dataSource={...} to recover.`);
|
|
130
119
|
return {
|
|
131
120
|
content: [
|
|
132
121
|
{
|
|
@@ -148,24 +148,14 @@ export const registerImportProcessFromGit = defineTool({
|
|
|
148
148
|
// The parsed tabs were preflighted above; unplacedBlobContent() made
|
|
149
149
|
// sure they cover this blob exactly, so what was checked is what deploys.
|
|
150
150
|
await withToolHint(tm1Client.processes.updateCodeBlob(processName, ti.replace(/\r?\n/g, "\r\n")), `Code update failed after process '${processName}' was ${exists ? "located" : "created"}. PARTIAL APPLY: shell exists but tabs are stale/empty. Re-run with mode=update once root cause fixed, or tm1_delete_process to roll back.`);
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// layout with an empty variable list — patch on either.
|
|
160
|
-
if (exists ||
|
|
161
|
-
parsed.variables.length > 0 ||
|
|
162
|
-
(parsed.variablesUIData?.length ?? 0) > 0) {
|
|
163
|
-
await withToolHint(tm1Client.processes.updateVariables(processName, parsed.variables, parsed.variablesUIData ??
|
|
164
|
-
(parsed.variables.length === 0 ? [] : undefined)), `Variable update failed for '${processName}'. Code+parameters applied but variables missing. tm1_upsert_process with mode=update + variables=[...] to recover.`);
|
|
165
|
-
}
|
|
166
|
-
if (exists || dataSource.type !== "None") {
|
|
167
|
-
await withToolHint(tm1Client.processes.updateDataSource(processName, dataSource), `Datasource update failed for '${processName}' (type=${dataSource.type}). Code+params+vars applied. For ODBC verify dataSourcePassword/DSN and re-run with mode=update.`);
|
|
168
|
-
}
|
|
151
|
+
// The file is the whole truth: an empty list or a None source is sent as
|
|
152
|
+
// well, because TM1 applies both (measured on 11.8 and 12.5) and skipping
|
|
153
|
+
// them left the removed parameters, variables and source on the server.
|
|
154
|
+
await withToolHint(tm1Client.processes.updateParameters(processName, parsed.parameters), `Parameter update failed for '${processName}'. Code applied but parameters missing. tm1_upsert_process with mode=update + parameters=[...] to recover.`);
|
|
155
|
+
// An export without variablesUIData (older format) leaves the server's
|
|
156
|
+
// column layout as it is; one that carries it replaces it.
|
|
157
|
+
await withToolHint(tm1Client.processes.updateVariables(processName, parsed.variables, parsed.variablesUIData), `Variable update failed for '${processName}'. Code+parameters applied but variables missing. tm1_upsert_process with mode=update + variables=[...] to recover.`);
|
|
158
|
+
await withToolHint(tm1Client.processes.updateDataSource(processName, dataSource), `Datasource update failed for '${processName}' (type=${dataSource.type}). Code+params+vars applied. For ODBC verify dataSourcePassword/DSN and re-run with mode=update.`);
|
|
169
159
|
if (parsed.hasSecurityAccess !== undefined) {
|
|
170
160
|
await withToolHint(tm1Client.processes.updateSecurityAccess(processName, parsed.hasSecurityAccess), `HasSecurityAccess update failed for '${processName}'. Code+params+vars+datasource applied. Re-run with mode=update once root cause fixed.`);
|
|
171
161
|
}
|
|
@@ -5,7 +5,7 @@ import { TM1Error, TM1ErrorCode } from "../../types.js";
|
|
|
5
5
|
import { compileUserRegex } from "../../lib/safe-regex.js";
|
|
6
6
|
import { parseProFile } from "../../lib/pro-parser.js";
|
|
7
7
|
import { resolveLocalPath } from "../local-file.js";
|
|
8
|
-
import { IDEMPOTENT_DESTRUCTIVE
|
|
8
|
+
import { IDEMPOTENT_DESTRUCTIVE } from "../annotations.js";
|
|
9
9
|
import { InstallProBundleResultSchema } from "../schemas/items.js";
|
|
10
10
|
import { defineTool } from "../define-tool.js";
|
|
11
11
|
import { runPreflight } from "./preflight.js";
|
|
@@ -13,7 +13,7 @@ import { backupProcess } from "./process-backup.js";
|
|
|
13
13
|
export const registerInstallProBundle = defineTool({
|
|
14
14
|
name: "tm1_install_pro_bundle",
|
|
15
15
|
description: "Install all .pro files from a directory in one call. Iterates the directory (non-recursive by default), applies tm1_import_pro_file logic per file, and reports per-file outcome. Stops on first failure unless continueOnError=true. Useful for Bedrock or library deployments.",
|
|
16
|
-
annotations:
|
|
16
|
+
annotations: IDEMPOTENT_DESTRUCTIVE,
|
|
17
17
|
output: InstallProBundleResultSchema,
|
|
18
18
|
input: {
|
|
19
19
|
directory: z
|
|
@@ -42,7 +42,14 @@ export const registerUpsertProcess = defineTool({
|
|
|
42
42
|
data: z.string().optional(),
|
|
43
43
|
epilog: z.string().optional(),
|
|
44
44
|
parameters: z.array(parameterSchema).optional(),
|
|
45
|
-
variables: z
|
|
45
|
+
variables: z
|
|
46
|
+
.array(variableSchema)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Replaces the complete variable list; [] removes every variable."),
|
|
49
|
+
variablesUIData: z
|
|
50
|
+
.array(z.string())
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Raw per-column layout (VariablesUIData), one entry per source column including ignored ones, sent verbatim. Take it from tm1_get_process_variables or an export; do not construct entries. Omitted: the server keeps its current layout."),
|
|
46
53
|
dataSource: dataSourceSchema.optional(),
|
|
47
54
|
hasSecurityAccess: z
|
|
48
55
|
.boolean()
|
|
@@ -66,7 +73,7 @@ export const registerUpsertProcess = defineTool({
|
|
|
66
73
|
.default(false)
|
|
67
74
|
.describe("Write nothing. Run the syntax AND reference check on the process as it would be after this call (both reported, neither stops the other) and diff it against the installed version (credentials masked). Needs no confirm and is not one: the real call still needs it. Replaces a separate check_process_code + validate_process_refs + diff before the risk assessment."),
|
|
68
75
|
},
|
|
69
|
-
handler: async ({ processName, prolog, metadata, data, epilog, parameters, variables, dataSource, hasSecurityAccess, mode, preflight, autoCompile, dryRun, confirm, }, tm1Client) => {
|
|
76
|
+
handler: async ({ processName, prolog, metadata, data, epilog, parameters, variables, variablesUIData, dataSource, hasSecurityAccess, mode, preflight, autoCompile, dryRun, confirm, }, tm1Client) => {
|
|
70
77
|
const trail = [];
|
|
71
78
|
const exists = await tm1Client.processes.exists(processName);
|
|
72
79
|
if (mode === "create" && exists) {
|
|
@@ -199,8 +206,21 @@ export const registerUpsertProcess = defineTool({
|
|
|
199
206
|
await tm1Client.processes.updateParameters(processName, parameters);
|
|
200
207
|
trail.push("updateProcessParameters");
|
|
201
208
|
}
|
|
202
|
-
|
|
203
|
-
|
|
209
|
+
let warning;
|
|
210
|
+
if (variables !== undefined || variablesUIData !== undefined) {
|
|
211
|
+
// A Variables PATCH alone leaves the server's VariablesUIData in place
|
|
212
|
+
// (measured on 11.8 and 12.5). When the new variable count no longer
|
|
213
|
+
// matches the kept layout's non-ignored columns, the ignore markers
|
|
214
|
+
// point at the wrong columns — say so rather than guess a layout.
|
|
215
|
+
if (exists && variables !== undefined && variablesUIData === undefined) {
|
|
216
|
+
const layout = await tm1Client.processes.getVariableLayout(processName);
|
|
217
|
+
const kept = layout.variablesUIData?.length ?? 0;
|
|
218
|
+
const used = kept - layout.ignoredColumns.length;
|
|
219
|
+
if (kept > 0 && used !== variables.length) {
|
|
220
|
+
warning = `VariablesUIData left as on the server: it describes ${used} used and ${layout.ignoredColumns.length} ignored column(s), but ${variables.length} variable(s) were written. Pass variablesUIData to replace the column layout.`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
await tm1Client.processes.updateVariables(processName, variables, variablesUIData);
|
|
204
224
|
trail.push("updateProcessVariables");
|
|
205
225
|
}
|
|
206
226
|
if (dataSource !== undefined) {
|
|
@@ -213,7 +233,7 @@ export const registerUpsertProcess = defineTool({
|
|
|
213
233
|
}
|
|
214
234
|
// Process body/parameters/datasource may have changed call sites — drop the
|
|
215
235
|
// 60s callgraph TTL so the next analysis sees fresh references instead of stale graph.
|
|
216
|
-
const { cleared: callgraphEntriesCleared } = invalidateCallgraphCache();
|
|
236
|
+
const { cleared: callgraphEntriesCleared } = invalidateCallgraphCache(tm1Client.connectionId);
|
|
217
237
|
// Read the code back: TM1 stores what REST sent, so a mismatch means the
|
|
218
238
|
// write did not land as sent. Saves the caller a get_process turn.
|
|
219
239
|
const sent = { prolog, metadata, data, epilog };
|
|
@@ -247,6 +267,7 @@ export const registerUpsertProcess = defineTool({
|
|
|
247
267
|
...(backup ? { backup } : {}),
|
|
248
268
|
...(verified !== undefined ? { verified } : {}),
|
|
249
269
|
...(compile !== undefined ? { compile } : {}),
|
|
270
|
+
...(warning !== undefined ? { warning } : {}),
|
|
250
271
|
}, null, 2),
|
|
251
272
|
},
|
|
252
273
|
],
|