codex-plugin-doctor 1.69.1 → 1.71.0

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.
@@ -26,4 +26,23 @@ export interface McpDiscoveryReport {
26
26
  export declare function findMcpSseResponse(body: Buffer, requestId?: string): McpJsonObject | null;
27
27
  export declare function parseMcpResponse(response: BoundedHttpResponse, requestId?: string): McpJsonObject | null;
28
28
  export declare function discoverMcpCapabilities(response: BoundedHttpResponse, requestId?: string): McpJsonObject | null;
29
+ export declare function serializeMcpDiscoverRequest(requestId?: string): string;
30
+ export type McpDiscoverOutcome = {
31
+ kind: "discovered";
32
+ supportedVersions: string[];
33
+ capabilities: McpJsonObject;
34
+ } | {
35
+ kind: "version-not-listed";
36
+ supportedVersions: string[];
37
+ } | {
38
+ kind: "version-unsupported";
39
+ supportedVersions: string[];
40
+ } | {
41
+ kind: "result-invalid";
42
+ } | {
43
+ kind: "envelope-invalid";
44
+ } | {
45
+ kind: "other-error";
46
+ };
47
+ export declare function classifyMcpDiscoverMessage(message: McpJsonObject, requestId?: string): McpDiscoverOutcome;
29
48
  export declare function discoverMcpServer(rawUrl: string, options?: McpDiscoveryOptions): Promise<McpDiscoveryReport>;
@@ -102,6 +102,29 @@ export function discoverMcpCapabilities(response, requestId = REQUEST_ID) {
102
102
  return null;
103
103
  return result.supportedVersions.includes(REQUESTED_VERSION) ? capabilities : null;
104
104
  }
105
+ export function serializeMcpDiscoverRequest(requestId = REQUEST_ID) {
106
+ return JSON.stringify({ jsonrpc: "2.0", id: requestId, method: "server/discover", params: { _meta: {
107
+ "io.modelcontextprotocol/protocolVersion": REQUESTED_VERSION,
108
+ "io.modelcontextprotocol/clientInfo": { name: "Codex Plugin Doctor", version: packageVersion },
109
+ "io.modelcontextprotocol/clientCapabilities": {}
110
+ } } });
111
+ }
112
+ // Classifies a transport-neutral server/discover reply. Only a valid result or a valid
113
+ // UnsupportedProtocolVersionError identifies a modern server; other errors do not.
114
+ export function classifyMcpDiscoverMessage(message, requestId = REQUEST_ID) {
115
+ if (!hasMatchingResponseEnvelope(message, requestId))
116
+ return { kind: "envelope-invalid" };
117
+ if (Object.hasOwn(message, "error")) {
118
+ const versions = unsupportedVersions(message.error);
119
+ return versions === null ? { kind: "other-error" } : { kind: "version-unsupported", supportedVersions: versions };
120
+ }
121
+ const result = message.result;
122
+ if (!validDiscoverResult(result))
123
+ return { kind: "result-invalid" };
124
+ return result.supportedVersions.includes(REQUESTED_VERSION)
125
+ ? { kind: "discovered", supportedVersions: result.supportedVersions, capabilities: result.capabilities }
126
+ : { kind: "version-not-listed", supportedVersions: result.supportedVersions };
127
+ }
105
128
  function failureReport(id, message) {
106
129
  return report("failed", "fail", [finding(id, "fail", message, "The discovery response cannot safely establish modern MCP discovery support.", "Verify the endpoint returns a valid server/discover response for the requested protocol version.")]);
107
130
  }
@@ -116,11 +139,7 @@ export async function discoverMcpServer(rawUrl, options = {}) {
116
139
  return report("blocked", "skipped", [finding("plugin.discovery.url.invalid", "warn", "The MCP discovery endpoint is unsafe or unsupported.", "Unsafe endpoint URLs can bypass network controls or expose credentials.", "Use an absolute HTTP or HTTPS endpoint without credentials, query parameters, fragments, or IP literals.")]);
117
140
  }
118
141
  const request = options.request ?? requestBoundedHttp;
119
- const body = JSON.stringify({ jsonrpc: "2.0", id: REQUEST_ID, method: "server/discover", params: { _meta: {
120
- "io.modelcontextprotocol/protocolVersion": REQUESTED_VERSION,
121
- "io.modelcontextprotocol/clientInfo": { name: "Codex Plugin Doctor", version: packageVersion },
122
- "io.modelcontextprotocol/clientCapabilities": {}
123
- } } });
142
+ const body = serializeMcpDiscoverRequest();
124
143
  let response;
125
144
  try {
126
145
  response = await request(rawUrl, {
@@ -0,0 +1,31 @@
1
+ import { spawn } from "node:child_process";
2
+ import type { RuntimeSandboxMode } from "../domain/types.js";
3
+ import { type McpToolCatalogSnapshot } from "./mcp-tool-catalog.js";
4
+ export interface McpStdioServer {
5
+ packageRoot: string;
6
+ command: string;
7
+ args: string[];
8
+ cwd: string;
9
+ source: "manifest" | "mcp-json";
10
+ }
11
+ export type McpStdioServerResolution = {
12
+ ok: true;
13
+ server: McpStdioServer;
14
+ } | {
15
+ ok: false;
16
+ message: string;
17
+ };
18
+ export interface McpStdioToolCatalogOptions {
19
+ sandbox?: RuntimeSandboxMode;
20
+ now?: () => number;
21
+ spawnImpl?: typeof spawn;
22
+ removeContainerImpl?: (containerName: string) => Promise<boolean>;
23
+ timeouts?: {
24
+ startupMs?: number;
25
+ requestMs?: number;
26
+ totalMs?: number;
27
+ shutdownMs?: number;
28
+ };
29
+ }
30
+ export declare function resolveMcpStdioServer(targetPath: string, serverName: string): Promise<McpStdioServerResolution>;
31
+ export declare function captureStdioMcpToolCatalog(server: McpStdioServer, options?: McpStdioToolCatalogOptions): Promise<McpToolCatalogSnapshot>;