@cplace/test-mcp-server 0.1.9 → 0.1.11
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 +126 -20
- package/dist/api.d.ts +3 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +4 -1
- package/dist/api.js.map +1 -1
- package/dist/conditional-registration.d.ts +4 -0
- package/dist/conditional-registration.d.ts.map +1 -0
- package/dist/conditional-registration.js +40 -0
- package/dist/conditional-registration.js.map +1 -0
- package/dist/index.js +49 -1129
- package/dist/index.js.map +1 -1
- package/dist/profiles.d.ts +10 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +138 -0
- package/dist/profiles.js.map +1 -0
- package/dist/searchSchema.d.ts +44 -44
- package/dist/tools/change-listeners.d.ts +4 -0
- package/dist/tools/change-listeners.d.ts.map +1 -0
- package/dist/tools/change-listeners.js +98 -0
- package/dist/tools/change-listeners.js.map +1 -0
- package/dist/tools/common-schemas.d.ts +228 -0
- package/dist/tools/common-schemas.d.ts.map +1 -0
- package/dist/tools/common-schemas.js +68 -0
- package/dist/tools/common-schemas.js.map +1 -0
- package/dist/tools/pages.d.ts +4 -0
- package/dist/tools/pages.d.ts.map +1 -0
- package/dist/tools/pages.js +275 -0
- package/dist/tools/pages.js.map +1 -0
- package/dist/tools/ppt-export-profiles.d.ts +4 -0
- package/dist/tools/ppt-export-profiles.d.ts.map +1 -0
- package/dist/tools/ppt-export-profiles.js +242 -0
- package/dist/tools/ppt-export-profiles.js.map +1 -0
- package/dist/tools/references.d.ts +4 -0
- package/dist/tools/references.d.ts.map +1 -0
- package/dist/tools/references.js +57 -0
- package/dist/tools/references.js.map +1 -0
- package/dist/tools/search.d.ts +4 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +304 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/system.d.ts +3 -0
- package/dist/tools/system.d.ts.map +1 -0
- package/dist/tools/system.js +22 -0
- package/dist/tools/system.js.map +1 -0
- package/dist/tools/type-layouts.d.ts +4 -0
- package/dist/tools/type-layouts.d.ts.map +1 -0
- package/dist/tools/type-layouts.js +56 -0
- package/dist/tools/type-layouts.js.map +1 -0
- package/dist/tools/users.d.ts +4 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +62 -0
- package/dist/tools/users.js.map +1 -0
- package/dist/tools/validators.d.ts +4 -0
- package/dist/tools/validators.d.ts.map +1 -0
- package/dist/tools/validators.js +87 -0
- package/dist/tools/validators.js.map +1 -0
- package/dist/tools/version-history.d.ts +4 -0
- package/dist/tools/version-history.d.ts.map +1 -0
- package/dist/tools/version-history.js +142 -0
- package/dist/tools/version-history.js.map +1 -0
- package/dist/tools/widgets.d.ts +4 -0
- package/dist/tools/widgets.d.ts.map +1 -0
- package/dist/tools/widgets.js +516 -0
- package/dist/tools/widgets.js.map +1 -0
- package/dist/tools/workspace.d.ts +4 -0
- package/dist/tools/workspace.d.ts.map +1 -0
- package/dist/tools/workspace.js +396 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/types.d.ts +2 -22
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -9
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +15 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +90 -12
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import * as dotenv from 'dotenv';
|
|
5
|
-
import { z } from "zod";
|
|
6
5
|
import { CplaceApiClient } from './api.js';
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { debugLogWithTag } from
|
|
11
|
-
import { DEBUG_LOGGING } from "./logger.js";
|
|
12
|
-
import { convertPagesToCsv } from "./csvUtils.js";
|
|
6
|
+
import { parseProfiles, getActiveTools, TOOL_GROUPS } from './profiles.js';
|
|
7
|
+
import { registerActiveTools } from './conditional-registration.js';
|
|
8
|
+
import { registerSystemTools } from './tools/system.js';
|
|
9
|
+
import { debugLogWithTag } from './logger.js';
|
|
13
10
|
dotenv.config();
|
|
14
11
|
const config = {
|
|
15
12
|
url: process.env.CPLACE_URL || '',
|
|
@@ -17,1140 +14,63 @@ const config = {
|
|
|
17
14
|
registerSystemInfoTool: process.env.REGISTER_SYSTEM_INFO_TOOL === 'true' || false,
|
|
18
15
|
};
|
|
19
16
|
const client = new CplaceApiClient(config);
|
|
17
|
+
const activeGroups = parseProfiles(process.argv);
|
|
18
|
+
const activeTools = getActiveTools(activeGroups);
|
|
19
|
+
debugLogWithTag('MCP', '====================================');
|
|
20
|
+
debugLogWithTag('MCP', 'cplace MCP Server Profile Configuration');
|
|
21
|
+
debugLogWithTag('MCP', '====================================');
|
|
22
|
+
debugLogWithTag('MCP', `Active groups: ${Array.from(activeGroups).join(', ')}`);
|
|
23
|
+
debugLogWithTag('MCP', `Total tools to register: ${activeTools.size}`);
|
|
24
|
+
debugLogWithTag('MCP', '====================================');
|
|
20
25
|
const server = new McpServer({
|
|
21
|
-
name:
|
|
26
|
+
name: `cplace-mcp-server`,
|
|
22
27
|
version: "1.0.0"
|
|
23
28
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
annotations: { title: "Get System Information" }
|
|
29
|
-
}, async () => {
|
|
30
|
-
const systemInfo = {
|
|
31
|
-
currentWorkingDirectory: process.cwd(),
|
|
32
|
-
cplaceUrl: config.url || 'Not set',
|
|
33
|
-
debugLogging: DEBUG_LOGGING,
|
|
34
|
-
nodeVersion: process.version,
|
|
35
|
-
platform: process.platform
|
|
36
|
-
};
|
|
37
|
-
return {
|
|
38
|
-
content: [{ type: "text", text: JSON.stringify(systemInfo, null, 2) }]
|
|
39
|
-
};
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
server.registerTool("cplace_list_workspaces", {
|
|
43
|
-
description: "Get a list of all workspaces with essential properties (id, name, displayName, totalPages, isFavorite, installed apps)",
|
|
29
|
+
registerActiveTools(server, client, activeGroups);
|
|
30
|
+
registerSystemTools(server, config);
|
|
31
|
+
server.registerTool("cplace_profile_info", {
|
|
32
|
+
description: "Get information about active MCP profiles and available groups",
|
|
44
33
|
inputSchema: {},
|
|
45
|
-
annotations: { title: "
|
|
34
|
+
annotations: { title: "Profile Information" }
|
|
46
35
|
}, async () => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
74
|
-
annotations: { title: "List Types" }
|
|
75
|
-
}, async ({ workspaceId }) => {
|
|
76
|
-
try {
|
|
77
|
-
const workspaces = await client.makeApiRequest('json/workspaces');
|
|
78
|
-
const workspace = workspaces.find((w) => w.id === workspaceId);
|
|
79
|
-
if (workspace) {
|
|
80
|
-
const types = workspace.typeDefinitions?.types || [];
|
|
81
|
-
return {
|
|
82
|
-
content: [{ type: "text", text: JSON.stringify(types, null, 2) }]
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
content: [{ type: "text", text: `Workspace ${workspaceId} not found` }]
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
return {
|
|
91
|
-
content: [{ type: "text", text: `Error retrieving types: ${error instanceof Error ? error.message : String(error)}` }]
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
server.registerTool("cplace_get_type_datamodel", {
|
|
96
|
-
description: "Get the datamodel of a type including its attributes, constraints, and permissions. Use this before performing a search to understand the type structure.",
|
|
97
|
-
inputSchema: {
|
|
98
|
-
workspaceId: z.string().describe("The ID of the workspace"),
|
|
99
|
-
internalName: z.string().describe("The internal name of the type")
|
|
100
|
-
},
|
|
101
|
-
annotations: { title: "Get Type Details" }
|
|
102
|
-
}, async ({ workspaceId, internalName }) => {
|
|
103
|
-
try {
|
|
104
|
-
const result = await client.makeApiRequest('json/type-definition', 'GET', {
|
|
105
|
-
workspaceId,
|
|
106
|
-
internalName
|
|
107
|
-
});
|
|
108
|
-
return {
|
|
109
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
return {
|
|
114
|
-
content: [{ type: "text", text: `Error retrieving type details: ${error instanceof Error ? error.message : String(error)}` }]
|
|
115
|
-
};
|
|
116
|
-
}
|
|
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
|
-
});
|
|
170
|
-
server.registerTool("cplace_get_page_by_id", {
|
|
171
|
-
description: "Get comprehensive page information including relationships and metadata",
|
|
172
|
-
inputSchema: {
|
|
173
|
-
id: z.string().describe("The ID of the page to get, e.g. 'page/kkt8ol745jqur4581kelm5ply'")
|
|
174
|
-
},
|
|
175
|
-
annotations: { title: "Get Page by ID" }
|
|
176
|
-
}, async ({ id }) => {
|
|
177
|
-
try {
|
|
178
|
-
const result = await client.makeApiRequest('json/page', 'GET', { pageUID: id });
|
|
179
|
-
return {
|
|
180
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
return {
|
|
185
|
-
content: [{ type: "text", text: `Error retrieving page: ${error instanceof Error ? error.message : String(error)}` }]
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
server.registerTool("cplace_get_person_by_id", {
|
|
190
|
-
description: "Get details about a person including their name and email.",
|
|
191
|
-
inputSchema: {
|
|
192
|
-
id: z.string().describe("The ID of the person to get, e.g. 'person/kkt8ol745jqur4581kelm5ply'")
|
|
193
|
-
},
|
|
194
|
-
annotations: { title: "Get Person by ID" }
|
|
195
|
-
}, async ({ id }) => {
|
|
196
|
-
try {
|
|
197
|
-
const result = await client.makeApiRequest('json/person', 'GET', { id });
|
|
198
|
-
return {
|
|
199
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
return {
|
|
204
|
-
content: [{ type: "text", text: `Error retrieving person: ${error instanceof Error ? error.message : String(error)}` }]
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
server.registerTool("cplace_get_person_by_name", {
|
|
209
|
-
description: "Get details about a person by searching for their name.",
|
|
210
|
-
inputSchema: {
|
|
211
|
-
name: z.string().describe("The name of the person or part of the name to search for"),
|
|
212
|
-
},
|
|
213
|
-
annotations: { title: "Get Person by Name" }
|
|
214
|
-
}, async ({ name }) => {
|
|
215
|
-
try {
|
|
216
|
-
const result = await client.makeApiRequest('json/person', 'GET', { name });
|
|
217
|
-
return {
|
|
218
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
catch (error) {
|
|
222
|
-
return {
|
|
223
|
-
content: [{ type: "text", text: `Error searching for person: ${error instanceof Error ? error.message : String(error)}` }]
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
server.registerTool("cplace_search_pages", {
|
|
228
|
-
description: "Search pages of a type in cplace.",
|
|
229
|
-
inputSchema: {
|
|
230
|
-
workspaceId: z.string().optional().describe("The ID of the workspace to search in. If not provided, searches across all accessible workspaces."),
|
|
231
|
-
internalTypeName: z.string().describe(`The internal name of the type to filter by. Examples:
|
|
232
|
-
- "cf.cplace.solution.safe.feature" for Feature pages
|
|
233
|
-
- "cf.cplace.solution.safe.epic" for Epic pages
|
|
234
|
-
- "cf.cplace.solution.safe.story" for Story pages
|
|
235
|
-
- "cf.projectNavigator.project" for Project pages
|
|
236
|
-
- "cf.cplace.solution.safe.portfolio" for Portfolio pages
|
|
237
|
-
Use cplace_get_types_in_workspace to discover available types in a workspace.`),
|
|
238
|
-
search_filter: SearchFilterSchema.describe(`Search Filters using cplace filter format. Examples:
|
|
239
|
-
|
|
240
|
-
Basic string filter:
|
|
241
|
-
[{"attribute": "cf.cplace.workflow", "string": {"equals": "approved"}}]
|
|
242
|
-
|
|
243
|
-
Multiple conditions:
|
|
244
|
-
[
|
|
245
|
-
{"name": {"equals": "Project Alpha"}},
|
|
246
|
-
{"attribute": "cf.cplace.location", "reference": {"equals": "page/abc123"}}
|
|
247
|
-
]
|
|
248
|
-
|
|
249
|
-
Date range filter:
|
|
250
|
-
[
|
|
251
|
-
{"attribute": "cf.cplace.projectStart", "date": {"on_or_after": "2023-01-01"}},
|
|
252
|
-
{"attribute": "cf.cplace.projectFinish", "date": {"on_or_before": "2024-12-31"}}
|
|
253
|
-
]
|
|
254
|
-
|
|
255
|
-
Number comparison:
|
|
256
|
-
[{"attribute": "cf.cplace.estimatedCost", "number": {"greater_than": 1000}}]
|
|
257
|
-
|
|
258
|
-
Logical OR operator:
|
|
259
|
-
[{
|
|
260
|
-
"or": [
|
|
261
|
-
{"attribute": "cf.cplace.managementPriority", "string": {"equals": "Focus"}},
|
|
262
|
-
{"attribute": "cf.cplace.managementPriority", "string": {"equals": "Accelerate"}}
|
|
263
|
-
]
|
|
264
|
-
}]
|
|
265
|
-
|
|
266
|
-
Complex AND/OR combination:
|
|
267
|
-
[{
|
|
268
|
-
"and": [
|
|
269
|
-
{"attribute": "cf.cplace.workflow", "string": {"equals": "inProgress"}},
|
|
270
|
-
{
|
|
271
|
-
"or": [
|
|
272
|
-
{"attribute": "cf.cplace.priority", "string": {"equals": "High"}},
|
|
273
|
-
{"attribute": "cf.cplace.priority", "string": {"equals": "Critical"}}
|
|
274
|
-
]
|
|
275
|
-
}
|
|
276
|
-
]
|
|
277
|
-
}]
|
|
278
|
-
|
|
279
|
-
Boolean filter:
|
|
280
|
-
[{"attribute": "cf.cplace.isActive", "boolean": {"equals": true}}]
|
|
281
|
-
|
|
282
|
-
Empty/not empty checks:
|
|
283
|
-
[{"attribute": "cf.cplace.description", "string": {"is_not_empty": true}}]`),
|
|
284
|
-
limit: z.number().min(1).max(1000).default(50).describe("Maximum number of results to return (1-1000)"),
|
|
285
|
-
offset: z.number().min(0).max(10000).default(0).describe("Number of results to skip for pagination, cannot be larger than 10000"),
|
|
286
|
-
responseFormat: z.enum(["minimal", "count"]).optional().describe(`Response format options:
|
|
287
|
-
- Default (not specified): Complete page data, respects 'attributes' parameter
|
|
288
|
-
- "minimal": Only core fields (id, name, url, type, workspace)
|
|
289
|
-
- "count": Only return the total count of matching pages`),
|
|
290
|
-
attributes: z.array(z.string()).optional().describe("Specific attribute names to include in response. If not provided, all attributes are included. Examples: ['cf.cplace.workflow', 'cf.cplace.priority']"),
|
|
291
|
-
},
|
|
292
|
-
annotations: { title: "Search Pages" }
|
|
293
|
-
}, async ({ workspaceId, internalTypeName, search_filter, limit = 50, offset = 0, responseFormat, attributes, }) => {
|
|
294
|
-
debugLogWithTag('SEARCH', `Starting search with params: workspaceId=${workspaceId || 'none'}, type=${internalTypeName}, filter=${JSON.stringify(search_filter)}, limit=${limit}, offset=${offset}`);
|
|
295
|
-
try {
|
|
296
|
-
const cplaceFilter = convertSearchFilterToCplaceFormat(search_filter);
|
|
297
|
-
debugLogWithTag('SEARCH', `Converted filter: ${JSON.stringify(cplaceFilter)}`);
|
|
298
|
-
if (workspaceId) {
|
|
299
|
-
cplaceFilter.filters.unshift({
|
|
300
|
-
type: "Workspace",
|
|
301
|
-
workspaceIds: [workspaceId]
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
if (internalTypeName) {
|
|
305
|
-
cplaceFilter.filters.unshift({
|
|
306
|
-
type: "Type",
|
|
307
|
-
types: [internalTypeName]
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
debugLogWithTag('SEARCH', `Final cplace filter: ${JSON.stringify(cplaceFilter)}`);
|
|
311
|
-
const result = await client.makeApiRequest('json/search', 'GET', {
|
|
312
|
-
filter: JSON.stringify(cplaceFilter),
|
|
313
|
-
limit,
|
|
314
|
-
offset
|
|
315
|
-
});
|
|
316
|
-
if (responseFormat === "count") {
|
|
317
|
-
const countResult = {
|
|
318
|
-
count: result.pagination?.total || 0
|
|
319
|
-
};
|
|
320
|
-
return {
|
|
321
|
-
content: [{ type: "text", text: JSON.stringify(countResult, null, 2) }]
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
const filteredResults = result.results ? result.results.map((item) => filterSearchResult(item, {
|
|
325
|
-
minimal: responseFormat === "minimal",
|
|
326
|
-
includeAttributes: responseFormat !== "minimal",
|
|
327
|
-
includeMetadata: false,
|
|
328
|
-
attributeFields: attributes,
|
|
329
|
-
truncateLargeValues: true
|
|
330
|
-
})) : [];
|
|
331
|
-
const filteredResult = {
|
|
332
|
-
results: filteredResults,
|
|
333
|
-
pagination: {
|
|
334
|
-
total: result.pagination?.total || 0,
|
|
335
|
-
limit: result.pagination?.limit || limit,
|
|
336
|
-
offset: result.pagination?.offset || offset,
|
|
337
|
-
hasMore: result.pagination?.hasMore || false
|
|
338
|
-
},
|
|
339
|
-
humanReadableRepresentation: result.summary,
|
|
340
|
-
cplaceJson: result.cplaceJson
|
|
341
|
-
};
|
|
342
|
-
return {
|
|
343
|
-
content: [{ type: "text", text: JSON.stringify(filteredResult, null, 2) }]
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
catch (error) {
|
|
347
|
-
debugLogWithTag('SEARCH', `Error during search: ${error instanceof Error ? error.message : String(error)}`);
|
|
348
|
-
return {
|
|
349
|
-
content: [{ type: "text", text: `Error converting or executing search: ${error instanceof Error ? error.message : String(error)}` }]
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
});
|
|
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.",
|
|
355
|
-
inputSchema: {
|
|
356
|
-
workspaceId: z.string().optional().describe("The ID of the workspace to search in. If not provided, searches across all accessible workspaces."),
|
|
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."),
|
|
358
|
-
limit: z.number().min(1).max(1000).default(50).describe("Maximum number of results to return (1-1000)"),
|
|
359
|
-
offset: z.number().min(0).max(10000).default(0).describe("Number of results to skip for pagination, cannot be larger than 10000"),
|
|
360
|
-
},
|
|
361
|
-
annotations: { title: "Search Pages by Fulltext" }
|
|
362
|
-
}, async ({ workspaceId, fulltext, limit = 50, offset = 0, }) => {
|
|
363
|
-
if (!fulltext) {
|
|
364
|
-
return {
|
|
365
|
-
content: [{ type: "text", text: "fulltext is required" }]
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
try {
|
|
369
|
-
const result = await client.makeApiRequest('json/fulltext-search', 'GET', {
|
|
370
|
-
spaceId: workspaceId,
|
|
371
|
-
fulltext: `"${fulltext}"`,
|
|
372
|
-
limit,
|
|
373
|
-
offset
|
|
374
|
-
});
|
|
375
|
-
const filteredResults = result.results ? result.results.map((item) => filterSearchResult(item, {
|
|
376
|
-
minimal: false,
|
|
377
|
-
includeAttributes: true,
|
|
378
|
-
includeMetadata: false,
|
|
379
|
-
truncateLargeValues: true
|
|
380
|
-
})) : [];
|
|
381
|
-
const filteredResult = {
|
|
382
|
-
results: filteredResults,
|
|
383
|
-
pagination: {
|
|
384
|
-
total: result.pagination?.total || 0,
|
|
385
|
-
limit: result.pagination?.limit || limit,
|
|
386
|
-
offset: result.pagination?.offset || offset,
|
|
387
|
-
hasMore: result.pagination?.hasMore || false
|
|
388
|
-
},
|
|
389
|
-
summary: result.summary,
|
|
390
|
-
cplaceJson: result.cplaceJson
|
|
391
|
-
};
|
|
392
|
-
return {
|
|
393
|
-
content: [{ type: "text", text: JSON.stringify(filteredResult, null, 2) }]
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
catch (error) {
|
|
397
|
-
return {
|
|
398
|
-
content: [{ type: "text", text: `Error converting or executing search: ${error instanceof Error ? error.message : String(error)}` }]
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
});
|
|
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.",
|
|
404
|
-
inputSchema: {
|
|
405
|
-
workspaceId: z.string().describe("The ID of the workspace to get pages from"),
|
|
406
|
-
typeName: z.string().describe("The internal name of the type to retrieve pages for"),
|
|
407
|
-
limit: z.number().min(1).max(1000).default(50).describe("Maximum number of results to return (1-1000)"),
|
|
408
|
-
offset: z.number().min(0).max(10000).default(0).describe("Number of results to skip for pagination, cannot be larger than 10000"),
|
|
409
|
-
},
|
|
410
|
-
annotations: { title: "List Pages of Type" }
|
|
411
|
-
}, async ({ workspaceId, typeName, limit = 50, offset = 0, }) => {
|
|
412
|
-
try {
|
|
413
|
-
const cplaceFilter = {
|
|
414
|
-
filters: [
|
|
415
|
-
{
|
|
416
|
-
type: "Workspace",
|
|
417
|
-
workspaceIds: [workspaceId]
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
type: "Type",
|
|
421
|
-
types: [typeName]
|
|
422
|
-
}
|
|
423
|
-
]
|
|
424
|
-
};
|
|
425
|
-
const result = await client.makeApiRequest('json/search', 'GET', {
|
|
426
|
-
filter: JSON.stringify(cplaceFilter),
|
|
427
|
-
limit,
|
|
428
|
-
offset
|
|
429
|
-
});
|
|
430
|
-
const filteredResults = result.results ? result.results.map((item) => filterSearchResult(item, {
|
|
431
|
-
minimal: false,
|
|
432
|
-
includeAttributes: true,
|
|
433
|
-
includeMetadata: false,
|
|
434
|
-
truncateLargeValues: true
|
|
435
|
-
})) : [];
|
|
436
|
-
const filteredResult = {
|
|
437
|
-
results: filteredResults,
|
|
438
|
-
pagination: {
|
|
439
|
-
total: result.pagination?.total || 0,
|
|
440
|
-
limit: result.pagination?.limit || limit,
|
|
441
|
-
offset: result.pagination?.offset || offset,
|
|
442
|
-
hasMore: result.pagination?.hasMore || false
|
|
443
|
-
},
|
|
444
|
-
summary: result.summary
|
|
445
|
-
};
|
|
446
|
-
return {
|
|
447
|
-
content: [{ type: "text", text: JSON.stringify(filteredResult, null, 2) }]
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
catch (error) {
|
|
451
|
-
return {
|
|
452
|
-
content: [{ type: "text", text: `Error retrieving pages: ${error instanceof Error ? error.message : String(error)}` }]
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
server.registerTool("cplace_search_pages_csv", {
|
|
457
|
-
description: "Same as cplace_search_pages but returns results in CSV format instead of JSON. Only use this tool after first calling cplace_search_pages to establish and validate the search parameters. The CSV result should always be stored as an artifact.",
|
|
458
|
-
inputSchema: {
|
|
459
|
-
workspaceId: z.string().optional().describe("Same as cplace_search_pages"),
|
|
460
|
-
internalTypeName: z.string().describe("Same as cplace_search_pages"),
|
|
461
|
-
search_filter: SearchFilterSchema.describe("Same as cplace_search_pages"),
|
|
462
|
-
limit: z.number().min(1).max(1000).default(50).describe("Same as cplace_search_pages"),
|
|
463
|
-
offset: z.number().min(0).max(10000).default(0).describe("Same as cplace_search_pages"),
|
|
464
|
-
attributes: z.array(z.string()).optional().describe("Same as cplace_search_pages"),
|
|
465
|
-
},
|
|
466
|
-
annotations: { title: "Search Pages (CSV Export)" }
|
|
467
|
-
}, async ({ workspaceId, internalTypeName, search_filter, limit = 50, offset = 0, attributes, }) => {
|
|
468
|
-
debugLogWithTag('CSV_SEARCH', `Starting CSV search with params: workspaceId=${workspaceId || 'none'}, type=${internalTypeName}, filter=${JSON.stringify(search_filter)}, limit=${limit}, offset=${offset}`);
|
|
469
|
-
try {
|
|
470
|
-
const cplaceFilter = convertSearchFilterToCplaceFormat(search_filter);
|
|
471
|
-
debugLogWithTag('CSV_SEARCH', `Converted filter: ${JSON.stringify(cplaceFilter)}`);
|
|
472
|
-
if (workspaceId) {
|
|
473
|
-
cplaceFilter.filters.unshift({
|
|
474
|
-
type: "Workspace",
|
|
475
|
-
workspaceIds: [workspaceId]
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
if (internalTypeName) {
|
|
479
|
-
cplaceFilter.filters.unshift({
|
|
480
|
-
type: "Type",
|
|
481
|
-
types: [internalTypeName]
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
debugLogWithTag('CSV_SEARCH', `Final cplace filter: ${JSON.stringify(cplaceFilter)}`);
|
|
485
|
-
const result = await client.makeApiRequest('json/search', 'GET', {
|
|
486
|
-
filter: JSON.stringify(cplaceFilter),
|
|
487
|
-
limit,
|
|
488
|
-
offset
|
|
489
|
-
});
|
|
490
|
-
const searchResults = result.results || [];
|
|
491
|
-
debugLogWithTag('CSV_SEARCH', `Retrieved ${searchResults.length} results for CSV conversion`);
|
|
492
|
-
const csvContent = await convertPagesToCsv(searchResults, client, attributes);
|
|
493
|
-
return {
|
|
494
|
-
content: [{ type: "text", text: csvContent }]
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
catch (error) {
|
|
498
|
-
debugLogWithTag('CSV_SEARCH', `Error during CSV search: ${error instanceof Error ? error.message : String(error)}`);
|
|
499
|
-
return {
|
|
500
|
-
content: [{ type: "text", text: `Error converting or executing CSV search: ${error instanceof Error ? error.message : String(error)}` }]
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
server.registerTool("cplace_list_widget_definitions", {
|
|
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
|
-
},
|
|
512
|
-
annotations: { title: "List Widget Definitions" }
|
|
513
|
-
}, async ({ embeddingContext = "AS_WIDGET" }) => {
|
|
514
|
-
debugLogWithTag('WIDGETS', `Starting widget definitions list request with embeddingContext: ${embeddingContext}`);
|
|
515
|
-
try {
|
|
516
|
-
const result = await client.makeApiRequest('json/widget-definitions', 'GET', { embeddingContext });
|
|
517
|
-
debugLogWithTag('WIDGETS', `Retrieved widget definitions for context: ${embeddingContext}`);
|
|
518
|
-
return {
|
|
519
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
catch (error) {
|
|
523
|
-
return {
|
|
524
|
-
content: [{ type: "text", text: `Error retrieving widget definitions: ${error instanceof Error ? error.message : String(error)}` }]
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
server.registerTool("cplace_get_widget_definition", {
|
|
529
|
-
description: "Get detailed information about a specific widget definition including its complete configuration schema with all attributes, constraints, and metadata",
|
|
530
|
-
inputSchema: {
|
|
531
|
-
widgetKind: z.string().describe("The widget kind identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki')")
|
|
532
|
-
},
|
|
533
|
-
annotations: { title: "Get Widget Definition Details" }
|
|
534
|
-
}, async ({ widgetKind }) => {
|
|
535
|
-
debugLogWithTag('WIDGETS', `Starting widget definition request for: ${widgetKind}`);
|
|
536
|
-
try {
|
|
537
|
-
const result = await client.makeApiRequest('json/widget-definition', 'GET', { widgetKind });
|
|
538
|
-
debugLogWithTag('WIDGETS', `Retrieved widget definition for: ${widgetKind}`);
|
|
539
|
-
return {
|
|
540
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
catch (error) {
|
|
544
|
-
return {
|
|
545
|
-
content: [{ type: "text", text: `Error retrieving widget definition for ${widgetKind}: ${error instanceof Error ? error.message : String(error)}` }]
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
server.registerTool("cplace_get_page_layout_overview", {
|
|
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.",
|
|
551
|
-
inputSchema: {
|
|
552
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page to get layout for, e.g. 'page/kkt8ol745jqur4581kelm5ply'")
|
|
553
|
-
},
|
|
554
|
-
annotations: { title: "Get Page Layout Overview" }
|
|
555
|
-
}, async ({ pageUID }) => {
|
|
556
|
-
debugLogWithTag('LAYOUT', `Starting page layout overview request for: ${pageUID}`);
|
|
557
|
-
try {
|
|
558
|
-
const result = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
559
|
-
const overview = {
|
|
560
|
-
rows: result.rows?.map((row, rowIndex) => ({
|
|
561
|
-
rowIndex,
|
|
562
|
-
columns: row.columns?.map((column, colIndex) => ({
|
|
563
|
-
columnIndex: colIndex,
|
|
564
|
-
proportion: column.proportion,
|
|
565
|
-
widgets: column.widgets?.map((widget) => ({
|
|
566
|
-
id: widget.id,
|
|
567
|
-
widgetType: widget.widgetType,
|
|
568
|
-
configurationCount: widget.configuration?.length || 0
|
|
569
|
-
})) || []
|
|
570
|
-
})) || []
|
|
571
|
-
})) || []
|
|
572
|
-
};
|
|
573
|
-
debugLogWithTag('LAYOUT', `Retrieved page layout overview for: ${pageUID}`);
|
|
574
|
-
return {
|
|
575
|
-
content: [{ type: "text", text: JSON.stringify(overview, null, 2) }]
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
catch (error) {
|
|
579
|
-
return {
|
|
580
|
-
content: [{ type: "text", text: `Error retrieving page layout overview for ${pageUID}: ${error instanceof Error ? error.message : String(error)}` }]
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
});
|
|
584
|
-
server.registerTool("cplace_get_widget_details", {
|
|
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.",
|
|
586
|
-
inputSchema: {
|
|
587
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
588
|
-
widgetId: z.string().describe("The unique widget identifier from the layout (e.g., 'id_123', 'id_456')")
|
|
589
|
-
},
|
|
590
|
-
annotations: { title: "Get Widget Details" }
|
|
591
|
-
}, async ({ pageUID, widgetId }) => {
|
|
592
|
-
debugLogWithTag('LAYOUT', `Starting widget details request for widget ${widgetId} in page ${pageUID}`);
|
|
593
|
-
try {
|
|
594
|
-
const result = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
595
|
-
let foundWidget = null;
|
|
596
|
-
const findWidget = (rows) => {
|
|
597
|
-
for (const row of rows || []) {
|
|
598
|
-
for (const column of row.columns || []) {
|
|
599
|
-
for (const widget of column.widgets || []) {
|
|
600
|
-
if (widget.id === widgetId) {
|
|
601
|
-
return widget;
|
|
602
|
-
}
|
|
603
|
-
if (widget.widgetsLayout?.rows) {
|
|
604
|
-
const nestedWidget = findWidget(widget.widgetsLayout.rows);
|
|
605
|
-
if (nestedWidget)
|
|
606
|
-
return nestedWidget;
|
|
607
|
-
}
|
|
36
|
+
const groupDetails = Array.from(activeGroups).map(name => ({
|
|
37
|
+
name,
|
|
38
|
+
description: TOOL_GROUPS[name]?.description || 'Unknown group',
|
|
39
|
+
toolCount: TOOL_GROUPS[name]?.tools.length || 0,
|
|
40
|
+
tools: TOOL_GROUPS[name]?.tools || []
|
|
41
|
+
}));
|
|
42
|
+
const allGroups = Object.entries(TOOL_GROUPS).map(([name, group]) => ({
|
|
43
|
+
name,
|
|
44
|
+
description: group.description,
|
|
45
|
+
toolCount: group.tools.length,
|
|
46
|
+
active: activeGroups.has(name)
|
|
47
|
+
}));
|
|
48
|
+
return {
|
|
49
|
+
content: [{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: JSON.stringify({
|
|
52
|
+
active_groups: Array.from(activeGroups),
|
|
53
|
+
total_active_tools: activeTools.size,
|
|
54
|
+
active_group_details: groupDetails,
|
|
55
|
+
all_available_groups: allGroups,
|
|
56
|
+
usage_examples: {
|
|
57
|
+
minimal: "No --profiles argument (core only)",
|
|
58
|
+
page_editing: "--profiles=pages_write",
|
|
59
|
+
dashboard_dev: "--profiles=pages_write+layouts",
|
|
60
|
+
type_dev: "--profiles=types_write+low_code",
|
|
61
|
+
full_access: "--profiles=all"
|
|
608
62
|
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
};
|
|
613
|
-
foundWidget = findWidget(result.rows);
|
|
614
|
-
if (!foundWidget) {
|
|
615
|
-
return {
|
|
616
|
-
content: [{ type: "text", text: `Widget with ID ${widgetId} not found in page ${pageUID}` }]
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
debugLogWithTag('LAYOUT', `Retrieved widget details for: ${widgetId} in page`);
|
|
620
|
-
return {
|
|
621
|
-
content: [{ type: "text", text: JSON.stringify(foundWidget, null, 2) }]
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
catch (error) {
|
|
625
|
-
return {
|
|
626
|
-
content: [{ type: "text", text: `Error retrieving widget details for ${widgetId} in page ${pageUID}: ${error instanceof Error ? error.message : String(error)}` }]
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
});
|
|
630
|
-
server.registerTool("cplace_get_current_user", {
|
|
631
|
-
description: "Get information about the currently logged-in user, including their attributes and metadata",
|
|
632
|
-
inputSchema: {},
|
|
633
|
-
annotations: { title: "Get Current User" }
|
|
634
|
-
}, async () => {
|
|
635
|
-
debugLogWithTag('CURRENT_USER', 'Starting current user request');
|
|
636
|
-
try {
|
|
637
|
-
const result = await client.makeApiRequest('json/current-user');
|
|
638
|
-
debugLogWithTag('CURRENT_USER', `Retrieved current user information`);
|
|
639
|
-
return {
|
|
640
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
catch (error) {
|
|
644
|
-
return {
|
|
645
|
-
content: [{ type: "text", text: `Error retrieving current user information: ${error instanceof Error ? error.message : String(error)}` }]
|
|
646
|
-
};
|
|
647
|
-
}
|
|
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
|
-
}
|
|
63
|
+
}, null, 2)
|
|
64
|
+
}]
|
|
65
|
+
};
|
|
1146
66
|
});
|
|
1147
67
|
async function runServer() {
|
|
1148
68
|
const transport = new StdioServerTransport();
|
|
1149
69
|
await server.connect(transport);
|
|
1150
|
-
|
|
70
|
+
debugLogWithTag('MCP', 'Server running on stdio');
|
|
1151
71
|
}
|
|
1152
72
|
runServer().catch((error) => {
|
|
1153
|
-
|
|
73
|
+
debugLogWithTag('MCP', `Fatal error running server: ${error}`);
|
|
1154
74
|
process.exit(1);
|
|
1155
75
|
});
|
|
1156
76
|
//# sourceMappingURL=index.js.map
|