@kontent-ai/mcp-server 0.1.0 → 0.3.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 +16 -4
- package/build/bin.js +45 -0
- 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 +20 -0
- package/package.json +4 -5
- package/build/sseTransport.js +0 -23
- package/build/stdioTransport.js +0 -13
package/README.md
CHANGED
|
@@ -18,12 +18,11 @@ This server provides a Model Context Protocol (MCP) interface for interacting wi
|
|
|
18
18
|
|
|
19
19
|
### Environment Variables
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
The following environment variables are needed:
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
KONTENT_ENVIRONMENT_ID=your_environment_id
|
|
25
25
|
KONTENT_API_KEY=your_api_key
|
|
26
|
-
PORT=3001 # Optional, defaults to 3001
|
|
27
26
|
```
|
|
28
27
|
|
|
29
28
|
### Using with npx
|
|
@@ -38,6 +37,20 @@ npx @kontent-ai/mcp-server sse
|
|
|
38
37
|
npx @kontent-ai/mcp-server stdio
|
|
39
38
|
```
|
|
40
39
|
|
|
40
|
+
### Example mcp.json usage
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"kontent-ai-stdio": {
|
|
45
|
+
"command": "npx @kontent-ai/mcp stdio",
|
|
46
|
+
"env": {
|
|
47
|
+
"KONTENT_API_KEY": "<management-api-key>",
|
|
48
|
+
"KONTENT_ENVIRONMENT_ID": "<environment-id>"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
41
54
|
### Local Installation
|
|
42
55
|
|
|
43
56
|
```bash
|
|
@@ -71,8 +84,7 @@ npm run start:stdio # For STDIO transport
|
|
|
71
84
|
- `clients/` - Kontent.ai API client setup
|
|
72
85
|
- `schemas/` - Data validation schemas
|
|
73
86
|
- `server.ts` - Main server setup and tool registration
|
|
74
|
-
- `
|
|
75
|
-
- `stdioTransport.ts` - STDIO transport implementation
|
|
87
|
+
- `bin.ts` - Single entry point that handles both transport types
|
|
76
88
|
|
|
77
89
|
## License
|
|
78
90
|
|
package/build/bin.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import express from "express";
|
|
6
|
+
import { createServer } from "./server.js";
|
|
7
|
+
async function startSSE() {
|
|
8
|
+
const app = express();
|
|
9
|
+
const { server } = createServer();
|
|
10
|
+
let transport;
|
|
11
|
+
app.get("/sse", async (req, res) => {
|
|
12
|
+
transport = new SSEServerTransport("/message", res);
|
|
13
|
+
await server.connect(transport);
|
|
14
|
+
});
|
|
15
|
+
app.post("/message", async (req, res) => {
|
|
16
|
+
await transport.handlePostMessage(req, res);
|
|
17
|
+
});
|
|
18
|
+
const PORT = process.env.PORT || 3001;
|
|
19
|
+
app.listen(PORT, () => {
|
|
20
|
+
console.log(`Kontent.ai MCP Server (SSE) running on port ${PORT}`);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function startStdio() {
|
|
24
|
+
const { server } = createServer();
|
|
25
|
+
const transport = new StdioServerTransport();
|
|
26
|
+
await server.connect(transport);
|
|
27
|
+
}
|
|
28
|
+
async function main() {
|
|
29
|
+
const args = process.argv.slice(2);
|
|
30
|
+
const transportType = args[0]?.toLowerCase();
|
|
31
|
+
if (!transportType || (transportType !== 'stdio' && transportType !== 'sse')) {
|
|
32
|
+
console.error('Please specify a valid transport type: stdio or sse');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (transportType === 'stdio') {
|
|
36
|
+
await startStdio();
|
|
37
|
+
}
|
|
38
|
+
else if (transportType === 'sse') {
|
|
39
|
+
await startSSE();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
main().catch((error) => {
|
|
43
|
+
console.error("Fatal error:", error);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
});
|
|
@@ -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,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createMapiClient } from '../clients/kontentClients.js';
|
|
3
|
+
export const registerTool = (server) => {
|
|
4
|
+
server.tool("list-taxonomy-groups-mapi", "Get all taxonomy groups from Management API", {
|
|
5
|
+
random_string: z.string().describe("Dummy parameter for no-parameter tools")
|
|
6
|
+
}, async () => {
|
|
7
|
+
const client = createMapiClient();
|
|
8
|
+
const response = await client
|
|
9
|
+
.listTaxonomies()
|
|
10
|
+
.toPromise();
|
|
11
|
+
return {
|
|
12
|
+
content: [
|
|
13
|
+
{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: JSON.stringify(response.data),
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kontent-ai/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc",
|
|
7
|
-
"start:stdio": "node build/
|
|
8
|
-
"start:sse": "node build/
|
|
7
|
+
"start:stdio": "node build/bin.js stdio",
|
|
8
|
+
"start:sse": "node build/bin.js sse"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
|
-
"
|
|
12
|
-
"sse": "./build/sseTransport.js"
|
|
11
|
+
"@kontent-ai/mcp-server": "./build/bin.js"
|
|
13
12
|
},
|
|
14
13
|
"files": [
|
|
15
14
|
"build"
|
package/build/sseTransport.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
3
|
-
import express from "express";
|
|
4
|
-
import { createServer } from "./server.js";
|
|
5
|
-
const app = express();
|
|
6
|
-
const { server } = createServer();
|
|
7
|
-
let transport;
|
|
8
|
-
app.get("/sse", async (req, res) => {
|
|
9
|
-
transport = new SSEServerTransport("/message", res);
|
|
10
|
-
await server.connect(transport);
|
|
11
|
-
/*server.onclose = async () => {
|
|
12
|
-
//await cleanup();
|
|
13
|
-
await server.close();
|
|
14
|
-
process.exit(0);
|
|
15
|
-
};*/
|
|
16
|
-
});
|
|
17
|
-
app.post("/message", async (req, res) => {
|
|
18
|
-
await transport.handlePostMessage(req, res);
|
|
19
|
-
});
|
|
20
|
-
const PORT = process.env.PORT || 3001;
|
|
21
|
-
app.listen(PORT, () => {
|
|
22
|
-
console.log(`Kontent.ai MCP Server (SSE) running on port ${PORT}`);
|
|
23
|
-
});
|
package/build/stdioTransport.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import { createServer } from "./server.js";
|
|
4
|
-
// Create server instance
|
|
5
|
-
const { server } = createServer();
|
|
6
|
-
async function main() {
|
|
7
|
-
const transport = new StdioServerTransport();
|
|
8
|
-
await server.connect(transport);
|
|
9
|
-
}
|
|
10
|
-
main().catch((error) => {
|
|
11
|
-
console.error("Fatal error in main():", error);
|
|
12
|
-
process.exit(1);
|
|
13
|
-
});
|