@kentico/management-api-mcp 30.12.3-preview → 31.0.0-preview

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.
Files changed (3) hide show
  1. package/README.md +57 -7
  2. package/dist/index.js +59 -53
  3. package/package.json +53 -28
package/README.md CHANGED
@@ -1,12 +1,62 @@
1
- # Xperience by Kentico - Management API MCP server
1
+ # Xperience by Kentico ManagementApiMcp
2
2
 
3
- This package provides a Model Context Protocol (MCP) server that allows AI tools to work with the Xperience by Kentico management API. Currently, the management API allows interaction with content types and reusable field schemas.
3
+ Model Context Protocol (MCP) server for managing data in Xperience by Kentico.
4
4
 
5
- ## Documentation
5
+ ## Development
6
6
 
7
- For setup instructions and usage guidelines, refer to the official Xperience by Kentico documentation:
8
- [Content type management API](https://docs.kentico.com/x/management_api_xp)
7
+ To develop the ManagementApiMcp
9
8
 
10
- ## License
9
+ 1. Run the `npm install` to install packages
10
+ 2. Run the `npm run dev` to start watcher that will rebuild the mcp on any change.
11
11
 
12
- See LICENSE.txt for license information.
12
+ To run the development Management API MCP in cursor/vscode/etc:
13
+ 1. Run `npm run dev` or `npm run build` at least once
14
+ 2. Add Kentico.Xperience.ManagementApi integration package to the DancingGoat and call `AddKenticoManagementApi()` / `UseKenticoManagementApi()`. Specify 32char length secret.
15
+ 3. Run the DancingGoat
16
+ 4. Update the `./mcp-config.json` to include correct secret and run `npm run debug`.
17
+ 5. Otherwise, you can add the following config to vscode/cursor/etc.:
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "xperience": {
23
+ "type": "stdio",
24
+ "command": "node",
25
+ "args": ["C:\\CMS\\XbK\\CMSSolution\\Integrations\\Kentico.Xperience.ManagementApiMcp\\dist\\index.js"],
26
+ "env": {
27
+ "NODE_OPTIONS": "--use-system-ca",
28
+ "CACHE_OPENAPI": "false",
29
+ "MANAGEMENT_API_URL": "https://localhost:5001/kentico-api/management",
30
+ "MANAGEMENT_API_SECRET": "<your-32+char-secret>"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ Or prettier one if you execute `npm link`:
38
+
39
+ ```json
40
+ {
41
+ "mcpServers": {
42
+ "xperience": {
43
+ "type": "stdio",
44
+ "command": "xperience-mcp",
45
+ "env": {
46
+ "NODE_OPTIONS": "--use-system-ca",
47
+ "CACHE_OPENAPI": "false",
48
+ "MANAGEMENT_API_URL": "https://localhost:5001/kentico-api/management",
49
+ "MANAGEMENT_API_SECRET": "<your-32+char-secret>"
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Custom environment variables
57
+
58
+ The following environment variables are used:
59
+
60
+ - `MANAGEMENT_API_URL` - path to the Management API endpoint
61
+ - `MANAGEMENT_API_SECRET` - required, secret used for Authorization header when calling the Management API (must be at least 32 characters)
62
+ - `CACHE_OPENAPI` - optional, can disable caching of OpenAPI spec for development purposes.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node --use-system-ca
1
+ #!/usr/bin/env node
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -12525,7 +12525,6 @@ function $constructor(name, initializer3, params) {
12525
12525
  Object.defineProperty(_, "name", { value: name });
12526
12526
  return _;
12527
12527
  }
12528
- var $brand = Symbol("zod_brand");
12529
12528
  var $ZodAsyncError = class extends Error {
12530
12529
  constructor() {
12531
12530
  super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
@@ -15029,8 +15028,6 @@ function en_default() {
15029
15028
  }
15030
15029
 
15031
15030
  // node_modules/zod/v4/core/registries.js
15032
- var $output = Symbol("ZodOutput");
15033
- var $input = Symbol("ZodInput");
15034
15031
  var $ZodRegistry = class {
15035
15032
  constructor() {
15036
15033
  this._map = /* @__PURE__ */ new Map();
@@ -16384,10 +16381,10 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
16384
16381
  };
16385
16382
  inst.clone = (def2, params) => clone(inst, def2, params);
16386
16383
  inst.brand = () => inst;
16387
- inst.register = (reg, meta) => {
16384
+ inst.register = ((reg, meta) => {
16388
16385
  reg.add(inst, meta);
16389
16386
  return inst;
16390
- };
16387
+ });
16391
16388
  inst.parse = (data, params) => parse2(inst, data, params, { callee: inst.parse });
16392
16389
  inst.safeParse = (data, params) => safeParse2(inst, data, params);
16393
16390
  inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
@@ -18294,11 +18291,13 @@ function assertCompleteRequestPrompt(request) {
18294
18291
  if (request.params.ref.type !== "ref/prompt") {
18295
18292
  throw new TypeError(`Expected CompleteRequestPrompt, but got ${request.params.ref.type}`);
18296
18293
  }
18294
+ void request;
18297
18295
  }
18298
18296
  function assertCompleteRequestResourceTemplate(request) {
18299
18297
  if (request.params.ref.type !== "ref/resource") {
18300
18298
  throw new TypeError(`Expected CompleteRequestResourceTemplate, but got ${request.params.ref.type}`);
18301
18299
  }
18300
+ void request;
18302
18301
  }
18303
18302
  var CompleteResultSchema = ResultSchema.extend({
18304
18303
  completion: looseObject({
@@ -22362,7 +22361,7 @@ ZodNaN.create = (params) => {
22362
22361
  ...processCreateParams(params)
22363
22362
  });
22364
22363
  };
22365
- var BRAND = Symbol("zod_brand");
22364
+ var BRAND = /* @__PURE__ */ Symbol("zod_brand");
22366
22365
  var ZodBranded = class extends ZodType2 {
22367
22366
  _parse(input) {
22368
22367
  const { ctx } = this._processInputParams(input);
@@ -22564,14 +22563,14 @@ var ostring = () => stringType().optional();
22564
22563
  var onumber = () => numberType().optional();
22565
22564
  var oboolean = () => booleanType().optional();
22566
22565
  var coerce = {
22567
- string: (arg) => ZodString2.create({ ...arg, coerce: true }),
22568
- number: (arg) => ZodNumber2.create({ ...arg, coerce: true }),
22569
- boolean: (arg) => ZodBoolean2.create({
22566
+ string: ((arg) => ZodString2.create({ ...arg, coerce: true })),
22567
+ number: ((arg) => ZodNumber2.create({ ...arg, coerce: true })),
22568
+ boolean: ((arg) => ZodBoolean2.create({
22570
22569
  ...arg,
22571
22570
  coerce: true
22572
- }),
22573
- bigint: (arg) => ZodBigInt.create({ ...arg, coerce: true }),
22574
- date: (arg) => ZodDate.create({ ...arg, coerce: true })
22571
+ })),
22572
+ bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })),
22573
+ date: ((arg) => ZodDate.create({ ...arg, coerce: true }))
22575
22574
  };
22576
22575
  var NEVER2 = INVALID;
22577
22576
 
@@ -22599,10 +22598,10 @@ var ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
22599
22598
  };
22600
22599
  inst.clone = (_def, params) => clone(inst, _def, params);
22601
22600
  inst.brand = () => inst;
22602
- inst.register = (reg, meta) => {
22601
+ inst.register = ((reg, meta) => {
22603
22602
  reg.add(inst, meta);
22604
22603
  return inst;
22605
- };
22604
+ });
22606
22605
  });
22607
22606
  var ZodMiniObject = /* @__PURE__ */ $constructor("ZodMiniObject", (inst, def) => {
22608
22607
  $ZodObject.init(inst, def);
@@ -22781,7 +22780,7 @@ function isTerminal(status) {
22781
22780
  }
22782
22781
 
22783
22782
  // node_modules/zod-to-json-schema/dist/esm/Options.js
22784
- var ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
22783
+ var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
22785
22784
  var defaultOptions = {
22786
22785
  name: void 0,
22787
22786
  $refStrategy: "root",
@@ -25631,7 +25630,7 @@ var Server = class extends Protocol {
25631
25630
  };
25632
25631
 
25633
25632
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
25634
- var COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
25633
+ var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
25635
25634
  function isCompletable(schema) {
25636
25635
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
25637
25636
  }
@@ -26502,7 +26501,6 @@ function requestBodyToZod(requestBody, components) {
26502
26501
  } else if ("text/plain" in requestBody.content && requestBody.content["text/plain"].schema) {
26503
26502
  schema = external_exports.string();
26504
26503
  } else {
26505
- console.error(`Unsupported media type in request body: ${JSON.stringify(requestBody.content, null, 2)}`);
26506
26504
  return external_exports.never();
26507
26505
  }
26508
26506
  if (!requestBody.required) {
@@ -26550,7 +26548,13 @@ function jsonToZodValidation(_schema, components) {
26550
26548
  let combinator;
26551
26549
  if (schema.allOf) {
26552
26550
  const schemas = schema.allOf.map((s) => schemaToZod(s, components));
26553
- combinator = schemas.length > 0 ? schemas.reduce((acc, s) => external_exports.intersection(acc, s)) : external_exports.unknown();
26551
+ combinator = schemas.length > 0 ? schemas.reduce((acc, s) => zodMerge(acc, s)) : external_exports.unknown();
26552
+ if (combinator && isZodObject(combinator)) {
26553
+ const { discriminatorKey, discriminatorValue } = findDiscriminator(schema, components);
26554
+ if (discriminatorKey && discriminatorValue) {
26555
+ combinator = combinator.extend({ [discriminatorKey]: external_exports.literal(discriminatorValue) });
26556
+ }
26557
+ }
26554
26558
  }
26555
26559
  if (schema.oneOf) {
26556
26560
  const schemas = schema.oneOf.map((s) => schemaToZod(s, components));
@@ -26591,14 +26595,9 @@ function jsonToZodValidation(_schema, components) {
26591
26595
  const shape = {};
26592
26596
  if (schema.properties) {
26593
26597
  for (const [key, property] of Object.entries(schema.properties)) {
26594
- if ("discriminator" in schema && schema.discriminator?.propertyName === key) {
26595
- const values = Object.keys(schema.discriminator.mapping ?? {});
26596
- shape[key] = external_exports.union(values.map((v) => external_exports.literal(v))).describe("Discriminator property for a union.");
26597
- } else {
26598
- shape[key] = schemaToZod(property, components);
26599
- if (!schema.required?.includes(key)) {
26600
- shape[key] = shape[key].nullish();
26601
- }
26598
+ shape[key] = schemaToZod(property, components);
26599
+ if (!schema.required?.includes(key)) {
26600
+ shape[key] = shape[key].nullish();
26602
26601
  }
26603
26602
  }
26604
26603
  }
@@ -26606,7 +26605,7 @@ function jsonToZodValidation(_schema, components) {
26606
26605
  if (schema.additionalProperties) {
26607
26606
  return objectSchema.passthrough();
26608
26607
  }
26609
- return combinator ? external_exports.intersection(combinator, objectSchema) : objectSchema;
26608
+ return combinator ? zodMerge(combinator, objectSchema) : objectSchema;
26610
26609
  }
26611
26610
  }
26612
26611
  }
@@ -26633,7 +26632,7 @@ function resolveRef(ref, components) {
26633
26632
  throw new Error(`Unknown components section: ${section}`);
26634
26633
  }
26635
26634
  const resolved = group[name];
26636
- if (!resolved) {
26635
+ if (resolved === void 0 || resolved === null) {
26637
26636
  throw new Error(`Reference not found: ${ref}`);
26638
26637
  }
26639
26638
  if (resolved && typeof resolved === "object" && "$ref" in resolved && typeof resolved.$ref === "string") {
@@ -26641,6 +26640,29 @@ function resolveRef(ref, components) {
26641
26640
  }
26642
26641
  return resolved;
26643
26642
  }
26643
+ function findDiscriminator(schema, components) {
26644
+ const partWithDiscriminator = schema.allOf?.map((s) => deref(s, components)).find((s) => typeof s === "object" && "discriminator" in s);
26645
+ const discriminator = partWithDiscriminator?.discriminator;
26646
+ if (discriminator?.mapping) {
26647
+ const discriminatorMappingEntry = Object.entries(discriminator.mapping ?? {}).find(
26648
+ ([, discriminatorRef]) => resolveRef(discriminatorRef, components) === schema
26649
+ );
26650
+ if (discriminatorMappingEntry) {
26651
+ const [discriminatorValue] = discriminatorMappingEntry;
26652
+ return { discriminatorKey: discriminator.propertyName, discriminatorValue };
26653
+ }
26654
+ }
26655
+ return {};
26656
+ }
26657
+ function zodMerge(a, b) {
26658
+ if (isZodObject(a) && isZodObject(b)) {
26659
+ return a.extend(b.shape);
26660
+ }
26661
+ return external_exports.intersection(a, b);
26662
+ }
26663
+ function isZodObject(obj) {
26664
+ return "shape" in obj && "extend" in obj;
26665
+ }
26644
26666
 
26645
26667
  // src/utils.ts
26646
26668
  function info(...parts) {
@@ -26735,17 +26757,17 @@ function generateMcpTool(description, config2) {
26735
26757
  isError: true
26736
26758
  };
26737
26759
  }
26760
+ const isJsonResponse = response.headers.get("Content-Type")?.includes("application/json");
26738
26761
  if (!response.ok) {
26739
26762
  const errorObj = {
26740
26763
  url,
26741
26764
  method,
26742
26765
  body: "data" in params ? params.data : void 0,
26743
- response: await prettyRead(response)
26766
+ response: isJsonResponse ? await response.json() : await response.text()
26744
26767
  };
26745
26768
  const errorMsg = JSON.stringify(errorObj, null, 2);
26746
- return { content: [{ type: "text", text: errorMsg }], isError: true };
26769
+ return { content: [{ type: "text", text: "```json\n" + errorMsg + "\n```" }], isError: true };
26747
26770
  }
26748
- const isJsonResponse = response.headers.get("Content-Type")?.includes("application/json");
26749
26771
  try {
26750
26772
  if (isJsonResponse) {
26751
26773
  const text = JSON.stringify(await response.json(), null, 2);
@@ -26854,18 +26876,13 @@ function write(newStorage) {
26854
26876
  async function lookupOpenApiSpec(managementApiUrl2, secret) {
26855
26877
  const workingDir2 = process.cwd();
26856
26878
  let openApiSpec2 = await fetchOpenApiSpec(managementApiUrl2, secret);
26857
- if (!openApiSpec2 && workingDir2 && process.env.CACHE_OPENAPI !== "false") {
26858
- openApiSpec2 = storage.openapiSpecs?.[workingDir2];
26859
- }
26860
- if (!openApiSpec2) {
26861
- openApiSpec2 = await fetchOpenApiSpec(managementApiUrl2, secret);
26862
- if (!openApiSpec2) {
26863
- return;
26864
- }
26865
- if (workingDir2 && process.env.CACHE_OPENAPI !== "false") {
26879
+ if (workingDir2 && process.env.CACHE_OPENAPI !== "false") {
26880
+ if (openApiSpec2) {
26866
26881
  const openApiSpecs = storage.openapiSpecs ?? {};
26867
26882
  openApiSpecs[workingDir2] = openApiSpec2;
26868
26883
  storage.openapiSpecs = openApiSpecs;
26884
+ } else {
26885
+ openApiSpec2 = storage.openapiSpecs?.[workingDir2];
26869
26886
  }
26870
26887
  }
26871
26888
  return openApiSpec2;
@@ -26901,18 +26918,7 @@ var managementApiUrl = process.env.MANAGEMENT_API_URL;
26901
26918
  if (!managementApiUrl) {
26902
26919
  err(
26903
26920
  "MANAGEMENT_API_URL environment variable is not set.",
26904
- "Please configure your mcp config to set the MANAGEMENT_API_URL environment variable, example:",
26905
- {
26906
- mcpServers: {
26907
- xperience: {
26908
- type: "stdio",
26909
- command: "@kentico/management-api-mcp",
26910
- env: {
26911
- MANAGEMENT_API_URL: "https://localhost:12345/kentico-api/management"
26912
- }
26913
- }
26914
- }
26915
- }
26921
+ "Please configure your mcp config to set the MANAGEMENT_API_URL environment variable."
26916
26922
  );
26917
26923
  process.exit(1);
26918
26924
  }
package/package.json CHANGED
@@ -1,28 +1,53 @@
1
- {
2
- "name": "@kentico/management-api-mcp",
3
- "version": "30.12.3-preview",
4
- "description": "Model Context Protocol server for Xperience by Kentico Management API",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "bin": {
8
- "xperience-mcp": "./dist/index.js"
9
- },
10
- "files": [
11
- "dist"
12
- ],
13
- "keywords": [
14
- "kentico",
15
- "xperience",
16
- "mcp",
17
- "model-context-protocol",
18
- "management-api"
19
- ],
20
- "author": "Kentico",
21
- "license": "SEE LICENSE IN LICENSE.txt",
22
- "dependencies": {
23
- "@modelcontextprotocol/sdk": "^1.0.4"
24
- },
25
- "engines": {
26
- "node": ">= 22.0.0"
27
- }
28
- }
1
+ {
2
+ "name": "@kentico/management-api-mcp",
3
+ "version": "31.0.0-preview",
4
+ "description": "Model Context Protocol server for Xperience by Kentico Management API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "xperience-mcp": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "start": "node dist/index.js",
15
+ "debug": "mcp-inspector --config .\\mcp-config.json",
16
+ "dev": "esbuild src/index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --sourcemap --watch",
17
+ "build": "esbuild src/index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js",
18
+ "lint": "eslint src/**/*.ts",
19
+ "lint:fix": "eslint src/**/*.ts --fix",
20
+ "format": "prettier --check \"src/**/*.ts\"",
21
+ "format:fix": "prettier --write \"src/**/*.ts\"",
22
+ "version:bump": "npm version",
23
+ "prepack": "node -e \"require('fs').copyFileSync('PACKAGE_README.md', 'README.md')\" && clean-pkg-json"
24
+ },
25
+ "keywords": [
26
+ "kentico",
27
+ "xperience",
28
+ "mcp",
29
+ "model-context-protocol",
30
+ "management-api"
31
+ ],
32
+ "author": "Kentico",
33
+ "license": "SEE LICENSE IN LICENSE.txt",
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.23.0"
36
+ },
37
+ "devDependencies": {
38
+ "@eslint/js": "^9.39.1",
39
+ "@modelcontextprotocol/inspector": "^0.17.2",
40
+ "@types/node": "22.19.1",
41
+ "@typescript-eslint/eslint-plugin": "^8.48.0",
42
+ "@typescript-eslint/parser": "^8.48.0",
43
+ "esbuild": "^0.27.0",
44
+ "eslint": "^9.39.1",
45
+ "prettier": "^3.7.3",
46
+ "typescript": "5.9.3",
47
+ "typescript-eslint": "^8.48.0",
48
+ "clean-pkg-json": "^1.3.0"
49
+ },
50
+ "engines": {
51
+ "node": ">= 22.0.0"
52
+ }
53
+ }