@kontent-ai/mcp-server 0.8.2 → 0.10.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 CHANGED
@@ -88,6 +88,7 @@ npx @kontent-ai/mcp-server@latest sse
88
88
  * **delete-content-item-mapi** – Delete a content item by internal ID
89
89
  * **upsert-language-variant-mapi** – Create or update a language variant with content using internal IDs
90
90
  * **delete-language-variant-mapi** – Delete a language variant of a content item by internal IDs
91
+ * **filter-variants-mapi** – Search and filter language variants using filters and search phrases
91
92
 
92
93
  ### Asset Management
93
94
 
@@ -98,6 +99,11 @@ npx @kontent-ai/mcp-server@latest sse
98
99
 
99
100
  * **list-languages-mapi** – List all languages configured in the environment
100
101
 
102
+ ### Workflow Management
103
+
104
+ * **list-workflows-mapi** – List all workflows in the environment with their lifecycle stages and transitions
105
+ * **change-variant-workflow-step-mapi** – Change the workflow step of a language variant (move content through workflow stages)
106
+
101
107
  ## ⚙️ Configuration
102
108
 
103
109
  The server requires the following environment variables:
@@ -1,11 +1,5 @@
1
1
  import { z } from "zod";
2
- const referenceObjectSchema = z
3
- .object({
4
- id: z.string().optional(),
5
- codename: z.string().optional(),
6
- external_id: z.string().optional(),
7
- })
8
- .describe("An object with an id, codename, or external_id property referencing another item. Using id is preferred for better performance.");
2
+ import { referenceObjectSchema } from "./referenceObjectSchema.js";
9
3
  const languageVariantElementBaseSchema = z.object({
10
4
  element: referenceObjectSchema,
11
5
  value: z.any(),
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ import { referenceObjectSchema } from "./referenceObjectSchema.js";
3
+ const userReferenceSchema = z.object({
4
+ id: z.string().optional().describe("User identifier"),
5
+ email: z.string().email().optional().describe("User email address"),
6
+ });
7
+ // Search variants tool input schema
8
+ export const filterVariantsSchema = z.object({
9
+ search_phrase: z
10
+ .string()
11
+ .optional()
12
+ .describe("Search phrase to look for in content"),
13
+ content_types: z
14
+ .array(referenceObjectSchema)
15
+ .min(1)
16
+ .optional()
17
+ .describe("Array of references to content types by their id, codename, or external id"),
18
+ contributors: z
19
+ .array(userReferenceSchema)
20
+ .min(1)
21
+ .optional()
22
+ .describe("Array of references to users by their id or email"),
23
+ completion_statuses: z
24
+ .array(z.enum(["unfinished", "completed", "not_translated", "all_done"]))
25
+ .min(1)
26
+ .optional()
27
+ .describe("Array of completion statuses to filter by. It is not the same thing as workflow steps, it reflects e.g. not filled in required elements"),
28
+ language: referenceObjectSchema
29
+ .optional()
30
+ .describe("Reference to a language by its id, codename, or external id (defaults to default language)"),
31
+ workflow_steps: z
32
+ .array(z.object({
33
+ workflow_identifier: referenceObjectSchema.describe("Reference to a workflow by its id, codename, or external id"),
34
+ step_identifiers: z
35
+ .array(referenceObjectSchema)
36
+ .min(1)
37
+ .describe("Array of references to workflow steps by their id, codename, or external id"),
38
+ }))
39
+ .min(1)
40
+ .optional()
41
+ .describe("Array of workflows with workflow steps"),
42
+ order_by: z
43
+ .enum(["name", "due", "last_modified"])
44
+ .optional()
45
+ .describe("Field to order by"),
46
+ order_direction: z
47
+ .enum(["asc", "desc"])
48
+ .optional()
49
+ .describe("Order direction"),
50
+ continuation_token: z
51
+ .string()
52
+ .optional()
53
+ .describe("Continuation token for pagination"),
54
+ });
@@ -0,0 +1,9 @@
1
+ import z from "zod";
2
+ // Define a reusable reference object schema
3
+ export const referenceObjectSchema = z
4
+ .object({
5
+ id: z.string().optional(),
6
+ codename: z.string().optional(),
7
+ external_id: z.string().optional(),
8
+ })
9
+ .describe("An object with an id, codename, or external_id property referencing another item. Using id is preferred for better performance.");
@@ -0,0 +1,106 @@
1
+ import { z } from "zod";
2
+ // Schema for a workflow step
3
+ const workflowStepSchema = z.object({
4
+ id: z
5
+ .string()
6
+ .uuid()
7
+ .describe("The unique identifier of the workflow step in UUID format"),
8
+ name: z.string().describe("The human-readable name of the workflow step"),
9
+ codename: z
10
+ .string()
11
+ .describe("The codename of the workflow step used for API operations"),
12
+ transitions_to: z
13
+ .array(z.string().uuid())
14
+ .describe("Array of workflow step IDs that this step can transition to")
15
+ .optional(),
16
+ role_ids: z
17
+ .array(z.string().uuid())
18
+ .describe("Array of role IDs that have permissions for this workflow step")
19
+ .optional(),
20
+ });
21
+ // Schema for the published step
22
+ const publishedStepSchema = z.object({
23
+ id: z
24
+ .string()
25
+ .uuid()
26
+ .describe("The unique identifier of the published step in UUID format"),
27
+ name: z
28
+ .string()
29
+ .describe("The name of the published step - typically 'Published'"),
30
+ codename: z
31
+ .string()
32
+ .describe("The codename of the published step - typically 'published'"),
33
+ unpublish_role_ids: z
34
+ .array(z.string().uuid())
35
+ .describe("Array of role IDs that can unpublish content from this step")
36
+ .optional(),
37
+ create_new_version_role_ids: z
38
+ .array(z.string().uuid())
39
+ .describe("Array of role IDs that can create new versions of content in this step")
40
+ .optional(),
41
+ });
42
+ // Schema for the scheduled step
43
+ const scheduledStepSchema = z.object({
44
+ id: z
45
+ .string()
46
+ .uuid()
47
+ .describe("The unique identifier of the scheduled step in UUID format"),
48
+ name: z
49
+ .string()
50
+ .describe("The name of the scheduled step - typically 'Scheduled'"),
51
+ codename: z
52
+ .string()
53
+ .describe("The codename of the scheduled step - typically 'scheduled'"),
54
+ });
55
+ // Schema for the archived step
56
+ const archivedStepSchema = z.object({
57
+ id: z
58
+ .string()
59
+ .uuid()
60
+ .describe("The unique identifier of the archived step in UUID format"),
61
+ name: z
62
+ .string()
63
+ .describe("The name of the archived step - typically 'Archived'"),
64
+ codename: z
65
+ .string()
66
+ .describe("The codename of the archived step - typically 'archived'"),
67
+ role_ids: z
68
+ .array(z.string().uuid())
69
+ .describe("Array of role IDs that can unarchive content from this step")
70
+ .optional(),
71
+ });
72
+ // Schema for workflow scope
73
+ const workflowScopeSchema = z.object({
74
+ content_types: z
75
+ .array(z.object({
76
+ id: z
77
+ .string()
78
+ .uuid()
79
+ .describe("The unique identifier of the content type in UUID format"),
80
+ }))
81
+ .describe("Array of content types that this workflow applies to"),
82
+ });
83
+ // Main workflow schema
84
+ export const workflowSchema = z.object({
85
+ id: z
86
+ .string()
87
+ .uuid()
88
+ .describe("The unique identifier of the workflow in UUID format"),
89
+ name: z.string().describe("The human-readable name of the workflow"),
90
+ codename: z
91
+ .string()
92
+ .describe("The codename of the workflow used for API operations"),
93
+ scopes: z
94
+ .array(workflowScopeSchema)
95
+ .describe("Array of scopes defining which content types use this workflow"),
96
+ steps: z
97
+ .array(workflowStepSchema)
98
+ .describe("Array of custom workflow steps between draft and published states"),
99
+ published_step: publishedStepSchema.describe("The published step configuration of the workflow"),
100
+ scheduled_step: scheduledStepSchema.describe("The scheduled step configuration of the workflow"),
101
+ archived_step: archivedStepSchema.describe("The archived step configuration of the workflow"),
102
+ });
103
+ // Schema for the list workflows response
104
+ export const listWorkflowsResponseSchema = z
105
+ .array(workflowSchema)
106
+ .describe("Array of workflows in the project");
package/build/server.js CHANGED
@@ -4,8 +4,10 @@ import { registerTool as registerAddContentItemMapi } from "./tools/add-content-
4
4
  import { registerTool as registerAddContentTypeMapi } from "./tools/add-content-type-mapi.js";
5
5
  import { registerTool as registerAddContentTypeSnippetMapi } from "./tools/add-content-type-snippet-mapi.js";
6
6
  import { registerTool as registerAddTaxonomyGroupMapi } from "./tools/add-taxonomy-group-mapi.js";
7
+ import { registerTool as registerChangeVariantWorkflowStepMapi } from "./tools/change-variant-workflow-step-mapi.js";
7
8
  import { registerTool as registerDeleteContentItemMapi } from "./tools/delete-content-item-mapi.js";
8
9
  import { registerTool as registerDeleteLanguageVariantMapi } from "./tools/delete-language-variant-mapi.js";
10
+ import { registerTool as registerFilterVariantsMapi } from "./tools/filter-variants-mapi.js";
9
11
  import { registerTool as registerGetAssetMapi } from "./tools/get-asset-mapi.js";
10
12
  import { registerTool as registerGetInitialContext } from "./tools/get-initial-context.js";
11
13
  import { registerTool as registerGetItemDapi } from "./tools/get-item-dapi.js";
@@ -19,6 +21,7 @@ import { registerTool as registerListContentTypeSnippetsMapi } from "./tools/lis
19
21
  import { registerTool as registerListContentTypesMapi } from "./tools/list-content-types-mapi.js";
20
22
  import { registerTool as registerListLanguagesMapi } from "./tools/list-languages-mapi.js";
21
23
  import { registerTool as registerListTaxonomyGroupsMapi } from "./tools/list-taxonomy-groups-mapi.js";
24
+ import { registerTool as registerListWorkflowsMapi } from "./tools/list-workflows-mapi.js";
22
25
  import { registerTool as registerUpdateContentItemMapi } from "./tools/update-content-item-mapi.js";
23
26
  import { registerTool as registerUpsertLanguageVariantMapi } from "./tools/upsert-language-variant-mapi.js";
24
27
  // Create server instance
@@ -53,5 +56,8 @@ export const createServer = () => {
53
56
  registerDeleteContentItemMapi(server);
54
57
  registerUpsertLanguageVariantMapi(server);
55
58
  registerDeleteLanguageVariantMapi(server);
59
+ registerListWorkflowsMapi(server);
60
+ registerChangeVariantWorkflowStepMapi(server);
61
+ registerFilterVariantsMapi(server);
56
62
  return { server };
57
63
  };
@@ -0,0 +1,48 @@
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("change-variant-workflow-step-mapi", "Change the workflow step of a language variant in Kontent.ai. This operation moves a language variant to a different step in the workflow, enabling content lifecycle management such as moving content from draft to review, review to published, etc.", {
7
+ itemId: z
8
+ .string()
9
+ .uuid()
10
+ .describe("Internal ID (UUID) of the content item whose language variant workflow step you want to change"),
11
+ languageId: z
12
+ .string()
13
+ .uuid()
14
+ .describe("Internal ID (UUID) of the language variant. Use '00000000-0000-0000-0000-000000000000' for the default language"),
15
+ workflowId: z
16
+ .string()
17
+ .uuid()
18
+ .describe("Internal ID (UUID) of the workflow. This is the workflow that contains the target step"),
19
+ workflowStepId: z
20
+ .string()
21
+ .uuid()
22
+ .describe("Internal ID (UUID) of the target workflow step. This must be a valid step ID from the specified workflow. Common steps include Draft, Review, Published, and Archived, but the actual IDs depend on your specific workflow configuration"),
23
+ }, async ({ itemId, languageId, workflowId, workflowStepId }) => {
24
+ const client = createMapiClient();
25
+ try {
26
+ const response = await client
27
+ .changeWorkflowOfLanguageVariant()
28
+ .byItemId(itemId)
29
+ .byLanguageId(languageId)
30
+ .withData({
31
+ workflow_identifier: {
32
+ id: workflowId,
33
+ },
34
+ step_identifier: {
35
+ id: workflowStepId,
36
+ },
37
+ })
38
+ .toPromise();
39
+ return createMcpToolSuccessResponse({
40
+ message: `Successfully changed workflow step of language variant '${languageId}' for content item '${itemId}' to workflow step '${workflowStepId}'`,
41
+ result: response.data,
42
+ });
43
+ }
44
+ catch (error) {
45
+ return handleMcpToolError(error, "Workflow Step Change");
46
+ }
47
+ });
48
+ };
@@ -80,6 +80,24 @@ ALL FOUR elements must be included in language variant using their internal IDs:
80
80
  - Create new language variants when expanding to additional languages
81
81
  - Organize with taxonomies for better content categorization
82
82
 
83
+ ### Workflow Step Management
84
+
85
+ **CRITICAL**: When changing workflow steps of language variants, you must:
86
+
87
+ 1. **Provide the workflowId parameter** - This is mandatory for all workflow step changes
88
+ 2. **Use internal IDs** for itemId, languageId, and workflowStepId parameters
89
+ 3. **Ensure the target workflow step exists** in the specified workflow
90
+
91
+ **WORKFLOW ID REQUIREMENT**: The workflowId parameter identifies which workflow contains the target step. Different content types may use different workflows, so always specify the correct workflow ID when changing workflow steps.
92
+
93
+ **Example**: To move a language variant to a "review" step:
94
+ - itemId: "content_item_internal_id"
95
+ - languageId: "language_internal_id"
96
+ - workflowStepId: "review_step_internal_id"
97
+ - workflowId: "workflow_internal_id" (MANDATORY)
98
+
99
+ **Failure to provide the workflowId parameter will result in workflow step change failures.**
100
+
83
101
  ## Essential Concepts
84
102
 
85
103
  **Taxonomies** provide hierarchical content categorization, allowing you to organize and tag content systematically.
@@ -0,0 +1,66 @@
1
+ import { filterVariantsSchema } from "../schemas/filterVariantSchemas.js";
2
+ import { handleMcpToolError } from "../utils/errorHandler.js";
3
+ import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
+ import { throwError } from "../utils/throwError.js";
5
+ export const registerTool = (server) => {
6
+ server.tool("filter-variants-mapi", "Search and filter language variants of content items using the Management API.", filterVariantsSchema.shape, async ({ search_phrase, content_types, contributors, completion_statuses, language, workflow_steps, order_by, order_direction, continuation_token, }) => {
7
+ try {
8
+ const requestPayload = {
9
+ filters: {
10
+ search_phrase,
11
+ content_types,
12
+ contributors,
13
+ completion_statuses,
14
+ language,
15
+ workflow_steps,
16
+ },
17
+ order: order_by
18
+ ? {
19
+ by: order_by,
20
+ direction: order_direction === "desc" ? "Descending" : "Ascending",
21
+ }
22
+ : null,
23
+ };
24
+ const environmentId = process.env.KONTENT_ENVIRONMENT_ID;
25
+ const apiKey = process.env.KONTENT_API_KEY;
26
+ if (!environmentId || !apiKey) {
27
+ throwError("Missing required environment variables");
28
+ }
29
+ const url = `https://manage.kontent.ai/v2/projects/${environmentId}/early-access/variants/filter`;
30
+ const headers = {
31
+ Authorization: `Bearer ${apiKey}`,
32
+ "Content-Type": "application/json",
33
+ };
34
+ if (continuation_token) {
35
+ headers["X-Continuation"] = continuation_token;
36
+ }
37
+ const response = await fetch(url, {
38
+ method: "POST",
39
+ headers: headers,
40
+ body: JSON.stringify(requestPayload),
41
+ });
42
+ if (!response.ok) {
43
+ const responseText = await response.text();
44
+ let responseData;
45
+ try {
46
+ responseData = JSON.parse(responseText);
47
+ }
48
+ catch {
49
+ responseData = responseText;
50
+ }
51
+ const error = new Error(`HTTP error! status: ${response.status}`);
52
+ error.response = {
53
+ status: response.status,
54
+ statusText: response.statusText,
55
+ data: responseData,
56
+ };
57
+ throw error;
58
+ }
59
+ const responseData = await response.json();
60
+ return createMcpToolSuccessResponse(responseData);
61
+ }
62
+ catch (error) {
63
+ return handleMcpToolError(error, "Variant Search");
64
+ }
65
+ });
66
+ };
@@ -0,0 +1,15 @@
1
+ import { createMapiClient } from "../clients/kontentClients.js";
2
+ import { handleMcpToolError } from "../utils/errorHandler.js";
3
+ import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
+ export const registerTool = (server) => {
5
+ server.tool("list-workflows-mapi", "Get all workflows from Management API. Workflows define the content lifecycle stages and transitions between them.", {}, async () => {
6
+ const client = createMapiClient();
7
+ try {
8
+ const response = await client.listWorkflows().toPromise();
9
+ return createMcpToolSuccessResponse(response.data);
10
+ }
11
+ catch (error) {
12
+ return handleMcpToolError(error, "Workflows Listing");
13
+ }
14
+ });
15
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontent-ai/mcp-server",
3
- "version": "0.8.2",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rimraf build && tsc",