pulsemcp-cms-admin-mcp-server 0.6.2 → 0.6.3

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/build/index.js CHANGED
@@ -1,7 +1,15 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from 'fs';
3
+ import { dirname, join } from 'path';
4
+ import { fileURLToPath } from 'url';
2
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
6
  import { createMCPServer } from '../shared/index.js';
4
7
  import { logServerStart, logError } from '../shared/logging.js';
8
+ // Read version from package.json
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const packageJsonPath = join(__dirname, '..', 'package.json');
11
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
12
+ const VERSION = packageJson.version;
5
13
  // Validate required environment variables before starting
6
14
  function validateEnvironment() {
7
15
  const required = [
@@ -33,7 +41,7 @@ async function main() {
33
41
  // Validate environment variables first
34
42
  validateEnvironment();
35
43
  // Create server using factory
36
- const { server, registerHandlers } = createMCPServer();
44
+ const { server, registerHandlers } = createMCPServer({ version: VERSION });
37
45
  // Register all handlers (resources and tools)
38
46
  await registerHandlers(server);
39
47
  // Start server
@@ -7,11 +7,19 @@
7
7
  *
8
8
  * Mock data is passed via the PULSEMCP_MOCK_DATA environment variable.
9
9
  */
10
+ import { readFileSync } from 'fs';
11
+ import { dirname, join } from 'path';
12
+ import { fileURLToPath } from 'url';
10
13
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
14
  // IMPORTANT: This uses the package name pattern, not a relative path
12
15
  import { createMCPServer } from 'pulsemcp-cms-admin-mcp-server-shared';
13
16
  // Import the mock client factory from the shared module
14
17
  import { createMockPulseMCPAdminClient } from '../../shared/src/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js';
18
+ // Read version from package.json
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const packageJsonPath = join(__dirname, '..', 'package.json');
21
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
22
+ const VERSION = packageJson.version;
15
23
  async function main() {
16
24
  const transport = new StdioServerTransport();
17
25
  // Parse mock data from environment variable
@@ -26,7 +34,7 @@ async function main() {
26
34
  }
27
35
  // Create client factory that returns our mock
28
36
  const clientFactory = () => createMockPulseMCPAdminClient(mockData);
29
- const { server, registerHandlers } = createMCPServer();
37
+ const { server, registerHandlers } = createMCPServer({ version: VERSION });
30
38
  await registerHandlers(server, clientFactory);
31
39
  await server.connect(transport);
32
40
  }
@@ -0,0 +1,179 @@
1
+ export async function createMCPImplementation(apiKey, baseUrl, params) {
2
+ const url = new URL(`/api/implementations`, baseUrl);
3
+ // Build form data for the POST request
4
+ const formData = new URLSearchParams();
5
+ // Required fields for creation
6
+ formData.append('mcp_implementation[name]', params.name);
7
+ formData.append('mcp_implementation[type]', params.type);
8
+ // Optional fields
9
+ if (params.short_description !== undefined) {
10
+ formData.append('mcp_implementation[short_description]', params.short_description);
11
+ }
12
+ if (params.description !== undefined) {
13
+ formData.append('mcp_implementation[description]', params.description);
14
+ }
15
+ if (params.status !== undefined) {
16
+ formData.append('mcp_implementation[status]', params.status);
17
+ }
18
+ if (params.slug !== undefined) {
19
+ formData.append('mcp_implementation[slug]', params.slug);
20
+ }
21
+ if (params.url !== undefined) {
22
+ // Backend expects 'marketing_url' field, but tool exposes it as 'url' for better UX
23
+ formData.append('mcp_implementation[marketing_url]', params.url);
24
+ }
25
+ if (params.provider_name !== undefined) {
26
+ formData.append('mcp_implementation[provider_name]', params.provider_name);
27
+ }
28
+ if (params.github_stars !== undefined) {
29
+ formData.append('mcp_implementation[github_stars]', params.github_stars === null ? '' : params.github_stars.toString());
30
+ }
31
+ if (params.classification !== undefined) {
32
+ formData.append('mcp_implementation[classification]', params.classification);
33
+ }
34
+ if (params.implementation_language !== undefined) {
35
+ formData.append('mcp_implementation[implementation_language]', params.implementation_language);
36
+ }
37
+ if (params.mcp_server_id !== undefined) {
38
+ formData.append('mcp_implementation[mcp_server_id]', params.mcp_server_id === null ? '' : params.mcp_server_id.toString());
39
+ }
40
+ if (params.mcp_client_id !== undefined) {
41
+ formData.append('mcp_implementation[mcp_client_id]', params.mcp_client_id === null ? '' : params.mcp_client_id.toString());
42
+ }
43
+ // Provider creation/linking
44
+ if (params.provider_id !== undefined) {
45
+ formData.append('mcp_implementation[provider_id]', params.provider_id.toString());
46
+ }
47
+ if (params.provider_slug !== undefined) {
48
+ formData.append('mcp_implementation[provider_slug]', params.provider_slug);
49
+ }
50
+ if (params.provider_url !== undefined) {
51
+ formData.append('mcp_implementation[provider_url]', params.provider_url);
52
+ }
53
+ // GitHub repository fields
54
+ if (params.github_owner !== undefined) {
55
+ formData.append('mcp_implementation[github_owner]', params.github_owner);
56
+ }
57
+ if (params.github_repo !== undefined) {
58
+ formData.append('mcp_implementation[github_repo]', params.github_repo);
59
+ }
60
+ if (params.github_subfolder !== undefined) {
61
+ formData.append('mcp_implementation[github_subfolder]', params.github_subfolder);
62
+ }
63
+ // Package registry fields
64
+ if (params.package_registry !== undefined) {
65
+ formData.append('mcp_implementation[package_registry]', params.package_registry);
66
+ }
67
+ if (params.package_name !== undefined) {
68
+ formData.append('mcp_implementation[package_name]', params.package_name);
69
+ }
70
+ // Flags
71
+ if (params.recommended !== undefined) {
72
+ formData.append('mcp_implementation[recommended]', params.recommended.toString());
73
+ }
74
+ // Date overrides
75
+ if (params.created_on_override !== undefined) {
76
+ formData.append('mcp_implementation[created_on_override]', params.created_on_override);
77
+ }
78
+ // Tags
79
+ if (params.tags !== undefined) {
80
+ if (params.tags.length > 0) {
81
+ params.tags.forEach((tagSlug, index) => {
82
+ formData.append(`mcp_implementation[tags][${index}]`, tagSlug);
83
+ });
84
+ }
85
+ else {
86
+ // Empty array explicitly provided - send empty array marker to Rails
87
+ formData.append('mcp_implementation[tags]', '[]');
88
+ }
89
+ }
90
+ // Internal notes
91
+ if (params.internal_notes !== undefined) {
92
+ formData.append('mcp_implementation[internal_notes]', params.internal_notes);
93
+ }
94
+ // Remote endpoints
95
+ // Rails expects nested attributes to use the _attributes suffix for has_many associations
96
+ if (params.remote !== undefined) {
97
+ if (params.remote.length > 0) {
98
+ params.remote.forEach((remote, index) => {
99
+ if (remote.id !== undefined) {
100
+ formData.append(`mcp_implementation[remote_attributes][${index}][id]`, remote.id.toString());
101
+ }
102
+ if (remote.url_direct !== undefined) {
103
+ formData.append(`mcp_implementation[remote_attributes][${index}][url_direct]`, remote.url_direct);
104
+ }
105
+ if (remote.url_setup !== undefined) {
106
+ formData.append(`mcp_implementation[remote_attributes][${index}][url_setup]`, remote.url_setup);
107
+ }
108
+ if (remote.transport !== undefined) {
109
+ formData.append(`mcp_implementation[remote_attributes][${index}][transport]`, remote.transport);
110
+ }
111
+ if (remote.host_platform !== undefined) {
112
+ formData.append(`mcp_implementation[remote_attributes][${index}][host_platform]`, remote.host_platform);
113
+ }
114
+ if (remote.host_infrastructure !== undefined) {
115
+ formData.append(`mcp_implementation[remote_attributes][${index}][host_infrastructure]`, remote.host_infrastructure);
116
+ }
117
+ if (remote.authentication_method !== undefined) {
118
+ formData.append(`mcp_implementation[remote_attributes][${index}][authentication_method]`, remote.authentication_method);
119
+ }
120
+ if (remote.cost !== undefined) {
121
+ formData.append(`mcp_implementation[remote_attributes][${index}][cost]`, remote.cost);
122
+ }
123
+ if (remote.status !== undefined) {
124
+ formData.append(`mcp_implementation[remote_attributes][${index}][status]`, remote.status);
125
+ }
126
+ if (remote.display_name !== undefined) {
127
+ formData.append(`mcp_implementation[remote_attributes][${index}][display_name]`, remote.display_name);
128
+ }
129
+ if (remote.internal_notes !== undefined) {
130
+ formData.append(`mcp_implementation[remote_attributes][${index}][internal_notes]`, remote.internal_notes);
131
+ }
132
+ });
133
+ }
134
+ }
135
+ // Canonical URLs
136
+ // Rails expects nested attributes to use the _attributes suffix for has_many associations
137
+ if (params.canonical !== undefined) {
138
+ if (params.canonical.length > 0) {
139
+ params.canonical.forEach((canonicalUrl, index) => {
140
+ formData.append(`mcp_implementation[canonical_attributes][${index}][url]`, canonicalUrl.url);
141
+ formData.append(`mcp_implementation[canonical_attributes][${index}][scope]`, canonicalUrl.scope);
142
+ if (canonicalUrl.note !== undefined) {
143
+ formData.append(`mcp_implementation[canonical_attributes][${index}][note]`, canonicalUrl.note);
144
+ }
145
+ });
146
+ }
147
+ }
148
+ const response = await fetch(url.toString(), {
149
+ method: 'POST',
150
+ headers: {
151
+ 'X-API-Key': apiKey,
152
+ 'Content-Type': 'application/x-www-form-urlencoded',
153
+ Accept: 'application/json',
154
+ },
155
+ body: formData.toString(),
156
+ });
157
+ if (!response.ok) {
158
+ if (response.status === 401) {
159
+ throw new Error('Invalid API key');
160
+ }
161
+ if (response.status === 403) {
162
+ throw new Error('User lacks admin privileges');
163
+ }
164
+ if (response.status === 422) {
165
+ const errorData = (await response.json());
166
+ // Handle both array format and single error string format from Rails
167
+ // Also handle empty arrays - an empty array should fall back to the default message
168
+ const errors = errorData.errors && errorData.errors.length > 0
169
+ ? errorData.errors
170
+ : errorData.error
171
+ ? [errorData.error]
172
+ : ['Unknown validation error'];
173
+ throw new Error(`Validation failed: ${errors.join(', ')}`);
174
+ }
175
+ throw new Error(`Failed to create MCP implementation: ${response.status} ${response.statusText}`);
176
+ }
177
+ const data = await response.json();
178
+ return data;
179
+ }
@@ -315,6 +315,33 @@ export function createMockPulseMCPAdminClient(mockData) {
315
315
  };
316
316
  return updatedImpl;
317
317
  },
318
+ async createMCPImplementation(params) {
319
+ // Create a new implementation with mock data
320
+ const newImpl = {
321
+ id: Math.floor(Math.random() * 10000) + 1000,
322
+ name: params.name,
323
+ type: params.type,
324
+ status: params.status || 'draft',
325
+ slug: params.slug || params.name.toLowerCase().replace(/\s+/g, '-'),
326
+ short_description: params.short_description,
327
+ description: params.description,
328
+ classification: params.classification,
329
+ implementation_language: params.implementation_language,
330
+ url: params.url,
331
+ provider_name: params.provider_name,
332
+ github_stars: params.github_stars,
333
+ mcp_server_id: params.mcp_server_id,
334
+ mcp_client_id: params.mcp_client_id,
335
+ github_owner: params.github_owner,
336
+ github_repo: params.github_repo,
337
+ github_subfolder: params.github_subfolder,
338
+ internal_notes: params.internal_notes,
339
+ canonical: params.canonical,
340
+ created_at: new Date().toISOString(),
341
+ updated_at: new Date().toISOString(),
342
+ };
343
+ return newImpl;
344
+ },
318
345
  async sendEmail(params) {
319
346
  if (mockData.errors?.sendEmail) {
320
347
  throw mockData.errors.sendEmail;
@@ -72,6 +72,10 @@ export class PulseMCPAdminClient {
72
72
  const { saveMCPImplementation } = await import('./pulsemcp-admin-client/lib/save-mcp-implementation.js');
73
73
  return saveMCPImplementation(this.apiKey, this.baseUrl, id, params);
74
74
  }
75
+ async createMCPImplementation(params) {
76
+ const { createMCPImplementation } = await import('./pulsemcp-admin-client/lib/create-mcp-implementation.js');
77
+ return createMCPImplementation(this.apiKey, this.baseUrl, params);
78
+ }
75
79
  async sendEmail(params) {
76
80
  const { sendEmail } = await import('./pulsemcp-admin-client/lib/send-email.js');
77
81
  return sendEmail(this.apiKey, this.baseUrl, params);
@@ -187,10 +191,10 @@ export class PulseMCPAdminClient {
187
191
  return updateUnifiedMCPServer(this.apiKey, this.baseUrl, implementationId, params);
188
192
  }
189
193
  }
190
- export function createMCPServer() {
194
+ export function createMCPServer(options) {
191
195
  const server = new Server({
192
196
  name: 'pulsemcp-cms-admin',
193
- version: '0.1.0',
197
+ version: options.version,
194
198
  }, {
195
199
  capabilities: {
196
200
  tools: {},
@@ -1,18 +1,18 @@
1
1
  import { z } from 'zod';
2
2
  // Parameter descriptions - single source of truth
3
3
  const PARAM_DESCRIPTIONS = {
4
- id: 'The ID of the MCP implementation to save/update (e.g., 11371)',
5
- name: 'Updated name of the MCP implementation',
6
- short_description: 'Updated short description (brief summary)',
7
- description: 'Updated full description (detailed documentation)',
8
- type: 'Implementation type - "server" for MCP servers, "client" for MCP clients',
4
+ id: 'The ID of the MCP implementation to update. Omit this field to CREATE a new implementation instead of updating an existing one.',
5
+ name: 'Name of the MCP implementation. Required when creating a new implementation.',
6
+ type: 'Implementation type - "server" for MCP servers, "client" for MCP clients. Required when creating a new implementation.',
7
+ short_description: 'Short description (brief summary)',
8
+ description: 'Full description (detailed documentation)',
9
9
  status: 'Publication status - "draft", "live", or "archived"',
10
- slug: 'Updated URL-friendly slug identifier',
11
- url: 'Updated URL to the implementation (GitHub repo, npm package, etc.)',
12
- provider_name: 'Updated provider/author name',
13
- github_stars: 'Updated GitHub star count (integer, or null if unknown)',
10
+ slug: 'URL-friendly slug identifier',
11
+ url: 'URL to the implementation (GitHub repo, npm package, etc.)',
12
+ provider_name: 'Provider/author name',
13
+ github_stars: 'GitHub star count (integer, or null if unknown)',
14
14
  classification: 'Implementation classification - "official", "community", or "reference"',
15
- implementation_language: 'Updated programming language (e.g., "TypeScript", "Python", "Go")',
15
+ implementation_language: 'Programming language (e.g., "TypeScript", "Python", "Go")',
16
16
  mcp_server_id: 'ID of associated MCP server record (null to unlink)',
17
17
  mcp_client_id: 'ID of associated MCP client record (null to unlink)',
18
18
  // Provider creation/linking
@@ -31,11 +31,11 @@ const PARAM_DESCRIPTIONS = {
31
31
  internal_notes: 'Admin-only notes. Not displayed publicly. Used for tracking submission sources, reviewer comments, etc.',
32
32
  };
33
33
  const SaveMCPImplementationSchema = z.object({
34
- id: z.number().describe(PARAM_DESCRIPTIONS.id),
34
+ id: z.number().optional().describe(PARAM_DESCRIPTIONS.id),
35
35
  name: z.string().optional().describe(PARAM_DESCRIPTIONS.name),
36
+ type: z.enum(['server', 'client']).optional().describe(PARAM_DESCRIPTIONS.type),
36
37
  short_description: z.string().optional().describe(PARAM_DESCRIPTIONS.short_description),
37
38
  description: z.string().optional().describe(PARAM_DESCRIPTIONS.description),
38
- type: z.enum(['server', 'client']).optional().describe(PARAM_DESCRIPTIONS.type),
39
39
  status: z.enum(['draft', 'live', 'archived']).optional().describe(PARAM_DESCRIPTIONS.status),
40
40
  slug: z.string().optional().describe(PARAM_DESCRIPTIONS.slug),
41
41
  url: z.string().optional().describe(PARAM_DESCRIPTIONS.url),
@@ -94,11 +94,30 @@ const SaveMCPImplementationSchema = z.object({
94
94
  export function saveMCPImplementation(_server, clientFactory) {
95
95
  return {
96
96
  name: 'save_mcp_implementation',
97
- description: `Save/update an MCP implementation by its ID. This tool replicates the "Save Changes" functionality from the PulseMCP Admin panel (e.g., https://admin.pulsemcp.com/mcp_implementations/11371/edit).
97
+ description: `Create or update an MCP implementation. This tool replicates the "Save Changes" functionality from the PulseMCP Admin panel.
98
+
99
+ **Creating a new implementation:**
100
+ - Omit the \`id\` field to create a new implementation
101
+ - Required fields for creation: \`name\`, \`type\` (either "server" or "client")
102
+
103
+ **Updating an existing implementation:**
104
+ - Provide the \`id\` field to update an existing implementation
105
+ - Only provided fields will be updated; omitted fields remain unchanged
106
+
107
+ All business logic from the Rails controller is applied (validation, associations, callbacks).
98
108
 
99
- This tool allows partial updates - you only need to provide the fields you want to change. All business logic from the Rails controller is applied (validation, associations, callbacks).
109
+ Example request (CREATE new implementation):
110
+ {
111
+ "name": "My New MCP Server",
112
+ "type": "server",
113
+ "short_description": "A new MCP server for doing cool things",
114
+ "classification": "community",
115
+ "implementation_language": "TypeScript",
116
+ "github_owner": "myorg",
117
+ "github_repo": "my-mcp-server"
118
+ }
100
119
 
101
- Example request (basic update):
120
+ Example request (UPDATE existing implementation):
102
121
  {
103
122
  "id": 11371,
104
123
  "name": "GitHub MCP Server",
@@ -125,30 +144,6 @@ Example request (with remote endpoints - new remote):
125
144
  ]
126
145
  }
127
146
 
128
- Example request (updating existing remote by ID):
129
- {
130
- "id": 11371,
131
- "remote": [
132
- {
133
- "id": 123,
134
- "url_direct": "https://updated-api.example.com/mcp",
135
- "status": "beta"
136
- }
137
- ]
138
- }
139
-
140
- Example request (with canonical URLs):
141
- {
142
- "id": 11371,
143
- "canonical": [
144
- {
145
- "url": "https://github.com/owner/repo",
146
- "scope": "url",
147
- "note": "Official GitHub repository"
148
- }
149
- ]
150
- }
151
-
152
147
  Example response:
153
148
  {
154
149
  "id": 11371,
@@ -161,15 +156,15 @@ Example response:
161
156
  }
162
157
 
163
158
  Important notes:
164
- - Only provided fields will be updated; omitted fields remain unchanged
165
- - All Rails controller logic is applied (validations, associations, callbacks)
166
- - Use get_draft_mcp_implementations first to see current values
167
- - The ID parameter is required to identify which implementation to update
159
+ - Omit \`id\` to CREATE, provide \`id\` to UPDATE
160
+ - When creating: \`name\` and \`type\` are required
161
+ - When updating: only provided fields will be changed
168
162
  - Setting mcp_server_id or mcp_client_id to null will unlink the association
169
163
  - Remote endpoints are for MCP servers only and configure how they can be accessed
170
164
  - Canonical URLs help identify the authoritative source for the implementation
171
165
 
172
166
  Use cases:
167
+ - Create new MCP implementation entries
173
168
  - Update draft implementations before publishing
174
169
  - Change implementation status (draft → live, live → archived)
175
170
  - Update metadata (stars, language, classification)
@@ -307,69 +302,139 @@ Use cases:
307
302
  description: PARAM_DESCRIPTIONS.internal_notes,
308
303
  },
309
304
  },
310
- required: ['id'],
311
305
  },
312
306
  handler: async (args) => {
313
307
  const validatedArgs = SaveMCPImplementationSchema.parse(args);
314
308
  const client = clientFactory();
315
309
  try {
316
- const { id, ...params } = validatedArgs;
317
- // Only update if there are actual changes
318
- if (Object.keys(params).length === 0) {
310
+ const { id, type, ...restParams } = validatedArgs;
311
+ // Determine if this is a create or update operation
312
+ const isCreate = id === undefined;
313
+ if (isCreate) {
314
+ // CREATE mode - validate required fields
315
+ if (!validatedArgs.name) {
316
+ return {
317
+ content: [
318
+ {
319
+ type: 'text',
320
+ text: 'Error: "name" is required when creating a new MCP implementation (when "id" is omitted).',
321
+ },
322
+ ],
323
+ isError: true,
324
+ };
325
+ }
326
+ if (!type) {
327
+ return {
328
+ content: [
329
+ {
330
+ type: 'text',
331
+ text: 'Error: "type" is required when creating a new MCP implementation (when "id" is omitted). Use "server" or "client".',
332
+ },
333
+ ],
334
+ isError: true,
335
+ };
336
+ }
337
+ // Create new implementation
338
+ const createParams = {
339
+ name: validatedArgs.name,
340
+ type: type,
341
+ ...restParams,
342
+ };
343
+ const implementation = await client.createMCPImplementation(createParams);
344
+ // Format the response for MCP
345
+ let content = `Successfully created new MCP implementation!\n\n`;
346
+ content += `**Name:** ${implementation.name}\n`;
347
+ content += `**ID:** ${implementation.id}\n`;
348
+ content += `**Slug:** ${implementation.slug}\n`;
349
+ content += `**Type:** ${implementation.type}\n`;
350
+ content += `**Status:** ${implementation.status}\n`;
351
+ if (implementation.classification) {
352
+ content += `**Classification:** ${implementation.classification}\n`;
353
+ }
354
+ if (implementation.implementation_language) {
355
+ content += `**Language:** ${implementation.implementation_language}\n`;
356
+ }
357
+ if (implementation.provider_name) {
358
+ content += `**Provider:** ${implementation.provider_name}\n`;
359
+ }
360
+ if (implementation.url) {
361
+ content += `**URL:** ${implementation.url}\n`;
362
+ }
363
+ if (implementation.created_at) {
364
+ content += `**Created:** ${new Date(implementation.created_at).toLocaleDateString()}\n`;
365
+ }
319
366
  return {
320
367
  content: [
321
368
  {
322
369
  type: 'text',
323
- text: 'No changes provided. Please specify at least one field to update.',
370
+ text: content,
324
371
  },
325
372
  ],
326
373
  };
327
374
  }
328
- const updateParams = params;
329
- const implementation = await client.saveMCPImplementation(id, updateParams);
330
- // Format the response for MCP
331
- let content = `Successfully saved MCP implementation!\n\n`;
332
- content += `**Name:** ${implementation.name}\n`;
333
- content += `**ID:** ${implementation.id}\n`;
334
- content += `**Slug:** ${implementation.slug}\n`;
335
- content += `**Type:** ${implementation.type}\n`;
336
- content += `**Status:** ${implementation.status}\n`;
337
- if (implementation.classification) {
338
- content += `**Classification:** ${implementation.classification}\n`;
339
- }
340
- if (implementation.implementation_language) {
341
- content += `**Language:** ${implementation.implementation_language}\n`;
342
- }
343
- if (implementation.provider_name) {
344
- content += `**Provider:** ${implementation.provider_name}\n`;
345
- }
346
- if (implementation.url) {
347
- content += `**URL:** ${implementation.url}\n`;
348
- }
349
- if (implementation.github_stars !== undefined) {
350
- content += `**GitHub Stars:** ${implementation.github_stars}\n`;
351
- }
352
- if (implementation.mcp_server_id) {
353
- content += `**Linked MCP Server ID:** ${implementation.mcp_server_id}\n`;
354
- }
355
- if (implementation.mcp_client_id) {
356
- content += `**Linked MCP Client ID:** ${implementation.mcp_client_id}\n`;
357
- }
358
- if (implementation.updated_at) {
359
- content += `**Updated:** ${new Date(implementation.updated_at).toLocaleDateString()}\n`;
375
+ else {
376
+ // UPDATE mode
377
+ const params = { type, ...restParams };
378
+ // Only update if there are actual changes
379
+ if (Object.keys(params).filter((k) => params[k] !== undefined)
380
+ .length === 0) {
381
+ return {
382
+ content: [
383
+ {
384
+ type: 'text',
385
+ text: 'No changes provided. Please specify at least one field to update.',
386
+ },
387
+ ],
388
+ };
389
+ }
390
+ const updateParams = params;
391
+ const implementation = await client.saveMCPImplementation(id, updateParams);
392
+ // Format the response for MCP
393
+ let content = `Successfully updated MCP implementation!\n\n`;
394
+ content += `**Name:** ${implementation.name}\n`;
395
+ content += `**ID:** ${implementation.id}\n`;
396
+ content += `**Slug:** ${implementation.slug}\n`;
397
+ content += `**Type:** ${implementation.type}\n`;
398
+ content += `**Status:** ${implementation.status}\n`;
399
+ if (implementation.classification) {
400
+ content += `**Classification:** ${implementation.classification}\n`;
401
+ }
402
+ if (implementation.implementation_language) {
403
+ content += `**Language:** ${implementation.implementation_language}\n`;
404
+ }
405
+ if (implementation.provider_name) {
406
+ content += `**Provider:** ${implementation.provider_name}\n`;
407
+ }
408
+ if (implementation.url) {
409
+ content += `**URL:** ${implementation.url}\n`;
410
+ }
411
+ if (implementation.github_stars !== undefined) {
412
+ content += `**GitHub Stars:** ${implementation.github_stars}\n`;
413
+ }
414
+ if (implementation.mcp_server_id) {
415
+ content += `**Linked MCP Server ID:** ${implementation.mcp_server_id}\n`;
416
+ }
417
+ if (implementation.mcp_client_id) {
418
+ content += `**Linked MCP Client ID:** ${implementation.mcp_client_id}\n`;
419
+ }
420
+ if (implementation.updated_at) {
421
+ content += `**Updated:** ${new Date(implementation.updated_at).toLocaleDateString()}\n`;
422
+ }
423
+ content += `\n**Fields updated:**\n`;
424
+ Object.keys(params)
425
+ .filter((k) => params[k] !== undefined)
426
+ .forEach((field) => {
427
+ content += `- ${field}\n`;
428
+ });
429
+ return {
430
+ content: [
431
+ {
432
+ type: 'text',
433
+ text: content,
434
+ },
435
+ ],
436
+ };
360
437
  }
361
- content += `\n**Fields updated:**\n`;
362
- Object.keys(params).forEach((field) => {
363
- content += `- ${field}\n`;
364
- });
365
- return {
366
- content: [
367
- {
368
- type: 'text',
369
- text: content,
370
- },
371
- ],
372
- };
373
438
  }
374
439
  catch (error) {
375
440
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsemcp-cms-admin-mcp-server",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
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",
package/shared/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { registerTools, createRegisterTools } from './tools.js';
2
- export { createMCPServer, type ClientFactory, type IPulseMCPAdminClient, PulseMCPAdminClient, } from './server.js';
2
+ export { createMCPServer, type CreateMCPServerOptions, type ClientFactory, type IPulseMCPAdminClient, PulseMCPAdminClient, } from './server.js';
3
3
  export type { Post, PostsResponse, CreatePostParams, UpdatePostParams, ImageUploadResponse, Author, AuthorsResponse, MCPServer, MCPClient, } from './types.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,3 @@
1
+ import type { MCPImplementation, CreateMCPImplementationParams } from '../../types.js';
2
+ export declare function createMCPImplementation(apiKey: string, baseUrl: string, params: CreateMCPImplementationParams): Promise<MCPImplementation>;
3
+ //# sourceMappingURL=create-mcp-implementation.d.ts.map