@schmadev/mcp-server 0.0.0-stage → 1.0.1
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/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +178 -0
- package/dist/index.mjs +131 -0
- package/package.json +25 -3
- package/src/index.ts +199 -0
- package/tsconfig.json +10 -0
- package/README.md +0 -3
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
var server = new Server({
|
|
8
|
+
name: "schma-mcp",
|
|
9
|
+
version: "1.0.0"
|
|
10
|
+
}, {
|
|
11
|
+
capabilities: { tools: {} }
|
|
12
|
+
});
|
|
13
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
14
|
+
tools: [
|
|
15
|
+
{
|
|
16
|
+
name: "list_content_types",
|
|
17
|
+
description: "List all content types in the CMS project",
|
|
18
|
+
inputSchema: { type: "object", properties: {}, required: [] }
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "get_entries",
|
|
22
|
+
description: "Get published entries of a given content type",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
contentType: { type: "string", description: 'The content type slug e.g. "post"' },
|
|
27
|
+
limit: { type: "number", description: "Max entries to return (default 10)" },
|
|
28
|
+
status: { type: "string", enum: ["published", "draft", "all"] }
|
|
29
|
+
},
|
|
30
|
+
required: ["contentType"]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "create_entry",
|
|
35
|
+
description: "Create a new content entry",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
contentType: { type: "string" },
|
|
40
|
+
data: { type: "object", description: "Field values matching the schema" },
|
|
41
|
+
status: { type: "string", enum: ["draft", "published"], default: "draft" }
|
|
42
|
+
},
|
|
43
|
+
required: ["contentType", "data"]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "update_entry",
|
|
48
|
+
description: "Update an existing content entry by ID",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
entryId: { type: "string" },
|
|
53
|
+
data: { type: "object" }
|
|
54
|
+
},
|
|
55
|
+
required: ["entryId", "data"]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "get_schema",
|
|
60
|
+
description: "Get schema fields for a content type",
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
contentType: { type: "string", description: "The content type slug" }
|
|
65
|
+
},
|
|
66
|
+
required: ["contentType"]
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "publish_entry",
|
|
71
|
+
description: "Publish an existing content entry by ID",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
entryId: { type: "string" }
|
|
76
|
+
},
|
|
77
|
+
required: ["entryId"]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "search_content",
|
|
82
|
+
description: "Search content semantically across all content types",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
query: { type: "string", description: "Natural language search query" }
|
|
87
|
+
},
|
|
88
|
+
required: ["query"]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}));
|
|
93
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
94
|
+
const { name, arguments: args } = request.params;
|
|
95
|
+
const apiBase = process.env.SCHMA_API_URL || "http://localhost:3001";
|
|
96
|
+
const token = process.env.SCHMA_API_KEY || "";
|
|
97
|
+
const tenantSlug = process.env.SCHMA_TENANT_SLUG || "";
|
|
98
|
+
const headers = {
|
|
99
|
+
"Content-Type": "application/json"
|
|
100
|
+
};
|
|
101
|
+
if (token) {
|
|
102
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
103
|
+
}
|
|
104
|
+
if (tenantSlug) {
|
|
105
|
+
headers["x-tenant-slug"] = tenantSlug;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
switch (name) {
|
|
109
|
+
case "list_content_types": {
|
|
110
|
+
const res = await fetch(`${apiBase}/content-types`, { headers });
|
|
111
|
+
const types = await res.json();
|
|
112
|
+
return { content: [{ type: "text", text: JSON.stringify(types, null, 2) }] };
|
|
113
|
+
}
|
|
114
|
+
case "get_entries": {
|
|
115
|
+
const limit = args.limit ? String(args.limit) : "10";
|
|
116
|
+
const status = args.status ? String(args.status) : "published";
|
|
117
|
+
const params = new URLSearchParams({
|
|
118
|
+
typeSlug: String(args.contentType),
|
|
119
|
+
limit,
|
|
120
|
+
status
|
|
121
|
+
});
|
|
122
|
+
const res = await fetch(`${apiBase}/entries?${params}`, { headers });
|
|
123
|
+
const entries = await res.json();
|
|
124
|
+
return { content: [{ type: "text", text: JSON.stringify(entries, null, 2) }] };
|
|
125
|
+
}
|
|
126
|
+
case "create_entry": {
|
|
127
|
+
const res = await fetch(`${apiBase}/entries`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers,
|
|
130
|
+
body: JSON.stringify({ typeSlug: args.contentType, dataJson: args.data, status: args.status ?? "draft" })
|
|
131
|
+
});
|
|
132
|
+
const entry = await res.json();
|
|
133
|
+
return { content: [{ type: "text", text: `Created entry: ${entry.id || JSON.stringify(entry)}` }] };
|
|
134
|
+
}
|
|
135
|
+
case "update_entry": {
|
|
136
|
+
const res = await fetch(`${apiBase}/entries/${args.entryId}`, {
|
|
137
|
+
method: "PUT",
|
|
138
|
+
headers,
|
|
139
|
+
body: JSON.stringify({ dataJson: args.data })
|
|
140
|
+
});
|
|
141
|
+
const entry = await res.json();
|
|
142
|
+
return { content: [{ type: "text", text: `Updated: ${entry.id || JSON.stringify(entry)}` }] };
|
|
143
|
+
}
|
|
144
|
+
case "get_schema": {
|
|
145
|
+
const res = await fetch(`${apiBase}/content-types/${args.contentType}`, { headers });
|
|
146
|
+
const schema = await res.json();
|
|
147
|
+
return { content: [{ type: "text", text: JSON.stringify(schema, null, 2) }] };
|
|
148
|
+
}
|
|
149
|
+
case "publish_entry": {
|
|
150
|
+
const res = await fetch(`${apiBase}/entries/${args.entryId}`, {
|
|
151
|
+
method: "PUT",
|
|
152
|
+
headers,
|
|
153
|
+
body: JSON.stringify({ status: "published" })
|
|
154
|
+
});
|
|
155
|
+
const entry = await res.json();
|
|
156
|
+
return { content: [{ type: "text", text: `Published: ${entry.id || JSON.stringify(entry)}` }] };
|
|
157
|
+
}
|
|
158
|
+
case "search_content": {
|
|
159
|
+
const params = new URLSearchParams({
|
|
160
|
+
text: String(args.query),
|
|
161
|
+
limit: "10"
|
|
162
|
+
});
|
|
163
|
+
const res = await fetch(`${apiBase}/v1/delivery/entries/similar?${params}`, { headers });
|
|
164
|
+
const results = await res.json();
|
|
165
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
166
|
+
}
|
|
167
|
+
default:
|
|
168
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
169
|
+
}
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return { content: [{ type: "text", text: `Error calling tool ${name}: ${err.message}` }] };
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
async function main() {
|
|
175
|
+
const transport = new StdioServerTransport();
|
|
176
|
+
await server.connect(transport);
|
|
177
|
+
}
|
|
178
|
+
main().catch(console.error);
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
var server = new Server({
|
|
8
|
+
name: "schma-mcp",
|
|
9
|
+
version: "1.0.0"
|
|
10
|
+
}, {
|
|
11
|
+
capabilities: { tools: {} }
|
|
12
|
+
});
|
|
13
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
14
|
+
tools: [
|
|
15
|
+
{
|
|
16
|
+
name: "list_content_types",
|
|
17
|
+
description: "List all content types in the CMS project",
|
|
18
|
+
inputSchema: { type: "object", properties: {}, required: [] }
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "get_entries",
|
|
22
|
+
description: "Get published entries of a given content type",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
contentType: { type: "string", description: 'The content type slug e.g. "post"' },
|
|
27
|
+
limit: { type: "number", description: "Max entries to return (default 10)" },
|
|
28
|
+
status: { type: "string", enum: ["published", "draft", "all"] }
|
|
29
|
+
},
|
|
30
|
+
required: ["contentType"]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "create_entry",
|
|
35
|
+
description: "Create a new content entry",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
contentType: { type: "string" },
|
|
40
|
+
data: { type: "object", description: "Field values matching the schema" },
|
|
41
|
+
status: { type: "string", enum: ["draft", "published"], default: "draft" }
|
|
42
|
+
},
|
|
43
|
+
required: ["contentType", "data"]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "update_entry",
|
|
48
|
+
description: "Update an existing content entry by ID",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
entryId: { type: "string" },
|
|
53
|
+
data: { type: "object" }
|
|
54
|
+
},
|
|
55
|
+
required: ["entryId", "data"]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "search_content",
|
|
60
|
+
description: "Search content semantically across all content types",
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
query: { type: "string", description: "Natural language search query" }
|
|
65
|
+
},
|
|
66
|
+
required: ["query"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}));
|
|
71
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
72
|
+
const { name, arguments: args } = request.params;
|
|
73
|
+
const apiBase = process.env.SCHMA_API_URL || "http://localhost:3001";
|
|
74
|
+
const token = process.env.SCHMA_API_KEY || "";
|
|
75
|
+
const headers = {
|
|
76
|
+
"Content-Type": "application/json"
|
|
77
|
+
};
|
|
78
|
+
if (token) {
|
|
79
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
switch (name) {
|
|
83
|
+
case "list_content_types": {
|
|
84
|
+
const res = await fetch(`${apiBase}/content-types`, { headers });
|
|
85
|
+
const types = await res.json();
|
|
86
|
+
return { content: [{ type: "text", text: JSON.stringify(types, null, 2) }] };
|
|
87
|
+
}
|
|
88
|
+
case "get_entries": {
|
|
89
|
+
const limit = args.limit ? String(args.limit) : "10";
|
|
90
|
+
const status = args.status ? String(args.status) : "published";
|
|
91
|
+
const params = new URLSearchParams({
|
|
92
|
+
limit,
|
|
93
|
+
status
|
|
94
|
+
});
|
|
95
|
+
const res = await fetch(`${apiBase}/entries/${args.contentType}?${params}`, { headers });
|
|
96
|
+
const entries = await res.json();
|
|
97
|
+
return { content: [{ type: "text", text: JSON.stringify(entries, null, 2) }] };
|
|
98
|
+
}
|
|
99
|
+
case "create_entry": {
|
|
100
|
+
const res = await fetch(`${apiBase}/entries/${args.contentType}`, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers,
|
|
103
|
+
body: JSON.stringify({ data: args.data, status: args.status ?? "draft" })
|
|
104
|
+
});
|
|
105
|
+
const entry = await res.json();
|
|
106
|
+
return { content: [{ type: "text", text: `Created entry: ${entry.id || JSON.stringify(entry)}` }] };
|
|
107
|
+
}
|
|
108
|
+
case "update_entry": {
|
|
109
|
+
const res = await fetch(`${apiBase}/entries/${args.entryId}`, {
|
|
110
|
+
method: "PATCH",
|
|
111
|
+
headers,
|
|
112
|
+
body: JSON.stringify({ data: args.data })
|
|
113
|
+
});
|
|
114
|
+
const entry = await res.json();
|
|
115
|
+
return { content: [{ type: "text", text: `Updated: ${entry.id || JSON.stringify(entry)}` }] };
|
|
116
|
+
}
|
|
117
|
+
case "search_content": {
|
|
118
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "Semantic search not yet implemented." }, null, 2) }] };
|
|
119
|
+
}
|
|
120
|
+
default:
|
|
121
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return { content: [{ type: "text", text: `Error calling tool ${name}: ${err.message}` }] };
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
async function main() {
|
|
128
|
+
const transport = new StdioServerTransport();
|
|
129
|
+
await server.connect(transport);
|
|
130
|
+
}
|
|
131
|
+
main().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schmadev/mcp-server",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Schma CMS MCP Server for AI IDE Integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"schma-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@modelcontextprotocol/sdk": "^1.4.1",
|
|
12
|
+
"zod": "^4.6.5"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@schmadev/typescript-config": "0.0.1",
|
|
16
|
+
"@types/node": "^20.0.0",
|
|
17
|
+
"tsup": "^8.0.0",
|
|
18
|
+
"typescript": "^5.0.0",
|
|
19
|
+
"vitest": "^5.0.3"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "vitest run --passWithNoTests",
|
|
24
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
25
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
26
|
+
"start": "node dist/index.js"
|
|
27
|
+
}
|
|
6
28
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
|
|
7
|
+
const server = new Server({
|
|
8
|
+
name: 'schma-mcp',
|
|
9
|
+
version: '1.0.0',
|
|
10
|
+
}, {
|
|
11
|
+
capabilities: { tools: {} }
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// -- Tool: list content types --
|
|
15
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
16
|
+
tools: [
|
|
17
|
+
{
|
|
18
|
+
name: 'list_content_types',
|
|
19
|
+
description: 'List all content types in the CMS project',
|
|
20
|
+
inputSchema: { type: 'object', properties: {}, required: [] }
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'get_entries',
|
|
24
|
+
description: 'Get published entries of a given content type',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
contentType: { type: 'string', description: 'The content type slug e.g. "post"' },
|
|
29
|
+
limit: { type: 'number', description: 'Max entries to return (default 10)' },
|
|
30
|
+
status: { type: 'string', enum: ['published', 'draft', 'all'] }
|
|
31
|
+
},
|
|
32
|
+
required: ['contentType']
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'create_entry',
|
|
37
|
+
description: 'Create a new content entry',
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
contentType: { type: 'string' },
|
|
42
|
+
data: { type: 'object', description: 'Field values matching the schema' },
|
|
43
|
+
status: { type: 'string', enum: ['draft', 'published'], default: 'draft' }
|
|
44
|
+
},
|
|
45
|
+
required: ['contentType', 'data']
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'update_entry',
|
|
50
|
+
description: 'Update an existing content entry by ID',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
entryId: { type: 'string' },
|
|
55
|
+
data: { type: 'object' }
|
|
56
|
+
},
|
|
57
|
+
required: ['entryId', 'data']
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'get_schema',
|
|
62
|
+
description: 'Get schema fields for a content type',
|
|
63
|
+
inputSchema: {
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
contentType: { type: 'string', description: 'The content type slug' }
|
|
67
|
+
},
|
|
68
|
+
required: ['contentType']
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'publish_entry',
|
|
73
|
+
description: 'Publish an existing content entry by ID',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
entryId: { type: 'string' }
|
|
78
|
+
},
|
|
79
|
+
required: ['entryId']
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'search_content',
|
|
84
|
+
description: 'Search content semantically across all content types',
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
query: { type: 'string', description: 'Natural language search query' }
|
|
89
|
+
},
|
|
90
|
+
required: ['query']
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
// -- Tool call handler --
|
|
97
|
+
server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
|
|
98
|
+
const { name, arguments: args } = request.params;
|
|
99
|
+
|
|
100
|
+
const apiBase = process.env.SCHMA_API_URL || 'http://localhost:3001';
|
|
101
|
+
const token = process.env.SCHMA_API_KEY || '';
|
|
102
|
+
const tenantSlug = process.env.SCHMA_TENANT_SLUG || '';
|
|
103
|
+
|
|
104
|
+
const headers: Record<string, string> = {
|
|
105
|
+
'Content-Type': 'application/json'
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
if (token) {
|
|
109
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
110
|
+
}
|
|
111
|
+
if (tenantSlug) {
|
|
112
|
+
headers['x-tenant-slug'] = tenantSlug;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
switch (name) {
|
|
117
|
+
case 'list_content_types': {
|
|
118
|
+
const res = await fetch(`${apiBase}/content-types`, { headers });
|
|
119
|
+
const types = await res.json();
|
|
120
|
+
return { content: [{ type: 'text', text: JSON.stringify(types, null, 2) }] };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
case 'get_entries': {
|
|
124
|
+
const limit = args.limit ? String(args.limit) : '10';
|
|
125
|
+
const status = args.status ? String(args.status) : 'published';
|
|
126
|
+
|
|
127
|
+
const params = new URLSearchParams({
|
|
128
|
+
typeSlug: String(args.contentType),
|
|
129
|
+
limit,
|
|
130
|
+
status
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const res = await fetch(`${apiBase}/entries?${params}`, { headers });
|
|
134
|
+
const entries = await res.json();
|
|
135
|
+
return { content: [{ type: 'text', text: JSON.stringify(entries, null, 2) }] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
case 'create_entry': {
|
|
139
|
+
const res = await fetch(`${apiBase}/entries`, {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
headers,
|
|
142
|
+
body: JSON.stringify({ typeSlug: args.contentType, dataJson: args.data, status: args.status ?? 'draft' })
|
|
143
|
+
});
|
|
144
|
+
const entry = await res.json();
|
|
145
|
+
return { content: [{ type: 'text', text: `Created entry: ${entry.id || JSON.stringify(entry)}` }] };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
case 'update_entry': {
|
|
149
|
+
const res = await fetch(`${apiBase}/entries/${args.entryId}`, {
|
|
150
|
+
method: 'PUT',
|
|
151
|
+
headers,
|
|
152
|
+
body: JSON.stringify({ dataJson: args.data })
|
|
153
|
+
});
|
|
154
|
+
const entry = await res.json();
|
|
155
|
+
return { content: [{ type: 'text', text: `Updated: ${entry.id || JSON.stringify(entry)}` }] };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
case 'get_schema': {
|
|
159
|
+
const res = await fetch(`${apiBase}/content-types/${args.contentType}`, { headers });
|
|
160
|
+
const schema = await res.json();
|
|
161
|
+
return { content: [{ type: 'text', text: JSON.stringify(schema, null, 2) }] };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
case 'publish_entry': {
|
|
165
|
+
const res = await fetch(`${apiBase}/entries/${args.entryId}`, {
|
|
166
|
+
method: 'PUT',
|
|
167
|
+
headers,
|
|
168
|
+
body: JSON.stringify({ status: 'published' })
|
|
169
|
+
});
|
|
170
|
+
const entry = await res.json();
|
|
171
|
+
return { content: [{ type: 'text', text: `Published: ${entry.id || JSON.stringify(entry)}` }] };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
case 'search_content': {
|
|
175
|
+
const params = new URLSearchParams({
|
|
176
|
+
text: String(args.query),
|
|
177
|
+
limit: '10'
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const res = await fetch(`${apiBase}/v1/delivery/entries/similar?${params}`, { headers });
|
|
181
|
+
const results = await res.json();
|
|
182
|
+
return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
default:
|
|
186
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
187
|
+
}
|
|
188
|
+
} catch (err: any) {
|
|
189
|
+
return { content: [{ type: 'text', text: `Error calling tool ${name}: ${err.message}` }] };
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Start the server on stdio (Cursor / Claude Code picks it up)
|
|
194
|
+
async function main() {
|
|
195
|
+
const transport = new StdioServerTransport();
|
|
196
|
+
await server.connect(transport);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
main().catch(console.error);
|
package/tsconfig.json
ADDED
package/README.md
DELETED