cloudflare-mcp-smart-proxy 1.5.18 → 1.5.20
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/connector-cli.js +36 -16
- package/index.js +2 -2
- package/package.json +1 -1
- package/src/codex-app-server.js +32 -5
- package/src/router.js +8 -5
package/connector-cli.js
CHANGED
|
@@ -38,6 +38,8 @@ function printUsage() {
|
|
|
38
38
|
console.error(' --codex-device-identity-path <path> Shared CloudMCP device identity');
|
|
39
39
|
console.error(' --app-server-socket <path> Current runtime Codex app-server socket');
|
|
40
40
|
console.error(' --runtime-id <id> Current Codex runtime identity');
|
|
41
|
+
console.error(' --probe-timeout-ms <ms> Fresh MCP catalog probe timeout (30000-300000; default 120000)');
|
|
42
|
+
console.error(' Env: CLOUDMCP_CONNECTOR_PROBE_TIMEOUT_MS');
|
|
41
43
|
console.error(' --dry-run Show output without writing');
|
|
42
44
|
console.error(' --show-secrets Explicitly include credentials in print output');
|
|
43
45
|
console.error(' --approval-code <code> One-time code shown by the CloudMCP administrator');
|
|
@@ -85,6 +87,27 @@ function resolveRequiredOption(options, flagName, envNames = []) {
|
|
|
85
87
|
throw new Error(`Missing required option --${flagName}`);
|
|
86
88
|
}
|
|
87
89
|
|
|
90
|
+
function resolveConnectorProbeTimeoutMs(options = {}, env = process.env) {
|
|
91
|
+
const raw = options['probe-timeout-ms'] || env.CLOUDMCP_CONNECTOR_PROBE_TIMEOUT_MS || '120000';
|
|
92
|
+
const timeoutMs = Number(raw);
|
|
93
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 30_000 || timeoutMs > 300_000) {
|
|
94
|
+
throw new Error('probe-timeout-ms must be an integer between 30000 and 300000');
|
|
95
|
+
}
|
|
96
|
+
return timeoutMs;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function runCodexReload(options, serverName, {
|
|
100
|
+
reload = reloadCodexMcpServer,
|
|
101
|
+
env = process.env
|
|
102
|
+
} = {}) {
|
|
103
|
+
return reload({
|
|
104
|
+
serverName,
|
|
105
|
+
socketPath: options['app-server-socket'] || env.CODEX_APP_SERVER_SOCKET || '',
|
|
106
|
+
runtimeId: options['runtime-id'] || env.CODEX_RUNTIME_ID || '',
|
|
107
|
+
timeoutMs: resolveConnectorProbeTimeoutMs(options, env)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
88
111
|
function buildInstallOptions(options) {
|
|
89
112
|
const workspaceRoot = path.resolve(options['workspace-root'] || process.cwd());
|
|
90
113
|
return {
|
|
@@ -181,11 +204,7 @@ async function runActivation(options) {
|
|
|
181
204
|
dryRun: options.dryRun === true
|
|
182
205
|
});
|
|
183
206
|
if (options.ecosystem === 'codex' && !options.dryRun) {
|
|
184
|
-
result.activation = await
|
|
185
|
-
serverName: result.serverName,
|
|
186
|
-
socketPath: options['app-server-socket'] || process.env.CODEX_APP_SERVER_SOCKET || '',
|
|
187
|
-
runtimeId: options['runtime-id'] || process.env.CODEX_RUNTIME_ID || ''
|
|
188
|
-
});
|
|
207
|
+
result.activation = await runCodexReload(options, result.serverName);
|
|
189
208
|
}
|
|
190
209
|
if (!options.dryRun) fs.chmodSync(paths.credentialPath, 0o600);
|
|
191
210
|
if (!options.dryRun && pending) {
|
|
@@ -300,6 +319,9 @@ function printInstallResult(result, { includeContent = false, includeSecrets = f
|
|
|
300
319
|
}
|
|
301
320
|
if (result.activation) {
|
|
302
321
|
console.error(`activation: ${result.activation.status}`);
|
|
322
|
+
if (result.activation.reason) {
|
|
323
|
+
console.error(`activation reason: ${result.activation.reason}`);
|
|
324
|
+
}
|
|
303
325
|
if (Number.isInteger(result.activation.toolCount)) {
|
|
304
326
|
console.error(`tools: ${result.activation.toolCount}`);
|
|
305
327
|
}
|
|
@@ -354,11 +376,7 @@ async function main() {
|
|
|
354
376
|
if (options.command === 'install') {
|
|
355
377
|
const result = installReferenceConnector(buildInstallOptions(options));
|
|
356
378
|
if (options.ecosystem === 'codex' && !options.dryRun) {
|
|
357
|
-
result.activation = await
|
|
358
|
-
serverName: result.serverName,
|
|
359
|
-
socketPath: options['app-server-socket'] || process.env.CODEX_APP_SERVER_SOCKET || '',
|
|
360
|
-
runtimeId: options['runtime-id'] || process.env.CODEX_RUNTIME_ID || ''
|
|
361
|
-
});
|
|
379
|
+
result.activation = await runCodexReload(options, result.serverName);
|
|
362
380
|
}
|
|
363
381
|
printInstallResult(result);
|
|
364
382
|
return;
|
|
@@ -368,11 +386,7 @@ async function main() {
|
|
|
368
386
|
if (options.ecosystem !== 'codex') {
|
|
369
387
|
throw new Error('Runtime reload is currently supported only for Codex');
|
|
370
388
|
}
|
|
371
|
-
const activation = await
|
|
372
|
-
serverName: options['server-name'] || 'cloudmcp',
|
|
373
|
-
socketPath: options['app-server-socket'] || process.env.CODEX_APP_SERVER_SOCKET || '',
|
|
374
|
-
runtimeId: options['runtime-id'] || process.env.CODEX_RUNTIME_ID || ''
|
|
375
|
-
});
|
|
389
|
+
const activation = await runCodexReload(options, options['server-name'] || 'cloudmcp');
|
|
376
390
|
printInstallResult({
|
|
377
391
|
ecosystem: 'codex',
|
|
378
392
|
scope: 'user',
|
|
@@ -410,4 +424,10 @@ if (isMainEntrypoint()) {
|
|
|
410
424
|
main();
|
|
411
425
|
}
|
|
412
426
|
|
|
413
|
-
export {
|
|
427
|
+
export {
|
|
428
|
+
isMainEntrypoint,
|
|
429
|
+
parseArgs,
|
|
430
|
+
resolveConnectorProbeTimeoutMs,
|
|
431
|
+
runCodexReload,
|
|
432
|
+
shouldInstallExistingCredential
|
|
433
|
+
};
|
package/index.js
CHANGED
|
@@ -148,7 +148,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
// 工具调用处理器
|
|
151
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
151
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
152
152
|
const { name, arguments: args } = request.params;
|
|
153
153
|
|
|
154
154
|
if (!name) {
|
|
@@ -165,7 +165,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
165
165
|
|
|
166
166
|
try {
|
|
167
167
|
await refreshProjectScope();
|
|
168
|
-
const result = await router.executeTool(name, args || {});
|
|
168
|
+
const result = await router.executeTool(name, args || {}, { signal: extra.signal });
|
|
169
169
|
|
|
170
170
|
// 格式化响应
|
|
171
171
|
if (typeof result === 'string') {
|
package/package.json
CHANGED
package/src/codex-app-server.js
CHANGED
|
@@ -276,18 +276,25 @@ export function resolveCodexAppServerSocket({
|
|
|
276
276
|
homeDir = os.homedir(),
|
|
277
277
|
codexHome = '',
|
|
278
278
|
socketPath = '',
|
|
279
|
-
runtimeDir = process.env.XDG_RUNTIME_DIR || ''
|
|
280
|
-
pathExists = fs.existsSync
|
|
279
|
+
runtimeDir = process.env.XDG_RUNTIME_DIR || ''
|
|
281
280
|
} = {}) {
|
|
282
281
|
const explicitSocketPath = socketPath || process.env.CODEX_APP_SERVER_SOCKET || '';
|
|
283
282
|
if (explicitSocketPath) return path.resolve(explicitSocketPath);
|
|
284
283
|
if (runtimeDir) return path.join(path.resolve(runtimeDir), 'codex', 'app-server.sock');
|
|
285
284
|
const resolvedCodexHome = codexHome || process.env.CODEX_HOME || path.join(homeDir, '.codex');
|
|
286
|
-
const ipcSocketPath = path.join(path.resolve(resolvedCodexHome), 'ipc', 'ipc.sock');
|
|
287
|
-
if (pathExists(ipcSocketPath)) return ipcSocketPath;
|
|
288
285
|
return path.join(resolvedCodexHome, 'app-server-control', 'app-server-control.sock');
|
|
289
286
|
}
|
|
290
287
|
|
|
288
|
+
function assertCodexAppServerSocket({ socketPath, homeDir, codexHome }) {
|
|
289
|
+
const resolvedCodexHome = codexHome || process.env.CODEX_HOME || path.join(homeDir, '.codex');
|
|
290
|
+
const chatGptIpcSocket = path.join(path.resolve(resolvedCodexHome), 'ipc', 'ipc.sock');
|
|
291
|
+
if (path.resolve(socketPath) === chatGptIpcSocket) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
`Refusing ChatGPT IPC socket as a Codex app-server endpoint: socket=${socketPath}`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
291
298
|
function assertIsolatedSocketPath({ socketPath, homeDir, codexHome, isolationMode }) {
|
|
292
299
|
if (!isolationMode) return;
|
|
293
300
|
const resolvedCodexHome = codexHome || process.env.CODEX_HOME || path.join(homeDir, '.codex');
|
|
@@ -454,6 +461,11 @@ export async function reloadCodexMcpServer({
|
|
|
454
461
|
socketPath,
|
|
455
462
|
runtimeDir
|
|
456
463
|
});
|
|
464
|
+
assertCodexAppServerSocket({
|
|
465
|
+
socketPath: resolvedSocketPath,
|
|
466
|
+
homeDir,
|
|
467
|
+
codexHome
|
|
468
|
+
});
|
|
457
469
|
assertIsolatedSocketPath({
|
|
458
470
|
socketPath: resolvedSocketPath,
|
|
459
471
|
homeDir,
|
|
@@ -461,11 +473,26 @@ export async function reloadCodexMcpServer({
|
|
|
461
473
|
isolationMode
|
|
462
474
|
});
|
|
463
475
|
if (!rpcClient && !fs.existsSync(resolvedSocketPath)) {
|
|
476
|
+
const resolvedConfigPath = configPath
|
|
477
|
+
|| path.join(path.resolve(codexHome || path.join(homeDir, '.codex')), 'config.toml');
|
|
478
|
+
const probeResult = toolProbe
|
|
479
|
+
? await toolProbe({ serverName, configPath: resolvedConfigPath, timeoutMs })
|
|
480
|
+
: (fs.existsSync(resolvedConfigPath)
|
|
481
|
+
? await probeCodexMcpServer({
|
|
482
|
+
configPath: resolvedConfigPath,
|
|
483
|
+
serverName,
|
|
484
|
+
timeoutMs
|
|
485
|
+
})
|
|
486
|
+
: null);
|
|
464
487
|
return {
|
|
465
488
|
status: 'next_start',
|
|
489
|
+
reason: 'app_server_control_unavailable',
|
|
466
490
|
serverName,
|
|
467
491
|
socketPath: resolvedSocketPath,
|
|
468
|
-
toolCount: null
|
|
492
|
+
toolCount: Number.isInteger(probeResult?.toolCount) ? probeResult.toolCount : null,
|
|
493
|
+
workspaceId: probeResult?.workspaceId || null,
|
|
494
|
+
workspaceRoot: probeResult?.workspaceRoot || null,
|
|
495
|
+
workspaceResolution: probeResult?.workspaceResolution || null
|
|
469
496
|
};
|
|
470
497
|
}
|
|
471
498
|
|
package/src/router.js
CHANGED
|
@@ -139,7 +139,7 @@ export class SmartRouter {
|
|
|
139
139
|
/**
|
|
140
140
|
* 执行工具调用
|
|
141
141
|
*/
|
|
142
|
-
async executeTool(toolName, params) {
|
|
142
|
+
async executeTool(toolName, params, { signal = null } = {}) {
|
|
143
143
|
const route = this.routeTool(toolName);
|
|
144
144
|
|
|
145
145
|
if (route === 'local') {
|
|
@@ -151,7 +151,7 @@ export class SmartRouter {
|
|
|
151
151
|
projectIdentity: this.localTools?.connectorBridge?.state?.projectIdentity
|
|
152
152
|
}
|
|
153
153
|
: params;
|
|
154
|
-
return await this.callCloudTool(toolName, recoveryParams);
|
|
154
|
+
return await this.callCloudTool(toolName, recoveryParams, { signal });
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -179,7 +179,7 @@ export class SmartRouter {
|
|
|
179
179
|
/**
|
|
180
180
|
* 调用云端工具
|
|
181
181
|
*/
|
|
182
|
-
async callCloudTool(toolName, params, { workspaceId = null } = {}) {
|
|
182
|
+
async callCloudTool(toolName, params, { workspaceId = null, signal = null } = {}) {
|
|
183
183
|
// 对于 skill_* 工具,自动注入项目根路径信息
|
|
184
184
|
if (toolName.startsWith('skill_')) {
|
|
185
185
|
// 如果参数中没有 project_root 且没有 paths,自动添加 project_root
|
|
@@ -205,9 +205,10 @@ export class SmartRouter {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
try {
|
|
208
|
+
const requestId = Date.now();
|
|
208
209
|
const body = JSON.stringify({
|
|
209
210
|
jsonrpc: '2.0',
|
|
210
|
-
id:
|
|
211
|
+
id: requestId,
|
|
211
212
|
method: 'tools/call',
|
|
212
213
|
params: {
|
|
213
214
|
name: toolName,
|
|
@@ -222,11 +223,13 @@ export class SmartRouter {
|
|
|
222
223
|
headers: {
|
|
223
224
|
'Authorization': `Bearer ${this.cloudApiKey}`,
|
|
224
225
|
'Content-Type': 'application/json',
|
|
226
|
+
'X-Request-ID': String(requestId),
|
|
225
227
|
...this.getScopeHeaders(),
|
|
226
228
|
...(workspaceId ? { 'X-CloudMCP-Workspace-ID': workspaceId } : {}),
|
|
227
229
|
...signedHeaders
|
|
228
230
|
},
|
|
229
|
-
body
|
|
231
|
+
body,
|
|
232
|
+
signal
|
|
230
233
|
});
|
|
231
234
|
|
|
232
235
|
if (!response.ok) {
|