@cplace/mcp-server 1.9.0 → 1.10.5

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 (235) hide show
  1. package/README.md +12 -13
  2. package/dist/index.js +4 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/plugins/app-catalog.js +1 -1
  5. package/dist/plugins/app-catalog.js.map +1 -1
  6. package/dist/plugins/application-settings.d.ts.map +1 -1
  7. package/dist/plugins/application-settings.js +6 -3
  8. package/dist/plugins/application-settings.js.map +1 -1
  9. package/dist/plugins/core/widget-specifications/cf.cplace.platform.tableWidget/columns.md +6 -0
  10. package/dist/plugins/core.d.ts.map +1 -1
  11. package/dist/plugins/core.js +25 -13
  12. package/dist/plugins/core.js.map +1 -1
  13. package/dist/plugins/forms-wizard.js +2 -2
  14. package/dist/plugins/forms-wizard.js.map +1 -1
  15. package/dist/plugins/history.d.ts.map +1 -1
  16. package/dist/plugins/history.js +6 -3
  17. package/dist/plugins/history.js.map +1 -1
  18. package/dist/plugins/jobs.js +2 -2
  19. package/dist/plugins/jobs.js.map +1 -1
  20. package/dist/plugins/layouts.d.ts.map +1 -1
  21. package/dist/plugins/layouts.js +17 -8
  22. package/dist/plugins/layouts.js.map +1 -1
  23. package/dist/plugins/low-code.d.ts.map +1 -1
  24. package/dist/plugins/low-code.js +48 -15
  25. package/dist/plugins/low-code.js.map +1 -1
  26. package/dist/plugins/project-planning.d.ts.map +1 -1
  27. package/dist/plugins/project-planning.js +6 -3
  28. package/dist/plugins/project-planning.js.map +1 -1
  29. package/dist/plugins/resource-management.d.ts.map +1 -1
  30. package/dist/plugins/resource-management.js +6 -3
  31. package/dist/plugins/resource-management.js.map +1 -1
  32. package/dist/plugins/solution-management.d.ts.map +1 -1
  33. package/dist/plugins/solution-management.js +6 -3
  34. package/dist/plugins/solution-management.js.map +1 -1
  35. package/dist/plugins/types-write.d.ts.map +1 -1
  36. package/dist/plugins/types-write.js +6 -3
  37. package/dist/plugins/types-write.js.map +1 -1
  38. package/dist/plugins/widget-specifications.d.ts.map +1 -1
  39. package/dist/plugins/widget-specifications.js +2 -2
  40. package/dist/plugins/widget-specifications.js.map +1 -1
  41. package/dist/plugins/workspace-admin.d.ts.map +1 -1
  42. package/dist/plugins/workspace-admin.js +6 -3
  43. package/dist/plugins/workspace-admin.js.map +1 -1
  44. package/dist/str-replace-utils.js +1 -1
  45. package/dist/str-replace-utils.js.map +1 -1
  46. package/dist/tools/apps-catalog.d.ts +1 -1
  47. package/dist/tools/apps-catalog.d.ts.map +1 -1
  48. package/dist/tools/apps-catalog.js +16 -12
  49. package/dist/tools/apps-catalog.js.map +1 -1
  50. package/dist/tools/board-widget.d.ts +2 -2
  51. package/dist/tools/board-widget.d.ts.map +1 -1
  52. package/dist/tools/board-widget.js +354 -201
  53. package/dist/tools/board-widget.js.map +1 -1
  54. package/dist/tools/change-listeners.d.ts +2 -2
  55. package/dist/tools/change-listeners.d.ts.map +1 -1
  56. package/dist/tools/change-listeners.js +125 -57
  57. package/dist/tools/change-listeners.js.map +1 -1
  58. package/dist/tools/common-schemas.d.ts +1 -1
  59. package/dist/tools/common-schemas.d.ts.map +1 -1
  60. package/dist/tools/common-schemas.js +5 -3
  61. package/dist/tools/common-schemas.js.map +1 -1
  62. package/dist/tools/csv-export.d.ts +2 -2
  63. package/dist/tools/csv-export.d.ts.map +1 -1
  64. package/dist/tools/csv-export.js +29 -24
  65. package/dist/tools/csv-export.js.map +1 -1
  66. package/dist/tools/documents.d.ts +2 -2
  67. package/dist/tools/documents.d.ts.map +1 -1
  68. package/dist/tools/documents.js +34 -14
  69. package/dist/tools/documents.js.map +1 -1
  70. package/dist/tools/expert-settings.d.ts +3 -3
  71. package/dist/tools/expert-settings.d.ts.map +1 -1
  72. package/dist/tools/expert-settings.js +97 -38
  73. package/dist/tools/expert-settings.js.map +1 -1
  74. package/dist/tools/get-operations.d.ts +2 -2
  75. package/dist/tools/get-operations.d.ts.map +1 -1
  76. package/dist/tools/get-operations.js +29 -21
  77. package/dist/tools/get-operations.js.map +1 -1
  78. package/dist/tools/job-schedule-trigger.d.ts +2 -2
  79. package/dist/tools/job-schedule-trigger.d.ts.map +1 -1
  80. package/dist/tools/job-schedule-trigger.js +19 -10
  81. package/dist/tools/job-schedule-trigger.js.map +1 -1
  82. package/dist/tools/job-scripts.d.ts +2 -2
  83. package/dist/tools/job-scripts.d.ts.map +1 -1
  84. package/dist/tools/job-scripts.js +119 -55
  85. package/dist/tools/job-scripts.js.map +1 -1
  86. package/dist/tools/jobs.d.ts +2 -2
  87. package/dist/tools/jobs.d.ts.map +1 -1
  88. package/dist/tools/jobs.js +68 -38
  89. package/dist/tools/jobs.js.map +1 -1
  90. package/dist/tools/layout-richstring-shared.d.ts +24 -1
  91. package/dist/tools/layout-richstring-shared.d.ts.map +1 -1
  92. package/dist/tools/layout-richstring-shared.js +99 -1
  93. package/dist/tools/layout-richstring-shared.js.map +1 -1
  94. package/dist/tools/layout-richstring-widgets.d.ts +94 -2
  95. package/dist/tools/layout-richstring-widgets.d.ts.map +1 -1
  96. package/dist/tools/layout-richstring-widgets.js +247 -25
  97. package/dist/tools/layout-richstring-widgets.js.map +1 -1
  98. package/dist/tools/layout.d.ts +5 -4
  99. package/dist/tools/layout.d.ts.map +1 -1
  100. package/dist/tools/layout.js +235 -124
  101. package/dist/tools/layout.js.map +1 -1
  102. package/dist/tools/linting.d.ts +2 -2
  103. package/dist/tools/linting.d.ts.map +1 -1
  104. package/dist/tools/linting.js +5 -5
  105. package/dist/tools/linting.js.map +1 -1
  106. package/dist/tools/page-action-simulation.d.ts +18 -0
  107. package/dist/tools/page-action-simulation.d.ts.map +1 -0
  108. package/dist/tools/page-action-simulation.js +88 -0
  109. package/dist/tools/page-action-simulation.js.map +1 -0
  110. package/dist/tools/page-actions.d.ts +60 -0
  111. package/dist/tools/page-actions.d.ts.map +1 -0
  112. package/dist/tools/page-actions.js +284 -0
  113. package/dist/tools/page-actions.js.map +1 -0
  114. package/dist/tools/pages.d.ts +3 -3
  115. package/dist/tools/pages.d.ts.map +1 -1
  116. package/dist/tools/pages.js +237 -112
  117. package/dist/tools/pages.js.map +1 -1
  118. package/dist/tools/ppt-export-schemas.d.ts +1 -1
  119. package/dist/tools/ppt-export-schemas.d.ts.map +1 -1
  120. package/dist/tools/ppt-export-schemas.js +269 -122
  121. package/dist/tools/ppt-export-schemas.js.map +1 -1
  122. package/dist/tools/ppt-export.d.ts +2 -2
  123. package/dist/tools/ppt-export.d.ts.map +1 -1
  124. package/dist/tools/ppt-export.js +82 -43
  125. package/dist/tools/ppt-export.js.map +1 -1
  126. package/dist/tools/profile-management.d.ts +2 -2
  127. package/dist/tools/profile-management.d.ts.map +1 -1
  128. package/dist/tools/profile-management.js +109 -82
  129. package/dist/tools/profile-management.js.map +1 -1
  130. package/dist/tools/references.d.ts +2 -2
  131. package/dist/tools/references.d.ts.map +1 -1
  132. package/dist/tools/references.js +36 -24
  133. package/dist/tools/references.js.map +1 -1
  134. package/dist/tools/resource-planner-widget.d.ts +2 -2
  135. package/dist/tools/resource-planner-widget.d.ts.map +1 -1
  136. package/dist/tools/resource-planner-widget.js +334 -138
  137. package/dist/tools/resource-planner-widget.js.map +1 -1
  138. package/dist/tools/richstring-marker-resolver.d.ts +16 -0
  139. package/dist/tools/richstring-marker-resolver.d.ts.map +1 -0
  140. package/dist/tools/richstring-marker-resolver.js +47 -0
  141. package/dist/tools/richstring-marker-resolver.js.map +1 -0
  142. package/dist/tools/richstring-widgets.d.ts +6 -16
  143. package/dist/tools/richstring-widgets.d.ts.map +1 -1
  144. package/dist/tools/richstring-widgets.js +184 -129
  145. package/dist/tools/richstring-widgets.js.map +1 -1
  146. package/dist/tools/schedule.d.ts +2 -2
  147. package/dist/tools/schedule.d.ts.map +1 -1
  148. package/dist/tools/schedule.js +23 -14
  149. package/dist/tools/schedule.js.map +1 -1
  150. package/dist/tools/script-logs.d.ts +2 -2
  151. package/dist/tools/script-logs.d.ts.map +1 -1
  152. package/dist/tools/script-logs.js +71 -32
  153. package/dist/tools/script-logs.js.map +1 -1
  154. package/dist/tools/script.d.ts +2 -2
  155. package/dist/tools/script.d.ts.map +1 -1
  156. package/dist/tools/script.js +44 -26
  157. package/dist/tools/script.js.map +1 -1
  158. package/dist/tools/search.d.ts +2 -2
  159. package/dist/tools/search.d.ts.map +1 -1
  160. package/dist/tools/search.js +139 -102
  161. package/dist/tools/search.js.map +1 -1
  162. package/dist/tools/solution-packages.d.ts +2 -2
  163. package/dist/tools/solution-packages.d.ts.map +1 -1
  164. package/dist/tools/solution-packages.js +149 -61
  165. package/dist/tools/solution-packages.js.map +1 -1
  166. package/dist/tools/system.d.ts +2 -2
  167. package/dist/tools/system.d.ts.map +1 -1
  168. package/dist/tools/system.js +43 -21
  169. package/dist/tools/system.js.map +1 -1
  170. package/dist/tools/type-layouts.d.ts +2 -2
  171. package/dist/tools/type-layouts.d.ts.map +1 -1
  172. package/dist/tools/type-layouts.js +67 -31
  173. package/dist/tools/type-layouts.js.map +1 -1
  174. package/dist/tools/type-management.d.ts +86 -70
  175. package/dist/tools/type-management.d.ts.map +1 -1
  176. package/dist/tools/type-management.js +410 -138
  177. package/dist/tools/type-management.js.map +1 -1
  178. package/dist/tools/url-resolution.d.ts +2 -2
  179. package/dist/tools/url-resolution.d.ts.map +1 -1
  180. package/dist/tools/url-resolution.js +16 -12
  181. package/dist/tools/url-resolution.js.map +1 -1
  182. package/dist/tools/users.d.ts +2 -2
  183. package/dist/tools/users.d.ts.map +1 -1
  184. package/dist/tools/users.js +24 -14
  185. package/dist/tools/users.js.map +1 -1
  186. package/dist/tools/validators.d.ts +2 -2
  187. package/dist/tools/validators.d.ts.map +1 -1
  188. package/dist/tools/validators.js +68 -35
  189. package/dist/tools/validators.js.map +1 -1
  190. package/dist/tools/version-check.d.ts +2 -2
  191. package/dist/tools/version-check.d.ts.map +1 -1
  192. package/dist/tools/version-check.js +36 -30
  193. package/dist/tools/version-check.js.map +1 -1
  194. package/dist/tools/version-history.d.ts +2 -2
  195. package/dist/tools/version-history.d.ts.map +1 -1
  196. package/dist/tools/version-history.js +72 -41
  197. package/dist/tools/version-history.js.map +1 -1
  198. package/dist/tools/widget-simulation.d.ts +18 -0
  199. package/dist/tools/widget-simulation.d.ts.map +1 -0
  200. package/dist/tools/widget-simulation.js +94 -0
  201. package/dist/tools/widget-simulation.js.map +1 -0
  202. package/dist/tools/widget-tool-helpers.d.ts +17 -1
  203. package/dist/tools/widget-tool-helpers.d.ts.map +1 -1
  204. package/dist/tools/widget-tool-helpers.js +41 -6
  205. package/dist/tools/widget-tool-helpers.js.map +1 -1
  206. package/dist/tools/widgets.d.ts +2 -2
  207. package/dist/tools/widgets.d.ts.map +1 -1
  208. package/dist/tools/widgets.js +62 -43
  209. package/dist/tools/widgets.js.map +1 -1
  210. package/dist/tools/wizards.d.ts +2 -2
  211. package/dist/tools/wizards.d.ts.map +1 -1
  212. package/dist/tools/wizards.js +378 -182
  213. package/dist/tools/wizards.js.map +1 -1
  214. package/dist/tools/workflow-execution.d.ts +2 -2
  215. package/dist/tools/workflow-execution.d.ts.map +1 -1
  216. package/dist/tools/workflow-execution.js +27 -19
  217. package/dist/tools/workflow-execution.js.map +1 -1
  218. package/dist/tools/workflow-scripts.d.ts +2 -2
  219. package/dist/tools/workflow-scripts.d.ts.map +1 -1
  220. package/dist/tools/workflow-scripts.js +168 -81
  221. package/dist/tools/workflow-scripts.js.map +1 -1
  222. package/dist/tools/workflow.d.ts +2 -2
  223. package/dist/tools/workflow.d.ts.map +1 -1
  224. package/dist/tools/workflow.js +185 -74
  225. package/dist/tools/workflow.js.map +1 -1
  226. package/dist/tools/workspace-admin.d.ts +2 -2
  227. package/dist/tools/workspace-admin.d.ts.map +1 -1
  228. package/dist/tools/workspace-admin.js +82 -40
  229. package/dist/tools/workspace-admin.js.map +1 -1
  230. package/dist/tools/workspace-core.d.ts +2 -2
  231. package/dist/tools/workspace-core.d.ts.map +1 -1
  232. package/dist/tools/workspace-core.js +93 -53
  233. package/dist/tools/workspace-core.js.map +1 -1
  234. package/dist/utils/dateValidation.js.map +1 -1
  235. package/package.json +9 -4
@@ -1,122 +1,303 @@
1
- import { z } from "zod";
2
- import { debugLogWithTag } from "../logger.js";
1
+ import { z } from 'zod';
2
+ import { debugLogWithTag } from '../logger.js';
3
3
  const TOOL_MANAGE_TYPE_DEFINITION = 'cplace_manage_type_definition';
4
4
  const TOOL_MANAGE_ATTRIBUTE_DEFINITION = 'cplace_manage_attribute_definition';
5
5
  const TOOL_DELETE_TYPE_DEFINITION = 'cplace_delete_type_definition';
6
6
  const TOOL_DELETE_ATTRIBUTE_DEFINITION = 'cplace_delete_attribute_definition';
7
+ const TOOL_LIST_CUSTOM_CONSTRAINT_TYPES = 'cplace_list_custom_constraint_types';
8
+ let cachedCustomConstraintTypes = null;
9
+ const MANAGE_ATTRIBUTE_BASE_DESCRIPTION = 'Create or update attribute definitions within existing type definitions. Supports all major constraint types including string, number, boolean, date, reference, enumeration, and specialized types like rich text and colors. Provides comprehensive configuration options for display properties, validation, and low-code integration.';
10
+ export function buildManageAttributeDefinitionDescription(customTypes) {
11
+ if (customTypes && customTypes.length > 0) {
12
+ const lines = customTypes.map((ct) => {
13
+ const mult = ct.allowedMultiplicities && ct.allowedMultiplicities.length > 0
14
+ ? `multiplicity: ${ct.allowedMultiplicities.join(', ')}`
15
+ : 'any multiplicity';
16
+ return `- ${ct.constraintName} (${mult})`;
17
+ });
18
+ return `${MANAGE_ATTRIBUTE_BASE_DESCRIPTION}\n\nCustom constraint types detected at startup:\n${lines.join('\n')}\nFor live/authoritative list, call cplace_list_custom_constraint_types.`;
19
+ }
20
+ return `${MANAGE_ATTRIBUTE_BASE_DESCRIPTION}\n\nCustom constraint types from installed plugins are supported. Call cplace_list_custom_constraint_types to see names and allowed multiplicities.`;
21
+ }
22
+ export async function primeCustomConstraintTypeCache(client) {
23
+ try {
24
+ const controller = new AbortController();
25
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
26
+ try {
27
+ const result = await client.makeApiRequest('json/custom-constraint-types', 'GET');
28
+ clearTimeout(timeoutId);
29
+ const entries = Array.isArray(result) ? result : (result?.result ?? []);
30
+ if (Array.isArray(entries)) {
31
+ cachedCustomConstraintTypes = entries;
32
+ TYPE_MANAGEMENT_TOOL_DEFINITIONS[TOOL_MANAGE_ATTRIBUTE_DEFINITION].description =
33
+ buildManageAttributeDefinitionDescription(cachedCustomConstraintTypes);
34
+ debugLogWithTag('TYPE_MANAGEMENT', `Primed custom constraint type cache with ${entries.length} entries`);
35
+ }
36
+ }
37
+ finally {
38
+ clearTimeout(timeoutId);
39
+ }
40
+ }
41
+ catch (error) {
42
+ debugLogWithTag('TYPE_MANAGEMENT', `Failed to prime custom constraint type cache: ${error instanceof Error ? error.message : String(error)}`);
43
+ cachedCustomConstraintTypes = null;
44
+ }
45
+ }
46
+ function appendCustomConstraintHintIfNeeded(errorText) {
47
+ const isUnknownType = errorText.includes('Unknown constraint type');
48
+ const isBadMultiplicity = errorText.includes('Multiplicity') && errorText.includes('not allowed');
49
+ if (isUnknownType || isBadMultiplicity) {
50
+ return (errorText +
51
+ '\n\nHint: call cplace_list_custom_constraint_types to see supported custom constraint names and their allowed multiplicities.');
52
+ }
53
+ return errorText;
54
+ }
7
55
  export const TYPE_MANAGEMENT_TOOL_DEFINITIONS = {
8
56
  [TOOL_MANAGE_TYPE_DEFINITION]: {
9
- description: "Create or update type definitions in a workspace with comprehensive configuration options. All properties from the enhanced read endpoint are available for both creation and updates to enable complete type configuration.",
57
+ description: 'Create or update type definitions in a workspace with comprehensive configuration options. All properties from the enhanced read endpoint are available for both creation and updates to enable complete type configuration.',
10
58
  inputSchema: {
11
- operation: z.enum(["create", "update"]).describe("Operation type: 'create' for new type definitions, 'update' for existing type definitions"),
12
- workspaceId: z.string().optional().describe("Required for both: Target workspace ID (e.g., 'abc123')"),
13
- typeInternalName: z.string().optional().describe("Type internal name (e.g., 'cf.example.myType') - no trailing dot (NOT `typeId` or `typeName`)"),
14
- localizedNames: z.record(z.string()).optional().describe("Localized type names (singular) - e.g., {\"en\": \"My Type\", \"de\": \"Mein Typ\"}"),
15
- localizedPlural: z.record(z.string()).optional().describe("Localized type names (plural) - e.g., {\"en\": \"My Types\", \"de\": \"Meine Typen\"}"),
16
- description: z.string().optional().describe("Type description"),
17
- showInExplorer: z.boolean().optional().describe("Whether to show in explorer (default: true for create)"),
18
- readers: z.array(z.string()).optional().describe("Create only: Reader principal IDs (e.g., ['person/user1', 'group/editors'])"),
19
- writers: z.array(z.string()).optional().describe("Create only: Writer principal IDs (e.g., ['person/user2'])"),
20
- readersAreDefault: z.boolean().optional().describe("Create only: Whether readers use default permissions"),
21
- writersAreDefault: z.boolean().optional().describe("Create only: Whether writers use default permissions"),
22
- editorsMayDeletePages: z.boolean().optional().describe("Whether editors can delete pages (default: false for create)"),
23
- showNewButton: z.boolean().optional().describe("Show 'New' button in UI (default: true for create)"),
24
- showInGlobalNewDialog: z.boolean().optional().describe("Include in global new dialog (default: true for create)"),
25
- showInGlobalSearch: z.boolean().optional().describe("Include in global search (default: true for create)"),
26
- namesAreUnique: z.boolean().optional().describe("Create only: Whether page names must be unique (default: false)"),
27
- enableIconLink: z.boolean().optional().describe("Enable icon linking (default: false for create)"),
28
- hideTabVersions: z.boolean().optional().describe("Hide versions tab (default: false for create)"),
29
- allowDivergentLayouts: z.boolean().optional().describe("Allow different layouts per page (default: false for create)"),
30
- iconName: z.string().optional().describe("FontAwesome icon name (e.g., 'fa-project', 'fa-list') or visual icon identifier for update"),
31
- nameGenerationPattern: z.string().optional().describe("Auto-naming pattern for pages of this type. When configured, page names can be auto-generated during creation. Angle-bracket DSL: `<attributeName>` for attribute values, `<#>` for sequential counter, `<#|numberFormat:\"0000\">` for zero-padded counter (zero-pad only via numberFormat filter, never via repeated `#`). Examples: `PROJ-<#>` → `PROJ-0`, `PROJ-1`; `PROJ-<#|numberFormat:\"000\">` → `PROJ-000`, `PROJ-001`; `<title>-<#|numberFormat:\"0000\">` → `ProjectAlpha-0001`. Pages can still override with explicit names. Leave empty to require explicit names."),
32
- displayNameGenerationPattern: z.string().optional().describe("Display name pattern for UI representation. Same angle-bracket DSL as nameGenerationPattern (`<attributeName>`, `<#>`, `<#|numberFormat:\"000\">`). Shown in UI, separate from internal page name. Cross-field rule: if this pattern uses the counter `<#>`, then nameGenerationPattern must also use `<#>` — backend validation rejects otherwise."),
33
- autocompleteDetailsPattern: z.string().optional().describe("Autocomplete display format. Angle-bracket DSL for attribute refs only (no counter — counters are instance-creation-time, autocomplete is display-only). Example: `<cf.myApp.title> - <cf.myApp.category>`. Tokens must be actual attribute internal names defined on the type."),
34
- internalAttributeNamePrefix: z.string().optional().describe("Prefix for attribute names (e.g., 'cf.mycompany.risk' - no trailing dot)"),
35
- localizedPageNamesMode: z.enum(["none", "optional", "optional_with_dialog", "mandatory"]).optional().describe("Localized naming mode")
59
+ operation: z
60
+ .enum(['create', 'update'])
61
+ .describe("Operation type: 'create' for new type definitions, 'update' for existing type definitions"),
62
+ workspaceId: z
63
+ .string()
64
+ .optional()
65
+ .describe("Required for both: Target workspace ID (e.g., 'abc123')"),
66
+ typeInternalName: z
67
+ .string()
68
+ .optional()
69
+ .describe("Type internal name (e.g., 'cf.example.myType') - no trailing dot (NOT `typeId` or `typeName`)"),
70
+ localizedNames: z
71
+ .record(z.string())
72
+ .optional()
73
+ .describe('Localized type names (singular) - e.g., {"en": "My Type", "de": "Mein Typ"}'),
74
+ localizedPlural: z
75
+ .record(z.string())
76
+ .optional()
77
+ .describe('Localized type names (plural) - e.g., {"en": "My Types", "de": "Meine Typen"}'),
78
+ description: z.string().optional().describe('Type description'),
79
+ showInExplorer: z
80
+ .boolean()
81
+ .optional()
82
+ .describe("Whether the type appears in the workspace navigation menu (UI label: 'Show in workspace navigation'). Default: false the type is hidden from workspace navigation unless this is set explicitly to true."),
83
+ readers: z
84
+ .array(z.string())
85
+ .optional()
86
+ .describe("Create only: Reader principal IDs (e.g., ['person/user1', 'group/editors'])"),
87
+ writers: z
88
+ .array(z.string())
89
+ .optional()
90
+ .describe("Create only: Writer principal IDs (e.g., ['person/user2'])"),
91
+ readersAreDefault: z
92
+ .boolean()
93
+ .optional()
94
+ .describe('Create only: Whether readers use default permissions'),
95
+ writersAreDefault: z
96
+ .boolean()
97
+ .optional()
98
+ .describe('Create only: Whether writers use default permissions'),
99
+ editorsMayDeletePages: z
100
+ .boolean()
101
+ .optional()
102
+ .describe('Whether editors can delete pages (default: false for create)'),
103
+ showNewButton: z
104
+ .boolean()
105
+ .optional()
106
+ .describe("Show 'New' button in UI (default: true for create)"),
107
+ showInGlobalNewDialog: z
108
+ .boolean()
109
+ .optional()
110
+ .describe('Include in global new dialog (default: true for create)'),
111
+ showInGlobalSearch: z
112
+ .boolean()
113
+ .optional()
114
+ .describe('Include in global search (default: true for create)'),
115
+ namesAreUnique: z
116
+ .boolean()
117
+ .optional()
118
+ .describe('Create only: Whether page names must be unique (default: false)'),
119
+ enableIconLink: z
120
+ .boolean()
121
+ .optional()
122
+ .describe('Enable icon linking (default: false for create)'),
123
+ hideTabVersions: z
124
+ .boolean()
125
+ .optional()
126
+ .describe('Hide versions tab (default: false for create)'),
127
+ allowDivergentLayouts: z
128
+ .boolean()
129
+ .optional()
130
+ .describe('Allow different layouts per page (default: false for create)'),
131
+ iconName: z
132
+ .string()
133
+ .optional()
134
+ .describe("FontAwesome icon name (e.g., 'fa-project', 'fa-list') or visual icon identifier for update"),
135
+ nameGenerationPattern: z
136
+ .string()
137
+ .optional()
138
+ .describe('Auto-naming pattern for pages of this type. When configured, page names can be auto-generated during creation. Angle-bracket DSL: `<attributeName>` for attribute values, `<#>` for sequential counter, `<#|numberFormat:"0000">` for zero-padded counter (zero-pad only via numberFormat filter, never via repeated `#`). Examples: `PROJ-<#>` → `PROJ-0`, `PROJ-1`; `PROJ-<#|numberFormat:"000">` → `PROJ-000`, `PROJ-001`; `<title>-<#|numberFormat:"0000">` → `ProjectAlpha-0001`. Pages can still override with explicit names. Leave empty to require explicit names.'),
139
+ displayNameGenerationPattern: z
140
+ .string()
141
+ .optional()
142
+ .describe('Display name pattern for UI representation. Same angle-bracket DSL as nameGenerationPattern (`<attributeName>`, `<#>`, `<#|numberFormat:"000">`). Shown in UI, separate from internal page name. Cross-field rule: if this pattern uses the counter `<#>`, then nameGenerationPattern must also use `<#>` — backend validation rejects otherwise.'),
143
+ autocompleteDetailsPattern: z
144
+ .string()
145
+ .optional()
146
+ .describe('Autocomplete display format. Angle-bracket DSL for attribute refs only (no counter — counters are instance-creation-time, autocomplete is display-only). Example: `<cf.myApp.title> - <cf.myApp.category>`. Tokens must be actual attribute internal names defined on the type.'),
147
+ internalAttributeNamePrefix: z
148
+ .string()
149
+ .optional()
150
+ .describe("Prefix for attribute names (e.g., 'cf.mycompany.risk' - no trailing dot)"),
151
+ localizedPageNamesMode: z
152
+ .enum(['none', 'optional', 'optional_with_dialog', 'mandatory'])
153
+ .optional()
154
+ .describe('Localized naming mode'),
36
155
  },
37
- annotations: { title: "Manage Type Definition" }
156
+ annotations: { title: 'Manage Type Definition' },
38
157
  },
39
158
  [TOOL_MANAGE_ATTRIBUTE_DEFINITION]: {
40
- description: "Create or update attribute definitions within existing type definitions. Supports all major constraint types including string, number, boolean, date, reference, enumeration, and specialized types like rich text and colors. Provides comprehensive configuration options for display properties, validation, and low-code integration.",
159
+ description: buildManageAttributeDefinitionDescription(cachedCustomConstraintTypes),
41
160
  inputSchema: {
42
- operation: z.enum(["create", "update"]).describe("Operation type: 'create' for new attribute definitions, 'update' for existing attribute definitions"),
161
+ operation: z
162
+ .enum(['create', 'update'])
163
+ .describe("Operation type: 'create' for new attribute definitions, 'update' for existing attribute definitions"),
43
164
  workspaceId: z.string().describe("Target workspace ID (e.g., 'abc123')"),
44
- typeInternalName: z.string().describe("Target type internal name (e.g., 'cf.example.myType') (NOT `typeId` or `typeName`)"),
45
- attributeName: z.string().describe("For create: short name (e.g., 'myAttribute') or full internal name — prefix auto-prepended if missing. For update: full internal name from create response (e.g., 'cf.cplace.myPlugin.myAttribute')"),
46
- multiplicity: z.enum(["exactlyOne", "maximalOne", "atLeastOne", "arbitrary"]).optional().describe("Required for create (except linkedAttribute where it must be omitted). Optional for update."),
47
- constraintConfig: z.object({
48
- constraintType: z.enum([
49
- "string", "longString", "richString", "localizedString",
50
- "number", "boolean", "date", "color", "reference",
51
- "textEnumeration", "numberEnumeration", "dynamicEnumeration", "workflow",
52
- "linkedAttribute"
53
- ]).describe("Constraint type. Note: linkedAttribute constraints cannot be updated via PATCH — delete and recreate instead."),
54
- pattern: z.string().optional().describe("Regex pattern for string validation"),
55
- patternErrorMessage: z.record(z.string()).optional().describe("Localized error messages for pattern validation"),
56
- precision: z.number().optional().describe("Decimal precision (-1 for unlimited)"),
57
- suffix: z.record(z.string()).optional().describe("Localized suffix text"),
58
- specificity: z.enum(["date", "datetime", "time"]).optional().describe("Date specificity"),
59
- withTime: z.boolean().optional().describe("Include time component"),
60
- dateFormat: z.string().optional().describe("Display format"),
61
- targetTypeNames: z.array(z.string()).optional().describe("Required for 'reference': Target type internal names (e.g., ['cf.example.targetType'])"),
62
- targetEntityKind: z.string().optional().describe("Target entity kind"),
63
- sameWorkspace: z.boolean().optional().describe("Restrict to same workspace"),
64
- isHierarchy: z.boolean().optional().describe("Whether this is a hierarchical reference"),
65
- inverseRoleName: z.record(z.string()).optional().describe("Localized inverse role name"),
66
- elements: z.array(z.object({
67
- value: z.string().describe("Enumeration value"),
68
- localizedName: z.record(z.string()).describe("Localized display names"),
69
- icon: z.string().optional().describe("Optional icon name")
70
- })).optional().describe("Required for 'textEnumeration'/'numberEnumeration': Enumeration elements"),
71
- providerClass: z.string().optional().describe("Provider class for dynamicEnumeration"),
72
- providerSimpleName: z.string().optional().describe("Provider simple name for dynamicEnumeration"),
73
- linkedReferenceName: z.string().optional().describe("Required for 'linkedAttribute': name of a reference attribute on the same type"),
74
- linkedPropertyName: z.string().optional().describe("Required for 'linkedAttribute': internal name of the property on the referenced type (e.g., 'cf.cplace.bo.name')")
75
- }).optional().describe("Required for create: Constraint configuration object. Optional for update: New constraint configuration object (replaces existing)."),
76
- localizedNames: z.record(z.string()).optional().describe("Localized attribute names - e.g., {\"en\": \"My Attribute\", \"de\": \"Mein Attribut\"}"),
77
- localizedShortNames: z.record(z.string()).optional().describe("Localized short names - e.g., {\"en\": \"My Attr\", \"de\": \"Mein Attr\"}"),
78
- localizedShortHelp: z.record(z.string()).optional().describe("Localized help text - e.g., {\"en\": \"Help text\", \"de\": \"Hilfetext\"}"),
79
- readOnly: z.boolean().optional().describe("Whether attribute is read-only"),
80
- showInTables: z.boolean().optional().describe("Show in table views"),
81
- showInNewDialog: z.boolean().optional().describe("Show in new item dialogs"),
82
- showValuesWithLineBreak: z.boolean().optional().describe("Display values with line breaks"),
83
- showInAttributesWidget: z.boolean().optional().describe("Show in attribute widgets"),
84
- showInColumnSelection: z.boolean().optional().describe("Include in column selection")
165
+ typeInternalName: z
166
+ .string()
167
+ .describe("Target type internal name (e.g., 'cf.example.myType') (NOT `typeId` or `typeName`)"),
168
+ attributeName: z
169
+ .string()
170
+ .describe("For create: short name (e.g., 'myAttribute') or full internal name — prefix auto-prepended if missing. For update: full internal name from create response (e.g., 'cf.cplace.myPlugin.myAttribute')"),
171
+ multiplicity: z
172
+ .enum(['exactlyOne', 'maximalOne', 'atLeastOne', 'arbitrary'])
173
+ .optional()
174
+ .describe('Required for create (except linkedAttribute where it must be omitted). Optional for update.'),
175
+ constraintConfig: z
176
+ .object({
177
+ constraintType: z
178
+ .string()
179
+ .describe("Built-in: 'string' | 'longString' | 'richString' | 'localizedString' | " +
180
+ "'number' | 'boolean' | 'date' | 'color' | 'reference' | 'textEnumeration'. " +
181
+ "Special: 'workflow', 'linkedAttribute'. " +
182
+ 'Custom constraints from installed plugins are also accepted by constraint name ' +
183
+ "(e.g. 'cf.cplace.timeBoundedValues.customAttributeType'). " +
184
+ 'Call cplace_list_custom_constraint_types to see installed custom constraints. ' +
185
+ 'Note: linkedAttribute constraints cannot be updated via PATCH — delete and recreate.'),
186
+ pattern: z.string().optional().describe('Regex pattern for string validation'),
187
+ patternErrorMessage: z
188
+ .record(z.string())
189
+ .optional()
190
+ .describe('Localized error messages for pattern validation'),
191
+ precision: z.number().optional().describe('Decimal precision (-1 for unlimited)'),
192
+ suffix: z.record(z.string()).optional().describe('Localized suffix text'),
193
+ specificity: z.enum(['date', 'datetime', 'time']).optional().describe('Date specificity'),
194
+ withTime: z.boolean().optional().describe('Include time component'),
195
+ dateFormat: z.string().optional().describe('Display format'),
196
+ targetTypeNames: z
197
+ .array(z.string())
198
+ .optional()
199
+ .describe("Required for 'reference': Target type internal names (e.g., ['cf.example.targetType'])"),
200
+ targetEntityKind: z.string().optional().describe('Target entity kind'),
201
+ sameWorkspace: z.boolean().optional().describe('Restrict to same workspace'),
202
+ isHierarchy: z.boolean().optional().describe('Whether this is a hierarchical reference'),
203
+ inverseRoleName: z.record(z.string()).optional().describe('Localized inverse role name'),
204
+ elements: z
205
+ .array(z.object({
206
+ value: z.string().describe('Enumeration value'),
207
+ localizedName: z.record(z.string()).describe('Localized display names'),
208
+ icon: z.string().optional().describe('Optional icon name'),
209
+ }))
210
+ .optional()
211
+ .describe("Required for 'textEnumeration'/'numberEnumeration': Enumeration elements"),
212
+ providerClass: z.string().optional().describe('Provider class for dynamicEnumeration'),
213
+ providerSimpleName: z
214
+ .string()
215
+ .optional()
216
+ .describe('Provider simple name for dynamicEnumeration'),
217
+ linkedReferenceName: z
218
+ .string()
219
+ .optional()
220
+ .describe("Required for 'linkedAttribute': name of a reference attribute on the same type"),
221
+ linkedPropertyName: z
222
+ .string()
223
+ .optional()
224
+ .describe("Required for 'linkedAttribute': internal name of the property on the referenced type (e.g., 'cf.cplace.bo.name')"),
225
+ })
226
+ .optional()
227
+ .describe('Required for create: Constraint configuration object. Optional for update: New constraint configuration object (replaces existing).'),
228
+ localizedNames: z
229
+ .record(z.string())
230
+ .optional()
231
+ .describe('Localized attribute names - e.g., {"en": "My Attribute", "de": "Mein Attribut"}'),
232
+ localizedShortNames: z
233
+ .record(z.string())
234
+ .optional()
235
+ .describe('Localized short names - e.g., {"en": "My Attr", "de": "Mein Attr"}'),
236
+ localizedShortHelp: z
237
+ .record(z.string())
238
+ .optional()
239
+ .describe('Localized help text - e.g., {"en": "Help text", "de": "Hilfetext"}'),
240
+ readOnly: z.boolean().optional().describe('Whether attribute is read-only'),
241
+ showInTables: z.boolean().optional().describe('Show in table views'),
242
+ showInNewDialog: z.boolean().optional().describe('Show in new item dialogs'),
243
+ showValuesWithLineBreak: z.boolean().optional().describe('Display values with line breaks'),
244
+ showInAttributesWidget: z.boolean().optional().describe('Show in attribute widgets'),
245
+ showInColumnSelection: z.boolean().optional().describe('Include in column selection'),
85
246
  },
86
- annotations: { title: "Manage Attribute Definition" }
247
+ annotations: { title: 'Manage Attribute Definition' },
87
248
  },
88
249
  [TOOL_DELETE_TYPE_DEFINITION]: {
89
250
  description: "Delete a type definition and all its attributes, validators, change listeners, and alternative layouts. Cannot delete types that have existing pages or are referenced by other types' attributes.",
90
251
  inputSchema: {
91
- workspaceId: z.string().describe("ID of the workspace containing the type (e.g., 'workspace/abc123')"),
92
- typeInternalName: z.string().describe("Internal name of the type definition to delete (e.g., 'cf.example.Task') (NOT `typeId` or `typeName`)")
252
+ workspaceId: z
253
+ .string()
254
+ .describe("ID of the workspace containing the type (e.g., 'workspace/abc123')"),
255
+ typeInternalName: z
256
+ .string()
257
+ .describe("Internal name of the type definition to delete (e.g., 'cf.example.Task') (NOT `typeId` or `typeName`)"),
93
258
  },
94
- annotations: { title: "Delete Type Definition" }
259
+ annotations: { title: 'Delete Type Definition' },
95
260
  },
96
261
  [TOOL_DELETE_ATTRIBUTE_DEFINITION]: {
97
- description: "Delete an attribute definition from a type. Cannot delete attributes referenced by validators or change listeners — delete those first.",
262
+ description: 'Delete an attribute definition from a type. Cannot delete attributes referenced by validators or change listeners — delete those first.',
98
263
  inputSchema: {
99
- workspaceId: z.string().describe("ID of the workspace containing the type (e.g., 'workspace/abc123')"),
100
- typeInternalName: z.string().describe("Internal name of the type definition (e.g., 'cf.example.Task') (NOT `typeId` or `typeName`)"),
101
- attributeName: z.string().describe("Internal name of the attribute to delete (e.g., 'cf.cplace.myPlugin.myAttribute')")
264
+ workspaceId: z
265
+ .string()
266
+ .describe("ID of the workspace containing the type (e.g., 'workspace/abc123')"),
267
+ typeInternalName: z
268
+ .string()
269
+ .describe("Internal name of the type definition (e.g., 'cf.example.Task') (NOT `typeId` or `typeName`)"),
270
+ attributeName: z
271
+ .string()
272
+ .describe("Internal name of the attribute to delete (e.g., 'cf.cplace.myPlugin.myAttribute')"),
102
273
  },
103
- annotations: { title: "Delete Attribute Definition" }
104
- }
274
+ annotations: { title: 'Delete Attribute Definition' },
275
+ },
276
+ [TOOL_LIST_CUSTOM_CONSTRAINT_TYPES]: {
277
+ description: "List custom constraint types registered by installed plugins. Returns each constraint's name, allowed multiplicities, and display name. Use the returned names as the 'constraintType' value when creating attributes with cplace_manage_attribute_definition.",
278
+ inputSchema: {},
279
+ annotations: { title: 'List Custom Constraint Types' },
280
+ },
105
281
  };
106
282
  export function registerTypeManagementTools(server, client) {
107
283
  server.registerTool(TOOL_MANAGE_TYPE_DEFINITION, TYPE_MANAGEMENT_TOOL_DEFINITIONS[TOOL_MANAGE_TYPE_DEFINITION], async (params) => {
108
284
  try {
109
- if (params.operation === "create") {
285
+ if (params.operation === 'create') {
110
286
  if (!params.workspaceId || !params.typeInternalName) {
111
287
  return {
112
- content: [{ type: "text", text: "Error: Create operation requires workspaceId and typeInternalName parameters" }],
113
- isError: true
288
+ content: [
289
+ {
290
+ type: 'text',
291
+ text: 'Error: Create operation requires workspaceId and typeInternalName parameters',
292
+ },
293
+ ],
294
+ isError: true,
114
295
  };
115
296
  }
116
297
  debugLogWithTag('TYPE_CREATION', `Creating type definition: ${params.typeInternalName} in workspace: ${params.workspaceId}`);
117
298
  const requestBody = {
118
299
  workspaceId: params.workspaceId,
119
- internalName: params.typeInternalName
300
+ internalName: params.typeInternalName,
120
301
  };
121
302
  if (params.localizedNames)
122
303
  requestBody.localizedNames = params.localizedNames;
@@ -124,8 +305,7 @@ export function registerTypeManagementTools(server, client) {
124
305
  requestBody.localizedPlural = params.localizedPlural;
125
306
  if (params.description)
126
307
  requestBody.description = params.description;
127
- if (params.showInExplorer !== undefined)
128
- requestBody.showInExplorer = params.showInExplorer;
308
+ requestBody.showInExplorer = params.showInExplorer ?? false;
129
309
  if (params.readers)
130
310
  requestBody.readers = params.readers;
131
311
  if (params.writers)
@@ -165,20 +345,25 @@ export function registerTypeManagementTools(server, client) {
165
345
  const result = await client.makeApiRequest('json/type-definition', 'POST', undefined, requestBody);
166
346
  debugLogWithTag('TYPE_CREATION', `Successfully created type definition: ${params.typeInternalName}`);
167
347
  return {
168
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
348
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
169
349
  };
170
350
  }
171
351
  else {
172
352
  if (!params.workspaceId || !params.typeInternalName) {
173
353
  return {
174
- content: [{ type: "text", text: "Error: Update operation requires workspaceId and typeInternalName parameters" }],
175
- isError: true
354
+ content: [
355
+ {
356
+ type: 'text',
357
+ text: 'Error: Update operation requires workspaceId and typeInternalName parameters',
358
+ },
359
+ ],
360
+ isError: true,
176
361
  };
177
362
  }
178
363
  debugLogWithTag('TYPE_UPDATE', `Updating type definition: ${params.typeInternalName} in workspace: ${params.workspaceId}`);
179
364
  const requestBody = {
180
365
  workspaceId: params.workspaceId,
181
- typeInternalName: params.typeInternalName
366
+ typeInternalName: params.typeInternalName,
182
367
  };
183
368
  if (params.localizedNames)
184
369
  requestBody.localizedNames = params.localizedNames;
@@ -217,54 +402,94 @@ export function registerTypeManagementTools(server, client) {
217
402
  const result = await client.makeApiRequest('json/type-definition', 'PATCH', undefined, requestBody);
218
403
  debugLogWithTag('TYPE_UPDATE', `Successfully updated type definition: ${params.typeInternalName}`);
219
404
  return {
220
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
405
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
221
406
  };
222
407
  }
223
408
  }
224
409
  catch (error) {
225
- const operationText = params.operation === "create" ? "creating" : "updating";
226
- debugLogWithTag(params.operation === "create" ? 'TYPE_CREATION' : 'TYPE_UPDATE', `Error ${operationText} type definition: ${error instanceof Error ? error.message : String(error)}`);
410
+ const operationText = params.operation === 'create' ? 'creating' : 'updating';
411
+ debugLogWithTag(params.operation === 'create' ? 'TYPE_CREATION' : 'TYPE_UPDATE', `Error ${operationText} type definition: ${error instanceof Error ? error.message : String(error)}`);
227
412
  return {
228
- content: [{
229
- type: "text",
230
- text: `Error ${operationText} type definition: ${error instanceof Error ? error.message : String(error)}`
231
- }],
232
- isError: true
413
+ content: [
414
+ {
415
+ type: 'text',
416
+ text: `Error ${operationText} type definition: ${error instanceof Error ? error.message : String(error)}`,
417
+ },
418
+ ],
419
+ isError: true,
233
420
  };
234
421
  }
235
422
  });
236
423
  server.registerTool(TOOL_MANAGE_ATTRIBUTE_DEFINITION, TYPE_MANAGEMENT_TOOL_DEFINITIONS[TOOL_MANAGE_ATTRIBUTE_DEFINITION], async (params) => {
237
424
  try {
238
- if (params.operation === "create") {
239
- if (!params.workspaceId || !params.typeInternalName || !params.attributeName || !params.constraintConfig) {
425
+ if (params.operation === 'create') {
426
+ if (!params.workspaceId ||
427
+ !params.typeInternalName ||
428
+ !params.attributeName ||
429
+ !params.constraintConfig) {
240
430
  return {
241
- content: [{ type: "text", text: "Error: Create operation requires workspaceId, typeInternalName, attributeName, and constraintConfig parameters" }],
242
- isError: true
431
+ content: [
432
+ {
433
+ type: 'text',
434
+ text: 'Error: Create operation requires workspaceId, typeInternalName, attributeName, and constraintConfig parameters',
435
+ },
436
+ ],
437
+ isError: true,
438
+ };
439
+ }
440
+ if (params.constraintConfig.additionalConstraintData !== undefined) {
441
+ return {
442
+ content: [
443
+ {
444
+ type: 'text',
445
+ text: 'Error: additionalConstraintData is not supported for custom constraint types in this version.',
446
+ },
447
+ ],
448
+ isError: true,
243
449
  };
244
450
  }
245
451
  const ct = params.constraintConfig.constraintType;
246
- if (ct === "reference") {
247
- const isPersonReference = params.constraintConfig.targetEntityKind === "person";
248
- if (!isPersonReference && (!params.constraintConfig.targetTypeNames || params.constraintConfig.targetTypeNames.length === 0)) {
452
+ if (ct === 'reference') {
453
+ const isPersonReference = params.constraintConfig.targetEntityKind === 'person';
454
+ if (!isPersonReference &&
455
+ (!params.constraintConfig.targetTypeNames ||
456
+ params.constraintConfig.targetTypeNames.length === 0)) {
249
457
  return {
250
- content: [{ type: "text", text: "Error: Reference attributes require 'targetTypeNames' in constraintConfig (e.g., [\"cf.example.targetType\"]). Without it, the attribute defaults to 'any content type'." }],
251
- isError: true
458
+ content: [
459
+ {
460
+ type: 'text',
461
+ text: "Error: Reference attributes require 'targetTypeNames' in constraintConfig (e.g., [\"cf.example.targetType\"]). Without it, the attribute defaults to 'any content type'.",
462
+ },
463
+ ],
464
+ isError: true,
252
465
  };
253
466
  }
254
467
  }
255
- if (ct === "textEnumeration" || ct === "numberEnumeration") {
256
- if (!params.constraintConfig.elements || params.constraintConfig.elements.length === 0) {
468
+ if (ct === 'textEnumeration' || ct === 'numberEnumeration') {
469
+ if (!params.constraintConfig.elements ||
470
+ params.constraintConfig.elements.length === 0) {
257
471
  return {
258
- content: [{ type: "text", text: "Error: Enumeration attributes require 'elements' in constraintConfig with at least one element." }],
259
- isError: true
472
+ content: [
473
+ {
474
+ type: 'text',
475
+ text: "Error: Enumeration attributes require 'elements' in constraintConfig with at least one element.",
476
+ },
477
+ ],
478
+ isError: true,
260
479
  };
261
480
  }
262
481
  }
263
- if (ct === "linkedAttribute") {
264
- if (!params.constraintConfig.linkedReferenceName || !params.constraintConfig.linkedPropertyName) {
482
+ if (ct === 'linkedAttribute') {
483
+ if (!params.constraintConfig.linkedReferenceName ||
484
+ !params.constraintConfig.linkedPropertyName) {
265
485
  return {
266
- content: [{ type: "text", text: "Error: Linked attributes require both 'linkedReferenceName' and 'linkedPropertyName' in constraintConfig." }],
267
- isError: true
486
+ content: [
487
+ {
488
+ type: 'text',
489
+ text: "Error: Linked attributes require both 'linkedReferenceName' and 'linkedPropertyName' in constraintConfig.",
490
+ },
491
+ ],
492
+ isError: true,
268
493
  };
269
494
  }
270
495
  }
@@ -273,7 +498,7 @@ export function registerTypeManagementTools(server, client) {
273
498
  workspaceId: params.workspaceId,
274
499
  typeDefinitionInternalName: params.typeInternalName,
275
500
  attributeName: params.attributeName,
276
- constraintConfig: params.constraintConfig
501
+ constraintConfig: params.constraintConfig,
277
502
  };
278
503
  if (params.multiplicity)
279
504
  requestBody.multiplicity = params.multiplicity;
@@ -298,21 +523,38 @@ export function registerTypeManagementTools(server, client) {
298
523
  const result = await client.makeApiRequest('json/attribute-definition', 'POST', undefined, requestBody);
299
524
  debugLogWithTag('ATTRIBUTE_CREATION', `Successfully created attribute: ${params.attributeName}`);
300
525
  return {
301
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
526
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
302
527
  };
303
528
  }
304
529
  else {
305
530
  if (!params.workspaceId || !params.typeInternalName || !params.attributeName) {
306
531
  return {
307
- content: [{ type: "text", text: "Error: Update operation requires workspaceId, typeInternalName and attributeName parameters" }],
308
- isError: true
532
+ content: [
533
+ {
534
+ type: 'text',
535
+ text: 'Error: Update operation requires workspaceId, typeInternalName and attributeName parameters',
536
+ },
537
+ ],
538
+ isError: true,
539
+ };
540
+ }
541
+ if (params.constraintConfig &&
542
+ params.constraintConfig.additionalConstraintData !== undefined) {
543
+ return {
544
+ content: [
545
+ {
546
+ type: 'text',
547
+ text: 'Error: additionalConstraintData is not supported for custom constraint types in this version.',
548
+ },
549
+ ],
550
+ isError: true,
309
551
  };
310
552
  }
311
553
  debugLogWithTag('ATTRIBUTE_UPDATE', `Updating attribute: ${params.attributeName} for type: ${params.typeInternalName} in workspace: ${params.workspaceId}`);
312
554
  const requestBody = {
313
555
  workspaceId: params.workspaceId,
314
556
  typeDefinitionInternalName: params.typeInternalName,
315
- attributeName: params.attributeName
557
+ attributeName: params.attributeName,
316
558
  };
317
559
  if (params.multiplicity)
318
560
  requestBody.multiplicity = params.multiplicity;
@@ -339,19 +581,39 @@ export function registerTypeManagementTools(server, client) {
339
581
  const result = await client.makeApiRequest('json/attribute-definition', 'PATCH', undefined, requestBody);
340
582
  debugLogWithTag('ATTRIBUTE_UPDATE', `Successfully updated attribute: ${params.attributeName}`);
341
583
  return {
342
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
584
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
343
585
  };
344
586
  }
345
587
  }
346
588
  catch (error) {
347
- const operationText = params.operation === "create" ? "creating" : "updating";
348
- debugLogWithTag(params.operation === "create" ? 'ATTRIBUTE_CREATION' : 'ATTRIBUTE_UPDATE', `Error ${operationText} attribute: ${error instanceof Error ? error.message : String(error)}`);
589
+ const operationText = params.operation === 'create' ? 'creating' : 'updating';
590
+ debugLogWithTag(params.operation === 'create' ? 'ATTRIBUTE_CREATION' : 'ATTRIBUTE_UPDATE', `Error ${operationText} attribute: ${error instanceof Error ? error.message : String(error)}`);
591
+ const rawText = `Error ${operationText} attribute definition: ${error instanceof Error ? error.message : String(error)}`;
349
592
  return {
350
- content: [{
351
- type: "text",
352
- text: `Error ${operationText} attribute definition: ${error instanceof Error ? error.message : String(error)}`
353
- }],
354
- isError: true
593
+ content: [
594
+ {
595
+ type: 'text',
596
+ text: appendCustomConstraintHintIfNeeded(rawText),
597
+ },
598
+ ],
599
+ isError: true,
600
+ };
601
+ }
602
+ });
603
+ server.registerTool(TOOL_LIST_CUSTOM_CONSTRAINT_TYPES, TYPE_MANAGEMENT_TOOL_DEFINITIONS[TOOL_LIST_CUSTOM_CONSTRAINT_TYPES], async () => {
604
+ try {
605
+ const result = await client.makeApiRequest('json/custom-constraint-types', 'GET');
606
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
607
+ }
608
+ catch (error) {
609
+ return {
610
+ content: [
611
+ {
612
+ type: 'text',
613
+ text: `Error listing custom constraint types: ${error instanceof Error ? error.message : String(error)}`,
614
+ },
615
+ ],
616
+ isError: true,
355
617
  };
356
618
  }
357
619
  });
@@ -360,17 +622,22 @@ export function registerTypeManagementTools(server, client) {
360
622
  try {
361
623
  const result = await client.makeApiRequest('json/type-definition', 'DELETE', {
362
624
  workspaceId,
363
- typeDefinitionInternalName: typeInternalName
625
+ typeDefinitionInternalName: typeInternalName,
364
626
  });
365
627
  debugLogWithTag('TYPE_DELETE', `Successfully deleted type definition '${typeInternalName}'`);
366
628
  return {
367
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
629
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
368
630
  };
369
631
  }
370
632
  catch (error) {
371
633
  return {
372
- content: [{ type: "text", text: `Error deleting type definition: ${error instanceof Error ? error.message : String(error)}` }],
373
- isError: true
634
+ content: [
635
+ {
636
+ type: 'text',
637
+ text: `Error deleting type definition: ${error instanceof Error ? error.message : String(error)}`,
638
+ },
639
+ ],
640
+ isError: true,
374
641
  };
375
642
  }
376
643
  });
@@ -380,17 +647,22 @@ export function registerTypeManagementTools(server, client) {
380
647
  const result = await client.makeApiRequest('json/attribute-definition', 'DELETE', {
381
648
  workspaceId,
382
649
  typeDefinitionInternalName: typeInternalName,
383
- attributeName
650
+ attributeName,
384
651
  });
385
652
  debugLogWithTag('ATTRIBUTE_DELETE', `Successfully deleted attribute '${attributeName}'`);
386
653
  return {
387
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
654
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
388
655
  };
389
656
  }
390
657
  catch (error) {
391
658
  return {
392
- content: [{ type: "text", text: `Error deleting attribute definition: ${error instanceof Error ? error.message : String(error)}` }],
393
- isError: true
659
+ content: [
660
+ {
661
+ type: 'text',
662
+ text: `Error deleting attribute definition: ${error instanceof Error ? error.message : String(error)}`,
663
+ },
664
+ ],
665
+ isError: true,
394
666
  };
395
667
  }
396
668
  });