pulsemcp-cms-admin-mcp-server 0.9.6 → 0.9.9
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/shared/src/pulsemcp-admin-client/lib/get-proctor-metadata.js +23 -0
- package/build/shared/src/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js +6 -0
- package/build/shared/src/server.js +4 -0
- package/build/shared/src/tools/get-proctor-metadata.js +59 -0
- package/build/shared/src/tools/list-discovered-urls.js +7 -3
- package/build/shared/src/tools/mark-discovered-url-processed.js +10 -6
- package/build/shared/src/tools.js +3 -1
- package/package.json +1 -1
- package/shared/pulsemcp-admin-client/lib/get-discovered-urls.d.ts +1 -1
- package/shared/pulsemcp-admin-client/lib/get-proctor-metadata.d.ts +6 -0
- package/shared/pulsemcp-admin-client/lib/get-proctor-metadata.js +23 -0
- package/shared/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js +6 -0
- package/shared/server.d.ts +5 -3
- package/shared/server.js +4 -0
- package/shared/tools/get-proctor-metadata.d.ts +25 -0
- package/shared/tools/get-proctor-metadata.js +59 -0
- package/shared/tools/list-discovered-urls.d.ts +1 -1
- package/shared/tools/list-discovered-urls.js +7 -3
- package/shared/tools/mark-discovered-url-processed.d.ts +2 -2
- package/shared/tools/mark-discovered-url-processed.js +10 -6
- package/shared/tools.d.ts +2 -2
- package/shared/tools.js +3 -1
- package/shared/types.d.ts +15 -1
|
@@ -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 {
|
|
@@ -64,6 +64,7 @@ import { cleanupGoodJobs } from './pulsemcp-admin-client/lib/cleanup-good-jobs.j
|
|
|
64
64
|
import { runExamForMirror } from './pulsemcp-admin-client/lib/run-exam-for-mirror.js';
|
|
65
65
|
import { saveResultsForMirror } from './pulsemcp-admin-client/lib/save-results-for-mirror.js';
|
|
66
66
|
import { getProctorRuns } from './pulsemcp-admin-client/lib/get-proctor-runs.js';
|
|
67
|
+
import { getProctorMetadata } from './pulsemcp-admin-client/lib/get-proctor-metadata.js';
|
|
67
68
|
import { getDiscoveredUrls } from './pulsemcp-admin-client/lib/get-discovered-urls.js';
|
|
68
69
|
import { markDiscoveredUrlProcessed } from './pulsemcp-admin-client/lib/mark-discovered-url-processed.js';
|
|
69
70
|
import { getDiscoveredUrlStats } from './pulsemcp-admin-client/lib/get-discovered-url-stats.js';
|
|
@@ -270,6 +271,9 @@ export class PulseMCPAdminClient {
|
|
|
270
271
|
async getProctorRuns(params) {
|
|
271
272
|
return getProctorRuns(this.apiKey, this.baseUrl, params);
|
|
272
273
|
}
|
|
274
|
+
async getProctorMetadata() {
|
|
275
|
+
return getProctorMetadata(this.apiKey, this.baseUrl);
|
|
276
|
+
}
|
|
273
277
|
// Discovered URL REST API methods
|
|
274
278
|
async getDiscoveredUrls(params) {
|
|
275
279
|
return getDiscoveredUrls(this.apiKey, this.baseUrl, params);
|
|
@@ -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
|
+
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
const PARAM_DESCRIPTIONS = {
|
|
3
|
-
status: 'Filter by processing status: "pending" (unprocessed, default), "processed", or "all"',
|
|
3
|
+
status: 'Filter by processing status: "pending" (unprocessed, default), "processed", "needs_indexing" (awaiting indexing), or "all"',
|
|
4
4
|
page: 'Page number for pagination. Default: 1',
|
|
5
5
|
per_page: 'Results per page, range 1-100. Default: 50',
|
|
6
6
|
};
|
|
7
7
|
const ListDiscoveredUrlsSchema = z.object({
|
|
8
|
-
status: z
|
|
8
|
+
status: z
|
|
9
|
+
.enum(['pending', 'processed', 'needs_indexing', 'all'])
|
|
10
|
+
.optional()
|
|
11
|
+
.describe(PARAM_DESCRIPTIONS.status),
|
|
9
12
|
page: z.number().min(1).optional().describe(PARAM_DESCRIPTIONS.page),
|
|
10
13
|
per_page: z.number().min(1).max(100).optional().describe(PARAM_DESCRIPTIONS.per_page),
|
|
11
14
|
});
|
|
@@ -34,13 +37,14 @@ Example response:
|
|
|
34
37
|
Use cases:
|
|
35
38
|
- Browse unprocessed discovered URLs for review
|
|
36
39
|
- Page through pending URLs to process them into MCP implementations
|
|
40
|
+
- Query needs_indexing URLs for the daily ingest pipeline
|
|
37
41
|
- Check processed URLs for audit purposes`,
|
|
38
42
|
inputSchema: {
|
|
39
43
|
type: 'object',
|
|
40
44
|
properties: {
|
|
41
45
|
status: {
|
|
42
46
|
type: 'string',
|
|
43
|
-
enum: ['pending', 'processed', 'all'],
|
|
47
|
+
enum: ['pending', 'processed', 'needs_indexing', 'all'],
|
|
44
48
|
description: PARAM_DESCRIPTIONS.status,
|
|
45
49
|
},
|
|
46
50
|
page: { type: 'number', minimum: 1, description: PARAM_DESCRIPTIONS.page },
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
const PARAM_DESCRIPTIONS = {
|
|
3
3
|
id: 'The ID of the discovered URL to mark as processed',
|
|
4
|
-
result: 'Processing result: "posted" (created MCP implementation), "skipped" (not relevant), "rejected" (invalid),
|
|
4
|
+
result: 'Processing result: "posted" (published MCP implementation), "drafted" (created draft MCP implementation), "skipped" (not relevant), "rejected" (invalid), "error" (processing failed), or "needs_indexing" (awaiting indexing)',
|
|
5
5
|
notes: 'Reason for skip/reject/error (e.g., "Not an MCP server", "Duplicate of ID 5678")',
|
|
6
|
-
mcp_implementation_id: 'The ID of the created mcp_implementation (
|
|
6
|
+
mcp_implementation_id: 'The ID of the created mcp_implementation (when result is "posted" or "drafted")',
|
|
7
7
|
};
|
|
8
8
|
const MarkDiscoveredUrlProcessedSchema = z.object({
|
|
9
9
|
id: z.number().describe(PARAM_DESCRIPTIONS.id),
|
|
10
|
-
result: z
|
|
10
|
+
result: z
|
|
11
|
+
.enum(['posted', 'skipped', 'rejected', 'error', 'needs_indexing', 'drafted'])
|
|
12
|
+
.describe(PARAM_DESCRIPTIONS.result),
|
|
11
13
|
notes: z.string().optional().describe(PARAM_DESCRIPTIONS.notes),
|
|
12
14
|
mcp_implementation_id: z.number().optional().describe(PARAM_DESCRIPTIONS.mcp_implementation_id),
|
|
13
15
|
});
|
|
@@ -19,17 +21,19 @@ export function markDiscoveredUrlProcessed(_server, clientFactory) {
|
|
|
19
21
|
Idempotent — calling on an already-processed URL updates the fields.
|
|
20
22
|
|
|
21
23
|
Use cases:
|
|
22
|
-
- Mark a URL as "posted" after
|
|
24
|
+
- Mark a URL as "posted" after publishing an MCP implementation from it
|
|
25
|
+
- Mark a URL as "drafted" after creating a draft MCP implementation from it
|
|
23
26
|
- Mark a URL as "skipped" if it's not relevant (e.g., not an MCP server)
|
|
24
27
|
- Mark a URL as "rejected" if it's invalid or a duplicate
|
|
25
|
-
- Mark a URL as "error" if processing failed
|
|
28
|
+
- Mark a URL as "error" if processing failed
|
|
29
|
+
- Mark a URL as "needs_indexing" to flag it for the indexing pipeline`,
|
|
26
30
|
inputSchema: {
|
|
27
31
|
type: 'object',
|
|
28
32
|
properties: {
|
|
29
33
|
id: { type: 'number', description: PARAM_DESCRIPTIONS.id },
|
|
30
34
|
result: {
|
|
31
35
|
type: 'string',
|
|
32
|
-
enum: ['posted', 'skipped', 'rejected', 'error'],
|
|
36
|
+
enum: ['posted', 'skipped', 'rejected', 'error', 'needs_indexing', 'drafted'],
|
|
33
37
|
description: PARAM_DESCRIPTIONS.result,
|
|
34
38
|
},
|
|
35
39
|
notes: { type: 'string', description: PARAM_DESCRIPTIONS.notes },
|
|
@@ -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
|
|
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
|
import type { DiscoveredUrlsResponse } from '../../types.js';
|
|
2
2
|
export declare function getDiscoveredUrls(apiKey: string, baseUrl: string, params?: {
|
|
3
|
-
status?: 'pending' | 'processed' | 'all';
|
|
3
|
+
status?: 'pending' | 'processed' | 'needs_indexing' | 'all';
|
|
4
4
|
page?: number;
|
|
5
5
|
per_page?: number;
|
|
6
6
|
}): Promise<DiscoveredUrlsResponse>;
|
|
@@ -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 {
|
package/shared/server.d.ts
CHANGED
|
@@ -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,8 +161,9 @@ 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
|
-
status?: 'pending' | 'processed' | 'all';
|
|
166
|
+
status?: 'pending' | 'processed' | 'needs_indexing' | 'all';
|
|
166
167
|
page?: number;
|
|
167
168
|
per_page?: number;
|
|
168
169
|
}): Promise<DiscoveredUrlsResponse>;
|
|
@@ -333,8 +334,9 @@ 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
|
-
status?: 'pending' | 'processed' | 'all';
|
|
339
|
+
status?: 'pending' | 'processed' | 'needs_indexing' | 'all';
|
|
338
340
|
page?: number;
|
|
339
341
|
per_page?: number;
|
|
340
342
|
}): Promise<DiscoveredUrlsResponse>;
|
package/shared/server.js
CHANGED
|
@@ -64,6 +64,7 @@ import { cleanupGoodJobs } from './pulsemcp-admin-client/lib/cleanup-good-jobs.j
|
|
|
64
64
|
import { runExamForMirror } from './pulsemcp-admin-client/lib/run-exam-for-mirror.js';
|
|
65
65
|
import { saveResultsForMirror } from './pulsemcp-admin-client/lib/save-results-for-mirror.js';
|
|
66
66
|
import { getProctorRuns } from './pulsemcp-admin-client/lib/get-proctor-runs.js';
|
|
67
|
+
import { getProctorMetadata } from './pulsemcp-admin-client/lib/get-proctor-metadata.js';
|
|
67
68
|
import { getDiscoveredUrls } from './pulsemcp-admin-client/lib/get-discovered-urls.js';
|
|
68
69
|
import { markDiscoveredUrlProcessed } from './pulsemcp-admin-client/lib/mark-discovered-url-processed.js';
|
|
69
70
|
import { getDiscoveredUrlStats } from './pulsemcp-admin-client/lib/get-discovered-url-stats.js';
|
|
@@ -270,6 +271,9 @@ export class PulseMCPAdminClient {
|
|
|
270
271
|
async getProctorRuns(params) {
|
|
271
272
|
return getProctorRuns(this.apiKey, this.baseUrl, params);
|
|
272
273
|
}
|
|
274
|
+
async getProctorMetadata() {
|
|
275
|
+
return getProctorMetadata(this.apiKey, this.baseUrl);
|
|
276
|
+
}
|
|
273
277
|
// Discovered URL REST API methods
|
|
274
278
|
async getDiscoveredUrls(params) {
|
|
275
279
|
return getDiscoveredUrls(this.apiKey, this.baseUrl, params);
|
|
@@ -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
|
+
}
|
|
@@ -9,7 +9,7 @@ export declare function listDiscoveredUrls(_server: Server, clientFactory: Clien
|
|
|
9
9
|
status: {
|
|
10
10
|
type: string;
|
|
11
11
|
enum: string[];
|
|
12
|
-
description: "Filter by processing status: \"pending\" (unprocessed, default), \"processed\", or \"all\"";
|
|
12
|
+
description: "Filter by processing status: \"pending\" (unprocessed, default), \"processed\", \"needs_indexing\" (awaiting indexing), or \"all\"";
|
|
13
13
|
};
|
|
14
14
|
page: {
|
|
15
15
|
type: string;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
const PARAM_DESCRIPTIONS = {
|
|
3
|
-
status: 'Filter by processing status: "pending" (unprocessed, default), "processed", or "all"',
|
|
3
|
+
status: 'Filter by processing status: "pending" (unprocessed, default), "processed", "needs_indexing" (awaiting indexing), or "all"',
|
|
4
4
|
page: 'Page number for pagination. Default: 1',
|
|
5
5
|
per_page: 'Results per page, range 1-100. Default: 50',
|
|
6
6
|
};
|
|
7
7
|
const ListDiscoveredUrlsSchema = z.object({
|
|
8
|
-
status: z
|
|
8
|
+
status: z
|
|
9
|
+
.enum(['pending', 'processed', 'needs_indexing', 'all'])
|
|
10
|
+
.optional()
|
|
11
|
+
.describe(PARAM_DESCRIPTIONS.status),
|
|
9
12
|
page: z.number().min(1).optional().describe(PARAM_DESCRIPTIONS.page),
|
|
10
13
|
per_page: z.number().min(1).max(100).optional().describe(PARAM_DESCRIPTIONS.per_page),
|
|
11
14
|
});
|
|
@@ -34,13 +37,14 @@ Example response:
|
|
|
34
37
|
Use cases:
|
|
35
38
|
- Browse unprocessed discovered URLs for review
|
|
36
39
|
- Page through pending URLs to process them into MCP implementations
|
|
40
|
+
- Query needs_indexing URLs for the daily ingest pipeline
|
|
37
41
|
- Check processed URLs for audit purposes`,
|
|
38
42
|
inputSchema: {
|
|
39
43
|
type: 'object',
|
|
40
44
|
properties: {
|
|
41
45
|
status: {
|
|
42
46
|
type: 'string',
|
|
43
|
-
enum: ['pending', 'processed', 'all'],
|
|
47
|
+
enum: ['pending', 'processed', 'needs_indexing', 'all'],
|
|
44
48
|
description: PARAM_DESCRIPTIONS.status,
|
|
45
49
|
},
|
|
46
50
|
page: { type: 'number', minimum: 1, description: PARAM_DESCRIPTIONS.page },
|
|
@@ -13,7 +13,7 @@ export declare function markDiscoveredUrlProcessed(_server: Server, clientFactor
|
|
|
13
13
|
result: {
|
|
14
14
|
type: string;
|
|
15
15
|
enum: string[];
|
|
16
|
-
description: "Processing result: \"posted\" (created MCP implementation), \"skipped\" (not relevant), \"rejected\" (invalid),
|
|
16
|
+
description: "Processing result: \"posted\" (published MCP implementation), \"drafted\" (created draft MCP implementation), \"skipped\" (not relevant), \"rejected\" (invalid), \"error\" (processing failed), or \"needs_indexing\" (awaiting indexing)";
|
|
17
17
|
};
|
|
18
18
|
notes: {
|
|
19
19
|
type: string;
|
|
@@ -21,7 +21,7 @@ export declare function markDiscoveredUrlProcessed(_server: Server, clientFactor
|
|
|
21
21
|
};
|
|
22
22
|
mcp_implementation_id: {
|
|
23
23
|
type: string;
|
|
24
|
-
description: "The ID of the created mcp_implementation (
|
|
24
|
+
description: "The ID of the created mcp_implementation (when result is \"posted\" or \"drafted\")";
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
required: string[];
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
const PARAM_DESCRIPTIONS = {
|
|
3
3
|
id: 'The ID of the discovered URL to mark as processed',
|
|
4
|
-
result: 'Processing result: "posted" (created MCP implementation), "skipped" (not relevant), "rejected" (invalid),
|
|
4
|
+
result: 'Processing result: "posted" (published MCP implementation), "drafted" (created draft MCP implementation), "skipped" (not relevant), "rejected" (invalid), "error" (processing failed), or "needs_indexing" (awaiting indexing)',
|
|
5
5
|
notes: 'Reason for skip/reject/error (e.g., "Not an MCP server", "Duplicate of ID 5678")',
|
|
6
|
-
mcp_implementation_id: 'The ID of the created mcp_implementation (
|
|
6
|
+
mcp_implementation_id: 'The ID of the created mcp_implementation (when result is "posted" or "drafted")',
|
|
7
7
|
};
|
|
8
8
|
const MarkDiscoveredUrlProcessedSchema = z.object({
|
|
9
9
|
id: z.number().describe(PARAM_DESCRIPTIONS.id),
|
|
10
|
-
result: z
|
|
10
|
+
result: z
|
|
11
|
+
.enum(['posted', 'skipped', 'rejected', 'error', 'needs_indexing', 'drafted'])
|
|
12
|
+
.describe(PARAM_DESCRIPTIONS.result),
|
|
11
13
|
notes: z.string().optional().describe(PARAM_DESCRIPTIONS.notes),
|
|
12
14
|
mcp_implementation_id: z.number().optional().describe(PARAM_DESCRIPTIONS.mcp_implementation_id),
|
|
13
15
|
});
|
|
@@ -19,17 +21,19 @@ export function markDiscoveredUrlProcessed(_server, clientFactory) {
|
|
|
19
21
|
Idempotent — calling on an already-processed URL updates the fields.
|
|
20
22
|
|
|
21
23
|
Use cases:
|
|
22
|
-
- Mark a URL as "posted" after
|
|
24
|
+
- Mark a URL as "posted" after publishing an MCP implementation from it
|
|
25
|
+
- Mark a URL as "drafted" after creating a draft MCP implementation from it
|
|
23
26
|
- Mark a URL as "skipped" if it's not relevant (e.g., not an MCP server)
|
|
24
27
|
- Mark a URL as "rejected" if it's invalid or a duplicate
|
|
25
|
-
- Mark a URL as "error" if processing failed
|
|
28
|
+
- Mark a URL as "error" if processing failed
|
|
29
|
+
- Mark a URL as "needs_indexing" to flag it for the indexing pipeline`,
|
|
26
30
|
inputSchema: {
|
|
27
31
|
type: 'object',
|
|
28
32
|
properties: {
|
|
29
33
|
id: { type: 'number', description: PARAM_DESCRIPTIONS.id },
|
|
30
34
|
result: {
|
|
31
35
|
type: 'string',
|
|
32
|
-
enum: ['posted', 'skipped', 'rejected', 'error'],
|
|
36
|
+
enum: ['posted', 'skipped', 'rejected', 'error', 'needs_indexing', 'drafted'],
|
|
33
37
|
description: PARAM_DESCRIPTIONS.result,
|
|
34
38
|
},
|
|
35
39
|
notes: { type: 'string', description: PARAM_DESCRIPTIONS.notes },
|
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
|
|
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
|
|
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
|
|
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,7 +736,21 @@ export interface GetProctorRunsParams {
|
|
|
736
736
|
limit?: number;
|
|
737
737
|
offset?: number;
|
|
738
738
|
}
|
|
739
|
-
export
|
|
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
|
+
}
|
|
753
|
+
export type DiscoveredUrlResult = 'posted' | 'skipped' | 'rejected' | 'error' | 'needs_indexing' | 'drafted';
|
|
740
754
|
export interface DiscoveredUrl {
|
|
741
755
|
id: number;
|
|
742
756
|
url: string;
|