@kontent-ai/mcp-server 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -25
- package/build/clients/kontentClients.js +9 -0
- package/build/schemas/contentTypeSchemas.js +139 -211
- package/build/schemas/taxonomySchemas.js +15 -0
- package/build/server.js +10 -0
- package/build/tools/add-taxonomy-group-mapi.js +19 -0
- package/build/tools/get-taxonomy-group-mapi.js +21 -0
- package/build/tools/get-type-snippet-mapi.js +21 -0
- package/build/tools/list-content-type-snippets-mapi.js +17 -0
- package/build/tools/list-taxonomy-groups-mapi.js +17 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -5,9 +5,9 @@ This server provides a Model Context Protocol (MCP) interface for interacting wi
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- Retrieve content items, variants, and assets
|
|
8
|
-
- Get content types and their structure
|
|
9
8
|
- List available languages and assets
|
|
10
|
-
- Create
|
|
9
|
+
- Get, List, and Create content types and snippets
|
|
10
|
+
- Get, List, and Create taxonomies
|
|
11
11
|
|
|
12
12
|
## Getting Started
|
|
13
13
|
|
|
@@ -16,41 +16,53 @@ This server provides a Model Context Protocol (MCP) interface for interacting wi
|
|
|
16
16
|
- Node.js (version specified in `.nvmrc`)
|
|
17
17
|
- Kontent.ai account with API keys
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### Running
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
You can run this server with either stdio or sse transport.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
### Stdio transport
|
|
24
|
+
|
|
25
|
+
To run the server with stdio transport configure your MCP client with the command to run and the necessary environment variables.
|
|
26
|
+
Example:
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"kontent-ai-stdio": {
|
|
30
|
+
"command": "npx @kontent-ai/mcp-server@latest stdio",
|
|
31
|
+
"env": {
|
|
32
|
+
"KONTENT_API_KEY": "<management-api-key>",
|
|
33
|
+
"KONTENT_ENVIRONMENT_ID": "<environment-id>"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
26
37
|
```
|
|
27
38
|
|
|
28
|
-
###
|
|
39
|
+
### SSE transport
|
|
29
40
|
|
|
30
|
-
You can run
|
|
41
|
+
You can also run your server manually with the SSE transport and configure your MCP client to connect to the port the server is running on.
|
|
42
|
+
Run the following command to start the server and ensure the environment variables are defined for it either by providing `.env` file in the `cwd` or providing the variables to the process any other way.
|
|
31
43
|
|
|
32
44
|
```bash
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
npx @kontent-ai/mcp-server@latest sse
|
|
46
|
+
```
|
|
47
|
+
```env
|
|
48
|
+
KONTENT_API_KEY=<management-api-key>
|
|
49
|
+
KONTENT_ENVIRONMENT_ID=<environment-id>
|
|
50
|
+
PORT=<port-number> # optionally specify port, defaults to 3001
|
|
38
51
|
```
|
|
39
52
|
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
Then configure your MCP client to connect to the running server.
|
|
54
|
+
Example:
|
|
42
55
|
```json
|
|
43
56
|
{
|
|
44
|
-
"kontent-ai-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"KONTENT_API_KEY": "<management-api-key>",
|
|
48
|
-
"KONTENT_ENVIRONMENT_ID": "<environment-id>"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
57
|
+
"kontent-ai-sse": {
|
|
58
|
+
"url": "http://localhost:3001/sse"
|
|
59
|
+
}
|
|
51
60
|
}
|
|
52
61
|
```
|
|
53
62
|
|
|
63
|
+
|
|
64
|
+
## Development
|
|
65
|
+
|
|
54
66
|
### Local Installation
|
|
55
67
|
|
|
56
68
|
```bash
|
|
@@ -69,8 +81,6 @@ npm run start:sse # For SSE transport
|
|
|
69
81
|
npm run start:stdio # For STDIO transport
|
|
70
82
|
```
|
|
71
83
|
|
|
72
|
-
## Development
|
|
73
|
-
|
|
74
84
|
### Available Scripts
|
|
75
85
|
|
|
76
86
|
- `npm run build` - Compile TypeScript to JavaScript
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { createManagementClient } from '@kontent-ai/management-sdk';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const packageJsonPath = join(import.meta.dirname, '../../package.json');
|
|
5
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
6
|
+
const sourceTrackingHeaderName = 'X-KC-SOURCE';
|
|
2
7
|
/**
|
|
3
8
|
* Creates a Kontent.ai Management API client
|
|
4
9
|
* @param environmentId Optional environment ID (defaults to process.env.KONTENT_ENVIRONMENT_ID)
|
|
@@ -9,6 +14,10 @@ export const createMapiClient = (environmentId, apiKey) => {
|
|
|
9
14
|
return createManagementClient({
|
|
10
15
|
apiKey: apiKey ?? process.env.KONTENT_API_KEY ?? throwError("KONTENT_API_KEY is not set"),
|
|
11
16
|
environmentId: environmentId ?? process.env.KONTENT_ENVIRONMENT_ID ?? throwError("KONTENT_ENVIRONMENT_ID is not set"),
|
|
17
|
+
headers: [{
|
|
18
|
+
header: sourceTrackingHeaderName,
|
|
19
|
+
value: `${packageJson.name};${packageJson.version}`,
|
|
20
|
+
}],
|
|
12
21
|
});
|
|
13
22
|
};
|
|
14
23
|
const throwError = (message) => {
|
|
@@ -8,7 +8,9 @@ const referenceObjectSchema = z.object({
|
|
|
8
8
|
const baseElementSchema = {
|
|
9
9
|
codename: z.string().optional(),
|
|
10
10
|
external_id: z.string().optional(),
|
|
11
|
-
content_group: referenceObjectSchema
|
|
11
|
+
content_group: referenceObjectSchema
|
|
12
|
+
.describe("An object with an id or codename property referencing a content group.")
|
|
13
|
+
.optional(),
|
|
12
14
|
};
|
|
13
15
|
const namedElementSchema = {
|
|
14
16
|
...baseElementSchema,
|
|
@@ -61,120 +63,131 @@ const textLengthLimitSchema = z.object({
|
|
|
61
63
|
value: z.number(),
|
|
62
64
|
applies_to: z.enum(['words', 'characters'])
|
|
63
65
|
}).optional();
|
|
66
|
+
// Individual element type schemas
|
|
67
|
+
const assetElementSchema = z.object({
|
|
68
|
+
type: z.literal('asset'),
|
|
69
|
+
...namedElementSchema,
|
|
70
|
+
asset_count_limit: countLimitSchema,
|
|
71
|
+
maximum_file_size: z.number().optional(),
|
|
72
|
+
allowed_file_types: z.enum(['adjustable', 'any']).optional(),
|
|
73
|
+
...imageLimitSchema,
|
|
74
|
+
default: arrayDefaultSchema(),
|
|
75
|
+
});
|
|
76
|
+
const customElementSchema = z.object({
|
|
77
|
+
type: z.literal('custom'),
|
|
78
|
+
...namedElementSchema,
|
|
79
|
+
source_url: z.string(),
|
|
80
|
+
json_parameters: z.string().optional(),
|
|
81
|
+
allowed_elements: z.array(referenceObjectSchema
|
|
82
|
+
.describe("An object with an id or codename property referencing an element.")).optional(),
|
|
83
|
+
});
|
|
84
|
+
const dateTimeElementSchema = z.object({
|
|
85
|
+
type: z.literal('date_time'),
|
|
86
|
+
...namedElementSchema,
|
|
87
|
+
default: stringDefaultSchema,
|
|
88
|
+
});
|
|
89
|
+
const guidelinesElementSchema = z.object({
|
|
90
|
+
type: z.literal('guidelines'),
|
|
91
|
+
guidelines: z.string(),
|
|
92
|
+
...baseElementSchema,
|
|
93
|
+
});
|
|
94
|
+
const modularContentElementSchema = z.object({
|
|
95
|
+
type: z.literal('modular_content'),
|
|
96
|
+
...namedElementSchema,
|
|
97
|
+
allowed_content_types: z.array(referenceObjectSchema
|
|
98
|
+
.describe("An object with an id or codename property referencing a content type.")).optional(),
|
|
99
|
+
item_count_limit: countLimitSchema,
|
|
100
|
+
default: arrayDefaultSchema(),
|
|
101
|
+
});
|
|
102
|
+
const subpagesElementSchema = z.object({
|
|
103
|
+
type: z.literal('subpages'),
|
|
104
|
+
...namedElementSchema,
|
|
105
|
+
allowed_content_types: z.array(referenceObjectSchema
|
|
106
|
+
.describe("An object with an id or codename property referencing a content type.")).optional(),
|
|
107
|
+
item_count_limit: countLimitSchema,
|
|
108
|
+
});
|
|
109
|
+
const multipleChoiceElementSchema = z.object({
|
|
110
|
+
type: z.literal('multiple_choice'),
|
|
111
|
+
...namedElementSchema,
|
|
112
|
+
mode: z.enum(['single', 'multiple']),
|
|
113
|
+
options: z.array(z.object({
|
|
114
|
+
name: z.string(),
|
|
115
|
+
codename: z.string().optional(),
|
|
116
|
+
external_id: z.string().optional(),
|
|
117
|
+
})),
|
|
118
|
+
default: arrayDefaultSchema(),
|
|
119
|
+
});
|
|
120
|
+
const numberElementSchema = z.object({
|
|
121
|
+
type: z.literal('number'),
|
|
122
|
+
...namedElementSchema,
|
|
123
|
+
default: numberDefaultSchema,
|
|
124
|
+
});
|
|
125
|
+
const richTextElementSchema = z.object({
|
|
126
|
+
type: z.literal('rich_text'),
|
|
127
|
+
...namedElementSchema,
|
|
128
|
+
allowed_blocks: z.array(z.enum(['images', 'text', 'tables', 'components-and-items'])).optional(),
|
|
129
|
+
allowed_formatting: z.array(z.enum(['unstyled', 'bold', 'italic', 'code', 'link', 'subscript', 'superscript'])).optional(),
|
|
130
|
+
allowed_text_blocks: z.array(z.enum(['paragraph', 'heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six', 'ordered-list', 'unordered-list'])).optional(),
|
|
131
|
+
allowed_table_blocks: z.array(z.enum(['images', 'text'])).optional(),
|
|
132
|
+
allowed_table_formatting: z.array(z.enum(['unstyled', 'bold', 'italic', 'code', 'link', 'subscript', 'superscript'])).optional(),
|
|
133
|
+
allowed_table_text_blocks: z.array(z.enum(['paragraph', 'heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six', 'ordered-list', 'unordered-list'])).optional(),
|
|
134
|
+
allowed_content_types: z.array(referenceObjectSchema
|
|
135
|
+
.describe("An object with an id or codename property referencing a content type.")).optional(),
|
|
136
|
+
allowed_item_link_types: z.array(referenceObjectSchema
|
|
137
|
+
.describe("An object with an id or codename property referencing a content type.")).optional(),
|
|
138
|
+
...imageLimitSchema,
|
|
139
|
+
allowed_image_types: z.enum(['adjustable', 'any']).optional(),
|
|
140
|
+
maximum_image_size: z.number().optional(),
|
|
141
|
+
maximum_text_length: textLengthLimitSchema,
|
|
142
|
+
});
|
|
143
|
+
const snippetElement = z.object({
|
|
144
|
+
type: z.literal('snippet'),
|
|
145
|
+
snippet: referenceObjectSchema
|
|
146
|
+
.describe("An object with an id or codename property referencing a snippet."),
|
|
147
|
+
...baseElementSchema,
|
|
148
|
+
});
|
|
149
|
+
const taxonomyElementSchema = z.object({
|
|
150
|
+
type: z.literal('taxonomy'),
|
|
151
|
+
taxonomy_group: referenceObjectSchema
|
|
152
|
+
.describe("An object with an id or codename property referencing a taxonomy group."),
|
|
153
|
+
...namedElementSchema,
|
|
154
|
+
term_count_limit: countLimitSchema,
|
|
155
|
+
default: arrayDefaultSchema(),
|
|
156
|
+
});
|
|
157
|
+
const textElementSchema = z.object({
|
|
158
|
+
type: z.literal('text'),
|
|
159
|
+
...namedElementSchema,
|
|
160
|
+
maximum_text_length: textLengthLimitSchema,
|
|
161
|
+
validation_regex: regexValidationSchema,
|
|
162
|
+
default: stringDefaultSchema,
|
|
163
|
+
});
|
|
164
|
+
const urlSlugElementSchema = z.object({
|
|
165
|
+
type: z.literal('url_slug'),
|
|
166
|
+
...namedElementSchema,
|
|
167
|
+
depends_on: z.object({
|
|
168
|
+
element: referenceObjectSchema
|
|
169
|
+
.describe("An object with an id or codename property referencing an element."),
|
|
170
|
+
snippet: referenceObjectSchema
|
|
171
|
+
.describe("An object with an id or codename property referencing a content type snippet.")
|
|
172
|
+
.optional(),
|
|
173
|
+
}),
|
|
174
|
+
validation_regex: regexValidationSchema,
|
|
175
|
+
});
|
|
64
176
|
// Define a union type of all possible element types for content types
|
|
65
|
-
export const elementSchema = z.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
...namedElementSchema,
|
|
80
|
-
source_url: z.string(),
|
|
81
|
-
json_parameters: z.string().optional(),
|
|
82
|
-
allowed_elements: z.array(referenceObjectSchema).optional(),
|
|
83
|
-
}),
|
|
84
|
-
// Date time element
|
|
85
|
-
z.object({
|
|
86
|
-
type: z.literal('date_time'),
|
|
87
|
-
...namedElementSchema,
|
|
88
|
-
default: stringDefaultSchema,
|
|
89
|
-
}),
|
|
90
|
-
// Guidelines element
|
|
91
|
-
z.object({
|
|
92
|
-
type: z.literal('guidelines'),
|
|
93
|
-
guidelines: z.string(),
|
|
94
|
-
...baseElementSchema,
|
|
95
|
-
}),
|
|
96
|
-
// Linked items (modular content) element
|
|
97
|
-
z.object({
|
|
98
|
-
type: z.literal('modular_content'),
|
|
99
|
-
...namedElementSchema,
|
|
100
|
-
allowed_content_types: z.array(referenceObjectSchema).optional(),
|
|
101
|
-
item_count_limit: countLimitSchema,
|
|
102
|
-
default: arrayDefaultSchema(),
|
|
103
|
-
}),
|
|
104
|
-
// Subpages element
|
|
105
|
-
z.object({
|
|
106
|
-
type: z.literal('subpages'),
|
|
107
|
-
...namedElementSchema,
|
|
108
|
-
allowed_content_types: z.array(referenceObjectSchema).optional(),
|
|
109
|
-
item_count_limit: countLimitSchema,
|
|
110
|
-
}),
|
|
111
|
-
// Multiple choice element
|
|
112
|
-
z.object({
|
|
113
|
-
type: z.literal('multiple_choice'),
|
|
114
|
-
...namedElementSchema,
|
|
115
|
-
mode: z.enum(['single', 'multiple']),
|
|
116
|
-
options: z.array(z.object({
|
|
117
|
-
name: z.string(),
|
|
118
|
-
codename: z.string().optional(),
|
|
119
|
-
external_id: z.string().optional(),
|
|
120
|
-
})),
|
|
121
|
-
default: arrayDefaultSchema(),
|
|
122
|
-
}),
|
|
123
|
-
// Number element
|
|
124
|
-
z.object({
|
|
125
|
-
type: z.literal('number'),
|
|
126
|
-
...namedElementSchema,
|
|
127
|
-
default: numberDefaultSchema,
|
|
128
|
-
}),
|
|
129
|
-
// Rich text element
|
|
130
|
-
z.object({
|
|
131
|
-
type: z.literal('rich_text'),
|
|
132
|
-
...namedElementSchema,
|
|
133
|
-
allowed_blocks: z.array(z.enum(['images', 'text', 'tables', 'components-and-items'])).optional(),
|
|
134
|
-
allowed_formatting: z.array(z.enum(['unstyled', 'bold', 'italic', 'code', 'link', 'subscript', 'superscript'])).optional(),
|
|
135
|
-
allowed_text_blocks: z.array(z.enum(['paragraph', 'heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six', 'ordered-list', 'unordered-list'])).optional(),
|
|
136
|
-
allowed_table_blocks: z.array(z.enum(['images', 'text'])).optional(),
|
|
137
|
-
allowed_table_formatting: z.array(z.enum(['unstyled', 'bold', 'italic', 'code', 'link', 'subscript', 'superscript'])).optional(),
|
|
138
|
-
allowed_table_text_blocks: z.array(z.enum(['paragraph', 'heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six', 'ordered-list', 'unordered-list'])).optional(),
|
|
139
|
-
allowed_content_types: z.array(referenceObjectSchema).optional(),
|
|
140
|
-
allowed_item_link_types: z.array(referenceObjectSchema).optional(),
|
|
141
|
-
...imageLimitSchema,
|
|
142
|
-
allowed_image_types: z.enum(['adjustable', 'any']).optional(),
|
|
143
|
-
maximum_image_size: z.number().optional(),
|
|
144
|
-
maximum_text_length: textLengthLimitSchema,
|
|
145
|
-
}),
|
|
146
|
-
// Snippet element
|
|
147
|
-
z.object({
|
|
148
|
-
type: z.literal('snippet'),
|
|
149
|
-
snippet: referenceObjectSchema,
|
|
150
|
-
...baseElementSchema,
|
|
151
|
-
}),
|
|
152
|
-
// Taxonomy element
|
|
153
|
-
z.object({
|
|
154
|
-
type: z.literal('taxonomy'),
|
|
155
|
-
taxonomy_group: referenceObjectSchema,
|
|
156
|
-
...namedElementSchema,
|
|
157
|
-
term_count_limit: countLimitSchema,
|
|
158
|
-
default: arrayDefaultSchema(),
|
|
159
|
-
}),
|
|
160
|
-
// Text element
|
|
161
|
-
z.object({
|
|
162
|
-
type: z.literal('text'),
|
|
163
|
-
...namedElementSchema,
|
|
164
|
-
maximum_text_length: textLengthLimitSchema,
|
|
165
|
-
validation_regex: regexValidationSchema,
|
|
166
|
-
default: stringDefaultSchema,
|
|
167
|
-
}),
|
|
168
|
-
// URL slug element
|
|
169
|
-
z.object({
|
|
170
|
-
type: z.literal('url_slug'),
|
|
171
|
-
...namedElementSchema,
|
|
172
|
-
depends_on: z.object({
|
|
173
|
-
element: referenceObjectSchema,
|
|
174
|
-
snippet: referenceObjectSchema.optional(),
|
|
175
|
-
}),
|
|
176
|
-
validation_regex: regexValidationSchema,
|
|
177
|
-
}),
|
|
177
|
+
export const elementSchema = z.discriminatedUnion('type', [
|
|
178
|
+
assetElementSchema,
|
|
179
|
+
customElementSchema,
|
|
180
|
+
dateTimeElementSchema,
|
|
181
|
+
guidelinesElementSchema,
|
|
182
|
+
modularContentElementSchema,
|
|
183
|
+
subpagesElementSchema,
|
|
184
|
+
multipleChoiceElementSchema,
|
|
185
|
+
numberElementSchema,
|
|
186
|
+
richTextElementSchema,
|
|
187
|
+
snippetElement,
|
|
188
|
+
taxonomyElementSchema,
|
|
189
|
+
textElementSchema,
|
|
190
|
+
urlSlugElementSchema,
|
|
178
191
|
]);
|
|
179
192
|
// Define schema for content groups
|
|
180
193
|
export const contentGroupSchema = z.object({
|
|
@@ -183,101 +196,16 @@ export const contentGroupSchema = z.object({
|
|
|
183
196
|
codename: z.string().optional(),
|
|
184
197
|
});
|
|
185
198
|
// Define a union type for snippet elements (excluding url_slug and snippet elements)
|
|
186
|
-
export const snippetElementSchema = z.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
z.object({
|
|
199
|
-
type: z.literal('custom'),
|
|
200
|
-
...namedElementSchema,
|
|
201
|
-
source_url: z.string(),
|
|
202
|
-
json_parameters: z.string().optional(),
|
|
203
|
-
allowed_elements: z.array(referenceObjectSchema).optional(),
|
|
204
|
-
}),
|
|
205
|
-
// Date time element
|
|
206
|
-
z.object({
|
|
207
|
-
type: z.literal('date_time'),
|
|
208
|
-
...namedElementSchema,
|
|
209
|
-
default: stringDefaultSchema,
|
|
210
|
-
}),
|
|
211
|
-
// Guidelines element
|
|
212
|
-
z.object({
|
|
213
|
-
type: z.literal('guidelines'),
|
|
214
|
-
guidelines: z.string(),
|
|
215
|
-
...baseElementSchema,
|
|
216
|
-
}),
|
|
217
|
-
// Linked items (modular content) element
|
|
218
|
-
z.object({
|
|
219
|
-
type: z.literal('modular_content'),
|
|
220
|
-
...namedElementSchema,
|
|
221
|
-
allowed_content_types: z.array(referenceObjectSchema).optional(),
|
|
222
|
-
item_count_limit: countLimitSchema,
|
|
223
|
-
default: arrayDefaultSchema(),
|
|
224
|
-
}),
|
|
225
|
-
// Subpages element
|
|
226
|
-
z.object({
|
|
227
|
-
type: z.literal('subpages'),
|
|
228
|
-
...namedElementSchema,
|
|
229
|
-
allowed_content_types: z.array(referenceObjectSchema).optional(),
|
|
230
|
-
item_count_limit: countLimitSchema,
|
|
231
|
-
}),
|
|
232
|
-
// Multiple choice element
|
|
233
|
-
z.object({
|
|
234
|
-
type: z.literal('multiple_choice'),
|
|
235
|
-
...namedElementSchema,
|
|
236
|
-
mode: z.enum(['single', 'multiple']),
|
|
237
|
-
options: z.array(z.object({
|
|
238
|
-
name: z.string(),
|
|
239
|
-
codename: z.string().optional(),
|
|
240
|
-
external_id: z.string().optional(),
|
|
241
|
-
})),
|
|
242
|
-
default: arrayDefaultSchema(),
|
|
243
|
-
}),
|
|
244
|
-
// Number element
|
|
245
|
-
z.object({
|
|
246
|
-
type: z.literal('number'),
|
|
247
|
-
...namedElementSchema,
|
|
248
|
-
default: numberDefaultSchema,
|
|
249
|
-
}),
|
|
250
|
-
// Rich text element
|
|
251
|
-
z.object({
|
|
252
|
-
type: z.literal('rich_text'),
|
|
253
|
-
...namedElementSchema,
|
|
254
|
-
allowed_blocks: z.array(z.enum(['images', 'text', 'tables', 'components-and-items'])).optional(),
|
|
255
|
-
allowed_formatting: z.array(z.enum(['unstyled', 'bold', 'italic', 'code', 'link', 'subscript', 'superscript'])).optional(),
|
|
256
|
-
allowed_text_blocks: z.array(z.enum(['paragraph', 'heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six', 'ordered-list', 'unordered-list'])).optional(),
|
|
257
|
-
allowed_table_blocks: z.array(z.enum(['images', 'text'])).optional(),
|
|
258
|
-
allowed_table_formatting: z.array(z.enum(['unstyled', 'bold', 'italic', 'code', 'link', 'subscript', 'superscript'])).optional(),
|
|
259
|
-
allowed_table_text_blocks: z.array(z.enum(['paragraph', 'heading-one', 'heading-two', 'heading-three', 'heading-four', 'heading-five', 'heading-six', 'ordered-list', 'unordered-list'])).optional(),
|
|
260
|
-
allowed_content_types: z.array(referenceObjectSchema).optional(),
|
|
261
|
-
allowed_item_link_types: z.array(referenceObjectSchema).optional(),
|
|
262
|
-
...imageLimitSchema,
|
|
263
|
-
allowed_image_types: z.enum(['adjustable', 'any']).optional(),
|
|
264
|
-
maximum_image_size: z.number().optional(),
|
|
265
|
-
maximum_text_length: textLengthLimitSchema,
|
|
266
|
-
}),
|
|
267
|
-
// Taxonomy element
|
|
268
|
-
z.object({
|
|
269
|
-
type: z.literal('taxonomy'),
|
|
270
|
-
taxonomy_group: referenceObjectSchema,
|
|
271
|
-
...namedElementSchema,
|
|
272
|
-
term_count_limit: countLimitSchema,
|
|
273
|
-
default: arrayDefaultSchema(),
|
|
274
|
-
}),
|
|
275
|
-
// Text element
|
|
276
|
-
z.object({
|
|
277
|
-
type: z.literal('text'),
|
|
278
|
-
...namedElementSchema,
|
|
279
|
-
maximum_text_length: textLengthLimitSchema,
|
|
280
|
-
validation_regex: regexValidationSchema,
|
|
281
|
-
default: stringDefaultSchema,
|
|
282
|
-
}),
|
|
199
|
+
export const snippetElementSchema = z.discriminatedUnion('type', [
|
|
200
|
+
assetElementSchema,
|
|
201
|
+
customElementSchema,
|
|
202
|
+
dateTimeElementSchema,
|
|
203
|
+
guidelinesElementSchema,
|
|
204
|
+
modularContentElementSchema,
|
|
205
|
+
subpagesElementSchema,
|
|
206
|
+
multipleChoiceElementSchema,
|
|
207
|
+
numberElementSchema,
|
|
208
|
+
richTextElementSchema,
|
|
209
|
+
taxonomyElementSchema,
|
|
210
|
+
textElementSchema,
|
|
283
211
|
]);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Schema for a taxonomy term
|
|
3
|
+
const taxonomyTermSchema = z.object({
|
|
4
|
+
name: z.string(),
|
|
5
|
+
codename: z.string().optional(),
|
|
6
|
+
external_id: z.string().optional(),
|
|
7
|
+
terms: z.lazy(() => z.array(taxonomyTermSchema)),
|
|
8
|
+
});
|
|
9
|
+
// Schema for a taxonomy group
|
|
10
|
+
export const taxonomyGroupSchemas = {
|
|
11
|
+
name: z.string().describe("Display name of the taxonomy group"),
|
|
12
|
+
codename: z.string().optional().describe("Codename of the taxonomy group (optional, will be generated if not provided)"),
|
|
13
|
+
external_id: z.string().optional().describe("External ID of the taxonomy group (optional)"),
|
|
14
|
+
terms: z.array(taxonomyTermSchema).describe("Hierarchical structure of taxonomy terms"),
|
|
15
|
+
};
|
package/build/server.js
CHANGED
|
@@ -9,6 +9,11 @@ import { registerTool as registerGetAssetMapi } from "./tools/get-asset-mapi.js"
|
|
|
9
9
|
import { registerTool as registerListAssetsMapi } from "./tools/list-assets-mapi.js";
|
|
10
10
|
import { registerTool as registerAddContentTypeMapi } from "./tools/add-content-type-mapi.js";
|
|
11
11
|
import { registerTool as registerAddContentTypeSnippetMapi } from "./tools/add-content-type-snippet-mapi.js";
|
|
12
|
+
import { registerTool as registerGetTypeSnippetMapi } from "./tools/get-type-snippet-mapi.js";
|
|
13
|
+
import { registerTool as registerListContentTypeSnippetsMapi } from "./tools/list-content-type-snippets-mapi.js";
|
|
14
|
+
import { registerTool as registerAddTaxonomyGroupMapi } from "./tools/add-taxonomy-group-mapi.js";
|
|
15
|
+
import { registerTool as registerListTaxonomyGroupsMapi } from "./tools/list-taxonomy-groups-mapi.js";
|
|
16
|
+
import { registerTool as registerGetTaxonomyGroupMapi } from "./tools/get-taxonomy-group-mapi.js";
|
|
12
17
|
// Create server instance
|
|
13
18
|
export const createServer = () => {
|
|
14
19
|
const server = new McpServer({
|
|
@@ -30,5 +35,10 @@ export const createServer = () => {
|
|
|
30
35
|
registerListAssetsMapi(server);
|
|
31
36
|
registerAddContentTypeMapi(server);
|
|
32
37
|
registerAddContentTypeSnippetMapi(server);
|
|
38
|
+
registerGetTypeSnippetMapi(server);
|
|
39
|
+
registerListContentTypeSnippetsMapi(server);
|
|
40
|
+
registerAddTaxonomyGroupMapi(server);
|
|
41
|
+
registerListTaxonomyGroupsMapi(server);
|
|
42
|
+
registerGetTaxonomyGroupMapi(server);
|
|
33
43
|
return { server };
|
|
34
44
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createMapiClient } from '../clients/kontentClients.js';
|
|
2
|
+
import { taxonomyGroupSchemas } from '../schemas/taxonomySchemas.js';
|
|
3
|
+
export const registerTool = (server) => {
|
|
4
|
+
server.tool("add-taxonomy-group-mapi", "Add a new taxonomy group via Management API", taxonomyGroupSchemas, async (taxonomyGroup) => {
|
|
5
|
+
const client = createMapiClient();
|
|
6
|
+
const response = await client
|
|
7
|
+
.addTaxonomy()
|
|
8
|
+
.withData(taxonomyGroup)
|
|
9
|
+
.toPromise();
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: JSON.stringify(response.data),
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from '../clients/kontentClients.js';
|
|
3
|
+
export const registerTool = (server) => {
|
|
4
|
+
server.tool("get-taxonomy-group-mapi", "Get taxonomy group by codename from Management API", {
|
|
5
|
+
codename: z.string().describe("Codename of the taxonomy group to get")
|
|
6
|
+
}, async ({ codename }) => {
|
|
7
|
+
const client = createMapiClient();
|
|
8
|
+
const response = await client
|
|
9
|
+
.getTaxonomy()
|
|
10
|
+
.byTaxonomyCodename(codename)
|
|
11
|
+
.toPromise();
|
|
12
|
+
return {
|
|
13
|
+
content: [
|
|
14
|
+
{
|
|
15
|
+
type: "text",
|
|
16
|
+
text: JSON.stringify(response.data),
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from '../clients/kontentClients.js';
|
|
3
|
+
export const registerTool = (server) => {
|
|
4
|
+
server.tool("get-type-snippet-mapi", "Get content type snippet by codename from Management API", {
|
|
5
|
+
codename: z.string().describe("Codename of the content type snippet to get")
|
|
6
|
+
}, async ({ codename }) => {
|
|
7
|
+
const client = createMapiClient();
|
|
8
|
+
const response = await client
|
|
9
|
+
.viewContentTypeSnippet()
|
|
10
|
+
.byTypeCodename(codename)
|
|
11
|
+
.toPromise();
|
|
12
|
+
return {
|
|
13
|
+
content: [
|
|
14
|
+
{
|
|
15
|
+
type: "text",
|
|
16
|
+
text: JSON.stringify(response.data),
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createMapiClient } from '../clients/kontentClients.js';
|
|
2
|
+
export const registerTool = (server) => {
|
|
3
|
+
server.tool("list-content-type-snippets-mapi", "Get all content type snippets from Management API", {}, async () => {
|
|
4
|
+
const client = createMapiClient();
|
|
5
|
+
const response = await client
|
|
6
|
+
.listContentTypeSnippets()
|
|
7
|
+
.toAllPromise();
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
text: JSON.stringify(response.data),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createMapiClient } from '../clients/kontentClients.js';
|
|
2
|
+
export const registerTool = (server) => {
|
|
3
|
+
server.tool("list-taxonomy-groups-mapi", "Get all taxonomy groups from Management API", {}, async () => {
|
|
4
|
+
const client = createMapiClient();
|
|
5
|
+
const response = await client
|
|
6
|
+
.listTaxonomies()
|
|
7
|
+
.toPromise();
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
text: JSON.stringify(response.data),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kontent-ai/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc",
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
"author": "Jiri Lojda",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@kontent-ai/delivery-sdk": "^16.
|
|
20
|
+
"@kontent-ai/delivery-sdk": "^16.2.0",
|
|
21
21
|
"@kontent-ai/management-sdk": "^7.9.0",
|
|
22
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
22
|
+
"@modelcontextprotocol/sdk": "^1.11.4",
|
|
23
23
|
"dotenv": "^16.5.0",
|
|
24
24
|
"express": "^5.1.0",
|
|
25
|
-
"zod": "^3.
|
|
25
|
+
"zod": "^3.25.7"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@types/express": "^5.0.
|
|
29
|
-
"@types/node": "^22.
|
|
28
|
+
"@types/express": "^5.0.2",
|
|
29
|
+
"@types/node": "^22.15.19",
|
|
30
30
|
"typescript": "^5.8.3"
|
|
31
31
|
}
|
|
32
32
|
}
|