@cplace/test-mcp-server 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -65
- package/dist/api.d.ts +10 -10
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +31 -4
- package/dist/api.js.map +1 -1
- package/dist/csvUtils.js +1 -1
- package/dist/csvUtils.js.map +1 -1
- package/dist/index.js +597 -40
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.js +7 -7
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,19 +13,19 @@ import { convertPagesToCsv } from "./csvUtils.js";
|
|
|
13
13
|
dotenv.config();
|
|
14
14
|
const config = {
|
|
15
15
|
url: process.env.CPLACE_URL || '',
|
|
16
|
-
apiToken: process.env.API_TOKEN || ''
|
|
16
|
+
apiToken: process.env.API_TOKEN || '',
|
|
17
|
+
registerSystemInfoTool: process.env.REGISTER_SYSTEM_INFO_TOOL === 'true' || false,
|
|
17
18
|
};
|
|
18
19
|
const client = new CplaceApiClient(config);
|
|
19
|
-
const REGISTER_SYSTEM_INFO_TOOL = false;
|
|
20
20
|
const server = new McpServer({
|
|
21
21
|
name: "cplace-mcp-server",
|
|
22
22
|
version: "1.0.0"
|
|
23
23
|
});
|
|
24
|
-
if (
|
|
25
|
-
server.registerTool("
|
|
24
|
+
if (config.registerSystemInfoTool) {
|
|
25
|
+
server.registerTool("cplace_get_system_info", {
|
|
26
26
|
description: "Get system information about the MCP server - including current working directory, CPLACE_URL setting, and debug state",
|
|
27
27
|
inputSchema: {},
|
|
28
|
-
annotations: { title: "System Information" }
|
|
28
|
+
annotations: { title: "Get System Information" }
|
|
29
29
|
}, async () => {
|
|
30
30
|
const systemInfo = {
|
|
31
31
|
currentWorkingDirectory: process.cwd(),
|
|
@@ -66,12 +66,12 @@ server.registerTool("cplace_list_workspaces", {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
|
-
server.registerTool("
|
|
70
|
-
description: "
|
|
69
|
+
server.registerTool("cplace_list_types", {
|
|
70
|
+
description: "List all types available in a workspace",
|
|
71
71
|
inputSchema: {
|
|
72
72
|
workspaceId: z.string().describe("The ID of the workspace to get types for")
|
|
73
73
|
},
|
|
74
|
-
annotations: { title: "
|
|
74
|
+
annotations: { title: "List Types" }
|
|
75
75
|
}, async ({ workspaceId }) => {
|
|
76
76
|
try {
|
|
77
77
|
const workspaces = await client.makeApiRequest('json/workspaces');
|
|
@@ -115,6 +115,58 @@ server.registerTool("cplace_get_type_datamodel", {
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
|
+
server.registerTool("cplace_get_type_incoming_references", {
|
|
119
|
+
description: "Get comprehensive information about all incoming references to a specific type definition. Identifies all attributes from other types that can reference pages of the target type, including custom attributes and built-in attributes.",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
workspaceId: z.string().describe("The ID of the workspace containing the target type definition"),
|
|
122
|
+
internalName: z.string().describe("The internal name of the target type definition")
|
|
123
|
+
},
|
|
124
|
+
annotations: { title: "Get Type Incoming References" }
|
|
125
|
+
}, async ({ workspaceId, internalName }) => {
|
|
126
|
+
debugLogWithTag('TYPE_REFS', `Starting incoming references request for type: ${internalName} in workspace: ${workspaceId}`);
|
|
127
|
+
try {
|
|
128
|
+
const result = await client.makeApiRequest('json/type/incoming-references', 'GET', {
|
|
129
|
+
workspaceId,
|
|
130
|
+
internalName
|
|
131
|
+
});
|
|
132
|
+
debugLogWithTag('TYPE_REFS', `Retrieved ${result.count || 0} incoming references for type: ${internalName}`);
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
debugLogWithTag('TYPE_REFS', `Error retrieving incoming references: ${error instanceof Error ? error.message : String(error)}`);
|
|
139
|
+
return {
|
|
140
|
+
content: [{ type: "text", text: `Error retrieving type incoming references: ${error instanceof Error ? error.message : String(error)}` }]
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
server.registerTool("cplace_get_page_incoming_references", {
|
|
145
|
+
description: "Get comprehensive information about all incoming references to a specific page. Identifies all pages that reference the target page through specific attributes, providing detailed information about the referencing pages and the attributes used for the references.",
|
|
146
|
+
inputSchema: {
|
|
147
|
+
pageUID: z.string().describe("The unique identifier (UID) of the target page"),
|
|
148
|
+
includeReferences: z.string().describe("JSON string specifying which references to include. Must be a JSON array containing objects with 'sourceType' and 'attributeName' properties, e.g. '[{\"sourceType\":\"cf.example.Project\",\"attributeName\":\"relatedTask\"}]'")
|
|
149
|
+
},
|
|
150
|
+
annotations: { title: "Get Page Incoming References" }
|
|
151
|
+
}, async ({ pageUID, includeReferences }) => {
|
|
152
|
+
debugLogWithTag('PAGE_REFS', `Starting incoming references request for page: ${pageUID}`);
|
|
153
|
+
try {
|
|
154
|
+
const result = await client.makeApiRequest('json/page/incoming-references', 'GET', {
|
|
155
|
+
pageUID,
|
|
156
|
+
includeReferences
|
|
157
|
+
});
|
|
158
|
+
debugLogWithTag('PAGE_REFS', `Retrieved ${result.totalCount || 0} incoming references for page: ${pageUID}`);
|
|
159
|
+
return {
|
|
160
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
debugLogWithTag('PAGE_REFS', `Error retrieving incoming references: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: "text", text: `Error retrieving page incoming references: ${error instanceof Error ? error.message : String(error)}` }]
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
});
|
|
118
170
|
server.registerTool("cplace_get_page_by_id", {
|
|
119
171
|
description: "Get comprehensive page information including relationships and metadata",
|
|
120
172
|
inputSchema: {
|
|
@@ -123,7 +175,7 @@ server.registerTool("cplace_get_page_by_id", {
|
|
|
123
175
|
annotations: { title: "Get Page by ID" }
|
|
124
176
|
}, async ({ id }) => {
|
|
125
177
|
try {
|
|
126
|
-
const result = await client.makeApiRequest('json/page', 'GET', { id });
|
|
178
|
+
const result = await client.makeApiRequest('json/page', 'GET', { pageUID: id });
|
|
127
179
|
return {
|
|
128
180
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
129
181
|
};
|
|
@@ -153,12 +205,12 @@ server.registerTool("cplace_get_person_by_id", {
|
|
|
153
205
|
};
|
|
154
206
|
}
|
|
155
207
|
});
|
|
156
|
-
server.registerTool("
|
|
157
|
-
description: "
|
|
208
|
+
server.registerTool("cplace_get_person_by_name", {
|
|
209
|
+
description: "Get details about a person by searching for their name.",
|
|
158
210
|
inputSchema: {
|
|
159
211
|
name: z.string().describe("The name of the person or part of the name to search for"),
|
|
160
212
|
},
|
|
161
|
-
annotations: { title: "Get Person by
|
|
213
|
+
annotations: { title: "Get Person by Name" }
|
|
162
214
|
}, async ({ name }) => {
|
|
163
215
|
try {
|
|
164
216
|
const result = await client.makeApiRequest('json/person', 'GET', { name });
|
|
@@ -284,7 +336,8 @@ Empty/not empty checks:
|
|
|
284
336
|
offset: result.pagination?.offset || offset,
|
|
285
337
|
hasMore: result.pagination?.hasMore || false
|
|
286
338
|
},
|
|
287
|
-
humanReadableRepresentation: result.summary
|
|
339
|
+
humanReadableRepresentation: result.summary,
|
|
340
|
+
cplaceJson: result.cplaceJson
|
|
288
341
|
};
|
|
289
342
|
return {
|
|
290
343
|
content: [{ type: "text", text: JSON.stringify(filteredResult, null, 2) }]
|
|
@@ -297,15 +350,15 @@ Empty/not empty checks:
|
|
|
297
350
|
};
|
|
298
351
|
}
|
|
299
352
|
});
|
|
300
|
-
server.registerTool("
|
|
301
|
-
description: "Make a fulltext search across all pages in cplace. Use this
|
|
353
|
+
server.registerTool("cplace_search_pages_fulltext", {
|
|
354
|
+
description: "Make a fulltext search across all pages in cplace. Use this when searching for text content within pages.",
|
|
302
355
|
inputSchema: {
|
|
303
356
|
workspaceId: z.string().optional().describe("The ID of the workspace to search in. If not provided, searches across all accessible workspaces."),
|
|
304
|
-
fulltext: z.string().describe("The fulltext search query to filter pages by. The results will include pages that
|
|
357
|
+
fulltext: z.string().describe("The fulltext search query to filter pages by. The results will include pages that contain this string in their name, attributes, or content."),
|
|
305
358
|
limit: z.number().min(1).max(1000).default(50).describe("Maximum number of results to return (1-1000)"),
|
|
306
359
|
offset: z.number().min(0).max(10000).default(0).describe("Number of results to skip for pagination, cannot be larger than 10000"),
|
|
307
360
|
},
|
|
308
|
-
annotations: { title: "Search Pages" }
|
|
361
|
+
annotations: { title: "Search Pages by Fulltext" }
|
|
309
362
|
}, async ({ workspaceId, fulltext, limit = 50, offset = 0, }) => {
|
|
310
363
|
if (!fulltext) {
|
|
311
364
|
return {
|
|
@@ -333,7 +386,8 @@ server.registerTool("cplace_fulltext_search", {
|
|
|
333
386
|
offset: result.pagination?.offset || offset,
|
|
334
387
|
hasMore: result.pagination?.hasMore || false
|
|
335
388
|
},
|
|
336
|
-
summary: result.summary
|
|
389
|
+
summary: result.summary,
|
|
390
|
+
cplaceJson: result.cplaceJson
|
|
337
391
|
};
|
|
338
392
|
return {
|
|
339
393
|
content: [{ type: "text", text: JSON.stringify(filteredResult, null, 2) }]
|
|
@@ -345,15 +399,15 @@ server.registerTool("cplace_fulltext_search", {
|
|
|
345
399
|
};
|
|
346
400
|
}
|
|
347
401
|
});
|
|
348
|
-
server.registerTool("
|
|
349
|
-
description: "
|
|
402
|
+
server.registerTool("cplace_list_pages_of_type", {
|
|
403
|
+
description: "List all pages of a specific type in a workspace in cplace. Use this to retrieve multiple pages of the same type.",
|
|
350
404
|
inputSchema: {
|
|
351
405
|
workspaceId: z.string().describe("The ID of the workspace to get pages from"),
|
|
352
406
|
typeName: z.string().describe("The internal name of the type to retrieve pages for"),
|
|
353
407
|
limit: z.number().min(1).max(1000).default(50).describe("Maximum number of results to return (1-1000)"),
|
|
354
408
|
offset: z.number().min(0).max(10000).default(0).describe("Number of results to skip for pagination, cannot be larger than 10000"),
|
|
355
409
|
},
|
|
356
|
-
annotations: { title: "
|
|
410
|
+
annotations: { title: "List Pages of Type" }
|
|
357
411
|
}, async ({ workspaceId, typeName, limit = 50, offset = 0, }) => {
|
|
358
412
|
try {
|
|
359
413
|
const cplaceFilter = {
|
|
@@ -448,14 +502,19 @@ server.registerTool("cplace_search_pages_csv", {
|
|
|
448
502
|
}
|
|
449
503
|
});
|
|
450
504
|
server.registerTool("cplace_list_widget_definitions", {
|
|
451
|
-
description: "Get a list of all available widget definitions in the system with their basic metadata including names, descriptions, and apps",
|
|
452
|
-
inputSchema: {
|
|
505
|
+
description: "Get a list of all available widget definitions in the system that support the specified embedding context, with their basic metadata including names, descriptions, and apps",
|
|
506
|
+
inputSchema: {
|
|
507
|
+
embeddingContext: z.enum(["AS_WIDGET", "INSIDE_RICHSTRING", "INSIDE_WIDGET"]).default("AS_WIDGET").describe(`Filter widgets by embedding context support:
|
|
508
|
+
- AS_WIDGET (default): Widgets that support full widget embedding with frame and title
|
|
509
|
+
- INSIDE_RICHSTRING: Widgets that can be embedded in rich text content without frame
|
|
510
|
+
- INSIDE_WIDGET: Widgets that can be embedded inside other widgets without frame`)
|
|
511
|
+
},
|
|
453
512
|
annotations: { title: "List Widget Definitions" }
|
|
454
|
-
}, async () => {
|
|
455
|
-
debugLogWithTag('WIDGETS',
|
|
513
|
+
}, async ({ embeddingContext = "AS_WIDGET" }) => {
|
|
514
|
+
debugLogWithTag('WIDGETS', `Starting widget definitions list request with embeddingContext: ${embeddingContext}`);
|
|
456
515
|
try {
|
|
457
|
-
const result = await client.makeApiRequest('json/widget-definitions');
|
|
458
|
-
debugLogWithTag('WIDGETS', `Retrieved widget definitions`);
|
|
516
|
+
const result = await client.makeApiRequest('json/widget-definitions', 'GET', { embeddingContext });
|
|
517
|
+
debugLogWithTag('WIDGETS', `Retrieved widget definitions for context: ${embeddingContext}`);
|
|
459
518
|
return {
|
|
460
519
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
461
520
|
};
|
|
@@ -490,13 +549,13 @@ server.registerTool("cplace_get_widget_definition", {
|
|
|
490
549
|
server.registerTool("cplace_get_page_layout_overview", {
|
|
491
550
|
description: "Get the high-level layout structure of a page including rows, columns, and widget summaries. Provides an overview of the page layout grid without detailed widget configurations.",
|
|
492
551
|
inputSchema: {
|
|
493
|
-
|
|
552
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page to get layout for, e.g. 'page/kkt8ol745jqur4581kelm5ply'")
|
|
494
553
|
},
|
|
495
554
|
annotations: { title: "Get Page Layout Overview" }
|
|
496
|
-
}, async ({
|
|
497
|
-
debugLogWithTag('LAYOUT', `Starting page layout overview request for: ${
|
|
555
|
+
}, async ({ pageUID }) => {
|
|
556
|
+
debugLogWithTag('LAYOUT', `Starting page layout overview request for: ${pageUID}`);
|
|
498
557
|
try {
|
|
499
|
-
const result = await client.makeApiRequest('json/pageLayout', 'GET', {
|
|
558
|
+
const result = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
500
559
|
const overview = {
|
|
501
560
|
rows: result.rows?.map((row, rowIndex) => ({
|
|
502
561
|
rowIndex,
|
|
@@ -511,28 +570,28 @@ server.registerTool("cplace_get_page_layout_overview", {
|
|
|
511
570
|
})) || []
|
|
512
571
|
})) || []
|
|
513
572
|
};
|
|
514
|
-
debugLogWithTag('LAYOUT', `Retrieved layout overview for: ${
|
|
573
|
+
debugLogWithTag('LAYOUT', `Retrieved page layout overview for: ${pageUID}`);
|
|
515
574
|
return {
|
|
516
575
|
content: [{ type: "text", text: JSON.stringify(overview, null, 2) }]
|
|
517
576
|
};
|
|
518
577
|
}
|
|
519
578
|
catch (error) {
|
|
520
579
|
return {
|
|
521
|
-
content: [{ type: "text", text: `Error retrieving page layout overview for ${
|
|
580
|
+
content: [{ type: "text", text: `Error retrieving page layout overview for ${pageUID}: ${error instanceof Error ? error.message : String(error)}` }]
|
|
522
581
|
};
|
|
523
582
|
}
|
|
524
583
|
});
|
|
525
584
|
server.registerTool("cplace_get_widget_details", {
|
|
526
585
|
description: "Get detailed configuration for a specific widget within a page layout. Use this after cplace_get_page_layout_overview to examine specific widget configurations.",
|
|
527
586
|
inputSchema: {
|
|
528
|
-
|
|
587
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
529
588
|
widgetId: z.string().describe("The unique widget identifier from the layout (e.g., 'id_123', 'id_456')")
|
|
530
589
|
},
|
|
531
590
|
annotations: { title: "Get Widget Details" }
|
|
532
|
-
}, async ({
|
|
533
|
-
debugLogWithTag('LAYOUT', `Starting widget details request for widget ${widgetId} in page ${
|
|
591
|
+
}, async ({ pageUID, widgetId }) => {
|
|
592
|
+
debugLogWithTag('LAYOUT', `Starting widget details request for widget ${widgetId} in page ${pageUID}`);
|
|
534
593
|
try {
|
|
535
|
-
const result = await client.makeApiRequest('json/pageLayout', 'GET', {
|
|
594
|
+
const result = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
536
595
|
let foundWidget = null;
|
|
537
596
|
const findWidget = (rows) => {
|
|
538
597
|
for (const row of rows || []) {
|
|
@@ -554,17 +613,17 @@ server.registerTool("cplace_get_widget_details", {
|
|
|
554
613
|
foundWidget = findWidget(result.rows);
|
|
555
614
|
if (!foundWidget) {
|
|
556
615
|
return {
|
|
557
|
-
content: [{ type: "text", text: `Widget with ID ${widgetId} not found in page ${
|
|
616
|
+
content: [{ type: "text", text: `Widget with ID ${widgetId} not found in page ${pageUID}` }]
|
|
558
617
|
};
|
|
559
618
|
}
|
|
560
|
-
debugLogWithTag('LAYOUT', `Retrieved widget details for: ${widgetId}`);
|
|
619
|
+
debugLogWithTag('LAYOUT', `Retrieved widget details for: ${widgetId} in page`);
|
|
561
620
|
return {
|
|
562
621
|
content: [{ type: "text", text: JSON.stringify(foundWidget, null, 2) }]
|
|
563
622
|
};
|
|
564
623
|
}
|
|
565
624
|
catch (error) {
|
|
566
625
|
return {
|
|
567
|
-
content: [{ type: "text", text: `Error retrieving widget details for ${widgetId} in page ${
|
|
626
|
+
content: [{ type: "text", text: `Error retrieving widget details for ${widgetId} in page ${pageUID}: ${error instanceof Error ? error.message : String(error)}` }]
|
|
568
627
|
};
|
|
569
628
|
}
|
|
570
629
|
});
|
|
@@ -587,6 +646,504 @@ server.registerTool("cplace_get_current_user", {
|
|
|
587
646
|
};
|
|
588
647
|
}
|
|
589
648
|
});
|
|
649
|
+
server.registerTool("cplace_create_page", {
|
|
650
|
+
description: "Create a new page with specified attributes and content using the POST /page/create endpoint",
|
|
651
|
+
inputSchema: {
|
|
652
|
+
workspaceId: z.string().describe("The ID of the workspace/space to create the page in (e.g., 'workspace/abc123')"),
|
|
653
|
+
typeInternalName: z.string().describe("The internal name of the page type (e.g., 'cf.example.myType')"),
|
|
654
|
+
name: z.string().describe("The name of the new page"),
|
|
655
|
+
parentUID: z.string().optional().describe("The UID of the parent page for hierarchy (optional)"),
|
|
656
|
+
content: z.string().optional().describe("Wiki markup content for the page (optional)"),
|
|
657
|
+
attributes: z.record(z.any()).optional().describe(`Custom attribute values as key-value pairs. Supports:
|
|
658
|
+
- String values: "text"
|
|
659
|
+
- Numeric values: 42 or 3.14
|
|
660
|
+
- Boolean values: true/false
|
|
661
|
+
- Date values: "2024-01-15" or "2024-01-15T10:30:00"
|
|
662
|
+
- Array values: ["value1", "value2"] for multi-valued attributes
|
|
663
|
+
- Reference values: "page/ref123" for page references
|
|
664
|
+
- Localized string values: {"en": "English text", "de": "German text", "fr": "French text"}
|
|
665
|
+
- Multi-valued localized strings: [{"en": "Text 1", "de": "Text 1"}, {"en": "Text 2", "de": "Text 2"}]
|
|
666
|
+
|
|
667
|
+
The system automatically detects attribute types from the page type definition and handles:
|
|
668
|
+
- Type-aware processing based on actual attribute definitions
|
|
669
|
+
- Proper multiplicity validation (single vs multi-valued)
|
|
670
|
+
- Automatic type conversion and validation
|
|
671
|
+
- Enhanced error messages with attribute-specific details`)
|
|
672
|
+
},
|
|
673
|
+
annotations: { title: "Create Page" }
|
|
674
|
+
}, async ({ workspaceId, typeInternalName, name, parentUID, content, attributes }) => {
|
|
675
|
+
debugLogWithTag('CREATE_PAGE', `Starting page creation: ${name} of type ${typeInternalName} in workspace ${workspaceId}`);
|
|
676
|
+
try {
|
|
677
|
+
const requestBody = {
|
|
678
|
+
workspaceId,
|
|
679
|
+
typeInternalName,
|
|
680
|
+
name
|
|
681
|
+
};
|
|
682
|
+
if (parentUID) {
|
|
683
|
+
requestBody.parentUID = parentUID;
|
|
684
|
+
debugLogWithTag('CREATE_PAGE', `Including parentUID: ${parentUID}`);
|
|
685
|
+
}
|
|
686
|
+
if (content) {
|
|
687
|
+
requestBody.content = content;
|
|
688
|
+
debugLogWithTag('CREATE_PAGE', `Including content (${content.length} chars)`);
|
|
689
|
+
}
|
|
690
|
+
if (attributes && Object.keys(attributes).length > 0) {
|
|
691
|
+
requestBody.attributes = attributes;
|
|
692
|
+
debugLogWithTag('CREATE_PAGE', `Including attributes: ${JSON.stringify(Object.keys(attributes))}`);
|
|
693
|
+
}
|
|
694
|
+
debugLogWithTag('CREATE_PAGE', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
695
|
+
const result = await client.makeApiRequest('json/page/create', 'POST', undefined, requestBody);
|
|
696
|
+
debugLogWithTag('CREATE_PAGE', `Successfully created page: ${name}`);
|
|
697
|
+
return {
|
|
698
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
catch (error) {
|
|
702
|
+
debugLogWithTag('CREATE_PAGE', `Error creating page: ${error instanceof Error ? error.message : String(error)}`);
|
|
703
|
+
return {
|
|
704
|
+
content: [{ type: "text", text: `Error creating page: ${error instanceof Error ? error.message : String(error)}` }]
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
server.registerTool("cplace_update_page", {
|
|
709
|
+
description: "Update an existing page's attributes, content, or structure using the PATCH /page/{pageId} endpoint",
|
|
710
|
+
inputSchema: {
|
|
711
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page to update"),
|
|
712
|
+
name: z.string().optional().describe("New name for the page (optional)"),
|
|
713
|
+
content: z.string().optional().describe("New wiki markup content (optional). Use empty string to remove content."),
|
|
714
|
+
parentUID: z.string().optional().describe("New parent page UID (optional - for moving pages). Use empty string to remove parent."),
|
|
715
|
+
attributes: z.record(z.any()).optional().describe(`Custom attributes to update as key-value pairs. Supports:
|
|
716
|
+
- String values: "text"
|
|
717
|
+
- Numeric values: 42 or 3.14
|
|
718
|
+
- Boolean values: true/false
|
|
719
|
+
- Date values: "2024-01-15" or "2024-01-15T10:30:00"
|
|
720
|
+
- Array values: ["value1", "value2"] for multi-valued attributes
|
|
721
|
+
- Reference values: "page/ref123" for page references
|
|
722
|
+
- Localized string values: {"en": "English text", "de": "German text", "fr": "French text"}
|
|
723
|
+
- Multi-valued localized strings: [{"en": "Text 1", "de": "Text 1"}, {"en": "Text 2", "de": "Text 2"}]
|
|
724
|
+
- Null values: null (removes the attribute value)
|
|
725
|
+
- Empty arrays: [] (removes all values for multi-valued attributes)
|
|
726
|
+
- New attributes: will be added to the page
|
|
727
|
+
|
|
728
|
+
The system automatically detects attribute types from the page type definition and handles:
|
|
729
|
+
- Type-aware processing based on actual attribute definitions
|
|
730
|
+
- Proper multiplicity validation (single vs multi-valued)
|
|
731
|
+
- Automatic type conversion and validation
|
|
732
|
+
- Enhanced error messages with attribute-specific details`)
|
|
733
|
+
},
|
|
734
|
+
annotations: { title: "Update Page" }
|
|
735
|
+
}, async ({ pageUID, name, content, parentUID, attributes }) => {
|
|
736
|
+
debugLogWithTag('UPDATE_PAGE', `Starting page update for: ${pageUID}`);
|
|
737
|
+
try {
|
|
738
|
+
const requestBody = {
|
|
739
|
+
pageUID
|
|
740
|
+
};
|
|
741
|
+
if (name !== undefined) {
|
|
742
|
+
requestBody.name = name;
|
|
743
|
+
}
|
|
744
|
+
if (content !== undefined) {
|
|
745
|
+
requestBody.content = content;
|
|
746
|
+
}
|
|
747
|
+
if (parentUID !== undefined) {
|
|
748
|
+
requestBody.parentUID = parentUID;
|
|
749
|
+
}
|
|
750
|
+
if (attributes && Object.keys(attributes).length > 0) {
|
|
751
|
+
requestBody.attributes = attributes;
|
|
752
|
+
}
|
|
753
|
+
if (Object.keys(requestBody).length === 1) {
|
|
754
|
+
return {
|
|
755
|
+
content: [{ type: "text", text: "No updates specified. At least one of name, content, parentId, or attributes must be provided." }]
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
const result = await client.makeApiRequest('json/page', 'PATCH', undefined, requestBody);
|
|
759
|
+
debugLogWithTag('UPDATE_PAGE', `Successfully updated page: ${pageUID}`);
|
|
760
|
+
return {
|
|
761
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
catch (error) {
|
|
765
|
+
debugLogWithTag('UPDATE_PAGE', `Error updating page: ${error instanceof Error ? error.message : String(error)}`);
|
|
766
|
+
return {
|
|
767
|
+
content: [{ type: "text", text: `Error updating page: ${error instanceof Error ? error.message : String(error)}` }]
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
server.registerTool("cplace_update_page_attributes", {
|
|
772
|
+
description: "Update page attributes (no content or structural changes) using the PATCH /page/{pageId} endpoint",
|
|
773
|
+
inputSchema: {
|
|
774
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page to update"),
|
|
775
|
+
attributes: z.record(z.any()).describe(`Attribute updates as key-value pairs. Supports all the same data types as the full update tool:
|
|
776
|
+
- String values: "text"
|
|
777
|
+
- Numeric values: 42 or 3.14
|
|
778
|
+
- Boolean values: true/false
|
|
779
|
+
- Date values: "2024-01-15" or "2024-01-15T10:30:00"
|
|
780
|
+
- Array values: ["value1", "value2"] for multi-valued attributes
|
|
781
|
+
- Reference values: "page/ref123" for page references
|
|
782
|
+
- Localized string values: {"en": "English text", "de": "German text", "fr": "French text"}
|
|
783
|
+
- Multi-valued localized strings: [{"en": "Text 1", "de": "Text 1"}, {"en": "Text 2", "de": "Text 2"}]
|
|
784
|
+
- Null values: null (removes the attribute value)
|
|
785
|
+
- Empty arrays: [] (removes all values for multi-valued attributes)
|
|
786
|
+
- New attributes: will be added to the page
|
|
787
|
+
|
|
788
|
+
The system automatically detects attribute types from the page type definition and handles:
|
|
789
|
+
- Type-aware processing based on actual attribute definitions
|
|
790
|
+
- Proper multiplicity validation (single vs multi-valued)
|
|
791
|
+
- Automatic type conversion and validation
|
|
792
|
+
- Enhanced error messages with attribute-specific details`)
|
|
793
|
+
},
|
|
794
|
+
annotations: { title: "Update Page Attributes" }
|
|
795
|
+
}, async ({ pageUID, attributes }) => {
|
|
796
|
+
debugLogWithTag('UPDATE_PAGE_ATTRS', `Starting attribute-only update for: ${pageUID}`);
|
|
797
|
+
try {
|
|
798
|
+
if (!attributes || Object.keys(attributes).length === 0) {
|
|
799
|
+
return {
|
|
800
|
+
content: [{ type: "text", text: "No attributes specified for update. The attributes parameter must contain at least one attribute." }]
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
const requestBody = {
|
|
804
|
+
pageUID,
|
|
805
|
+
attributes: attributes
|
|
806
|
+
};
|
|
807
|
+
const result = await client.makeApiRequest('json/page', 'PATCH', undefined, requestBody);
|
|
808
|
+
debugLogWithTag('UPDATE_PAGE_ATTRS', `Successfully updated attributes for page: ${pageUID}`);
|
|
809
|
+
return {
|
|
810
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
catch (error) {
|
|
814
|
+
debugLogWithTag('UPDATE_PAGE_ATTRS', `Error updating page attributes: ${error instanceof Error ? error.message : String(error)}`);
|
|
815
|
+
return {
|
|
816
|
+
content: [{ type: "text", text: `Error updating page attributes: ${error instanceof Error ? error.message : String(error)}` }]
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
server.registerTool("cplace_add_widget_to_layout", {
|
|
821
|
+
description: "Add a new widget to a page layout at a specific position. Supports both page-level layouts (default) and embedded layouts within container widgets like AttributesGroup.",
|
|
822
|
+
inputSchema: {
|
|
823
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page to add the widget to"),
|
|
824
|
+
widgetType: z.string().describe("The widget type identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki', 'cf.platform.singleAttribute')"),
|
|
825
|
+
configuration: z.record(z.any()).optional().describe(`Widget-specific configuration object as key-value pairs. IMPORTANT: Check the widget definition schema first to understand required data types:
|
|
826
|
+
- localizedString attributes: use {"en": "English text", "de": "German text"} format
|
|
827
|
+
- boolean attributes: use true/false
|
|
828
|
+
- number attributes: use numeric values
|
|
829
|
+
- string attributes: use simple strings
|
|
830
|
+
|
|
831
|
+
RECOMMENDED WORKFLOW:
|
|
832
|
+
1. Use cplace_get_widget_definition() first to understand the configuration schema
|
|
833
|
+
2. Match your configuration values to the constraint types defined in the schema
|
|
834
|
+
3. Use appropriate data formats for each attribute type
|
|
835
|
+
|
|
836
|
+
Examples: {'title': {'en': 'My Widget', 'de': 'Mein Widget'}, 'showHeader': true, 'height': 600}
|
|
837
|
+
For embedded attribute widgets: {'cf.platform.quotedAttributeName': "'cf.cplace.myAttribute'", 'cf.platform.withLabel': true}`),
|
|
838
|
+
position: z.object({
|
|
839
|
+
rowIndex: z.number().min(0).describe("Row index in the layout (0-based)"),
|
|
840
|
+
columnIndex: z.number().min(0).describe("Column index within the row (0-based)"),
|
|
841
|
+
widgetIndex: z.number().min(0).describe("Widget index within the column (0-based)")
|
|
842
|
+
}).describe("Grid position where the widget should be added"),
|
|
843
|
+
layoutContext: z.enum(["page", "widget"]).default("page").describe("Layout context: 'page' for page-level layout (default), 'widget' for embedded layout within a container widget"),
|
|
844
|
+
containerWidgetId: z.string().optional().describe("Required when layoutContext is 'widget'. The unique identifier of the container widget (e.g., AttributesGroup widget) that contains the embedded layout to modify"),
|
|
845
|
+
layoutAttributeName: z.string().optional().describe("Optional layout attribute name for embedded layouts. If not provided, it will be auto-detected based on the container widget type")
|
|
846
|
+
},
|
|
847
|
+
annotations: { title: "Add Widget to Layout" }
|
|
848
|
+
}, async ({ pageUID, widgetType, configuration, position, layoutContext = "page", containerWidgetId, layoutAttributeName }) => {
|
|
849
|
+
debugLogWithTag('LAYOUT_MODIFY', `Starting add widget operation: ${widgetType} to ${layoutContext === "widget" ? "embedded layout in container " + containerWidgetId : "page layout"} ${pageUID} at position ${JSON.stringify(position)}`);
|
|
850
|
+
try {
|
|
851
|
+
if (layoutContext === "widget") {
|
|
852
|
+
if (!containerWidgetId) {
|
|
853
|
+
return {
|
|
854
|
+
content: [{ type: "text", text: "containerWidgetId is required when layoutContext is 'widget'" }]
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
debugLogWithTag('LAYOUT_MODIFY', `Adding to embedded layout in container widget: ${containerWidgetId}`);
|
|
858
|
+
}
|
|
859
|
+
const operation = {
|
|
860
|
+
type: "ADD",
|
|
861
|
+
widgetType,
|
|
862
|
+
position: {
|
|
863
|
+
rowIndex: position.rowIndex,
|
|
864
|
+
columnIndex: position.columnIndex,
|
|
865
|
+
widgetIndex: position.widgetIndex
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
if (configuration && Object.keys(configuration).length > 0) {
|
|
869
|
+
operation.configuration = configuration;
|
|
870
|
+
debugLogWithTag('LAYOUT_MODIFY', `Including configuration: ${JSON.stringify(Object.keys(configuration))}`);
|
|
871
|
+
}
|
|
872
|
+
const requestBody = {
|
|
873
|
+
pageUID,
|
|
874
|
+
layoutContext,
|
|
875
|
+
operation
|
|
876
|
+
};
|
|
877
|
+
if (layoutContext === "widget") {
|
|
878
|
+
requestBody.containerWidgetId = containerWidgetId;
|
|
879
|
+
if (layoutAttributeName) {
|
|
880
|
+
requestBody.layoutAttributeName = layoutAttributeName;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
884
|
+
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
885
|
+
debugLogWithTag('LAYOUT_MODIFY', `Successfully added widget ${widgetType} to page ${pageUID}`);
|
|
886
|
+
return {
|
|
887
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
catch (error) {
|
|
891
|
+
debugLogWithTag('LAYOUT_MODIFY', `Error adding widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
892
|
+
return {
|
|
893
|
+
content: [{ type: "text", text: `Error adding widget to layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
server.registerTool("cplace_remove_widget_from_layout", {
|
|
898
|
+
description: "Remove an existing widget from a page layout",
|
|
899
|
+
inputSchema: {
|
|
900
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
901
|
+
widgetId: z.string().describe("The unique identifier of the widget to remove")
|
|
902
|
+
},
|
|
903
|
+
annotations: { title: "Remove Widget from Layout" }
|
|
904
|
+
}, async ({ pageUID, widgetId }) => {
|
|
905
|
+
debugLogWithTag('LAYOUT_MODIFY', `Starting remove widget operation: ${widgetId} from page ${pageUID}`);
|
|
906
|
+
try {
|
|
907
|
+
const requestBody = {
|
|
908
|
+
pageUID,
|
|
909
|
+
operation: {
|
|
910
|
+
type: "REMOVE",
|
|
911
|
+
widgetId
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
915
|
+
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
916
|
+
debugLogWithTag('LAYOUT_MODIFY', `Successfully removed widget ${widgetId} from page ${pageUID}`);
|
|
917
|
+
return {
|
|
918
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
catch (error) {
|
|
922
|
+
debugLogWithTag('LAYOUT_MODIFY', `Error removing widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
923
|
+
return {
|
|
924
|
+
content: [{ type: "text", text: `Error removing widget from layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
server.registerTool("cplace_update_widget_in_layout", {
|
|
929
|
+
description: "Modify widget configuration or display properties",
|
|
930
|
+
inputSchema: {
|
|
931
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
932
|
+
widgetId: z.string().describe("The unique identifier of the widget to update"),
|
|
933
|
+
newConfiguration: z.record(z.any()).optional().describe(`Updated widget configuration as key-value pairs (optional). IMPORTANT: Check the widget definition schema first to understand required data types:
|
|
934
|
+
- localizedString attributes: use {"en": "English text", "de": "German text"} format
|
|
935
|
+
- boolean attributes: use true/false
|
|
936
|
+
- number attributes: use numeric values
|
|
937
|
+
- string attributes: use simple strings
|
|
938
|
+
|
|
939
|
+
RECOMMENDED WORKFLOW:
|
|
940
|
+
1. Use cplace_get_widget_definition() first to understand the configuration schema
|
|
941
|
+
2. Match your configuration values to the constraint types defined in the schema
|
|
942
|
+
3. Use appropriate data formats for each attribute type
|
|
943
|
+
|
|
944
|
+
Examples: {'title': {'en': 'My Widget', 'de': 'Mein Widget'}, 'showHeader': true, 'height': 600}`),
|
|
945
|
+
collapsed: z.boolean().optional().describe("Widget collapse state (optional)")
|
|
946
|
+
},
|
|
947
|
+
annotations: { title: "Update Widget in Layout" }
|
|
948
|
+
}, async ({ pageUID, widgetId, newConfiguration, collapsed }) => {
|
|
949
|
+
debugLogWithTag('LAYOUT_MODIFY', `Starting update widget operation: ${widgetId} in page ${pageUID}`);
|
|
950
|
+
try {
|
|
951
|
+
const operation = {
|
|
952
|
+
type: "UPDATE",
|
|
953
|
+
widgetId
|
|
954
|
+
};
|
|
955
|
+
if (newConfiguration && Object.keys(newConfiguration).length > 0) {
|
|
956
|
+
operation.newConfiguration = newConfiguration;
|
|
957
|
+
debugLogWithTag('LAYOUT_MODIFY', `Including new configuration: ${JSON.stringify(Object.keys(newConfiguration))}`);
|
|
958
|
+
}
|
|
959
|
+
if (collapsed !== undefined) {
|
|
960
|
+
operation.collapsed = collapsed;
|
|
961
|
+
debugLogWithTag('LAYOUT_MODIFY', `Setting collapsed state to: ${collapsed}`);
|
|
962
|
+
}
|
|
963
|
+
if (!operation.newConfiguration && operation.collapsed === undefined) {
|
|
964
|
+
return {
|
|
965
|
+
content: [{ type: "text", text: "No updates specified. At least one of newConfiguration or collapsed must be provided." }]
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
const requestBody = {
|
|
969
|
+
pageUID,
|
|
970
|
+
operation
|
|
971
|
+
};
|
|
972
|
+
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
973
|
+
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
974
|
+
debugLogWithTag('LAYOUT_MODIFY', `Successfully updated widget ${widgetId} in page ${pageUID}`);
|
|
975
|
+
return {
|
|
976
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
catch (error) {
|
|
980
|
+
debugLogWithTag('LAYOUT_MODIFY', `Error updating widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
981
|
+
return {
|
|
982
|
+
content: [{ type: "text", text: `Error updating widget in layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
server.registerTool("cplace_move_widget_in_layout", {
|
|
987
|
+
description: "Relocate a widget to a different position in the layout",
|
|
988
|
+
inputSchema: {
|
|
989
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
990
|
+
widgetId: z.string().describe("The unique identifier of the widget to move"),
|
|
991
|
+
newPosition: z.object({
|
|
992
|
+
rowIndex: z.number().min(0).describe("Target row index in the layout (0-based)"),
|
|
993
|
+
columnIndex: z.number().min(0).describe("Target column index within the row (0-based)"),
|
|
994
|
+
widgetIndex: z.number().min(0).describe("Target widget index within the column (0-based)")
|
|
995
|
+
}).describe("Target grid position for the widget")
|
|
996
|
+
},
|
|
997
|
+
annotations: { title: "Move Widget in Layout" }
|
|
998
|
+
}, async ({ pageUID, widgetId, newPosition }) => {
|
|
999
|
+
debugLogWithTag('LAYOUT_MODIFY', `Starting move widget operation: ${widgetId} in page ${pageUID} to position ${JSON.stringify(newPosition)}`);
|
|
1000
|
+
try {
|
|
1001
|
+
const requestBody = {
|
|
1002
|
+
pageUID,
|
|
1003
|
+
operation: {
|
|
1004
|
+
type: "MOVE",
|
|
1005
|
+
widgetId,
|
|
1006
|
+
newPosition: {
|
|
1007
|
+
rowIndex: newPosition.rowIndex,
|
|
1008
|
+
columnIndex: newPosition.columnIndex,
|
|
1009
|
+
widgetIndex: newPosition.widgetIndex
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
1014
|
+
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
1015
|
+
debugLogWithTag('LAYOUT_MODIFY', `Successfully moved widget ${widgetId} in page ${pageUID}`);
|
|
1016
|
+
return {
|
|
1017
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
catch (error) {
|
|
1021
|
+
debugLogWithTag('LAYOUT_MODIFY', `Error moving widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
1022
|
+
return {
|
|
1023
|
+
content: [{ type: "text", text: `Error moving widget in layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
server.registerTool("cplace_get_embedded_layout", {
|
|
1028
|
+
description: "Get the widget layout structure of an embedded widget within a container widget on a specific page. This endpoint accesses nested widget layouts embedded within other widgets, such as AttributesGroup widgets.",
|
|
1029
|
+
inputSchema: {
|
|
1030
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the container widget"),
|
|
1031
|
+
containerWidgetId: z.string().describe("The ID of the container widget that contains the embedded layout"),
|
|
1032
|
+
layoutAttributeName: z.string().describe("The name of the attribute that defines the embedded layout structure")
|
|
1033
|
+
},
|
|
1034
|
+
annotations: { title: "Get Embedded Layout" }
|
|
1035
|
+
}, async ({ pageUID, containerWidgetId, layoutAttributeName }) => {
|
|
1036
|
+
debugLogWithTag('EMBEDDED_LAYOUT', `Starting embedded widget layout request for container ${containerWidgetId} in page ${pageUID}`);
|
|
1037
|
+
try {
|
|
1038
|
+
const result = await client.makeApiRequest('json/embeddedWidgetLayout', 'GET', {
|
|
1039
|
+
pageUID,
|
|
1040
|
+
containerWidgetId,
|
|
1041
|
+
layoutAttributeName
|
|
1042
|
+
});
|
|
1043
|
+
debugLogWithTag('EMBEDDED_LAYOUT', `Retrieved embedded widget layout for container: ${containerWidgetId}`);
|
|
1044
|
+
return {
|
|
1045
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
catch (error) {
|
|
1049
|
+
return {
|
|
1050
|
+
content: [{ type: "text", text: `Error retrieving embedded widget layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
server.registerTool("cplace_add_widget_to_embedded_layout", {
|
|
1055
|
+
description: "Add a new widget to an embedded layout within a container widget. This enables adding widgets to nested layouts like those within AttributesGroup widgets.",
|
|
1056
|
+
inputSchema: {
|
|
1057
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the container widget"),
|
|
1058
|
+
containerWidgetId: z.string().describe("The ID of the container widget that contains the embedded layout to modify"),
|
|
1059
|
+
layoutAttributeName: z.string().describe("The name of the attribute that defines the embedded layout structure"),
|
|
1060
|
+
widgetType: z.string().describe("Widget type identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki')"),
|
|
1061
|
+
position: z.object({
|
|
1062
|
+
rowIndex: z.number().min(0).describe("Row index in the embedded layout (0-based)"),
|
|
1063
|
+
columnIndex: z.number().min(0).describe("Column index within the row (0-based)"),
|
|
1064
|
+
widgetIndex: z.number().min(0).describe("Widget index within the column (0-based)")
|
|
1065
|
+
}).describe("Position where the widget should be added in the embedded layout"),
|
|
1066
|
+
configuration: z.record(z.any()).optional().describe(`Widget configuration as key-value pairs. IMPORTANT: Check the widget definition schema first to understand required data types:
|
|
1067
|
+
- localizedString attributes: use {"en": "English text", "de": "German text"} format
|
|
1068
|
+
- boolean attributes: use true/false
|
|
1069
|
+
- number attributes: use numeric values
|
|
1070
|
+
- string attributes: use simple strings
|
|
1071
|
+
|
|
1072
|
+
RECOMMENDED WORKFLOW:
|
|
1073
|
+
1. Use cplace_get_widget_definition() first to understand the configuration schema
|
|
1074
|
+
2. Match your configuration values to the constraint types defined in the schema
|
|
1075
|
+
3. Use appropriate data formats for each attribute type
|
|
1076
|
+
|
|
1077
|
+
Examples: {'title': {'en': 'Embedded Widget', 'de': 'Eingebettetes Widget'}, 'showHeader': true}`)
|
|
1078
|
+
},
|
|
1079
|
+
annotations: { title: "Add Widget to Embedded Layout" }
|
|
1080
|
+
}, async ({ pageUID, containerWidgetId, layoutAttributeName, widgetType, position, configuration }) => {
|
|
1081
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Starting add widget to embedded layout: ${widgetType} to container ${containerWidgetId} in page ${pageUID}`);
|
|
1082
|
+
try {
|
|
1083
|
+
const operation = {
|
|
1084
|
+
type: "ADD",
|
|
1085
|
+
widgetType,
|
|
1086
|
+
position
|
|
1087
|
+
};
|
|
1088
|
+
if (configuration && Object.keys(configuration).length > 0) {
|
|
1089
|
+
operation.configuration = configuration;
|
|
1090
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Including configuration: ${JSON.stringify(Object.keys(configuration))}`);
|
|
1091
|
+
}
|
|
1092
|
+
const requestBody = {
|
|
1093
|
+
pageUID,
|
|
1094
|
+
containerWidgetId,
|
|
1095
|
+
layoutAttributeName,
|
|
1096
|
+
operation
|
|
1097
|
+
};
|
|
1098
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
1099
|
+
const result = await client.makeApiRequest('json/embeddedWidgetLayout', 'PATCH', undefined, requestBody);
|
|
1100
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Successfully added widget ${widgetType} to embedded layout`);
|
|
1101
|
+
return {
|
|
1102
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
catch (error) {
|
|
1106
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Error adding widget to embedded layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
1107
|
+
return {
|
|
1108
|
+
content: [{ type: "text", text: `Error adding widget to embedded layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
server.registerTool("cplace_remove_widget_from_embedded_layout", {
|
|
1113
|
+
description: "Remove an existing widget from an embedded layout within a container widget. This enables removing widgets from nested layouts like those within AttributesGroup widgets.",
|
|
1114
|
+
inputSchema: {
|
|
1115
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the container widget"),
|
|
1116
|
+
containerWidgetId: z.string().describe("The ID of the container widget that contains the embedded layout to modify"),
|
|
1117
|
+
layoutAttributeName: z.string().describe("The name of the attribute that defines the embedded layout structure"),
|
|
1118
|
+
widgetId: z.string().describe("The ID of the existing widget to remove from the embedded layout")
|
|
1119
|
+
},
|
|
1120
|
+
annotations: { title: "Remove Widget from Embedded Layout" }
|
|
1121
|
+
}, async ({ pageUID, containerWidgetId, layoutAttributeName, widgetId }) => {
|
|
1122
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Starting remove widget from embedded layout: ${widgetId} from container ${containerWidgetId} in page ${pageUID}`);
|
|
1123
|
+
try {
|
|
1124
|
+
const requestBody = {
|
|
1125
|
+
pageUID,
|
|
1126
|
+
containerWidgetId,
|
|
1127
|
+
layoutAttributeName,
|
|
1128
|
+
operation: {
|
|
1129
|
+
type: "REMOVE",
|
|
1130
|
+
widgetId
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
1134
|
+
const result = await client.makeApiRequest('json/embeddedWidgetLayout', 'PATCH', undefined, requestBody);
|
|
1135
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Successfully removed widget ${widgetId} from embedded layout`);
|
|
1136
|
+
return {
|
|
1137
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
catch (error) {
|
|
1141
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Error removing widget from embedded layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
1142
|
+
return {
|
|
1143
|
+
content: [{ type: "text", text: `Error removing widget from embedded layout: ${error instanceof Error ? error.message : String(error)}` }]
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
590
1147
|
async function runServer() {
|
|
591
1148
|
const transport = new StdioServerTransport();
|
|
592
1149
|
await server.connect(transport);
|