@happyvertical/smrt-core 0.51.37 → 0.51.39

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 (65) hide show
  1. package/agents/build-knowledge.md +25 -0
  2. package/agents/generators.md +27 -0
  3. package/agents/schema-paths.md +11 -0
  4. package/dist/consumer-plugin/artifact-publication.d.ts +2 -0
  5. package/dist/consumer-plugin/artifact-publication.d.ts.map +1 -1
  6. package/dist/consumer-plugin/artifact-publication.js +15 -1
  7. package/dist/consumer-plugin/artifact-publication.js.map +1 -1
  8. package/dist/consumer-plugin/index.d.ts.map +1 -1
  9. package/dist/consumer-plugin/index.js +3 -3
  10. package/dist/consumer-plugin/index.js.map +1 -1
  11. package/dist/generators/mcp-runtime-template.d.ts +17 -0
  12. package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
  13. package/dist/generators/mcp-runtime-template.js +27 -19
  14. package/dist/generators/mcp-runtime-template.js.map +1 -1
  15. package/dist/generators/mcp-tool-name.d.ts +17 -0
  16. package/dist/generators/mcp-tool-name.d.ts.map +1 -0
  17. package/dist/generators/mcp-tool-name.js +33 -0
  18. package/dist/generators/mcp-tool-name.js.map +1 -0
  19. package/dist/generators/mcp.d.ts +46 -1
  20. package/dist/generators/mcp.d.ts.map +1 -1
  21. package/dist/generators/mcp.js +105 -53
  22. package/dist/generators/mcp.js.map +1 -1
  23. package/dist/generators/tool-schema.d.ts +6 -0
  24. package/dist/generators/tool-schema.d.ts.map +1 -1
  25. package/dist/generators/tool-schema.js +8 -3
  26. package/dist/generators/tool-schema.js.map +1 -1
  27. package/dist/index.js +3 -1
  28. package/dist/knowledge.d.ts +2 -0
  29. package/dist/knowledge.d.ts.map +1 -1
  30. package/dist/knowledge.js +3 -1
  31. package/dist/knowledge.js.map +1 -1
  32. package/dist/manifest/discover-base-classes.js +2 -2
  33. package/dist/manifest/discover-base-classes.js.map +1 -1
  34. package/dist/manifest/discover-smrt-packages.d.ts.map +1 -1
  35. package/dist/manifest/discover-smrt-packages.js +3 -2
  36. package/dist/manifest/discover-smrt-packages.js.map +1 -1
  37. package/dist/manifest/generator.d.ts +7 -0
  38. package/dist/manifest/generator.d.ts.map +1 -1
  39. package/dist/manifest/generator.js +30 -15
  40. package/dist/manifest/generator.js.map +1 -1
  41. package/dist/manifest/manager.d.ts.map +1 -1
  42. package/dist/manifest/manager.js +6 -2
  43. package/dist/manifest/manager.js.map +1 -1
  44. package/dist/manifest/static-manifest.js +1 -1
  45. package/dist/manifest/static-manifest.js.map +1 -1
  46. package/dist/manifest/store.js +1 -1
  47. package/dist/manifest.json +1 -1
  48. package/dist/migrations/differ.d.ts +2 -0
  49. package/dist/migrations/differ.d.ts.map +1 -1
  50. package/dist/migrations/differ.js +35 -5
  51. package/dist/migrations/differ.js.map +1 -1
  52. package/dist/node_modules/.pnpm/{brace-expansion@5.0.9 → brace-expansion@5.0.11}/node_modules/brace-expansion/dist/esm/index.js +32 -19
  53. package/dist/node_modules/.pnpm/brace-expansion@5.0.11/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
  54. package/dist/node_modules/.pnpm/minimatch@10.2.6/node_modules/minimatch/dist/esm/index.js +1 -1
  55. package/dist/scanner/types.d.ts +2 -0
  56. package/dist/scanner/types.d.ts.map +1 -1
  57. package/dist/scanner/types.js.map +1 -1
  58. package/dist/scripts/generate-manifest.js +44 -44
  59. package/dist/scripts/generate-test-manifest.js +49 -2
  60. package/dist/smrt-knowledge.json +9 -9
  61. package/dist/vite-plugin/index.d.ts.map +1 -1
  62. package/dist/vite-plugin/index.js +16 -6
  63. package/dist/vite-plugin/index.js.map +1 -1
  64. package/package.json +4 -4
  65. package/dist/node_modules/.pnpm/brace-expansion@5.0.9/node_modules/brace-expansion/dist/esm/index.js.map +0 -1
@@ -5,8 +5,9 @@ import { ObjectRegistry } from "../registry.js";
5
5
  import { SmrtCollection } from "../collection.js";
6
6
  import { generatedSiblingExtension, renderGeneratedSource, resolveGeneratedSourceLanguage } from "./mcp-emit.js";
7
7
  import { generateClaudeConfig, generateMCPDocumentation, generateMCPScript, generateRuntimeBootstrap } from "./mcp-runtime-template.js";
8
+ import { canonicalMcpToolNames } from "./mcp-tool-name.js";
8
9
  import { runWithTenantGate } from "./tenant-gate.js";
9
- import { buildToolInputSchema, fieldTypeToJsonSchema, finalizeMcpJsonSchema, isCrudAction } from "./tool-schema.js";
10
+ import { assertMcpJsonSchemaSafety, buildToolInputSchema, fieldTypeToJsonSchema, finalizeMcpJsonSchema, isCrudAction, resolveToolSemantics } from "./tool-schema.js";
10
11
  import { dirname, resolve } from "node:path";
11
12
  import { mkdir, writeFile } from "node:fs/promises";
12
13
  //#region src/generators/mcp.ts
@@ -45,6 +46,20 @@ function resolveMCPToolListCacheHint(options, hasTenantScopedTools) {
45
46
  cacheScope: !hasTenantScopedTools && options?.cacheScope === "public" && options.publicCatalog === true ? "public" : "private"
46
47
  };
47
48
  }
49
+ /** Map a canonical effect classification into inert MCP capability hints. */
50
+ function mcpToolAnnotations(action, customAction) {
51
+ const semantics = resolveToolSemantics(action, customAction);
52
+ return mcpToolAnnotationsFor(semantics.effect, semantics.idempotent, semantics.openWorld);
53
+ }
54
+ /** Map an explicitly declared canonical classification into inert MCP hints. */
55
+ function mcpToolAnnotationsFor(effect, idempotent, openWorld) {
56
+ return {
57
+ readOnlyHint: effect === "read",
58
+ destructiveHint: effect === "destructive",
59
+ idempotentHint: idempotent,
60
+ openWorldHint: openWorld
61
+ };
62
+ }
48
63
  /** Return a copied, canonical tool sequence for byte-stable tools/list output. */
49
64
  function sortMCPTools(tools) {
50
65
  return [...tools].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
@@ -104,6 +119,24 @@ function buildTaskActionInvocationArgs(metadata, args) {
104
119
  * Generate MCP server from smrt objects
105
120
  */
106
121
  var MCPGenerator = class {
122
+ toolTargets = /* @__PURE__ */ new WeakMap();
123
+ toolTarget(tool) {
124
+ const target = this.toolTargets.get(tool);
125
+ if (!target) throw new Error(`Missing MCP tool target: ${tool.name}`);
126
+ return target;
127
+ }
128
+ /** Return the validated source identity for a tool returned by this generator. */
129
+ getToolIdentity(tool) {
130
+ const target = this.toolTarget(tool);
131
+ return {
132
+ objectName: target.objectName,
133
+ action: target.action,
134
+ originalName: target.originalName ?? tool.name
135
+ };
136
+ }
137
+ runtimeToolTargets(tools) {
138
+ return Object.fromEntries(tools.map((tool) => [tool.name, this.toolTarget(tool)]));
139
+ }
107
140
  config;
108
141
  context;
109
142
  collections = /* @__PURE__ */ new Map();
@@ -153,6 +186,13 @@ var MCPGenerator = class {
153
186
  const objectTools = await this.generateObjectTools(simpleName, shouldInclude);
154
187
  tools.push(...objectTools);
155
188
  }
189
+ const names = canonicalMcpToolNames(tools.map((tool) => ({
190
+ name: tool.name,
191
+ target: this.toolTarget(tool)
192
+ })));
193
+ tools.forEach((tool, index) => {
194
+ tool.name = names[index];
195
+ });
156
196
  return sortMCPTools(tools);
157
197
  }
158
198
  /**
@@ -167,31 +207,36 @@ var MCPGenerator = class {
167
207
  name: `${lowerName}_list`,
168
208
  description: `List ${objectName} objects with optional filtering`,
169
209
  inputSchema: this.buildInputSchema(objectName, "list", fields),
170
- outputSchema: this.buildOutputSchema(objectName, "list", fields)
210
+ outputSchema: this.buildOutputSchema(objectName, "list", fields),
211
+ annotations: mcpToolAnnotations("list")
171
212
  });
172
213
  if (shouldInclude("get")) tools.push({
173
214
  name: `${lowerName}_get`,
174
215
  description: `Get a specific ${objectName} by ID or slug`,
175
216
  inputSchema: this.buildInputSchema(objectName, "get", fields),
176
- outputSchema: this.buildOutputSchema(objectName, "get", fields)
217
+ outputSchema: this.buildOutputSchema(objectName, "get", fields),
218
+ annotations: mcpToolAnnotations("get")
177
219
  });
178
220
  if (shouldInclude("create")) tools.push({
179
221
  name: `${lowerName}_create`,
180
222
  description: `Create a new ${objectName}`,
181
223
  inputSchema: this.buildInputSchema(objectName, "create", fields),
182
- outputSchema: this.buildOutputSchema(objectName, "create", fields)
224
+ outputSchema: this.buildOutputSchema(objectName, "create", fields),
225
+ annotations: mcpToolAnnotations("create")
183
226
  });
184
227
  if (shouldInclude("update")) tools.push({
185
228
  name: `${lowerName}_update`,
186
229
  description: `Update an existing ${objectName}`,
187
230
  inputSchema: this.buildInputSchema(objectName, "update", fields),
188
- outputSchema: this.buildOutputSchema(objectName, "update", fields)
231
+ outputSchema: this.buildOutputSchema(objectName, "update", fields),
232
+ annotations: mcpToolAnnotations("update")
189
233
  });
190
234
  if (shouldInclude("delete")) tools.push({
191
235
  name: `${lowerName}_delete`,
192
236
  description: `Delete a ${objectName} by ID`,
193
237
  inputSchema: this.buildInputSchema(objectName, "delete", fields),
194
- outputSchema: this.buildOutputSchema(objectName, "delete", fields)
238
+ outputSchema: this.buildOutputSchema(objectName, "delete", fields),
239
+ annotations: mcpToolAnnotations("delete")
195
240
  });
196
241
  if (classInfo) {
197
242
  const mcpConfig = ObjectRegistry.getConfig(objectName).mcp;
@@ -234,6 +279,11 @@ var MCPGenerator = class {
234
279
  tools.push(tool);
235
280
  }
236
281
  }
282
+ for (const tool of tools) this.toolTargets.set(tool, {
283
+ objectName,
284
+ action: tool.name.slice(lowerName.length + 1),
285
+ originalName: tool.name
286
+ });
237
287
  return tools;
238
288
  }
239
289
  buildCustomActionTool(objectName, lowerName, methodName, methodDef, collectionReceiver = false) {
@@ -242,7 +292,8 @@ var MCPGenerator = class {
242
292
  name: `${lowerName}_${methodName}`.toLowerCase(),
243
293
  description: `Execute ${methodName} action on ${objectName}`,
244
294
  inputSchema: this.buildInputSchema(objectName, methodName, ObjectRegistry.getFields(objectName), metadata),
245
- outputSchema: this.buildOutputSchema(objectName, methodName, ObjectRegistry.getFields(objectName))
295
+ outputSchema: this.buildOutputSchema(objectName, methodName, ObjectRegistry.getFields(objectName)),
296
+ annotations: mcpToolAnnotations(methodName, metadata)
246
297
  };
247
298
  }
248
299
  resolveCustomActionMetadata(objectName, action, method, collectionReceiver = false) {
@@ -457,11 +508,9 @@ var MCPGenerator = class {
457
508
  async handleToolCall(request) {
458
509
  const { name, arguments: args } = request.params;
459
510
  try {
460
- if (!(await this.generateTools()).some((t) => t.name === name)) throw new Error(`Unknown tool: ${name}`);
461
- const firstUnderscore = name.indexOf("_");
462
- const objectName = firstUnderscore === -1 ? "" : name.slice(0, firstUnderscore);
463
- const action = firstUnderscore === -1 ? "" : name.slice(firstUnderscore + 1);
464
- if (!objectName || !action) throw new Error(`Invalid tool name format: ${name}`);
511
+ const tool = (await this.generateTools()).find((candidate) => candidate.name === name);
512
+ if (!tool) throw new Error(`Unknown tool: ${name}`);
513
+ const { objectName, action } = this.toolTarget(tool);
465
514
  const registeredClasses = ObjectRegistry.getAllClasses();
466
515
  let classInfo = null;
467
516
  let actualObjectName = "";
@@ -536,10 +585,10 @@ var MCPGenerator = class {
536
585
  };
537
586
  }
538
587
  async resolveTaskAction(toolName, args) {
539
- const separator = toolName.indexOf("_");
540
- if (separator <= 0) return null;
541
- const objectPrefix = toolName.slice(0, separator);
542
- const action = toolName.slice(separator + 1);
588
+ const tools = await this.generateTools();
589
+ const tool = tools.find((candidate) => candidate.name === toolName);
590
+ if (!tool) return null;
591
+ const { objectName: objectPrefix, action } = this.toolTarget(tool);
543
592
  if (isCrudToolAction(action)) return null;
544
593
  const classEntry = Array.from(ObjectRegistry.getAllClasses().entries()).find(([key, info]) => (info.name || key).toLowerCase() === objectPrefix.toLowerCase());
545
594
  if (!classEntry) return null;
@@ -548,7 +597,7 @@ var MCPGenerator = class {
548
597
  const mcpConfig = ObjectRegistry.getConfig(objectName).mcp;
549
598
  const configuredTasks = typeof mcpConfig === "object" ? mcpConfig.tasks : void 0;
550
599
  if (configuredTasks !== true && (!Array.isArray(configuredTasks) || !configuredTasks.some((method) => method.toLowerCase() === action.toLowerCase()))) return null;
551
- if (!(await this.generateTools()).some((tool) => tool.name === toolName)) return null;
600
+ if (!tools.some((tool) => tool.name === toolName)) return null;
552
601
  const [resolvedMethodName, method] = resolveCustomActionMethod(await ObjectRegistry.getAllMethods(objectName), action);
553
602
  const methodName = method ? resolvedMethodName : resolveRuntimeMethodName(classInfo.constructor, action);
554
603
  const metadata = this.resolveCustomActionMetadata(objectName, methodName, method, this.hasCollectionReceiver(classInfo));
@@ -712,7 +761,7 @@ var MCPGenerator = class {
712
761
  if (typeof isTenantScopedClass !== "function") return [];
713
762
  const scoped = /* @__PURE__ */ new Set();
714
763
  for (const tool of tools) {
715
- const [objectName] = tool.name.split("_");
764
+ const { objectName } = this.toolTarget(tool);
716
765
  if (!objectName) continue;
717
766
  for (const [key, info] of ObjectRegistry.getAllClasses()) {
718
767
  const simpleName = info.name || key;
@@ -735,7 +784,7 @@ var MCPGenerator = class {
735
784
  async hasTenantScopedTools(tools) {
736
785
  if ((await this.tenantScopedObjectNames(tools)).length > 0) return true;
737
786
  for (const tool of tools) {
738
- const [objectName] = tool.name.split("_");
787
+ const { objectName } = this.toolTarget(tool);
739
788
  if (!objectName) continue;
740
789
  for (const [key, info] of ObjectRegistry.getAllClasses()) {
741
790
  const simpleName = info.name || key;
@@ -915,6 +964,7 @@ var MCPGenerator = class {
915
964
  context: this.context,
916
965
  debug,
917
966
  tools,
967
+ toolTargets: this.runtimeToolTargets(tools),
918
968
  customActions: await this.runtimeCustomActions(tools),
919
969
  taskActions: await this.runtimeTaskActions(tools),
920
970
  tenantScopedObjects,
@@ -944,10 +994,9 @@ var MCPGenerator = class {
944
994
  const metadata = {};
945
995
  const classes = ObjectRegistry.getAllClasses();
946
996
  for (const tool of tools) {
947
- const separator = tool.name.indexOf("_");
948
- if (separator === -1) continue;
949
- const objectPrefix = tool.name.slice(0, separator);
950
- const action = tool.name.slice(separator + 1);
997
+ const target = this.toolTarget(tool);
998
+ const objectPrefix = target.objectName.toLowerCase();
999
+ const action = target.action;
951
1000
  if (isCrudToolAction(action)) continue;
952
1001
  const matched = Array.from(classes.entries()).find(([key, info]) => (info.name || key).toLowerCase() === objectPrefix);
953
1002
  if (!matched) continue;
@@ -974,9 +1023,7 @@ var MCPGenerator = class {
974
1023
  const classes = ObjectRegistry.getAllClasses();
975
1024
  for (const tool of tools) {
976
1025
  if (!await this.supportsTaskTool(tool.name)) continue;
977
- const separator = tool.name.indexOf("_");
978
- if (separator <= 0) continue;
979
- const objectPrefix = tool.name.slice(0, separator).toLowerCase();
1026
+ const objectPrefix = this.toolTarget(tool).objectName.toLowerCase();
980
1027
  const matched = Array.from(classes.entries()).find(([key, info]) => (info.name || key).toLowerCase() === objectPrefix);
981
1028
  if (!matched) continue;
982
1029
  const [key, classInfo] = matched;
@@ -1020,9 +1067,9 @@ var MCPGenerator = class {
1020
1067
  const orderings = {};
1021
1068
  const classes = ObjectRegistry.getAllClasses();
1022
1069
  for (const tool of tools) {
1023
- const separator = tool.name.indexOf("_");
1024
- if (separator === -1 || tool.name.slice(separator + 1) !== "list") continue;
1025
- const objectPrefix = tool.name.slice(0, separator);
1070
+ const target = this.toolTarget(tool);
1071
+ if (target.action !== "list") continue;
1072
+ const objectPrefix = target.objectName.toLowerCase();
1026
1073
  if (orderings[objectPrefix]) continue;
1027
1074
  const matched = Array.from(classes.entries()).find(([key, info]) => (info.name || key).toLowerCase() === objectPrefix);
1028
1075
  if (!matched) continue;
@@ -1034,9 +1081,9 @@ var MCPGenerator = class {
1034
1081
  const targets = {};
1035
1082
  const classes = ObjectRegistry.getAllClasses();
1036
1083
  for (const tool of tools) {
1037
- const separator = tool.name.indexOf("_");
1038
- if (separator === -1 || tool.name.slice(separator + 1) !== "create") continue;
1039
- const objectPrefix = tool.name.slice(0, separator);
1084
+ const target = this.toolTarget(tool);
1085
+ if (target.action !== "create") continue;
1086
+ const objectPrefix = target.objectName.toLowerCase();
1040
1087
  const matched = Array.from(classes.entries()).find(([key, info]) => (info.name || key).toLowerCase() === objectPrefix);
1041
1088
  if (!matched) continue;
1042
1089
  const [key, classInfo] = matched;
@@ -1113,6 +1160,15 @@ export const tools: Array<{
1113
1160
  description: string;
1114
1161
  inputSchema: any;
1115
1162
  outputSchema: any;
1163
+ annotations?: {
1164
+ readOnlyHint: boolean;
1165
+ destructiveHint: boolean;
1166
+ idempotentHint: boolean;
1167
+ openWorldHint: boolean;
1168
+ };
1169
+ title?: string;
1170
+ icons?: Array<{ src: string; mimeType?: string; sizes?: string[]; theme?: 'light' | 'dark' }>;
1171
+ _meta?: Record<string, unknown>;
1116
1172
  }> = ${JSON.stringify(tools, null, 2)};
1117
1173
  `;
1118
1174
  }
@@ -1121,18 +1177,17 @@ export const tools: Array<{
1121
1177
  */
1122
1178
  async generateToolSwitchCases(indent = " ", generatedTools) {
1123
1179
  const tools = generatedTools ?? await this.generateTools();
1124
- const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
1125
1180
  return (await Promise.all(tools.map(async (tool) => {
1126
- const separator = tool.name.indexOf("_");
1127
- const objectName = tool.name.slice(0, separator);
1128
- const action = tool.name.slice(separator + 1);
1181
+ const target = this.toolTarget(tool);
1182
+ const objectName = target.objectName.toLowerCase();
1183
+ const action = target.action;
1129
1184
  switch (action) {
1130
1185
  case "list": return `${indent}case '${tool.name}': {
1131
1186
  ${indent} const limit = args.limit ?? 50;
1132
1187
  ${indent} const offset = args.offset ?? 0;
1133
1188
  ${indent} const where = args.where ?? {};
1134
1189
 
1135
- ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
1190
+ ${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(target.objectName)}, {
1136
1191
  ${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },
1137
1192
  ${indent} ai: aiConfig
1138
1193
  ${indent} });
@@ -1150,7 +1205,7 @@ ${indent} if (!args.id && !args.slug) {
1150
1205
  ${indent} throw new Error('Either id or slug is required');
1151
1206
  ${indent} }
1152
1207
 
1153
- ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
1208
+ ${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(target.objectName)}, {
1154
1209
  ${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },
1155
1210
  ${indent} ai: aiConfig
1156
1211
  ${indent} });
@@ -1165,7 +1220,7 @@ ${indent} }
1165
1220
  ${indent} return successResult(item.toPublicJSON(PUBLIC_JSON_OPTIONS));
1166
1221
  ${indent}}`;
1167
1222
  case "create": return `${indent}case '${tool.name}': {
1168
- ${indent} const { collection, objectName: targetObjectName } = await resolveCreateTarget('${objectName}', args, aiConfig);
1223
+ ${indent} const { collection, objectName: targetObjectName } = await resolveCreateTarget(${JSON.stringify(objectName)}, args, aiConfig);
1169
1224
 
1170
1225
  ${indent} const newItem = await collection.create(applyWritablePolicy(targetObjectName, args));
1171
1226
  ${indent} await newItem.save();
@@ -1178,7 +1233,7 @@ ${indent} if (!id) {
1178
1233
  ${indent} throw new Error('ID is required for update');
1179
1234
  ${indent} }
1180
1235
 
1181
- ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
1236
+ ${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(target.objectName)}, {
1182
1237
  ${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },
1183
1238
  ${indent} ai: aiConfig
1184
1239
  ${indent} });
@@ -1188,7 +1243,7 @@ ${indent} if (!existing) {
1188
1243
  ${indent} throw new Error('Object not found');
1189
1244
  ${indent} }
1190
1245
 
1191
- ${indent} Object.assign(existing, applyWritablePolicy('${capitalize(objectName)}', updateData));
1246
+ ${indent} Object.assign(existing, applyWritablePolicy(${JSON.stringify(target.objectName)}, updateData));
1192
1247
  ${indent} await existing.save();
1193
1248
 
1194
1249
  ${indent} return successResult(existing.toPublicJSON(PUBLIC_JSON_OPTIONS));
@@ -1198,7 +1253,7 @@ ${indent} if (!args.id) {
1198
1253
  ${indent} throw new Error('ID is required for delete');
1199
1254
  ${indent} }
1200
1255
 
1201
- ${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {
1256
+ ${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(target.objectName)}, {
1202
1257
  ${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },
1203
1258
  ${indent} ai: aiConfig
1204
1259
  ${indent} });
@@ -1224,10 +1279,10 @@ ${indent}}`;
1224
1279
  ${indent} const { id, options, ...directArgs } = args;
1225
1280
 
1226
1281
  ${indent} if (${JSON.stringify(metadata.scope)} === 'item' && !id) {
1227
- ${indent} throw new Error('ID is required for custom action ${action}');
1282
+ ${indent} throw new Error(${JSON.stringify(`ID is required for custom action ${action}`)});
1228
1283
  ${indent} }
1229
1284
  ${indent} if (${JSON.stringify(metadata.scope)} === 'collection' && id) {
1230
- ${indent} throw new Error('Custom action ${action} is collection-scoped and does not accept an ID');
1285
+ ${indent} throw new Error(${JSON.stringify(`Custom action ${action} is collection-scoped and does not accept an ID`)});
1231
1286
  ${indent} }
1232
1287
 
1233
1288
  ${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(registeredName)}, {
@@ -1246,7 +1301,7 @@ ${indent} }
1246
1301
 
1247
1302
  ${indent} const actionMethod = target[${JSON.stringify(methodName)}];
1248
1303
  ${indent} if (typeof actionMethod !== 'function') {
1249
- ${indent} throw new Error('Method ${methodName} not found on custom action target');
1304
+ ${indent} throw new Error(${JSON.stringify(`Method ${methodName} not found on custom action target`)});
1250
1305
  ${indent} }
1251
1306
 
1252
1307
  ${indent} const methodArgs = ${methodArgs.startsWith("[") ? methodArgs : `[${methodArgs}]`};
@@ -1274,6 +1329,7 @@ ${indent}}`;
1274
1329
  const tools = await this.generateTools();
1275
1330
  const switchCases = await this.generateToolSwitchCases(" ", tools);
1276
1331
  const stiTargets = this.runtimeStiTargets(tools);
1332
+ const toolTargets = this.runtimeToolTargets(tools);
1277
1333
  const tenantScopedSet = Array.from(new Set(tenantScopedObjects.map((n) => n.toLowerCase())));
1278
1334
  const hasTenantScoped = tenantScopedSet.length > 0;
1279
1335
  return `/**
@@ -1301,6 +1357,7 @@ const MCP_TENANT_ID = process.env.SMRT_MCP_TENANT_ID || undefined;
1301
1357
  const MCP_ALLOW_CROSS_TENANT = process.env.SMRT_MCP_ALLOW_CROSS_TENANT === 'true';
1302
1358
  ` : ""}
1303
1359
 
1360
+ const TOOL_TARGETS: Record<string, { objectName: string; action: string }> = ${JSON.stringify(toolTargets)};
1304
1361
  const PUBLIC_JSON_OPTIONS = {
1305
1362
  permissions: (process.env.SMRT_MCP_PERMISSIONS || '')
1306
1363
  .split(',')
@@ -1420,7 +1477,7 @@ ${switchCases}
1420
1477
  };
1421
1478
  ${hasTenantScoped ? `
1422
1479
  // Fail-closed tenant context for tenant-scoped tools (#1554).
1423
- const [toolObject] = name.split('_');
1480
+ const toolObject = TOOL_TARGETS[name]?.objectName;
1424
1481
  const result =
1425
1482
  toolObject && TENANT_SCOPED.has(toolObject.toLowerCase())
1426
1483
  ? await runTenantScopedEntryPoint(
@@ -1518,12 +1575,7 @@ export async function createServer() {
1518
1575
  }
1519
1576
 
1520
1577
  return {
1521
- tools: [...tools].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0).map(tool => ({
1522
- name: tool.name,
1523
- description: tool.description,
1524
- inputSchema: tool.inputSchema,
1525
- outputSchema: tool.outputSchema,
1526
- })),
1578
+ tools: [...tools].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0),
1527
1579
  };
1528
1580
  });
1529
1581
 
@@ -1570,6 +1622,6 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
1570
1622
  }
1571
1623
  };
1572
1624
  //#endregion
1573
- export { MCPGenerator, MCP_STABLE_CATALOG_TTL_MS, resolveMCPToolListCacheHint, sortMCPTools };
1625
+ export { MCPGenerator, MCP_STABLE_CATALOG_TTL_MS, assertMcpJsonSchemaSafety, mcpToolAnnotations, mcpToolAnnotationsFor, resolveMCPToolListCacheHint, sortMCPTools };
1574
1626
 
1575
1627
  //# sourceMappingURL=mcp.js.map