@jgardner04/ghost-mcp-server 1.13.4 → 1.13.5
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 +68 -0
- package/package.json +7 -3
- package/src/__tests__/helpers/testUtils.js +15 -1
- package/src/__tests__/mcp_server.test.js +69 -1
- package/src/__tests__/mcp_server_pages.test.js +23 -6
- package/src/mcp_server.js +393 -1143
- package/src/services/__tests__/createResourceService.test.js +468 -0
- package/src/services/__tests__/ghostServiceImproved.members.test.js +0 -3
- package/src/services/__tests__/ghostServiceImproved.newsletters.test.js +2 -2
- package/src/services/__tests__/ghostServiceImproved.pages.test.js +0 -3
- package/src/services/__tests__/ghostServiceImproved.posts.test.js +0 -1
- package/src/services/__tests__/ghostServiceImproved.tags.test.js +0 -3
- package/src/services/__tests__/ghostServiceImproved.tiers.test.js +3 -5
- package/src/services/createResourceService.js +138 -0
- package/src/services/ghostApiClient.js +240 -0
- package/src/services/ghostServiceImproved.js +76 -915
- package/src/services/images.js +27 -0
- package/src/services/members.js +127 -0
- package/src/services/newsletters.js +63 -0
- package/src/services/pages.js +116 -0
- package/src/services/posts.js +116 -0
- package/src/services/tags.js +118 -0
- package/src/services/tiers.js +72 -0
- package/src/services/validators.js +218 -0
package/src/mcp_server.js
CHANGED
|
@@ -83,6 +83,49 @@ const escapeNqlValue = (value) => {
|
|
|
83
83
|
return value.replace(/'/g, "''");
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Higher-order function that wraps a tool handler with standardized
|
|
88
|
+
* input validation, service loading, and error handling.
|
|
89
|
+
*
|
|
90
|
+
* Note: Each registerTool call passes the schema twice — once as `inputSchema`
|
|
91
|
+
* (MCP protocol metadata exposed to clients) and once here for runtime input
|
|
92
|
+
* validation via validateToolInput. These serve different purposes and both
|
|
93
|
+
* are required.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} toolName - The tool identifier (e.g., 'ghost_get_tags')
|
|
96
|
+
* @param {object} schema - Zod schema for input validation
|
|
97
|
+
* @param {Function} handler - Async function receiving validated input, returns MCP response
|
|
98
|
+
* @returns {Function} Wrapped async handler for server.registerTool
|
|
99
|
+
*/
|
|
100
|
+
const withErrorHandling = (toolName, schema, handler) => {
|
|
101
|
+
const zodContext = toolName.replace('ghost_', '').replace(/_/g, ' ');
|
|
102
|
+
return async (rawInput) => {
|
|
103
|
+
console.error(`Executing tool: ${toolName}`);
|
|
104
|
+
const validation = validateToolInput(schema, rawInput, toolName);
|
|
105
|
+
if (!validation.success) {
|
|
106
|
+
return validation.errorResponse;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await loadServices();
|
|
111
|
+
return await handler(validation.data);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(`Error in ${toolName}:`, error);
|
|
114
|
+
if (error.name === 'ZodError') {
|
|
115
|
+
const validationError = ValidationError.fromZod(error, zodContext);
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
content: [{ type: 'text', text: `Error in ${toolName}: ${error.message}` }],
|
|
123
|
+
isError: true,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
|
|
86
129
|
// Create server instance with new API
|
|
87
130
|
const server = new McpServer({
|
|
88
131
|
name: 'ghost-mcp-server',
|
|
@@ -116,58 +159,32 @@ server.registerTool(
|
|
|
116
159
|
'Retrieves a list of tags from Ghost CMS with pagination, filtering, sorting, and relation inclusion. Supports filtering by name, slug, visibility, or custom NQL filter expressions.',
|
|
117
160
|
inputSchema: getTagsSchema,
|
|
118
161
|
},
|
|
119
|
-
async (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
options.filter = filters.join('+');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const tags = await ghostService.getTags(options);
|
|
149
|
-
console.error(`Retrieved ${tags.length} tags from Ghost.`);
|
|
150
|
-
|
|
151
|
-
const result = tags;
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
155
|
-
};
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error(`Error in ghost_get_tags:`, error);
|
|
158
|
-
if (error.name === 'ZodError') {
|
|
159
|
-
const validationError = ValidationError.fromZod(error, 'Tags retrieval');
|
|
160
|
-
return {
|
|
161
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
162
|
-
isError: true,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
167
|
-
isError: true,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
}
|
|
162
|
+
withErrorHandling('ghost_get_tags', getTagsSchema, async (input) => {
|
|
163
|
+
// Build options object with provided parameters
|
|
164
|
+
const options = {};
|
|
165
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
166
|
+
if (input.page !== undefined) options.page = input.page;
|
|
167
|
+
if (input.order !== undefined) options.order = input.order;
|
|
168
|
+
if (input.include !== undefined) options.include = input.include;
|
|
169
|
+
|
|
170
|
+
// Build filter string from individual filter parameters
|
|
171
|
+
const filters = [];
|
|
172
|
+
if (input.name) filters.push(`name:'${escapeNqlValue(input.name)}'`);
|
|
173
|
+
if (input.slug) filters.push(`slug:'${escapeNqlValue(input.slug)}'`);
|
|
174
|
+
if (input.visibility) filters.push(`visibility:'${input.visibility}'`); // visibility is enum-validated, no escaping needed
|
|
175
|
+
if (input.filter) filters.push(input.filter);
|
|
176
|
+
|
|
177
|
+
if (filters.length > 0) {
|
|
178
|
+
options.filter = filters.join('+');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const tags = await ghostService.getTags(options);
|
|
182
|
+
console.error(`Retrieved ${tags.length} tags from Ghost.`);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
content: [{ type: 'text', text: JSON.stringify(tags, null, 2) }],
|
|
186
|
+
};
|
|
187
|
+
})
|
|
171
188
|
);
|
|
172
189
|
|
|
173
190
|
// Create Tag Tool
|
|
@@ -177,37 +194,14 @@ server.registerTool(
|
|
|
177
194
|
description: 'Creates a new tag in Ghost CMS.',
|
|
178
195
|
inputSchema: createTagSchema,
|
|
179
196
|
},
|
|
180
|
-
async (
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
return validation.errorResponse;
|
|
184
|
-
}
|
|
185
|
-
const input = validation.data;
|
|
186
|
-
|
|
187
|
-
console.error(`Executing tool: ghost_create_tag with name: ${input.name}`);
|
|
188
|
-
try {
|
|
189
|
-
await loadServices();
|
|
190
|
-
const createdTag = await ghostService.createTag(input);
|
|
191
|
-
console.error(`Tag created successfully. Tag ID: ${createdTag.id}`);
|
|
197
|
+
withErrorHandling('ghost_create_tag', createTagSchema, async (input) => {
|
|
198
|
+
const createdTag = await ghostService.createTag(input);
|
|
199
|
+
console.error(`Tag created successfully. Tag ID: ${createdTag.id}`);
|
|
192
200
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
console.error(`Error in ghost_create_tag:`, error);
|
|
198
|
-
if (error.name === 'ZodError') {
|
|
199
|
-
const validationError = ValidationError.fromZod(error, 'Tag creation');
|
|
200
|
-
return {
|
|
201
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
202
|
-
isError: true,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
return {
|
|
206
|
-
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
207
|
-
isError: true,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
}
|
|
201
|
+
return {
|
|
202
|
+
content: [{ type: 'text', text: JSON.stringify(createdTag, null, 2) }],
|
|
203
|
+
};
|
|
204
|
+
})
|
|
211
205
|
);
|
|
212
206
|
|
|
213
207
|
// Get Tag Tool
|
|
@@ -217,42 +211,22 @@ server.registerTool(
|
|
|
217
211
|
description: 'Retrieves a single tag from Ghost CMS by ID or slug.',
|
|
218
212
|
inputSchema: getTagSchema,
|
|
219
213
|
},
|
|
220
|
-
async (
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
return validation.errorResponse;
|
|
224
|
-
}
|
|
225
|
-
const { id, slug, include } = validation.data;
|
|
226
|
-
|
|
227
|
-
console.error(`Executing tool: ghost_get_tag`);
|
|
228
|
-
try {
|
|
229
|
-
await loadServices();
|
|
214
|
+
withErrorHandling('ghost_get_tag', getTagSchema, async (input) => {
|
|
215
|
+
const options = {};
|
|
216
|
+
if (input.include !== undefined) options.include = input.include;
|
|
230
217
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
218
|
+
if (!input.id && !input.slug) {
|
|
219
|
+
throw new Error('Either id or slug is required');
|
|
220
|
+
}
|
|
221
|
+
const identifier = input.id || `slug/${input.slug}`;
|
|
234
222
|
|
|
235
|
-
|
|
236
|
-
|
|
223
|
+
const tag = await ghostService.getTag(identifier, options);
|
|
224
|
+
console.error(`Retrieved tag: ${tag.name} (ID: ${tag.id})`);
|
|
237
225
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
console.error(`Error in ghost_get_tag:`, error);
|
|
243
|
-
if (error.name === 'ZodError') {
|
|
244
|
-
const validationError = ValidationError.fromZod(error, 'Tag retrieval');
|
|
245
|
-
return {
|
|
246
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
247
|
-
isError: true,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
return {
|
|
251
|
-
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
252
|
-
isError: true,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
}
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: 'text', text: JSON.stringify(tag, null, 2) }],
|
|
228
|
+
};
|
|
229
|
+
})
|
|
256
230
|
);
|
|
257
231
|
|
|
258
232
|
// Update Tag Tool
|
|
@@ -262,90 +236,34 @@ server.registerTool(
|
|
|
262
236
|
description: 'Updates an existing tag in Ghost CMS.',
|
|
263
237
|
inputSchema: updateTagInputSchema,
|
|
264
238
|
},
|
|
265
|
-
async (
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (!input.id) {
|
|
275
|
-
throw new Error('Tag ID is required');
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
await loadServices();
|
|
279
|
-
|
|
280
|
-
// Build update data object with only provided fields (exclude id from update data)
|
|
281
|
-
const { id, ...updateData } = input;
|
|
282
|
-
|
|
283
|
-
const updatedTag = await ghostService.updateTag(id, updateData);
|
|
284
|
-
console.error(`Tag updated successfully. Tag ID: ${updatedTag.id}`);
|
|
285
|
-
|
|
286
|
-
return {
|
|
287
|
-
content: [{ type: 'text', text: JSON.stringify(updatedTag, null, 2) }],
|
|
288
|
-
};
|
|
289
|
-
} catch (error) {
|
|
290
|
-
console.error(`Error in ghost_update_tag:`, error);
|
|
291
|
-
if (error.name === 'ZodError') {
|
|
292
|
-
const validationError = ValidationError.fromZod(error, 'Tag update');
|
|
293
|
-
return {
|
|
294
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
295
|
-
isError: true,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
return {
|
|
299
|
-
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
300
|
-
isError: true,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
239
|
+
withErrorHandling('ghost_update_tag', updateTagInputSchema, async (input) => {
|
|
240
|
+
const { id, ...updateData } = input;
|
|
241
|
+
const updatedTag = await ghostService.updateTag(id, updateData);
|
|
242
|
+
console.error(`Tag updated successfully. Tag ID: ${updatedTag.id}`);
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
content: [{ type: 'text', text: JSON.stringify(updatedTag, null, 2) }],
|
|
246
|
+
};
|
|
247
|
+
})
|
|
304
248
|
);
|
|
305
249
|
|
|
306
250
|
// Delete Tag Tool
|
|
307
251
|
server.registerTool(
|
|
308
252
|
'ghost_delete_tag',
|
|
309
253
|
{
|
|
310
|
-
description:
|
|
254
|
+
description:
|
|
255
|
+
'Deletes a tag from Ghost CMS by ID. This operation is permanent and cannot be undone.',
|
|
311
256
|
inputSchema: deleteTagSchema,
|
|
312
257
|
},
|
|
313
|
-
async (
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (!id) {
|
|
323
|
-
throw new Error('Tag ID is required');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
await loadServices();
|
|
327
|
-
|
|
328
|
-
await ghostService.deleteTag(id);
|
|
329
|
-
console.error(`Tag deleted successfully. Tag ID: ${id}`);
|
|
330
|
-
|
|
331
|
-
return {
|
|
332
|
-
content: [{ type: 'text', text: `Tag with ID ${id} has been successfully deleted.` }],
|
|
333
|
-
};
|
|
334
|
-
} catch (error) {
|
|
335
|
-
console.error(`Error in ghost_delete_tag:`, error);
|
|
336
|
-
if (error.name === 'ZodError') {
|
|
337
|
-
const validationError = ValidationError.fromZod(error, 'Tag deletion');
|
|
338
|
-
return {
|
|
339
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
340
|
-
isError: true,
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
return {
|
|
344
|
-
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
345
|
-
isError: true,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
}
|
|
258
|
+
withErrorHandling('ghost_delete_tag', deleteTagSchema, async (input) => {
|
|
259
|
+
const { id } = input;
|
|
260
|
+
await ghostService.deleteTag(id);
|
|
261
|
+
console.error(`Tag deleted successfully. Tag ID: ${id}`);
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
content: [{ type: 'text', text: `Tag ${id} has been successfully deleted.` }],
|
|
265
|
+
};
|
|
266
|
+
})
|
|
349
267
|
);
|
|
350
268
|
|
|
351
269
|
// --- Image Schema ---
|
|
@@ -357,7 +275,7 @@ const uploadImageSchema = z.object({
|
|
|
357
275
|
}),
|
|
358
276
|
});
|
|
359
277
|
|
|
360
|
-
// Upload Image Tool
|
|
278
|
+
// Upload Image Tool — unique handler with finally-clause cleanup
|
|
361
279
|
server.registerTool(
|
|
362
280
|
'ghost_upload_image',
|
|
363
281
|
{
|
|
@@ -486,37 +404,14 @@ server.registerTool(
|
|
|
486
404
|
description: 'Creates a new post in Ghost CMS.',
|
|
487
405
|
inputSchema: createPostSchema,
|
|
488
406
|
},
|
|
489
|
-
async (
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
return validation.errorResponse;
|
|
493
|
-
}
|
|
494
|
-
const input = validation.data;
|
|
407
|
+
withErrorHandling('ghost_create_post', createPostSchema, async (input) => {
|
|
408
|
+
const createdPost = await postService.createPostService(input);
|
|
409
|
+
console.error(`Post created successfully. Post ID: ${createdPost.id}`);
|
|
495
410
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
console.error(`Post created successfully. Post ID: ${createdPost.id}`);
|
|
501
|
-
|
|
502
|
-
return {
|
|
503
|
-
content: [{ type: 'text', text: JSON.stringify(createdPost, null, 2) }],
|
|
504
|
-
};
|
|
505
|
-
} catch (error) {
|
|
506
|
-
console.error(`Error in ghost_create_post:`, error);
|
|
507
|
-
if (error.name === 'ZodError') {
|
|
508
|
-
const validationError = ValidationError.fromZod(error, 'Post creation');
|
|
509
|
-
return {
|
|
510
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
511
|
-
isError: true,
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
return {
|
|
515
|
-
content: [{ type: 'text', text: `Error creating post: ${error.message}` }],
|
|
516
|
-
isError: true,
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
}
|
|
411
|
+
return {
|
|
412
|
+
content: [{ type: 'text', text: JSON.stringify(createdPost, null, 2) }],
|
|
413
|
+
};
|
|
414
|
+
})
|
|
520
415
|
);
|
|
521
416
|
|
|
522
417
|
// Get Posts Tool
|
|
@@ -527,49 +422,25 @@ server.registerTool(
|
|
|
527
422
|
'Retrieves a list of posts from Ghost CMS with pagination, filtering, and sorting options.',
|
|
528
423
|
inputSchema: getPostsSchema,
|
|
529
424
|
},
|
|
530
|
-
async (
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if (input.fields !== undefined) options.fields = input.fields;
|
|
550
|
-
if (input.formats !== undefined) options.formats = input.formats;
|
|
551
|
-
|
|
552
|
-
const posts = await ghostService.getPosts(options);
|
|
553
|
-
console.error(`Retrieved ${posts.length} posts from Ghost.`);
|
|
554
|
-
|
|
555
|
-
return {
|
|
556
|
-
content: [{ type: 'text', text: JSON.stringify(posts, null, 2) }],
|
|
557
|
-
};
|
|
558
|
-
} catch (error) {
|
|
559
|
-
console.error(`Error in ghost_get_posts:`, error);
|
|
560
|
-
if (error.name === 'ZodError') {
|
|
561
|
-
const validationError = ValidationError.fromZod(error, 'Posts retrieval');
|
|
562
|
-
return {
|
|
563
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
564
|
-
isError: true,
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
return {
|
|
568
|
-
content: [{ type: 'text', text: `Error retrieving posts: ${error.message}` }],
|
|
569
|
-
isError: true,
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
}
|
|
425
|
+
withErrorHandling('ghost_get_posts', getPostsSchema, async (input) => {
|
|
426
|
+
// Build options object with provided parameters
|
|
427
|
+
const options = {};
|
|
428
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
429
|
+
if (input.page !== undefined) options.page = input.page;
|
|
430
|
+
if (input.status !== undefined) options.status = input.status;
|
|
431
|
+
if (input.include !== undefined) options.include = input.include;
|
|
432
|
+
if (input.filter !== undefined) options.filter = input.filter;
|
|
433
|
+
if (input.order !== undefined) options.order = input.order;
|
|
434
|
+
if (input.fields !== undefined) options.fields = input.fields;
|
|
435
|
+
if (input.formats !== undefined) options.formats = input.formats;
|
|
436
|
+
|
|
437
|
+
const posts = await ghostService.getPosts(options);
|
|
438
|
+
console.error(`Retrieved ${posts.length} posts from Ghost.`);
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
content: [{ type: 'text', text: JSON.stringify(posts, null, 2) }],
|
|
442
|
+
};
|
|
443
|
+
})
|
|
573
444
|
);
|
|
574
445
|
|
|
575
446
|
// Get Post Tool
|
|
@@ -579,45 +450,24 @@ server.registerTool(
|
|
|
579
450
|
description: 'Retrieves a single post from Ghost CMS by ID or slug.',
|
|
580
451
|
inputSchema: getPostSchema,
|
|
581
452
|
},
|
|
582
|
-
async (
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}
|
|
587
|
-
const input = validation.data;
|
|
588
|
-
|
|
589
|
-
console.error(`Executing tool: ghost_get_post`);
|
|
590
|
-
try {
|
|
591
|
-
await loadServices();
|
|
453
|
+
withErrorHandling('ghost_get_post', getPostSchema, async (input) => {
|
|
454
|
+
// Build options object
|
|
455
|
+
const options = {};
|
|
456
|
+
if (input.include !== undefined) options.include = input.include;
|
|
592
457
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
const identifier = input.id || `slug/${input.slug}`;
|
|
458
|
+
// Determine identifier (prefer ID over slug)
|
|
459
|
+
if (!input.id && !input.slug) {
|
|
460
|
+
throw new Error('Either id or slug is required');
|
|
461
|
+
}
|
|
462
|
+
const identifier = input.id || `slug/${input.slug}`;
|
|
599
463
|
|
|
600
|
-
|
|
601
|
-
|
|
464
|
+
const post = await ghostService.getPost(identifier, options);
|
|
465
|
+
console.error(`Retrieved post: ${post.title} (ID: ${post.id})`);
|
|
602
466
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
console.error(`Error in ghost_get_post:`, error);
|
|
608
|
-
if (error.name === 'ZodError') {
|
|
609
|
-
const validationError = ValidationError.fromZod(error, 'Post retrieval');
|
|
610
|
-
return {
|
|
611
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
612
|
-
isError: true,
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
return {
|
|
616
|
-
content: [{ type: 'text', text: `Error retrieving post: ${error.message}` }],
|
|
617
|
-
isError: true,
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
}
|
|
467
|
+
return {
|
|
468
|
+
content: [{ type: 'text', text: JSON.stringify(post, null, 2) }],
|
|
469
|
+
};
|
|
470
|
+
})
|
|
621
471
|
);
|
|
622
472
|
|
|
623
473
|
// Search Posts Tool
|
|
@@ -627,43 +477,19 @@ server.registerTool(
|
|
|
627
477
|
description: 'Search for posts in Ghost CMS by query string with optional status filtering.',
|
|
628
478
|
inputSchema: searchPostsSchema,
|
|
629
479
|
},
|
|
630
|
-
async (
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
console.error(`
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
if (input.status !== undefined) options.status = input.status;
|
|
644
|
-
if (input.limit !== undefined) options.limit = input.limit;
|
|
645
|
-
|
|
646
|
-
const posts = await ghostService.searchPosts(input.query, options);
|
|
647
|
-
console.error(`Found ${posts.length} posts matching "${input.query}".`);
|
|
648
|
-
|
|
649
|
-
return {
|
|
650
|
-
content: [{ type: 'text', text: JSON.stringify(posts, null, 2) }],
|
|
651
|
-
};
|
|
652
|
-
} catch (error) {
|
|
653
|
-
console.error(`Error in ghost_search_posts:`, error);
|
|
654
|
-
if (error.name === 'ZodError') {
|
|
655
|
-
const validationError = ValidationError.fromZod(error, 'Post search');
|
|
656
|
-
return {
|
|
657
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
658
|
-
isError: true,
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
return {
|
|
662
|
-
content: [{ type: 'text', text: `Error searching posts: ${error.message}` }],
|
|
663
|
-
isError: true,
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
}
|
|
480
|
+
withErrorHandling('ghost_search_posts', searchPostsSchema, async (input) => {
|
|
481
|
+
// Build options object with provided parameters
|
|
482
|
+
const options = {};
|
|
483
|
+
if (input.status !== undefined) options.status = input.status;
|
|
484
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
485
|
+
|
|
486
|
+
const posts = await ghostService.searchPosts(input.query, options);
|
|
487
|
+
console.error(`Found ${posts.length} posts matching "${input.query}".`);
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
content: [{ type: 'text', text: JSON.stringify(posts, null, 2) }],
|
|
491
|
+
};
|
|
492
|
+
})
|
|
667
493
|
);
|
|
668
494
|
|
|
669
495
|
// Update Post Tool
|
|
@@ -674,42 +500,18 @@ server.registerTool(
|
|
|
674
500
|
'Updates an existing post in Ghost CMS. Can update title, content, status, tags, images, and SEO fields. Only the provided fields are changed; omitted fields remain unchanged. Note: tags and authors arrays are fully replaced, not merged with existing values.',
|
|
675
501
|
inputSchema: updatePostInputSchema,
|
|
676
502
|
},
|
|
677
|
-
async (
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return validation.errorResponse;
|
|
681
|
-
}
|
|
682
|
-
const input = validation.data;
|
|
503
|
+
withErrorHandling('ghost_update_post', updatePostInputSchema, async (input) => {
|
|
504
|
+
// Extract ID from input and build update data
|
|
505
|
+
const { id, ...updateData } = input;
|
|
683
506
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
await loadServices();
|
|
507
|
+
const updatedPost = await ghostService.updatePost(id, updateData);
|
|
508
|
+
console.error(`Post updated successfully. Post ID: ${updatedPost.id}`);
|
|
687
509
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
return {
|
|
695
|
-
content: [{ type: 'text', text: JSON.stringify(updatedPost, null, 2) }],
|
|
696
|
-
};
|
|
697
|
-
} catch (error) {
|
|
698
|
-
console.error(`Error in ghost_update_post:`, error);
|
|
699
|
-
if (error.name === 'ZodError') {
|
|
700
|
-
const validationError = ValidationError.fromZod(error, 'Post update');
|
|
701
|
-
return {
|
|
702
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
703
|
-
isError: true,
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
return {
|
|
707
|
-
content: [{ type: 'text', text: `Error updating post: ${error.message}` }],
|
|
708
|
-
isError: true,
|
|
709
|
-
};
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
);
|
|
510
|
+
return {
|
|
511
|
+
content: [{ type: 'text', text: JSON.stringify(updatedPost, null, 2) }],
|
|
512
|
+
};
|
|
513
|
+
})
|
|
514
|
+
);
|
|
713
515
|
|
|
714
516
|
// Delete Post Tool
|
|
715
517
|
server.registerTool(
|
|
@@ -719,38 +521,15 @@ server.registerTool(
|
|
|
719
521
|
'Deletes a post from Ghost CMS by ID. This operation is permanent and cannot be undone.',
|
|
720
522
|
inputSchema: deletePostSchema,
|
|
721
523
|
},
|
|
722
|
-
async (
|
|
723
|
-
const
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
await loadServices();
|
|
732
|
-
|
|
733
|
-
await ghostService.deletePost(id);
|
|
734
|
-
console.error(`Post deleted successfully. Post ID: ${id}`);
|
|
735
|
-
|
|
736
|
-
return {
|
|
737
|
-
content: [{ type: 'text', text: `Post ${id} has been successfully deleted.` }],
|
|
738
|
-
};
|
|
739
|
-
} catch (error) {
|
|
740
|
-
console.error(`Error in ghost_delete_post:`, error);
|
|
741
|
-
if (error.name === 'ZodError') {
|
|
742
|
-
const validationError = ValidationError.fromZod(error, 'Post deletion');
|
|
743
|
-
return {
|
|
744
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
745
|
-
isError: true,
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
return {
|
|
749
|
-
content: [{ type: 'text', text: `Error deleting post: ${error.message}` }],
|
|
750
|
-
isError: true,
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
}
|
|
524
|
+
withErrorHandling('ghost_delete_post', deletePostSchema, async (input) => {
|
|
525
|
+
const { id } = input;
|
|
526
|
+
await ghostService.deletePost(id);
|
|
527
|
+
console.error(`Post deleted successfully. Post ID: ${id}`);
|
|
528
|
+
|
|
529
|
+
return {
|
|
530
|
+
content: [{ type: 'text', text: `Post ${id} has been successfully deleted.` }],
|
|
531
|
+
};
|
|
532
|
+
})
|
|
754
533
|
);
|
|
755
534
|
|
|
756
535
|
// =============================================================================
|
|
@@ -804,47 +583,23 @@ server.registerTool(
|
|
|
804
583
|
'Retrieves a list of pages from Ghost CMS with pagination, filtering, and sorting options.',
|
|
805
584
|
inputSchema: pageQuerySchema,
|
|
806
585
|
},
|
|
807
|
-
async (
|
|
808
|
-
const
|
|
809
|
-
if (
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (input.formats !== undefined) options.formats = input.formats;
|
|
825
|
-
if (input.order !== undefined) options.order = input.order;
|
|
826
|
-
|
|
827
|
-
const pages = await ghostService.getPages(options);
|
|
828
|
-
console.error(`Retrieved ${pages.length} pages from Ghost.`);
|
|
829
|
-
|
|
830
|
-
return {
|
|
831
|
-
content: [{ type: 'text', text: JSON.stringify(pages, null, 2) }],
|
|
832
|
-
};
|
|
833
|
-
} catch (error) {
|
|
834
|
-
console.error(`Error in ghost_get_pages:`, error);
|
|
835
|
-
if (error.name === 'ZodError') {
|
|
836
|
-
const validationError = ValidationError.fromZod(error, 'Page query');
|
|
837
|
-
return {
|
|
838
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
839
|
-
isError: true,
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
return {
|
|
843
|
-
content: [{ type: 'text', text: `Error retrieving pages: ${error.message}` }],
|
|
844
|
-
isError: true,
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
}
|
|
586
|
+
withErrorHandling('ghost_get_pages', pageQuerySchema, async (input) => {
|
|
587
|
+
const options = {};
|
|
588
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
589
|
+
if (input.page !== undefined) options.page = input.page;
|
|
590
|
+
if (input.filter !== undefined) options.filter = input.filter;
|
|
591
|
+
if (input.include !== undefined) options.include = input.include;
|
|
592
|
+
if (input.fields !== undefined) options.fields = input.fields;
|
|
593
|
+
if (input.formats !== undefined) options.formats = input.formats;
|
|
594
|
+
if (input.order !== undefined) options.order = input.order;
|
|
595
|
+
|
|
596
|
+
const pages = await ghostService.getPages(options);
|
|
597
|
+
console.error(`Retrieved ${pages.length} pages from Ghost.`);
|
|
598
|
+
|
|
599
|
+
return {
|
|
600
|
+
content: [{ type: 'text', text: JSON.stringify(pages, null, 2) }],
|
|
601
|
+
};
|
|
602
|
+
})
|
|
848
603
|
);
|
|
849
604
|
|
|
850
605
|
// Get Page Tool
|
|
@@ -854,43 +609,22 @@ server.registerTool(
|
|
|
854
609
|
description: 'Retrieves a single page from Ghost CMS by ID or slug.',
|
|
855
610
|
inputSchema: getPageSchema,
|
|
856
611
|
},
|
|
857
|
-
async (
|
|
858
|
-
const
|
|
859
|
-
if (
|
|
860
|
-
return validation.errorResponse;
|
|
861
|
-
}
|
|
862
|
-
const input = validation.data;
|
|
863
|
-
|
|
864
|
-
console.error(`Executing tool: ghost_get_page`);
|
|
865
|
-
try {
|
|
866
|
-
await loadServices();
|
|
867
|
-
|
|
868
|
-
const options = {};
|
|
869
|
-
if (input.include !== undefined) options.include = input.include;
|
|
612
|
+
withErrorHandling('ghost_get_page', getPageSchema, async (input) => {
|
|
613
|
+
const options = {};
|
|
614
|
+
if (input.include !== undefined) options.include = input.include;
|
|
870
615
|
|
|
871
|
-
|
|
616
|
+
if (!input.id && !input.slug) {
|
|
617
|
+
throw new Error('Either id or slug is required');
|
|
618
|
+
}
|
|
619
|
+
const identifier = input.id || `slug/${input.slug}`;
|
|
872
620
|
|
|
873
|
-
|
|
874
|
-
|
|
621
|
+
const page = await ghostService.getPage(identifier, options);
|
|
622
|
+
console.error(`Retrieved page: ${page.title} (ID: ${page.id})`);
|
|
875
623
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
console.error(`Error in ghost_get_page:`, error);
|
|
881
|
-
if (error.name === 'ZodError') {
|
|
882
|
-
const validationError = ValidationError.fromZod(error, 'Get page');
|
|
883
|
-
return {
|
|
884
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
885
|
-
isError: true,
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
return {
|
|
889
|
-
content: [{ type: 'text', text: `Error retrieving page: ${error.message}` }],
|
|
890
|
-
isError: true,
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
}
|
|
624
|
+
return {
|
|
625
|
+
content: [{ type: 'text', text: JSON.stringify(page, null, 2) }],
|
|
626
|
+
};
|
|
627
|
+
})
|
|
894
628
|
);
|
|
895
629
|
|
|
896
630
|
// Create Page Tool
|
|
@@ -901,38 +635,14 @@ server.registerTool(
|
|
|
901
635
|
'Creates a new page in Ghost CMS. Note: Pages do NOT typically use tags (unlike posts).',
|
|
902
636
|
inputSchema: createPageSchema,
|
|
903
637
|
},
|
|
904
|
-
async (
|
|
905
|
-
const
|
|
906
|
-
|
|
907
|
-
return validation.errorResponse;
|
|
908
|
-
}
|
|
909
|
-
const input = validation.data;
|
|
910
|
-
|
|
911
|
-
console.error(`Executing tool: ghost_create_page with title: ${input.title}`);
|
|
912
|
-
try {
|
|
913
|
-
await loadServices();
|
|
914
|
-
|
|
915
|
-
const createdPage = await pageService.createPageService(input);
|
|
916
|
-
console.error(`Page created successfully. Page ID: ${createdPage.id}`);
|
|
638
|
+
withErrorHandling('ghost_create_page', createPageSchema, async (input) => {
|
|
639
|
+
const createdPage = await pageService.createPageService(input);
|
|
640
|
+
console.error(`Page created successfully. Page ID: ${createdPage.id}`);
|
|
917
641
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
console.error(`Error in ghost_create_page:`, error);
|
|
923
|
-
if (error.name === 'ZodError') {
|
|
924
|
-
const validationError = ValidationError.fromZod(error, 'Page creation');
|
|
925
|
-
return {
|
|
926
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
927
|
-
isError: true,
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
return {
|
|
931
|
-
content: [{ type: 'text', text: `Error creating page: ${error.message}` }],
|
|
932
|
-
isError: true,
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
}
|
|
642
|
+
return {
|
|
643
|
+
content: [{ type: 'text', text: JSON.stringify(createdPage, null, 2) }],
|
|
644
|
+
};
|
|
645
|
+
})
|
|
936
646
|
);
|
|
937
647
|
|
|
938
648
|
// Update Page Tool
|
|
@@ -943,40 +653,16 @@ server.registerTool(
|
|
|
943
653
|
'Updates an existing page in Ghost CMS. Can update title, content, status, images, and SEO fields. Only the provided fields are changed; omitted fields remain unchanged.',
|
|
944
654
|
inputSchema: updatePageInputSchema,
|
|
945
655
|
},
|
|
946
|
-
async (
|
|
947
|
-
const
|
|
948
|
-
if (!validation.success) {
|
|
949
|
-
return validation.errorResponse;
|
|
950
|
-
}
|
|
951
|
-
const input = validation.data;
|
|
952
|
-
|
|
953
|
-
console.error(`Executing tool: ghost_update_page for page ID: ${input.id}`);
|
|
954
|
-
try {
|
|
955
|
-
await loadServices();
|
|
656
|
+
withErrorHandling('ghost_update_page', updatePageInputSchema, async (input) => {
|
|
657
|
+
const { id, ...updateData } = input;
|
|
956
658
|
|
|
957
|
-
|
|
659
|
+
const updatedPage = await ghostService.updatePage(id, updateData);
|
|
660
|
+
console.error(`Page updated successfully. Page ID: ${updatedPage.id}`);
|
|
958
661
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
content: [{ type: 'text', text: JSON.stringify(updatedPage, null, 2) }],
|
|
964
|
-
};
|
|
965
|
-
} catch (error) {
|
|
966
|
-
console.error(`Error in ghost_update_page:`, error);
|
|
967
|
-
if (error.name === 'ZodError') {
|
|
968
|
-
const validationError = ValidationError.fromZod(error, 'Page update');
|
|
969
|
-
return {
|
|
970
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
971
|
-
isError: true,
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
return {
|
|
975
|
-
content: [{ type: 'text', text: `Error updating page: ${error.message}` }],
|
|
976
|
-
isError: true,
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
}
|
|
662
|
+
return {
|
|
663
|
+
content: [{ type: 'text', text: JSON.stringify(updatedPage, null, 2) }],
|
|
664
|
+
};
|
|
665
|
+
})
|
|
980
666
|
);
|
|
981
667
|
|
|
982
668
|
// Delete Page Tool
|
|
@@ -987,38 +673,15 @@ server.registerTool(
|
|
|
987
673
|
'Deletes a page from Ghost CMS by ID. This operation is permanent and cannot be undone.',
|
|
988
674
|
inputSchema: deletePageSchema,
|
|
989
675
|
},
|
|
990
|
-
async (
|
|
991
|
-
const
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
await loadServices();
|
|
1000
|
-
|
|
1001
|
-
await ghostService.deletePage(id);
|
|
1002
|
-
console.error(`Page deleted successfully. Page ID: ${id}`);
|
|
1003
|
-
|
|
1004
|
-
return {
|
|
1005
|
-
content: [{ type: 'text', text: `Page ${id} has been successfully deleted.` }],
|
|
1006
|
-
};
|
|
1007
|
-
} catch (error) {
|
|
1008
|
-
console.error(`Error in ghost_delete_page:`, error);
|
|
1009
|
-
if (error.name === 'ZodError') {
|
|
1010
|
-
const validationError = ValidationError.fromZod(error, 'Page deletion');
|
|
1011
|
-
return {
|
|
1012
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1013
|
-
isError: true,
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
|
-
return {
|
|
1017
|
-
content: [{ type: 'text', text: `Error deleting page: ${error.message}` }],
|
|
1018
|
-
isError: true,
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
676
|
+
withErrorHandling('ghost_delete_page', deletePageSchema, async (input) => {
|
|
677
|
+
const { id } = input;
|
|
678
|
+
await ghostService.deletePage(id);
|
|
679
|
+
console.error(`Page deleted successfully. Page ID: ${id}`);
|
|
680
|
+
|
|
681
|
+
return {
|
|
682
|
+
content: [{ type: 'text', text: `Page ${id} has been successfully deleted.` }],
|
|
683
|
+
};
|
|
684
|
+
})
|
|
1022
685
|
);
|
|
1023
686
|
|
|
1024
687
|
// Search Pages Tool
|
|
@@ -1028,42 +691,18 @@ server.registerTool(
|
|
|
1028
691
|
description: 'Search for pages in Ghost CMS by query string with optional status filtering.',
|
|
1029
692
|
inputSchema: searchPagesSchema,
|
|
1030
693
|
},
|
|
1031
|
-
async (
|
|
1032
|
-
const
|
|
1033
|
-
if (
|
|
1034
|
-
|
|
1035
|
-
}
|
|
1036
|
-
const input = validation.data;
|
|
694
|
+
withErrorHandling('ghost_search_pages', searchPagesSchema, async (input) => {
|
|
695
|
+
const options = {};
|
|
696
|
+
if (input.status !== undefined) options.status = input.status;
|
|
697
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
1037
698
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
await loadServices();
|
|
1041
|
-
|
|
1042
|
-
const options = {};
|
|
1043
|
-
if (input.status !== undefined) options.status = input.status;
|
|
1044
|
-
if (input.limit !== undefined) options.limit = input.limit;
|
|
1045
|
-
|
|
1046
|
-
const pages = await ghostService.searchPages(input.query, options);
|
|
1047
|
-
console.error(`Found ${pages.length} pages matching "${input.query}".`);
|
|
699
|
+
const pages = await ghostService.searchPages(input.query, options);
|
|
700
|
+
console.error(`Found ${pages.length} pages matching "${input.query}".`);
|
|
1048
701
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
console.error(`Error in ghost_search_pages:`, error);
|
|
1054
|
-
if (error.name === 'ZodError') {
|
|
1055
|
-
const validationError = ValidationError.fromZod(error, 'Page search');
|
|
1056
|
-
return {
|
|
1057
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1058
|
-
isError: true,
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
return {
|
|
1062
|
-
content: [{ type: 'text', text: `Error searching pages: ${error.message}` }],
|
|
1063
|
-
isError: true,
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
702
|
+
return {
|
|
703
|
+
content: [{ type: 'text', text: JSON.stringify(pages, null, 2) }],
|
|
704
|
+
};
|
|
705
|
+
})
|
|
1067
706
|
);
|
|
1068
707
|
|
|
1069
708
|
// =============================================================================
|
|
@@ -1104,38 +743,14 @@ server.registerTool(
|
|
|
1104
743
|
description: 'Creates a new member (subscriber) in Ghost CMS.',
|
|
1105
744
|
inputSchema: createMemberSchema,
|
|
1106
745
|
},
|
|
1107
|
-
async (
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
return validation.errorResponse;
|
|
1111
|
-
}
|
|
1112
|
-
const input = validation.data;
|
|
1113
|
-
|
|
1114
|
-
console.error(`Executing tool: ghost_create_member with email: ${input.email}`);
|
|
1115
|
-
try {
|
|
1116
|
-
await loadServices();
|
|
746
|
+
withErrorHandling('ghost_create_member', createMemberSchema, async (input) => {
|
|
747
|
+
const createdMember = await ghostService.createMember(input);
|
|
748
|
+
console.error(`Member created successfully. Member ID: ${createdMember.id}`);
|
|
1117
749
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
content: [{ type: 'text', text: JSON.stringify(createdMember, null, 2) }],
|
|
1123
|
-
};
|
|
1124
|
-
} catch (error) {
|
|
1125
|
-
console.error(`Error in ghost_create_member:`, error);
|
|
1126
|
-
if (error.name === 'ZodError') {
|
|
1127
|
-
const validationError = ValidationError.fromZod(error, 'Member creation');
|
|
1128
|
-
return {
|
|
1129
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1130
|
-
isError: true,
|
|
1131
|
-
};
|
|
1132
|
-
}
|
|
1133
|
-
return {
|
|
1134
|
-
content: [{ type: 'text', text: `Error creating member: ${error.message}` }],
|
|
1135
|
-
isError: true,
|
|
1136
|
-
};
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
750
|
+
return {
|
|
751
|
+
content: [{ type: 'text', text: JSON.stringify(createdMember, null, 2) }],
|
|
752
|
+
};
|
|
753
|
+
})
|
|
1139
754
|
);
|
|
1140
755
|
|
|
1141
756
|
// Update Member Tool
|
|
@@ -1145,40 +760,16 @@ server.registerTool(
|
|
|
1145
760
|
description: 'Updates an existing member in Ghost CMS. All fields except id are optional.',
|
|
1146
761
|
inputSchema: updateMemberInputSchema,
|
|
1147
762
|
},
|
|
1148
|
-
async (
|
|
1149
|
-
const
|
|
1150
|
-
if (!validation.success) {
|
|
1151
|
-
return validation.errorResponse;
|
|
1152
|
-
}
|
|
1153
|
-
const input = validation.data;
|
|
1154
|
-
|
|
1155
|
-
console.error(`Executing tool: ghost_update_member for member ID: ${input.id}`);
|
|
1156
|
-
try {
|
|
1157
|
-
await loadServices();
|
|
1158
|
-
|
|
1159
|
-
const { id, ...updateData } = input;
|
|
763
|
+
withErrorHandling('ghost_update_member', updateMemberInputSchema, async (input) => {
|
|
764
|
+
const { id, ...updateData } = input;
|
|
1160
765
|
|
|
1161
|
-
|
|
1162
|
-
|
|
766
|
+
const updatedMember = await ghostService.updateMember(id, updateData);
|
|
767
|
+
console.error(`Member updated successfully. Member ID: ${updatedMember.id}`);
|
|
1163
768
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
console.error(`Error in ghost_update_member:`, error);
|
|
1169
|
-
if (error.name === 'ZodError') {
|
|
1170
|
-
const validationError = ValidationError.fromZod(error, 'Member update');
|
|
1171
|
-
return {
|
|
1172
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1173
|
-
isError: true,
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
return {
|
|
1177
|
-
content: [{ type: 'text', text: `Error updating member: ${error.message}` }],
|
|
1178
|
-
isError: true,
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
769
|
+
return {
|
|
770
|
+
content: [{ type: 'text', text: JSON.stringify(updatedMember, null, 2) }],
|
|
771
|
+
};
|
|
772
|
+
})
|
|
1182
773
|
);
|
|
1183
774
|
|
|
1184
775
|
// Delete Member Tool
|
|
@@ -1189,38 +780,15 @@ server.registerTool(
|
|
|
1189
780
|
'Deletes a member from Ghost CMS by ID. This operation is permanent and cannot be undone.',
|
|
1190
781
|
inputSchema: deleteMemberSchema,
|
|
1191
782
|
},
|
|
1192
|
-
async (
|
|
1193
|
-
const
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
await loadServices();
|
|
1202
|
-
|
|
1203
|
-
await ghostService.deleteMember(id);
|
|
1204
|
-
console.error(`Member deleted successfully. Member ID: ${id}`);
|
|
1205
|
-
|
|
1206
|
-
return {
|
|
1207
|
-
content: [{ type: 'text', text: `Member ${id} has been successfully deleted.` }],
|
|
1208
|
-
};
|
|
1209
|
-
} catch (error) {
|
|
1210
|
-
console.error(`Error in ghost_delete_member:`, error);
|
|
1211
|
-
if (error.name === 'ZodError') {
|
|
1212
|
-
const validationError = ValidationError.fromZod(error, 'Member deletion');
|
|
1213
|
-
return {
|
|
1214
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1215
|
-
isError: true,
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
|
-
return {
|
|
1219
|
-
content: [{ type: 'text', text: `Error deleting member: ${error.message}` }],
|
|
1220
|
-
isError: true,
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
783
|
+
withErrorHandling('ghost_delete_member', deleteMemberSchema, async (input) => {
|
|
784
|
+
const { id } = input;
|
|
785
|
+
await ghostService.deleteMember(id);
|
|
786
|
+
console.error(`Member deleted successfully. Member ID: ${id}`);
|
|
787
|
+
|
|
788
|
+
return {
|
|
789
|
+
content: [{ type: 'text', text: `Member ${id} has been successfully deleted.` }],
|
|
790
|
+
};
|
|
791
|
+
})
|
|
1224
792
|
);
|
|
1225
793
|
|
|
1226
794
|
// Get Members Tool
|
|
@@ -1231,46 +799,22 @@ server.registerTool(
|
|
|
1231
799
|
'Retrieves a list of members (subscribers) from Ghost CMS with optional filtering, pagination, and includes.',
|
|
1232
800
|
inputSchema: getMembersSchema,
|
|
1233
801
|
},
|
|
1234
|
-
async (
|
|
1235
|
-
const
|
|
1236
|
-
if (
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
if (input.include !== undefined) options.include = input.include;
|
|
1251
|
-
|
|
1252
|
-
const members = await ghostService.getMembers(options);
|
|
1253
|
-
console.error(`Retrieved ${members.length} members from Ghost.`);
|
|
1254
|
-
|
|
1255
|
-
return {
|
|
1256
|
-
content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
|
|
1257
|
-
};
|
|
1258
|
-
} catch (error) {
|
|
1259
|
-
console.error(`Error in ghost_get_members:`, error);
|
|
1260
|
-
if (error.name === 'ZodError') {
|
|
1261
|
-
const validationError = ValidationError.fromZod(error, 'Member query');
|
|
1262
|
-
return {
|
|
1263
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1264
|
-
isError: true,
|
|
1265
|
-
};
|
|
1266
|
-
}
|
|
1267
|
-
return {
|
|
1268
|
-
content: [{ type: 'text', text: `Error retrieving members: ${error.message}` }],
|
|
1269
|
-
isError: true,
|
|
1270
|
-
};
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
);
|
|
802
|
+
withErrorHandling('ghost_get_members', getMembersSchema, async (input) => {
|
|
803
|
+
const options = {};
|
|
804
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
805
|
+
if (input.page !== undefined) options.page = input.page;
|
|
806
|
+
if (input.filter !== undefined) options.filter = input.filter;
|
|
807
|
+
if (input.order !== undefined) options.order = input.order;
|
|
808
|
+
if (input.include !== undefined) options.include = input.include;
|
|
809
|
+
|
|
810
|
+
const members = await ghostService.getMembers(options);
|
|
811
|
+
console.error(`Retrieved ${members.length} members from Ghost.`);
|
|
812
|
+
|
|
813
|
+
return {
|
|
814
|
+
content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
|
|
815
|
+
};
|
|
816
|
+
})
|
|
817
|
+
);
|
|
1274
818
|
|
|
1275
819
|
// Get Member Tool
|
|
1276
820
|
server.registerTool(
|
|
@@ -1280,38 +824,15 @@ server.registerTool(
|
|
|
1280
824
|
'Retrieves a single member from Ghost CMS by ID or email. Provide either id OR email.',
|
|
1281
825
|
inputSchema: getMemberSchema,
|
|
1282
826
|
},
|
|
1283
|
-
async (
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
await loadServices();
|
|
1293
|
-
|
|
1294
|
-
const member = await ghostService.getMember({ id, email });
|
|
1295
|
-
console.error(`Retrieved member: ${member.email} (ID: ${member.id})`);
|
|
1296
|
-
|
|
1297
|
-
return {
|
|
1298
|
-
content: [{ type: 'text', text: JSON.stringify(member, null, 2) }],
|
|
1299
|
-
};
|
|
1300
|
-
} catch (error) {
|
|
1301
|
-
console.error(`Error in ghost_get_member:`, error);
|
|
1302
|
-
if (error.name === 'ZodError') {
|
|
1303
|
-
const validationError = ValidationError.fromZod(error, 'Member lookup');
|
|
1304
|
-
return {
|
|
1305
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1306
|
-
isError: true,
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
return {
|
|
1310
|
-
content: [{ type: 'text', text: `Error retrieving member: ${error.message}` }],
|
|
1311
|
-
isError: true,
|
|
1312
|
-
};
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
827
|
+
withErrorHandling('ghost_get_member', getMemberSchema, async (input) => {
|
|
828
|
+
const { id, email } = input;
|
|
829
|
+
const member = await ghostService.getMember({ id, email });
|
|
830
|
+
console.error(`Retrieved member: ${member.email} (ID: ${member.id})`);
|
|
831
|
+
|
|
832
|
+
return {
|
|
833
|
+
content: [{ type: 'text', text: JSON.stringify(member, null, 2) }],
|
|
834
|
+
};
|
|
835
|
+
})
|
|
1315
836
|
);
|
|
1316
837
|
|
|
1317
838
|
// Search Members Tool
|
|
@@ -1321,41 +842,18 @@ server.registerTool(
|
|
|
1321
842
|
description: 'Searches for members by name or email in Ghost CMS.',
|
|
1322
843
|
inputSchema: searchMembersSchema,
|
|
1323
844
|
},
|
|
1324
|
-
async (
|
|
1325
|
-
const
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
}
|
|
1329
|
-
const { query, limit } = validation.data;
|
|
845
|
+
withErrorHandling('ghost_search_members', searchMembersSchema, async (input) => {
|
|
846
|
+
const { query, limit } = input;
|
|
847
|
+
const options = {};
|
|
848
|
+
if (limit !== undefined) options.limit = limit;
|
|
1330
849
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
await loadServices();
|
|
1334
|
-
|
|
1335
|
-
const options = {};
|
|
1336
|
-
if (limit !== undefined) options.limit = limit;
|
|
850
|
+
const members = await ghostService.searchMembers(query, options);
|
|
851
|
+
console.error(`Found ${members.length} members matching "${query}".`);
|
|
1337
852
|
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
|
|
1343
|
-
};
|
|
1344
|
-
} catch (error) {
|
|
1345
|
-
console.error(`Error in ghost_search_members:`, error);
|
|
1346
|
-
if (error.name === 'ZodError') {
|
|
1347
|
-
const validationError = ValidationError.fromZod(error, 'Member search');
|
|
1348
|
-
return {
|
|
1349
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1350
|
-
isError: true,
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
return {
|
|
1354
|
-
content: [{ type: 'text', text: `Error searching members: ${error.message}` }],
|
|
1355
|
-
isError: true,
|
|
1356
|
-
};
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
853
|
+
return {
|
|
854
|
+
content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
|
|
855
|
+
};
|
|
856
|
+
})
|
|
1359
857
|
);
|
|
1360
858
|
|
|
1361
859
|
// =============================================================================
|
|
@@ -1374,44 +872,20 @@ server.registerTool(
|
|
|
1374
872
|
description: 'Retrieves a list of newsletters from Ghost CMS with optional filtering.',
|
|
1375
873
|
inputSchema: newsletterQuerySchema,
|
|
1376
874
|
},
|
|
1377
|
-
async (
|
|
1378
|
-
const
|
|
1379
|
-
if (
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
if (input.filter !== undefined) options.filter = input.filter;
|
|
1392
|
-
if (input.order !== undefined) options.order = input.order;
|
|
1393
|
-
|
|
1394
|
-
const newsletters = await ghostService.getNewsletters(options);
|
|
1395
|
-
console.error(`Retrieved ${newsletters.length} newsletters from Ghost.`);
|
|
1396
|
-
|
|
1397
|
-
return {
|
|
1398
|
-
content: [{ type: 'text', text: JSON.stringify(newsletters, null, 2) }],
|
|
1399
|
-
};
|
|
1400
|
-
} catch (error) {
|
|
1401
|
-
console.error(`Error in ghost_get_newsletters:`, error);
|
|
1402
|
-
if (error.name === 'ZodError') {
|
|
1403
|
-
const validationError = ValidationError.fromZod(error, 'Newsletter query');
|
|
1404
|
-
return {
|
|
1405
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1406
|
-
isError: true,
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
return {
|
|
1410
|
-
content: [{ type: 'text', text: `Error retrieving newsletters: ${error.message}` }],
|
|
1411
|
-
isError: true,
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
875
|
+
withErrorHandling('ghost_get_newsletters', newsletterQuerySchema, async (input) => {
|
|
876
|
+
const options = {};
|
|
877
|
+
if (input.limit !== undefined) options.limit = input.limit;
|
|
878
|
+
if (input.page !== undefined) options.page = input.page;
|
|
879
|
+
if (input.filter !== undefined) options.filter = input.filter;
|
|
880
|
+
if (input.order !== undefined) options.order = input.order;
|
|
881
|
+
|
|
882
|
+
const newsletters = await ghostService.getNewsletters(options);
|
|
883
|
+
console.error(`Retrieved ${newsletters.length} newsletters from Ghost.`);
|
|
884
|
+
|
|
885
|
+
return {
|
|
886
|
+
content: [{ type: 'text', text: JSON.stringify(newsletters, null, 2) }],
|
|
887
|
+
};
|
|
888
|
+
})
|
|
1415
889
|
);
|
|
1416
890
|
|
|
1417
891
|
// Get Newsletter Tool
|
|
@@ -1421,38 +895,15 @@ server.registerTool(
|
|
|
1421
895
|
description: 'Retrieves a single newsletter from Ghost CMS by ID.',
|
|
1422
896
|
inputSchema: getNewsletterSchema,
|
|
1423
897
|
},
|
|
1424
|
-
async (
|
|
1425
|
-
const
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
await loadServices();
|
|
1434
|
-
|
|
1435
|
-
const newsletter = await ghostService.getNewsletter(id);
|
|
1436
|
-
console.error(`Retrieved newsletter: ${newsletter.name} (ID: ${newsletter.id})`);
|
|
1437
|
-
|
|
1438
|
-
return {
|
|
1439
|
-
content: [{ type: 'text', text: JSON.stringify(newsletter, null, 2) }],
|
|
1440
|
-
};
|
|
1441
|
-
} catch (error) {
|
|
1442
|
-
console.error(`Error in ghost_get_newsletter:`, error);
|
|
1443
|
-
if (error.name === 'ZodError') {
|
|
1444
|
-
const validationError = ValidationError.fromZod(error, 'Newsletter retrieval');
|
|
1445
|
-
return {
|
|
1446
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1447
|
-
isError: true,
|
|
1448
|
-
};
|
|
1449
|
-
}
|
|
1450
|
-
return {
|
|
1451
|
-
content: [{ type: 'text', text: `Error retrieving newsletter: ${error.message}` }],
|
|
1452
|
-
isError: true,
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
898
|
+
withErrorHandling('ghost_get_newsletter', getNewsletterSchema, async (input) => {
|
|
899
|
+
const { id } = input;
|
|
900
|
+
const newsletter = await ghostService.getNewsletter(id);
|
|
901
|
+
console.error(`Retrieved newsletter: ${newsletter.name} (ID: ${newsletter.id})`);
|
|
902
|
+
|
|
903
|
+
return {
|
|
904
|
+
content: [{ type: 'text', text: JSON.stringify(newsletter, null, 2) }],
|
|
905
|
+
};
|
|
906
|
+
})
|
|
1456
907
|
);
|
|
1457
908
|
|
|
1458
909
|
// Create Newsletter Tool
|
|
@@ -1463,42 +914,14 @@ server.registerTool(
|
|
|
1463
914
|
'Creates a new newsletter in Ghost CMS with customizable sender settings and display options.',
|
|
1464
915
|
inputSchema: createNewsletterSchema,
|
|
1465
916
|
},
|
|
1466
|
-
async (
|
|
1467
|
-
const
|
|
1468
|
-
|
|
1469
|
-
rawInput,
|
|
1470
|
-
'ghost_create_newsletter'
|
|
1471
|
-
);
|
|
1472
|
-
if (!validation.success) {
|
|
1473
|
-
return validation.errorResponse;
|
|
1474
|
-
}
|
|
1475
|
-
const input = validation.data;
|
|
1476
|
-
|
|
1477
|
-
console.error(`Executing tool: ghost_create_newsletter with name: ${input.name}`);
|
|
1478
|
-
try {
|
|
1479
|
-
await loadServices();
|
|
1480
|
-
|
|
1481
|
-
const createdNewsletter = await newsletterService.createNewsletterService(input);
|
|
1482
|
-
console.error(`Newsletter created successfully. Newsletter ID: ${createdNewsletter.id}`);
|
|
917
|
+
withErrorHandling('ghost_create_newsletter', createNewsletterSchema, async (input) => {
|
|
918
|
+
const createdNewsletter = await newsletterService.createNewsletterService(input);
|
|
919
|
+
console.error(`Newsletter created successfully. Newsletter ID: ${createdNewsletter.id}`);
|
|
1483
920
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
console.error(`Error in ghost_create_newsletter:`, error);
|
|
1489
|
-
if (error.name === 'ZodError') {
|
|
1490
|
-
const validationError = ValidationError.fromZod(error, 'Newsletter creation');
|
|
1491
|
-
return {
|
|
1492
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1493
|
-
isError: true,
|
|
1494
|
-
};
|
|
1495
|
-
}
|
|
1496
|
-
return {
|
|
1497
|
-
content: [{ type: 'text', text: `Error creating newsletter: ${error.message}` }],
|
|
1498
|
-
isError: true,
|
|
1499
|
-
};
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
921
|
+
return {
|
|
922
|
+
content: [{ type: 'text', text: JSON.stringify(createdNewsletter, null, 2) }],
|
|
923
|
+
};
|
|
924
|
+
})
|
|
1502
925
|
);
|
|
1503
926
|
|
|
1504
927
|
// Update Newsletter Tool
|
|
@@ -1509,44 +932,16 @@ server.registerTool(
|
|
|
1509
932
|
'Updates an existing newsletter in Ghost CMS. Can update name, description, sender settings, and display options.',
|
|
1510
933
|
inputSchema: updateNewsletterInputSchema,
|
|
1511
934
|
},
|
|
1512
|
-
async (
|
|
1513
|
-
const
|
|
1514
|
-
updateNewsletterInputSchema,
|
|
1515
|
-
rawInput,
|
|
1516
|
-
'ghost_update_newsletter'
|
|
1517
|
-
);
|
|
1518
|
-
if (!validation.success) {
|
|
1519
|
-
return validation.errorResponse;
|
|
1520
|
-
}
|
|
1521
|
-
const input = validation.data;
|
|
935
|
+
withErrorHandling('ghost_update_newsletter', updateNewsletterInputSchema, async (input) => {
|
|
936
|
+
const { id, ...updateData } = input;
|
|
1522
937
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
await loadServices();
|
|
1526
|
-
|
|
1527
|
-
const { id, ...updateData } = input;
|
|
938
|
+
const updatedNewsletter = await ghostService.updateNewsletter(id, updateData);
|
|
939
|
+
console.error(`Newsletter updated successfully. Newsletter ID: ${updatedNewsletter.id}`);
|
|
1528
940
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
content: [{ type: 'text', text: JSON.stringify(updatedNewsletter, null, 2) }],
|
|
1534
|
-
};
|
|
1535
|
-
} catch (error) {
|
|
1536
|
-
console.error(`Error in ghost_update_newsletter:`, error);
|
|
1537
|
-
if (error.name === 'ZodError') {
|
|
1538
|
-
const validationError = ValidationError.fromZod(error, 'Newsletter update');
|
|
1539
|
-
return {
|
|
1540
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1541
|
-
isError: true,
|
|
1542
|
-
};
|
|
1543
|
-
}
|
|
1544
|
-
return {
|
|
1545
|
-
content: [{ type: 'text', text: `Error updating newsletter: ${error.message}` }],
|
|
1546
|
-
isError: true,
|
|
1547
|
-
};
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
941
|
+
return {
|
|
942
|
+
content: [{ type: 'text', text: JSON.stringify(updatedNewsletter, null, 2) }],
|
|
943
|
+
};
|
|
944
|
+
})
|
|
1550
945
|
);
|
|
1551
946
|
|
|
1552
947
|
// Delete Newsletter Tool
|
|
@@ -1557,42 +952,15 @@ server.registerTool(
|
|
|
1557
952
|
'Deletes a newsletter from Ghost CMS by ID. This operation is permanent and cannot be undone.',
|
|
1558
953
|
inputSchema: deleteNewsletterSchema,
|
|
1559
954
|
},
|
|
1560
|
-
async (
|
|
1561
|
-
const
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
const { id } = validation.data;
|
|
1570
|
-
|
|
1571
|
-
console.error(`Executing tool: ghost_delete_newsletter for newsletter ID: ${id}`);
|
|
1572
|
-
try {
|
|
1573
|
-
await loadServices();
|
|
1574
|
-
|
|
1575
|
-
await ghostService.deleteNewsletter(id);
|
|
1576
|
-
console.error(`Newsletter deleted successfully. Newsletter ID: ${id}`);
|
|
1577
|
-
|
|
1578
|
-
return {
|
|
1579
|
-
content: [{ type: 'text', text: `Newsletter ${id} has been successfully deleted.` }],
|
|
1580
|
-
};
|
|
1581
|
-
} catch (error) {
|
|
1582
|
-
console.error(`Error in ghost_delete_newsletter:`, error);
|
|
1583
|
-
if (error.name === 'ZodError') {
|
|
1584
|
-
const validationError = ValidationError.fromZod(error, 'Newsletter deletion');
|
|
1585
|
-
return {
|
|
1586
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1587
|
-
isError: true,
|
|
1588
|
-
};
|
|
1589
|
-
}
|
|
1590
|
-
return {
|
|
1591
|
-
content: [{ type: 'text', text: `Error deleting newsletter: ${error.message}` }],
|
|
1592
|
-
isError: true,
|
|
1593
|
-
};
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
955
|
+
withErrorHandling('ghost_delete_newsletter', deleteNewsletterSchema, async (input) => {
|
|
956
|
+
const { id } = input;
|
|
957
|
+
await ghostService.deleteNewsletter(id);
|
|
958
|
+
console.error(`Newsletter deleted successfully. Newsletter ID: ${id}`);
|
|
959
|
+
|
|
960
|
+
return {
|
|
961
|
+
content: [{ type: 'text', text: `Newsletter ${id} has been successfully deleted.` }],
|
|
962
|
+
};
|
|
963
|
+
})
|
|
1596
964
|
);
|
|
1597
965
|
|
|
1598
966
|
// --- Tier Tools ---
|
|
@@ -1610,38 +978,14 @@ server.registerTool(
|
|
|
1610
978
|
'Retrieves a list of tiers (membership levels) from Ghost CMS with optional filtering by type (free/paid).',
|
|
1611
979
|
inputSchema: tierQuerySchema,
|
|
1612
980
|
},
|
|
1613
|
-
async (
|
|
1614
|
-
const
|
|
1615
|
-
|
|
1616
|
-
return validation.errorResponse;
|
|
1617
|
-
}
|
|
1618
|
-
const input = validation.data;
|
|
981
|
+
withErrorHandling('ghost_get_tiers', tierQuerySchema, async (input) => {
|
|
982
|
+
const tiers = await ghostService.getTiers(input);
|
|
983
|
+
console.error(`Retrieved ${tiers.length} tiers`);
|
|
1619
984
|
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
const tiers = await ghostService.getTiers(input);
|
|
1625
|
-
console.error(`Retrieved ${tiers.length} tiers`);
|
|
1626
|
-
|
|
1627
|
-
return {
|
|
1628
|
-
content: [{ type: 'text', text: JSON.stringify(tiers, null, 2) }],
|
|
1629
|
-
};
|
|
1630
|
-
} catch (error) {
|
|
1631
|
-
console.error(`Error in ghost_get_tiers:`, error);
|
|
1632
|
-
if (error.name === 'ZodError') {
|
|
1633
|
-
const validationError = ValidationError.fromZod(error, 'Tier query');
|
|
1634
|
-
return {
|
|
1635
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1636
|
-
isError: true,
|
|
1637
|
-
};
|
|
1638
|
-
}
|
|
1639
|
-
return {
|
|
1640
|
-
content: [{ type: 'text', text: `Error getting tiers: ${error.message}` }],
|
|
1641
|
-
isError: true,
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
985
|
+
return {
|
|
986
|
+
content: [{ type: 'text', text: JSON.stringify(tiers, null, 2) }],
|
|
987
|
+
};
|
|
988
|
+
})
|
|
1645
989
|
);
|
|
1646
990
|
|
|
1647
991
|
// Get Tier Tool
|
|
@@ -1651,38 +995,15 @@ server.registerTool(
|
|
|
1651
995
|
description: 'Retrieves a single tier (membership level) from Ghost CMS by ID.',
|
|
1652
996
|
inputSchema: getTierSchema,
|
|
1653
997
|
},
|
|
1654
|
-
async (
|
|
1655
|
-
const
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
await loadServices();
|
|
1664
|
-
|
|
1665
|
-
const tier = await ghostService.getTier(id);
|
|
1666
|
-
console.error(`Tier retrieved successfully. Tier ID: ${tier.id}`);
|
|
1667
|
-
|
|
1668
|
-
return {
|
|
1669
|
-
content: [{ type: 'text', text: JSON.stringify(tier, null, 2) }],
|
|
1670
|
-
};
|
|
1671
|
-
} catch (error) {
|
|
1672
|
-
console.error(`Error in ghost_get_tier:`, error);
|
|
1673
|
-
if (error.name === 'ZodError') {
|
|
1674
|
-
const validationError = ValidationError.fromZod(error, 'Tier retrieval');
|
|
1675
|
-
return {
|
|
1676
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1677
|
-
isError: true,
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
|
-
return {
|
|
1681
|
-
content: [{ type: 'text', text: `Error getting tier: ${error.message}` }],
|
|
1682
|
-
isError: true,
|
|
1683
|
-
};
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
998
|
+
withErrorHandling('ghost_get_tier', getTierSchema, async (input) => {
|
|
999
|
+
const { id } = input;
|
|
1000
|
+
const tier = await ghostService.getTier(id);
|
|
1001
|
+
console.error(`Tier retrieved successfully. Tier ID: ${tier.id}`);
|
|
1002
|
+
|
|
1003
|
+
return {
|
|
1004
|
+
content: [{ type: 'text', text: JSON.stringify(tier, null, 2) }],
|
|
1005
|
+
};
|
|
1006
|
+
})
|
|
1686
1007
|
);
|
|
1687
1008
|
|
|
1688
1009
|
// Create Tier Tool
|
|
@@ -1692,38 +1013,14 @@ server.registerTool(
|
|
|
1692
1013
|
description: 'Creates a new tier (membership level) in Ghost CMS with pricing and benefits.',
|
|
1693
1014
|
inputSchema: createTierSchema,
|
|
1694
1015
|
},
|
|
1695
|
-
async (
|
|
1696
|
-
const
|
|
1697
|
-
|
|
1698
|
-
return validation.errorResponse;
|
|
1699
|
-
}
|
|
1700
|
-
const input = validation.data;
|
|
1016
|
+
withErrorHandling('ghost_create_tier', createTierSchema, async (input) => {
|
|
1017
|
+
const tier = await ghostService.createTier(input);
|
|
1018
|
+
console.error(`Tier created successfully. Tier ID: ${tier.id}`);
|
|
1701
1019
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
const tier = await ghostService.createTier(input);
|
|
1707
|
-
console.error(`Tier created successfully. Tier ID: ${tier.id}`);
|
|
1708
|
-
|
|
1709
|
-
return {
|
|
1710
|
-
content: [{ type: 'text', text: JSON.stringify(tier, null, 2) }],
|
|
1711
|
-
};
|
|
1712
|
-
} catch (error) {
|
|
1713
|
-
console.error(`Error in ghost_create_tier:`, error);
|
|
1714
|
-
if (error.name === 'ZodError') {
|
|
1715
|
-
const validationError = ValidationError.fromZod(error, 'Tier creation');
|
|
1716
|
-
return {
|
|
1717
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1718
|
-
isError: true,
|
|
1719
|
-
};
|
|
1720
|
-
}
|
|
1721
|
-
return {
|
|
1722
|
-
content: [{ type: 'text', text: `Error creating tier: ${error.message}` }],
|
|
1723
|
-
isError: true,
|
|
1724
|
-
};
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1020
|
+
return {
|
|
1021
|
+
content: [{ type: 'text', text: JSON.stringify(tier, null, 2) }],
|
|
1022
|
+
};
|
|
1023
|
+
})
|
|
1727
1024
|
);
|
|
1728
1025
|
|
|
1729
1026
|
// Update Tier Tool
|
|
@@ -1734,40 +1031,16 @@ server.registerTool(
|
|
|
1734
1031
|
'Updates an existing tier (membership level) in Ghost CMS. Can update pricing, benefits, and other tier properties.',
|
|
1735
1032
|
inputSchema: updateTierInputSchema,
|
|
1736
1033
|
},
|
|
1737
|
-
async (
|
|
1738
|
-
const
|
|
1739
|
-
if (!validation.success) {
|
|
1740
|
-
return validation.errorResponse;
|
|
1741
|
-
}
|
|
1742
|
-
const input = validation.data;
|
|
1034
|
+
withErrorHandling('ghost_update_tier', updateTierInputSchema, async (input) => {
|
|
1035
|
+
const { id, ...updateData } = input;
|
|
1743
1036
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
await loadServices();
|
|
1037
|
+
const updatedTier = await ghostService.updateTier(id, updateData);
|
|
1038
|
+
console.error(`Tier updated successfully. Tier ID: ${updatedTier.id}`);
|
|
1747
1039
|
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
return {
|
|
1754
|
-
content: [{ type: 'text', text: JSON.stringify(updatedTier, null, 2) }],
|
|
1755
|
-
};
|
|
1756
|
-
} catch (error) {
|
|
1757
|
-
console.error(`Error in ghost_update_tier:`, error);
|
|
1758
|
-
if (error.name === 'ZodError') {
|
|
1759
|
-
const validationError = ValidationError.fromZod(error, 'Tier update');
|
|
1760
|
-
return {
|
|
1761
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1762
|
-
isError: true,
|
|
1763
|
-
};
|
|
1764
|
-
}
|
|
1765
|
-
return {
|
|
1766
|
-
content: [{ type: 'text', text: `Error updating tier: ${error.message}` }],
|
|
1767
|
-
isError: true,
|
|
1768
|
-
};
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1040
|
+
return {
|
|
1041
|
+
content: [{ type: 'text', text: JSON.stringify(updatedTier, null, 2) }],
|
|
1042
|
+
};
|
|
1043
|
+
})
|
|
1771
1044
|
);
|
|
1772
1045
|
|
|
1773
1046
|
// Delete Tier Tool
|
|
@@ -1778,38 +1051,15 @@ server.registerTool(
|
|
|
1778
1051
|
'Deletes a tier (membership level) from Ghost CMS by ID. This operation is permanent and cannot be undone.',
|
|
1779
1052
|
inputSchema: deleteTierSchema,
|
|
1780
1053
|
},
|
|
1781
|
-
async (
|
|
1782
|
-
const
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
await loadServices();
|
|
1791
|
-
|
|
1792
|
-
await ghostService.deleteTier(id);
|
|
1793
|
-
console.error(`Tier deleted successfully. Tier ID: ${id}`);
|
|
1794
|
-
|
|
1795
|
-
return {
|
|
1796
|
-
content: [{ type: 'text', text: `Tier ${id} has been successfully deleted.` }],
|
|
1797
|
-
};
|
|
1798
|
-
} catch (error) {
|
|
1799
|
-
console.error(`Error in ghost_delete_tier:`, error);
|
|
1800
|
-
if (error.name === 'ZodError') {
|
|
1801
|
-
const validationError = ValidationError.fromZod(error, 'Tier deletion');
|
|
1802
|
-
return {
|
|
1803
|
-
content: [{ type: 'text', text: JSON.stringify(validationError.toJSON(), null, 2) }],
|
|
1804
|
-
isError: true,
|
|
1805
|
-
};
|
|
1806
|
-
}
|
|
1807
|
-
return {
|
|
1808
|
-
content: [{ type: 'text', text: `Error deleting tier: ${error.message}` }],
|
|
1809
|
-
isError: true,
|
|
1810
|
-
};
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1054
|
+
withErrorHandling('ghost_delete_tier', deleteTierSchema, async (input) => {
|
|
1055
|
+
const { id } = input;
|
|
1056
|
+
await ghostService.deleteTier(id);
|
|
1057
|
+
console.error(`Tier deleted successfully. Tier ID: ${id}`);
|
|
1058
|
+
|
|
1059
|
+
return {
|
|
1060
|
+
content: [{ type: 'text', text: `Tier ${id} has been successfully deleted.` }],
|
|
1061
|
+
};
|
|
1062
|
+
})
|
|
1813
1063
|
);
|
|
1814
1064
|
|
|
1815
1065
|
// --- Main Entry Point ---
|