@webhouse/cms-mcp-server 0.1.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.
@@ -0,0 +1,320 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { ContentService, CmsConfig } from '@webhouse/cms';
3
+
4
+ declare const ADMIN_TOOLS: readonly [{
5
+ readonly name: "get_site_summary";
6
+ readonly description: string;
7
+ readonly inputSchema: {
8
+ readonly type: "object";
9
+ readonly properties: {};
10
+ readonly required: string[];
11
+ };
12
+ }, {
13
+ readonly name: "list_collection";
14
+ readonly description: string;
15
+ readonly inputSchema: {
16
+ readonly type: "object";
17
+ readonly properties: {
18
+ readonly collection: {
19
+ readonly type: "string";
20
+ readonly description: "Collection name, e.g. 'posts', 'products'";
21
+ };
22
+ readonly limit: {
23
+ readonly type: "number";
24
+ readonly description: "Max results. Default 20, max 100.";
25
+ };
26
+ readonly offset: {
27
+ readonly type: "number";
28
+ readonly description: "Pagination offset. Default 0.";
29
+ };
30
+ readonly sort: {
31
+ readonly type: "string";
32
+ readonly enum: readonly ["date_desc", "date_asc", "title_asc"];
33
+ readonly description: "Sort order. Default: date_desc.";
34
+ };
35
+ };
36
+ readonly required: string[];
37
+ };
38
+ }, {
39
+ readonly name: "search_content";
40
+ readonly description: string;
41
+ readonly inputSchema: {
42
+ readonly type: "object";
43
+ readonly properties: {
44
+ readonly query: {
45
+ readonly type: "string";
46
+ readonly description: "Search query.";
47
+ };
48
+ readonly collection: {
49
+ readonly type: "string";
50
+ readonly description: "Optional: limit search to this collection.";
51
+ };
52
+ readonly limit: {
53
+ readonly type: "number";
54
+ readonly description: "Max results. Default 10, max 50.";
55
+ };
56
+ };
57
+ readonly required: string[];
58
+ };
59
+ }, {
60
+ readonly name: "get_page";
61
+ readonly description: string;
62
+ readonly inputSchema: {
63
+ readonly type: "object";
64
+ readonly properties: {
65
+ readonly slug: {
66
+ readonly type: "string";
67
+ readonly description: "Document slug, e.g. 'getting-started'.";
68
+ };
69
+ readonly collection: {
70
+ readonly type: "string";
71
+ readonly description: "Optional: collection to scope the lookup.";
72
+ };
73
+ };
74
+ readonly required: string[];
75
+ };
76
+ }, {
77
+ readonly name: "get_schema";
78
+ readonly description: "Returns the field schema for a collection, describing all available fields and their types.";
79
+ readonly inputSchema: {
80
+ readonly type: "object";
81
+ readonly properties: {
82
+ readonly collection: {
83
+ readonly type: "string";
84
+ readonly description: "Collection name.";
85
+ };
86
+ };
87
+ readonly required: string[];
88
+ };
89
+ }, {
90
+ readonly name: "export_all";
91
+ readonly description: string;
92
+ readonly inputSchema: {
93
+ readonly type: "object";
94
+ readonly properties: {
95
+ readonly include_body: {
96
+ readonly type: "boolean";
97
+ readonly description: "Include full body (true) or metadata only (false). Default: true.";
98
+ };
99
+ };
100
+ readonly required: string[];
101
+ };
102
+ }, {
103
+ readonly name: "create_document";
104
+ readonly description: string;
105
+ readonly inputSchema: {
106
+ readonly type: "object";
107
+ readonly properties: {
108
+ readonly collection: {
109
+ readonly type: "string";
110
+ };
111
+ readonly fields: {
112
+ readonly type: "object";
113
+ readonly description: "Document fields matching the collection schema.";
114
+ };
115
+ readonly status: {
116
+ readonly type: "string";
117
+ readonly enum: readonly ["draft", "published"];
118
+ readonly description: "Initial status. Default: draft.";
119
+ };
120
+ };
121
+ readonly required: string[];
122
+ };
123
+ }, {
124
+ readonly name: "update_document";
125
+ readonly description: string;
126
+ readonly inputSchema: {
127
+ readonly type: "object";
128
+ readonly properties: {
129
+ readonly collection: {
130
+ readonly type: "string";
131
+ };
132
+ readonly slug: {
133
+ readonly type: "string";
134
+ };
135
+ readonly fields: {
136
+ readonly type: "object";
137
+ readonly description: "Fields to update.";
138
+ };
139
+ };
140
+ readonly required: string[];
141
+ };
142
+ }, {
143
+ readonly name: "publish_document";
144
+ readonly description: "Sets a document status to 'published'. Optionally triggers an immediate build.";
145
+ readonly inputSchema: {
146
+ readonly type: "object";
147
+ readonly properties: {
148
+ readonly collection: {
149
+ readonly type: "string";
150
+ };
151
+ readonly slug: {
152
+ readonly type: "string";
153
+ };
154
+ readonly auto_build: {
155
+ readonly type: "boolean";
156
+ readonly description: "Trigger site build after publishing. Default: false.";
157
+ };
158
+ };
159
+ readonly required: string[];
160
+ };
161
+ }, {
162
+ readonly name: "unpublish_document";
163
+ readonly description: "Sets a document back to draft status.";
164
+ readonly inputSchema: {
165
+ readonly type: "object";
166
+ readonly properties: {
167
+ readonly collection: {
168
+ readonly type: "string";
169
+ };
170
+ readonly slug: {
171
+ readonly type: "string";
172
+ };
173
+ };
174
+ readonly required: string[];
175
+ };
176
+ }, {
177
+ readonly name: "generate_with_ai";
178
+ readonly description: string;
179
+ readonly inputSchema: {
180
+ readonly type: "object";
181
+ readonly properties: {
182
+ readonly collection: {
183
+ readonly type: "string";
184
+ };
185
+ readonly intent: {
186
+ readonly type: "string";
187
+ readonly description: string;
188
+ };
189
+ readonly status: {
190
+ readonly type: "string";
191
+ readonly enum: readonly ["draft", "published"];
192
+ readonly description: "Status for the created document. Default: draft.";
193
+ };
194
+ };
195
+ readonly required: string[];
196
+ };
197
+ }, {
198
+ readonly name: "rewrite_field";
199
+ readonly description: string;
200
+ readonly inputSchema: {
201
+ readonly type: "object";
202
+ readonly properties: {
203
+ readonly collection: {
204
+ readonly type: "string";
205
+ };
206
+ readonly slug: {
207
+ readonly type: "string";
208
+ };
209
+ readonly field: {
210
+ readonly type: "string";
211
+ readonly description: "Field name to rewrite.";
212
+ };
213
+ readonly instruction: {
214
+ readonly type: "string";
215
+ readonly description: string;
216
+ };
217
+ };
218
+ readonly required: string[];
219
+ };
220
+ }, {
221
+ readonly name: "trigger_build";
222
+ readonly description: string;
223
+ readonly inputSchema: {
224
+ readonly type: "object";
225
+ readonly properties: {
226
+ readonly mode: {
227
+ readonly type: "string";
228
+ readonly enum: readonly ["full", "incremental"];
229
+ readonly description: "Build mode. Default: incremental.";
230
+ };
231
+ };
232
+ readonly required: string[];
233
+ };
234
+ }, {
235
+ readonly name: "list_drafts";
236
+ readonly description: "Lists all unpublished draft documents across all (or one) collection.";
237
+ readonly inputSchema: {
238
+ readonly type: "object";
239
+ readonly properties: {
240
+ readonly collection: {
241
+ readonly type: "string";
242
+ readonly description: "Optional: filter by collection.";
243
+ };
244
+ };
245
+ readonly required: string[];
246
+ };
247
+ }, {
248
+ readonly name: "get_version_history";
249
+ readonly description: "Returns revision history for a document.";
250
+ readonly inputSchema: {
251
+ readonly type: "object";
252
+ readonly properties: {
253
+ readonly collection: {
254
+ readonly type: "string";
255
+ };
256
+ readonly slug: {
257
+ readonly type: "string";
258
+ };
259
+ readonly limit: {
260
+ readonly type: "number";
261
+ readonly description: "Number of versions. Default 10.";
262
+ };
263
+ };
264
+ readonly required: string[];
265
+ };
266
+ }];
267
+ type AdminToolName = (typeof ADMIN_TOOLS)[number]["name"];
268
+ declare const TOOL_SCOPES: Record<AdminToolName, string[]>;
269
+
270
+ interface ApiKeyConfig {
271
+ key: string;
272
+ label: string;
273
+ scopes: string[];
274
+ }
275
+ declare function validateApiKey(authHeader: string | null | undefined, keys: ApiKeyConfig[]): {
276
+ authenticated: true;
277
+ label: string;
278
+ scopes: string[];
279
+ } | {
280
+ authenticated: false;
281
+ error: string;
282
+ };
283
+ declare function hasScope(userScopes: string[], required: string[]): boolean;
284
+
285
+ interface AuditEntry {
286
+ timestamp: string;
287
+ tool: string;
288
+ actor: string;
289
+ result: "success" | "error";
290
+ documentRef?: string;
291
+ error?: string;
292
+ }
293
+ declare function initAuditLog(dataDir: string): void;
294
+ declare function writeAudit(entry: AuditEntry): void;
295
+
296
+ interface AiGenerator {
297
+ generate(intent: string, collectionName: string): Promise<{
298
+ fields: Record<string, string>;
299
+ slug: string;
300
+ }>;
301
+ rewriteField(collection: string, slug: string, field: string, instruction: string, currentValue: string): Promise<string>;
302
+ }
303
+ interface AdminServerOptions {
304
+ content: ContentService;
305
+ config: CmsConfig;
306
+ /** Resolved scopes for this session — determined by auth middleware before connect */
307
+ scopes: string[];
308
+ /** Label identifying the API key / user for audit log */
309
+ actor: string;
310
+ /** Optional AI generator — if not provided, AI tools return a "not configured" error */
311
+ ai?: AiGenerator;
312
+ /** Called when a write tool needs to trigger a build */
313
+ onBuild?: (mode: "full" | "incremental") => Promise<{
314
+ ok: boolean;
315
+ message: string;
316
+ }>;
317
+ }
318
+ declare function createAdminMcpServer(opts: AdminServerOptions): Server;
319
+
320
+ export { ADMIN_TOOLS, type AdminServerOptions, type AdminToolName, type AiGenerator, type ApiKeyConfig, type AuditEntry, TOOL_SCOPES, createAdminMcpServer, hasScope, initAuditLog, validateApiKey, writeAudit };
@@ -0,0 +1,320 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { ContentService, CmsConfig } from '@webhouse/cms';
3
+
4
+ declare const ADMIN_TOOLS: readonly [{
5
+ readonly name: "get_site_summary";
6
+ readonly description: string;
7
+ readonly inputSchema: {
8
+ readonly type: "object";
9
+ readonly properties: {};
10
+ readonly required: string[];
11
+ };
12
+ }, {
13
+ readonly name: "list_collection";
14
+ readonly description: string;
15
+ readonly inputSchema: {
16
+ readonly type: "object";
17
+ readonly properties: {
18
+ readonly collection: {
19
+ readonly type: "string";
20
+ readonly description: "Collection name, e.g. 'posts', 'products'";
21
+ };
22
+ readonly limit: {
23
+ readonly type: "number";
24
+ readonly description: "Max results. Default 20, max 100.";
25
+ };
26
+ readonly offset: {
27
+ readonly type: "number";
28
+ readonly description: "Pagination offset. Default 0.";
29
+ };
30
+ readonly sort: {
31
+ readonly type: "string";
32
+ readonly enum: readonly ["date_desc", "date_asc", "title_asc"];
33
+ readonly description: "Sort order. Default: date_desc.";
34
+ };
35
+ };
36
+ readonly required: string[];
37
+ };
38
+ }, {
39
+ readonly name: "search_content";
40
+ readonly description: string;
41
+ readonly inputSchema: {
42
+ readonly type: "object";
43
+ readonly properties: {
44
+ readonly query: {
45
+ readonly type: "string";
46
+ readonly description: "Search query.";
47
+ };
48
+ readonly collection: {
49
+ readonly type: "string";
50
+ readonly description: "Optional: limit search to this collection.";
51
+ };
52
+ readonly limit: {
53
+ readonly type: "number";
54
+ readonly description: "Max results. Default 10, max 50.";
55
+ };
56
+ };
57
+ readonly required: string[];
58
+ };
59
+ }, {
60
+ readonly name: "get_page";
61
+ readonly description: string;
62
+ readonly inputSchema: {
63
+ readonly type: "object";
64
+ readonly properties: {
65
+ readonly slug: {
66
+ readonly type: "string";
67
+ readonly description: "Document slug, e.g. 'getting-started'.";
68
+ };
69
+ readonly collection: {
70
+ readonly type: "string";
71
+ readonly description: "Optional: collection to scope the lookup.";
72
+ };
73
+ };
74
+ readonly required: string[];
75
+ };
76
+ }, {
77
+ readonly name: "get_schema";
78
+ readonly description: "Returns the field schema for a collection, describing all available fields and their types.";
79
+ readonly inputSchema: {
80
+ readonly type: "object";
81
+ readonly properties: {
82
+ readonly collection: {
83
+ readonly type: "string";
84
+ readonly description: "Collection name.";
85
+ };
86
+ };
87
+ readonly required: string[];
88
+ };
89
+ }, {
90
+ readonly name: "export_all";
91
+ readonly description: string;
92
+ readonly inputSchema: {
93
+ readonly type: "object";
94
+ readonly properties: {
95
+ readonly include_body: {
96
+ readonly type: "boolean";
97
+ readonly description: "Include full body (true) or metadata only (false). Default: true.";
98
+ };
99
+ };
100
+ readonly required: string[];
101
+ };
102
+ }, {
103
+ readonly name: "create_document";
104
+ readonly description: string;
105
+ readonly inputSchema: {
106
+ readonly type: "object";
107
+ readonly properties: {
108
+ readonly collection: {
109
+ readonly type: "string";
110
+ };
111
+ readonly fields: {
112
+ readonly type: "object";
113
+ readonly description: "Document fields matching the collection schema.";
114
+ };
115
+ readonly status: {
116
+ readonly type: "string";
117
+ readonly enum: readonly ["draft", "published"];
118
+ readonly description: "Initial status. Default: draft.";
119
+ };
120
+ };
121
+ readonly required: string[];
122
+ };
123
+ }, {
124
+ readonly name: "update_document";
125
+ readonly description: string;
126
+ readonly inputSchema: {
127
+ readonly type: "object";
128
+ readonly properties: {
129
+ readonly collection: {
130
+ readonly type: "string";
131
+ };
132
+ readonly slug: {
133
+ readonly type: "string";
134
+ };
135
+ readonly fields: {
136
+ readonly type: "object";
137
+ readonly description: "Fields to update.";
138
+ };
139
+ };
140
+ readonly required: string[];
141
+ };
142
+ }, {
143
+ readonly name: "publish_document";
144
+ readonly description: "Sets a document status to 'published'. Optionally triggers an immediate build.";
145
+ readonly inputSchema: {
146
+ readonly type: "object";
147
+ readonly properties: {
148
+ readonly collection: {
149
+ readonly type: "string";
150
+ };
151
+ readonly slug: {
152
+ readonly type: "string";
153
+ };
154
+ readonly auto_build: {
155
+ readonly type: "boolean";
156
+ readonly description: "Trigger site build after publishing. Default: false.";
157
+ };
158
+ };
159
+ readonly required: string[];
160
+ };
161
+ }, {
162
+ readonly name: "unpublish_document";
163
+ readonly description: "Sets a document back to draft status.";
164
+ readonly inputSchema: {
165
+ readonly type: "object";
166
+ readonly properties: {
167
+ readonly collection: {
168
+ readonly type: "string";
169
+ };
170
+ readonly slug: {
171
+ readonly type: "string";
172
+ };
173
+ };
174
+ readonly required: string[];
175
+ };
176
+ }, {
177
+ readonly name: "generate_with_ai";
178
+ readonly description: string;
179
+ readonly inputSchema: {
180
+ readonly type: "object";
181
+ readonly properties: {
182
+ readonly collection: {
183
+ readonly type: "string";
184
+ };
185
+ readonly intent: {
186
+ readonly type: "string";
187
+ readonly description: string;
188
+ };
189
+ readonly status: {
190
+ readonly type: "string";
191
+ readonly enum: readonly ["draft", "published"];
192
+ readonly description: "Status for the created document. Default: draft.";
193
+ };
194
+ };
195
+ readonly required: string[];
196
+ };
197
+ }, {
198
+ readonly name: "rewrite_field";
199
+ readonly description: string;
200
+ readonly inputSchema: {
201
+ readonly type: "object";
202
+ readonly properties: {
203
+ readonly collection: {
204
+ readonly type: "string";
205
+ };
206
+ readonly slug: {
207
+ readonly type: "string";
208
+ };
209
+ readonly field: {
210
+ readonly type: "string";
211
+ readonly description: "Field name to rewrite.";
212
+ };
213
+ readonly instruction: {
214
+ readonly type: "string";
215
+ readonly description: string;
216
+ };
217
+ };
218
+ readonly required: string[];
219
+ };
220
+ }, {
221
+ readonly name: "trigger_build";
222
+ readonly description: string;
223
+ readonly inputSchema: {
224
+ readonly type: "object";
225
+ readonly properties: {
226
+ readonly mode: {
227
+ readonly type: "string";
228
+ readonly enum: readonly ["full", "incremental"];
229
+ readonly description: "Build mode. Default: incremental.";
230
+ };
231
+ };
232
+ readonly required: string[];
233
+ };
234
+ }, {
235
+ readonly name: "list_drafts";
236
+ readonly description: "Lists all unpublished draft documents across all (or one) collection.";
237
+ readonly inputSchema: {
238
+ readonly type: "object";
239
+ readonly properties: {
240
+ readonly collection: {
241
+ readonly type: "string";
242
+ readonly description: "Optional: filter by collection.";
243
+ };
244
+ };
245
+ readonly required: string[];
246
+ };
247
+ }, {
248
+ readonly name: "get_version_history";
249
+ readonly description: "Returns revision history for a document.";
250
+ readonly inputSchema: {
251
+ readonly type: "object";
252
+ readonly properties: {
253
+ readonly collection: {
254
+ readonly type: "string";
255
+ };
256
+ readonly slug: {
257
+ readonly type: "string";
258
+ };
259
+ readonly limit: {
260
+ readonly type: "number";
261
+ readonly description: "Number of versions. Default 10.";
262
+ };
263
+ };
264
+ readonly required: string[];
265
+ };
266
+ }];
267
+ type AdminToolName = (typeof ADMIN_TOOLS)[number]["name"];
268
+ declare const TOOL_SCOPES: Record<AdminToolName, string[]>;
269
+
270
+ interface ApiKeyConfig {
271
+ key: string;
272
+ label: string;
273
+ scopes: string[];
274
+ }
275
+ declare function validateApiKey(authHeader: string | null | undefined, keys: ApiKeyConfig[]): {
276
+ authenticated: true;
277
+ label: string;
278
+ scopes: string[];
279
+ } | {
280
+ authenticated: false;
281
+ error: string;
282
+ };
283
+ declare function hasScope(userScopes: string[], required: string[]): boolean;
284
+
285
+ interface AuditEntry {
286
+ timestamp: string;
287
+ tool: string;
288
+ actor: string;
289
+ result: "success" | "error";
290
+ documentRef?: string;
291
+ error?: string;
292
+ }
293
+ declare function initAuditLog(dataDir: string): void;
294
+ declare function writeAudit(entry: AuditEntry): void;
295
+
296
+ interface AiGenerator {
297
+ generate(intent: string, collectionName: string): Promise<{
298
+ fields: Record<string, string>;
299
+ slug: string;
300
+ }>;
301
+ rewriteField(collection: string, slug: string, field: string, instruction: string, currentValue: string): Promise<string>;
302
+ }
303
+ interface AdminServerOptions {
304
+ content: ContentService;
305
+ config: CmsConfig;
306
+ /** Resolved scopes for this session — determined by auth middleware before connect */
307
+ scopes: string[];
308
+ /** Label identifying the API key / user for audit log */
309
+ actor: string;
310
+ /** Optional AI generator — if not provided, AI tools return a "not configured" error */
311
+ ai?: AiGenerator;
312
+ /** Called when a write tool needs to trigger a build */
313
+ onBuild?: (mode: "full" | "incremental") => Promise<{
314
+ ok: boolean;
315
+ message: string;
316
+ }>;
317
+ }
318
+ declare function createAdminMcpServer(opts: AdminServerOptions): Server;
319
+
320
+ export { ADMIN_TOOLS, type AdminServerOptions, type AdminToolName, type AiGenerator, type ApiKeyConfig, type AuditEntry, TOOL_SCOPES, createAdminMcpServer, hasScope, initAuditLog, validateApiKey, writeAudit };