@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.
Files changed (119) hide show
  1. package/README.md +57 -61
  2. package/build/schemas/bulkGetItemsWithVariantsSchemas.js +1 -1
  3. package/build/schemas/contentItemSchemas.js +1 -1
  4. package/build/schemas/filterVariantSchemas.js +8 -3
  5. package/build/schemas/searchOperationSchemas.js +2 -1
  6. package/build/server.js +4 -112
  7. package/build/test/bm25/bm25.js +47 -0
  8. package/build/test/bm25/toolSearchBm25.spec.js +874 -0
  9. package/build/tools/bulk-get-content-item-variants.js +31 -0
  10. package/build/tools/change-content-item-variant-workflow-step.js +35 -0
  11. package/build/tools/create-content-item-variant.js +44 -0
  12. package/build/tools/create-content-item.js +47 -0
  13. package/build/tools/create-content-type-snippet.js +34 -0
  14. package/build/tools/create-content-type.js +37 -0
  15. package/build/tools/create-language.js +24 -0
  16. package/build/tools/create-new-content-item-variant-version.js +27 -0
  17. package/build/tools/create-space.js +22 -0
  18. package/build/tools/create-taxonomy-group.js +18 -0
  19. package/build/tools/create-workflow.js +23 -0
  20. package/build/tools/delete-content-item-variant.js +25 -0
  21. package/build/tools/delete-content-item.js +23 -0
  22. package/build/tools/delete-content-type-snippet.js +19 -0
  23. package/build/tools/delete-content-type.js +23 -0
  24. package/build/tools/delete-space.js +19 -0
  25. package/build/tools/delete-taxonomy-group.js +19 -0
  26. package/build/tools/delete-workflow.js +19 -0
  27. package/build/tools/get-asset.js +17 -0
  28. package/build/tools/get-content-item-translations.js +20 -0
  29. package/build/tools/get-content-item-variant.js +22 -0
  30. package/build/tools/get-content-item.js +17 -0
  31. package/build/tools/get-content-type-snippet.js +20 -0
  32. package/build/tools/get-content-type.js +17 -0
  33. package/build/tools/get-patch-guide.js +12 -12
  34. package/build/tools/get-published-content-item-variant-version.js +23 -0
  35. package/build/tools/get-taxonomy-group.js +17 -0
  36. package/build/tools/index.js +106 -0
  37. package/build/tools/list-asset-folders.js +14 -0
  38. package/build/tools/list-assets.js +23 -0
  39. package/build/tools/list-collections.js +14 -0
  40. package/build/tools/list-content-item-variants.js +50 -0
  41. package/build/tools/list-content-type-snippets.js +23 -0
  42. package/build/tools/list-content-types.js +23 -0
  43. package/build/tools/list-languages.js +24 -0
  44. package/build/tools/list-roles.js +14 -0
  45. package/build/tools/list-spaces.js +14 -0
  46. package/build/tools/list-taxonomy-groups.js +23 -0
  47. package/build/tools/list-workflows.js +14 -0
  48. package/build/tools/patch-asset-folders.js +25 -0
  49. package/build/tools/patch-collections.js +25 -0
  50. package/build/tools/patch-content-type-snippet.js +30 -0
  51. package/build/tools/patch-content-type.js +33 -0
  52. package/build/tools/patch-language.js +24 -0
  53. package/build/tools/patch-space.js +28 -0
  54. package/build/tools/patch-taxonomy-group.js +28 -0
  55. package/build/tools/publish-content-item-variant.js +72 -0
  56. package/build/tools/referencedToolNames.js +10 -0
  57. package/build/tools/search-content-item-variants.js +108 -0
  58. package/build/tools/toolDefinition.js +1 -0
  59. package/build/tools/unpublish-content-item-variant.js +72 -0
  60. package/build/tools/update-asset.js +23 -0
  61. package/build/tools/update-content-item-variant.js +36 -0
  62. package/build/tools/update-content-item.js +74 -0
  63. package/build/tools/update-workflow.js +31 -0
  64. package/package.json +18 -17
  65. package/build/tools/add-content-item-mapi.js +0 -47
  66. package/build/tools/add-content-type-mapi.js +0 -38
  67. package/build/tools/add-content-type-snippet-mapi.js +0 -35
  68. package/build/tools/add-language-mapi.js +0 -25
  69. package/build/tools/add-space-mapi.js +0 -23
  70. package/build/tools/add-taxonomy-group-mapi.js +0 -19
  71. package/build/tools/add-workflow-mapi.js +0 -24
  72. package/build/tools/bulk-get-items-variants-mapi.js +0 -31
  73. package/build/tools/change-variant-workflow-step-mapi.js +0 -36
  74. package/build/tools/create-language-variant-mapi.js +0 -44
  75. package/build/tools/create-variant-version-mapi.js +0 -28
  76. package/build/tools/delete-content-item-mapi.js +0 -24
  77. package/build/tools/delete-content-type-mapi.js +0 -24
  78. package/build/tools/delete-language-variant-mapi.js +0 -26
  79. package/build/tools/delete-space-mapi.js +0 -20
  80. package/build/tools/delete-taxonomy-group-mapi.js +0 -20
  81. package/build/tools/delete-type-snippet-mapi.js +0 -23
  82. package/build/tools/delete-workflow-mapi.js +0 -20
  83. package/build/tools/filter-variants-mapi.js +0 -49
  84. package/build/tools/get-asset-mapi.js +0 -21
  85. package/build/tools/get-item-mapi.js +0 -21
  86. package/build/tools/get-latest-variant-mapi.js +0 -23
  87. package/build/tools/get-published-variant-mapi.js +0 -24
  88. package/build/tools/get-taxonomy-group-mapi.js +0 -21
  89. package/build/tools/get-type-mapi.js +0 -21
  90. package/build/tools/get-type-snippet-mapi.js +0 -21
  91. package/build/tools/list-asset-folders-mapi.js +0 -15
  92. package/build/tools/list-assets-mapi.js +0 -24
  93. package/build/tools/list-collections-mapi.js +0 -15
  94. package/build/tools/list-content-type-snippets-mapi.js +0 -24
  95. package/build/tools/list-content-types-mapi.js +0 -24
  96. package/build/tools/list-languages-mapi.js +0 -24
  97. package/build/tools/list-roles-mapi.js +0 -15
  98. package/build/tools/list-spaces-mapi.js +0 -15
  99. package/build/tools/list-taxonomy-groups-mapi.js +0 -24
  100. package/build/tools/list-variants-collection-mapi.js +0 -26
  101. package/build/tools/list-variants-components-type-mapi.js +0 -26
  102. package/build/tools/list-variants-item-mapi.js +0 -21
  103. package/build/tools/list-variants-space-mapi.js +0 -24
  104. package/build/tools/list-variants-type-mapi.js +0 -26
  105. package/build/tools/list-workflows-mapi.js +0 -15
  106. package/build/tools/patch-asset-folders-mapi.js +0 -25
  107. package/build/tools/patch-collections-mapi.js +0 -25
  108. package/build/tools/patch-content-type-mapi.js +0 -33
  109. package/build/tools/patch-language-mapi.js +0 -24
  110. package/build/tools/patch-space-mapi.js +0 -28
  111. package/build/tools/patch-taxonomy-group-mapi.js +0 -28
  112. package/build/tools/patch-type-snippet-mapi.js +0 -30
  113. package/build/tools/publish-variant-mapi.js +0 -73
  114. package/build/tools/search-variants-mapi.js +0 -108
  115. package/build/tools/unpublish-variant-mapi.js +0 -73
  116. package/build/tools/update-asset-mapi.js +0 -24
  117. package/build/tools/update-content-item-mapi.js +0 -74
  118. package/build/tools/update-language-variant-mapi.js +0 -37
  119. 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.31.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": "^8.3.1",
33
- "@modelcontextprotocol/sdk": "^1.26.0",
34
- "applicationinsights": "^2.9.8",
35
- "dotenv": "^17.2.3",
36
- "express": "^5.2.1",
37
- "p-retry": "^7.1.1",
38
- "zod": "^4.1.13"
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": "^2.3.8",
42
- "@types/express": "^5.0.6",
43
- "@types/mocha": "^10.0.10",
44
- "@types/node": "^24.10.2",
45
- "cross-env": "^10.1.0",
46
- "mocha": "^11.7.5",
47
- "rimraf": "^6.1.2",
48
- "tsx": "^4.21.0",
49
- "typescript": "^5.9.3"
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
- };