@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 +10 -10
- package/build/schemas/contentItemSchemas.js +58 -191
- package/build/schemas/contentTypeSchemas.js +1 -1
- package/build/tools/context/initial-context.js +67 -6
- package/build/tools/delete-content-item-mapi.js +5 -5
- package/build/tools/delete-language-variant-mapi.js +7 -7
- package/build/tools/get-asset-mapi.js +4 -4
- package/build/tools/get-item-mapi.js +4 -4
- package/build/tools/get-taxonomy-group-mapi.js +4 -4
- package/build/tools/get-type-mapi.js +4 -4
- package/build/tools/get-type-snippet-mapi.js +4 -6
- package/build/tools/get-variant-mapi.js +6 -6
- package/build/tools/update-content-item-mapi.js +7 -7
- package/build/tools/upsert-language-variant-mapi.js +14 -22
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
88
|
-
* **delete-content-item-mapi** – Delete a content item by
|
|
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
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
value: z.
|
|
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
|
|
15
|
-
|
|
13
|
+
const richTextComponentSchema = z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
type: referenceObjectSchema,
|
|
16
|
+
elements: z.array(languageVariantElementBaseSchema),
|
|
16
17
|
});
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const customElementInVariantElementSchema = z.object({
|
|
23
|
+
element: referenceObjectSchema,
|
|
24
|
+
value: z.string().nullable(),
|
|
25
|
+
searchable_value: z.string().nullable(),
|
|
27
26
|
});
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const dateTimeInVariantElementSchema = z.object({
|
|
28
|
+
element: referenceObjectSchema,
|
|
29
|
+
value: z.string().nullable(),
|
|
30
|
+
display_timezone: z.string().nullable(),
|
|
32
31
|
});
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
49
|
-
|
|
44
|
+
const richTextInVariantElementSchema = z.object({
|
|
45
|
+
element: referenceObjectSchema,
|
|
46
|
+
value: z.string().nullable(),
|
|
47
|
+
components: z.array(richTextComponentSchema).nullable(),
|
|
50
48
|
});
|
|
51
|
-
const
|
|
52
|
-
|
|
49
|
+
const taxonomyInVariantElementSchema = z.object({
|
|
50
|
+
element: referenceObjectSchema,
|
|
51
|
+
value: z.array(referenceObjectSchema).nullable(),
|
|
53
52
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
32
|
+
**SNIPPET ELEMENT IMPLEMENTATION DETAILS**:
|
|
33
33
|
|
|
34
|
-
|
|
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
|
-
**
|
|
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.
|
|
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
|
-
|
|
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
|
|
7
|
-
|
|
8
|
-
}, async ({
|
|
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
|
-
.
|
|
13
|
+
.byItemId(id)
|
|
14
14
|
.toPromise();
|
|
15
15
|
return createMcpToolSuccessResponse({
|
|
16
|
-
message: `Content item '${
|
|
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
|
-
|
|
8
|
-
|
|
7
|
+
itemId: z.string().describe("Internal ID of the content item"),
|
|
8
|
+
languageId: z
|
|
9
9
|
.string()
|
|
10
|
-
.describe("
|
|
11
|
-
}, async ({
|
|
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
|
-
.
|
|
17
|
-
.
|
|
16
|
+
.byItemId(itemId)
|
|
17
|
+
.byLanguageId(languageId)
|
|
18
18
|
.toPromise();
|
|
19
19
|
return createMcpToolSuccessResponse({
|
|
20
|
-
message: `Language variant '${
|
|
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
|
|
7
|
-
|
|
8
|
-
}, async ({
|
|
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
|
-
.
|
|
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
|
|
7
|
-
|
|
8
|
-
}, async ({
|
|
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
|
-
.
|
|
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
|
|
7
|
-
|
|
8
|
-
}, async ({
|
|
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
|
-
.
|
|
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
|
|
7
|
-
|
|
8
|
-
}, async ({
|
|
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
|
-
.
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
.
|
|
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
|
-
|
|
8
|
-
|
|
7
|
+
itemId: z.string().describe("Internal ID of the content item"),
|
|
8
|
+
languageId: z
|
|
9
9
|
.string()
|
|
10
|
-
.describe("
|
|
11
|
-
}, async ({
|
|
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
|
-
.
|
|
17
|
-
.
|
|
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
|
|
7
|
-
|
|
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 ({
|
|
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().
|
|
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
|
-
.
|
|
49
|
+
.byItemId(id)
|
|
50
50
|
.withData(updateData)
|
|
51
51
|
.toPromise();
|
|
52
52
|
return createMcpToolSuccessResponse({
|
|
53
|
-
message: `Content item '${
|
|
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
|
|
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 {
|
|
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
|
-
|
|
8
|
-
|
|
8
|
+
itemId: z.string().describe("Internal ID of the content item"),
|
|
9
|
+
languageId: z
|
|
9
10
|
.string()
|
|
10
|
-
.describe("
|
|
11
|
-
elements: z
|
|
12
|
-
|
|
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("
|
|
18
|
-
}, async ({
|
|
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
|
|
20
|
+
elements,
|
|
29
21
|
};
|
|
30
|
-
if (
|
|
31
|
-
data.workflow_step = {
|
|
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
|
-
.
|
|
37
|
-
.
|
|
28
|
+
.byItemId(itemId)
|
|
29
|
+
.byLanguageId(languageId)
|
|
38
30
|
.withData(() => data)
|
|
39
31
|
.toPromise();
|
|
40
32
|
return createMcpToolSuccessResponse(response.rawData);
|