@jgardner04/ghost-mcp-server 1.8.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgardner04/ghost-mcp-server",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "A Model Context Protocol (MCP) server for interacting with Ghost CMS via the Admin API",
5
5
  "author": "Jonathan Gardner",
6
6
  "type": "module",
@@ -903,6 +903,241 @@ server.tool(
903
903
  }
904
904
  );
905
905
 
906
+ // =============================================================================
907
+ // MEMBER TOOLS
908
+ // Member management for Ghost CMS subscribers
909
+ // =============================================================================
910
+
911
+ // Create Member Tool
912
+ server.tool(
913
+ 'ghost_create_member',
914
+ 'Creates a new member (subscriber) in Ghost CMS.',
915
+ {
916
+ email: z.string().email().describe('The email address of the member (required).'),
917
+ name: z.string().optional().describe('The name of the member.'),
918
+ note: z.string().optional().describe('A note about the member.'),
919
+ labels: z.array(z.string()).optional().describe('List of label names to assign to the member.'),
920
+ newsletters: z
921
+ .array(z.object({ id: z.string() }))
922
+ .optional()
923
+ .describe('List of newsletter objects with id field to subscribe the member to.'),
924
+ subscribed: z
925
+ .boolean()
926
+ .optional()
927
+ .describe('Whether the member is subscribed to emails. Defaults to true.'),
928
+ },
929
+ async (input) => {
930
+ console.error(`Executing tool: ghost_create_member with email: ${input.email}`);
931
+ try {
932
+ await loadServices();
933
+
934
+ const ghostServiceImproved = await import('./services/ghostServiceImproved.js');
935
+ const createdMember = await ghostServiceImproved.createMember(input);
936
+ console.error(`Member created successfully. Member ID: ${createdMember.id}`);
937
+
938
+ return {
939
+ content: [{ type: 'text', text: JSON.stringify(createdMember, null, 2) }],
940
+ };
941
+ } catch (error) {
942
+ console.error(`Error in ghost_create_member:`, error);
943
+ return {
944
+ content: [{ type: 'text', text: `Error creating member: ${error.message}` }],
945
+ isError: true,
946
+ };
947
+ }
948
+ }
949
+ );
950
+
951
+ // Update Member Tool
952
+ server.tool(
953
+ 'ghost_update_member',
954
+ 'Updates an existing member in Ghost CMS. All fields except id are optional.',
955
+ {
956
+ id: z.string().describe('The ID of the member to update.'),
957
+ email: z.string().email().optional().describe('New email address for the member.'),
958
+ name: z.string().optional().describe('New name for the member.'),
959
+ note: z.string().optional().describe('New note about the member.'),
960
+ labels: z
961
+ .array(z.string())
962
+ .optional()
963
+ .describe('New list of label names to assign to the member.'),
964
+ newsletters: z
965
+ .array(z.object({ id: z.string() }))
966
+ .optional()
967
+ .describe('New list of newsletter objects with id field to subscribe the member to.'),
968
+ },
969
+ async (input) => {
970
+ console.error(`Executing tool: ghost_update_member for member ID: ${input.id}`);
971
+ try {
972
+ await loadServices();
973
+
974
+ const { id, ...updateData } = input;
975
+
976
+ const ghostServiceImproved = await import('./services/ghostServiceImproved.js');
977
+ const updatedMember = await ghostServiceImproved.updateMember(id, updateData);
978
+ console.error(`Member updated successfully. Member ID: ${updatedMember.id}`);
979
+
980
+ return {
981
+ content: [{ type: 'text', text: JSON.stringify(updatedMember, null, 2) }],
982
+ };
983
+ } catch (error) {
984
+ console.error(`Error in ghost_update_member:`, error);
985
+ return {
986
+ content: [{ type: 'text', text: `Error updating member: ${error.message}` }],
987
+ isError: true,
988
+ };
989
+ }
990
+ }
991
+ );
992
+
993
+ // Delete Member Tool
994
+ server.tool(
995
+ 'ghost_delete_member',
996
+ 'Deletes a member from Ghost CMS by ID. This operation is permanent and cannot be undone.',
997
+ {
998
+ id: z.string().describe('The ID of the member to delete.'),
999
+ },
1000
+ async ({ id }) => {
1001
+ console.error(`Executing tool: ghost_delete_member for member ID: ${id}`);
1002
+ try {
1003
+ await loadServices();
1004
+
1005
+ const ghostServiceImproved = await import('./services/ghostServiceImproved.js');
1006
+ await ghostServiceImproved.deleteMember(id);
1007
+ console.error(`Member deleted successfully. Member ID: ${id}`);
1008
+
1009
+ return {
1010
+ content: [{ type: 'text', text: `Member ${id} has been successfully deleted.` }],
1011
+ };
1012
+ } catch (error) {
1013
+ console.error(`Error in ghost_delete_member:`, error);
1014
+ return {
1015
+ content: [{ type: 'text', text: `Error deleting member: ${error.message}` }],
1016
+ isError: true,
1017
+ };
1018
+ }
1019
+ }
1020
+ );
1021
+
1022
+ // Get Members Tool
1023
+ server.tool(
1024
+ 'ghost_get_members',
1025
+ 'Retrieves a list of members (subscribers) from Ghost CMS with optional filtering, pagination, and includes.',
1026
+ {
1027
+ limit: z
1028
+ .number()
1029
+ .min(1)
1030
+ .max(100)
1031
+ .optional()
1032
+ .describe('Number of members to retrieve (1-100). Default is 15.'),
1033
+ page: z.number().min(1).optional().describe('Page number for pagination (starts at 1).'),
1034
+ filter: z
1035
+ .string()
1036
+ .optional()
1037
+ .describe('Ghost NQL filter string (e.g., "status:free", "status:paid", "subscribed:true").'),
1038
+ order: z.string().optional().describe('Order string (e.g., "created_at desc", "email asc").'),
1039
+ include: z
1040
+ .string()
1041
+ .optional()
1042
+ .describe('Comma-separated list of related data to include (e.g., "labels,newsletters").'),
1043
+ },
1044
+ async (input) => {
1045
+ console.error(`Executing tool: ghost_get_members`);
1046
+ try {
1047
+ await loadServices();
1048
+
1049
+ const options = {};
1050
+ if (input.limit !== undefined) options.limit = input.limit;
1051
+ if (input.page !== undefined) options.page = input.page;
1052
+ if (input.filter !== undefined) options.filter = input.filter;
1053
+ if (input.order !== undefined) options.order = input.order;
1054
+ if (input.include !== undefined) options.include = input.include;
1055
+
1056
+ const ghostServiceImproved = await import('./services/ghostServiceImproved.js');
1057
+ const members = await ghostServiceImproved.getMembers(options);
1058
+ console.error(`Retrieved ${members.length} members from Ghost.`);
1059
+
1060
+ return {
1061
+ content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
1062
+ };
1063
+ } catch (error) {
1064
+ console.error(`Error in ghost_get_members:`, error);
1065
+ return {
1066
+ content: [{ type: 'text', text: `Error retrieving members: ${error.message}` }],
1067
+ isError: true,
1068
+ };
1069
+ }
1070
+ }
1071
+ );
1072
+
1073
+ // Get Member Tool
1074
+ server.tool(
1075
+ 'ghost_get_member',
1076
+ 'Retrieves a single member from Ghost CMS by ID or email. Provide either id OR email.',
1077
+ {
1078
+ id: z.string().optional().describe('The ID of the member to retrieve.'),
1079
+ email: z.string().email().optional().describe('The email of the member to retrieve.'),
1080
+ },
1081
+ async ({ id, email }) => {
1082
+ console.error(`Executing tool: ghost_get_member for ${id ? `ID: ${id}` : `email: ${email}`}`);
1083
+ try {
1084
+ await loadServices();
1085
+
1086
+ const ghostServiceImproved = await import('./services/ghostServiceImproved.js');
1087
+ const member = await ghostServiceImproved.getMember({ id, email });
1088
+ console.error(`Retrieved member: ${member.email} (ID: ${member.id})`);
1089
+
1090
+ return {
1091
+ content: [{ type: 'text', text: JSON.stringify(member, null, 2) }],
1092
+ };
1093
+ } catch (error) {
1094
+ console.error(`Error in ghost_get_member:`, error);
1095
+ return {
1096
+ content: [{ type: 'text', text: `Error retrieving member: ${error.message}` }],
1097
+ isError: true,
1098
+ };
1099
+ }
1100
+ }
1101
+ );
1102
+
1103
+ // Search Members Tool
1104
+ server.tool(
1105
+ 'ghost_search_members',
1106
+ 'Searches for members by name or email in Ghost CMS.',
1107
+ {
1108
+ query: z.string().min(1).describe('Search query to match against member name or email.'),
1109
+ limit: z
1110
+ .number()
1111
+ .min(1)
1112
+ .max(50)
1113
+ .optional()
1114
+ .describe('Maximum number of results to return (1-50). Default is 15.'),
1115
+ },
1116
+ async ({ query, limit }) => {
1117
+ console.error(`Executing tool: ghost_search_members with query: ${query}`);
1118
+ try {
1119
+ await loadServices();
1120
+
1121
+ const options = {};
1122
+ if (limit !== undefined) options.limit = limit;
1123
+
1124
+ const ghostServiceImproved = await import('./services/ghostServiceImproved.js');
1125
+ const members = await ghostServiceImproved.searchMembers(query, options);
1126
+ console.error(`Found ${members.length} members matching "${query}".`);
1127
+
1128
+ return {
1129
+ content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
1130
+ };
1131
+ } catch (error) {
1132
+ console.error(`Error in ghost_search_members:`, error);
1133
+ return {
1134
+ content: [{ type: 'text', text: `Error searching members: ${error.message}` }],
1135
+ isError: true,
1136
+ };
1137
+ }
1138
+ }
1139
+ );
1140
+
906
1141
  // =============================================================================
907
1142
  // NEWSLETTER TOOLS
908
1143
  // =============================================================================
@@ -1108,6 +1343,7 @@ async function main() {
1108
1343
  'Available tools: ghost_get_tags, ghost_create_tag, ghost_get_tag, ghost_update_tag, ghost_delete_tag, ghost_upload_image, ' +
1109
1344
  'ghost_create_post, ghost_get_posts, ghost_get_post, ghost_search_posts, ghost_update_post, ghost_delete_post, ' +
1110
1345
  'ghost_get_pages, ghost_get_page, ghost_create_page, ghost_update_page, ghost_delete_page, ghost_search_pages, ' +
1346
+ 'ghost_create_member, ghost_update_member, ghost_delete_member, ghost_get_members, ghost_get_member, ghost_search_members, ' +
1111
1347
  'ghost_get_newsletters, ghost_get_newsletter, ghost_create_newsletter, ghost_update_newsletter, ghost_delete_newsletter'
1112
1348
  );
1113
1349
  }