@ffschrattenecker/tm1-mcp-server 6.1.1 → 7.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/README.md +23 -5
  3. package/dist/config.d.ts +9 -0
  4. package/dist/config.js +89 -64
  5. package/dist/connections.d.ts +69 -0
  6. package/dist/connections.js +262 -0
  7. package/dist/http-transport.d.ts +2 -2
  8. package/dist/index.js +45 -40
  9. package/dist/lib/callgraph/tm1-adapter.d.ts +4 -1
  10. package/dist/lib/callgraph/tm1-adapter.js +5 -2
  11. package/dist/lib/slim-json-schema.d.ts +8 -0
  12. package/dist/lib/slim-json-schema.js +34 -0
  13. package/dist/lib/strip-comments.js +1 -1
  14. package/dist/lib/tm1-events.d.ts +2 -0
  15. package/dist/prompts/index.js +2 -2
  16. package/dist/resources/index.d.ts +4 -2
  17. package/dist/resources/index.js +93 -53
  18. package/dist/resources/subscriptions.d.ts +2 -1
  19. package/dist/resources/subscriptions.js +16 -7
  20. package/dist/server-instructions.d.ts +3 -0
  21. package/dist/server-instructions.js +12 -0
  22. package/dist/tm1-client/http.d.ts +1 -1
  23. package/dist/tm1-client/http.js +21 -4
  24. package/dist/tm1-client/services/process-service.d.ts +7 -1
  25. package/dist/tm1-client/services/process-service.js +7 -5
  26. package/dist/tm1-client.d.ts +1 -1
  27. package/dist/tm1-client.js +2 -11
  28. package/dist/tools/analysis/audit-naming.js +1 -1
  29. package/dist/tools/analysis/invalidate-callgraph-cache.js +2 -1
  30. package/dist/tools/analysis/trace-data-flow.js +1 -1
  31. package/dist/tools/confirm.js +1 -1
  32. package/dist/tools/define-tool.d.ts +35 -11
  33. package/dist/tools/define-tool.js +51 -4
  34. package/dist/tools/index.d.ts +2 -2
  35. package/dist/tools/index.js +6 -12
  36. package/dist/tools/metadata/list-cubes.js +3 -3
  37. package/dist/tools/metadata/list-processes.js +11 -7
  38. package/dist/tools/model-building/unload-cube.js +1 -1
  39. package/dist/tools/operations/get-audit-log.js +1 -1
  40. package/dist/tools/operations/get-jobs.js +2 -2
  41. package/dist/tools/operations/get-message-log.js +1 -1
  42. package/dist/tools/operations/get-server-state.js +1 -1
  43. package/dist/tools/operations/get-threads.js +2 -2
  44. package/dist/tools/operations/get-transaction-log.js +1 -1
  45. package/dist/tools/operations/list-connections.d.ts +2 -0
  46. package/dist/tools/operations/list-connections.js +35 -0
  47. package/dist/tools/operations/save-data.js +1 -1
  48. package/dist/tools/ti-development/execute-process.js +2 -2
  49. package/dist/tools/ti-development/import-pro-file.js +1 -1
  50. package/dist/tools/ti-development/search-code.js +1 -1
  51. package/dist/tools/ti-development/upsert-process.js +2 -2
  52. package/dist/tools/with-annotations.d.ts +10 -0
  53. package/dist/tools/with-annotations.js +58 -3
  54. package/npm-shrinkwrap.json +2 -2
  55. package/package.json +4 -3
  56. package/dist/tools/ti-development/get-process-code.d.ts +0 -2
  57. package/dist/tools/ti-development/get-process-code.js +0 -100
  58. package/dist/tools/ti-development/get-process-datasource.d.ts +0 -2
  59. package/dist/tools/ti-development/get-process-datasource.js +0 -20
  60. package/dist/tools/ti-development/get-process-parameters.d.ts +0 -2
  61. package/dist/tools/ti-development/get-process-parameters.js +0 -25
  62. package/dist/tools/ti-development/get-process-variables.d.ts +0 -2
  63. package/dist/tools/ti-development/get-process-variables.js +0 -38
@@ -14,19 +14,24 @@
14
14
  // resources/unsubscribe, notifications/resources/updated).
15
15
  import { SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
16
16
  import { tm1Events } from "../lib/tm1-events.js";
17
- // URIs whose contents are sensitive to *any* mutation. The server-state
18
- // resource aggregates counts across cubes/dims/processes/chores/clients —
19
- // almost any non-safe call can change it.
20
- const STATE_SENSITIVE_URIS = new Set(["tm1://server/state"]);
17
+ // The server-state resource aggregates counts across cubes/dims/processes/
18
+ // chores/clients — almost any non-safe call can change it. With several
19
+ // connections there is one such resource per connection; stateUris maps each
20
+ // to the connectionId whose mutations affect it.
21
+ const SINGLE_STATE_URIS = new Map([
22
+ ["tm1://server/state", ""],
23
+ ]);
21
24
  export class SubscriptionRegistry {
22
25
  server;
23
26
  logger;
27
+ stateUris;
24
28
  // URIs the client has asked us to push updates for.
25
29
  subscribed = new Set();
26
30
  mutationListener;
27
- constructor(server, logger) {
31
+ constructor(server, logger, stateUris = SINGLE_STATE_URIS) {
28
32
  this.server = server;
29
33
  this.logger = logger;
34
+ this.stateUris = stateUris;
30
35
  }
31
36
  /** Install subscribe/unsubscribe request handlers + mutation listener. */
32
37
  install() {
@@ -62,13 +67,17 @@ export class SubscriptionRegistry {
62
67
  size() {
63
68
  return this.subscribed.size;
64
69
  }
65
- onMutation(_e) {
70
+ onMutation(e) {
66
71
  // Iterate subscribed URIs and notify those affected by this mutation.
67
72
  // Currently only the aggregate state resource is mutation-sensitive;
68
73
  // future entries can branch on e.path / e.method for finer-grained
69
74
  // notifications (e.g. tm1://process/{name}/code on /Processes mutations).
70
75
  for (const uri of this.subscribed) {
71
- if (!STATE_SENSITIVE_URIS.has(uri))
76
+ const target = this.stateUris.get(uri);
77
+ if (target === undefined)
78
+ continue;
79
+ // An empty target or an untagged event matches any connection.
80
+ if (target && e.connectionId && target !== e.connectionId)
72
81
  continue;
73
82
  // Fire-and-forget; missing transport (server not connected) throws.
74
83
  this.server.server.sendResourceUpdated({ uri }).catch((err) => {
@@ -0,0 +1,3 @@
1
+ import type { ConnectionRegistry } from "./connections.js";
2
+ export declare function serverInstructions(registry: ConnectionRegistry): string;
3
+ //# sourceMappingURL=server-instructions.d.ts.map
@@ -0,0 +1,12 @@
1
+ // Sent once per session (MCP `instructions`), so every sentence here is paid
2
+ // for by every conversation — keep it to what a model cannot infer from the
3
+ // tool list itself.
4
+ export function serverInstructions(registry) {
5
+ const lines = ["TM1 / IBM Planning Analytics server."];
6
+ if (!registry.isSingle) {
7
+ lines.push("Every tool except tm1_list_connections takes a `connection`; if the target is unclear, call tm1_list_connections and ask. Never write to a connection the user did not name.");
8
+ }
9
+ lines.push("Keep results small: filter by name, use projections (fields, include* flags, compact) and countOnly before paging.");
10
+ return lines.join(" ");
11
+ }
12
+ //# sourceMappingURL=server-instructions.js.map
@@ -1,5 +1,5 @@
1
1
  import type pino from "pino";
2
- import type { TM1Config } from "../config.js";
2
+ import { type TM1Config } from "../config.js";
3
3
  import type { SessionManager } from "../session-manager.js";
4
4
  import { TM1Error } from "../types.js";
5
5
  export interface RequestOptions {
@@ -1,3 +1,4 @@
1
+ import { connectionIdOf } from "../config.js";
1
2
  import { createConnectionProfile, } from "./connection/profile.js";
2
3
  import { TM1Error, TM1ErrorCode } from "../types.js";
3
4
  import { PRODUCT, VERSION } from "../version.js";
@@ -110,13 +111,21 @@ export class TM1HttpClient {
110
111
  }
111
112
  const retryResult = await this.handleResponse(retryResponse, path);
112
113
  if (!isSafeMethod) {
113
- tm1Events.emit("mutation", { method, path });
114
+ tm1Events.emit("mutation", {
115
+ method,
116
+ path,
117
+ connectionId: connectionIdOf(this.config),
118
+ });
114
119
  }
115
120
  return retryResult;
116
121
  }
117
122
  const result = await this.handleResponse(response, path);
118
123
  if (!isSafeMethod) {
119
- tm1Events.emit("mutation", { method, path });
124
+ tm1Events.emit("mutation", {
125
+ method,
126
+ path,
127
+ connectionId: connectionIdOf(this.config),
128
+ });
120
129
  }
121
130
  return result;
122
131
  }
@@ -191,7 +200,11 @@ export class TM1HttpClient {
191
200
  }
192
201
  const text = await response.text();
193
202
  if (!isSafeHttpMethod(method)) {
194
- tm1Events.emit("mutation", { method, path });
203
+ tm1Events.emit("mutation", {
204
+ method,
205
+ path,
206
+ connectionId: connectionIdOf(this.config),
207
+ });
195
208
  }
196
209
  return text;
197
210
  }
@@ -225,7 +238,11 @@ export class TM1HttpClient {
225
238
  throw this.classifyHttpError(response.status, path, errBody || undefined);
226
239
  }
227
240
  if (!isSafeHttpMethod(method)) {
228
- tm1Events.emit("mutation", { method, path });
241
+ tm1Events.emit("mutation", {
242
+ method,
243
+ path,
244
+ connectionId: connectionIdOf(this.config),
245
+ });
229
246
  }
230
247
  }
231
248
  /**
@@ -12,6 +12,12 @@ export interface ProcessVariableLayout {
12
12
  export interface ProcessListOpts extends NameFilterOpts {
13
13
  /** Set to slice server-side. Only legal when every active filter is in NameFilterOpts. */
14
14
  page?: PageOpts;
15
+ /**
16
+ * Select Name only; every process comes back with `parameters: []`. TM1
17
+ * then serializes no parameter blocks at all — for callers that only need
18
+ * names (counts, existence checks, listings) this is the cheap query.
19
+ */
20
+ namesOnly?: boolean;
15
21
  }
16
22
  export declare class ProcessService {
17
23
  private readonly http;
@@ -29,7 +35,7 @@ export declare class ProcessService {
29
35
  * Name-only when v11 rejects the inline Parameters select.
30
36
  * GET /api/v1/Processes?$select=Name,Parameters
31
37
  */
32
- list(): Promise<Process[]>;
38
+ list(opts?: Pick<ProcessListOpts, "namesOnly">): Promise<Process[]>;
33
39
  /**
34
40
  * Paged variant: with `page` set the slice happens server-side
35
41
  * (`$orderby=Name&$top&$skip&$count=true`) and the return carries the
@@ -85,6 +85,12 @@ export class ProcessService {
85
85
  // — TM1 v11 rejects $expand=Parameters with a syntax error. Use $select
86
86
  // instead, which returns Parameters inline. Param.Type comes back as the
87
87
  // already-decoded string "Numeric" / "String" (not the legacy int code).
88
+ const namesOnly = async () => {
89
+ const response = await this.http.request("GET", `/api/v1/Processes?$select=Name${query}`);
90
+ return wrap(response.value.map((p) => ({ name: p.Name, parameters: [] })), readCount(response));
91
+ };
92
+ if (opts.namesOnly)
93
+ return namesOnly();
88
94
  try {
89
95
  const response = await this.http.request("GET", `/api/v1/Processes?$select=Name,Parameters${query}`);
90
96
  return wrap(response.value.map((p) => ({
@@ -99,11 +105,7 @@ export class ProcessService {
99
105
  }
100
106
  catch (e) {
101
107
  rethrowIfSystemic(e);
102
- const response = await this.http.request("GET", `/api/v1/Processes?$select=Name${query}`);
103
- return wrap(response.value.map((p) => ({
104
- name: p.Name,
105
- parameters: [],
106
- })), readCount(response));
108
+ return namesOnly();
107
109
  }
108
110
  }
109
111
  /**
@@ -1,5 +1,5 @@
1
1
  import type pino from "pino";
2
- import type { TM1Config } from "./config.js";
2
+ import { type TM1Config } from "./config.js";
3
3
  import type { SessionManager } from "./session-manager.js";
4
4
  import { BatchService } from "./tm1-client/services/batch-service.js";
5
5
  import { CubeService } from "./tm1-client/services/cube-service.js";
@@ -1,3 +1,4 @@
1
+ import { connectionIdOf } from "./config.js";
1
2
  import { TM1HttpClient } from "./tm1-client/http.js";
2
3
  import { BatchService } from "./tm1-client/services/batch-service.js";
3
4
  import { CubeService } from "./tm1-client/services/cube-service.js";
@@ -95,17 +96,7 @@ export class TM1Client {
95
96
  * process backups) apart: host and port, plus the v12 instance/database.
96
97
  */
97
98
  get connectionId() {
98
- let host;
99
- try {
100
- const url = new URL(this.config.baseUrl);
101
- host = url.port ? `${url.hostname}_${url.port}` : url.hostname;
102
- }
103
- catch {
104
- host = this.config.baseUrl;
105
- }
106
- return [host, this.config.instance, this.config.database]
107
- .filter((part) => Boolean(part))
108
- .join("_");
99
+ return connectionIdOf(this.config);
109
100
  }
110
101
  /**
111
102
  * Authenticate and start the keep-alive timer.
@@ -240,7 +240,7 @@ export const registerAuditNaming = defineTool({
240
240
  // ── Processes + (optional) variables ───────────────────────────────
241
241
  let processNames = [];
242
242
  if (want("processes") || want("processVariables")) {
243
- const procs = await tm1Client.processes.list();
243
+ const procs = await tm1Client.processes.list({ namesOnly: true });
244
244
  processNames = (includeControl ? procs : procs.filter((p) => !isControlName(p.name))).map((p) => p.name);
245
245
  }
246
246
  if (want("processes")) {
@@ -7,8 +7,9 @@ export const registerInvalidateCallgraphCache = defineTool({
7
7
  description: "Drop the in-memory ReferenceIndex cache used by tm1_analyze_callgraph / tm1_analyze_object_usage / tm1_analyze_chore_graph. Rarely needed: every successful mutating call through this server already drops it. Use it only after changes made outside this server (Workspace, TI, another client). The next analysis call rebuilds the index (single bulk fetch). Touches no TM1 object, so it is available in readonly mode.",
8
8
  annotations: READ_ONLY,
9
9
  output: InvalidateCallgraphCacheResultSchema,
10
- // Takes no arguments: the cache is process-wide.
10
+ // Takes no arguments and no connection: the cache is process-wide.
11
11
  input: {},
12
+ connectionless: true,
12
13
  handler: () => {
13
14
  try {
14
15
  const before = getCallgraphCacheStats();
@@ -13,7 +13,7 @@ const FLOW_MAX_ITEMS = 500;
13
13
  export const registerTraceDataFlow = defineTool({
14
14
  name: "tm1_trace_data_flow",
15
15
  description: [
16
- "Trace data flow into and out of a cube in one call, instead of analyze_object_usage + N× get_process_code.",
16
+ "Trace data flow into and out of a cube in one call, instead of analyze_object_usage + N× get_process.",
17
17
  "downstream: processes that READ the cube and which cubes they WRITE to (where the data flows next).",
18
18
  "upstream: processes that WRITE the cube and where they SOURCE data (read cubes + datasource).",
19
19
  "Combines code-level CellGet/CellPut/DB access with each process's datasource, so view-sourced reads",
@@ -27,7 +27,7 @@ import { TM1Error, TM1ErrorCode } from "../types.js";
27
27
  export const CONFIRM_SCHEMA = {
28
28
  confirm: z
29
29
  .string()
30
- .describe("Safety check: repeat the target identifier verbatim (e.g. cube/dimension/process name) to confirm this irreversible action. Mismatched values reject the call."),
30
+ .describe("Repeat the target name verbatim to confirm this irreversible action; a mismatch rejects the call."),
31
31
  };
32
32
  // For a destructive tool with a dryRun: a dry run needs no confirm, so the
33
33
  // field is optional in the schema and required at runtime on the real call.
@@ -1,10 +1,18 @@
1
1
  import type { McpServer, ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { ZodObject, ZodRawShape, ZodTypeAny } from "zod";
2
+ import { type ZodObject, type ZodRawShape, type ZodTypeAny } from "zod";
3
3
  import type { TM1Client } from "../tm1-client.js";
4
+ import { ConnectionRegistry } from "../connections.js";
4
5
  import type { Tm1ToolAnnotations } from "./annotations.js";
6
+ /**
7
+ * Where a tool gets its client from: the multi-connection registry in
8
+ * production, or one prebuilt client (unit tests, embedders), which is wrapped
9
+ * as a single-connection registry.
10
+ */
11
+ export type ClientSource = TM1Client | ConnectionRegistry;
5
12
  /** Registrar shape expected by the REGISTRARS array in ./index.ts. */
6
- export type ToolRegistrar = (server: McpServer, tm1Client: TM1Client) => void;
7
- export interface ToolSpec<I extends ZodRawShape> {
13
+ export type ToolRegistrar = (server: McpServer, source: ClientSource) => void;
14
+ export declare function asRegistry(source: ClientSource): ConnectionRegistry;
15
+ interface ToolSpecBase<I extends ZodRawShape> {
8
16
  /** Wire name, `tm1_*`. */
9
17
  name: string;
10
18
  /**
@@ -24,19 +32,34 @@ export interface ToolSpec<I extends ZodRawShape> {
24
32
  /** MCP behavior hints — one of the presets in ./annotations.js. */
25
33
  annotations: Tm1ToolAnnotations;
26
34
  /**
27
- * Registration gate for tools that exist on one TM1 generation only (v11
28
- * threads vs v12 jobs, v11-only save_data). Returning false skips the tool
29
- * entirely — it never appears in tools/list. This is deliberately separate
30
- * from the `requiresVersion` annotation, which is a client-facing HINT and
31
- * is also carried by tools that stay registered on both generations.
35
+ * Gate for tools that exist on one TM1 generation only (v11 threads vs v12
36
+ * jobs, v11-only save_data). The tool is registered only when at least one
37
+ * connection runs that version, and a call against a connection on the other
38
+ * version is refused. This is deliberately separate from the
39
+ * `requiresVersion` annotation, which is a client-facing HINT and is also
40
+ * carried by tools that stay registered on both generations.
32
41
  */
33
- enabled?: (tm1Client: TM1Client) => boolean;
42
+ version?: 11 | 12;
43
+ }
44
+ /** A tool that acts on one TM1 connection — every tool but a handful. */
45
+ interface ConnectionToolSpec<I extends ZodRawShape> extends ToolSpecBase<I> {
46
+ connectionless?: false;
34
47
  /**
35
- * Handler. Receives the parsed args, the shared TM1 client, and the SDK's
36
- * per-call extra (abort signal, request metadata).
48
+ * Handler. Receives the parsed args, the client of the connection the call
49
+ * targets, and the SDK's per-call extra (abort signal, request metadata).
37
50
  */
38
51
  handler: (args: Parameters<ToolCallback<I>>[0], tm1Client: TM1Client, extra: Parameters<ToolCallback<I>>[1]) => ReturnType<ToolCallback<I>>;
39
52
  }
53
+ /**
54
+ * A tool about the connections themselves (tm1_list_connections): it takes no
55
+ * `connection` argument and gets the registry instead of a client, so calling
56
+ * it never logs in anywhere.
57
+ */
58
+ interface ConnectionlessToolSpec<I extends ZodRawShape> extends ToolSpecBase<I> {
59
+ connectionless: true;
60
+ handler: (args: Parameters<ToolCallback<I>>[0], registry: ConnectionRegistry, extra: Parameters<ToolCallback<I>>[1]) => ReturnType<ToolCallback<I>>;
61
+ }
62
+ export type ToolSpec<I extends ZodRawShape> = ConnectionToolSpec<I> | ConnectionlessToolSpec<I>;
40
63
  /** What ./with-annotations.ts needs at registration time. */
41
64
  export interface ResolvedSpec {
42
65
  name: string;
@@ -48,4 +71,5 @@ export declare function specFor(name: string): ResolvedSpec | undefined;
48
71
  /** Every spec defined so far. Used by the lint gates and by tests. */
49
72
  export declare function allSpecs(): ReadonlyMap<string, ResolvedSpec>;
50
73
  export declare function defineTool<I extends ZodRawShape>(spec: ToolSpec<I>): ToolRegistrar;
74
+ export {};
51
75
  //# sourceMappingURL=define-tool.d.ts.map
@@ -1,5 +1,13 @@
1
+ import { z } from "zod";
2
+ import { ConnectionRegistry } from "../connections.js";
3
+ import { TM1Error, TM1ErrorCode } from "../types.js";
1
4
  import { asOutputSchema } from "./schemas/output-schema.js";
2
5
  import { markdownCapable } from "./schemas/markdown-capable.js";
6
+ export function asRegistry(source) {
7
+ return source instanceof ConnectionRegistry
8
+ ? source
9
+ : ConnectionRegistry.single(source);
10
+ }
3
11
  // Populated at module-load time, when a tool file's top-level defineTool()
4
12
  // call runs. That is strictly before registerAllTools() executes, because the
5
13
  // import graph resolves first — so the Proxy always finds the spec.
@@ -36,14 +44,53 @@ export function defineTool(spec) {
36
44
  // `outputSchema: undefined` for an optional property.
37
45
  ...(outputSchema === undefined ? {} : { outputSchema }),
38
46
  });
39
- return (server, tm1Client) => {
40
- if (spec.enabled && !spec.enabled(tm1Client))
47
+ return (server, source) => {
48
+ const registry = asRegistry(source);
49
+ if (spec.connectionless) {
50
+ const handler = spec.handler;
51
+ const cb = ((args, extra) => handler(args, registry, extra));
52
+ server.tool(spec.name, description, spec.input, cb);
53
+ return;
54
+ }
55
+ const handler = spec.handler;
56
+ if (spec.version !== undefined && !registry.hasVersion(spec.version)) {
41
57
  return;
58
+ }
59
+ // One connection: the input shape is exactly what the tool declares. More
60
+ // than one: every tool takes a `connection` naming the target.
61
+ const input = registry.isSingle
62
+ ? spec.input
63
+ : {
64
+ ...spec.input,
65
+ connection: z
66
+ .enum(registry.usableNames)
67
+ .describe("Target TM1 connection."),
68
+ };
42
69
  // ToolCallback<I> is a conditional type over an unresolved generic, so TS
43
70
  // cannot check the lambda against it — the cast asserts what the
44
71
  // ToolSpec.handler signature already pins down (same args, same return).
45
- const cb = ((args, extra) => spec.handler(args, tm1Client, extra));
46
- server.tool(spec.name, description, spec.input, cb);
72
+ const cb = (async (args, extra) => {
73
+ const { connection, ...rest } = args;
74
+ const info = registry.resolveInfo(connection);
75
+ if (!spec.annotations.readOnlyHint && info.mode === "readonly") {
76
+ throw new TM1Error({
77
+ code: TM1ErrorCode.PERMISSION_DENIED,
78
+ message: `${spec.name} changes TM1, but connection "${info.name}" is readonly.`,
79
+ hint: info.modeReason ??
80
+ "Set TM1_MODE=readwrite in that connection's .env to allow writes.",
81
+ });
82
+ }
83
+ if (spec.version !== undefined && info.version !== spec.version) {
84
+ throw new TM1Error({
85
+ code: TM1ErrorCode.UNSUPPORTED_OPERATION,
86
+ message: `${spec.name} needs TM1 v${spec.version}; connection "${info.name}" is v${info.version}.`,
87
+ hint: `Pick a v${spec.version} connection, or use the v${info.version} equivalent.`,
88
+ });
89
+ }
90
+ const tm1Client = await registry.get(connection);
91
+ return handler(rest, tm1Client, extra);
92
+ });
93
+ server.tool(spec.name, description, input, cb);
47
94
  };
48
95
  }
49
96
  //# sourceMappingURL=define-tool.js.map
@@ -1,4 +1,4 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { TM1Client } from "../tm1-client.js";
3
- export declare function registerAllTools(server: McpServer, tm1Client: TM1Client): void;
2
+ import type { ClientSource } from "./define-tool.js";
3
+ export declare function registerAllTools(server: McpServer, source: ClientSource): void;
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -20,11 +20,7 @@ import { registerTraceFeeders } from "./celldata/trace-feeders.js";
20
20
  import { registerTraceCellCalculation } from "./celldata/trace-cell-calculation.js";
21
21
  // TI development tools (process CRUD, execution, code, params, datasource)
22
22
  import { registerExecuteProcess } from "./ti-development/execute-process.js";
23
- import { registerGetProcessParameters } from "./ti-development/get-process-parameters.js";
24
- import { registerGetProcessCode } from "./ti-development/get-process-code.js";
25
23
  import { registerGetProcess } from "./ti-development/get-process.js";
26
- import { registerGetProcessDatasource } from "./ti-development/get-process-datasource.js";
27
- import { registerGetProcessVariables } from "./ti-development/get-process-variables.js";
28
24
  import { registerDeleteProcess } from "./ti-development/delete-process.js";
29
25
  import { registerCopyProcess } from "./ti-development/copy-process.js";
30
26
  import { registerCompileProcess } from "./ti-development/compile-process.js";
@@ -84,6 +80,7 @@ import { registerCreateChore } from "./scheduling/create-chore.js";
84
80
  import { registerUpdateChore } from "./scheduling/update-chore.js";
85
81
  import { registerDeleteChore } from "./scheduling/delete-chore.js";
86
82
  // Operations tools
83
+ import { registerListConnections } from "./operations/list-connections.js";
87
84
  import { registerGetMessageLog } from "./operations/get-message-log.js";
88
85
  import { registerGetThreads } from "./operations/get-threads.js";
89
86
  import { registerGetJobs } from "./operations/get-jobs.js";
@@ -150,14 +147,10 @@ const REGISTRARS = [
150
147
  registerTraceFeeders,
151
148
  registerTraceCellCalculation,
152
149
  registerCheckWritableCoords,
153
- // TI development — writes go through registerUpsertProcess (bundled),
154
- // reads remain atomic for inspection without pulling full process code.
150
+ // TI development — writes go through registerUpsertProcess and reads
151
+ // through registerGetProcess (include-flags pick the parts).
155
152
  registerExecuteProcess,
156
- registerGetProcessParameters,
157
- registerGetProcessCode,
158
153
  registerGetProcess,
159
- registerGetProcessDatasource,
160
- registerGetProcessVariables,
161
154
  registerDeleteProcess,
162
155
  registerCopyProcess,
163
156
  registerCompileProcess,
@@ -216,6 +209,7 @@ const REGISTRARS = [
216
209
  registerUpdateChore,
217
210
  registerDeleteChore,
218
211
  // Operations
212
+ registerListConnections,
219
213
  registerGetMessageLog,
220
214
  registerGetThreads,
221
215
  registerGetJobs,
@@ -256,8 +250,8 @@ const REGISTRARS = [
256
250
  registerAssignClientGroup,
257
251
  registerRemoveClientGroup,
258
252
  ];
259
- export function registerAllTools(server, tm1Client) {
253
+ export function registerAllTools(server, source) {
260
254
  for (const register of REGISTRARS)
261
- register(server, tm1Client);
255
+ register(server, source);
262
256
  }
263
257
  //# sourceMappingURL=index.js.map
@@ -11,7 +11,7 @@ export const registerListCubes = defineTool({
11
11
  name: "tm1_list_cubes",
12
12
  description: [
13
13
  "List cubes in the TM1 server. Control cubes ('}'-prefixed) excluded unless includeControl=true.",
14
- "Combinable name filters (nameExact/nameContains/nameRegex) and projection toggles (includeDimensions, includeRules) trim payload on wide models.",
14
+ "Returns names; includeDimensions / includeRules add each cube's dimensions[] / hasRules. Combinable name filters: nameExact/nameContains/nameRegex.",
15
15
  "Paginated (default 50/page).",
16
16
  ],
17
17
  annotations: READ_ONLY,
@@ -27,8 +27,8 @@ export const registerListCubes = defineTool({
27
27
  includeDimensions: z
28
28
  .boolean()
29
29
  .optional()
30
- .default(true)
31
- .describe("Include the dimensions[] array per cube (default: true). Set false for compact output on wide cubes."),
30
+ .default(false)
31
+ .describe("Include the dimensions[] array per cube."),
32
32
  includeRules: z
33
33
  .boolean()
34
34
  .optional()
@@ -10,8 +10,8 @@ import { pageShapeFor } from "../schemas/common.js";
10
10
  export const registerListProcesses = defineTool({
11
11
  name: "tm1_list_processes",
12
12
  description: [
13
- "List TurboIntegrator processes (with parameters) in the TM1 server. Control processes ('}'-prefixed) excluded unless includeControl=true.",
14
- "Name filters (nameContains/nameRegex/nameNotContains/excludePattern) and fields=['name'] projection trim payload on large models.",
13
+ "List TurboIntegrator process names in the TM1 server; fields=['name','parameters'] adds each process's parameters. Control processes ('}'-prefixed) excluded unless includeControl=true.",
14
+ "Name filters: nameContains/nameRegex/nameNotContains/excludePattern.",
15
15
  "Paginated (default 50/page).",
16
16
  ],
17
17
  annotations: READ_ONLY,
@@ -43,14 +43,17 @@ export const registerListProcesses = defineTool({
43
43
  fields: z
44
44
  .array(z.enum(["name", "parameters"]))
45
45
  .optional()
46
- .describe("Projection. Default: all fields. Use ['name'] to skip parameters[] and shrink payload ~10x."),
46
+ .describe("Projection. Default ['name']; include 'parameters' for parameter lists (~10x larger)."),
47
47
  },
48
48
  handler: async ({ limit, offset, fetchAll, format, includeControl, nameContains, nameRegex, nameNotContains, excludePattern, fields, }, tm1Client) => {
49
- const project = (list) => fields && !fields.includes("parameters")
50
- ? list.map((p) => ({ name: p.name }))
51
- : list;
49
+ // Names only unless parameters are asked for: listing is how a model
50
+ // orients, and the parameter blocks are ~10x the bytes of the names.
51
+ const withParameters = fields?.includes("parameters") ?? false;
52
+ const project = (list) => withParameters ? list : list.map((p) => ({ name: p.name }));
52
53
  const fullScan = async () => {
53
- let processes = await tm1Client.processes.list();
54
+ let processes = await tm1Client.processes.list({
55
+ namesOnly: !withParameters,
56
+ });
54
57
  if (!includeControl)
55
58
  processes = processes.filter((p) => !p.name.startsWith("}"));
56
59
  if (nameContains) {
@@ -79,6 +82,7 @@ export const registerListProcesses = defineTool({
79
82
  let page;
80
83
  if (canPushDown) {
81
84
  const { items, total } = await tm1Client.processes.list({
85
+ namesOnly: !withParameters,
82
86
  includeControl,
83
87
  ...(nameContains ? { nameContains } : {}),
84
88
  ...(nameNotContains ? { nameNotContains } : {}),
@@ -10,7 +10,7 @@ export const registerUnloadCube = defineTool({
10
10
  // v11 only. v12 answers tm1.Unload with "Demand load, loading and unloading
11
11
  // of cubes is no longer supported." — the feature is gone, with no successor
12
12
  // endpoint, so the tool is withheld rather than offered and refused.
13
- enabled: (tm1Client) => tm1Client.version === 11,
13
+ version: 11,
14
14
  output: MutationResultSchema,
15
15
  input: {
16
16
  cubeName: z.string().describe("Name of the cube to unload"),
@@ -11,7 +11,7 @@ export const registerGetAuditLog = defineTool({
11
11
  annotations: withVersion(READ_ONLY, "v11"),
12
12
  // v12 deprecated AuditLogEntry/AuditLogEntries in 12.0.0 and serves an empty
13
13
  // collection with no successor endpoint, so the tool can only mislead there.
14
- enabled: (tm1Client) => tm1Client.version === 11,
14
+ version: 11,
15
15
  output: {
16
16
  count: z.number().int(),
17
17
  entries: z.array(AuditLogEntrySchema),
@@ -11,7 +11,7 @@ const registerListJobs = defineTool({
11
11
  name: "tm1_list_jobs",
12
12
  description: "List active jobs (Activity) on a TM1 v12 database — the running tasks that replaced v11 threads. Paginated (default 50/page). (v12 only)",
13
13
  annotations: READ_ONLY,
14
- enabled: (tm1Client) => tm1Client.version === 12,
14
+ version: 12,
15
15
  output: pageShapeFor(JobSchema),
16
16
  input: { ...PAGINATION_SCHEMA, ...FORMAT_SCHEMA },
17
17
  handler: async ({ limit, offset, fetchAll, format }, tm1Client) => {
@@ -34,7 +34,7 @@ const registerCancelJob = defineTool({
34
34
  "(v12 only)",
35
35
  ],
36
36
  annotations: DESTRUCTIVE,
37
- enabled: (tm1Client) => tm1Client.version === 12,
37
+ version: 12,
38
38
  output: MutationResultSchema,
39
39
  input: {
40
40
  jobId: z.string().describe("Job ID to cancel"),
@@ -10,7 +10,7 @@ export const registerGetMessageLog = defineTool({
10
10
  // v12 deprecated MessageLogEntry/MessageLogEntries (and the MessageLog /
11
11
  // TailMessageLog functions) in 12.0.0; all of them serve empty with no
12
12
  // successor endpoint.
13
- enabled: (tm1Client) => tm1Client.version === 11,
13
+ version: 11,
14
14
  output: {
15
15
  count: z.number().int(),
16
16
  entries: z.array(MessageLogEntrySchema),
@@ -47,7 +47,7 @@ export const registerGetServerState = defineTool({
47
47
  tm1Client.server.getInfo(),
48
48
  tm1Client.cubes.list(),
49
49
  tm1Client.dimensions.list(),
50
- tm1Client.processes.list(),
50
+ tm1Client.processes.list({ namesOnly: true }),
51
51
  tm1Client.chores.list(),
52
52
  tm1Client.security.listClients(),
53
53
  ]);
@@ -9,7 +9,7 @@ const registerListThreads = defineTool({
9
9
  name: "tm1_list_threads",
10
10
  description: "List active threads on the TM1 server (running processes, chores, MDX queries, etc.). Paginated (default 50/page). (v11 only)",
11
11
  annotations: READ_ONLY,
12
- enabled: (tm1Client) => tm1Client.version === 11,
12
+ version: 11,
13
13
  output: pageShapeFor(ThreadSchema),
14
14
  input: { ...PAGINATION_SCHEMA, ...FORMAT_SCHEMA },
15
15
  handler: async ({ limit, offset, fetchAll, format }, tm1Client) => {
@@ -33,7 +33,7 @@ const registerCancelThread = defineTool({
33
33
  "(v11 only)",
34
34
  ],
35
35
  annotations: DESTRUCTIVE,
36
- enabled: (tm1Client) => tm1Client.version === 11,
36
+ version: 11,
37
37
  output: MutationResultSchema,
38
38
  input: {
39
39
  id: z.number().int().describe("Thread ID to cancel"),
@@ -10,7 +10,7 @@ export const registerGetTransactionLog = defineTool({
10
10
  // v12 deprecated TransactionLogEntry/TransactionLogEntries (and the
11
11
  // TransactionLog / TailTransactionLog functions) in 12.0.0; all of them serve
12
12
  // empty with no successor endpoint.
13
- enabled: (tm1Client) => tm1Client.version === 11,
13
+ version: 11,
14
14
  output: {
15
15
  count: z.number().int(),
16
16
  coverage: z
@@ -0,0 +1,2 @@
1
+ export declare const registerListConnections: import("../define-tool.js").ToolRegistrar;
2
+ //# sourceMappingURL=list-connections.d.ts.map