pulsemcp-cms-admin-mcp-server 0.9.24 → 0.9.27
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/create-api-key.js +3 -1
- package/build/shared/src/pulsemcp-admin-client/lib/delete-api-key.js +3 -1
- package/build/shared/src/pulsemcp-admin-client/lib/delete-tenant.js +3 -1
- package/build/shared/src/pulsemcp-admin-client/lib/set-known-missing-init-tools-list.js +42 -0
- package/build/shared/src/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js +10 -0
- package/build/shared/src/server.js +4 -0
- package/build/shared/src/tools/set-known-missing-init-tools-list.js +75 -0
- package/build/shared/src/tools.js +18 -9
- package/package.json +1 -1
- package/shared/elicitation-config.d.ts +3 -3
- package/shared/pulsemcp-admin-client/lib/create-api-key.js +3 -1
- package/shared/pulsemcp-admin-client/lib/delete-api-key.js +3 -1
- package/shared/pulsemcp-admin-client/lib/delete-tenant.js +3 -1
- package/shared/pulsemcp-admin-client/lib/set-known-missing-init-tools-list.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/set-known-missing-init-tools-list.js +42 -0
- package/shared/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js +10 -0
- package/shared/server.d.ts +3 -1
- package/shared/server.js +4 -0
- package/shared/tools/set-known-missing-init-tools-list.d.ts +38 -0
- package/shared/tools/set-known-missing-init-tools-list.js +75 -0
- package/shared/tools.d.ts +4 -4
- package/shared/tools.js +18 -9
- package/shared/types.d.ts +6 -0
|
@@ -24,7 +24,9 @@ export async function createApiKey(apiKey, baseUrl, params) {
|
|
|
24
24
|
throw new Error('Invalid API key');
|
|
25
25
|
}
|
|
26
26
|
if (response.status === 403) {
|
|
27
|
-
|
|
27
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
28
|
+
const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
|
|
29
|
+
throw new Error(message);
|
|
28
30
|
}
|
|
29
31
|
if (response.status === 404) {
|
|
30
32
|
const errorData = (await response.json());
|
|
@@ -13,7 +13,9 @@ export async function deleteApiKey(apiKey, baseUrl, id) {
|
|
|
13
13
|
throw new Error('Invalid API key');
|
|
14
14
|
}
|
|
15
15
|
if (response.status === 403) {
|
|
16
|
-
|
|
16
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
17
|
+
const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
|
|
18
|
+
throw new Error(message);
|
|
17
19
|
}
|
|
18
20
|
if (response.status === 422) {
|
|
19
21
|
const errorData = (await response.json().catch(() => ({})));
|
|
@@ -16,7 +16,9 @@ export async function deleteTenant(apiKey, baseUrl, params) {
|
|
|
16
16
|
throw new Error('Invalid API key');
|
|
17
17
|
}
|
|
18
18
|
if (response.status === 403) {
|
|
19
|
-
|
|
19
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
20
|
+
const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
|
|
21
|
+
throw new Error(message);
|
|
20
22
|
}
|
|
21
23
|
if (response.status === 404) {
|
|
22
24
|
throw new Error(`Tenant ${params.id_or_slug} not found`);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { adminFetch } from './admin-fetch.js';
|
|
2
|
+
export async function setKnownMissingInitToolsList(apiKey, baseUrl, id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo) {
|
|
3
|
+
const url = new URL(`/api/mcp_servers/${id}/known_missing_init_tools_list`, baseUrl);
|
|
4
|
+
const body = {
|
|
5
|
+
known_missing_init_tools_list: knownMissingInitToolsList,
|
|
6
|
+
};
|
|
7
|
+
if (knownMissingInitToolsListFilterTo !== undefined) {
|
|
8
|
+
// null is sent as JSON null; the Rails controller treats nil/blank as "clear".
|
|
9
|
+
body.known_missing_init_tools_list_filter_to = knownMissingInitToolsListFilterTo;
|
|
10
|
+
}
|
|
11
|
+
const response = await adminFetch(url.toString(), {
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: {
|
|
14
|
+
'X-API-Key': apiKey,
|
|
15
|
+
Accept: 'application/json',
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify(body),
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
if (response.status === 401) {
|
|
22
|
+
throw new Error('Invalid API key');
|
|
23
|
+
}
|
|
24
|
+
if (response.status === 403) {
|
|
25
|
+
throw new Error('User lacks write privileges');
|
|
26
|
+
}
|
|
27
|
+
if (response.status === 404) {
|
|
28
|
+
throw new Error(`MCP server not found: ${id}`);
|
|
29
|
+
}
|
|
30
|
+
if (response.status === 400) {
|
|
31
|
+
const errBody = (await response.json().catch(() => ({})));
|
|
32
|
+
throw new Error(errBody.error ?? 'Bad request');
|
|
33
|
+
}
|
|
34
|
+
if (response.status === 422) {
|
|
35
|
+
const errBody = (await response.json().catch(() => ({})));
|
|
36
|
+
const detailStr = errBody.details?.length ? ` (${errBody.details.join(', ')})` : '';
|
|
37
|
+
throw new Error(`${errBody.error ?? 'Validation failed'}${detailStr}`);
|
|
38
|
+
}
|
|
39
|
+
throw new Error(`Failed to set known_missing_init_tools_list: ${response.status} ${response.statusText}`);
|
|
40
|
+
}
|
|
41
|
+
return (await response.json());
|
|
42
|
+
}
|
|
@@ -1079,5 +1079,15 @@ export function createMockPulseMCPAdminClient(mockData) {
|
|
|
1079
1079
|
message: `Cache successfully refreshed for ${slug}.`,
|
|
1080
1080
|
};
|
|
1081
1081
|
},
|
|
1082
|
+
async setKnownMissingInitToolsList(id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo) {
|
|
1083
|
+
return {
|
|
1084
|
+
id,
|
|
1085
|
+
slug: `mock-server-${id}`,
|
|
1086
|
+
known_missing_init_tools_list: knownMissingInitToolsList,
|
|
1087
|
+
known_missing_init_tools_list_filter_to: knownMissingInitToolsListFilterTo === undefined
|
|
1088
|
+
? null
|
|
1089
|
+
: (knownMissingInitToolsListFilterTo ?? null),
|
|
1090
|
+
};
|
|
1091
|
+
},
|
|
1082
1092
|
};
|
|
1083
1093
|
}
|
|
@@ -72,6 +72,7 @@ import { getMozMetrics } from './pulsemcp-admin-client/lib/get-moz-metrics.js';
|
|
|
72
72
|
import { getMozBacklinks } from './pulsemcp-admin-client/lib/get-moz-backlinks.js';
|
|
73
73
|
import { getMozStoredMetrics } from './pulsemcp-admin-client/lib/get-moz-stored-metrics.js';
|
|
74
74
|
import { recacheMCPServer } from './pulsemcp-admin-client/lib/recache-mcp-server.js';
|
|
75
|
+
import { setKnownMissingInitToolsList } from './pulsemcp-admin-client/lib/set-known-missing-init-tools-list.js';
|
|
75
76
|
import { createTenant } from './pulsemcp-admin-client/lib/create-tenant.js';
|
|
76
77
|
import { createApiKey } from './pulsemcp-admin-client/lib/create-api-key.js';
|
|
77
78
|
import { deleteTenant } from './pulsemcp-admin-client/lib/delete-tenant.js';
|
|
@@ -245,6 +246,9 @@ export class PulseMCPAdminClient {
|
|
|
245
246
|
async recacheMCPServer(slug) {
|
|
246
247
|
return recacheMCPServer(this.apiKey, this.baseUrl, slug);
|
|
247
248
|
}
|
|
249
|
+
async setKnownMissingInitToolsList(id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo) {
|
|
250
|
+
return setKnownMissingInitToolsList(this.apiKey, this.baseUrl, id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo);
|
|
251
|
+
}
|
|
248
252
|
// Redirect REST API methods
|
|
249
253
|
async getRedirects(params) {
|
|
250
254
|
return getRedirects(this.apiKey, this.baseUrl, params);
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const PARAM_DESCRIPTIONS = {
|
|
3
|
+
id: 'The integer id of the MCP server (the "mirror id" used elsewhere in the proctor flow)',
|
|
4
|
+
known_missing_init_tools_list: 'Whether the MCP server is known to be missing the init/tools-list capability. true marks the server as known-missing (proctor will skip the init/tools-list exam); false clears the flag.',
|
|
5
|
+
known_missing_init_tools_list_filter_to: 'Optional. When set, scopes the known-missing flag to a specific entry (e.g., "remotes[0]" or "packages[0]"). Pass an empty string or null to clear the filter. Omit the parameter entirely to leave the existing value untouched.',
|
|
6
|
+
};
|
|
7
|
+
const SetKnownMissingInitToolsListSchema = z.object({
|
|
8
|
+
id: z.number().int().describe(PARAM_DESCRIPTIONS.id),
|
|
9
|
+
known_missing_init_tools_list: z
|
|
10
|
+
.boolean()
|
|
11
|
+
.describe(PARAM_DESCRIPTIONS.known_missing_init_tools_list),
|
|
12
|
+
known_missing_init_tools_list_filter_to: z
|
|
13
|
+
.string()
|
|
14
|
+
.nullable()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe(PARAM_DESCRIPTIONS.known_missing_init_tools_list_filter_to),
|
|
17
|
+
});
|
|
18
|
+
export function setKnownMissingInitToolsList(_server, clientFactory) {
|
|
19
|
+
return {
|
|
20
|
+
name: 'set_known_missing_init_tools_list',
|
|
21
|
+
description: `Update the \`known_missing_init_tools_list\` flag on an MCP server. Optionally also updates the \`known_missing_init_tools_list_filter_to\` scoping value. Identifies the server by integer id (the "mirror id" used elsewhere in the proctor flow).
|
|
22
|
+
|
|
23
|
+
Example request:
|
|
24
|
+
{
|
|
25
|
+
"id": 27765,
|
|
26
|
+
"known_missing_init_tools_list": true,
|
|
27
|
+
"known_missing_init_tools_list_filter_to": "remotes[0]"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Use cases:
|
|
31
|
+
- Mark a server as known-missing the init/tools-list capability so proctor skips that exam
|
|
32
|
+
- Clear the known-missing flag once the server starts responding correctly
|
|
33
|
+
- Scope the known-missing flag to a specific remote/package entry via the filter_to value`,
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
id: { type: 'integer', description: PARAM_DESCRIPTIONS.id },
|
|
38
|
+
known_missing_init_tools_list: {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: PARAM_DESCRIPTIONS.known_missing_init_tools_list,
|
|
41
|
+
},
|
|
42
|
+
known_missing_init_tools_list_filter_to: {
|
|
43
|
+
type: ['string', 'null'],
|
|
44
|
+
description: PARAM_DESCRIPTIONS.known_missing_init_tools_list_filter_to,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
required: ['id', 'known_missing_init_tools_list'],
|
|
48
|
+
},
|
|
49
|
+
handler: async (args) => {
|
|
50
|
+
const validatedArgs = SetKnownMissingInitToolsListSchema.parse(args);
|
|
51
|
+
const client = clientFactory();
|
|
52
|
+
try {
|
|
53
|
+
const result = await client.setKnownMissingInitToolsList(validatedArgs.id, validatedArgs.known_missing_init_tools_list, validatedArgs.known_missing_init_tools_list_filter_to);
|
|
54
|
+
const filterDisplay = result.known_missing_init_tools_list_filter_to === null
|
|
55
|
+
? '(none)'
|
|
56
|
+
: result.known_missing_init_tools_list_filter_to;
|
|
57
|
+
const text = `Updated MCP server ${result.slug} (id: ${result.id}):
|
|
58
|
+
- known_missing_init_tools_list: ${result.known_missing_init_tools_list}
|
|
59
|
+
- known_missing_init_tools_list_filter_to: ${filterDisplay}`;
|
|
60
|
+
return { content: [{ type: 'text', text }] };
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: 'text',
|
|
67
|
+
text: `Error setting known_missing_init_tools_list: ${error instanceof Error ? error.message : String(error)}`,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
isError: true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -70,6 +70,7 @@ import { runExamForMirror } from './tools/run-exam-for-mirror.js';
|
|
|
70
70
|
import { getExamResult } from './tools/get-exam-result.js';
|
|
71
71
|
import { saveResultsForMirror } from './tools/save-results-for-mirror.js';
|
|
72
72
|
import { listProctorRuns } from './tools/list-proctor-runs.js';
|
|
73
|
+
import { setKnownMissingInitToolsList } from './tools/set-known-missing-init-tools-list.js';
|
|
73
74
|
import { getProctorMetadata } from './tools/get-proctor-metadata.js';
|
|
74
75
|
// Discovered URLs tools
|
|
75
76
|
import { listDiscoveredUrls } from './tools/list-discovered-urls.js';
|
|
@@ -184,13 +185,14 @@ const ALL_TOOLS = [
|
|
|
184
185
|
{ factory: getTenant, groups: ['tenants'], isWriteOperation: false },
|
|
185
186
|
{ factory: createTenant, groups: ['tenants'], isWriteOperation: true },
|
|
186
187
|
{ factory: createApiKey, groups: ['tenants'], isWriteOperation: true },
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
//
|
|
188
|
+
// Destructive tenant tools — opt-in only, NOT in BASE_TOOL_GROUPS.
|
|
189
|
+
// revoke_api_key lives here (not in `tenants`) because it calls the same
|
|
190
|
+
// DELETE /api/api_keys/:id endpoint as delete_api_key and the Rails admin
|
|
191
|
+
// API gates that endpoint behind permission_level=all (full_access). The
|
|
192
|
+
// standard read-write admin credential cannot DELETE, so exposing
|
|
193
|
+
// revoke_api_key in the regular tenants group surfaced confusing 403s on
|
|
194
|
+
// workflows like sub-registry credential re-issuance.
|
|
195
|
+
{ factory: revokeApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
|
|
194
196
|
{ factory: deleteTenant, groups: ['tenants_destructive'], isWriteOperation: true },
|
|
195
197
|
{ factory: deleteApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
|
|
196
198
|
// Tenant -> recommended MCP server association tools
|
|
@@ -267,6 +269,13 @@ const ALL_TOOLS = [
|
|
|
267
269
|
{ factory: saveResultsForMirror, groups: ['proctor'], isWriteOperation: true },
|
|
268
270
|
{ factory: listProctorRuns, groups: ['proctor'], isWriteOperation: false },
|
|
269
271
|
{ factory: getProctorMetadata, groups: ['proctor'], isWriteOperation: false },
|
|
272
|
+
// setKnownMissingInitToolsList flips a flag on `mcp_server` records, so it lives in
|
|
273
|
+
// the mcp_servers / server_directory groups (alongside recacheMCPServer), not proctor.
|
|
274
|
+
{
|
|
275
|
+
factory: setKnownMissingInitToolsList,
|
|
276
|
+
groups: ['mcp_servers', 'server_directory'],
|
|
277
|
+
isWriteOperation: true,
|
|
278
|
+
},
|
|
270
279
|
// Discovered URLs tools
|
|
271
280
|
{ factory: listDiscoveredUrls, groups: ['discovered_urls'], isWriteOperation: false },
|
|
272
281
|
{
|
|
@@ -402,9 +411,9 @@ function shouldIncludeTool(toolDef, enabledGroups) {
|
|
|
402
411
|
* - unofficial_mirrors: Unofficial mirror CRUD tools (read + write)
|
|
403
412
|
* - unofficial_mirrors_readonly: Unofficial mirror tools (read only)
|
|
404
413
|
* - official_mirrors_readonly: Official mirrors REST API tools (read only)
|
|
405
|
-
* - tenants: Tenant management tools including API key provisioning
|
|
414
|
+
* - tenants: Tenant management tools including API key provisioning (read + write).
|
|
406
415
|
* - tenants_readonly: Tenant tools (read only)
|
|
407
|
-
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
416
|
+
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
408
417
|
* - mcp_jsons: MCP JSON configuration tools (read + write)
|
|
409
418
|
* - mcp_jsons_readonly: MCP JSON tools (read only)
|
|
410
419
|
* - mcp_servers: Unified MCP server tools with abstracted interface (read + write)
|
package/package.json
CHANGED
|
@@ -8,13 +8,13 @@ import { type ElicitationConfig } from '@pulsemcp/mcp-elicitation';
|
|
|
8
8
|
* 3. Per-action override: PULSEMCP_CMS_ADMIN_ELICITATION_DESTRUCTIVE
|
|
9
9
|
*
|
|
10
10
|
* Destructive elicitation gates the `tenants_destructive` tool group only
|
|
11
|
-
* (delete_tenant, delete_api_key). All other write tools in
|
|
12
|
-
* not gated by elicitation.
|
|
11
|
+
* (delete_tenant, delete_api_key, revoke_api_key). All other write tools in
|
|
12
|
+
* the server are not gated by elicitation.
|
|
13
13
|
*/
|
|
14
14
|
export interface CmsAdminElicitationConfig {
|
|
15
15
|
/** Base elicitation config from the shared library */
|
|
16
16
|
base: ElicitationConfig;
|
|
17
|
-
/** Whether to elicit confirmation for destructive operations (delete_tenant, delete_api_key) */
|
|
17
|
+
/** Whether to elicit confirmation for destructive operations (delete_tenant, delete_api_key, revoke_api_key) */
|
|
18
18
|
destructiveElicitationEnabled: boolean;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -24,7 +24,9 @@ export async function createApiKey(apiKey, baseUrl, params) {
|
|
|
24
24
|
throw new Error('Invalid API key');
|
|
25
25
|
}
|
|
26
26
|
if (response.status === 403) {
|
|
27
|
-
|
|
27
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
28
|
+
const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
|
|
29
|
+
throw new Error(message);
|
|
28
30
|
}
|
|
29
31
|
if (response.status === 404) {
|
|
30
32
|
const errorData = (await response.json());
|
|
@@ -13,7 +13,9 @@ export async function deleteApiKey(apiKey, baseUrl, id) {
|
|
|
13
13
|
throw new Error('Invalid API key');
|
|
14
14
|
}
|
|
15
15
|
if (response.status === 403) {
|
|
16
|
-
|
|
16
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
17
|
+
const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
|
|
18
|
+
throw new Error(message);
|
|
17
19
|
}
|
|
18
20
|
if (response.status === 422) {
|
|
19
21
|
const errorData = (await response.json().catch(() => ({})));
|
|
@@ -16,7 +16,9 @@ export async function deleteTenant(apiKey, baseUrl, params) {
|
|
|
16
16
|
throw new Error('Invalid API key');
|
|
17
17
|
}
|
|
18
18
|
if (response.status === 403) {
|
|
19
|
-
|
|
19
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
20
|
+
const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
|
|
21
|
+
throw new Error(message);
|
|
20
22
|
}
|
|
21
23
|
if (response.status === 404) {
|
|
22
24
|
throw new Error(`Tenant ${params.id_or_slug} not found`);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SetKnownMissingInitToolsListResponse } from '../../types.js';
|
|
2
|
+
export declare function setKnownMissingInitToolsList(apiKey: string, baseUrl: string, id: number, knownMissingInitToolsList: boolean, knownMissingInitToolsListFilterTo?: string | null): Promise<SetKnownMissingInitToolsListResponse>;
|
|
3
|
+
//# sourceMappingURL=set-known-missing-init-tools-list.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { adminFetch } from './admin-fetch.js';
|
|
2
|
+
export async function setKnownMissingInitToolsList(apiKey, baseUrl, id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo) {
|
|
3
|
+
const url = new URL(`/api/mcp_servers/${id}/known_missing_init_tools_list`, baseUrl);
|
|
4
|
+
const body = {
|
|
5
|
+
known_missing_init_tools_list: knownMissingInitToolsList,
|
|
6
|
+
};
|
|
7
|
+
if (knownMissingInitToolsListFilterTo !== undefined) {
|
|
8
|
+
// null is sent as JSON null; the Rails controller treats nil/blank as "clear".
|
|
9
|
+
body.known_missing_init_tools_list_filter_to = knownMissingInitToolsListFilterTo;
|
|
10
|
+
}
|
|
11
|
+
const response = await adminFetch(url.toString(), {
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: {
|
|
14
|
+
'X-API-Key': apiKey,
|
|
15
|
+
Accept: 'application/json',
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify(body),
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
if (response.status === 401) {
|
|
22
|
+
throw new Error('Invalid API key');
|
|
23
|
+
}
|
|
24
|
+
if (response.status === 403) {
|
|
25
|
+
throw new Error('User lacks write privileges');
|
|
26
|
+
}
|
|
27
|
+
if (response.status === 404) {
|
|
28
|
+
throw new Error(`MCP server not found: ${id}`);
|
|
29
|
+
}
|
|
30
|
+
if (response.status === 400) {
|
|
31
|
+
const errBody = (await response.json().catch(() => ({})));
|
|
32
|
+
throw new Error(errBody.error ?? 'Bad request');
|
|
33
|
+
}
|
|
34
|
+
if (response.status === 422) {
|
|
35
|
+
const errBody = (await response.json().catch(() => ({})));
|
|
36
|
+
const detailStr = errBody.details?.length ? ` (${errBody.details.join(', ')})` : '';
|
|
37
|
+
throw new Error(`${errBody.error ?? 'Validation failed'}${detailStr}`);
|
|
38
|
+
}
|
|
39
|
+
throw new Error(`Failed to set known_missing_init_tools_list: ${response.status} ${response.statusText}`);
|
|
40
|
+
}
|
|
41
|
+
return (await response.json());
|
|
42
|
+
}
|
|
@@ -1079,5 +1079,15 @@ export function createMockPulseMCPAdminClient(mockData) {
|
|
|
1079
1079
|
message: `Cache successfully refreshed for ${slug}.`,
|
|
1080
1080
|
};
|
|
1081
1081
|
},
|
|
1082
|
+
async setKnownMissingInitToolsList(id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo) {
|
|
1083
|
+
return {
|
|
1084
|
+
id,
|
|
1085
|
+
slug: `mock-server-${id}`,
|
|
1086
|
+
known_missing_init_tools_list: knownMissingInitToolsList,
|
|
1087
|
+
known_missing_init_tools_list_filter_to: knownMissingInitToolsListFilterTo === undefined
|
|
1088
|
+
? null
|
|
1089
|
+
: (knownMissingInitToolsListFilterTo ?? null),
|
|
1090
|
+
};
|
|
1091
|
+
},
|
|
1082
1092
|
};
|
|
1083
1093
|
}
|
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, ListTenantServersResponse, BulkUpdateTenantServersParams, BulkUpdateTenantServersResponse, 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, MozMetricsResponse, MozBacklinksResponse, MozStoredMetricsResponse, CreateTenantParams, ApiKey, CreateApiKeyParams, DeleteTenantParams, DeleteTenantResponse, DeleteApiKeyResponse, RecacheMCPServerResponse } 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, ListTenantServersResponse, BulkUpdateTenantServersParams, BulkUpdateTenantServersResponse, 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, MozMetricsResponse, MozBacklinksResponse, MozStoredMetricsResponse, CreateTenantParams, ApiKey, CreateApiKeyParams, DeleteTenantParams, DeleteTenantResponse, DeleteApiKeyResponse, RecacheMCPServerResponse, SetKnownMissingInitToolsListResponse } from './types.js';
|
|
3
3
|
export interface IPulseMCPAdminClient {
|
|
4
4
|
getPosts(params?: {
|
|
5
5
|
search?: string;
|
|
@@ -135,6 +135,7 @@ export interface IPulseMCPAdminClient {
|
|
|
135
135
|
getUnifiedMCPServer(slug: string): Promise<UnifiedMCPServer>;
|
|
136
136
|
updateUnifiedMCPServer(implementationId: number, params: UpdateUnifiedMCPServerParams): Promise<UnifiedMCPServer>;
|
|
137
137
|
recacheMCPServer(slug: string): Promise<RecacheMCPServerResponse>;
|
|
138
|
+
setKnownMissingInitToolsList(id: number, knownMissingInitToolsList: boolean, knownMissingInitToolsListFilterTo?: string | null): Promise<SetKnownMissingInitToolsListResponse>;
|
|
138
139
|
getRedirects(params?: {
|
|
139
140
|
q?: string;
|
|
140
141
|
status?: RedirectStatus;
|
|
@@ -334,6 +335,7 @@ export declare class PulseMCPAdminClient implements IPulseMCPAdminClient {
|
|
|
334
335
|
getUnifiedMCPServer(slug: string): Promise<UnifiedMCPServer>;
|
|
335
336
|
updateUnifiedMCPServer(implementationId: number, params: UpdateUnifiedMCPServerParams): Promise<UnifiedMCPServer>;
|
|
336
337
|
recacheMCPServer(slug: string): Promise<RecacheMCPServerResponse>;
|
|
338
|
+
setKnownMissingInitToolsList(id: number, knownMissingInitToolsList: boolean, knownMissingInitToolsListFilterTo?: string | null): Promise<SetKnownMissingInitToolsListResponse>;
|
|
337
339
|
getRedirects(params?: {
|
|
338
340
|
q?: string;
|
|
339
341
|
status?: RedirectStatus;
|
package/shared/server.js
CHANGED
|
@@ -72,6 +72,7 @@ import { getMozMetrics } from './pulsemcp-admin-client/lib/get-moz-metrics.js';
|
|
|
72
72
|
import { getMozBacklinks } from './pulsemcp-admin-client/lib/get-moz-backlinks.js';
|
|
73
73
|
import { getMozStoredMetrics } from './pulsemcp-admin-client/lib/get-moz-stored-metrics.js';
|
|
74
74
|
import { recacheMCPServer } from './pulsemcp-admin-client/lib/recache-mcp-server.js';
|
|
75
|
+
import { setKnownMissingInitToolsList } from './pulsemcp-admin-client/lib/set-known-missing-init-tools-list.js';
|
|
75
76
|
import { createTenant } from './pulsemcp-admin-client/lib/create-tenant.js';
|
|
76
77
|
import { createApiKey } from './pulsemcp-admin-client/lib/create-api-key.js';
|
|
77
78
|
import { deleteTenant } from './pulsemcp-admin-client/lib/delete-tenant.js';
|
|
@@ -245,6 +246,9 @@ export class PulseMCPAdminClient {
|
|
|
245
246
|
async recacheMCPServer(slug) {
|
|
246
247
|
return recacheMCPServer(this.apiKey, this.baseUrl, slug);
|
|
247
248
|
}
|
|
249
|
+
async setKnownMissingInitToolsList(id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo) {
|
|
250
|
+
return setKnownMissingInitToolsList(this.apiKey, this.baseUrl, id, knownMissingInitToolsList, knownMissingInitToolsListFilterTo);
|
|
251
|
+
}
|
|
248
252
|
// Redirect REST API methods
|
|
249
253
|
async getRedirects(params) {
|
|
250
254
|
return getRedirects(this.apiKey, this.baseUrl, params);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import type { ClientFactory } from '../server.js';
|
|
3
|
+
export declare function setKnownMissingInitToolsList(_server: Server, clientFactory: ClientFactory): {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: string;
|
|
8
|
+
properties: {
|
|
9
|
+
id: {
|
|
10
|
+
type: string;
|
|
11
|
+
description: "The integer id of the MCP server (the \"mirror id\" used elsewhere in the proctor flow)";
|
|
12
|
+
};
|
|
13
|
+
known_missing_init_tools_list: {
|
|
14
|
+
type: string;
|
|
15
|
+
description: "Whether the MCP server is known to be missing the init/tools-list capability. true marks the server as known-missing (proctor will skip the init/tools-list exam); false clears the flag.";
|
|
16
|
+
};
|
|
17
|
+
known_missing_init_tools_list_filter_to: {
|
|
18
|
+
type: string[];
|
|
19
|
+
description: "Optional. When set, scopes the known-missing flag to a specific entry (e.g., \"remotes[0]\" or \"packages[0]\"). Pass an empty string or null to clear the filter. Omit the parameter entirely to leave the existing value untouched.";
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
required: string[];
|
|
23
|
+
};
|
|
24
|
+
handler: (args: unknown) => Promise<{
|
|
25
|
+
content: {
|
|
26
|
+
type: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}[];
|
|
29
|
+
isError?: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
content: {
|
|
32
|
+
type: string;
|
|
33
|
+
text: string;
|
|
34
|
+
}[];
|
|
35
|
+
isError: boolean;
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=set-known-missing-init-tools-list.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const PARAM_DESCRIPTIONS = {
|
|
3
|
+
id: 'The integer id of the MCP server (the "mirror id" used elsewhere in the proctor flow)',
|
|
4
|
+
known_missing_init_tools_list: 'Whether the MCP server is known to be missing the init/tools-list capability. true marks the server as known-missing (proctor will skip the init/tools-list exam); false clears the flag.',
|
|
5
|
+
known_missing_init_tools_list_filter_to: 'Optional. When set, scopes the known-missing flag to a specific entry (e.g., "remotes[0]" or "packages[0]"). Pass an empty string or null to clear the filter. Omit the parameter entirely to leave the existing value untouched.',
|
|
6
|
+
};
|
|
7
|
+
const SetKnownMissingInitToolsListSchema = z.object({
|
|
8
|
+
id: z.number().int().describe(PARAM_DESCRIPTIONS.id),
|
|
9
|
+
known_missing_init_tools_list: z
|
|
10
|
+
.boolean()
|
|
11
|
+
.describe(PARAM_DESCRIPTIONS.known_missing_init_tools_list),
|
|
12
|
+
known_missing_init_tools_list_filter_to: z
|
|
13
|
+
.string()
|
|
14
|
+
.nullable()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe(PARAM_DESCRIPTIONS.known_missing_init_tools_list_filter_to),
|
|
17
|
+
});
|
|
18
|
+
export function setKnownMissingInitToolsList(_server, clientFactory) {
|
|
19
|
+
return {
|
|
20
|
+
name: 'set_known_missing_init_tools_list',
|
|
21
|
+
description: `Update the \`known_missing_init_tools_list\` flag on an MCP server. Optionally also updates the \`known_missing_init_tools_list_filter_to\` scoping value. Identifies the server by integer id (the "mirror id" used elsewhere in the proctor flow).
|
|
22
|
+
|
|
23
|
+
Example request:
|
|
24
|
+
{
|
|
25
|
+
"id": 27765,
|
|
26
|
+
"known_missing_init_tools_list": true,
|
|
27
|
+
"known_missing_init_tools_list_filter_to": "remotes[0]"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Use cases:
|
|
31
|
+
- Mark a server as known-missing the init/tools-list capability so proctor skips that exam
|
|
32
|
+
- Clear the known-missing flag once the server starts responding correctly
|
|
33
|
+
- Scope the known-missing flag to a specific remote/package entry via the filter_to value`,
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
id: { type: 'integer', description: PARAM_DESCRIPTIONS.id },
|
|
38
|
+
known_missing_init_tools_list: {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: PARAM_DESCRIPTIONS.known_missing_init_tools_list,
|
|
41
|
+
},
|
|
42
|
+
known_missing_init_tools_list_filter_to: {
|
|
43
|
+
type: ['string', 'null'],
|
|
44
|
+
description: PARAM_DESCRIPTIONS.known_missing_init_tools_list_filter_to,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
required: ['id', 'known_missing_init_tools_list'],
|
|
48
|
+
},
|
|
49
|
+
handler: async (args) => {
|
|
50
|
+
const validatedArgs = SetKnownMissingInitToolsListSchema.parse(args);
|
|
51
|
+
const client = clientFactory();
|
|
52
|
+
try {
|
|
53
|
+
const result = await client.setKnownMissingInitToolsList(validatedArgs.id, validatedArgs.known_missing_init_tools_list, validatedArgs.known_missing_init_tools_list_filter_to);
|
|
54
|
+
const filterDisplay = result.known_missing_init_tools_list_filter_to === null
|
|
55
|
+
? '(none)'
|
|
56
|
+
: result.known_missing_init_tools_list_filter_to;
|
|
57
|
+
const text = `Updated MCP server ${result.slug} (id: ${result.id}):
|
|
58
|
+
- known_missing_init_tools_list: ${result.known_missing_init_tools_list}
|
|
59
|
+
- known_missing_init_tools_list_filter_to: ${filterDisplay}`;
|
|
60
|
+
return { content: [{ type: 'text', text }] };
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: 'text',
|
|
67
|
+
text: `Error setting known_missing_init_tools_list: ${error instanceof Error ? error.message : String(error)}`,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
isError: true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
package/shared/tools.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ import { ClientFactory } from './server.js';
|
|
|
18
18
|
* - official_queue / official_queue_readonly: Official mirror queue tools (list, get, approve, reject, unlink)
|
|
19
19
|
* - unofficial_mirrors / unofficial_mirrors_readonly: Unofficial mirror CRUD tools
|
|
20
20
|
* - official_mirrors_readonly: Official mirrors read-only tools (REST API)
|
|
21
|
-
* - tenants / tenants_readonly: Tenant management tools (CRUD + API key provisioning
|
|
22
|
-
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default — operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
21
|
+
* - tenants / tenants_readonly: Tenant management tools (CRUD + API key provisioning)
|
|
22
|
+
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default — operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution. revoke_api_key lives here (not in `tenants`) because it calls the same DELETE /api/api_keys/:id endpoint as delete_api_key, which the Rails admin API gates behind permission_level=all.
|
|
23
23
|
* - mcp_jsons / mcp_jsons_readonly: MCP JSON configuration tools
|
|
24
24
|
* - mcp_servers / mcp_servers_readonly: Unified MCP server tools (abstracted interface)
|
|
25
25
|
* - redirects / redirects_readonly: URL redirect management tools
|
|
@@ -61,9 +61,9 @@ export declare function parseEnabledToolGroups(enabledGroupsParam?: string): Too
|
|
|
61
61
|
* - unofficial_mirrors: Unofficial mirror CRUD tools (read + write)
|
|
62
62
|
* - unofficial_mirrors_readonly: Unofficial mirror tools (read only)
|
|
63
63
|
* - official_mirrors_readonly: Official mirrors REST API tools (read only)
|
|
64
|
-
* - tenants: Tenant management tools including API key provisioning
|
|
64
|
+
* - tenants: Tenant management tools including API key provisioning (read + write).
|
|
65
65
|
* - tenants_readonly: Tenant tools (read only)
|
|
66
|
-
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
66
|
+
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
67
67
|
* - mcp_jsons: MCP JSON configuration tools (read + write)
|
|
68
68
|
* - mcp_jsons_readonly: MCP JSON tools (read only)
|
|
69
69
|
* - mcp_servers: Unified MCP server tools with abstracted interface (read + write)
|
package/shared/tools.js
CHANGED
|
@@ -70,6 +70,7 @@ import { runExamForMirror } from './tools/run-exam-for-mirror.js';
|
|
|
70
70
|
import { getExamResult } from './tools/get-exam-result.js';
|
|
71
71
|
import { saveResultsForMirror } from './tools/save-results-for-mirror.js';
|
|
72
72
|
import { listProctorRuns } from './tools/list-proctor-runs.js';
|
|
73
|
+
import { setKnownMissingInitToolsList } from './tools/set-known-missing-init-tools-list.js';
|
|
73
74
|
import { getProctorMetadata } from './tools/get-proctor-metadata.js';
|
|
74
75
|
// Discovered URLs tools
|
|
75
76
|
import { listDiscoveredUrls } from './tools/list-discovered-urls.js';
|
|
@@ -184,13 +185,14 @@ const ALL_TOOLS = [
|
|
|
184
185
|
{ factory: getTenant, groups: ['tenants'], isWriteOperation: false },
|
|
185
186
|
{ factory: createTenant, groups: ['tenants'], isWriteOperation: true },
|
|
186
187
|
{ factory: createApiKey, groups: ['tenants'], isWriteOperation: true },
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
//
|
|
188
|
+
// Destructive tenant tools — opt-in only, NOT in BASE_TOOL_GROUPS.
|
|
189
|
+
// revoke_api_key lives here (not in `tenants`) because it calls the same
|
|
190
|
+
// DELETE /api/api_keys/:id endpoint as delete_api_key and the Rails admin
|
|
191
|
+
// API gates that endpoint behind permission_level=all (full_access). The
|
|
192
|
+
// standard read-write admin credential cannot DELETE, so exposing
|
|
193
|
+
// revoke_api_key in the regular tenants group surfaced confusing 403s on
|
|
194
|
+
// workflows like sub-registry credential re-issuance.
|
|
195
|
+
{ factory: revokeApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
|
|
194
196
|
{ factory: deleteTenant, groups: ['tenants_destructive'], isWriteOperation: true },
|
|
195
197
|
{ factory: deleteApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
|
|
196
198
|
// Tenant -> recommended MCP server association tools
|
|
@@ -267,6 +269,13 @@ const ALL_TOOLS = [
|
|
|
267
269
|
{ factory: saveResultsForMirror, groups: ['proctor'], isWriteOperation: true },
|
|
268
270
|
{ factory: listProctorRuns, groups: ['proctor'], isWriteOperation: false },
|
|
269
271
|
{ factory: getProctorMetadata, groups: ['proctor'], isWriteOperation: false },
|
|
272
|
+
// setKnownMissingInitToolsList flips a flag on `mcp_server` records, so it lives in
|
|
273
|
+
// the mcp_servers / server_directory groups (alongside recacheMCPServer), not proctor.
|
|
274
|
+
{
|
|
275
|
+
factory: setKnownMissingInitToolsList,
|
|
276
|
+
groups: ['mcp_servers', 'server_directory'],
|
|
277
|
+
isWriteOperation: true,
|
|
278
|
+
},
|
|
270
279
|
// Discovered URLs tools
|
|
271
280
|
{ factory: listDiscoveredUrls, groups: ['discovered_urls'], isWriteOperation: false },
|
|
272
281
|
{
|
|
@@ -402,9 +411,9 @@ function shouldIncludeTool(toolDef, enabledGroups) {
|
|
|
402
411
|
* - unofficial_mirrors: Unofficial mirror CRUD tools (read + write)
|
|
403
412
|
* - unofficial_mirrors_readonly: Unofficial mirror tools (read only)
|
|
404
413
|
* - official_mirrors_readonly: Official mirrors REST API tools (read only)
|
|
405
|
-
* - tenants: Tenant management tools including API key provisioning
|
|
414
|
+
* - tenants: Tenant management tools including API key provisioning (read + write).
|
|
406
415
|
* - tenants_readonly: Tenant tools (read only)
|
|
407
|
-
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
416
|
+
* - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
|
|
408
417
|
* - mcp_jsons: MCP JSON configuration tools (read + write)
|
|
409
418
|
* - mcp_jsons_readonly: MCP JSON tools (read only)
|
|
410
419
|
* - mcp_servers: Unified MCP server tools with abstracted interface (read + write)
|
package/shared/types.d.ts
CHANGED
|
@@ -891,6 +891,12 @@ export interface DeleteApiKeyResponse {
|
|
|
891
891
|
export interface RecacheMCPServerResponse {
|
|
892
892
|
message: string;
|
|
893
893
|
}
|
|
894
|
+
export interface SetKnownMissingInitToolsListResponse {
|
|
895
|
+
id: number;
|
|
896
|
+
slug: string;
|
|
897
|
+
known_missing_init_tools_list: boolean;
|
|
898
|
+
known_missing_init_tools_list_filter_to: string | null;
|
|
899
|
+
}
|
|
894
900
|
export interface MozMetrics {
|
|
895
901
|
page_authority?: number;
|
|
896
902
|
domain_authority?: number;
|