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 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 reloadCodexMcpServer({
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 reloadCodexMcpServer({
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 reloadCodexMcpServer({
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 { isMainEntrypoint, parseArgs, shouldInstallExistingCredential };
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-mcp-smart-proxy",
3
- "version": "1.5.18",
3
+ "version": "1.5.20",
4
4
  "description": "Smart proxy for Cloudflare MCP - routes tools to cloud or local execution",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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: Date.now(),
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) {