pulsemcp-cms-admin-mcp-server 0.4.2 → 0.4.4

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.
@@ -65,7 +65,13 @@ export async function createPost(apiKey, baseUrl, params) {
65
65
  }
66
66
  if (response.status === 422) {
67
67
  const errorData = (await response.json());
68
- const errors = errorData.errors || ['Validation failed'];
68
+ // Handle both array format and single error string format from Rails
69
+ // Also handle empty arrays - an empty array should fall back to the default message
70
+ const errors = errorData.errors && errorData.errors.length > 0
71
+ ? errorData.errors
72
+ : errorData.error
73
+ ? [errorData.error]
74
+ : ['Unknown validation error'];
69
75
  throw new Error(`Validation failed: ${errors.join(', ')}`);
70
76
  }
71
77
  throw new Error(`Failed to create post: ${response.status} ${response.statusText}`);
@@ -69,53 +69,69 @@ export async function saveMCPImplementation(apiKey, baseUrl, id, params) {
69
69
  }
70
70
  // Remote endpoints
71
71
  // Rails expects nested attributes to use the _attributes suffix for has_many associations
72
- if (params.remote !== undefined && params.remote.length > 0) {
73
- params.remote.forEach((remote, index) => {
74
- if (remote.id !== undefined) {
75
- formData.append(`mcp_implementation[remote_attributes][${index}][id]`, remote.id.toString());
76
- }
77
- if (remote.url_direct !== undefined) {
78
- formData.append(`mcp_implementation[remote_attributes][${index}][url_direct]`, remote.url_direct);
79
- }
80
- if (remote.url_setup !== undefined) {
81
- formData.append(`mcp_implementation[remote_attributes][${index}][url_setup]`, remote.url_setup);
82
- }
83
- if (remote.transport !== undefined) {
84
- formData.append(`mcp_implementation[remote_attributes][${index}][transport]`, remote.transport);
85
- }
86
- if (remote.host_platform !== undefined) {
87
- formData.append(`mcp_implementation[remote_attributes][${index}][host_platform]`, remote.host_platform);
88
- }
89
- if (remote.host_infrastructure !== undefined) {
90
- formData.append(`mcp_implementation[remote_attributes][${index}][host_infrastructure]`, remote.host_infrastructure);
91
- }
92
- if (remote.authentication_method !== undefined) {
93
- formData.append(`mcp_implementation[remote_attributes][${index}][authentication_method]`, remote.authentication_method);
94
- }
95
- if (remote.cost !== undefined) {
96
- formData.append(`mcp_implementation[remote_attributes][${index}][cost]`, remote.cost);
97
- }
98
- if (remote.status !== undefined) {
99
- formData.append(`mcp_implementation[remote_attributes][${index}][status]`, remote.status);
100
- }
101
- if (remote.display_name !== undefined) {
102
- formData.append(`mcp_implementation[remote_attributes][${index}][display_name]`, remote.display_name);
103
- }
104
- if (remote.internal_notes !== undefined) {
105
- formData.append(`mcp_implementation[remote_attributes][${index}][internal_notes]`, remote.internal_notes);
106
- }
107
- });
72
+ if (params.remote !== undefined) {
73
+ if (params.remote.length > 0) {
74
+ params.remote.forEach((remote, index) => {
75
+ if (remote.id !== undefined) {
76
+ formData.append(`mcp_implementation[remote_attributes][${index}][id]`, remote.id.toString());
77
+ }
78
+ if (remote.url_direct !== undefined) {
79
+ formData.append(`mcp_implementation[remote_attributes][${index}][url_direct]`, remote.url_direct);
80
+ }
81
+ if (remote.url_setup !== undefined) {
82
+ formData.append(`mcp_implementation[remote_attributes][${index}][url_setup]`, remote.url_setup);
83
+ }
84
+ if (remote.transport !== undefined) {
85
+ formData.append(`mcp_implementation[remote_attributes][${index}][transport]`, remote.transport);
86
+ }
87
+ if (remote.host_platform !== undefined) {
88
+ formData.append(`mcp_implementation[remote_attributes][${index}][host_platform]`, remote.host_platform);
89
+ }
90
+ if (remote.host_infrastructure !== undefined) {
91
+ formData.append(`mcp_implementation[remote_attributes][${index}][host_infrastructure]`, remote.host_infrastructure);
92
+ }
93
+ if (remote.authentication_method !== undefined) {
94
+ formData.append(`mcp_implementation[remote_attributes][${index}][authentication_method]`, remote.authentication_method);
95
+ }
96
+ if (remote.cost !== undefined) {
97
+ formData.append(`mcp_implementation[remote_attributes][${index}][cost]`, remote.cost);
98
+ }
99
+ if (remote.status !== undefined) {
100
+ formData.append(`mcp_implementation[remote_attributes][${index}][status]`, remote.status);
101
+ }
102
+ if (remote.display_name !== undefined) {
103
+ formData.append(`mcp_implementation[remote_attributes][${index}][display_name]`, remote.display_name);
104
+ }
105
+ if (remote.internal_notes !== undefined) {
106
+ formData.append(`mcp_implementation[remote_attributes][${index}][internal_notes]`, remote.internal_notes);
107
+ }
108
+ });
109
+ }
110
+ else {
111
+ // Empty array explicitly provided - send empty array marker to Rails.
112
+ // The Rails backend has custom logic to interpret '[]' as "delete all remote endpoints".
113
+ // See: mcp_implementation_update_service.rb:612-613 for the destroy_all logic.
114
+ formData.append('mcp_implementation[remote_attributes]', '[]');
115
+ }
108
116
  }
109
117
  // Canonical URLs
110
118
  // Rails expects nested attributes to use the _attributes suffix for has_many associations
111
- if (params.canonical !== undefined && params.canonical.length > 0) {
112
- params.canonical.forEach((canonicalUrl, index) => {
113
- formData.append(`mcp_implementation[canonical_attributes][${index}][url]`, canonicalUrl.url);
114
- formData.append(`mcp_implementation[canonical_attributes][${index}][scope]`, canonicalUrl.scope);
115
- if (canonicalUrl.note !== undefined) {
116
- formData.append(`mcp_implementation[canonical_attributes][${index}][note]`, canonicalUrl.note);
117
- }
118
- });
119
+ if (params.canonical !== undefined) {
120
+ if (params.canonical.length > 0) {
121
+ params.canonical.forEach((canonicalUrl, index) => {
122
+ formData.append(`mcp_implementation[canonical_attributes][${index}][url]`, canonicalUrl.url);
123
+ formData.append(`mcp_implementation[canonical_attributes][${index}][scope]`, canonicalUrl.scope);
124
+ if (canonicalUrl.note !== undefined) {
125
+ formData.append(`mcp_implementation[canonical_attributes][${index}][note]`, canonicalUrl.note);
126
+ }
127
+ });
128
+ }
129
+ else {
130
+ // Empty array explicitly provided - send empty array marker to Rails.
131
+ // The Rails backend has custom logic to interpret '[]' as "delete all canonical URLs".
132
+ // See: mcp_implementation_update_service.rb for the destroy_all logic.
133
+ formData.append('mcp_implementation[canonical_attributes]', '[]');
134
+ }
119
135
  }
120
136
  const response = await fetch(url.toString(), {
121
137
  method: 'PUT',
@@ -138,7 +154,13 @@ export async function saveMCPImplementation(apiKey, baseUrl, id, params) {
138
154
  }
139
155
  if (response.status === 422) {
140
156
  const errorData = (await response.json());
141
- const errors = errorData.errors || ['Validation failed'];
157
+ // Handle both array format and single error string format from Rails
158
+ // Also handle empty arrays - an empty array should fall back to the default message
159
+ const errors = errorData.errors && errorData.errors.length > 0
160
+ ? errorData.errors
161
+ : errorData.error
162
+ ? [errorData.error]
163
+ : ['Unknown validation error'];
142
164
  throw new Error(`Validation failed: ${errors.join(', ')}`);
143
165
  }
144
166
  throw new Error(`Failed to save MCP implementation: ${response.status} ${response.statusText}`);
@@ -25,16 +25,19 @@ export async function sendEmail(apiKey, baseUrl, params) {
25
25
  let errorMessage;
26
26
  try {
27
27
  const errorData = JSON.parse(errorBody);
28
- if (errorData.errors) {
29
- errorMessage = Array.isArray(errorData.errors)
30
- ? errorData.errors.join(', ')
31
- : JSON.stringify(errorData.errors);
28
+ // Handle both array format and single error string format from Rails
29
+ // Also handle empty arrays - an empty array should fall back to checking other fields
30
+ if (Array.isArray(errorData.errors) && errorData.errors.length > 0) {
31
+ errorMessage = errorData.errors.join(', ');
32
+ }
33
+ else if (errorData.errors && typeof errorData.errors === 'object') {
34
+ errorMessage = JSON.stringify(errorData.errors);
32
35
  }
33
36
  else if (errorData.error) {
34
37
  errorMessage = errorData.error;
35
38
  }
36
39
  else {
37
- errorMessage = errorBody;
40
+ errorMessage = errorBody || 'Unknown validation error';
38
41
  }
39
42
  }
40
43
  catch {
@@ -71,7 +71,13 @@ export async function updatePost(apiKey, baseUrl, slug, params) {
71
71
  }
72
72
  if (response.status === 422) {
73
73
  const errorData = (await response.json());
74
- const errors = errorData.errors || ['Validation failed'];
74
+ // Handle both array format and single error string format from Rails
75
+ // Also handle empty arrays - an empty array should fall back to the default message
76
+ const errors = errorData.errors && errorData.errors.length > 0
77
+ ? errorData.errors
78
+ : errorData.error
79
+ ? [errorData.error]
80
+ : ['Unknown validation error'];
75
81
  throw new Error(`Validation failed: ${errors.join(', ')}`);
76
82
  }
77
83
  throw new Error(`Failed to update post: ${response.status} ${response.statusText}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsemcp-cms-admin-mcp-server",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Local implementation of PulseMCP CMS Admin MCP server",
5
5
  "mcpName": "com.pulsemcp.servers/pulsemcp-cms-admin",
6
6
  "main": "build/index.js",
@@ -65,7 +65,13 @@ export async function createPost(apiKey, baseUrl, params) {
65
65
  }
66
66
  if (response.status === 422) {
67
67
  const errorData = (await response.json());
68
- const errors = errorData.errors || ['Validation failed'];
68
+ // Handle both array format and single error string format from Rails
69
+ // Also handle empty arrays - an empty array should fall back to the default message
70
+ const errors = errorData.errors && errorData.errors.length > 0
71
+ ? errorData.errors
72
+ : errorData.error
73
+ ? [errorData.error]
74
+ : ['Unknown validation error'];
69
75
  throw new Error(`Validation failed: ${errors.join(', ')}`);
70
76
  }
71
77
  throw new Error(`Failed to create post: ${response.status} ${response.statusText}`);
@@ -69,53 +69,69 @@ export async function saveMCPImplementation(apiKey, baseUrl, id, params) {
69
69
  }
70
70
  // Remote endpoints
71
71
  // Rails expects nested attributes to use the _attributes suffix for has_many associations
72
- if (params.remote !== undefined && params.remote.length > 0) {
73
- params.remote.forEach((remote, index) => {
74
- if (remote.id !== undefined) {
75
- formData.append(`mcp_implementation[remote_attributes][${index}][id]`, remote.id.toString());
76
- }
77
- if (remote.url_direct !== undefined) {
78
- formData.append(`mcp_implementation[remote_attributes][${index}][url_direct]`, remote.url_direct);
79
- }
80
- if (remote.url_setup !== undefined) {
81
- formData.append(`mcp_implementation[remote_attributes][${index}][url_setup]`, remote.url_setup);
82
- }
83
- if (remote.transport !== undefined) {
84
- formData.append(`mcp_implementation[remote_attributes][${index}][transport]`, remote.transport);
85
- }
86
- if (remote.host_platform !== undefined) {
87
- formData.append(`mcp_implementation[remote_attributes][${index}][host_platform]`, remote.host_platform);
88
- }
89
- if (remote.host_infrastructure !== undefined) {
90
- formData.append(`mcp_implementation[remote_attributes][${index}][host_infrastructure]`, remote.host_infrastructure);
91
- }
92
- if (remote.authentication_method !== undefined) {
93
- formData.append(`mcp_implementation[remote_attributes][${index}][authentication_method]`, remote.authentication_method);
94
- }
95
- if (remote.cost !== undefined) {
96
- formData.append(`mcp_implementation[remote_attributes][${index}][cost]`, remote.cost);
97
- }
98
- if (remote.status !== undefined) {
99
- formData.append(`mcp_implementation[remote_attributes][${index}][status]`, remote.status);
100
- }
101
- if (remote.display_name !== undefined) {
102
- formData.append(`mcp_implementation[remote_attributes][${index}][display_name]`, remote.display_name);
103
- }
104
- if (remote.internal_notes !== undefined) {
105
- formData.append(`mcp_implementation[remote_attributes][${index}][internal_notes]`, remote.internal_notes);
106
- }
107
- });
72
+ if (params.remote !== undefined) {
73
+ if (params.remote.length > 0) {
74
+ params.remote.forEach((remote, index) => {
75
+ if (remote.id !== undefined) {
76
+ formData.append(`mcp_implementation[remote_attributes][${index}][id]`, remote.id.toString());
77
+ }
78
+ if (remote.url_direct !== undefined) {
79
+ formData.append(`mcp_implementation[remote_attributes][${index}][url_direct]`, remote.url_direct);
80
+ }
81
+ if (remote.url_setup !== undefined) {
82
+ formData.append(`mcp_implementation[remote_attributes][${index}][url_setup]`, remote.url_setup);
83
+ }
84
+ if (remote.transport !== undefined) {
85
+ formData.append(`mcp_implementation[remote_attributes][${index}][transport]`, remote.transport);
86
+ }
87
+ if (remote.host_platform !== undefined) {
88
+ formData.append(`mcp_implementation[remote_attributes][${index}][host_platform]`, remote.host_platform);
89
+ }
90
+ if (remote.host_infrastructure !== undefined) {
91
+ formData.append(`mcp_implementation[remote_attributes][${index}][host_infrastructure]`, remote.host_infrastructure);
92
+ }
93
+ if (remote.authentication_method !== undefined) {
94
+ formData.append(`mcp_implementation[remote_attributes][${index}][authentication_method]`, remote.authentication_method);
95
+ }
96
+ if (remote.cost !== undefined) {
97
+ formData.append(`mcp_implementation[remote_attributes][${index}][cost]`, remote.cost);
98
+ }
99
+ if (remote.status !== undefined) {
100
+ formData.append(`mcp_implementation[remote_attributes][${index}][status]`, remote.status);
101
+ }
102
+ if (remote.display_name !== undefined) {
103
+ formData.append(`mcp_implementation[remote_attributes][${index}][display_name]`, remote.display_name);
104
+ }
105
+ if (remote.internal_notes !== undefined) {
106
+ formData.append(`mcp_implementation[remote_attributes][${index}][internal_notes]`, remote.internal_notes);
107
+ }
108
+ });
109
+ }
110
+ else {
111
+ // Empty array explicitly provided - send empty array marker to Rails.
112
+ // The Rails backend has custom logic to interpret '[]' as "delete all remote endpoints".
113
+ // See: mcp_implementation_update_service.rb:612-613 for the destroy_all logic.
114
+ formData.append('mcp_implementation[remote_attributes]', '[]');
115
+ }
108
116
  }
109
117
  // Canonical URLs
110
118
  // Rails expects nested attributes to use the _attributes suffix for has_many associations
111
- if (params.canonical !== undefined && params.canonical.length > 0) {
112
- params.canonical.forEach((canonicalUrl, index) => {
113
- formData.append(`mcp_implementation[canonical_attributes][${index}][url]`, canonicalUrl.url);
114
- formData.append(`mcp_implementation[canonical_attributes][${index}][scope]`, canonicalUrl.scope);
115
- if (canonicalUrl.note !== undefined) {
116
- formData.append(`mcp_implementation[canonical_attributes][${index}][note]`, canonicalUrl.note);
117
- }
118
- });
119
+ if (params.canonical !== undefined) {
120
+ if (params.canonical.length > 0) {
121
+ params.canonical.forEach((canonicalUrl, index) => {
122
+ formData.append(`mcp_implementation[canonical_attributes][${index}][url]`, canonicalUrl.url);
123
+ formData.append(`mcp_implementation[canonical_attributes][${index}][scope]`, canonicalUrl.scope);
124
+ if (canonicalUrl.note !== undefined) {
125
+ formData.append(`mcp_implementation[canonical_attributes][${index}][note]`, canonicalUrl.note);
126
+ }
127
+ });
128
+ }
129
+ else {
130
+ // Empty array explicitly provided - send empty array marker to Rails.
131
+ // The Rails backend has custom logic to interpret '[]' as "delete all canonical URLs".
132
+ // See: mcp_implementation_update_service.rb for the destroy_all logic.
133
+ formData.append('mcp_implementation[canonical_attributes]', '[]');
134
+ }
119
135
  }
120
136
  const response = await fetch(url.toString(), {
121
137
  method: 'PUT',
@@ -138,7 +154,13 @@ export async function saveMCPImplementation(apiKey, baseUrl, id, params) {
138
154
  }
139
155
  if (response.status === 422) {
140
156
  const errorData = (await response.json());
141
- const errors = errorData.errors || ['Validation failed'];
157
+ // Handle both array format and single error string format from Rails
158
+ // Also handle empty arrays - an empty array should fall back to the default message
159
+ const errors = errorData.errors && errorData.errors.length > 0
160
+ ? errorData.errors
161
+ : errorData.error
162
+ ? [errorData.error]
163
+ : ['Unknown validation error'];
142
164
  throw new Error(`Validation failed: ${errors.join(', ')}`);
143
165
  }
144
166
  throw new Error(`Failed to save MCP implementation: ${response.status} ${response.statusText}`);
@@ -25,16 +25,19 @@ export async function sendEmail(apiKey, baseUrl, params) {
25
25
  let errorMessage;
26
26
  try {
27
27
  const errorData = JSON.parse(errorBody);
28
- if (errorData.errors) {
29
- errorMessage = Array.isArray(errorData.errors)
30
- ? errorData.errors.join(', ')
31
- : JSON.stringify(errorData.errors);
28
+ // Handle both array format and single error string format from Rails
29
+ // Also handle empty arrays - an empty array should fall back to checking other fields
30
+ if (Array.isArray(errorData.errors) && errorData.errors.length > 0) {
31
+ errorMessage = errorData.errors.join(', ');
32
+ }
33
+ else if (errorData.errors && typeof errorData.errors === 'object') {
34
+ errorMessage = JSON.stringify(errorData.errors);
32
35
  }
33
36
  else if (errorData.error) {
34
37
  errorMessage = errorData.error;
35
38
  }
36
39
  else {
37
- errorMessage = errorBody;
40
+ errorMessage = errorBody || 'Unknown validation error';
38
41
  }
39
42
  }
40
43
  catch {
@@ -71,7 +71,13 @@ export async function updatePost(apiKey, baseUrl, slug, params) {
71
71
  }
72
72
  if (response.status === 422) {
73
73
  const errorData = (await response.json());
74
- const errors = errorData.errors || ['Validation failed'];
74
+ // Handle both array format and single error string format from Rails
75
+ // Also handle empty arrays - an empty array should fall back to the default message
76
+ const errors = errorData.errors && errorData.errors.length > 0
77
+ ? errorData.errors
78
+ : errorData.error
79
+ ? [errorData.error]
80
+ : ['Unknown validation error'];
75
81
  throw new Error(`Validation failed: ${errors.join(', ')}`);
76
82
  }
77
83
  throw new Error(`Failed to update post: ${response.status} ${response.statusText}`);