@kontent-ai/mcp-server 0.8.0 → 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(),
@@ -0,0 +1,125 @@
1
+ export const initialContext = `
2
+ # Kontent.ai Platform Guide
3
+
4
+ Kontent.ai is a headless content management system (CMS) that provides two main APIs: the Management API for creating, updating, and deleting content and structure, and the Delivery API for retrieving content for applications.
5
+
6
+ ## Core Entities
7
+
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 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
+
11
+ ### Language Variants
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.
13
+
14
+ ### Content Types
15
+ Content types define the structure and blueprint for language variants. They specify field definitions, validation rules, and element types that language variants will use. Think of them as templates that determine what fields and data types your language variants will have.
16
+
17
+ ### Content Type Snippets
18
+ Content type snippets are reusable field groups that promote consistency across multiple content types. Following the DRY principle (define once, use everywhere), one snippet can be used across multiple content types. This prevents duplication and ensures consistency when you need the same fields across different content types.
19
+
20
+ ## Understanding Key Relationships
21
+
22
+ The content structure flows from Content Type → Content Item → Language Variant(s). For reusability, Content Type Snippets can be included in multiple Content Types. For localization, each Content Item can have one Language Variant per language.
23
+
24
+ ## Working with Content Types Containing Snippets
25
+
26
+ **CRITICAL**: When creating language variants for content types with snippets, you must:
27
+
28
+ 1. **Read the content type** to identify snippet elements (type: "snippet")
29
+ 2. **Retrieve each snippet definition** to understand its internal elements
30
+ 3. **Include ALL elements** from both the content type AND all snippets in the language variant
31
+
32
+ **SNIPPET ELEMENT IMPLEMENTATION DETAILS**:
33
+
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.**
68
+
69
+ ## Operational Patterns
70
+
71
+ ### Content Creation Workflow
72
+ 1. Define content types (structure) - Create the blueprint for your content
73
+ 2. Create content items (containers) - Establish the content containers
74
+ 3. Add language variants (actual content) - Fill in the language-specific content
75
+ 4. Publish variants (make live) - Make content available through the Delivery API
76
+
77
+ ### Content Management Workflow
78
+ - Update language variants with new content or changes
79
+ - Manage workflow states as content progresses through its lifecycle
80
+ - Create new language variants when expanding to additional languages
81
+ - Organize with taxonomies for better content categorization
82
+
83
+ ## Essential Concepts
84
+
85
+ **Taxonomies** provide hierarchical content categorization, allowing you to organize and tag content systematically.
86
+
87
+ **Assets** are digital files including images, videos, and documents that can be referenced throughout your content.
88
+
89
+ **Workflow states** manage the content lifecycle, tracking whether content is being drafted, is live, or has been archived.
90
+
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.
94
+
95
+ ## Best Practices
96
+
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
124
+
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
  }
@@ -1,15 +1,9 @@
1
- import { readFile } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
1
  import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = dirname(__filename);
2
+ import { initialContext } from "./context/initial-context.js";
7
3
  export const registerTool = (server) => {
8
4
  server.tool("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. If you have not called this tool, do so immediately before proceeding with any other operation.", {}, async () => {
9
5
  try {
10
- const markdownPath = join(__dirname, "./context/get-initial-context.md");
11
- const kontentaiInstructions = await readFile(markdownPath, "utf-8");
12
- return createMcpToolSuccessResponse(kontentaiInstructions);
6
+ return createMcpToolSuccessResponse(initialContext);
13
7
  }
14
8
  catch (error) {
15
9
  throw new Error(`Failed to read initial context: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -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.0",
3
+ "version": "0.8.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rimraf build && tsc",