pulsemcp-cms-admin-mcp-server 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Get available runtimes and exams from the Proctor API
3
+ */
4
+ export async function getProctorMetadata(apiKey, baseUrl) {
5
+ const url = new URL('/api/proctor/metadata', baseUrl);
6
+ const response = await fetch(url.toString(), {
7
+ method: 'GET',
8
+ headers: {
9
+ 'X-API-Key': apiKey,
10
+ Accept: 'application/json',
11
+ },
12
+ });
13
+ if (!response.ok) {
14
+ if (response.status === 401) {
15
+ throw new Error('Invalid API key');
16
+ }
17
+ if (response.status === 403) {
18
+ throw new Error('User lacks admin privileges or insufficient permissions');
19
+ }
20
+ throw new Error(`Failed to get proctor metadata: ${response.status} ${response.statusText}`);
21
+ }
22
+ return (await response.json());
23
+ }
@@ -964,6 +964,12 @@ export function createMockPulseMCPAdminClient(mockData) {
964
964
  pagination: { current_page: 1, total_pages: 1, total_count: 0, has_next: false, limit: 30 },
965
965
  };
966
966
  },
967
+ async getProctorMetadata() {
968
+ return {
969
+ runtimes: [],
970
+ exams: [],
971
+ };
972
+ },
967
973
  // Discovered URL methods
968
974
  async getDiscoveredUrls() {
969
975
  return {
@@ -1,5 +1,73 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { createRegisterTools } from './tools.js';
3
+ // Static imports for all API client functions (replaces dynamic imports
4
+ // which can fail at runtime in some environments due to ESM resolution)
5
+ import { getPosts } from './pulsemcp-admin-client/lib/get-posts.js';
6
+ import { getPost } from './pulsemcp-admin-client/lib/get-post.js';
7
+ import { createPost } from './pulsemcp-admin-client/lib/create-post.js';
8
+ import { updatePost } from './pulsemcp-admin-client/lib/update-post.js';
9
+ import { uploadImage } from './pulsemcp-admin-client/lib/upload-image.js';
10
+ import { getAuthors } from './pulsemcp-admin-client/lib/get-authors.js';
11
+ import { getAuthorBySlug } from './pulsemcp-admin-client/lib/get-author-by-slug.js';
12
+ import { getAuthorById } from './pulsemcp-admin-client/lib/get-author-by-id.js';
13
+ import { getMCPServerBySlug } from './pulsemcp-admin-client/lib/get-mcp-server-by-slug.js';
14
+ import { getMCPServerById } from './pulsemcp-admin-client/lib/get-mcp-server-by-id.js';
15
+ import { getMCPClientBySlug } from './pulsemcp-admin-client/lib/get-mcp-client-by-slug.js';
16
+ import { getMCPClientById } from './pulsemcp-admin-client/lib/get-mcp-client-by-id.js';
17
+ import { getMCPImplementationById } from './pulsemcp-admin-client/lib/get-mcp-implementation-by-id.js';
18
+ import { searchMCPImplementations } from './pulsemcp-admin-client/lib/search-mcp-implementations.js';
19
+ import { getDraftMCPImplementations } from './pulsemcp-admin-client/lib/get-draft-mcp-implementations.js';
20
+ import { saveMCPImplementation } from './pulsemcp-admin-client/lib/save-mcp-implementation.js';
21
+ import { createMCPImplementation } from './pulsemcp-admin-client/lib/create-mcp-implementation.js';
22
+ import { sendEmail } from './pulsemcp-admin-client/lib/send-email.js';
23
+ import { searchProviders } from './pulsemcp-admin-client/lib/search-providers.js';
24
+ import { getProviderById } from './pulsemcp-admin-client/lib/get-provider-by-id.js';
25
+ import { getOfficialMirrorQueueItems } from './pulsemcp-admin-client/lib/get-official-mirror-queue-items.js';
26
+ import { getOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/get-official-mirror-queue-item.js';
27
+ import { approveOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/approve-official-mirror-queue-item.js';
28
+ import { approveOfficialMirrorQueueItemWithoutModifying } from './pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.js';
29
+ import { rejectOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/reject-official-mirror-queue-item.js';
30
+ import { addOfficialMirrorToRegularQueue } from './pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.js';
31
+ import { unlinkOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.js';
32
+ import { getUnofficialMirrors } from './pulsemcp-admin-client/lib/get-unofficial-mirrors.js';
33
+ import { getUnofficialMirror } from './pulsemcp-admin-client/lib/get-unofficial-mirror.js';
34
+ import { createUnofficialMirror } from './pulsemcp-admin-client/lib/create-unofficial-mirror.js';
35
+ import { updateUnofficialMirror } from './pulsemcp-admin-client/lib/update-unofficial-mirror.js';
36
+ import { deleteUnofficialMirror } from './pulsemcp-admin-client/lib/delete-unofficial-mirror.js';
37
+ import { getOfficialMirrors } from './pulsemcp-admin-client/lib/get-official-mirrors.js';
38
+ import { getOfficialMirror } from './pulsemcp-admin-client/lib/get-official-mirror.js';
39
+ import { getTenants } from './pulsemcp-admin-client/lib/get-tenants.js';
40
+ import { getTenant } from './pulsemcp-admin-client/lib/get-tenant.js';
41
+ import { getMcpJsons } from './pulsemcp-admin-client/lib/get-mcp-jsons.js';
42
+ import { getMcpJson } from './pulsemcp-admin-client/lib/get-mcp-json.js';
43
+ import { createMcpJson } from './pulsemcp-admin-client/lib/create-mcp-json.js';
44
+ import { updateMcpJson } from './pulsemcp-admin-client/lib/update-mcp-json.js';
45
+ import { deleteMcpJson } from './pulsemcp-admin-client/lib/delete-mcp-json.js';
46
+ import { getUnifiedMCPServers } from './pulsemcp-admin-client/lib/get-unified-mcp-servers.js';
47
+ import { getUnifiedMCPServer } from './pulsemcp-admin-client/lib/get-unified-mcp-server.js';
48
+ import { updateUnifiedMCPServer } from './pulsemcp-admin-client/lib/update-unified-mcp-server.js';
49
+ import { getRedirects } from './pulsemcp-admin-client/lib/get-redirects.js';
50
+ import { getRedirect } from './pulsemcp-admin-client/lib/get-redirect.js';
51
+ import { createRedirect } from './pulsemcp-admin-client/lib/create-redirect.js';
52
+ import { updateRedirect } from './pulsemcp-admin-client/lib/update-redirect.js';
53
+ import { deleteRedirect } from './pulsemcp-admin-client/lib/delete-redirect.js';
54
+ import { getGoodJobs } from './pulsemcp-admin-client/lib/get-good-jobs.js';
55
+ import { getGoodJob } from './pulsemcp-admin-client/lib/get-good-job.js';
56
+ import { getGoodJobCronSchedules } from './pulsemcp-admin-client/lib/get-good-job-cron-schedules.js';
57
+ import { getGoodJobProcesses } from './pulsemcp-admin-client/lib/get-good-job-processes.js';
58
+ import { getGoodJobStatistics } from './pulsemcp-admin-client/lib/get-good-job-statistics.js';
59
+ import { retryGoodJob } from './pulsemcp-admin-client/lib/retry-good-job.js';
60
+ import { discardGoodJob } from './pulsemcp-admin-client/lib/discard-good-job.js';
61
+ import { rescheduleGoodJob } from './pulsemcp-admin-client/lib/reschedule-good-job.js';
62
+ import { forceTriggerGoodJobCron } from './pulsemcp-admin-client/lib/force-trigger-good-job-cron.js';
63
+ import { cleanupGoodJobs } from './pulsemcp-admin-client/lib/cleanup-good-jobs.js';
64
+ import { runExamForMirror } from './pulsemcp-admin-client/lib/run-exam-for-mirror.js';
65
+ import { saveResultsForMirror } from './pulsemcp-admin-client/lib/save-results-for-mirror.js';
66
+ import { getProctorRuns } from './pulsemcp-admin-client/lib/get-proctor-runs.js';
67
+ import { getProctorMetadata } from './pulsemcp-admin-client/lib/get-proctor-metadata.js';
68
+ import { getDiscoveredUrls } from './pulsemcp-admin-client/lib/get-discovered-urls.js';
69
+ import { markDiscoveredUrlProcessed } from './pulsemcp-admin-client/lib/mark-discovered-url-processed.js';
70
+ import { getDiscoveredUrlStats } from './pulsemcp-admin-client/lib/get-discovered-url-stats.js';
3
71
  // PulseMCP Admin API client implementation
4
72
  export class PulseMCPAdminClient {
5
73
  apiKey;
@@ -9,273 +77,211 @@ export class PulseMCPAdminClient {
9
77
  this.baseUrl = baseUrl || 'https://admin.pulsemcp.com';
10
78
  }
11
79
  async getPosts(params) {
12
- const { getPosts } = await import('./pulsemcp-admin-client/lib/get-posts.js');
13
80
  return getPosts(this.apiKey, this.baseUrl, params);
14
81
  }
15
82
  async getPost(slug) {
16
- const { getPost } = await import('./pulsemcp-admin-client/lib/get-post.js');
17
83
  return getPost(this.apiKey, this.baseUrl, slug);
18
84
  }
19
85
  async createPost(params) {
20
- const { createPost } = await import('./pulsemcp-admin-client/lib/create-post.js');
21
86
  return createPost(this.apiKey, this.baseUrl, params);
22
87
  }
23
88
  async updatePost(slug, params) {
24
- const { updatePost } = await import('./pulsemcp-admin-client/lib/update-post.js');
25
89
  return updatePost(this.apiKey, this.baseUrl, slug, params);
26
90
  }
27
91
  async uploadImage(postSlug, fileName, fileData) {
28
- const { uploadImage } = await import('./pulsemcp-admin-client/lib/upload-image.js');
29
92
  return uploadImage(this.apiKey, this.baseUrl, postSlug, fileName, fileData);
30
93
  }
31
94
  async getAuthors(params) {
32
- const { getAuthors } = await import('./pulsemcp-admin-client/lib/get-authors.js');
33
95
  return getAuthors(this.apiKey, this.baseUrl, params);
34
96
  }
35
97
  async getAuthorBySlug(slug) {
36
- const { getAuthorBySlug } = await import('./pulsemcp-admin-client/lib/get-author-by-slug.js');
37
98
  return getAuthorBySlug(this.apiKey, this.baseUrl, slug);
38
99
  }
39
100
  async getAuthorById(id) {
40
- const { getAuthorById } = await import('./pulsemcp-admin-client/lib/get-author-by-id.js');
41
101
  return getAuthorById(this.apiKey, this.baseUrl, id);
42
102
  }
43
103
  async getMCPServerBySlug(slug) {
44
- const { getMCPServerBySlug } = await import('./pulsemcp-admin-client/lib/get-mcp-server-by-slug.js');
45
104
  return getMCPServerBySlug(this.apiKey, this.baseUrl, slug);
46
105
  }
47
106
  async getMCPServerById(id) {
48
- const { getMCPServerById } = await import('./pulsemcp-admin-client/lib/get-mcp-server-by-id.js');
49
107
  return getMCPServerById(this.apiKey, this.baseUrl, id);
50
108
  }
51
109
  async getMCPClientBySlug(slug) {
52
- const { getMCPClientBySlug } = await import('./pulsemcp-admin-client/lib/get-mcp-client-by-slug.js');
53
110
  return getMCPClientBySlug(this.apiKey, this.baseUrl, slug);
54
111
  }
55
112
  async getMCPClientById(id) {
56
- const { getMCPClientById } = await import('./pulsemcp-admin-client/lib/get-mcp-client-by-id.js');
57
113
  return getMCPClientById(this.apiKey, this.baseUrl, id);
58
114
  }
59
115
  async getMCPImplementationById(id) {
60
- const { getMCPImplementationById } = await import('./pulsemcp-admin-client/lib/get-mcp-implementation-by-id.js');
61
116
  return getMCPImplementationById(this.apiKey, this.baseUrl, id);
62
117
  }
63
118
  async searchMCPImplementations(params) {
64
- const { searchMCPImplementations } = await import('./pulsemcp-admin-client/lib/search-mcp-implementations.js');
65
119
  return searchMCPImplementations(this.apiKey, this.baseUrl, params);
66
120
  }
67
121
  async getDraftMCPImplementations(params) {
68
- const { getDraftMCPImplementations } = await import('./pulsemcp-admin-client/lib/get-draft-mcp-implementations.js');
69
122
  return getDraftMCPImplementations(this.apiKey, this.baseUrl, params);
70
123
  }
71
124
  async saveMCPImplementation(id, params) {
72
- const { saveMCPImplementation } = await import('./pulsemcp-admin-client/lib/save-mcp-implementation.js');
73
125
  return saveMCPImplementation(this.apiKey, this.baseUrl, id, params);
74
126
  }
75
127
  async createMCPImplementation(params) {
76
- const { createMCPImplementation } = await import('./pulsemcp-admin-client/lib/create-mcp-implementation.js');
77
128
  return createMCPImplementation(this.apiKey, this.baseUrl, params);
78
129
  }
79
130
  async sendEmail(params) {
80
- const { sendEmail } = await import('./pulsemcp-admin-client/lib/send-email.js');
81
131
  return sendEmail(this.apiKey, this.baseUrl, params);
82
132
  }
83
133
  async searchProviders(params) {
84
- const { searchProviders } = await import('./pulsemcp-admin-client/lib/search-providers.js');
85
134
  return searchProviders(this.apiKey, this.baseUrl, params);
86
135
  }
87
136
  async getProviderById(id) {
88
- const { getProviderById } = await import('./pulsemcp-admin-client/lib/get-provider-by-id.js');
89
137
  return getProviderById(this.apiKey, this.baseUrl, id);
90
138
  }
91
139
  // Official Mirror Queue methods
92
140
  async getOfficialMirrorQueueItems(params) {
93
- const { getOfficialMirrorQueueItems } = await import('./pulsemcp-admin-client/lib/get-official-mirror-queue-items.js');
94
141
  return getOfficialMirrorQueueItems(this.apiKey, this.baseUrl, params);
95
142
  }
96
143
  async getOfficialMirrorQueueItem(id) {
97
- const { getOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/get-official-mirror-queue-item.js');
98
144
  return getOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id);
99
145
  }
100
146
  async approveOfficialMirrorQueueItem(id, mcpServerSlug) {
101
- const { approveOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/approve-official-mirror-queue-item.js');
102
147
  return approveOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id, mcpServerSlug);
103
148
  }
104
149
  async approveOfficialMirrorQueueItemWithoutModifying(id) {
105
- const { approveOfficialMirrorQueueItemWithoutModifying } = await import('./pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.js');
106
150
  return approveOfficialMirrorQueueItemWithoutModifying(this.apiKey, this.baseUrl, id);
107
151
  }
108
152
  async rejectOfficialMirrorQueueItem(id) {
109
- const { rejectOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/reject-official-mirror-queue-item.js');
110
153
  return rejectOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id);
111
154
  }
112
155
  async addOfficialMirrorToRegularQueue(id) {
113
- const { addOfficialMirrorToRegularQueue } = await import('./pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.js');
114
156
  return addOfficialMirrorToRegularQueue(this.apiKey, this.baseUrl, id);
115
157
  }
116
158
  async unlinkOfficialMirrorQueueItem(id) {
117
- const { unlinkOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.js');
118
159
  return unlinkOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id);
119
160
  }
120
161
  // Unofficial Mirror REST API methods
121
162
  async getUnofficialMirrors(params) {
122
- const { getUnofficialMirrors } = await import('./pulsemcp-admin-client/lib/get-unofficial-mirrors.js');
123
163
  return getUnofficialMirrors(this.apiKey, this.baseUrl, params);
124
164
  }
125
165
  async getUnofficialMirror(id) {
126
- const { getUnofficialMirror } = await import('./pulsemcp-admin-client/lib/get-unofficial-mirror.js');
127
166
  return getUnofficialMirror(this.apiKey, this.baseUrl, id);
128
167
  }
129
168
  async createUnofficialMirror(params) {
130
- const { createUnofficialMirror } = await import('./pulsemcp-admin-client/lib/create-unofficial-mirror.js');
131
169
  return createUnofficialMirror(this.apiKey, this.baseUrl, params);
132
170
  }
133
171
  async updateUnofficialMirror(id, params) {
134
- const { updateUnofficialMirror } = await import('./pulsemcp-admin-client/lib/update-unofficial-mirror.js');
135
172
  return updateUnofficialMirror(this.apiKey, this.baseUrl, id, params);
136
173
  }
137
174
  async deleteUnofficialMirror(id) {
138
- const { deleteUnofficialMirror } = await import('./pulsemcp-admin-client/lib/delete-unofficial-mirror.js');
139
175
  return deleteUnofficialMirror(this.apiKey, this.baseUrl, id);
140
176
  }
141
177
  // Official Mirror REST API methods (read-only)
142
178
  async getOfficialMirrors(params) {
143
- const { getOfficialMirrors } = await import('./pulsemcp-admin-client/lib/get-official-mirrors.js');
144
179
  return getOfficialMirrors(this.apiKey, this.baseUrl, params);
145
180
  }
146
181
  async getOfficialMirror(id) {
147
- const { getOfficialMirror } = await import('./pulsemcp-admin-client/lib/get-official-mirror.js');
148
182
  return getOfficialMirror(this.apiKey, this.baseUrl, id);
149
183
  }
150
184
  // Tenant REST API methods (read-only)
151
185
  async getTenants(params) {
152
- const { getTenants } = await import('./pulsemcp-admin-client/lib/get-tenants.js');
153
186
  return getTenants(this.apiKey, this.baseUrl, params);
154
187
  }
155
188
  async getTenant(idOrSlug) {
156
- const { getTenant } = await import('./pulsemcp-admin-client/lib/get-tenant.js');
157
189
  return getTenant(this.apiKey, this.baseUrl, idOrSlug);
158
190
  }
159
191
  // MCP JSON REST API methods
160
192
  async getMcpJsons(params) {
161
- const { getMcpJsons } = await import('./pulsemcp-admin-client/lib/get-mcp-jsons.js');
162
193
  return getMcpJsons(this.apiKey, this.baseUrl, params);
163
194
  }
164
195
  async getMcpJson(id) {
165
- const { getMcpJson } = await import('./pulsemcp-admin-client/lib/get-mcp-json.js');
166
196
  return getMcpJson(this.apiKey, this.baseUrl, id);
167
197
  }
168
198
  async createMcpJson(params) {
169
- const { createMcpJson } = await import('./pulsemcp-admin-client/lib/create-mcp-json.js');
170
199
  return createMcpJson(this.apiKey, this.baseUrl, params);
171
200
  }
172
201
  async updateMcpJson(id, params) {
173
- const { updateMcpJson } = await import('./pulsemcp-admin-client/lib/update-mcp-json.js');
174
202
  return updateMcpJson(this.apiKey, this.baseUrl, id, params);
175
203
  }
176
204
  async deleteMcpJson(id) {
177
- const { deleteMcpJson } = await import('./pulsemcp-admin-client/lib/delete-mcp-json.js');
178
205
  return deleteMcpJson(this.apiKey, this.baseUrl, id);
179
206
  }
180
207
  // Unified MCP Server methods (abstracted interface)
181
208
  async getUnifiedMCPServers(params) {
182
- const { getUnifiedMCPServers } = await import('./pulsemcp-admin-client/lib/get-unified-mcp-servers.js');
183
209
  return getUnifiedMCPServers(this.apiKey, this.baseUrl, params);
184
210
  }
185
211
  async getUnifiedMCPServer(slug) {
186
- const { getUnifiedMCPServer } = await import('./pulsemcp-admin-client/lib/get-unified-mcp-server.js');
187
212
  return getUnifiedMCPServer(this.apiKey, this.baseUrl, slug);
188
213
  }
189
214
  async updateUnifiedMCPServer(implementationId, params) {
190
- const { updateUnifiedMCPServer } = await import('./pulsemcp-admin-client/lib/update-unified-mcp-server.js');
191
215
  return updateUnifiedMCPServer(this.apiKey, this.baseUrl, implementationId, params);
192
216
  }
193
217
  // Redirect REST API methods
194
218
  async getRedirects(params) {
195
- const { getRedirects } = await import('./pulsemcp-admin-client/lib/get-redirects.js');
196
219
  return getRedirects(this.apiKey, this.baseUrl, params);
197
220
  }
198
221
  async getRedirect(id) {
199
- const { getRedirect } = await import('./pulsemcp-admin-client/lib/get-redirect.js');
200
222
  return getRedirect(this.apiKey, this.baseUrl, id);
201
223
  }
202
224
  async createRedirect(params) {
203
- const { createRedirect } = await import('./pulsemcp-admin-client/lib/create-redirect.js');
204
225
  return createRedirect(this.apiKey, this.baseUrl, params);
205
226
  }
206
227
  async updateRedirect(id, params) {
207
- const { updateRedirect } = await import('./pulsemcp-admin-client/lib/update-redirect.js');
208
228
  return updateRedirect(this.apiKey, this.baseUrl, id, params);
209
229
  }
210
230
  async deleteRedirect(id) {
211
- const { deleteRedirect } = await import('./pulsemcp-admin-client/lib/delete-redirect.js');
212
231
  return deleteRedirect(this.apiKey, this.baseUrl, id);
213
232
  }
214
233
  // GoodJob REST API methods
215
234
  async getGoodJobs(params) {
216
- const { getGoodJobs } = await import('./pulsemcp-admin-client/lib/get-good-jobs.js');
217
235
  return getGoodJobs(this.apiKey, this.baseUrl, params);
218
236
  }
219
237
  async getGoodJob(id) {
220
- const { getGoodJob } = await import('./pulsemcp-admin-client/lib/get-good-job.js');
221
238
  return getGoodJob(this.apiKey, this.baseUrl, id);
222
239
  }
223
240
  async getGoodJobCronSchedules() {
224
- const { getGoodJobCronSchedules } = await import('./pulsemcp-admin-client/lib/get-good-job-cron-schedules.js');
225
241
  return getGoodJobCronSchedules(this.apiKey, this.baseUrl);
226
242
  }
227
243
  async getGoodJobProcesses() {
228
- const { getGoodJobProcesses } = await import('./pulsemcp-admin-client/lib/get-good-job-processes.js');
229
244
  return getGoodJobProcesses(this.apiKey, this.baseUrl);
230
245
  }
231
246
  async getGoodJobStatistics() {
232
- const { getGoodJobStatistics } = await import('./pulsemcp-admin-client/lib/get-good-job-statistics.js');
233
247
  return getGoodJobStatistics(this.apiKey, this.baseUrl);
234
248
  }
235
249
  async retryGoodJob(id) {
236
- const { retryGoodJob } = await import('./pulsemcp-admin-client/lib/retry-good-job.js');
237
250
  return retryGoodJob(this.apiKey, this.baseUrl, id);
238
251
  }
239
252
  async discardGoodJob(id) {
240
- const { discardGoodJob } = await import('./pulsemcp-admin-client/lib/discard-good-job.js');
241
253
  return discardGoodJob(this.apiKey, this.baseUrl, id);
242
254
  }
243
255
  async rescheduleGoodJob(id, scheduledAt) {
244
- const { rescheduleGoodJob } = await import('./pulsemcp-admin-client/lib/reschedule-good-job.js');
245
256
  return rescheduleGoodJob(this.apiKey, this.baseUrl, id, scheduledAt);
246
257
  }
247
258
  async forceTriggerGoodJobCron(cronKey) {
248
- const { forceTriggerGoodJobCron } = await import('./pulsemcp-admin-client/lib/force-trigger-good-job-cron.js');
249
259
  return forceTriggerGoodJobCron(this.apiKey, this.baseUrl, cronKey);
250
260
  }
251
261
  async cleanupGoodJobs(params) {
252
- const { cleanupGoodJobs } = await import('./pulsemcp-admin-client/lib/cleanup-good-jobs.js');
253
262
  return cleanupGoodJobs(this.apiKey, this.baseUrl, params);
254
263
  }
255
264
  // Proctor REST API methods
256
265
  async runExamForMirror(params) {
257
- const { runExamForMirror } = await import('./pulsemcp-admin-client/lib/run-exam-for-mirror.js');
258
266
  return runExamForMirror(this.apiKey, this.baseUrl, params);
259
267
  }
260
268
  async saveResultsForMirror(params) {
261
- const { saveResultsForMirror } = await import('./pulsemcp-admin-client/lib/save-results-for-mirror.js');
262
269
  return saveResultsForMirror(this.apiKey, this.baseUrl, params);
263
270
  }
264
271
  async getProctorRuns(params) {
265
- const { getProctorRuns } = await import('./pulsemcp-admin-client/lib/get-proctor-runs.js');
266
272
  return getProctorRuns(this.apiKey, this.baseUrl, params);
267
273
  }
274
+ async getProctorMetadata() {
275
+ return getProctorMetadata(this.apiKey, this.baseUrl);
276
+ }
268
277
  // Discovered URL REST API methods
269
278
  async getDiscoveredUrls(params) {
270
- const { getDiscoveredUrls } = await import('./pulsemcp-admin-client/lib/get-discovered-urls.js');
271
279
  return getDiscoveredUrls(this.apiKey, this.baseUrl, params);
272
280
  }
273
281
  async markDiscoveredUrlProcessed(params) {
274
- const { markDiscoveredUrlProcessed } = await import('./pulsemcp-admin-client/lib/mark-discovered-url-processed.js');
275
282
  return markDiscoveredUrlProcessed(this.apiKey, this.baseUrl, params);
276
283
  }
277
284
  async getDiscoveredUrlStats() {
278
- const { getDiscoveredUrlStats } = await import('./pulsemcp-admin-client/lib/get-discovered-url-stats.js');
279
285
  return getDiscoveredUrlStats(this.apiKey, this.baseUrl);
280
286
  }
281
287
  }
@@ -0,0 +1,59 @@
1
+ export function getProctorMetadata(_server, clientFactory) {
2
+ return {
3
+ name: 'get_proctor_metadata',
4
+ description: `Get available runtimes and exams for Proctor testing.
5
+
6
+ Returns the list of available runtime environments (Docker images) and exam types.
7
+
8
+ **Returns:**
9
+ - runtimes: Array of runtime configurations with id, name, and Docker image
10
+ - exams: Array of exam types with id, name, and description
11
+
12
+ **Use cases:**
13
+ - Discover available runtime environments and their IDs (needed for run_exam_for_mirror)
14
+ - Find the correct exam ID for a specific test type
15
+ - Check which runtime versions are available`,
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {},
19
+ required: [],
20
+ },
21
+ handler: async () => {
22
+ const client = clientFactory();
23
+ try {
24
+ const response = await client.getProctorMetadata();
25
+ let content = '## Available Proctor Runtimes\n\n';
26
+ for (const runtime of response.runtimes) {
27
+ content += `- **${runtime.name}** (id: \`${runtime.id}\`)\n`;
28
+ content += ` Image: \`${runtime.image}\`\n`;
29
+ }
30
+ content += '\n## Available Exams\n\n';
31
+ for (const exam of response.exams) {
32
+ content += `- **${exam.name}** (id: \`${exam.id}\`)\n`;
33
+ if (exam.description) {
34
+ content += ` ${exam.description}\n`;
35
+ }
36
+ }
37
+ return {
38
+ content: [
39
+ {
40
+ type: 'text',
41
+ text: content.trim(),
42
+ },
43
+ ],
44
+ };
45
+ }
46
+ catch (error) {
47
+ return {
48
+ content: [
49
+ {
50
+ type: 'text',
51
+ text: `Error getting Proctor metadata: ${error instanceof Error ? error.message : String(error)}`,
52
+ },
53
+ ],
54
+ isError: true,
55
+ };
56
+ }
57
+ },
58
+ };
59
+ }
@@ -61,6 +61,7 @@ import { runExamForMirror } from './tools/run-exam-for-mirror.js';
61
61
  import { getExamResult } from './tools/get-exam-result.js';
62
62
  import { saveResultsForMirror } from './tools/save-results-for-mirror.js';
63
63
  import { listProctorRuns } from './tools/list-proctor-runs.js';
64
+ import { getProctorMetadata } from './tools/get-proctor-metadata.js';
64
65
  // Discovered URLs tools
65
66
  import { listDiscoveredUrls } from './tools/list-discovered-urls.js';
66
67
  import { markDiscoveredUrlProcessed } from './tools/mark-discovered-url-processed.js';
@@ -232,6 +233,7 @@ const ALL_TOOLS = [
232
233
  { factory: getExamResult, groups: ['proctor'], isWriteOperation: false },
233
234
  { factory: saveResultsForMirror, groups: ['proctor'], isWriteOperation: true },
234
235
  { factory: listProctorRuns, groups: ['proctor'], isWriteOperation: false },
236
+ { factory: getProctorMetadata, groups: ['proctor'], isWriteOperation: false },
235
237
  // Discovered URLs tools
236
238
  { factory: listDiscoveredUrls, groups: ['discovered_urls'], isWriteOperation: false },
237
239
  {
@@ -369,7 +371,7 @@ function shouldIncludeTool(toolDef, enabledGroups) {
369
371
  * - good_jobs: GoodJob background job management tools (read + write)
370
372
  * - good_jobs_readonly: GoodJob tools (read only)
371
373
  * - proctor: Proctor exam execution and result storage tools (read + write)
372
- * - proctor_readonly: Proctor tools (read only - get_exam_result and list_proctor_runs)
374
+ * - proctor_readonly: Proctor tools (read only - get_exam_result, list_proctor_runs, and get_proctor_metadata)
373
375
  * - discovered_urls: Discovered URL management tools for processing URLs into MCP implementations (read + write)
374
376
  * - discovered_urls_readonly: Discovered URL tools (read only - list and stats)
375
377
  * - notifications: Notification email tools - send_impl_posted_notif (write-only, no readonly variant)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsemcp-cms-admin-mcp-server",
3
- "version": "0.9.5",
3
+ "version": "0.9.7",
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",
@@ -0,0 +1,6 @@
1
+ import type { ProctorMetadataResponse } from '../../types.js';
2
+ /**
3
+ * Get available runtimes and exams from the Proctor API
4
+ */
5
+ export declare function getProctorMetadata(apiKey: string, baseUrl: string): Promise<ProctorMetadataResponse>;
6
+ //# sourceMappingURL=get-proctor-metadata.d.ts.map
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Get available runtimes and exams from the Proctor API
3
+ */
4
+ export async function getProctorMetadata(apiKey, baseUrl) {
5
+ const url = new URL('/api/proctor/metadata', baseUrl);
6
+ const response = await fetch(url.toString(), {
7
+ method: 'GET',
8
+ headers: {
9
+ 'X-API-Key': apiKey,
10
+ Accept: 'application/json',
11
+ },
12
+ });
13
+ if (!response.ok) {
14
+ if (response.status === 401) {
15
+ throw new Error('Invalid API key');
16
+ }
17
+ if (response.status === 403) {
18
+ throw new Error('User lacks admin privileges or insufficient permissions');
19
+ }
20
+ throw new Error(`Failed to get proctor metadata: ${response.status} ${response.statusText}`);
21
+ }
22
+ return (await response.json());
23
+ }
@@ -964,6 +964,12 @@ export function createMockPulseMCPAdminClient(mockData) {
964
964
  pagination: { current_page: 1, total_pages: 1, total_count: 0, has_next: false, limit: 30 },
965
965
  };
966
966
  },
967
+ async getProctorMetadata() {
968
+ return {
969
+ runtimes: [],
970
+ exams: [],
971
+ };
972
+ },
967
973
  // Discovered URL methods
968
974
  async getDiscoveredUrls() {
969
975
  return {
@@ -1,5 +1,5 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import type { Post, PostsResponse, CreatePostParams, UpdatePostParams, ImageUploadResponse, Author, AuthorsResponse, MCPServer, MCPClient, MCPImplementation, MCPImplementationsResponse, SaveMCPImplementationParams, CreateMCPImplementationParams, Provider, ProvidersResponse, OfficialMirrorQueueStatus, OfficialMirrorQueueResponse, OfficialMirrorQueueItemDetail, OfficialMirrorQueueActionResponse, UnofficialMirror, UnofficialMirrorsResponse, CreateUnofficialMirrorParams, UpdateUnofficialMirrorParams, OfficialMirrorRest, OfficialMirrorsResponse, Tenant, TenantsResponse, McpJson, McpJsonsResponse, CreateMcpJsonParams, UpdateMcpJsonParams, UnifiedMCPServer, UnifiedMCPServersResponse, UpdateUnifiedMCPServerParams, Redirect, RedirectsResponse, RedirectStatus, CreateRedirectParams, UpdateRedirectParams, GoodJob, GoodJobsResponse, GoodJobStatus, GoodJobCronSchedule, GoodJobProcess, GoodJobStatistics, GoodJobActionResponse, GoodJobCleanupResponse, ProctorRunExamParams, ProctorRunExamResponse, ProctorSaveResultsParams, ProctorSaveResultsResponse, ProctorRunsResponse, GetProctorRunsParams, DiscoveredUrlsResponse, MarkDiscoveredUrlProcessedParams, MarkDiscoveredUrlProcessedResponse, DiscoveredUrlStats } from './types.js';
2
+ import type { Post, PostsResponse, CreatePostParams, UpdatePostParams, ImageUploadResponse, Author, AuthorsResponse, MCPServer, MCPClient, MCPImplementation, MCPImplementationsResponse, SaveMCPImplementationParams, CreateMCPImplementationParams, Provider, ProvidersResponse, OfficialMirrorQueueStatus, OfficialMirrorQueueResponse, OfficialMirrorQueueItemDetail, OfficialMirrorQueueActionResponse, UnofficialMirror, UnofficialMirrorsResponse, CreateUnofficialMirrorParams, UpdateUnofficialMirrorParams, OfficialMirrorRest, OfficialMirrorsResponse, Tenant, TenantsResponse, McpJson, McpJsonsResponse, CreateMcpJsonParams, UpdateMcpJsonParams, UnifiedMCPServer, UnifiedMCPServersResponse, UpdateUnifiedMCPServerParams, Redirect, RedirectsResponse, RedirectStatus, CreateRedirectParams, UpdateRedirectParams, GoodJob, GoodJobsResponse, GoodJobStatus, GoodJobCronSchedule, GoodJobProcess, GoodJobStatistics, GoodJobActionResponse, GoodJobCleanupResponse, ProctorRunExamParams, ProctorRunExamResponse, ProctorSaveResultsParams, ProctorSaveResultsResponse, ProctorRunsResponse, GetProctorRunsParams, ProctorMetadataResponse, DiscoveredUrlsResponse, MarkDiscoveredUrlProcessedParams, MarkDiscoveredUrlProcessedResponse, DiscoveredUrlStats } from './types.js';
3
3
  export interface IPulseMCPAdminClient {
4
4
  getPosts(params?: {
5
5
  search?: string;
@@ -161,6 +161,7 @@ export interface IPulseMCPAdminClient {
161
161
  runExamForMirror(params: ProctorRunExamParams): Promise<ProctorRunExamResponse>;
162
162
  saveResultsForMirror(params: ProctorSaveResultsParams): Promise<ProctorSaveResultsResponse>;
163
163
  getProctorRuns(params?: GetProctorRunsParams): Promise<ProctorRunsResponse>;
164
+ getProctorMetadata(): Promise<ProctorMetadataResponse>;
164
165
  getDiscoveredUrls(params?: {
165
166
  status?: 'pending' | 'processed' | 'all';
166
167
  page?: number;
@@ -333,6 +334,7 @@ export declare class PulseMCPAdminClient implements IPulseMCPAdminClient {
333
334
  runExamForMirror(params: ProctorRunExamParams): Promise<ProctorRunExamResponse>;
334
335
  saveResultsForMirror(params: ProctorSaveResultsParams): Promise<ProctorSaveResultsResponse>;
335
336
  getProctorRuns(params?: GetProctorRunsParams): Promise<ProctorRunsResponse>;
337
+ getProctorMetadata(): Promise<ProctorMetadataResponse>;
336
338
  getDiscoveredUrls(params?: {
337
339
  status?: 'pending' | 'processed' | 'all';
338
340
  page?: number;
package/shared/server.js CHANGED
@@ -1,5 +1,73 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { createRegisterTools } from './tools.js';
3
+ // Static imports for all API client functions (replaces dynamic imports
4
+ // which can fail at runtime in some environments due to ESM resolution)
5
+ import { getPosts } from './pulsemcp-admin-client/lib/get-posts.js';
6
+ import { getPost } from './pulsemcp-admin-client/lib/get-post.js';
7
+ import { createPost } from './pulsemcp-admin-client/lib/create-post.js';
8
+ import { updatePost } from './pulsemcp-admin-client/lib/update-post.js';
9
+ import { uploadImage } from './pulsemcp-admin-client/lib/upload-image.js';
10
+ import { getAuthors } from './pulsemcp-admin-client/lib/get-authors.js';
11
+ import { getAuthorBySlug } from './pulsemcp-admin-client/lib/get-author-by-slug.js';
12
+ import { getAuthorById } from './pulsemcp-admin-client/lib/get-author-by-id.js';
13
+ import { getMCPServerBySlug } from './pulsemcp-admin-client/lib/get-mcp-server-by-slug.js';
14
+ import { getMCPServerById } from './pulsemcp-admin-client/lib/get-mcp-server-by-id.js';
15
+ import { getMCPClientBySlug } from './pulsemcp-admin-client/lib/get-mcp-client-by-slug.js';
16
+ import { getMCPClientById } from './pulsemcp-admin-client/lib/get-mcp-client-by-id.js';
17
+ import { getMCPImplementationById } from './pulsemcp-admin-client/lib/get-mcp-implementation-by-id.js';
18
+ import { searchMCPImplementations } from './pulsemcp-admin-client/lib/search-mcp-implementations.js';
19
+ import { getDraftMCPImplementations } from './pulsemcp-admin-client/lib/get-draft-mcp-implementations.js';
20
+ import { saveMCPImplementation } from './pulsemcp-admin-client/lib/save-mcp-implementation.js';
21
+ import { createMCPImplementation } from './pulsemcp-admin-client/lib/create-mcp-implementation.js';
22
+ import { sendEmail } from './pulsemcp-admin-client/lib/send-email.js';
23
+ import { searchProviders } from './pulsemcp-admin-client/lib/search-providers.js';
24
+ import { getProviderById } from './pulsemcp-admin-client/lib/get-provider-by-id.js';
25
+ import { getOfficialMirrorQueueItems } from './pulsemcp-admin-client/lib/get-official-mirror-queue-items.js';
26
+ import { getOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/get-official-mirror-queue-item.js';
27
+ import { approveOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/approve-official-mirror-queue-item.js';
28
+ import { approveOfficialMirrorQueueItemWithoutModifying } from './pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.js';
29
+ import { rejectOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/reject-official-mirror-queue-item.js';
30
+ import { addOfficialMirrorToRegularQueue } from './pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.js';
31
+ import { unlinkOfficialMirrorQueueItem } from './pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.js';
32
+ import { getUnofficialMirrors } from './pulsemcp-admin-client/lib/get-unofficial-mirrors.js';
33
+ import { getUnofficialMirror } from './pulsemcp-admin-client/lib/get-unofficial-mirror.js';
34
+ import { createUnofficialMirror } from './pulsemcp-admin-client/lib/create-unofficial-mirror.js';
35
+ import { updateUnofficialMirror } from './pulsemcp-admin-client/lib/update-unofficial-mirror.js';
36
+ import { deleteUnofficialMirror } from './pulsemcp-admin-client/lib/delete-unofficial-mirror.js';
37
+ import { getOfficialMirrors } from './pulsemcp-admin-client/lib/get-official-mirrors.js';
38
+ import { getOfficialMirror } from './pulsemcp-admin-client/lib/get-official-mirror.js';
39
+ import { getTenants } from './pulsemcp-admin-client/lib/get-tenants.js';
40
+ import { getTenant } from './pulsemcp-admin-client/lib/get-tenant.js';
41
+ import { getMcpJsons } from './pulsemcp-admin-client/lib/get-mcp-jsons.js';
42
+ import { getMcpJson } from './pulsemcp-admin-client/lib/get-mcp-json.js';
43
+ import { createMcpJson } from './pulsemcp-admin-client/lib/create-mcp-json.js';
44
+ import { updateMcpJson } from './pulsemcp-admin-client/lib/update-mcp-json.js';
45
+ import { deleteMcpJson } from './pulsemcp-admin-client/lib/delete-mcp-json.js';
46
+ import { getUnifiedMCPServers } from './pulsemcp-admin-client/lib/get-unified-mcp-servers.js';
47
+ import { getUnifiedMCPServer } from './pulsemcp-admin-client/lib/get-unified-mcp-server.js';
48
+ import { updateUnifiedMCPServer } from './pulsemcp-admin-client/lib/update-unified-mcp-server.js';
49
+ import { getRedirects } from './pulsemcp-admin-client/lib/get-redirects.js';
50
+ import { getRedirect } from './pulsemcp-admin-client/lib/get-redirect.js';
51
+ import { createRedirect } from './pulsemcp-admin-client/lib/create-redirect.js';
52
+ import { updateRedirect } from './pulsemcp-admin-client/lib/update-redirect.js';
53
+ import { deleteRedirect } from './pulsemcp-admin-client/lib/delete-redirect.js';
54
+ import { getGoodJobs } from './pulsemcp-admin-client/lib/get-good-jobs.js';
55
+ import { getGoodJob } from './pulsemcp-admin-client/lib/get-good-job.js';
56
+ import { getGoodJobCronSchedules } from './pulsemcp-admin-client/lib/get-good-job-cron-schedules.js';
57
+ import { getGoodJobProcesses } from './pulsemcp-admin-client/lib/get-good-job-processes.js';
58
+ import { getGoodJobStatistics } from './pulsemcp-admin-client/lib/get-good-job-statistics.js';
59
+ import { retryGoodJob } from './pulsemcp-admin-client/lib/retry-good-job.js';
60
+ import { discardGoodJob } from './pulsemcp-admin-client/lib/discard-good-job.js';
61
+ import { rescheduleGoodJob } from './pulsemcp-admin-client/lib/reschedule-good-job.js';
62
+ import { forceTriggerGoodJobCron } from './pulsemcp-admin-client/lib/force-trigger-good-job-cron.js';
63
+ import { cleanupGoodJobs } from './pulsemcp-admin-client/lib/cleanup-good-jobs.js';
64
+ import { runExamForMirror } from './pulsemcp-admin-client/lib/run-exam-for-mirror.js';
65
+ import { saveResultsForMirror } from './pulsemcp-admin-client/lib/save-results-for-mirror.js';
66
+ import { getProctorRuns } from './pulsemcp-admin-client/lib/get-proctor-runs.js';
67
+ import { getProctorMetadata } from './pulsemcp-admin-client/lib/get-proctor-metadata.js';
68
+ import { getDiscoveredUrls } from './pulsemcp-admin-client/lib/get-discovered-urls.js';
69
+ import { markDiscoveredUrlProcessed } from './pulsemcp-admin-client/lib/mark-discovered-url-processed.js';
70
+ import { getDiscoveredUrlStats } from './pulsemcp-admin-client/lib/get-discovered-url-stats.js';
3
71
  // PulseMCP Admin API client implementation
4
72
  export class PulseMCPAdminClient {
5
73
  apiKey;
@@ -9,273 +77,211 @@ export class PulseMCPAdminClient {
9
77
  this.baseUrl = baseUrl || 'https://admin.pulsemcp.com';
10
78
  }
11
79
  async getPosts(params) {
12
- const { getPosts } = await import('./pulsemcp-admin-client/lib/get-posts.js');
13
80
  return getPosts(this.apiKey, this.baseUrl, params);
14
81
  }
15
82
  async getPost(slug) {
16
- const { getPost } = await import('./pulsemcp-admin-client/lib/get-post.js');
17
83
  return getPost(this.apiKey, this.baseUrl, slug);
18
84
  }
19
85
  async createPost(params) {
20
- const { createPost } = await import('./pulsemcp-admin-client/lib/create-post.js');
21
86
  return createPost(this.apiKey, this.baseUrl, params);
22
87
  }
23
88
  async updatePost(slug, params) {
24
- const { updatePost } = await import('./pulsemcp-admin-client/lib/update-post.js');
25
89
  return updatePost(this.apiKey, this.baseUrl, slug, params);
26
90
  }
27
91
  async uploadImage(postSlug, fileName, fileData) {
28
- const { uploadImage } = await import('./pulsemcp-admin-client/lib/upload-image.js');
29
92
  return uploadImage(this.apiKey, this.baseUrl, postSlug, fileName, fileData);
30
93
  }
31
94
  async getAuthors(params) {
32
- const { getAuthors } = await import('./pulsemcp-admin-client/lib/get-authors.js');
33
95
  return getAuthors(this.apiKey, this.baseUrl, params);
34
96
  }
35
97
  async getAuthorBySlug(slug) {
36
- const { getAuthorBySlug } = await import('./pulsemcp-admin-client/lib/get-author-by-slug.js');
37
98
  return getAuthorBySlug(this.apiKey, this.baseUrl, slug);
38
99
  }
39
100
  async getAuthorById(id) {
40
- const { getAuthorById } = await import('./pulsemcp-admin-client/lib/get-author-by-id.js');
41
101
  return getAuthorById(this.apiKey, this.baseUrl, id);
42
102
  }
43
103
  async getMCPServerBySlug(slug) {
44
- const { getMCPServerBySlug } = await import('./pulsemcp-admin-client/lib/get-mcp-server-by-slug.js');
45
104
  return getMCPServerBySlug(this.apiKey, this.baseUrl, slug);
46
105
  }
47
106
  async getMCPServerById(id) {
48
- const { getMCPServerById } = await import('./pulsemcp-admin-client/lib/get-mcp-server-by-id.js');
49
107
  return getMCPServerById(this.apiKey, this.baseUrl, id);
50
108
  }
51
109
  async getMCPClientBySlug(slug) {
52
- const { getMCPClientBySlug } = await import('./pulsemcp-admin-client/lib/get-mcp-client-by-slug.js');
53
110
  return getMCPClientBySlug(this.apiKey, this.baseUrl, slug);
54
111
  }
55
112
  async getMCPClientById(id) {
56
- const { getMCPClientById } = await import('./pulsemcp-admin-client/lib/get-mcp-client-by-id.js');
57
113
  return getMCPClientById(this.apiKey, this.baseUrl, id);
58
114
  }
59
115
  async getMCPImplementationById(id) {
60
- const { getMCPImplementationById } = await import('./pulsemcp-admin-client/lib/get-mcp-implementation-by-id.js');
61
116
  return getMCPImplementationById(this.apiKey, this.baseUrl, id);
62
117
  }
63
118
  async searchMCPImplementations(params) {
64
- const { searchMCPImplementations } = await import('./pulsemcp-admin-client/lib/search-mcp-implementations.js');
65
119
  return searchMCPImplementations(this.apiKey, this.baseUrl, params);
66
120
  }
67
121
  async getDraftMCPImplementations(params) {
68
- const { getDraftMCPImplementations } = await import('./pulsemcp-admin-client/lib/get-draft-mcp-implementations.js');
69
122
  return getDraftMCPImplementations(this.apiKey, this.baseUrl, params);
70
123
  }
71
124
  async saveMCPImplementation(id, params) {
72
- const { saveMCPImplementation } = await import('./pulsemcp-admin-client/lib/save-mcp-implementation.js');
73
125
  return saveMCPImplementation(this.apiKey, this.baseUrl, id, params);
74
126
  }
75
127
  async createMCPImplementation(params) {
76
- const { createMCPImplementation } = await import('./pulsemcp-admin-client/lib/create-mcp-implementation.js');
77
128
  return createMCPImplementation(this.apiKey, this.baseUrl, params);
78
129
  }
79
130
  async sendEmail(params) {
80
- const { sendEmail } = await import('./pulsemcp-admin-client/lib/send-email.js');
81
131
  return sendEmail(this.apiKey, this.baseUrl, params);
82
132
  }
83
133
  async searchProviders(params) {
84
- const { searchProviders } = await import('./pulsemcp-admin-client/lib/search-providers.js');
85
134
  return searchProviders(this.apiKey, this.baseUrl, params);
86
135
  }
87
136
  async getProviderById(id) {
88
- const { getProviderById } = await import('./pulsemcp-admin-client/lib/get-provider-by-id.js');
89
137
  return getProviderById(this.apiKey, this.baseUrl, id);
90
138
  }
91
139
  // Official Mirror Queue methods
92
140
  async getOfficialMirrorQueueItems(params) {
93
- const { getOfficialMirrorQueueItems } = await import('./pulsemcp-admin-client/lib/get-official-mirror-queue-items.js');
94
141
  return getOfficialMirrorQueueItems(this.apiKey, this.baseUrl, params);
95
142
  }
96
143
  async getOfficialMirrorQueueItem(id) {
97
- const { getOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/get-official-mirror-queue-item.js');
98
144
  return getOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id);
99
145
  }
100
146
  async approveOfficialMirrorQueueItem(id, mcpServerSlug) {
101
- const { approveOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/approve-official-mirror-queue-item.js');
102
147
  return approveOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id, mcpServerSlug);
103
148
  }
104
149
  async approveOfficialMirrorQueueItemWithoutModifying(id) {
105
- const { approveOfficialMirrorQueueItemWithoutModifying } = await import('./pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.js');
106
150
  return approveOfficialMirrorQueueItemWithoutModifying(this.apiKey, this.baseUrl, id);
107
151
  }
108
152
  async rejectOfficialMirrorQueueItem(id) {
109
- const { rejectOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/reject-official-mirror-queue-item.js');
110
153
  return rejectOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id);
111
154
  }
112
155
  async addOfficialMirrorToRegularQueue(id) {
113
- const { addOfficialMirrorToRegularQueue } = await import('./pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.js');
114
156
  return addOfficialMirrorToRegularQueue(this.apiKey, this.baseUrl, id);
115
157
  }
116
158
  async unlinkOfficialMirrorQueueItem(id) {
117
- const { unlinkOfficialMirrorQueueItem } = await import('./pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.js');
118
159
  return unlinkOfficialMirrorQueueItem(this.apiKey, this.baseUrl, id);
119
160
  }
120
161
  // Unofficial Mirror REST API methods
121
162
  async getUnofficialMirrors(params) {
122
- const { getUnofficialMirrors } = await import('./pulsemcp-admin-client/lib/get-unofficial-mirrors.js');
123
163
  return getUnofficialMirrors(this.apiKey, this.baseUrl, params);
124
164
  }
125
165
  async getUnofficialMirror(id) {
126
- const { getUnofficialMirror } = await import('./pulsemcp-admin-client/lib/get-unofficial-mirror.js');
127
166
  return getUnofficialMirror(this.apiKey, this.baseUrl, id);
128
167
  }
129
168
  async createUnofficialMirror(params) {
130
- const { createUnofficialMirror } = await import('./pulsemcp-admin-client/lib/create-unofficial-mirror.js');
131
169
  return createUnofficialMirror(this.apiKey, this.baseUrl, params);
132
170
  }
133
171
  async updateUnofficialMirror(id, params) {
134
- const { updateUnofficialMirror } = await import('./pulsemcp-admin-client/lib/update-unofficial-mirror.js');
135
172
  return updateUnofficialMirror(this.apiKey, this.baseUrl, id, params);
136
173
  }
137
174
  async deleteUnofficialMirror(id) {
138
- const { deleteUnofficialMirror } = await import('./pulsemcp-admin-client/lib/delete-unofficial-mirror.js');
139
175
  return deleteUnofficialMirror(this.apiKey, this.baseUrl, id);
140
176
  }
141
177
  // Official Mirror REST API methods (read-only)
142
178
  async getOfficialMirrors(params) {
143
- const { getOfficialMirrors } = await import('./pulsemcp-admin-client/lib/get-official-mirrors.js');
144
179
  return getOfficialMirrors(this.apiKey, this.baseUrl, params);
145
180
  }
146
181
  async getOfficialMirror(id) {
147
- const { getOfficialMirror } = await import('./pulsemcp-admin-client/lib/get-official-mirror.js');
148
182
  return getOfficialMirror(this.apiKey, this.baseUrl, id);
149
183
  }
150
184
  // Tenant REST API methods (read-only)
151
185
  async getTenants(params) {
152
- const { getTenants } = await import('./pulsemcp-admin-client/lib/get-tenants.js');
153
186
  return getTenants(this.apiKey, this.baseUrl, params);
154
187
  }
155
188
  async getTenant(idOrSlug) {
156
- const { getTenant } = await import('./pulsemcp-admin-client/lib/get-tenant.js');
157
189
  return getTenant(this.apiKey, this.baseUrl, idOrSlug);
158
190
  }
159
191
  // MCP JSON REST API methods
160
192
  async getMcpJsons(params) {
161
- const { getMcpJsons } = await import('./pulsemcp-admin-client/lib/get-mcp-jsons.js');
162
193
  return getMcpJsons(this.apiKey, this.baseUrl, params);
163
194
  }
164
195
  async getMcpJson(id) {
165
- const { getMcpJson } = await import('./pulsemcp-admin-client/lib/get-mcp-json.js');
166
196
  return getMcpJson(this.apiKey, this.baseUrl, id);
167
197
  }
168
198
  async createMcpJson(params) {
169
- const { createMcpJson } = await import('./pulsemcp-admin-client/lib/create-mcp-json.js');
170
199
  return createMcpJson(this.apiKey, this.baseUrl, params);
171
200
  }
172
201
  async updateMcpJson(id, params) {
173
- const { updateMcpJson } = await import('./pulsemcp-admin-client/lib/update-mcp-json.js');
174
202
  return updateMcpJson(this.apiKey, this.baseUrl, id, params);
175
203
  }
176
204
  async deleteMcpJson(id) {
177
- const { deleteMcpJson } = await import('./pulsemcp-admin-client/lib/delete-mcp-json.js');
178
205
  return deleteMcpJson(this.apiKey, this.baseUrl, id);
179
206
  }
180
207
  // Unified MCP Server methods (abstracted interface)
181
208
  async getUnifiedMCPServers(params) {
182
- const { getUnifiedMCPServers } = await import('./pulsemcp-admin-client/lib/get-unified-mcp-servers.js');
183
209
  return getUnifiedMCPServers(this.apiKey, this.baseUrl, params);
184
210
  }
185
211
  async getUnifiedMCPServer(slug) {
186
- const { getUnifiedMCPServer } = await import('./pulsemcp-admin-client/lib/get-unified-mcp-server.js');
187
212
  return getUnifiedMCPServer(this.apiKey, this.baseUrl, slug);
188
213
  }
189
214
  async updateUnifiedMCPServer(implementationId, params) {
190
- const { updateUnifiedMCPServer } = await import('./pulsemcp-admin-client/lib/update-unified-mcp-server.js');
191
215
  return updateUnifiedMCPServer(this.apiKey, this.baseUrl, implementationId, params);
192
216
  }
193
217
  // Redirect REST API methods
194
218
  async getRedirects(params) {
195
- const { getRedirects } = await import('./pulsemcp-admin-client/lib/get-redirects.js');
196
219
  return getRedirects(this.apiKey, this.baseUrl, params);
197
220
  }
198
221
  async getRedirect(id) {
199
- const { getRedirect } = await import('./pulsemcp-admin-client/lib/get-redirect.js');
200
222
  return getRedirect(this.apiKey, this.baseUrl, id);
201
223
  }
202
224
  async createRedirect(params) {
203
- const { createRedirect } = await import('./pulsemcp-admin-client/lib/create-redirect.js');
204
225
  return createRedirect(this.apiKey, this.baseUrl, params);
205
226
  }
206
227
  async updateRedirect(id, params) {
207
- const { updateRedirect } = await import('./pulsemcp-admin-client/lib/update-redirect.js');
208
228
  return updateRedirect(this.apiKey, this.baseUrl, id, params);
209
229
  }
210
230
  async deleteRedirect(id) {
211
- const { deleteRedirect } = await import('./pulsemcp-admin-client/lib/delete-redirect.js');
212
231
  return deleteRedirect(this.apiKey, this.baseUrl, id);
213
232
  }
214
233
  // GoodJob REST API methods
215
234
  async getGoodJobs(params) {
216
- const { getGoodJobs } = await import('./pulsemcp-admin-client/lib/get-good-jobs.js');
217
235
  return getGoodJobs(this.apiKey, this.baseUrl, params);
218
236
  }
219
237
  async getGoodJob(id) {
220
- const { getGoodJob } = await import('./pulsemcp-admin-client/lib/get-good-job.js');
221
238
  return getGoodJob(this.apiKey, this.baseUrl, id);
222
239
  }
223
240
  async getGoodJobCronSchedules() {
224
- const { getGoodJobCronSchedules } = await import('./pulsemcp-admin-client/lib/get-good-job-cron-schedules.js');
225
241
  return getGoodJobCronSchedules(this.apiKey, this.baseUrl);
226
242
  }
227
243
  async getGoodJobProcesses() {
228
- const { getGoodJobProcesses } = await import('./pulsemcp-admin-client/lib/get-good-job-processes.js');
229
244
  return getGoodJobProcesses(this.apiKey, this.baseUrl);
230
245
  }
231
246
  async getGoodJobStatistics() {
232
- const { getGoodJobStatistics } = await import('./pulsemcp-admin-client/lib/get-good-job-statistics.js');
233
247
  return getGoodJobStatistics(this.apiKey, this.baseUrl);
234
248
  }
235
249
  async retryGoodJob(id) {
236
- const { retryGoodJob } = await import('./pulsemcp-admin-client/lib/retry-good-job.js');
237
250
  return retryGoodJob(this.apiKey, this.baseUrl, id);
238
251
  }
239
252
  async discardGoodJob(id) {
240
- const { discardGoodJob } = await import('./pulsemcp-admin-client/lib/discard-good-job.js');
241
253
  return discardGoodJob(this.apiKey, this.baseUrl, id);
242
254
  }
243
255
  async rescheduleGoodJob(id, scheduledAt) {
244
- const { rescheduleGoodJob } = await import('./pulsemcp-admin-client/lib/reschedule-good-job.js');
245
256
  return rescheduleGoodJob(this.apiKey, this.baseUrl, id, scheduledAt);
246
257
  }
247
258
  async forceTriggerGoodJobCron(cronKey) {
248
- const { forceTriggerGoodJobCron } = await import('./pulsemcp-admin-client/lib/force-trigger-good-job-cron.js');
249
259
  return forceTriggerGoodJobCron(this.apiKey, this.baseUrl, cronKey);
250
260
  }
251
261
  async cleanupGoodJobs(params) {
252
- const { cleanupGoodJobs } = await import('./pulsemcp-admin-client/lib/cleanup-good-jobs.js');
253
262
  return cleanupGoodJobs(this.apiKey, this.baseUrl, params);
254
263
  }
255
264
  // Proctor REST API methods
256
265
  async runExamForMirror(params) {
257
- const { runExamForMirror } = await import('./pulsemcp-admin-client/lib/run-exam-for-mirror.js');
258
266
  return runExamForMirror(this.apiKey, this.baseUrl, params);
259
267
  }
260
268
  async saveResultsForMirror(params) {
261
- const { saveResultsForMirror } = await import('./pulsemcp-admin-client/lib/save-results-for-mirror.js');
262
269
  return saveResultsForMirror(this.apiKey, this.baseUrl, params);
263
270
  }
264
271
  async getProctorRuns(params) {
265
- const { getProctorRuns } = await import('./pulsemcp-admin-client/lib/get-proctor-runs.js');
266
272
  return getProctorRuns(this.apiKey, this.baseUrl, params);
267
273
  }
274
+ async getProctorMetadata() {
275
+ return getProctorMetadata(this.apiKey, this.baseUrl);
276
+ }
268
277
  // Discovered URL REST API methods
269
278
  async getDiscoveredUrls(params) {
270
- const { getDiscoveredUrls } = await import('./pulsemcp-admin-client/lib/get-discovered-urls.js');
271
279
  return getDiscoveredUrls(this.apiKey, this.baseUrl, params);
272
280
  }
273
281
  async markDiscoveredUrlProcessed(params) {
274
- const { markDiscoveredUrlProcessed } = await import('./pulsemcp-admin-client/lib/mark-discovered-url-processed.js');
275
282
  return markDiscoveredUrlProcessed(this.apiKey, this.baseUrl, params);
276
283
  }
277
284
  async getDiscoveredUrlStats() {
278
- const { getDiscoveredUrlStats } = await import('./pulsemcp-admin-client/lib/get-discovered-url-stats.js');
279
285
  return getDiscoveredUrlStats(this.apiKey, this.baseUrl);
280
286
  }
281
287
  }
@@ -0,0 +1,25 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import type { ClientFactory } from '../server.js';
3
+ export declare function getProctorMetadata(_server: Server, clientFactory: ClientFactory): {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: {
7
+ type: string;
8
+ properties: {};
9
+ required: never[];
10
+ };
11
+ handler: () => Promise<{
12
+ content: {
13
+ type: string;
14
+ text: string;
15
+ }[];
16
+ isError?: undefined;
17
+ } | {
18
+ content: {
19
+ type: string;
20
+ text: string;
21
+ }[];
22
+ isError: boolean;
23
+ }>;
24
+ };
25
+ //# sourceMappingURL=get-proctor-metadata.d.ts.map
@@ -0,0 +1,59 @@
1
+ export function getProctorMetadata(_server, clientFactory) {
2
+ return {
3
+ name: 'get_proctor_metadata',
4
+ description: `Get available runtimes and exams for Proctor testing.
5
+
6
+ Returns the list of available runtime environments (Docker images) and exam types.
7
+
8
+ **Returns:**
9
+ - runtimes: Array of runtime configurations with id, name, and Docker image
10
+ - exams: Array of exam types with id, name, and description
11
+
12
+ **Use cases:**
13
+ - Discover available runtime environments and their IDs (needed for run_exam_for_mirror)
14
+ - Find the correct exam ID for a specific test type
15
+ - Check which runtime versions are available`,
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {},
19
+ required: [],
20
+ },
21
+ handler: async () => {
22
+ const client = clientFactory();
23
+ try {
24
+ const response = await client.getProctorMetadata();
25
+ let content = '## Available Proctor Runtimes\n\n';
26
+ for (const runtime of response.runtimes) {
27
+ content += `- **${runtime.name}** (id: \`${runtime.id}\`)\n`;
28
+ content += ` Image: \`${runtime.image}\`\n`;
29
+ }
30
+ content += '\n## Available Exams\n\n';
31
+ for (const exam of response.exams) {
32
+ content += `- **${exam.name}** (id: \`${exam.id}\`)\n`;
33
+ if (exam.description) {
34
+ content += ` ${exam.description}\n`;
35
+ }
36
+ }
37
+ return {
38
+ content: [
39
+ {
40
+ type: 'text',
41
+ text: content.trim(),
42
+ },
43
+ ],
44
+ };
45
+ }
46
+ catch (error) {
47
+ return {
48
+ content: [
49
+ {
50
+ type: 'text',
51
+ text: `Error getting Proctor metadata: ${error instanceof Error ? error.message : String(error)}`,
52
+ },
53
+ ],
54
+ isError: true,
55
+ };
56
+ }
57
+ },
58
+ };
59
+ }
package/shared/tools.d.ts CHANGED
@@ -23,7 +23,7 @@ import { ClientFactory } from './server.js';
23
23
  * - mcp_servers / mcp_servers_readonly: Unified MCP server tools (abstracted interface)
24
24
  * - redirects / redirects_readonly: URL redirect management tools
25
25
  * - good_jobs / good_jobs_readonly: GoodJob background job management tools
26
- * - proctor / proctor_readonly: Proctor exam execution and result storage tools. The readonly variant includes get_exam_result and list_proctor_runs for retrieving stored results without running exams or saving
26
+ * - proctor / proctor_readonly: Proctor exam execution and result storage tools. The readonly variant includes get_exam_result, list_proctor_runs, and get_proctor_metadata for retrieving stored results and metadata without running exams or saving
27
27
  * - discovered_urls / discovered_urls_readonly: Discovered URL management tools for processing URLs into MCP implementations
28
28
  * - notifications: Notification email tools (send_impl_posted_notif). Separated from server_directory so notification capability can be granted independently.
29
29
  */
@@ -69,7 +69,7 @@ export declare function parseEnabledToolGroups(enabledGroupsParam?: string): Too
69
69
  * - good_jobs: GoodJob background job management tools (read + write)
70
70
  * - good_jobs_readonly: GoodJob tools (read only)
71
71
  * - proctor: Proctor exam execution and result storage tools (read + write)
72
- * - proctor_readonly: Proctor tools (read only - get_exam_result and list_proctor_runs)
72
+ * - proctor_readonly: Proctor tools (read only - get_exam_result, list_proctor_runs, and get_proctor_metadata)
73
73
  * - discovered_urls: Discovered URL management tools for processing URLs into MCP implementations (read + write)
74
74
  * - discovered_urls_readonly: Discovered URL tools (read only - list and stats)
75
75
  * - notifications: Notification email tools - send_impl_posted_notif (write-only, no readonly variant)
package/shared/tools.js CHANGED
@@ -61,6 +61,7 @@ import { runExamForMirror } from './tools/run-exam-for-mirror.js';
61
61
  import { getExamResult } from './tools/get-exam-result.js';
62
62
  import { saveResultsForMirror } from './tools/save-results-for-mirror.js';
63
63
  import { listProctorRuns } from './tools/list-proctor-runs.js';
64
+ import { getProctorMetadata } from './tools/get-proctor-metadata.js';
64
65
  // Discovered URLs tools
65
66
  import { listDiscoveredUrls } from './tools/list-discovered-urls.js';
66
67
  import { markDiscoveredUrlProcessed } from './tools/mark-discovered-url-processed.js';
@@ -232,6 +233,7 @@ const ALL_TOOLS = [
232
233
  { factory: getExamResult, groups: ['proctor'], isWriteOperation: false },
233
234
  { factory: saveResultsForMirror, groups: ['proctor'], isWriteOperation: true },
234
235
  { factory: listProctorRuns, groups: ['proctor'], isWriteOperation: false },
236
+ { factory: getProctorMetadata, groups: ['proctor'], isWriteOperation: false },
235
237
  // Discovered URLs tools
236
238
  { factory: listDiscoveredUrls, groups: ['discovered_urls'], isWriteOperation: false },
237
239
  {
@@ -369,7 +371,7 @@ function shouldIncludeTool(toolDef, enabledGroups) {
369
371
  * - good_jobs: GoodJob background job management tools (read + write)
370
372
  * - good_jobs_readonly: GoodJob tools (read only)
371
373
  * - proctor: Proctor exam execution and result storage tools (read + write)
372
- * - proctor_readonly: Proctor tools (read only - get_exam_result and list_proctor_runs)
374
+ * - proctor_readonly: Proctor tools (read only - get_exam_result, list_proctor_runs, and get_proctor_metadata)
373
375
  * - discovered_urls: Discovered URL management tools for processing URLs into MCP implementations (read + write)
374
376
  * - discovered_urls_readonly: Discovered URL tools (read only - list and stats)
375
377
  * - notifications: Notification email tools - send_impl_posted_notif (write-only, no readonly variant)
package/shared/types.d.ts CHANGED
@@ -736,6 +736,20 @@ export interface GetProctorRunsParams {
736
736
  limit?: number;
737
737
  offset?: number;
738
738
  }
739
+ export interface ProctorRuntime {
740
+ id: string;
741
+ name: string;
742
+ image: string;
743
+ }
744
+ export interface ProctorExam {
745
+ id: string;
746
+ name: string;
747
+ description: string;
748
+ }
749
+ export interface ProctorMetadataResponse {
750
+ runtimes: ProctorRuntime[];
751
+ exams: ProctorExam[];
752
+ }
739
753
  export type DiscoveredUrlResult = 'posted' | 'skipped' | 'rejected' | 'error';
740
754
  export interface DiscoveredUrl {
741
755
  id: number;