@kontent-ai/mcp-server 0.8.1 → 0.8.2

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
@@ -62,36 +62,36 @@ npx @kontent-ai/mcp-server@latest sse
62
62
 
63
63
  ### Content Type Management
64
64
 
65
- * **get-type-mapi** – Get a specific content type by codename
65
+ * **get-type-mapi** – Get a specific content type by internal ID
66
66
  * **list-content-types-mapi** – List all content types in the environment
67
67
  * **add-content-type-mapi** – Create a new content type with elements
68
68
 
69
69
  ### Content Type Snippet Management
70
70
 
71
- * **get-type-snippet-mapi** – Get a specific content type snippet by codename
71
+ * **get-type-snippet-mapi** – Get a specific content type snippet by internal ID
72
72
  * **list-content-type-snippets-mapi** – List all content type snippets
73
73
  * **add-content-type-snippet-mapi** – Create a new content type snippet
74
74
 
75
75
  ### Taxonomy Management
76
76
 
77
- * **get-taxonomy-group-mapi** – Get a specific taxonomy group by codename
77
+ * **get-taxonomy-group-mapi** – Get a specific taxonomy group by internal ID
78
78
  * **list-taxonomy-groups-mapi** – List all taxonomy groups
79
79
  * **add-taxonomy-group-mapi** – Create a new taxonomy group with terms
80
80
 
81
81
  ### Content Item Management
82
82
 
83
- * **get-item-mapi** – Get a specific content item by codename
83
+ * **get-item-mapi** – Get a specific content item by internal ID
84
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
85
+ * **get-variant-mapi** – Get a language variant of a content item by internal IDs
86
86
  * **add-content-item-mapi** – Create a new content item (structure only)
87
- * **update-content-item-mapi** – Update an existing content item by codename (name, collection)
88
- * **delete-content-item-mapi** – Delete a content item by codename
89
- * **upsert-language-variant-mapi** – Create or update a language variant with content
90
- * **delete-language-variant-mapi** – Delete a language variant of a content item
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
91
 
92
92
  ### Asset Management
93
93
 
94
- * **get-asset-mapi** – Get a specific asset by codename
94
+ * **get-asset-mapi** – Get a specific asset by internal ID
95
95
  * **list-assets-mapi** – List all assets in the environment
96
96
 
97
97
  ### Language Management
@@ -1,209 +1,76 @@
1
1
  import { z } from "zod";
2
- // Define a reusable reference object schema
3
2
  const referenceObjectSchema = z
4
3
  .object({
5
4
  id: z.string().optional(),
6
5
  codename: z.string().optional(),
7
6
  external_id: z.string().optional(),
8
7
  })
9
- .describe("An object with an id, codename, or external_id property referencing another item. Using codename is preferred for better readability.");
10
- // Language variant element value schemas
11
- const textElementValueSchema = z.object({
12
- value: z.string().describe("The text content of the element"),
8
+ .describe("An object with an id, codename, or external_id property referencing another item. Using id is preferred for better performance.");
9
+ const languageVariantElementBaseSchema = z.object({
10
+ element: referenceObjectSchema,
11
+ value: z.any(),
13
12
  });
14
- const numberElementValueSchema = z.object({
15
- value: z.number().describe("The numeric value of the element"),
13
+ const richTextComponentSchema = z.object({
14
+ id: z.string(),
15
+ type: referenceObjectSchema,
16
+ elements: z.array(languageVariantElementBaseSchema),
16
17
  });
17
- const dateTimeElementValueSchema = z.object({
18
- value: z
19
- .string()
20
- .nullable()
21
- .describe("The ISO-8601 formatted date-time string, or null for empty"),
18
+ const assetInVariantElementSchema = z.object({
19
+ element: referenceObjectSchema,
20
+ value: z.array(referenceObjectSchema).nullable(),
22
21
  });
23
- const multipleChoiceElementValueSchema = z.object({
24
- value: z
25
- .array(referenceObjectSchema)
26
- .describe("Array of references to the selected options by their codename or id"),
22
+ const customElementInVariantElementSchema = z.object({
23
+ element: referenceObjectSchema,
24
+ value: z.string().nullable(),
25
+ searchable_value: z.string().nullable(),
27
26
  });
28
- const assetElementValueSchema = z.object({
29
- value: z
30
- .array(referenceObjectSchema)
31
- .describe("Array of references to assets by their codename or id"),
27
+ const dateTimeInVariantElementSchema = z.object({
28
+ element: referenceObjectSchema,
29
+ value: z.string().nullable(),
30
+ display_timezone: z.string().nullable(),
32
31
  });
33
- const modularContentElementValueSchema = z.object({
34
- value: z
35
- .array(referenceObjectSchema)
36
- .describe("Array of references to linked content items by their codename or id"),
32
+ const linkedItemsInVariantElementSchema = z.object({
33
+ element: referenceObjectSchema,
34
+ value: z.array(referenceObjectSchema).nullable(),
37
35
  });
38
- const taxonomyElementValueSchema = z.object({
39
- value: z
40
- .array(referenceObjectSchema)
41
- .describe("Array of references to taxonomy terms by their codename or id"),
36
+ const multipleChoiceInVariantElementSchema = z.object({
37
+ element: referenceObjectSchema,
38
+ value: z.array(referenceObjectSchema).nullable(),
42
39
  });
43
- const richTextElementValueSchema = z.object({
44
- value: z
45
- .string()
46
- .describe("The rich text content as a subset of HTML string format. Only specific HTML5 elements and attributes are supported as defined by Kontent.ai's rich text specification. See: https://kontent.ai/learn/docs/apis/openapi/management-api-v2/#section/HTML5-elements-allowed-in-rich-text"),
40
+ const numberInVariantElementSchema = z.object({
41
+ element: referenceObjectSchema,
42
+ value: z.number().nullable(),
47
43
  });
48
- const urlSlugElementValueSchema = z.object({
49
- value: z.string().describe("The URL slug value"),
44
+ const richTextInVariantElementSchema = z.object({
45
+ element: referenceObjectSchema,
46
+ value: z.string().nullable(),
47
+ components: z.array(richTextComponentSchema).nullable(),
50
48
  });
51
- const customElementValueSchema = z.object({
52
- value: z.string().describe("The JSON string value for custom element"),
49
+ const taxonomyInVariantElementSchema = z.object({
50
+ element: referenceObjectSchema,
51
+ value: z.array(referenceObjectSchema).nullable(),
53
52
  });
54
- // Union type for all possible element values
55
- const _elementValueSchema = z.discriminatedUnion("value", [
56
- textElementValueSchema,
57
- numberElementValueSchema,
58
- dateTimeElementValueSchema,
59
- multipleChoiceElementValueSchema,
60
- assetElementValueSchema,
61
- modularContentElementValueSchema,
62
- taxonomyElementValueSchema,
63
- richTextElementValueSchema,
64
- urlSlugElementValueSchema,
65
- customElementValueSchema,
53
+ const textInVariantElementSchema = z.object({
54
+ element: referenceObjectSchema,
55
+ value: z.string().nullable(),
56
+ });
57
+ const urlSlugInVariantElementSchema = z.object({
58
+ element: referenceObjectSchema,
59
+ mode: z.enum(["autogenerated", "custom"]),
60
+ value: z.string().nullable(),
61
+ });
62
+ export const languageVariantElementSchema = z.union([
63
+ // Most specific schemas first (with unique distinguishing fields)
64
+ urlSlugInVariantElementSchema, // has unique required 'mode' field
65
+ richTextInVariantElementSchema, // has unique optional 'components' field
66
+ dateTimeInVariantElementSchema, // has unique nullable 'display_timezone' field
67
+ customElementInVariantElementSchema, // has unique optional 'searchable_value' field
68
+ numberInVariantElementSchema, // has unique value type (number)
69
+ // Medium specificity (array value types)
70
+ assetInVariantElementSchema, // value: array of references
71
+ linkedItemsInVariantElementSchema, // value: array of references
72
+ multipleChoiceInVariantElementSchema, // value: array of references
73
+ taxonomyInVariantElementSchema, // value: array of references
74
+ // Least specific (basic string value, no unique fields)
75
+ textInVariantElementSchema, // value: string, no distinguishing fields
66
76
  ]);
67
- // Language variant element schema
68
- const languageVariantElementSchema = z
69
- .record(z.string().describe("Element codename as key"), z
70
- .union([
71
- textElementValueSchema,
72
- numberElementValueSchema,
73
- dateTimeElementValueSchema,
74
- multipleChoiceElementValueSchema,
75
- assetElementValueSchema,
76
- modularContentElementValueSchema,
77
- taxonomyElementValueSchema,
78
- richTextElementValueSchema,
79
- urlSlugElementValueSchema,
80
- customElementValueSchema,
81
- ])
82
- .describe("Element value object with 'value' property containing the element's content"))
83
- .describe("Object where keys are element codenames and values are element value objects");
84
- // Collection reference schema
85
- const collectionReferenceSchema = z
86
- .object({
87
- reference: referenceObjectSchema
88
- .nullable()
89
- .describe("Reference to a collection by id, codename, or external_id. Use null to remove from collection."),
90
- })
91
- .describe("Collection assignment for the content item");
92
- // Content item creation schema
93
- export const contentItemCreateSchema = z
94
- .object({
95
- name: z
96
- .string()
97
- .min(1)
98
- .max(200)
99
- .describe("Display name of the content item (1-200 characters)"),
100
- codename: z
101
- .string()
102
- .optional()
103
- .describe("Codename of the content item (optional, will be generated from name if not provided)"),
104
- type: referenceObjectSchema.describe("Reference to the content type by id, codename, or external_id"),
105
- external_id: z
106
- .string()
107
- .optional()
108
- .describe("External ID for the content item (optional, useful for external system integration)"),
109
- collection: collectionReferenceSchema
110
- .optional()
111
- .describe("Collection assignment for the content item (optional)"),
112
- })
113
- .describe("Schema for creating a new content item");
114
- // Language variant creation/update schema
115
- export const languageVariantUpsertSchema = z
116
- .object({
117
- elements: languageVariantElementSchema.describe("Object containing element values for the language variant. Keys are element codenames, values are element value objects."),
118
- workflow_step: referenceObjectSchema
119
- .optional()
120
- .describe("Reference to workflow step by id or codename (optional)"),
121
- })
122
- .describe("Schema for creating or updating a language variant of a content item");
123
- // Complete content item with language variant schema for convenience
124
- export const contentItemWithVariantSchema = z
125
- .object({
126
- item: contentItemCreateSchema.describe("Content item data"),
127
- language_codename: z
128
- .string()
129
- .default("default")
130
- .describe("Codename of the language for the variant (defaults to 'default')"),
131
- variant: languageVariantUpsertSchema.describe("Language variant data with element values"),
132
- })
133
- .describe("Schema for creating a content item along with its language variant in one operation");
134
- // Element value helper schemas for better LLM understanding
135
- export const elementValueHelpers = {
136
- text: z
137
- .object({
138
- value: z.string().describe("Text content"),
139
- })
140
- .describe("Text element value - use for simple text fields like titles, descriptions, etc."),
141
- richText: z
142
- .object({
143
- value: z
144
- .string()
145
- .describe("Rich text content as a subset of HTML string format. See: https://kontent.ai/learn/docs/apis/openapi/management-api-v2/#section/HTML5-elements-allowed-in-rich-text"),
146
- })
147
- .describe("Rich text element value - use for formatted content with HTML subset (specific HTML5 elements and attributes supported by Kontent.ai)"),
148
- number: z
149
- .object({
150
- value: z.number().describe("Numeric value"),
151
- })
152
- .describe("Number element value - use for numeric fields like prices, quantities, etc."),
153
- dateTime: z
154
- .object({
155
- value: z
156
- .string()
157
- .nullable()
158
- .describe("ISO-8601 date-time string or null"),
159
- })
160
- .describe("Date-time element value - use ISO format like '2023-12-25T10:30:00.000Z' or null for empty"),
161
- multipleChoice: z
162
- .object({
163
- value: z
164
- .array(z.object({
165
- codename: z.string().describe("Codename of the selected option"),
166
- }))
167
- .describe("Array of selected option references"),
168
- })
169
- .describe("Multiple choice element value - reference options by their codename"),
170
- asset: z
171
- .object({
172
- value: z
173
- .array(z.object({
174
- codename: z.string().describe("Codename of the asset"),
175
- }))
176
- .describe("Array of asset references"),
177
- })
178
- .describe("Asset element value - reference assets by their codename"),
179
- modularContent: z
180
- .object({
181
- value: z
182
- .array(z.object({
183
- codename: z
184
- .string()
185
- .describe("Codename of the linked content item"),
186
- }))
187
- .describe("Array of content item references"),
188
- })
189
- .describe("Modular content element value - reference other content items by their codename"),
190
- taxonomy: z
191
- .object({
192
- value: z
193
- .array(z.object({
194
- codename: z.string().describe("Codename of the taxonomy term"),
195
- }))
196
- .describe("Array of taxonomy term references"),
197
- })
198
- .describe("Taxonomy element value - reference taxonomy terms by their codename"),
199
- urlSlug: z
200
- .object({
201
- value: z.string().describe("URL slug value"),
202
- })
203
- .describe("URL slug element value - use for SEO-friendly URLs"),
204
- custom: z
205
- .object({
206
- value: z.string().describe("JSON string value"),
207
- })
208
- .describe("Custom element value - depends on the custom element implementation"),
209
- };
@@ -5,7 +5,7 @@ const referenceObjectSchema = z
5
5
  id: z.string().optional(),
6
6
  codename: z.string().optional(),
7
7
  })
8
- .describe("An object with an id or codename property referencing another item. Using codename is preferred for better readability.");
8
+ .describe("An object with an id or codename property referencing another item. Using id is preferred for better performance.");
9
9
  // Common property schemas
10
10
  const baseElementSchema = {
11
11
  codename: z.string().optional(),
@@ -6,7 +6,7 @@ Kontent.ai is a headless content management system (CMS) that provides two main
6
6
  ## Core Entities
7
7
 
8
8
  ### Content Items
9
- Content items are language-neutral content containers that serve as the foundation for your content structure. Each content item has a unique identifier and codename, and references a specific content type. The key relationship to understand is that one content item can have multiple language variants.
9
+ Content items are language-neutral content containers that serve as the foundation for your content structure. Each content item has a unique internal ID and codename, and references a specific content type. The key relationship to understand is that one content item can have multiple language variants.
10
10
 
11
11
  ### Language Variants
12
12
  Language variants contain the actual language-specific content data including field values, workflow state, and language reference. Importantly, each variant is managed independently per language.
@@ -29,9 +29,42 @@ The content structure flows from Content Type → Content Item → Language Vari
29
29
  2. **Retrieve each snippet definition** to understand its internal elements
30
30
  3. **Include ALL elements** from both the content type AND all snippets in the language variant
31
31
 
32
- Example: If a content type has direct elements (title, body) and a metadata snippet (meta_title, meta_description), your language variant must include ALL four elements.
32
+ **SNIPPET ELEMENT IMPLEMENTATION DETAILS**:
33
33
 
34
- **Failure to include snippet elements will result in incomplete content creation.**
34
+ When implementing snippet elements in language variants, follow these rules:
35
+ - **Element Reference Format**: Use {"element": {"id": "internal_id_here"}} format with internal IDs
36
+ - **Codename Convention**: Snippet elements use double underscore format: {snippet_codename}__{element_codename}
37
+ - **Example**: For a "metadata" snippet with a "title" element, the codename becomes metadata__title
38
+
39
+ **CRITICAL**: Always use internal IDs from snippet definitions, never construct codenames manually.
40
+
41
+ **Complete Example**:
42
+ Content type has: title, body (direct) + metadata snippet (meta_title, meta_description)
43
+ ALL FOUR elements must be included in language variant using their internal IDs:
44
+ - Direct element: title ("title_internal_id_here")
45
+ - Direct element: body ("body_internal_id_here")
46
+ - Snippet element: metadata title ("metadata_title_internal_id_here")
47
+ - Snippet element: metadata description ("metadata_description_internal_id_here")
48
+
49
+ **Failure to include snippet elements or using incorrect references will result in incomplete content creation.**
50
+
51
+ ## Working with Content Types Containing Taxonomy Groups
52
+
53
+ **CRITICAL**: When creating language variants for content types with taxonomy elements, you must:
54
+
55
+ 1. **Read the content type** to identify ALL taxonomy elements (type: "taxonomy")
56
+ 2. **Retrieve EACH taxonomy group definition** to understand the available terms and their hierarchical structure
57
+ 3. **Fill ALL taxonomy elements** in the language variant - DO NOT leave any taxonomy elements empty
58
+ 4. **Use appropriate term internal IDs** when filling taxonomy elements based on the content being created
59
+
60
+ **MANDATORY REQUIREMENT**: Every taxonomy element in the content type MUST be filled with at least one appropriate term when creating language variants. Empty taxonomy elements are not acceptable and indicate incomplete content creation.
61
+
62
+ **Example Process**: If a content type has three taxonomy elements:
63
+ - "article_type" (required) → Must select appropriate type using its internal ID
64
+ - "topics" (optional but must be filled) → Must select relevant topics using their internal IDs
65
+ - "medical_specialties" (optional but must be filled) → Must select relevant specialties using their internal IDs
66
+
67
+ **Failure to fill ALL taxonomy elements will result in incomplete content creation and poor content organization.**
35
68
 
36
69
  ## Operational Patterns
37
70
 
@@ -55,10 +88,38 @@ Example: If a content type has direct elements (title, body) and a metadata snip
55
88
 
56
89
  **Workflow states** manage the content lifecycle, tracking whether content is being drafted, is live, or has been archived.
57
90
 
58
- **Codenames** are human-readable unique identifiers that provide a consistent way to reference content programmatically.
91
+ **Internal IDs** are unique identifiers that provide fast and reliable access to content entities. **ALWAYS use internal IDs when working with MCP tools for better performance and reliability.**
92
+
93
+ **Codenames** are human-readable unique identifiers that provide a consistent way to reference content programmatically, but should be used primarily for readability and debugging.
59
94
 
60
95
  ## Best Practices
61
96
 
62
- Use snippets for common field groups to maintain consistency and avoid duplication. Plan your content types before creating content to ensure proper structure. Use meaningful codenames consistently throughout your project for better maintainability. Leverage taxonomies for organization to create logical content hierarchies. Consider your multilingual strategy early in the planning process to avoid restructuring later.
97
+ 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.
98
+
99
+ When working with snippets, always retrieve and understand the complete element structure before creating content variants.
100
+
101
+ When working with taxonomy elements, always retrieve and understand the taxonomy group structure and available terms before creating content variants. **NEVER leave taxonomy elements empty - all taxonomy elements must be properly categorized using internal IDs.**
102
+
103
+ ## MCP Tool Usage Guidelines
104
+
105
+ **CRITICAL**: When using MCP tools, always prefer internal IDs over codenames:
106
+
107
+ - **Content Items**: Use internal IDs to reference content items
108
+ - **Language Variants**: Use internal IDs for both item and language references
109
+ - **Content Types**: Use internal IDs to reference content types
110
+ - **Taxonomy Terms**: Use internal IDs when referencing taxonomy terms
111
+ - **Assets**: Use internal IDs when referencing assets
112
+ - **Workflow Steps**: Use internal IDs for workflow step references
113
+
114
+ **Why Internal IDs?** Internal IDs provide:
115
+ - Better performance (faster lookups)
116
+ - Immutability (won't change if names change)
117
+ - Reliability (consistent across environments)
118
+ - API efficiency (direct database lookups)
119
+
120
+ **When to use codenames?** Codenames are useful for:
121
+ - Human readability during development
122
+ - Debugging and logging
123
+ - Initial content setup when IDs are not yet known
63
124
 
64
- When working with snippets, always retrieve and understand the complete element structure before creating content variants.`;
125
+ All MCP tools have been optimized to work with internal IDs for maximum efficiency.`;
@@ -3,17 +3,17 @@ 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 codename from Management API", {
7
- codename: z.string().describe("Codename of the content item to delete"),
8
- }, async ({ codename }) => {
6
+ server.tool("delete-content-item-mapi", "Delete a content item by internal ID from Management API", {
7
+ id: z.string().describe("Internal ID of the content item to delete"),
8
+ }, async ({ id }) => {
9
9
  const client = createMapiClient();
10
10
  try {
11
11
  const response = await client
12
12
  .deleteContentItem()
13
- .byItemCodename(codename)
13
+ .byItemId(id)
14
14
  .toPromise();
15
15
  return createMcpToolSuccessResponse({
16
- message: `Content item '${codename}' deleted successfully`,
16
+ message: `Content item '${id}' deleted successfully`,
17
17
  deletedItem: response.data,
18
18
  });
19
19
  }
@@ -4,20 +4,20 @@ import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
6
  server.tool("delete-language-variant-mapi", "Delete a language variant of a content item from Management API", {
7
- itemCodename: z.string().describe("Codename of the content item"),
8
- languageCodename: z
7
+ itemId: z.string().describe("Internal ID of the content item"),
8
+ languageId: z
9
9
  .string()
10
- .describe("Codename of the language variant to delete"),
11
- }, async ({ itemCodename, languageCodename }) => {
10
+ .describe("Internal ID of the language variant to delete"),
11
+ }, async ({ itemId, languageId }) => {
12
12
  const client = createMapiClient();
13
13
  try {
14
14
  const response = await client
15
15
  .deleteLanguageVariant()
16
- .byItemCodename(itemCodename)
17
- .byLanguageCodename(languageCodename)
16
+ .byItemId(itemId)
17
+ .byLanguageId(languageId)
18
18
  .toPromise();
19
19
  return createMcpToolSuccessResponse({
20
- message: `Language variant '${languageCodename}' of content item '${itemCodename}' deleted successfully`,
20
+ message: `Language variant '${languageId}' of content item '${itemId}' deleted successfully`,
21
21
  deletedVariant: response.data,
22
22
  });
23
23
  }
@@ -3,14 +3,14 @@ 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 codename from Management API", {
7
- assetCodename: z.string().describe("Codename of the asset to retrieve"),
8
- }, async ({ assetCodename }) => {
6
+ server.tool("get-asset-mapi", "Get a specific asset by internal ID from Management API", {
7
+ assetId: z.string().describe("Internal ID of the asset to retrieve"),
8
+ }, async ({ assetId }) => {
9
9
  const client = createMapiClient();
10
10
  try {
11
11
  const response = await client
12
12
  .viewAsset()
13
- .byAssetCodename(assetCodename)
13
+ .byAssetId(assetId)
14
14
  .toPromise();
15
15
  return createMcpToolSuccessResponse(response.data);
16
16
  }
@@ -3,14 +3,14 @@ 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-item-mapi", "Get Kontent.ai item by codename from Management API", {
7
- codename: z.string().describe("Codename of the item to get"),
8
- }, async ({ codename }) => {
6
+ server.tool("get-item-mapi", "Get Kontent.ai item by internal ID from Management API", {
7
+ id: z.string().describe("Internal ID of the item to get"),
8
+ }, async ({ id }) => {
9
9
  const client = createMapiClient();
10
10
  try {
11
11
  const response = await client
12
12
  .viewContentItem()
13
- .byItemCodename(codename)
13
+ .byItemId(id)
14
14
  .toPromise();
15
15
  return createMcpToolSuccessResponse(response.data);
16
16
  }
@@ -3,14 +3,14 @@ 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 codename from Management API", {
7
- codename: z.string().describe("Codename of the taxonomy group to get"),
8
- }, async ({ codename }) => {
6
+ server.tool("get-taxonomy-group-mapi", "Get taxonomy group by internal ID from Management API", {
7
+ id: z.string().describe("Internal ID of the taxonomy group to get"),
8
+ }, async ({ id }) => {
9
9
  const client = createMapiClient();
10
10
  try {
11
11
  const response = await client
12
12
  .getTaxonomy()
13
- .byTaxonomyCodename(codename)
13
+ .byTaxonomyId(id)
14
14
  .toPromise();
15
15
  return createMcpToolSuccessResponse(response.data);
16
16
  }
@@ -3,14 +3,14 @@ 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 codename from Management API", {
7
- codename: z.string().describe("Codename of the content type to get"),
8
- }, async ({ codename }) => {
6
+ server.tool("get-type-mapi", "Get content type by internal ID from Management API", {
7
+ id: z.string().describe("Internal ID of the content type to get"),
8
+ }, async ({ id }) => {
9
9
  const client = createMapiClient();
10
10
  try {
11
11
  const response = await client
12
12
  .viewContentType()
13
- .byTypeCodename(codename)
13
+ .byTypeId(id)
14
14
  .toPromise();
15
15
  return createMcpToolSuccessResponse(response.data);
16
16
  }
@@ -3,16 +3,14 @@ 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 codename from Management API", {
7
- codename: z
8
- .string()
9
- .describe("Codename of the content type snippet to get"),
10
- }, async ({ codename }) => {
6
+ server.tool("get-type-snippet-mapi", "Get content type snippet by internal ID from Management API", {
7
+ id: z.string().describe("Internal ID of the content type snippet to get"),
8
+ }, async ({ id }) => {
11
9
  const client = createMapiClient();
12
10
  try {
13
11
  const response = await client
14
12
  .viewContentTypeSnippet()
15
- .byTypeCodename(codename)
13
+ .byTypeId(id)
16
14
  .toPromise();
17
15
  return createMcpToolSuccessResponse(response.data);
18
16
  }
@@ -4,17 +4,17 @@ import { handleMcpToolError } from "../utils/errorHandler.js";
4
4
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
5
  export const registerTool = (server) => {
6
6
  server.tool("get-variant-mapi", "Get language variant of a content item from Management API", {
7
- itemCodename: z.string().describe("Codename of the content item"),
8
- languageCodename: z
7
+ itemId: z.string().describe("Internal ID of the content item"),
8
+ languageId: z
9
9
  .string()
10
- .describe("Codename of the language variant to get"),
11
- }, async ({ itemCodename, languageCodename }) => {
10
+ .describe("Internal ID of the language variant to get"),
11
+ }, async ({ itemId, languageId }) => {
12
12
  const client = createMapiClient();
13
13
  try {
14
14
  const response = await client
15
15
  .viewLanguageVariant()
16
- .byItemCodename(itemCodename)
17
- .byLanguageCodename(languageCodename)
16
+ .byItemId(itemId)
17
+ .byLanguageId(languageId)
18
18
  .toPromise();
19
19
  return createMcpToolSuccessResponse(response.data);
20
20
  }
@@ -3,8 +3,8 @@ 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 codename via Management API. The content item must already exist - this tool will not create new items.", {
7
- codename: z.string().describe("Codename of the content item to update"),
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.", {
7
+ id: z.string().describe("Internal ID of the content item to update"),
8
8
  name: z
9
9
  .string()
10
10
  .min(1)
@@ -19,11 +19,11 @@ export const registerTool = (server) => {
19
19
  })
20
20
  .optional()
21
21
  .describe("Reference to a collection by id, codename, or external_id (optional)"),
22
- }, async ({ codename, name, collection }) => {
22
+ }, async ({ id, name, collection }) => {
23
23
  const client = createMapiClient();
24
24
  try {
25
25
  // First, verify the item exists by trying to get it
26
- await client.viewContentItem().byItemCodename(codename).toPromise();
26
+ await client.viewContentItem().byItemId(id).toPromise();
27
27
  // If we get here, the item exists, so we can update it
28
28
  const updateData = {};
29
29
  if (name !== undefined) {
@@ -46,11 +46,11 @@ export const registerTool = (server) => {
46
46
  }
47
47
  const response = await client
48
48
  .upsertContentItem()
49
- .byItemCodename(codename)
49
+ .byItemId(id)
50
50
  .withData(updateData)
51
51
  .toPromise();
52
52
  return createMcpToolSuccessResponse({
53
- message: `Content item '${codename}' updated successfully`,
53
+ message: `Content item '${id}' updated successfully`,
54
54
  updatedItem: response.rawData,
55
55
  });
56
56
  }
@@ -62,7 +62,7 @@ export const registerTool = (server) => {
62
62
  content: [
63
63
  {
64
64
  type: "text",
65
- text: `Update Content Item: Content item with codename '${codename}' does not exist. Use add-content-item-mapi to create new items.`,
65
+ text: `Update Content Item: Content item with ID '${id}' does not exist. Use add-content-item-mapi to create new items.`,
66
66
  },
67
67
  ],
68
68
  isError: true,
@@ -1,40 +1,32 @@
1
1
  import { z } from "zod";
2
2
  import { createMapiClient } from "../clients/kontentClients.js";
3
- import { createValidationErrorResponse, handleMcpToolError, } from "../utils/errorHandler.js";
3
+ import { languageVariantElementSchema } from "../schemas/contentItemSchemas.js";
4
+ import { handleMcpToolError } from "../utils/errorHandler.js";
4
5
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
6
  export const registerTool = (server) => {
6
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
- itemCodename: z.string().describe("Codename of the content item"),
8
- languageCodename: z
8
+ itemId: z.string().describe("Internal ID of the content item"),
9
+ languageId: z
9
10
  .string()
10
- .describe("Codename of the language variant (e.g., 'default', 'en-US', 'es-ES')"),
11
- elements: z
12
- .string()
13
- .describe('JSON string representing an array of element objects. Each element should have an "element" object with "codename" property and a "value" property. Example: \'[{"element": {"codename": "title"}, "value": "My Title"}, {"element": {"codename": "content"}, "value": "<p>My content</p>"}]\''),
14
- workflow_step_codename: z
11
+ .describe("Internal ID of the language variant (e.g., '00000000-0000-0000-0000-000000000000' for default language)"),
12
+ elements: z.array(languageVariantElementSchema),
13
+ workflow_step_id: z
15
14
  .string()
16
15
  .optional()
17
- .describe("Codename of the workflow step (optional)"),
18
- }, async ({ itemCodename, languageCodename, elements, workflow_step_codename, }) => {
16
+ .describe("Internal ID of the workflow step (optional)"),
17
+ }, async ({ itemId, languageId, elements, workflow_step_id }) => {
19
18
  const client = createMapiClient();
20
- let parsedElements;
21
- try {
22
- parsedElements = JSON.parse(elements);
23
- }
24
- catch (error) {
25
- return createValidationErrorResponse(`Invalid JSON format in elements parameter. ${error instanceof Error ? error.message : "Unknown JSON parsing error"}`, "JSON Parsing Error");
26
- }
27
19
  const data = {
28
- elements: parsedElements,
20
+ elements,
29
21
  };
30
- if (workflow_step_codename) {
31
- data.workflow_step = { codename: workflow_step_codename };
22
+ if (workflow_step_id) {
23
+ data.workflow_step = { id: workflow_step_id };
32
24
  }
33
25
  try {
34
26
  const response = await client
35
27
  .upsertLanguageVariant()
36
- .byItemCodename(itemCodename)
37
- .byLanguageCodename(languageCodename)
28
+ .byItemId(itemId)
29
+ .byLanguageId(languageId)
38
30
  .withData(() => data)
39
31
  .toPromise();
40
32
  return createMcpToolSuccessResponse(response.rawData);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontent-ai/mcp-server",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rimraf build && tsc",