@kontent-ai/mcp-server 0.10.0 → 0.12.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
@@ -58,51 +58,53 @@ npx @kontent-ai/mcp-server@latest sse
58
58
 
59
59
  ### Context and Setup
60
60
 
61
- * **get-initial-context** – 🚨 **MANDATORY FIRST STEP**: Provides essential context, configuration, and operational guidelines for Kontent.ai. This tool MUST be called before using any other tools to understand the platform structure, core entities, relationships, and best practices.
61
+ * **get-initial-context** – 🚨 **MANDATORY FIRST STEP**: This tool MUST be called before using ANY other tools. It provides essential context, configuration, and operational guidelines for Kontent.ai
62
62
 
63
63
  ### Content Type Management
64
64
 
65
- * **get-type-mapi** – Get a specific content type by internal ID
66
- * **list-content-types-mapi** – List all content types in the environment
67
- * **add-content-type-mapi** – Create a new content type with elements
65
+ * **get-type-mapi** – Get Kontent.ai content type by internal ID from Management API
66
+ * **list-content-types-mapi** – Get all Kontent.ai content types from Management API
67
+ * **add-content-type-mapi** – Add new Kontent.ai content type via Management API
68
68
 
69
69
  ### Content Type Snippet Management
70
70
 
71
- * **get-type-snippet-mapi** – Get a specific content type snippet by internal ID
72
- * **list-content-type-snippets-mapi** – List all content type snippets
73
- * **add-content-type-snippet-mapi** – Create a new content type snippet
71
+ * **get-type-snippet-mapi** – Get Kontent.ai content type snippet by internal ID from Management API
72
+ * **list-content-type-snippets-mapi** – Get all Kontent.ai content type snippets from Management API
73
+ * **add-content-type-snippet-mapi** – Add new Kontent.ai content type snippet via Management API
74
74
 
75
75
  ### Taxonomy Management
76
76
 
77
- * **get-taxonomy-group-mapi** – Get a specific taxonomy group by internal ID
78
- * **list-taxonomy-groups-mapi** – List all taxonomy groups
79
- * **add-taxonomy-group-mapi** – Create a new taxonomy group with terms
77
+ * **get-taxonomy-group-mapi** – Get Kontent.ai taxonomy group by internal ID from Management API
78
+ * **list-taxonomy-groups-mapi** – Get all Kontent.ai taxonomy groups from Management API
79
+ * **add-taxonomy-group-mapi** – Add new Kontent.ai taxonomy group via Management API
80
80
 
81
81
  ### Content Item Management
82
82
 
83
- * **get-item-mapi** – Get a specific content item by internal ID
84
- * **get-item-dapi** – Get a content item by codename from Delivery API
85
- * **get-variant-mapi** – Get a language variant of a content item by internal IDs
86
- * **add-content-item-mapi** – Create a new content item (structure only)
87
- * **update-content-item-mapi** – Update an existing content item by internal ID (name, collection)
88
- * **delete-content-item-mapi** – Delete a content item by internal ID
89
- * **upsert-language-variant-mapi** – Create or update a language variant with content using internal IDs
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
83
+ * **get-item-mapi** – Get Kontent.ai item by internal ID from Management API
84
+ * **get-item-dapi** – Get Kontent.ai item by codename from Delivery API
85
+ * **get-variant-mapi** – Get Kontent.ai language variant of content item from Management API
86
+ * **add-content-item-mapi** – Add new Kontent.ai content item via Management API. This creates the content item structure but does not add content to language variants. Use upsert-language-variant-mapi to add content to the item
87
+ * **update-content-item-mapi** – Update existing Kontent.ai content item by internal ID via Management API. The content item must already exist - this tool will not create new items
88
+ * **delete-content-item-mapi** – Delete Kontent.ai content item by internal ID from Management API
89
+ * **upsert-language-variant-mapi** – Create or update Kontent.ai language variant of a content item via Management API. This adds actual content to the content item elements. Elements should be provided as JSON string in the format expected by the SDK
90
+ * **delete-language-variant-mapi** – Delete Kontent.ai language variant from Management API
91
+ * **filter-variants-mapi** – Search and filter Kontent.ai language variants of content items using Management API
92
92
 
93
93
  ### Asset Management
94
94
 
95
- * **get-asset-mapi** – Get a specific asset by internal ID
96
- * **list-assets-mapi** – List all assets in the environment
95
+ * **get-asset-mapi** – Get a specific Kontent.ai asset by internal ID from Management API
96
+ * **list-assets-mapi** – Get all Kontent.ai assets from Management API
97
97
 
98
98
  ### Language Management
99
99
 
100
- * **list-languages-mapi** – List all languages configured in the environment
100
+ * **list-languages-mapi** – Get all Kontent.ai languages from Management API
101
101
 
102
102
  ### Workflow Management
103
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)
104
+ * **list-workflows-mapi** – Get all Kontent.ai workflows from Management API. Workflows define the content lifecycle stages and transitions between them
105
+ * **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.
106
+ * **publish-variant-mapi** – Publish or schedule a language variant of a content item in Kontent.ai. This operation can either immediately publish the variant or schedule it for publication at a specific future date and time with optional timezone specification
107
+ * **unpublish-variant-mapi** – Unpublish or schedule unpublishing of a language variant of a content item in Kontent.ai. This operation can either immediately unpublish the variant (making it unavailable through the Delivery API) or schedule it for unpublishing at a specific future date and time with optional timezone specification
106
108
 
107
109
  ## ⚙️ Configuration
108
110
 
package/build/server.js CHANGED
@@ -22,6 +22,8 @@ import { registerTool as registerListContentTypesMapi } from "./tools/list-conte
22
22
  import { registerTool as registerListLanguagesMapi } from "./tools/list-languages-mapi.js";
23
23
  import { registerTool as registerListTaxonomyGroupsMapi } from "./tools/list-taxonomy-groups-mapi.js";
24
24
  import { registerTool as registerListWorkflowsMapi } from "./tools/list-workflows-mapi.js";
25
+ import { registerTool as registerPublishVariantMapi } from "./tools/publish-variant-mapi.js";
26
+ import { registerTool as registerUnpublishVariantMapi } from "./tools/unpublish-variant-mapi.js";
25
27
  import { registerTool as registerUpdateContentItemMapi } from "./tools/update-content-item-mapi.js";
26
28
  import { registerTool as registerUpsertLanguageVariantMapi } from "./tools/upsert-language-variant-mapi.js";
27
29
  // Create server instance
@@ -59,5 +61,7 @@ export const createServer = () => {
59
61
  registerListWorkflowsMapi(server);
60
62
  registerChangeVariantWorkflowStepMapi(server);
61
63
  registerFilterVariantsMapi(server);
64
+ registerPublishVariantMapi(server);
65
+ registerUnpublishVariantMapi(server);
62
66
  return { server };
63
67
  };
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("add-content-item-mapi", "Add a new content item via Management API. This creates the content item structure but does not add content to language variants. Use upsert-language-variant-mapi to add content to the item.", {
6
+ server.tool("add-content-item-mapi", "Add new Kontent.ai content item via Management API. This creates the content item structure but does not add content to language variants. Use upsert-language-variant-mapi to add content to the item.", {
7
7
  name: z
8
8
  .string()
9
9
  .min(1)
@@ -4,7 +4,7 @@ import { contentGroupSchema, elementSchema, } from "../schemas/contentTypeSchema
4
4
  import { handleMcpToolError } from "../utils/errorHandler.js";
5
5
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
6
6
  export const registerTool = (server) => {
7
- server.tool("add-content-type-mapi", "Add a new content type via Management API", {
7
+ server.tool("add-content-type-mapi", "Add new Kontent.ai content type via Management API", {
8
8
  name: z.string().describe("Display name of the content type"),
9
9
  codename: z
10
10
  .string()
@@ -4,7 +4,7 @@ import { snippetElementSchema } from "../schemas/contentTypeSchemas.js";
4
4
  import { handleMcpToolError } from "../utils/errorHandler.js";
5
5
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
6
6
  export const registerTool = (server) => {
7
- server.tool("add-content-type-snippet-mapi", "Add a new content type snippet via Management API", {
7
+ server.tool("add-content-type-snippet-mapi", "Add new Kontent.ai content type snippet via Management API", {
8
8
  name: z.string().describe("Display name of the content type snippet"),
9
9
  codename: z
10
10
  .string()
@@ -3,7 +3,7 @@ import { taxonomyGroupSchemas } from "../schemas/taxonomySchemas.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("add-taxonomy-group-mapi", "Add a new taxonomy group via Management API", taxonomyGroupSchemas, async (taxonomyGroup) => {
6
+ server.tool("add-taxonomy-group-mapi", "Add new Kontent.ai taxonomy group via Management API", taxonomyGroupSchemas, async (taxonomyGroup) => {
7
7
  const client = createMapiClient();
8
8
  try {
9
9
  const response = await client
@@ -98,6 +98,7 @@ ALL FOUR elements must be included in language variant using their internal IDs:
98
98
 
99
99
  **Failure to provide the workflowId parameter will result in workflow step change failures.**
100
100
 
101
+
101
102
  ## Essential Concepts
102
103
 
103
104
  **Taxonomies** provide hierarchical content categorization, allowing you to organize and tag content systematically.
@@ -112,6 +113,8 @@ ALL FOUR elements must be included in language variant using their internal IDs:
112
113
 
113
114
  ## Best Practices
114
115
 
116
+ **CRITICAL**: Never assume the current time. Always obtain the current date and time when needed for time-sensitive operations like scheduling. If the current date and time in UTC format cannot be decisively obtained by any available tool, force the user to specify the current date and time explicitly.
117
+
115
118
  Use snippets for common field groups to maintain consistency and avoid duplication. Plan your content types before creating content to ensure proper structure. **Always use internal IDs when working with MCP tools** for optimal performance and reliability. Leverage taxonomies for organization to create logical content hierarchies. Consider your multilingual strategy early in the planning process to avoid restructuring later.
116
119
 
117
120
  When working with snippets, always retrieve and understand the complete element structure before creating content variants.
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("delete-content-item-mapi", "Delete a content item by internal ID from Management API", {
6
+ server.tool("delete-content-item-mapi", "Delete Kontent.ai content item by internal ID from Management API", {
7
7
  id: z.string().describe("Internal ID of the content item to delete"),
8
8
  }, async ({ id }) => {
9
9
  const client = createMapiClient();
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("delete-language-variant-mapi", "Delete a language variant of a content item from Management API", {
6
+ server.tool("delete-language-variant-mapi", "Delete Kontent.ai language variant from Management API", {
7
7
  itemId: z.string().describe("Internal ID of the content item"),
8
8
  languageId: z
9
9
  .string()
@@ -3,7 +3,7 @@ import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
4
  import { throwError } from "../utils/throwError.js";
5
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, }) => {
6
+ server.tool("filter-variants-mapi", "Search and filter Kontent.ai language variants of content items using Management API", filterVariantsSchema.shape, async ({ search_phrase, content_types, contributors, completion_statuses, language, workflow_steps, order_by, order_direction, continuation_token, }) => {
7
7
  try {
8
8
  const requestPayload = {
9
9
  filters: {
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("get-asset-mapi", "Get a specific asset by internal ID from Management API", {
6
+ server.tool("get-asset-mapi", "Get a specific Kontent.ai asset by internal ID from Management API", {
7
7
  assetId: z.string().describe("Internal ID of the asset to retrieve"),
8
8
  }, async ({ assetId }) => {
9
9
  const client = createMapiClient();
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("get-taxonomy-group-mapi", "Get taxonomy group by internal ID from Management API", {
6
+ server.tool("get-taxonomy-group-mapi", "Get Kontent.ai taxonomy group by internal ID from Management API", {
7
7
  id: z.string().describe("Internal ID of the taxonomy group to get"),
8
8
  }, async ({ id }) => {
9
9
  const client = createMapiClient();
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("get-type-mapi", "Get content type by internal ID from Management API", {
6
+ server.tool("get-type-mapi", "Get Kontent.ai content type by internal ID from Management API", {
7
7
  id: z.string().describe("Internal ID of the content type to get"),
8
8
  }, async ({ id }) => {
9
9
  const client = createMapiClient();
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("get-type-snippet-mapi", "Get content type snippet by internal ID from Management API", {
6
+ server.tool("get-type-snippet-mapi", "Get Kontent.ai content type snippet by internal ID from Management API", {
7
7
  id: z.string().describe("Internal ID of the content type snippet to get"),
8
8
  }, async ({ id }) => {
9
9
  const client = createMapiClient();
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("get-variant-mapi", "Get language variant of a content item from Management API", {
6
+ server.tool("get-variant-mapi", "Get Kontent.ai language variant of content item from Management API", {
7
7
  itemId: z.string().describe("Internal ID of the content item"),
8
8
  languageId: z
9
9
  .string()
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
2
2
  import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
4
  export const registerTool = (server) => {
5
- server.tool("list-assets-mapi", "Get all assets from Management API", {}, async () => {
5
+ server.tool("list-assets-mapi", "Get all Kontent.ai assets from Management API", {}, async () => {
6
6
  const client = createMapiClient();
7
7
  try {
8
8
  const response = await client.listAssets().toAllPromise();
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
2
2
  import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
4
  export const registerTool = (server) => {
5
- server.tool("list-content-type-snippets-mapi", "Get all content type snippets from Management API", {}, async () => {
5
+ server.tool("list-content-type-snippets-mapi", "Get all Kontent.ai content type snippets from Management API", {}, async () => {
6
6
  const client = createMapiClient();
7
7
  try {
8
8
  const response = await client.listContentTypeSnippets().toAllPromise();
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
2
2
  import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
4
  export const registerTool = (server) => {
5
- server.tool("list-content-types-mapi", "Get all content types from Management API", {}, async () => {
5
+ server.tool("list-content-types-mapi", "Get all Kontent.ai content types from Management API", {}, async () => {
6
6
  const client = createMapiClient();
7
7
  try {
8
8
  const response = await client.listContentTypes().toAllPromise();
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
2
2
  import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
4
  export const registerTool = (server) => {
5
- server.tool("list-languages-mapi", "Get all languages from Management API", {}, async () => {
5
+ server.tool("list-languages-mapi", "Get all Kontent.ai languages from Management API", {}, async () => {
6
6
  const client = createMapiClient();
7
7
  try {
8
8
  const response = await client.listLanguages().toAllPromise();
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
2
2
  import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
4
  export const registerTool = (server) => {
5
- server.tool("list-taxonomy-groups-mapi", "Get all taxonomy groups from Management API", {}, async () => {
5
+ server.tool("list-taxonomy-groups-mapi", "Get all Kontent.ai taxonomy groups from Management API", {}, async () => {
6
6
  const client = createMapiClient();
7
7
  try {
8
8
  const response = await client.listTaxonomies().toAllPromise();
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
2
2
  import { handleMcpToolError } from "../utils/errorHandler.js";
3
3
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
4
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 () => {
5
+ server.tool("list-workflows-mapi", "Get all Kontent.ai workflows from Management API. Workflows define the content lifecycle stages and transitions between them.", {}, async () => {
6
6
  const client = createMapiClient();
7
7
  try {
8
8
  const response = await client.listWorkflows().toPromise();
@@ -0,0 +1,78 @@
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("publish-variant-mapi", "Publish or schedule a language variant of a content item in Kontent.ai. This operation can either immediately publish the variant (publishing happens right now) or schedule it for publication at a specific future date and time. For immediate publishing: the variant is published immediately and becomes available through the Delivery API. For scheduled publishing: the variant moves to a 'Scheduled' workflow state and will automatically transition to 'Published' at the specified time. The variant must be in a valid state with all required fields filled and validation rules satisfied. A variant can only be published if a transition is defined between the variant's current workflow step and the Published workflow step.", {
7
+ itemId: z
8
+ .string()
9
+ .uuid()
10
+ .describe("Internal ID (UUID) of the content item whose language variant you want to publish or schedule. This identifies the content item container that holds all language variants."),
11
+ languageId: z
12
+ .string()
13
+ .uuid()
14
+ .describe("Internal ID (UUID) of the language variant to publish or schedule. Use '00000000-0000-0000-0000-000000000000' for the default language. Each language in your project has a unique ID that identifies the specific variant."),
15
+ scheduledTo: z
16
+ .string()
17
+ .datetime({ offset: true })
18
+ .optional()
19
+ .describe("ISO 8601 formatted date and time when the publish action should occur (e.g., '2024-12-25T10:00:00Z' for UTC or '2024-12-25T10:00:00+02:00' for specific timezone). If not provided, the variant will be published immediately. If provided, must be a future date/time. The actual execution may have up to 5 minutes delay from the specified time."),
20
+ displayTimezone: z
21
+ .string()
22
+ .optional()
23
+ .describe("The timezone identifier for displaying the scheduled time in the Kontent.ai UI (e.g., 'America/New_York', 'Europe/London', 'UTC'). This parameter is used for scheduled publishing to specify the timezone context for the scheduled_to parameter. If not provided, the system will use the default timezone. This helps content creators understand when content will be published in their local context."),
24
+ }, async ({ itemId, languageId, scheduledTo, displayTimezone }) => {
25
+ const client = createMapiClient();
26
+ try {
27
+ // Validate that displayTimezone can only be used with scheduledTo
28
+ if (displayTimezone && !scheduledTo) {
29
+ throw new Error("The 'displayTimezone' parameter can only be used in combination with 'scheduledTo' parameter for scheduled publishing.");
30
+ }
31
+ let action;
32
+ let message;
33
+ if (scheduledTo) {
34
+ // Scheduled publishing
35
+ const requestData = {
36
+ scheduled_to: scheduledTo,
37
+ };
38
+ // Add display_timezone if provided
39
+ if (displayTimezone) {
40
+ requestData.display_timezone = displayTimezone;
41
+ }
42
+ await client
43
+ .publishLanguageVariant()
44
+ .byItemId(itemId)
45
+ .byLanguageId(languageId)
46
+ .withData(requestData)
47
+ .toPromise();
48
+ action = "scheduled";
49
+ message = `Successfully scheduled language variant '${languageId}' for content item '${itemId}' to be published at '${scheduledTo}'${displayTimezone ? ` (timezone: ${displayTimezone})` : ""}.`;
50
+ }
51
+ else {
52
+ // Immediate publishing
53
+ await client
54
+ .publishLanguageVariant()
55
+ .byItemId(itemId)
56
+ .byLanguageId(languageId)
57
+ .withoutData()
58
+ .toPromise();
59
+ action = "published";
60
+ message = `Successfully published language variant '${languageId}' for content item '${itemId}'. The content is now live and available through Delivery API.`;
61
+ }
62
+ return createMcpToolSuccessResponse({
63
+ message,
64
+ result: {
65
+ itemId,
66
+ languageId,
67
+ scheduledTo: scheduledTo || null,
68
+ displayTimezone: displayTimezone || null,
69
+ action,
70
+ timestamp: new Date().toISOString(),
71
+ },
72
+ });
73
+ }
74
+ catch (error) {
75
+ return handleMcpToolError(error, "Publish/Schedule Language Variant");
76
+ }
77
+ });
78
+ };
@@ -0,0 +1,78 @@
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("unpublish-variant-mapi", "Unpublish or schedule unpublishing of a language variant of a content item in Kontent.ai. This operation can either immediately unpublish the variant (making it unavailable through the Delivery API) or schedule it for unpublishing at a specific future date and time. For immediate unpublishing: the variant is unpublished right away and moves to the 'Archived' workflow step, becoming unavailable through the Delivery API. For scheduled unpublishing: the variant remains published but is scheduled to be automatically unpublished at the specified time. The variant must currently be in the 'Published' state for this operation to succeed.", {
7
+ itemId: z
8
+ .string()
9
+ .uuid()
10
+ .describe("Internal ID (UUID) of the content item whose language variant you want to unpublish or schedule for unpublishing. This identifies the content item container that holds all language variants."),
11
+ languageId: z
12
+ .string()
13
+ .uuid()
14
+ .describe("Internal ID (UUID) of the language variant to unpublish or schedule for unpublishing. Use '00000000-0000-0000-0000-000000000000' for the default language. Each language in your project has a unique ID that identifies the specific variant."),
15
+ scheduledTo: z
16
+ .string()
17
+ .datetime({ offset: true })
18
+ .optional()
19
+ .describe("ISO 8601 formatted date and time when the unpublish action should occur (e.g., '2024-12-25T10:00:00Z' for UTC or '2024-12-25T10:00:00+02:00' for specific timezone). If not provided, the variant will be unpublished immediately. If provided, must be a future date/time. The actual execution may have up to 5 minutes delay from the specified time. When unpublished, the content will no longer be available through the Delivery API."),
20
+ displayTimezone: z
21
+ .string()
22
+ .optional()
23
+ .describe("The timezone identifier for displaying the scheduled time in the Kontent.ai UI (e.g., 'America/New_York', 'Europe/London', 'UTC'). This parameter is used for scheduled unpublishing to specify the timezone context for the scheduled_to parameter. If not provided, the system will use the default timezone. This helps content creators understand when content will be unpublished in their local context."),
24
+ }, async ({ itemId, languageId, scheduledTo, displayTimezone }) => {
25
+ const client = createMapiClient();
26
+ try {
27
+ // Validate that displayTimezone can only be used with scheduledTo
28
+ if (displayTimezone && !scheduledTo) {
29
+ throw new Error("The 'displayTimezone' parameter can only be used in combination with 'scheduledTo' parameter for scheduled unpublishing.");
30
+ }
31
+ let action;
32
+ let message;
33
+ if (scheduledTo) {
34
+ // Scheduled unpublishing
35
+ const requestData = {
36
+ scheduled_to: scheduledTo,
37
+ };
38
+ // Add display_timezone if provided
39
+ if (displayTimezone) {
40
+ requestData.display_timezone = displayTimezone;
41
+ }
42
+ await client
43
+ .unpublishLanguageVariant()
44
+ .byItemId(itemId)
45
+ .byLanguageId(languageId)
46
+ .withData(requestData)
47
+ .toPromise();
48
+ action = "scheduled for unpublishing";
49
+ message = `Successfully scheduled language 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.`;
50
+ }
51
+ else {
52
+ // Immediate unpublishing
53
+ await client
54
+ .unpublishLanguageVariant()
55
+ .byItemId(itemId)
56
+ .byLanguageId(languageId)
57
+ .withoutData()
58
+ .toPromise();
59
+ action = "unpublished";
60
+ message = `Successfully unpublished language variant '${languageId}' for content item '${itemId}'. The content has been moved to Archived and is no longer available through Delivery API.`;
61
+ }
62
+ return createMcpToolSuccessResponse({
63
+ message,
64
+ result: {
65
+ itemId,
66
+ languageId,
67
+ scheduledTo: scheduledTo || null,
68
+ displayTimezone: displayTimezone || null,
69
+ action,
70
+ timestamp: new Date().toISOString(),
71
+ },
72
+ });
73
+ }
74
+ catch (error) {
75
+ return handleMcpToolError(error, "Unpublish/Schedule Unpublishing Language Variant");
76
+ }
77
+ });
78
+ };
@@ -3,7 +3,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
3
3
  import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
- server.tool("update-content-item-mapi", "Update an existing content item by internal ID via Management API. The content item must already exist - this tool will not create new items.", {
6
+ server.tool("update-content-item-mapi", "Update existing Kontent.ai content item by internal ID via Management API. The content item must already exist - this tool will not create new items.", {
7
7
  id: z.string().describe("Internal ID of the content item to update"),
8
8
  name: z
9
9
  .string()
@@ -4,7 +4,7 @@ import { languageVariantElementSchema } from "../schemas/contentItemSchemas.js";
4
4
  import { handleMcpToolError } from "../utils/errorHandler.js";
5
5
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
6
6
  export const registerTool = (server) => {
7
- server.tool("upsert-language-variant-mapi", "Create or update a language variant of a content item via Management API. This adds actual content to the content item elements. Elements should be provided as JSON string in the format expected by the SDK.", {
7
+ server.tool("upsert-language-variant-mapi", "Create or update Kontent.ai language variant of a content item via Management API. This adds actual content to the content item elements. Elements should be provided as JSON string in the format expected by the SDK.", {
8
8
  itemId: z.string().describe("Internal ID of the content item"),
9
9
  languageId: z
10
10
  .string()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontent-ai/mcp-server",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rimraf build && tsc",