@kontent-ai/mcp-server 0.21.9 → 0.21.11
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 +30 -1
- package/build/bin.js +7 -0
- package/build/schemas/contentTypeSchemas.js +24 -61
- package/build/schemas/filterVariantSchemas.js +2 -0
- package/build/schemas/listSchemas.js +26 -0
- package/build/schemas/patchSchemas/contentTypePatchSchemas.js +12 -64
- package/build/schemas/referenceObjectSchema.js +3 -5
- package/build/schemas/taxonomySchemas.js +4 -9
- package/build/test/utils/responseHelper.spec.js +450 -0
- package/build/tools/add-content-item-mapi.js +6 -13
- package/build/tools/add-content-type-mapi.js +6 -11
- package/build/tools/add-content-type-snippet-mapi.js +5 -8
- package/build/tools/add-taxonomy-group-mapi.js +1 -1
- package/build/tools/change-variant-workflow-step-mapi.js +5 -14
- package/build/tools/context/initial-context.js +40 -1
- package/build/tools/context/patch-operations-guide.js +58 -0
- package/build/tools/create-variant-version-mapi.js +3 -6
- package/build/tools/delete-content-item-mapi.js +2 -2
- package/build/tools/delete-content-type-mapi.js +2 -2
- package/build/tools/delete-language-variant-mapi.js +3 -5
- package/build/tools/filter-variants-mapi.js +13 -20
- package/build/tools/get-asset-mapi.js +2 -2
- package/build/tools/get-initial-context.js +2 -1
- package/build/tools/get-item-mapi.js +2 -2
- package/build/tools/get-taxonomy-group-mapi.js +2 -2
- package/build/tools/get-type-mapi.js +2 -2
- package/build/tools/get-type-snippet-mapi.js +2 -2
- package/build/tools/get-variant-mapi.js +5 -7
- package/build/tools/list-assets-mapi.js +12 -4
- package/build/tools/list-content-type-snippets-mapi.js +12 -4
- package/build/tools/list-content-types-mapi.js +12 -4
- package/build/tools/list-languages-mapi.js +12 -4
- package/build/tools/list-taxonomy-groups-mapi.js +12 -4
- package/build/tools/list-workflows-mapi.js +1 -1
- package/build/tools/patch-content-type-mapi.js +3 -50
- package/build/tools/publish-variant-mapi.js +5 -8
- package/build/tools/search-variants-mapi.js +3 -29
- package/build/tools/unpublish-variant-mapi.js +5 -8
- package/build/tools/update-content-item-mapi.js +4 -4
- package/build/tools/upsert-language-variant-mapi.js +7 -10
- package/build/utils/responseHelper.js +90 -6
- package/package.json +4 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const patchOperationsGuide = `
|
|
2
|
+
# Content Type Patch Operations Guide
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
Modify content types using RFC 6902 JSON Patch operations: move, addInto, remove, replace.
|
|
6
|
+
|
|
7
|
+
## Critical Requirements
|
|
8
|
+
- **Always call get-type-mapi first** to get current schema
|
|
9
|
+
- **Use addInto/remove for arrays** (elements, allowed_content_types, allowed_blocks, etc.)
|
|
10
|
+
- **Never use replace for array properties** - use addInto/remove instead
|
|
11
|
+
- **Use replace for primitives/objects** (name, maximum_text_length, validation_regex)
|
|
12
|
+
- **external_id and type cannot be modified** after creation
|
|
13
|
+
- **When adding allowed_formatting/allowed_table_formatting**, 'unstyled' must be first
|
|
14
|
+
|
|
15
|
+
## Operation Types
|
|
16
|
+
|
|
17
|
+
### move
|
|
18
|
+
Reorganize elements, options, or content groups using 'before' or 'after' reference.
|
|
19
|
+
|
|
20
|
+
### addInto
|
|
21
|
+
Add new items to arrays. Use for all array operations (elements, options, allowed_blocks, etc.).
|
|
22
|
+
|
|
23
|
+
### remove
|
|
24
|
+
Delete items from arrays or remove elements/groups.
|
|
25
|
+
|
|
26
|
+
### replace
|
|
27
|
+
Update primitives and objects. Cannot modify external_id, id, or type.
|
|
28
|
+
|
|
29
|
+
## Path Formats
|
|
30
|
+
Use JSON Pointer with id:{uuid} format:
|
|
31
|
+
- Element: /elements/id:{uuid}
|
|
32
|
+
- Element property: /elements/id:{uuid}/name
|
|
33
|
+
- Option: /elements/id:{uuid}/options/id:{uuid}
|
|
34
|
+
- Content group: /content_groups/id:{uuid}
|
|
35
|
+
- Array item: /elements/id:{uuid}/allowed_content_types/id:{uuid}
|
|
36
|
+
|
|
37
|
+
## Rich Text Properties
|
|
38
|
+
- **allowed_content_types**: Content types for components/linked items (empty=all)
|
|
39
|
+
- **allowed_item_link_types**: Content types for text links (empty=all)
|
|
40
|
+
- **allowed_blocks**: "images", "text", "tables", "components-and-items" (empty=all)
|
|
41
|
+
- **allowed_image_types**: "adjustable" or "any"
|
|
42
|
+
- **allowed_text_blocks**: "paragraph", "heading-one" through "heading-six", "ordered-list", "unordered-list" (empty=all)
|
|
43
|
+
- **allowed_formatting**: "unstyled", "bold", "italic", "code", "link", "subscript", "superscript" (empty=all, unstyled must be first)
|
|
44
|
+
- **allowed_table_blocks**: "images", "text" (empty=both)
|
|
45
|
+
- **allowed_table_text_blocks**: Same as allowed_text_blocks (empty=all)
|
|
46
|
+
- **allowed_table_formatting**: Same as allowed_formatting (empty=all, unstyled must be first)
|
|
47
|
+
|
|
48
|
+
## Special Techniques
|
|
49
|
+
- **Remove content groups**: Set ALL elements' content_group to null AND remove ALL groups in one request
|
|
50
|
+
- **URL Slug with snippet**: Add snippet element first, then URL slug with depends_on reference
|
|
51
|
+
|
|
52
|
+
## Best Practices
|
|
53
|
+
- Use descriptive codenames
|
|
54
|
+
- Group related operations in single request
|
|
55
|
+
- Use id:{uuid} format in paths
|
|
56
|
+
- Validate dependencies before adding URL slugs
|
|
57
|
+
- Consider element ordering for move operations
|
|
58
|
+
`;
|
|
@@ -3,15 +3,12 @@ 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("create-variant-version-mapi", "Create new version of Kontent.ai
|
|
7
|
-
itemId: z
|
|
8
|
-
.string()
|
|
9
|
-
.uuid()
|
|
10
|
-
.describe("Internal ID (UUID) of the content item whose language variant you want to create a new version of"),
|
|
6
|
+
server.tool("create-variant-version-mapi", "Create new version of Kontent.ai variant", {
|
|
7
|
+
itemId: z.string().uuid().describe("Content item UUID"),
|
|
11
8
|
languageId: z
|
|
12
9
|
.string()
|
|
13
10
|
.uuid()
|
|
14
|
-
.describe("
|
|
11
|
+
.describe("Language variant UUID (default: 00000000-0000-0000-0000-000000000000)"),
|
|
15
12
|
}, async ({ itemId, languageId }, { authInfo: { token, clientId } = {} }) => {
|
|
16
13
|
const client = createMapiClient(clientId, token);
|
|
17
14
|
try {
|
|
@@ -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("delete-content-item-mapi", "Delete Kontent.ai content item
|
|
7
|
-
id: z.string().describe("
|
|
6
|
+
server.tool("delete-content-item-mapi", "Delete Kontent.ai content item", {
|
|
7
|
+
id: z.string().describe("Item ID"),
|
|
8
8
|
}, async ({ id }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -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("delete-content-type-mapi", "Delete
|
|
7
|
-
codename: z.string().describe("
|
|
6
|
+
server.tool("delete-content-type-mapi", "Delete Kontent.ai content type by codename", {
|
|
7
|
+
codename: z.string().describe("Content type codename"),
|
|
8
8
|
}, async ({ codename }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -3,11 +3,9 @@ import { createMapiClient } from "../clients/kontentClients.js";
|
|
|
3
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
4
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
5
|
export const registerTool = (server) => {
|
|
6
|
-
server.tool("delete-language-variant-mapi", "Delete Kontent.ai
|
|
7
|
-
itemId: z.string().describe("
|
|
8
|
-
languageId: z
|
|
9
|
-
.string()
|
|
10
|
-
.describe("Internal ID of the language variant to delete"),
|
|
6
|
+
server.tool("delete-language-variant-mapi", "Delete Kontent.ai variant", {
|
|
7
|
+
itemId: z.string().describe("Item ID"),
|
|
8
|
+
languageId: z.string().describe("Language variant ID"),
|
|
11
9
|
}, async ({ itemId, languageId }, { authInfo: { token, clientId } = {} }) => {
|
|
12
10
|
const client = createMapiClient(clientId, token);
|
|
13
11
|
try {
|
|
@@ -1,31 +1,17 @@
|
|
|
1
1
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
2
|
import { filterVariantsSchema } from "../schemas/filterVariantSchemas.js";
|
|
3
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createVariantMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
5
|
import { throwError } from "../utils/throwError.js";
|
|
6
6
|
export const registerTool = (server) => {
|
|
7
|
-
server.tool("filter-variants-mapi",
|
|
8
|
-
|
|
9
|
-
USE FOR:
|
|
10
|
-
- EXACT keyword matching: finding specific words, phrases, names, codes, or IDs anywhere in content, regardless of overall topic
|
|
11
|
-
✓ Example: 'find items containing rabbit' → search 'rabbit'
|
|
12
|
-
- Brand guideline compliance: detecting prohibited terms across all content
|
|
13
|
-
✓ Example: Search "hunt beast prey" to find content containing ANY of these terms (natural OR operator)
|
|
14
|
-
- CAN expand concepts to keywords when using filter (e.g., "neurology-related" → "neurology neurological brain nervous system")
|
|
15
|
-
- Advanced filtering by content type, contributors, workflow steps, taxonomies etc
|
|
16
|
-
- Also use as fallback when AI search is unavailable
|
|
17
|
-
- Optionally includes full content of variants with include_content parameter
|
|
18
|
-
|
|
19
|
-
BEST FOR: Finding needles in haystacks - specific words in otherwise unrelated content. Multiple search terms use OR logic.`, filterVariantsSchema.shape, async ({ search_phrase, content_types, contributors, has_no_contributors, completion_statuses, language, workflow_steps, taxonomy_groups, order_by, order_direction, include_content, }, { authInfo: { token, clientId } = {} }) => {
|
|
7
|
+
server.tool("filter-variants-mapi", "Filter Kontent.ai variants. For EXACT keyword matching and compliance (terms use OR). Use search-variants-mapi for semantic/topic search.", filterVariantsSchema.shape, async ({ search_phrase, content_types, contributors, has_no_contributors, completion_statuses, language, workflow_steps, taxonomy_groups, order_by, order_direction, include_content, continuation_token, }, { authInfo: { token, clientId } = {} }) => {
|
|
20
8
|
try {
|
|
21
9
|
const environmentId = clientId ?? process.env.KONTENT_ENVIRONMENT_ID;
|
|
22
10
|
if (!environmentId) {
|
|
23
11
|
throwError("Missing required environment ID");
|
|
24
12
|
}
|
|
25
13
|
const client = createMapiClient(environmentId, token);
|
|
26
|
-
const
|
|
27
|
-
.filterLanguageVariants()
|
|
28
|
-
.withData({
|
|
14
|
+
const query = client.earlyAccess.filterLanguageVariants().withData({
|
|
29
15
|
filters: {
|
|
30
16
|
search_phrase,
|
|
31
17
|
content_types,
|
|
@@ -43,9 +29,16 @@ export const registerTool = (server) => {
|
|
|
43
29
|
}
|
|
44
30
|
: undefined,
|
|
45
31
|
include_content: include_content ?? false,
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
});
|
|
33
|
+
const response = await (continuation_token
|
|
34
|
+
? query.xContinuationToken(continuation_token)
|
|
35
|
+
: query).toPromise();
|
|
36
|
+
return createVariantMcpToolSuccessResponse({
|
|
37
|
+
data: response.rawData.data,
|
|
38
|
+
pagination: {
|
|
39
|
+
continuation_token: response.data.pagination.continuationToken,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
49
42
|
}
|
|
50
43
|
catch (error) {
|
|
51
44
|
return handleMcpToolError(error, "Variant Filter");
|
|
@@ -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("get-asset-mapi", "Get
|
|
7
|
-
assetId: z.string().describe("
|
|
6
|
+
server.tool("get-asset-mapi", "Get Kontent.ai asset by ID", {
|
|
7
|
+
assetId: z.string().describe("Asset ID"),
|
|
8
8
|
}, async ({ assetId }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
2
2
|
import { initialContext } from "./context/initial-context.js";
|
|
3
|
+
import { patchOperationsGuide } from "./context/patch-operations-guide.js";
|
|
3
4
|
export const registerTool = (server) => {
|
|
4
5
|
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 () => {
|
|
5
6
|
try {
|
|
6
|
-
return createMcpToolSuccessResponse(initialContext);
|
|
7
|
+
return createMcpToolSuccessResponse(`${initialContext}\n\n${patchOperationsGuide}`);
|
|
7
8
|
}
|
|
8
9
|
catch (error) {
|
|
9
10
|
throw new Error(`Failed to read initial context: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -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("get-item-mapi", "Get Kontent.ai item by
|
|
7
|
-
id: z.string().describe("
|
|
6
|
+
server.tool("get-item-mapi", "Get Kontent.ai item by ID", {
|
|
7
|
+
id: z.string().describe("Item ID"),
|
|
8
8
|
}, async ({ id }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -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("get-taxonomy-group-mapi", "Get Kontent.ai taxonomy group by
|
|
7
|
-
id: z.string().describe("
|
|
6
|
+
server.tool("get-taxonomy-group-mapi", "Get Kontent.ai taxonomy group by ID", {
|
|
7
|
+
id: z.string().describe("Taxonomy group ID"),
|
|
8
8
|
}, async ({ id }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -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("get-type-mapi", "Get Kontent.ai content type by
|
|
7
|
-
id: z.string().describe("
|
|
6
|
+
server.tool("get-type-mapi", "Get Kontent.ai content type by ID", {
|
|
7
|
+
id: z.string().describe("Content type ID"),
|
|
8
8
|
}, async ({ id }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -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("get-type-snippet-mapi", "Get Kontent.ai content type snippet by
|
|
7
|
-
id: z.string().describe("
|
|
6
|
+
server.tool("get-type-snippet-mapi", "Get Kontent.ai content type snippet by ID", {
|
|
7
|
+
id: z.string().describe("Snippet ID"),
|
|
8
8
|
}, async ({ id }, { authInfo: { token, clientId } = {} }) => {
|
|
9
9
|
const client = createMapiClient(clientId, token);
|
|
10
10
|
try {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createVariantMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
5
|
export const registerTool = (server) => {
|
|
6
|
-
server.tool("get-variant-mapi", "Get Kontent.ai
|
|
7
|
-
itemId: z.string().describe("
|
|
8
|
-
languageId: z
|
|
9
|
-
.string()
|
|
10
|
-
.describe("Internal ID of the language variant to get"),
|
|
6
|
+
server.tool("get-variant-mapi", "Get Kontent.ai variant", {
|
|
7
|
+
itemId: z.string().describe("Item ID"),
|
|
8
|
+
languageId: z.string().describe("Language variant ID"),
|
|
11
9
|
}, async ({ itemId, languageId }, { authInfo: { token, clientId } = {} }) => {
|
|
12
10
|
const client = createMapiClient(clientId, token);
|
|
13
11
|
try {
|
|
@@ -16,7 +14,7 @@ export const registerTool = (server) => {
|
|
|
16
14
|
.byItemId(itemId)
|
|
17
15
|
.byLanguageId(languageId)
|
|
18
16
|
.toPromise();
|
|
19
|
-
return
|
|
17
|
+
return createVariantMcpToolSuccessResponse(response.rawData);
|
|
20
18
|
}
|
|
21
19
|
catch (error) {
|
|
22
20
|
return handleMcpToolError(error, "Language Variant Retrieval");
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
+
import { listAssetsSchema } from "../schemas/listSchemas.js";
|
|
2
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
3
4
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
4
5
|
export const registerTool = (server) => {
|
|
5
|
-
server.tool("list-assets-mapi", "Get all Kontent.ai assets
|
|
6
|
+
server.tool("list-assets-mapi", "Get all Kontent.ai assets (paginated)", listAssetsSchema.shape, async ({ continuation_token }, { authInfo: { token, clientId } = {} }) => {
|
|
6
7
|
const client = createMapiClient(clientId, token);
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const query = client.listAssets();
|
|
10
|
+
const response = await (continuation_token
|
|
11
|
+
? query.xContinuationToken(continuation_token)
|
|
12
|
+
: query).toPromise();
|
|
13
|
+
return createMcpToolSuccessResponse({
|
|
14
|
+
data: response.rawData.assets,
|
|
15
|
+
pagination: {
|
|
16
|
+
continuation_token: response.data.pagination.continuationToken,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
11
19
|
}
|
|
12
20
|
catch (error) {
|
|
13
21
|
return handleMcpToolError(error, "Assets Listing");
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
+
import { listContentTypeSnippetsSchema } from "../schemas/listSchemas.js";
|
|
2
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
3
4
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
4
5
|
export const registerTool = (server) => {
|
|
5
|
-
server.tool("list-content-type-snippets-mapi", "Get all Kontent.ai content type snippets
|
|
6
|
+
server.tool("list-content-type-snippets-mapi", "Get all Kontent.ai content type snippets (paginated)", listContentTypeSnippetsSchema.shape, async ({ continuation_token }, { authInfo: { token, clientId } = {} }) => {
|
|
6
7
|
const client = createMapiClient(clientId, token);
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const query = client.listContentTypeSnippets();
|
|
10
|
+
const response = await (continuation_token
|
|
11
|
+
? query.xContinuationToken(continuation_token)
|
|
12
|
+
: query).toPromise();
|
|
13
|
+
return createMcpToolSuccessResponse({
|
|
14
|
+
data: response.rawData.snippets,
|
|
15
|
+
pagination: {
|
|
16
|
+
continuation_token: response.data.pagination.continuationToken,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
11
19
|
}
|
|
12
20
|
catch (error) {
|
|
13
21
|
return handleMcpToolError(error, "Content Type Snippets Listing");
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
+
import { listContentTypesSchema } from "../schemas/listSchemas.js";
|
|
2
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
3
4
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
4
5
|
export const registerTool = (server) => {
|
|
5
|
-
server.tool("list-content-types-mapi", "Get all Kontent.ai content types
|
|
6
|
+
server.tool("list-content-types-mapi", "Get all Kontent.ai content types (paginated)", listContentTypesSchema.shape, async ({ continuation_token }, { authInfo: { token, clientId } = {} }) => {
|
|
6
7
|
const client = createMapiClient(clientId, token);
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const query = client.listContentTypes();
|
|
10
|
+
const response = await (continuation_token
|
|
11
|
+
? query.xContinuationToken(continuation_token)
|
|
12
|
+
: query).toPromise();
|
|
13
|
+
return createMcpToolSuccessResponse({
|
|
14
|
+
data: response.rawData.types,
|
|
15
|
+
pagination: {
|
|
16
|
+
continuation_token: response.data.pagination.continuationToken,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
11
19
|
}
|
|
12
20
|
catch (error) {
|
|
13
21
|
return handleMcpToolError(error, "Content Types Listing");
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
+
import { listLanguagesSchema } from "../schemas/listSchemas.js";
|
|
2
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
3
4
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
4
5
|
export const registerTool = (server) => {
|
|
5
|
-
server.tool("list-languages-mapi", "Get all Kontent.ai languages
|
|
6
|
+
server.tool("list-languages-mapi", "Get all Kontent.ai languages (paginated)", listLanguagesSchema.shape, async ({ continuation_token }, { authInfo: { token, clientId } = {} }) => {
|
|
6
7
|
const client = createMapiClient(clientId, token);
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const query = client.listLanguages();
|
|
10
|
+
const response = await (continuation_token
|
|
11
|
+
? query.xContinuationToken(continuation_token)
|
|
12
|
+
: query).toPromise();
|
|
13
|
+
return createMcpToolSuccessResponse({
|
|
14
|
+
data: response.rawData.languages,
|
|
15
|
+
pagination: {
|
|
16
|
+
continuation_token: response.data.pagination.continuationToken,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
11
19
|
}
|
|
12
20
|
catch (error) {
|
|
13
21
|
return handleMcpToolError(error, "Languages Listing");
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
2
|
+
import { listTaxonomyGroupsSchema } from "../schemas/listSchemas.js";
|
|
2
3
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
3
4
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
4
5
|
export const registerTool = (server) => {
|
|
5
|
-
server.tool("list-taxonomy-groups-mapi", "Get all Kontent.ai taxonomy groups
|
|
6
|
+
server.tool("list-taxonomy-groups-mapi", "Get all Kontent.ai taxonomy groups (paginated)", listTaxonomyGroupsSchema.shape, async ({ continuation_token }, { authInfo: { token, clientId } = {} }) => {
|
|
6
7
|
const client = createMapiClient(clientId, token);
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const query = client.listTaxonomies();
|
|
10
|
+
const response = await (continuation_token
|
|
11
|
+
? query.xContinuationToken(continuation_token)
|
|
12
|
+
: query).toPromise();
|
|
13
|
+
return createMcpToolSuccessResponse({
|
|
14
|
+
data: response.rawData.taxonomies,
|
|
15
|
+
pagination: {
|
|
16
|
+
continuation_token: response.data.pagination.continuationToken,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
11
19
|
}
|
|
12
20
|
catch (error) {
|
|
13
21
|
return handleMcpToolError(error, "Taxonomy Groups Listing");
|
|
@@ -2,7 +2,7 @@ import { createMapiClient } from "../clients/kontentClients.js";
|
|
|
2
2
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
3
3
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
4
4
|
export const registerTool = (server) => {
|
|
5
|
-
server.tool("list-workflows-mapi", "Get all Kontent.ai workflows
|
|
5
|
+
server.tool("list-workflows-mapi", "Get all Kontent.ai workflows", {}, async (_, { authInfo: { token, clientId } = {} }) => {
|
|
6
6
|
const client = createMapiClient(clientId, token);
|
|
7
7
|
try {
|
|
8
8
|
const response = await client.listWorkflows().toPromise();
|
|
@@ -4,56 +4,9 @@ import { patchOperationsSchema } from "../schemas/patchSchemas/contentTypePatchS
|
|
|
4
4
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
5
|
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
6
6
|
export const registerTool = (server) => {
|
|
7
|
-
server.tool("patch-content-type-mapi", "Update
|
|
8
|
-
codename: z.string().describe("
|
|
9
|
-
operations: patchOperationsSchema.describe(
|
|
10
|
-
|
|
11
|
-
CRITICAL REQUIREMENTS:
|
|
12
|
-
- ALWAYS call get-type-mapi tool before patching to get the latest content type schema
|
|
13
|
-
- Use addInto/remove for array operations (adding/removing items from arrays like elements and element's array properties - allowed_content_types, allowed_item_link_types, allowed_blocks, allowed_text_blocks, allowed_formatting, allowed_table_blocks, allowed_table_text_blocks, allowed_table_formatting)
|
|
14
|
-
- Never ever use replace for element's array properties - use addInto/remove instead
|
|
15
|
-
- Use replace for element's primitive data types and object properties (maximum_text_length, validation_regex, etc.)
|
|
16
|
-
- External_id and type cannot be modified after creation
|
|
17
|
-
- Patch operations with URL Slug elements referencing snippet elements MUST ensure snippet is present first
|
|
18
|
-
- When adding to allowed_formatting or allowed_table_formatting, 'unstyled' must be the first item in the array. If it is not present, then add it as first operation.
|
|
19
|
-
|
|
20
|
-
RICH TEXT ELEMENT PROPERTIES:
|
|
21
|
-
- allowed_content_types: Array of content type references. Specifies allowed content types for components and linked items. Empty array allows all.
|
|
22
|
-
- allowed_item_link_types: Array of content type references. Specifies content types allowed in text links (applies to text and tables). Empty array allows all.
|
|
23
|
-
- allowed_blocks: Available options: "images", "text", "tables", "components-and-items". Empty array allows all blocks.
|
|
24
|
-
- allowed_image_types: Available options: "adjustable" (only transformable images), "any" (all image files).
|
|
25
|
-
- allowed_text_blocks: Available options: "paragraph", "heading-one", "heading-two", "heading-three", "heading-four", "heading-five", "heading-six", "ordered-list", "unordered-list". Empty array allows all.
|
|
26
|
-
- allowed_formatting: Available options: "unstyled", "bold", "italic", "code", "link", "subscript", "superscript". "unstyled" must be first if used. Empty array allows all.
|
|
27
|
-
- allowed_table_blocks: Available options: "images", "text". Use ["text"] for text-only or empty array for both text and images.
|
|
28
|
-
- allowed_table_text_blocks: Available options: "paragraph", "heading-one", "heading-two", "heading-three", "heading-four", "heading-five", "heading-six", "ordered-list", "unordered-list". Empty array allows all.
|
|
29
|
-
- allowed_table_formatting: Available options: "unstyled", "bold", "italic", "code", "link", "subscript", "superscript". "unstyled" must be first if used. Empty array allows all.
|
|
30
|
-
|
|
31
|
-
OPERATION TYPES:
|
|
32
|
-
1. move: Reorganize elements, options, or content groups. Uses 'before' or 'after' reference.
|
|
33
|
-
2. addInto: Add new elements, options, content groups, or array items. Use for all array operations.
|
|
34
|
-
3. remove: Remove elements, options, content groups, or array items. Use for all array removals.
|
|
35
|
-
4. replace: Update existing properties of primitive data types and objects. Cannot modify external_id, id, or type.
|
|
36
|
-
|
|
37
|
-
PATH FORMATS:
|
|
38
|
-
- Use JSON Pointer paths with id:{uuid} format for referencing objects
|
|
39
|
-
- Element: /elements/id:123e4567-e89b-12d3-a456-426614174000
|
|
40
|
-
- Element property: /elements/id:123e4567-e89b-12d3-a456-426614174000/name
|
|
41
|
-
- Multiple choice option: /elements/id:123e4567-e89b-12d3-a456-426614174000/options/id:987fcdeb-51a2-43d1-9f4e-123456789abc
|
|
42
|
-
- Content group: /content_groups/id:456e7890-a12b-34c5-d678-901234567def
|
|
43
|
-
- Rich text array property: /elements/id:123e4567-e89b-12d3-a456-426614174000/allowed_content_types/id:987fcdeb-51a2-43d1-9f4e-123456789abc
|
|
44
|
-
|
|
45
|
-
SPECIAL TECHNIQUES:
|
|
46
|
-
- To remove content groups while keeping elements: Set ALL elements' content_group to null AND remove ALL content groups in ONE request (atomic operation)
|
|
47
|
-
- URL Slug with snippet dependency: First add snippet element, then add URL slug with depends_on reference
|
|
48
|
-
|
|
49
|
-
BEST PRACTICES:
|
|
50
|
-
- Use descriptive codenames following naming conventions
|
|
51
|
-
- Group related operations in a single patch request when possible
|
|
52
|
-
- Use proper reference formats (id:{uuid}) in paths
|
|
53
|
-
- Validate element dependencies before adding URL slug elements
|
|
54
|
-
- Consider element ordering when using move operations
|
|
55
|
-
- Use atomic operations for complex changes like removing content groups
|
|
56
|
-
- When adding to allowed_formatting or allowed_table_formatting, always ensure 'unstyled' is the first item in the array`),
|
|
7
|
+
server.tool("patch-content-type-mapi", "Update Kontent.ai content type using JSON Patch (move, addInto, remove, replace)", {
|
|
8
|
+
codename: z.string().describe("Content type codename"),
|
|
9
|
+
operations: patchOperationsSchema.describe("Patch operations array. CRITICAL: Always call get-type-mapi first. Use addInto/remove for arrays, replace for primitives/objects. See context for details."),
|
|
57
10
|
}, async ({ codename, operations }, { authInfo: { token, clientId } = {} }) => {
|
|
58
11
|
const client = createMapiClient(clientId, token);
|
|
59
12
|
try {
|
|
@@ -3,24 +3,21 @@ 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("publish-variant-mapi", "Publish or schedule
|
|
7
|
-
itemId: z
|
|
8
|
-
.string()
|
|
9
|
-
.uuid()
|
|
10
|
-
.describe("Internal ID (UUID) of the content item whose language variant you want to publish or schedule. This identifies the content item container that holds all language variants."),
|
|
6
|
+
server.tool("publish-variant-mapi", "Publish or schedule Kontent.ai variant", {
|
|
7
|
+
itemId: z.string().uuid().describe("Content item UUID"),
|
|
11
8
|
languageId: z
|
|
12
9
|
.string()
|
|
13
10
|
.uuid()
|
|
14
|
-
.describe("
|
|
11
|
+
.describe("Language variant UUID (default: 00000000-0000-0000-0000-000000000000)"),
|
|
15
12
|
scheduledTo: z
|
|
16
13
|
.string()
|
|
17
14
|
.datetime({ offset: true })
|
|
18
15
|
.optional()
|
|
19
|
-
.describe("ISO 8601
|
|
16
|
+
.describe("ISO 8601 datetime for scheduled publish (omit for immediate)"),
|
|
20
17
|
displayTimezone: z
|
|
21
18
|
.string()
|
|
22
19
|
.optional()
|
|
23
|
-
.describe("
|
|
20
|
+
.describe("Timezone for UI display (e.g., America/New_York, UTC)"),
|
|
24
21
|
}, async ({ itemId, languageId, scheduledTo, displayTimezone }, { authInfo: { token, clientId } = {} }) => {
|
|
25
22
|
const client = createMapiClient(clientId, token);
|
|
26
23
|
try {
|
|
@@ -2,7 +2,7 @@ import pRetry, { AbortError } from "p-retry";
|
|
|
2
2
|
import { createMapiClient } from "../clients/kontentClients.js";
|
|
3
3
|
import { searchOperationSchema } from "../schemas/searchOperationSchemas.js";
|
|
4
4
|
import { handleMcpToolError } from "../utils/errorHandler.js";
|
|
5
|
-
import { createMcpToolSuccessResponse } from "../utils/responseHelper.js";
|
|
5
|
+
import { createMcpToolSuccessResponse, createVariantMcpToolSuccessResponse, } from "../utils/responseHelper.js";
|
|
6
6
|
import { throwError } from "../utils/throwError.js";
|
|
7
7
|
class OperationResultIncompleteError extends Error {
|
|
8
8
|
constructor() {
|
|
@@ -11,33 +11,7 @@ class OperationResultIncompleteError extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
export const registerTool = (server) => {
|
|
14
|
-
server.tool("search-variants-mapi",
|
|
15
|
-
|
|
16
|
-
CRITICAL REQUIREMENTS:
|
|
17
|
-
- The AI search feature may not be available for all Kontent.ai environments
|
|
18
|
-
- If you receive an "unavailable" status response, DO NOT attempt to use this tool again in the same session
|
|
19
|
-
- Use filter-variants-mapi for exact text matching when semantic search is unavailable
|
|
20
|
-
- Requires language variant filter parameter (e.g., default language '00000000-0000-0000-0000-000000000000')
|
|
21
|
-
- The tool always RETURNS ONLY TOP 50 most relevant items at max
|
|
22
|
-
- Limited filtering options (only by variant ID) - use filter-variants-mapi for advanced filtering by content types, workflow steps, taxonomies, etc.
|
|
23
|
-
|
|
24
|
-
USE FOR:
|
|
25
|
-
- Finding content WHERE THE OVERALL TOPIC/THEME matches a concept
|
|
26
|
-
✓ Example: "fairy tales" → finds articles primarily about fairy tales
|
|
27
|
-
✓ Example: "beverage temperature control" → finds content focused on keeping drinks cold/hot
|
|
28
|
-
- Content similarity: Finding articles with similar overall themes
|
|
29
|
-
- Thematic content discovery when the main subject matter is what you're looking for
|
|
30
|
-
|
|
31
|
-
DO NOT USE FOR:
|
|
32
|
-
- Finding specific words scattered in otherwise unrelated content
|
|
33
|
-
✗ Example: Finding "challenge" term in articles about various topics (use filter-variants-mapi)
|
|
34
|
-
- Brand guideline violations or prohibited term detection (use filter-variants-mapi)
|
|
35
|
-
- Compliance audits looking for specific keywords (use filter-variants-mapi)
|
|
36
|
-
- Finding exhaustive and exact number of results (use filter-variants-mapi)
|
|
37
|
-
|
|
38
|
-
CRITICAL: This is SEMANTIC search for topic matching. Pass natural language concepts AS-IS. DO NOT generate keyword lists or concatenate multiple keywords.
|
|
39
|
-
✓ CORRECT: "animal predators" or "articles about temperature control"
|
|
40
|
-
✗ WRONG: "animal beast creature wild hunt predator prey attack"`, searchOperationSchema.shape, async ({ searchPhrase, filter }, { authInfo: { token, clientId } = {} }) => {
|
|
14
|
+
server.tool("search-variants-mapi", "AI semantic search for Kontent.ai content by topic/theme (max 50 results). Use filter-variants-mapi for exact keywords. May be unavailable.", searchOperationSchema.shape, async ({ searchPhrase, filter }, { authInfo: { token, clientId } = {} }) => {
|
|
41
15
|
try {
|
|
42
16
|
const environmentId = clientId ?? process.env.KONTENT_ENVIRONMENT_ID;
|
|
43
17
|
if (!environmentId) {
|
|
@@ -110,7 +84,7 @@ export const registerTool = (server) => {
|
|
|
110
84
|
maxTimeout: 10000,
|
|
111
85
|
factor: 1.5,
|
|
112
86
|
});
|
|
113
|
-
return
|
|
87
|
+
return createVariantMcpToolSuccessResponse({
|
|
114
88
|
result: resultData,
|
|
115
89
|
});
|
|
116
90
|
}
|
|
@@ -3,24 +3,21 @@ 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("unpublish-variant-mapi", "Unpublish or schedule unpublishing of
|
|
7
|
-
itemId: z
|
|
8
|
-
.string()
|
|
9
|
-
.uuid()
|
|
10
|
-
.describe("Internal ID (UUID) of the content item whose language variant you want to unpublish or schedule for unpublishing. This identifies the content item container that holds all language variants."),
|
|
6
|
+
server.tool("unpublish-variant-mapi", "Unpublish or schedule unpublishing of Kontent.ai variant", {
|
|
7
|
+
itemId: z.string().uuid().describe("Content item UUID"),
|
|
11
8
|
languageId: z
|
|
12
9
|
.string()
|
|
13
10
|
.uuid()
|
|
14
|
-
.describe("
|
|
11
|
+
.describe("Language variant UUID (default: 00000000-0000-0000-0000-000000000000)"),
|
|
15
12
|
scheduledTo: z
|
|
16
13
|
.string()
|
|
17
14
|
.datetime({ offset: true })
|
|
18
15
|
.optional()
|
|
19
|
-
.describe("ISO 8601
|
|
16
|
+
.describe("ISO 8601 datetime for scheduled unpublish (omit for immediate)"),
|
|
20
17
|
displayTimezone: z
|
|
21
18
|
.string()
|
|
22
19
|
.optional()
|
|
23
|
-
.describe("
|
|
20
|
+
.describe("Timezone for UI display (e.g., America/New_York, UTC)"),
|
|
24
21
|
}, async ({ itemId, languageId, scheduledTo, displayTimezone }, { authInfo: { token, clientId } = {} }) => {
|
|
25
22
|
const client = createMapiClient(clientId, token);
|
|
26
23
|
try {
|