@kontent-ai/mcp-server 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -61
- package/build/schemas/bulkGetItemsWithVariantsSchemas.js +1 -1
- package/build/schemas/contentItemSchemas.js +1 -1
- package/build/schemas/filterVariantSchemas.js +8 -3
- package/build/schemas/searchOperationSchemas.js +2 -1
- package/build/server.js +4 -112
- package/build/test/bm25/bm25.js +47 -0
- package/build/test/bm25/toolSearchBm25.spec.js +874 -0
- package/build/tools/bulk-get-content-item-variants.js +31 -0
- package/build/tools/change-content-item-variant-workflow-step.js +35 -0
- package/build/tools/create-content-item-variant.js +44 -0
- package/build/tools/create-content-item.js +47 -0
- package/build/tools/create-content-type-snippet.js +34 -0
- package/build/tools/create-content-type.js +37 -0
- package/build/tools/create-language.js +24 -0
- package/build/tools/create-new-content-item-variant-version.js +27 -0
- package/build/tools/create-space.js +22 -0
- package/build/tools/create-taxonomy-group.js +18 -0
- package/build/tools/create-workflow.js +23 -0
- package/build/tools/delete-content-item-variant.js +25 -0
- package/build/tools/delete-content-item.js +23 -0
- package/build/tools/delete-content-type-snippet.js +19 -0
- package/build/tools/delete-content-type.js +23 -0
- package/build/tools/delete-space.js +19 -0
- package/build/tools/delete-taxonomy-group.js +19 -0
- package/build/tools/delete-workflow.js +19 -0
- package/build/tools/get-asset.js +17 -0
- package/build/tools/get-content-item-translations.js +20 -0
- package/build/tools/get-content-item-variant.js +22 -0
- package/build/tools/get-content-item.js +17 -0
- package/build/tools/get-content-type-snippet.js +20 -0
- package/build/tools/get-content-type.js +17 -0
- package/build/tools/get-patch-guide.js +12 -12
- package/build/tools/get-published-content-item-variant-version.js +23 -0
- package/build/tools/get-taxonomy-group.js +17 -0
- package/build/tools/index.js +106 -0
- package/build/tools/list-asset-folders.js +14 -0
- package/build/tools/list-assets.js +23 -0
- package/build/tools/list-collections.js +14 -0
- package/build/tools/list-content-item-variants.js +50 -0
- package/build/tools/list-content-type-snippets.js +23 -0
- package/build/tools/list-content-types.js +23 -0
- package/build/tools/list-languages.js +24 -0
- package/build/tools/list-roles.js +14 -0
- package/build/tools/list-spaces.js +14 -0
- package/build/tools/list-taxonomy-groups.js +23 -0
- package/build/tools/list-workflows.js +14 -0
- package/build/tools/patch-asset-folders.js +25 -0
- package/build/tools/patch-collections.js +25 -0
- package/build/tools/patch-content-type-snippet.js +30 -0
- package/build/tools/patch-content-type.js +33 -0
- package/build/tools/patch-language.js +24 -0
- package/build/tools/patch-space.js +28 -0
- package/build/tools/patch-taxonomy-group.js +28 -0
- package/build/tools/publish-content-item-variant.js +72 -0
- package/build/tools/referencedToolNames.js +10 -0
- package/build/tools/search-content-item-variants.js +108 -0
- package/build/tools/toolDefinition.js +1 -0
- package/build/tools/unpublish-content-item-variant.js +72 -0
- package/build/tools/update-asset.js +23 -0
- package/build/tools/update-content-item-variant.js +36 -0
- package/build/tools/update-content-item.js +74 -0
- package/build/tools/update-workflow.js +31 -0
- package/package.json +18 -17
- package/build/tools/add-content-item-mapi.js +0 -47
- package/build/tools/add-content-type-mapi.js +0 -38
- package/build/tools/add-content-type-snippet-mapi.js +0 -35
- package/build/tools/add-language-mapi.js +0 -25
- package/build/tools/add-space-mapi.js +0 -23
- package/build/tools/add-taxonomy-group-mapi.js +0 -19
- package/build/tools/add-workflow-mapi.js +0 -24
- package/build/tools/bulk-get-items-variants-mapi.js +0 -31
- package/build/tools/change-variant-workflow-step-mapi.js +0 -36
- package/build/tools/create-language-variant-mapi.js +0 -44
- package/build/tools/create-variant-version-mapi.js +0 -28
- package/build/tools/delete-content-item-mapi.js +0 -24
- package/build/tools/delete-content-type-mapi.js +0 -24
- package/build/tools/delete-language-variant-mapi.js +0 -26
- package/build/tools/delete-space-mapi.js +0 -20
- package/build/tools/delete-taxonomy-group-mapi.js +0 -20
- package/build/tools/delete-type-snippet-mapi.js +0 -23
- package/build/tools/delete-workflow-mapi.js +0 -20
- package/build/tools/filter-variants-mapi.js +0 -49
- package/build/tools/get-asset-mapi.js +0 -21
- package/build/tools/get-item-mapi.js +0 -21
- package/build/tools/get-latest-variant-mapi.js +0 -23
- package/build/tools/get-published-variant-mapi.js +0 -24
- package/build/tools/get-taxonomy-group-mapi.js +0 -21
- package/build/tools/get-type-mapi.js +0 -21
- package/build/tools/get-type-snippet-mapi.js +0 -21
- package/build/tools/list-asset-folders-mapi.js +0 -15
- package/build/tools/list-assets-mapi.js +0 -24
- package/build/tools/list-collections-mapi.js +0 -15
- package/build/tools/list-content-type-snippets-mapi.js +0 -24
- package/build/tools/list-content-types-mapi.js +0 -24
- package/build/tools/list-languages-mapi.js +0 -24
- package/build/tools/list-roles-mapi.js +0 -15
- package/build/tools/list-spaces-mapi.js +0 -15
- package/build/tools/list-taxonomy-groups-mapi.js +0 -24
- package/build/tools/list-variants-collection-mapi.js +0 -26
- package/build/tools/list-variants-components-type-mapi.js +0 -26
- package/build/tools/list-variants-item-mapi.js +0 -21
- package/build/tools/list-variants-space-mapi.js +0 -24
- package/build/tools/list-variants-type-mapi.js +0 -26
- package/build/tools/list-workflows-mapi.js +0 -15
- package/build/tools/patch-asset-folders-mapi.js +0 -25
- package/build/tools/patch-collections-mapi.js +0 -25
- package/build/tools/patch-content-type-mapi.js +0 -33
- package/build/tools/patch-language-mapi.js +0 -24
- package/build/tools/patch-space-mapi.js +0 -28
- package/build/tools/patch-taxonomy-group-mapi.js +0 -28
- package/build/tools/patch-type-snippet-mapi.js +0 -30
- package/build/tools/publish-variant-mapi.js +0 -73
- package/build/tools/search-variants-mapi.js +0 -108
- package/build/tools/unpublish-variant-mapi.js +0 -73
- package/build/tools/update-asset-mapi.js +0 -24
- package/build/tools/update-content-item-mapi.js +0 -74
- package/build/tools/update-language-variant-mapi.js +0 -37
- package/build/tools/update-workflow-mapi.js +0 -32
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
+
import { defineTool } from "./toolDefinition.js";
|
|
6
|
+
export const publishContentItemVariant = defineTool("publish-content-item-variant", "Publish or schedule publishing of Kontent.ai content item variant (language version/translation). Transitions content to the published workflow step, making it live. For scheduling, verify current UTC time before using scheduledTo.", {
|
|
7
|
+
itemId: z.guid().describe("Content item ID"),
|
|
8
|
+
languageId: z
|
|
9
|
+
.guid()
|
|
10
|
+
.describe("Language ID (default: 00000000-0000-0000-0000-000000000000)"),
|
|
11
|
+
scheduledTo: z.iso
|
|
12
|
+
.datetime({ offset: true })
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("ISO 8601 datetime for scheduled publish (omit for immediate)"),
|
|
15
|
+
displayTimezone: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Timezone for UI display (e.g., America/New_York, UTC)"),
|
|
19
|
+
}, async ({ itemId, languageId, scheduledTo, displayTimezone }, { authInfo: { token, clientId } = {} }) => {
|
|
20
|
+
const client = createMapiClient(clientId, token);
|
|
21
|
+
try {
|
|
22
|
+
// Validate that displayTimezone can only be used with scheduledTo
|
|
23
|
+
if (displayTimezone && !scheduledTo) {
|
|
24
|
+
throw new Error("The 'displayTimezone' parameter can only be used in combination with 'scheduledTo' parameter for scheduled publishing.");
|
|
25
|
+
}
|
|
26
|
+
let action;
|
|
27
|
+
let message;
|
|
28
|
+
if (scheduledTo) {
|
|
29
|
+
// Scheduled publishing
|
|
30
|
+
const requestData = {
|
|
31
|
+
scheduled_to: scheduledTo,
|
|
32
|
+
};
|
|
33
|
+
// Add display_timezone if provided
|
|
34
|
+
if (displayTimezone) {
|
|
35
|
+
requestData.display_timezone = displayTimezone;
|
|
36
|
+
}
|
|
37
|
+
await client
|
|
38
|
+
.publishLanguageVariant()
|
|
39
|
+
.byItemId(itemId)
|
|
40
|
+
.byLanguageId(languageId)
|
|
41
|
+
.withData(requestData)
|
|
42
|
+
.toPromise();
|
|
43
|
+
action = "scheduled";
|
|
44
|
+
message = `Successfully scheduled item variant '${languageId}' for content item '${itemId}' to be published at '${scheduledTo}'${displayTimezone ? ` (timezone: ${displayTimezone})` : ""}.`;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Immediate publishing
|
|
48
|
+
await client
|
|
49
|
+
.publishLanguageVariant()
|
|
50
|
+
.byItemId(itemId)
|
|
51
|
+
.byLanguageId(languageId)
|
|
52
|
+
.withoutData()
|
|
53
|
+
.toPromise();
|
|
54
|
+
action = "published";
|
|
55
|
+
message = `Successfully published item variant '${languageId}' for content item '${itemId}'. The content is now live and available through Delivery API.`;
|
|
56
|
+
}
|
|
57
|
+
return createMcpToolSuccessResponse({
|
|
58
|
+
message,
|
|
59
|
+
result: {
|
|
60
|
+
itemId,
|
|
61
|
+
languageId,
|
|
62
|
+
scheduledTo: scheduledTo || null,
|
|
63
|
+
displayTimezone: displayTimezone || null,
|
|
64
|
+
action,
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return handleMcpToolError(error, "Publish/Schedule Language Variant");
|
|
71
|
+
}
|
|
72
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Tools whose names are referenced by other tools
|
|
2
|
+
export const searchContentItemVariantsToolName = "search-content-item-variants";
|
|
3
|
+
export const listContentItemVariantsToolName = "list-content-item-variants";
|
|
4
|
+
export const bulkGetContentItemVariantsToolName = "bulk-get-content-item-variants";
|
|
5
|
+
export const createContentItemToolName = "create-content-item";
|
|
6
|
+
export const createContentItemVariantToolName = "create-content-item-variant";
|
|
7
|
+
export const getPatchGuideToolName = "get-patch-guide";
|
|
8
|
+
export const getTaxonomyGroupToolName = "get-taxonomy-group";
|
|
9
|
+
export const listCollectionsToolName = "list-collections";
|
|
10
|
+
export const listLanguagesToolName = "list-languages";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import pRetry, { AbortError } from "p-retry";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { searchOperationSchema } from "../schemas/searchOperationSchemas.js";
|
|
4
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
|
+
import { throwError } from "../utils/throwError.js";
|
|
7
|
+
import { bulkGetContentItemVariantsToolName, listContentItemVariantsToolName, searchContentItemVariantsToolName, } from "./referencedToolNames.js";
|
|
8
|
+
import { defineTool } from "./toolDefinition.js";
|
|
9
|
+
class OperationResultIncompleteError extends Error {
|
|
10
|
+
constructor() {
|
|
11
|
+
super("AI operation result is incomplete");
|
|
12
|
+
this.name = "OperationResultIncompleteError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const isSearchResponseWrapper = (value) => typeof value === "object" && value !== null && "searchResults" in value;
|
|
16
|
+
const extractSearchResults = (response) => {
|
|
17
|
+
const value = response.result?.value;
|
|
18
|
+
if (!value) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
const parsed = JSON.parse(value);
|
|
22
|
+
if (isSearchResponseWrapper(parsed)) {
|
|
23
|
+
return JSON.parse(parsed.searchResults);
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
};
|
|
27
|
+
export const searchContentItemVariants = defineTool(searchContentItemVariantsToolName, `AI semantic search for Kontent.ai content items with content item variants (language versions/translations) by topic, theme, or meaning. Find content by natural language query. Returns only top 50 results. This feature may be unavailable. Use ${listContentItemVariantsToolName} for full content inventory filtering or exact keyword matching. Use ${bulkGetContentItemVariantsToolName} to retrieve full content of the variants.`, searchOperationSchema.shape, async ({ searchPhrase, filter }, { authInfo: { token, clientId } = {} }) => {
|
|
28
|
+
try {
|
|
29
|
+
const environmentId = clientId ?? process.env.KONTENT_ENVIRONMENT_ID;
|
|
30
|
+
if (!environmentId) {
|
|
31
|
+
throwError("Missing required environment ID");
|
|
32
|
+
}
|
|
33
|
+
const client = createMapiClient(environmentId, token);
|
|
34
|
+
// Step 1: Initiate the AI search operation
|
|
35
|
+
const searchPayload = {
|
|
36
|
+
actionName: "Search",
|
|
37
|
+
type: "multiple-inputs-request-v1",
|
|
38
|
+
inputs: {
|
|
39
|
+
searchPhrase: {
|
|
40
|
+
type: "string",
|
|
41
|
+
value: searchPhrase,
|
|
42
|
+
},
|
|
43
|
+
filter: {
|
|
44
|
+
type: "content-item-variant-filter",
|
|
45
|
+
value: filter,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
trackingData: {
|
|
49
|
+
type: "empty-operation-tracking-data-v1",
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
let searchResponse;
|
|
53
|
+
try {
|
|
54
|
+
searchResponse = await client
|
|
55
|
+
.post()
|
|
56
|
+
.withAction(`projects/${environmentId}/early-access/ai-operation`)
|
|
57
|
+
.withData(searchPayload)
|
|
58
|
+
.toPromise();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (error?.response?.status === 403 &&
|
|
62
|
+
error?.response?.data?.message?.includes("AI Feature Not Available")) {
|
|
63
|
+
return createMcpToolSuccessResponse({
|
|
64
|
+
status: "unavailable",
|
|
65
|
+
result: `AI search feature is not available for environment ${clientId}`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
const operationData = searchResponse.data;
|
|
71
|
+
const operationId = operationData.operationId;
|
|
72
|
+
// Step 2: Poll for results with exponential backoff
|
|
73
|
+
const resultData = await pRetry(async () => {
|
|
74
|
+
try {
|
|
75
|
+
const pollResponse = await client
|
|
76
|
+
.get()
|
|
77
|
+
.withAction(`projects/${environmentId}/early-access/ai-operation-result/${operationId}`)
|
|
78
|
+
.toPromise();
|
|
79
|
+
const [response] = pollResponse.data;
|
|
80
|
+
if (response.type === "cumulated-result-v1" &&
|
|
81
|
+
!response.result?.isFinished) {
|
|
82
|
+
throw new OperationResultIncompleteError();
|
|
83
|
+
}
|
|
84
|
+
return response;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (error?.response?.status === 404 ||
|
|
88
|
+
error instanceof OperationResultIncompleteError) {
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
throw new AbortError(error);
|
|
92
|
+
}
|
|
93
|
+
}, {
|
|
94
|
+
// Worst-case retry time: ~1 minute
|
|
95
|
+
retries: 10,
|
|
96
|
+
minTimeout: 1000,
|
|
97
|
+
maxTimeout: 10000,
|
|
98
|
+
factor: 1.5,
|
|
99
|
+
});
|
|
100
|
+
const searchResults = extractSearchResults(resultData);
|
|
101
|
+
return createMcpToolSuccessResponse({
|
|
102
|
+
result: searchResults,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return handleMcpToolError(error, "AI-powered Variant Search");
|
|
107
|
+
}
|
|
108
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const defineTool = (name, description, inputSchema, handler) => ({ name, description, inputSchema, handler });
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
+
import { defineTool } from "./toolDefinition.js";
|
|
6
|
+
export const unpublishContentItemVariant = defineTool("unpublish-content-item-variant", "Unpublish or schedule unpublishing of Kontent.ai content item variant (language version/translation). Takes content offline and archives it. For scheduling, verify current UTC time before using scheduledTo.", {
|
|
7
|
+
itemId: z.guid().describe("Content item ID"),
|
|
8
|
+
languageId: z
|
|
9
|
+
.guid()
|
|
10
|
+
.describe("Language ID (default: 00000000-0000-0000-0000-000000000000)"),
|
|
11
|
+
scheduledTo: z.iso
|
|
12
|
+
.datetime({ offset: true })
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("ISO 8601 datetime for scheduled unpublish (omit for immediate)"),
|
|
15
|
+
displayTimezone: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Timezone for UI display (e.g., America/New_York, UTC)"),
|
|
19
|
+
}, async ({ itemId, languageId, scheduledTo, displayTimezone }, { authInfo: { token, clientId } = {} }) => {
|
|
20
|
+
const client = createMapiClient(clientId, token);
|
|
21
|
+
try {
|
|
22
|
+
// Validate that displayTimezone can only be used with scheduledTo
|
|
23
|
+
if (displayTimezone && !scheduledTo) {
|
|
24
|
+
throw new Error("The 'displayTimezone' parameter can only be used in combination with 'scheduledTo' parameter for scheduled unpublishing.");
|
|
25
|
+
}
|
|
26
|
+
let action;
|
|
27
|
+
let message;
|
|
28
|
+
if (scheduledTo) {
|
|
29
|
+
// Scheduled unpublishing
|
|
30
|
+
const requestData = {
|
|
31
|
+
scheduled_to: scheduledTo,
|
|
32
|
+
};
|
|
33
|
+
// Add display_timezone if provided
|
|
34
|
+
if (displayTimezone) {
|
|
35
|
+
requestData.display_timezone = displayTimezone;
|
|
36
|
+
}
|
|
37
|
+
await client
|
|
38
|
+
.unpublishLanguageVariant()
|
|
39
|
+
.byItemId(itemId)
|
|
40
|
+
.byLanguageId(languageId)
|
|
41
|
+
.withData(requestData)
|
|
42
|
+
.toPromise();
|
|
43
|
+
action = "scheduled for unpublishing";
|
|
44
|
+
message = `Successfully scheduled item variant '${languageId}' for content item '${itemId}' to be unpublished at '${scheduledTo}'${displayTimezone ? ` (timezone: ${displayTimezone})` : ""}. The content will be removed from Delivery API at the scheduled time.`;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Immediate unpublishing
|
|
48
|
+
await client
|
|
49
|
+
.unpublishLanguageVariant()
|
|
50
|
+
.byItemId(itemId)
|
|
51
|
+
.byLanguageId(languageId)
|
|
52
|
+
.withoutData()
|
|
53
|
+
.toPromise();
|
|
54
|
+
action = "unpublished";
|
|
55
|
+
message = `Successfully unpublished item variant '${languageId}' for content item '${itemId}'. The content has been moved to Archived and is no longer available through Delivery API.`;
|
|
56
|
+
}
|
|
57
|
+
return createMcpToolSuccessResponse({
|
|
58
|
+
message,
|
|
59
|
+
result: {
|
|
60
|
+
itemId,
|
|
61
|
+
languageId,
|
|
62
|
+
scheduledTo: scheduledTo || null,
|
|
63
|
+
displayTimezone: displayTimezone || null,
|
|
64
|
+
action,
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return handleMcpToolError(error, "Unpublish/Schedule Unpublishing Language Variant");
|
|
71
|
+
}
|
|
72
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { updateAssetDataSchema } from "../schemas/assetSchemas.js";
|
|
4
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
|
+
import { defineTool } from "./toolDefinition.js";
|
|
7
|
+
export const updateAsset = defineTool("update-asset", "Update (edit) Kontent.ai asset metadata by ID. Modify asset title, descriptions, or taxonomy-based properties.", {
|
|
8
|
+
id: z.guid().describe("Asset ID"),
|
|
9
|
+
data: updateAssetDataSchema,
|
|
10
|
+
}, async ({ id, data }, { authInfo: { token, clientId } = {} }) => {
|
|
11
|
+
const client = createMapiClient(clientId, token);
|
|
12
|
+
try {
|
|
13
|
+
const response = await client
|
|
14
|
+
.upsertAsset()
|
|
15
|
+
.byAssetId(id)
|
|
16
|
+
.withData(() => data)
|
|
17
|
+
.toPromise();
|
|
18
|
+
return createMcpToolSuccessResponse(response.rawData);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
return handleMcpToolError(error, "Asset Update");
|
|
22
|
+
}
|
|
23
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { languageVariantElementSchema } from "../schemas/contentItemSchemas.js";
|
|
4
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
|
+
import { defineTool } from "./toolDefinition.js";
|
|
7
|
+
export const updateContentItemVariant = defineTool("update-content-item-variant", "Update Kontent.ai content item variant (language version/translation) content. Write translated content into item elements. Values must fulfill validation rules defined in the content type.", {
|
|
8
|
+
itemId: z.string().describe("Content item ID"),
|
|
9
|
+
languageId: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe("Language ID (default: 00000000-0000-0000-0000-000000000000)"),
|
|
12
|
+
elements: z
|
|
13
|
+
.array(languageVariantElementSchema)
|
|
14
|
+
.describe("Content elements array"),
|
|
15
|
+
workflow_step_id: z.string().optional().describe("Workflow step ID"),
|
|
16
|
+
}, async ({ itemId, languageId, elements, workflow_step_id }, { authInfo: { token, clientId } = {} }) => {
|
|
17
|
+
const client = createMapiClient(clientId, token);
|
|
18
|
+
const data = {
|
|
19
|
+
elements,
|
|
20
|
+
};
|
|
21
|
+
if (workflow_step_id) {
|
|
22
|
+
data.workflow_step = { id: workflow_step_id };
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const response = await client
|
|
26
|
+
.upsertLanguageVariant()
|
|
27
|
+
.byItemId(itemId)
|
|
28
|
+
.byLanguageId(languageId)
|
|
29
|
+
.withData(() => data)
|
|
30
|
+
.toPromise();
|
|
31
|
+
return createMcpToolSuccessResponse(response.rawData);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
return handleMcpToolError(error, "Language Variant Update");
|
|
35
|
+
}
|
|
36
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
+
import { createContentItemToolName } from "./referencedToolNames.js";
|
|
6
|
+
import { defineTool } from "./toolDefinition.js";
|
|
7
|
+
export const updateContentItem = defineTool("update-content-item", "Update (edit) Kontent.ai content item metadata: name, collection.", {
|
|
8
|
+
id: z.string().describe("Content item ID"),
|
|
9
|
+
name: z
|
|
10
|
+
.string()
|
|
11
|
+
.min(1)
|
|
12
|
+
.max(200)
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("New name (1-200 chars)"),
|
|
15
|
+
collection: z
|
|
16
|
+
.object({
|
|
17
|
+
id: z.string().optional(),
|
|
18
|
+
codename: z.string().optional(),
|
|
19
|
+
external_id: z.string().optional(),
|
|
20
|
+
})
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Collection reference"),
|
|
23
|
+
}, async ({ id, name, collection }, { authInfo: { token, clientId } = {} }) => {
|
|
24
|
+
const client = createMapiClient(clientId, token);
|
|
25
|
+
try {
|
|
26
|
+
// First, verify the item exists by trying to get it
|
|
27
|
+
await client.viewContentItem().byItemId(id).toPromise();
|
|
28
|
+
// If we get here, the item exists, so we can update it
|
|
29
|
+
const updateData = {};
|
|
30
|
+
if (name !== undefined) {
|
|
31
|
+
updateData.name = name;
|
|
32
|
+
}
|
|
33
|
+
if (collection !== undefined) {
|
|
34
|
+
updateData.collection = collection;
|
|
35
|
+
}
|
|
36
|
+
// If no update data is provided, return an error
|
|
37
|
+
if (Object.keys(updateData).length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: "Update Content Item: No update data provided. At least one field (name or collection) must be specified.",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const response = await client
|
|
49
|
+
.upsertContentItem()
|
|
50
|
+
.byItemId(id)
|
|
51
|
+
.withData(updateData)
|
|
52
|
+
.toPromise();
|
|
53
|
+
return createMcpToolSuccessResponse({
|
|
54
|
+
message: `Content item '${id}' updated successfully`,
|
|
55
|
+
updatedItem: response.rawData,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
// Check if the error is because the item doesn't exist
|
|
60
|
+
if (error?.response?.status === 404 ||
|
|
61
|
+
error?.message?.includes("not found")) {
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: "text",
|
|
66
|
+
text: `Update Content Item: Content item with ID '${id}' does not exist. Use ${createContentItemToolName} to create new items.`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return handleMcpToolError(error, "Content Item Update");
|
|
73
|
+
}
|
|
74
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
+
import { workflowInputSchema } from "../schemas/workflowSchemas.js";
|
|
4
|
+
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
+
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
|
+
import { defineTool } from "./toolDefinition.js";
|
|
7
|
+
export const updateWorkflow = defineTool("update-workflow", "Update (edit) Kontent.ai workflow steps, transitions, and settings. Modify content lifecycle stages.", {
|
|
8
|
+
id: z.guid().describe("Workflow ID"),
|
|
9
|
+
...workflowInputSchema.shape,
|
|
10
|
+
}, async ({ id, name, codename, scopes, steps, published_step, archived_step }, { authInfo: { token, clientId } = {} }) => {
|
|
11
|
+
const client = createMapiClient(clientId, token);
|
|
12
|
+
const data = {
|
|
13
|
+
name,
|
|
14
|
+
codename,
|
|
15
|
+
scopes,
|
|
16
|
+
steps,
|
|
17
|
+
published_step,
|
|
18
|
+
archived_step,
|
|
19
|
+
};
|
|
20
|
+
try {
|
|
21
|
+
const response = await client
|
|
22
|
+
.updateWorkflow()
|
|
23
|
+
.byWorkflowId(id)
|
|
24
|
+
.withData(data)
|
|
25
|
+
.toPromise();
|
|
26
|
+
return createMcpToolSuccessResponse(response.rawData);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return handleMcpToolError(error, "Workflow Update");
|
|
30
|
+
}
|
|
31
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kontent-ai/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"mcpName": "io.github.kontent-ai/mcp-server",
|
|
6
6
|
"repository": {
|
|
@@ -29,23 +29,24 @@
|
|
|
29
29
|
"author": "Jiri Lojda",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@kontent-ai/management-sdk": "
|
|
33
|
-
"@modelcontextprotocol/sdk": "
|
|
34
|
-
"applicationinsights": "
|
|
35
|
-
"dotenv": "
|
|
36
|
-
"express": "
|
|
37
|
-
"p-retry": "
|
|
38
|
-
"zod": "
|
|
32
|
+
"@kontent-ai/management-sdk": "8.4.1",
|
|
33
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
34
|
+
"applicationinsights": "2.9.8",
|
|
35
|
+
"dotenv": "17.4.1",
|
|
36
|
+
"express": "5.2.1",
|
|
37
|
+
"p-retry": "7.1.1",
|
|
38
|
+
"zod": "4.3.6"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@biomejs/biome": "
|
|
42
|
-
"@types/express": "
|
|
43
|
-
"@types/mocha": "
|
|
44
|
-
"@types/node": "
|
|
45
|
-
"cross-env": "
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
41
|
+
"@biomejs/biome": "2.4.11",
|
|
42
|
+
"@types/express": "5.0.6",
|
|
43
|
+
"@types/mocha": "10.0.10",
|
|
44
|
+
"@types/node": "24.12.2",
|
|
45
|
+
"cross-env": "10.1.0",
|
|
46
|
+
"minisearch": "7.2.0",
|
|
47
|
+
"mocha": "11.7.5",
|
|
48
|
+
"rimraf": "6.1.3",
|
|
49
|
+
"tsx": "4.21.0",
|
|
50
|
+
"typescript": "5.9.3"
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
-
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
-
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
-
export const registerTool = (server) => {
|
|
6
|
-
server.tool("add-content-item-mapi", "Add new Kontent.ai content item (creates structure only, use upsert-language-variant-mapi for content)", {
|
|
7
|
-
name: z.string().min(1).max(200).describe("Item name (1-200 chars)"),
|
|
8
|
-
type: z
|
|
9
|
-
.object({
|
|
10
|
-
id: z.string().optional(),
|
|
11
|
-
codename: z.string().optional(),
|
|
12
|
-
external_id: z.string().optional(),
|
|
13
|
-
})
|
|
14
|
-
.describe("Content type reference"),
|
|
15
|
-
codename: z
|
|
16
|
-
.string()
|
|
17
|
-
.optional()
|
|
18
|
-
.describe("Codename (auto-generated if omitted)"),
|
|
19
|
-
external_id: z.string().optional().describe("External ID"),
|
|
20
|
-
collection: z
|
|
21
|
-
.object({
|
|
22
|
-
id: z.string().optional(),
|
|
23
|
-
codename: z.string().optional(),
|
|
24
|
-
external_id: z.string().optional(),
|
|
25
|
-
})
|
|
26
|
-
.optional()
|
|
27
|
-
.describe("Collection reference"),
|
|
28
|
-
}, async ({ name, type, codename, external_id, collection }, { authInfo: { token, clientId } = {} }) => {
|
|
29
|
-
const client = createMapiClient(clientId, token);
|
|
30
|
-
try {
|
|
31
|
-
const response = await client
|
|
32
|
-
.addContentItem()
|
|
33
|
-
.withData({
|
|
34
|
-
name,
|
|
35
|
-
type,
|
|
36
|
-
codename,
|
|
37
|
-
external_id,
|
|
38
|
-
collection,
|
|
39
|
-
})
|
|
40
|
-
.toPromise();
|
|
41
|
-
return createMcpToolSuccessResponse(response.rawData);
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
return handleMcpToolError(error, "Content Item Creation");
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
-
import { contentGroupSchema, elementSchema, } from "../schemas/contentTypeAndSnippetSchemas.js";
|
|
4
|
-
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
-
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
|
-
export const registerTool = (server) => {
|
|
7
|
-
server.tool("add-content-type-mapi", "Add new Kontent.ai content type", {
|
|
8
|
-
name: z.string().describe("Content type name"),
|
|
9
|
-
codename: z
|
|
10
|
-
.string()
|
|
11
|
-
.optional()
|
|
12
|
-
.describe("Codename (auto-generated if omitted)"),
|
|
13
|
-
external_id: z.string().optional().describe("External ID"),
|
|
14
|
-
elements: z.array(elementSchema).describe("Elements defining structure"),
|
|
15
|
-
content_groups: z
|
|
16
|
-
.array(contentGroupSchema)
|
|
17
|
-
.optional()
|
|
18
|
-
.describe("Content groups"),
|
|
19
|
-
}, async ({ name, codename, external_id, elements, content_groups }, { authInfo: { token, clientId } = {} }) => {
|
|
20
|
-
const client = createMapiClient(clientId, token);
|
|
21
|
-
try {
|
|
22
|
-
const response = await client
|
|
23
|
-
.addContentType()
|
|
24
|
-
.withData(() => ({
|
|
25
|
-
name,
|
|
26
|
-
codename,
|
|
27
|
-
external_id,
|
|
28
|
-
elements,
|
|
29
|
-
content_groups,
|
|
30
|
-
}))
|
|
31
|
-
.toPromise();
|
|
32
|
-
return createMcpToolSuccessResponse(response.rawData);
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
return handleMcpToolError(error, "Content Type Creation");
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
|
-
import { snippetElementSchema } from "../schemas/contentTypeAndSnippetSchemas.js";
|
|
4
|
-
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
-
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
|
-
export const registerTool = (server) => {
|
|
7
|
-
server.tool("add-content-type-snippet-mapi", "Add new Kontent.ai content type snippet", {
|
|
8
|
-
name: z.string().describe("Snippet name"),
|
|
9
|
-
codename: z
|
|
10
|
-
.string()
|
|
11
|
-
.optional()
|
|
12
|
-
.describe("Codename (auto-generated if omitted)"),
|
|
13
|
-
external_id: z.string().optional().describe("External ID"),
|
|
14
|
-
elements: z
|
|
15
|
-
.array(snippetElementSchema)
|
|
16
|
-
.describe("Elements defining structure"),
|
|
17
|
-
}, async ({ name, codename, external_id, elements }, { authInfo: { token, clientId } = {} }) => {
|
|
18
|
-
const client = createMapiClient(clientId, token);
|
|
19
|
-
try {
|
|
20
|
-
const response = await client
|
|
21
|
-
.addContentTypeSnippet()
|
|
22
|
-
.withData(() => ({
|
|
23
|
-
name,
|
|
24
|
-
codename,
|
|
25
|
-
external_id,
|
|
26
|
-
elements,
|
|
27
|
-
}))
|
|
28
|
-
.toPromise();
|
|
29
|
-
return createMcpToolSuccessResponse(response.rawData);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
return handleMcpToolError(error, "Content Type Snippet Creation");
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
-
import { addLanguageSchema } from "../schemas/languageSchemas.js";
|
|
3
|
-
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
-
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
-
export const registerTool = (server) => {
|
|
6
|
-
server.tool("add-language-mapi", "Add new Kontent.ai language via Management API. Languages are always created as active.", addLanguageSchema.shape, async ({ name, codename, fallback_language, external_id }, { authInfo: { token, clientId } = {} }) => {
|
|
7
|
-
const client = createMapiClient(clientId, token);
|
|
8
|
-
try {
|
|
9
|
-
const response = await client
|
|
10
|
-
.addLanguage()
|
|
11
|
-
.withData({
|
|
12
|
-
name,
|
|
13
|
-
codename,
|
|
14
|
-
is_active: true,
|
|
15
|
-
fallback_language,
|
|
16
|
-
external_id,
|
|
17
|
-
})
|
|
18
|
-
.toPromise();
|
|
19
|
-
return createMcpToolSuccessResponse(response.rawData);
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
return handleMcpToolError(error, "Language Creation");
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
-
import { addSpaceSchema } from "../schemas/spaceSchemas.js";
|
|
3
|
-
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
-
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
-
export const registerTool = (server) => {
|
|
6
|
-
server.tool("add-space-mapi", "Add Kontent.ai space", addSpaceSchema.shape, async ({ name, codename, collections }, { authInfo: { token, clientId } = {} }) => {
|
|
7
|
-
const client = createMapiClient(clientId, token);
|
|
8
|
-
try {
|
|
9
|
-
const response = await client
|
|
10
|
-
.addSpace()
|
|
11
|
-
.withData({
|
|
12
|
-
name,
|
|
13
|
-
codename,
|
|
14
|
-
collections,
|
|
15
|
-
})
|
|
16
|
-
.toPromise();
|
|
17
|
-
return createMcpToolSuccessResponse(response.rawData);
|
|
18
|
-
}
|
|
19
|
-
catch (error) {
|
|
20
|
-
return handleMcpToolError(error, "Space Creation");
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
};
|