@cnwenf/occ 2.1.339 → 2.1.341

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.
Files changed (2) hide show
  1. package/dist/cli.js +506 -110
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- globalThis.MACRO={"VERSION":"2.1.339","BINARY_NAME":"occ","BUILD_TIME":"2026-09-17T03:37:58.902Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
2
+ globalThis.MACRO={"VERSION":"2.1.341","BINARY_NAME":"occ","BUILD_TIME":"2026-09-18T01:06:37.948Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
3
3
  // @bun
4
4
  var __create = Object.create;
5
5
  var __getProtoOf = Object.getPrototypeOf;
@@ -9112,6 +9112,17 @@ async function appendAsync(needMkdir, dir, path2, content) {
9112
9112
  updateLatestDebugLogSymlink();
9113
9113
  }
9114
9114
  function noop2() {}
9115
+ function appendFileSyncWithDirFallback(path2, content) {
9116
+ try {
9117
+ getFsImplementation().appendFileSync(path2, content);
9118
+ } catch (e) {
9119
+ if (e?.code !== "EISDIR")
9120
+ throw e;
9121
+ const fallback = join3(path2, `${getSessionId()}.txt`);
9122
+ dirFallbackLogPath = fallback;
9123
+ getFsImplementation().appendFileSync(fallback, content);
9124
+ }
9125
+ }
9115
9126
  function getDebugWriter() {
9116
9127
  if (!debugWriter) {
9117
9128
  let ensuredDir = null;
@@ -9127,7 +9138,7 @@ function getDebugWriter() {
9127
9138
  getFsImplementation().mkdirSync(dir);
9128
9139
  } catch {}
9129
9140
  }
9130
- getFsImplementation().appendFileSync(path2, content);
9141
+ appendFileSyncWithDirFallback(path2, content);
9131
9142
  updateLatestDebugLogSymlink();
9132
9143
  return;
9133
9144
  }
@@ -9167,7 +9178,7 @@ function logForDebugging(message, { level } = {
9167
9178
  getDebugWriter().write(output);
9168
9179
  }
9169
9180
  function getDebugLogPath() {
9170
- return getDebugFilePath() ?? process.env.CLAUDE_CODE_DEBUG_LOGS_DIR ?? join3(getClaudeConfigHomeDir(), "debug", `${getSessionId()}.txt`);
9181
+ return dirFallbackLogPath ?? getDebugFilePath() ?? process.env.CLAUDE_CODE_DEBUG_LOGS_DIR ?? join3(getClaudeConfigHomeDir(), "debug", `${getSessionId()}.txt`);
9171
9182
  }
9172
9183
  function logAntError(context, error2) {
9173
9184
  if (process.env.USER_TYPE !== "ant") {
@@ -9180,7 +9191,7 @@ ${error2.stack}`, {
9180
9191
  });
9181
9192
  }
9182
9193
  }
9183
- var LEVEL_ORDER, getMinDebugLogLevel, runtimeDebugEnabled = false, isDebugMode, getDebugFilter, isDebugToStdErr, getDebugFilePath, hasFormattedOutput = false, debugWriter = null, pendingWrite, updateLatestDebugLogSymlink;
9194
+ var LEVEL_ORDER, getMinDebugLogLevel, runtimeDebugEnabled = false, isDebugMode, getDebugFilter, isDebugToStdErr, getDebugFilePath, hasFormattedOutput = false, debugWriter = null, pendingWrite, dirFallbackLogPath = null, updateLatestDebugLogSymlink;
9184
9195
  var init_debug = __esm(() => {
9185
9196
  init_memoize();
9186
9197
  init_state();
@@ -473601,8 +473612,8 @@ async function getMessagesForSlashCommand(commandName, args, setToolJSX, context
473601
473612
  command4.load().then((mod2) => mod2.call(onDone, {
473602
473613
  ...context6,
473603
473614
  canUseTool
473604
- }, args)).then((jsx128) => {
473605
- if (jsx128 == null)
473615
+ }, args)).then((commandJsx) => {
473616
+ if (commandJsx == null)
473606
473617
  return;
473607
473618
  if (context6.options.isNonInteractiveSession) {
473608
473619
  resolve37({
@@ -473615,7 +473626,7 @@ async function getMessagesForSlashCommand(commandName, args, setToolJSX, context
473615
473626
  if (doneWasCalled)
473616
473627
  return;
473617
473628
  setToolJSX({
473618
- jsx: jsx128,
473629
+ jsx: commandJsx,
473619
473630
  shouldHidePromptInput: true,
473620
473631
  showSpinner: false,
473621
473632
  isLocalJSXCommand: true,
@@ -627153,6 +627164,52 @@ async function fetchAuthServerMetadata(serverName, serverUrl, configuredMetadata
627153
627164
  ...fetchFn && { fetchFn }
627154
627165
  });
627155
627166
  }
627167
+ function getOAuthCallbackSubmitter(serverName) {
627168
+ return oauthCallbackSubmitters.get(serverName);
627169
+ }
627170
+ function setActiveOAuthPromise(serverName, promise3) {
627171
+ activeOAuthFlows.set(serverName, promise3);
627172
+ promise3.finally(() => {
627173
+ if (activeOAuthFlows.get(serverName) === promise3) {
627174
+ activeOAuthFlows.delete(serverName);
627175
+ }
627176
+ }).catch(() => {});
627177
+ }
627178
+ function getActiveOAuthPromise(serverName) {
627179
+ return activeOAuthFlows.get(serverName);
627180
+ }
627181
+ function createManualCallbackSubmitter(serverName, oauthState, hooks) {
627182
+ return (callbackUrl) => {
627183
+ try {
627184
+ const parsed = new URL(callbackUrl);
627185
+ const code = parsed.searchParams.get("code");
627186
+ const state3 = parsed.searchParams.get("state");
627187
+ const error52 = parsed.searchParams.get("error");
627188
+ if (!code && !error52) {
627189
+ return false;
627190
+ }
627191
+ if (state3 !== oauthState) {
627192
+ logMCPDebug(serverName, "Ignoring manual callback URL whose state belongs to a different flow");
627193
+ return false;
627194
+ }
627195
+ if (error52) {
627196
+ const errorDescription = parsed.searchParams.get("error_description") || "";
627197
+ hooks.cleanup();
627198
+ hooks.rejectFlow(new Error(`OAuth error: ${error52} - ${errorDescription}`));
627199
+ return true;
627200
+ }
627201
+ if (!code) {
627202
+ return false;
627203
+ }
627204
+ logMCPDebug(serverName, "Received auth code via manual callback URL");
627205
+ hooks.cleanup();
627206
+ hooks.resolveCode(code);
627207
+ return true;
627208
+ } catch {
627209
+ return false;
627210
+ }
627211
+ };
627212
+ }
627156
627213
  function getServerKey(serverName, serverConfig) {
627157
627214
  const configJson = jsonStringify({
627158
627215
  type: serverConfig.type,
@@ -627510,6 +627567,7 @@ async function performMCPOAuthFlow(serverName, serverConfig, onAuthorizationUrl,
627510
627567
  let server = null;
627511
627568
  let timeoutId = null;
627512
627569
  let abortHandler = null;
627570
+ let manualSubmitter = null;
627513
627571
  const cleanup2 = () => {
627514
627572
  if (server) {
627515
627573
  server.removeAllListeners();
@@ -627525,6 +627583,13 @@ async function performMCPOAuthFlow(serverName, serverConfig, onAuthorizationUrl,
627525
627583
  abortSignal.removeEventListener("abort", abortHandler);
627526
627584
  abortHandler = null;
627527
627585
  }
627586
+ if (manualSubmitter && oauthCallbackSubmitters.get(serverName) === manualSubmitter) {
627587
+ oauthCallbackSubmitters.delete(serverName);
627588
+ }
627589
+ if (manualSubmitter && oauthFlowRecords.get(serverName)?.submitter === manualSubmitter) {
627590
+ oauthFlowRecords.delete(serverName);
627591
+ }
627592
+ manualSubmitter = null;
627528
627593
  logMCPDebug(serverName, `MCP OAuth server cleaned up`);
627529
627594
  };
627530
627595
  const authorizationCode = await new Promise((resolve53, reject2) => {
@@ -627552,32 +627617,37 @@ async function performMCPOAuthFlow(serverName, serverConfig, onAuthorizationUrl,
627552
627617
  }
627553
627618
  abortSignal.addEventListener("abort", abortHandler);
627554
627619
  }
627555
- if (options?.onWaitingForCallback) {
627556
- options.onWaitingForCallback((callbackUrl) => {
627557
- try {
627558
- const parsed = new URL(callbackUrl);
627559
- const code = parsed.searchParams.get("code");
627560
- const state3 = parsed.searchParams.get("state");
627561
- const error52 = parsed.searchParams.get("error");
627562
- if (error52) {
627563
- const errorDescription = parsed.searchParams.get("error_description") || "";
627564
- cleanup2();
627565
- rejectOnce(new Error(`OAuth error: ${error52} - ${errorDescription}`));
627566
- return;
627567
- }
627568
- if (!code) {
627569
- return;
627570
- }
627571
- if (state3 !== oauthState) {
627572
- cleanup2();
627573
- rejectOnce(new Error("OAuth state mismatch - possible CSRF attack"));
627574
- return;
627575
- }
627576
- logMCPDebug(serverName, `Received auth code via manual callback URL`);
627577
- cleanup2();
627578
- resolveOnce(code);
627579
- } catch {}
627580
- });
627620
+ manualSubmitter = createManualCallbackSubmitter(serverName, oauthState, {
627621
+ cleanup: cleanup2,
627622
+ resolveCode: resolveOnce,
627623
+ rejectFlow: rejectOnce
627624
+ });
627625
+ const supersededFlow = oauthFlowRecords.get(serverName);
627626
+ if (supersededFlow) {
627627
+ logMCPDebug(serverName, `Cancelling superseded OAuth flow (epoch ${supersededFlow.epoch}) \u2014 a newer flow is taking over`);
627628
+ supersededFlow.cancel();
627629
+ }
627630
+ const flowRecord = {
627631
+ epoch: ++oauthFlowEpochCounter,
627632
+ submitter: manualSubmitter,
627633
+ cancel: () => {
627634
+ cleanup2();
627635
+ rejectOnce(new AuthenticationCancelledError);
627636
+ }
627637
+ };
627638
+ oauthFlowRecords.set(serverName, flowRecord);
627639
+ oauthCallbackSubmitters.set(serverName, manualSubmitter);
627640
+ try {
627641
+ options?.onWaitingForCallback?.(manualSubmitter, redirectUri, oauthState);
627642
+ } catch (callbackError) {
627643
+ if (oauthCallbackSubmitters.get(serverName) === manualSubmitter) {
627644
+ oauthCallbackSubmitters.delete(serverName);
627645
+ }
627646
+ if (oauthFlowRecords.get(serverName) === flowRecord) {
627647
+ oauthFlowRecords.delete(serverName);
627648
+ }
627649
+ manualSubmitter = null;
627650
+ throw callbackError;
627581
627651
  }
627582
627652
  server = createServer6((req, res) => {
627583
627653
  const parsedUrl = parse14(req.url || "", true);
@@ -628417,7 +628487,7 @@ function getScopeFromMetadata(metadata) {
628417
628487
  }
628418
628488
  return;
628419
628489
  }
628420
- var import_xss2, AUTH_REQUEST_TIMEOUT_MS = 30000, MAX_LOCK_RETRIES = 5, SENSITIVE_OAUTH_PARAMS, NONSTANDARD_INVALID_GRANT_ALIASES, AuthenticationCancelledError;
628490
+ var import_xss2, AUTH_REQUEST_TIMEOUT_MS = 30000, MAX_LOCK_RETRIES = 5, SENSITIVE_OAUTH_PARAMS, NONSTANDARD_INVALID_GRANT_ALIASES, AuthenticationCancelledError, oauthCallbackSubmitters, activeOAuthFlows, oauthFlowRecords, oauthFlowEpochCounter = 0;
628421
628491
  var init_auth11 = __esm(() => {
628422
628492
  init_auth10();
628423
628493
  init_errors12();
@@ -628457,6 +628527,9 @@ var init_auth11 = __esm(() => {
628457
628527
  this.name = "AuthenticationCancelledError";
628458
628528
  }
628459
628529
  };
628530
+ oauthCallbackSubmitters = new Map;
628531
+ activeOAuthFlows = new Map;
628532
+ oauthFlowRecords = new Map;
628460
628533
  });
628461
628534
 
628462
628535
  // src/services/mcp/displaySanitize.ts
@@ -628521,20 +628594,205 @@ var init_displaySanitize = __esm(() => {
628521
628594
  INVISIBLE_PATTERN = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}\p{Default_Ignorable_Code_Point}\u2800]|(?!\u0020)\p{Zs}/gu;
628522
628595
  });
628523
628596
 
628597
+ // src/tools/McpAuthTool/mcpAuthStubShared.ts
628598
+ function isRemoteOAuthSession() {
628599
+ return env4.isSSH() || isEnvTruthy(process.env.CLAUDE_CODE_REMOTE);
628600
+ }
628601
+ function extractOAuthRedirectUri(authUrl) {
628602
+ try {
628603
+ const redirectUri = new URL(authUrl).searchParams.get("redirect_uri");
628604
+ if (redirectUri) {
628605
+ return redirectUri;
628606
+ }
628607
+ } catch {}
628608
+ return "http://localhost:<port>/callback";
628609
+ }
628610
+ var MCP_AUTH_TOOL_SUFFIX = "authenticate", MCP_COMPLETE_AUTH_TOOL_SUFFIX = "complete_authentication", TOOLS_BECOME_AVAILABLE_TEXT = "available automatically", TOOLS_NOW_AVAILABLE_SENTENCE = "The server's tools should now be available.";
628611
+ var init_mcpAuthStubShared = __esm(() => {
628612
+ init_env();
628613
+ init_envUtils();
628614
+ });
628615
+
628616
+ // src/tools/McpAuthTool/McpCompleteAuthTool.ts
628617
+ function buildMcpCompleteAuthToolDescription(serverName) {
628618
+ const authenticateToolName = buildMcpToolName(serverName, MCP_AUTH_TOOL_SUFFIX);
628619
+ return `Complete an in-progress OAuth flow for the "${sanitizeServerNameForDisplay(serverName)}" MCP server by submitting the callback URL. Call \`${authenticateToolName}\` first to start the flow and get the authorization URL. ` + "After the user authorizes in their browser, the browser is redirected to a `http://localhost:<port>/callback?code=...&state=...` URL \u2014 " + "on remote sessions that page fails to load, but the URL in the address bar is still valid. Pass that full URL here as `callback_url`.";
628620
+ }
628621
+ function createMcpCompleteAuthTool(serverName, config7, resolveUnexpanded = resolveUnexpandedMcpServers) {
628622
+ const description = buildMcpCompleteAuthToolDescription(serverName);
628623
+ return {
628624
+ name: buildMcpToolName(serverName, MCP_COMPLETE_AUTH_TOOL_SUFFIX),
628625
+ isMcp: true,
628626
+ mcpInfo: { serverName, toolName: MCP_COMPLETE_AUTH_TOOL_SUFFIX },
628627
+ isEnabled: () => true,
628628
+ isConcurrencySafe: () => false,
628629
+ isReadOnly: () => false,
628630
+ toAutoClassifierInput: () => serverName,
628631
+ userFacingName: () => `${serverName} - complete authentication (MCP)`,
628632
+ maxResultSizeChars: 1e4,
628633
+ renderToolUseMessage: () => `Complete authentication for ${serverName} MCP server`,
628634
+ async description() {
628635
+ return description;
628636
+ },
628637
+ async prompt() {
628638
+ return description;
628639
+ },
628640
+ get inputSchema() {
628641
+ return inputSchema45();
628642
+ },
628643
+ async checkPermissions(input2) {
628644
+ return { behavior: "allow", updatedInput: input2 };
628645
+ },
628646
+ async call(input2) {
628647
+ const { callback_url: callbackUrl } = input2;
628648
+ const displayName = sanitizeServerNameForDisplay(serverName);
628649
+ const authenticateToolName = buildMcpToolName(serverName, MCP_AUTH_TOOL_SUFFIX);
628650
+ const submitter = getOAuthCallbackSubmitter(serverName);
628651
+ if (!submitter) {
628652
+ return {
628653
+ data: {
628654
+ status: "error",
628655
+ message: `No OAuth flow is in progress for ${displayName}. Call \`${authenticateToolName}\` first, then retry with the callback URL.`
628656
+ }
628657
+ };
628658
+ }
628659
+ let hasCodeOrError = false;
628660
+ try {
628661
+ const parsed = new URL(callbackUrl);
628662
+ hasCodeOrError = parsed.searchParams.has("code") || parsed.searchParams.has("error");
628663
+ } catch {}
628664
+ if (!hasCodeOrError) {
628665
+ return {
628666
+ data: {
628667
+ status: "error",
628668
+ message: "Invalid callback URL: missing authorization code. Ask the user to paste the full redirect URL from their browser's address bar, including the `?code=...&state=...` query string."
628669
+ }
628670
+ };
628671
+ }
628672
+ if (!submitter(callbackUrl)) {
628673
+ return {
628674
+ data: {
628675
+ status: "error",
628676
+ message: `That callback URL belongs to a different sign-in attempt for ${displayName} (its state does not match the flow in progress), or carries no authorization code. The current flow is still waiting: ask the user for the URL from the page this sign-in opened, then retry.`
628677
+ }
628678
+ };
628679
+ }
628680
+ const activeFlow = getActiveOAuthPromise(serverName);
628681
+ if (!activeFlow) {
628682
+ return {
628683
+ data: {
628684
+ status: "error",
628685
+ message: `The callback URL was accepted by the in-progress OAuth flow for ${displayName}, but that flow was started outside this session's tool path (e.g. \`occ mcp login\` or a headless control channel), so its token exchange cannot be tracked here. The surface that started the flow will report completion \u2014 do not retry this tool.`
628686
+ }
628687
+ };
628688
+ }
628689
+ try {
628690
+ await activeFlow;
628691
+ return {
628692
+ data: {
628693
+ status: "success",
628694
+ message: `Authentication complete for ${displayName}. ${TOOLS_NOW_AVAILABLE_SENTENCE}`
628695
+ }
628696
+ };
628697
+ } catch (err2) {
628698
+ if (err2 instanceof AuthenticationCancelledError) {
628699
+ return {
628700
+ data: {
628701
+ status: "error",
628702
+ message: `The OAuth flow for ${displayName} was cancelled (a newer attempt may have superseded it). Call \`${authenticateToolName}\` again to restart.`
628703
+ }
628704
+ };
628705
+ }
628706
+ return {
628707
+ data: {
628708
+ status: "error",
628709
+ message: `Authentication failed for ${displayName}: ${sanitizeForDisplay(redactMcpErrorDetail(serverName, config7, errorMessage(err2), resolveUnexpanded))}`
628710
+ }
628711
+ };
628712
+ }
628713
+ },
628714
+ mapToolResultToToolResultBlockParam(data, toolUseID) {
628715
+ return {
628716
+ tool_use_id: toolUseID,
628717
+ type: "tool_result",
628718
+ content: data.message
628719
+ };
628720
+ }
628721
+ };
628722
+ }
628723
+ var inputSchema45;
628724
+ var init_McpCompleteAuthTool = __esm(() => {
628725
+ init_v4();
628726
+ init_auth11();
628727
+ init_displaySanitize();
628728
+ init_mcpStringUtils();
628729
+ init_redaction();
628730
+ init_utils9();
628731
+ init_errors();
628732
+ init_mcpAuthStubShared();
628733
+ inputSchema45 = lazySchema(() => exports_external.object({
628734
+ callback_url: exports_external.string().describe("The full callback URL from the browser address bar after authorizing, e.g. http://localhost:<port>/callback?code=...&state=...")
628735
+ }));
628736
+ });
628737
+
628524
628738
  // src/tools/McpAuthTool/McpAuthTool.ts
628739
+ function normalizeHostnameForMatch(hostname4) {
628740
+ return hostname4.toLowerCase().replace(/\.$/, "");
628741
+ }
628742
+ function isAnthropicHostedMcpUrl(url3) {
628743
+ if (!url3) {
628744
+ return false;
628745
+ }
628746
+ try {
628747
+ const blocked = new Set(ANTHROPIC_HOSTED_OAUTH_BLOCKED_HOSTS.map(normalizeHostnameForMatch));
628748
+ return blocked.has(normalizeHostnameForMatch(new URL(url3).hostname));
628749
+ } catch {
628750
+ return false;
628751
+ }
628752
+ }
628753
+ function renderMcpRemoveCommand(serverName) {
628754
+ if (!COMMAND_ARG_SAFE_PATTERN.test(serverName)) {
628755
+ return null;
628756
+ }
628757
+ return `occ mcp remove ${serverName}`;
628758
+ }
628759
+ function buildAnthropicHostedMessage(serverName, scope) {
628760
+ const base2 = `"${sanitizeServerNameForDisplay(serverName)}" is Anthropic-hosted and doesn't support local OAuth. ` + "Connect it via Settings \u2192 Connectors on claude.ai (requires " + "`claude login`), then it'll be available here automatically.";
628761
+ const removeCommand = scope === "local" || scope === "project" || scope === "user" ? renderMcpRemoveCommand(serverName) : null;
628762
+ if (!removeCommand) {
628763
+ return base2;
628764
+ }
628765
+ const withRemove = `${base2} Remove the stale entry with: \`${removeCommand}\``;
628766
+ return [...withRemove].length <= 1024 ? withRemove : base2;
628767
+ }
628768
+ function classifyMcpServerAuthBlock(serverName, config7) {
628769
+ if (!isMcpServerAllowedByPolicy(serverName, config7)) {
628770
+ return "managed-policy";
628771
+ }
628772
+ if (config7.scope === "project" && getProjectMcpServerStatus(serverName) !== "approved") {
628773
+ return "project-approval";
628774
+ }
628775
+ return null;
628776
+ }
628777
+ function managedPolicyBlockMessage(serverName) {
628778
+ return `"${sanitizeServerNameForDisplay(serverName)}" is blocked by your organization's managed policy \u2014 it can't be authenticated or reconnected here`;
628779
+ }
628780
+ function projectApprovalBlockMessage(serverName) {
628781
+ return `"${sanitizeServerNameForDisplay(serverName)}" is a project-scope MCP server (.mcp.json) that is not approved for this project \u2014 approve it via /mcp first, then authenticate or reconnect it`;
628782
+ }
628525
628783
  function buildMcpAuthToolDescription(serverName, config7, resolveUnexpanded = resolveUnexpandedMcpServers) {
628526
628784
  const transport = config7.type ?? "stdio";
628527
628785
  const displayOrigin = getMcpErrorEndpoint(serverName, config7, { detail: "origin" }, resolveUnexpanded);
628528
628786
  const location = displayOrigin && displayOrigin !== transport ? `${transport} at ${sanitizeDisplayUrl(displayOrigin, 256)}` : transport;
628529
- return `The "${sanitizeServerNameForDisplay(serverName)}" MCP server (${location}) is installed but requires authentication. ` + `Call this tool to start the OAuth flow \u2014 you'll receive an authorization URL to share with the user. ` + `Once the user completes authorization in their browser, the server's real tools will become available automatically.`;
628787
+ return `The "${sanitizeServerNameForDisplay(serverName)}" MCP server (${location}) is installed but requires authentication. ` + `Call this tool to start the OAuth flow \u2014 you'll receive an authorization URL to share with the user. ` + `Once the user completes authorization in their browser, the server's real tools will become ${TOOLS_BECOME_AVAILABLE_TEXT}.`;
628530
628788
  }
628531
628789
  function createMcpAuthTool(serverName, config7, resolveUnexpanded = resolveUnexpandedMcpServers) {
628532
628790
  const transport = config7.type ?? "stdio";
628533
628791
  const description = buildMcpAuthToolDescription(serverName, config7, resolveUnexpanded);
628534
628792
  return {
628535
- name: buildMcpToolName(serverName, "authenticate"),
628793
+ name: buildMcpToolName(serverName, MCP_AUTH_TOOL_SUFFIX),
628536
628794
  isMcp: true,
628537
- mcpInfo: { serverName, toolName: "authenticate" },
628795
+ mcpInfo: { serverName, toolName: MCP_AUTH_TOOL_SUFFIX },
628538
628796
  isEnabled: () => true,
628539
628797
  isConcurrencySafe: () => false,
628540
628798
  isReadOnly: () => false,
@@ -628549,17 +628807,43 @@ function createMcpAuthTool(serverName, config7, resolveUnexpanded = resolveUnexp
628549
628807
  return description;
628550
628808
  },
628551
628809
  get inputSchema() {
628552
- return inputSchema45();
628810
+ return inputSchema46();
628553
628811
  },
628554
628812
  async checkPermissions(input2) {
628555
628813
  return { behavior: "allow", updatedInput: input2 };
628556
628814
  },
628557
628815
  async call(_input, context7) {
628816
+ const displayName = sanitizeServerNameForDisplay(serverName);
628817
+ const policyBlock = classifyMcpServerAuthBlock(serverName, config7);
628818
+ if (policyBlock === "managed-policy") {
628819
+ return {
628820
+ data: {
628821
+ status: "error",
628822
+ message: `${managedPolicyBlockMessage(serverName)}. Only an organization admin can change this; do not retry or ask the user to enable it.`
628823
+ }
628824
+ };
628825
+ }
628826
+ if (isMcpServerDisabled(serverName)) {
628827
+ return {
628828
+ data: {
628829
+ status: "error",
628830
+ message: `MCP server ${displayName} is disabled. Ask the user to enable it in /mcp before authenticating.`
628831
+ }
628832
+ };
628833
+ }
628834
+ if (policyBlock === "project-approval") {
628835
+ return {
628836
+ data: {
628837
+ status: "error",
628838
+ message: `${projectApprovalBlockMessage(serverName)}. Ask the user to approve it; do not retry until they have.`
628839
+ }
628840
+ };
628841
+ }
628558
628842
  if (config7.type === "claudeai-proxy") {
628559
628843
  return {
628560
628844
  data: {
628561
628845
  status: "unsupported",
628562
- message: `This is a claude.ai MCP connector. Ask the user to run /mcp and select "${serverName}" to authenticate.`
628846
+ message: `This is a claude.ai MCP connector. Ask the user to run /mcp and select "${displayName}" to authenticate.`
628563
628847
  }
628564
628848
  };
628565
628849
  }
@@ -628567,7 +628851,15 @@ function createMcpAuthTool(serverName, config7, resolveUnexpanded = resolveUnexp
628567
628851
  return {
628568
628852
  data: {
628569
628853
  status: "unsupported",
628570
- message: `Server "${serverName}" uses ${transport} transport which does not support OAuth from this tool. Ask the user to run /mcp and authenticate manually.`
628854
+ message: `Server "${displayName}" uses ${transport} transport which does not support OAuth from this tool. Ask the user to run /mcp and authenticate manually.`
628855
+ }
628856
+ };
628857
+ }
628858
+ if (isAnthropicHostedMcpUrl(config7.url)) {
628859
+ return {
628860
+ data: {
628861
+ status: "unsupported",
628862
+ message: sanitizeForDisplay(buildAnthropicHostedMessage(serverName, config7.scope), 1024, "none")
628571
628863
  }
628572
628864
  };
628573
628865
  }
@@ -628576,11 +628868,15 @@ function createMcpAuthTool(serverName, config7, resolveUnexpanded = resolveUnexp
628576
628868
  const authUrlPromise = new Promise((resolve53) => {
628577
628869
  resolveAuthUrl = resolve53;
628578
628870
  });
628579
- const controller = new AbortController;
628580
628871
  const { setAppState } = context7;
628581
- const oauthPromise = performMCPOAuthFlow(serverName, sseOrHttpConfig, (u7) => resolveAuthUrl?.(u7), controller.signal, { skipBrowserOpen: true });
628872
+ const oauthPromise = performMCPOAuthFlow(serverName, sseOrHttpConfig, (u7) => resolveAuthUrl?.(u7), undefined, { skipBrowserOpen: true });
628873
+ setActiveOAuthPromise(serverName, oauthPromise);
628582
628874
  oauthPromise.then(async () => {
628583
628875
  clearMcpAuthCache();
628876
+ if (isMcpServerDisabled(serverName) || !isMcpServerAllowedByPolicy(serverName, config7)) {
628877
+ logMCPDebug(serverName, "OAuth completed but the server is now disabled or policy-blocked; not reconnecting");
628878
+ return;
628879
+ }
628584
628880
  const result = await reconnectMcpServerImpl(serverName, config7);
628585
628881
  const prefix = getMcpPrefix(serverName);
628586
628882
  setAppState((prev) => ({
@@ -628601,7 +628897,7 @@ function createMcpAuthTool(serverName, config7, resolveUnexpanded = resolveUnexp
628601
628897
  }));
628602
628898
  logMCPDebug(serverName, `OAuth complete, reconnected with ${result.tools.length} tool(s)`);
628603
628899
  }).catch((err2) => {
628604
- logMCPError(serverName, `OAuth flow failed after tool-triggered start: ${errorMessage(err2)}`);
628900
+ logMCPError(serverName, `OAuth flow failed after tool-triggered start: ${sanitizeForDisplay(redactMcpErrorDetail(serverName, config7, errorMessage(err2), resolveUnexpanded), 2000)}`);
628605
628901
  });
628606
628902
  try {
628607
628903
  const authUrl = await Promise.race([
@@ -628609,29 +628905,37 @@ function createMcpAuthTool(serverName, config7, resolveUnexpanded = resolveUnexp
628609
628905
  oauthPromise.then(() => null)
628610
628906
  ]);
628611
628907
  if (authUrl) {
628908
+ const completeAuthToolName = buildMcpToolName(serverName, MCP_COMPLETE_AUTH_TOOL_SUFFIX);
628909
+ const redirectUri = extractOAuthRedirectUri(authUrl);
628910
+ const callbackGuidance = isRemoteOAuthSession() ? `
628911
+
628912
+ This session is remote, so after authorizing the browser will try to load \`${redirectUri}?code=...\` and show a connection error \u2014 that's expected. Ask the user to copy the full URL from the browser's address bar and paste it into chat, then call \`${completeAuthToolName}\` with that URL as \`callback_url\`.` : `
628913
+
628914
+ If the browser shows a connection error on the redirect page, ask the user to paste the full URL from the address bar and call \`${completeAuthToolName}\` with it.`;
628612
628915
  return {
628613
628916
  data: {
628614
628917
  status: "auth_url",
628615
628918
  authUrl,
628616
- message: `Ask the user to open this URL in their browser to authorize the ${serverName} MCP server:
628919
+ message: `Ask the user to open this URL in their browser to authorize the ${displayName} MCP server:
628617
628920
 
628618
628921
  ${authUrl}
628619
628922
 
628620
- Once they complete the flow, the server's tools will become available automatically.`
628923
+ Once they complete the flow, the server's tools will become ${TOOLS_BECOME_AVAILABLE_TEXT}.${callbackGuidance}`
628621
628924
  }
628622
628925
  };
628623
628926
  }
628624
628927
  return {
628625
628928
  data: {
628626
628929
  status: "auth_url",
628627
- message: `Authentication completed silently for ${serverName}. The server's tools should now be available.`
628930
+ message: `Authentication completed silently for ${displayName}. ${TOOLS_NOW_AVAILABLE_SENTENCE}`
628628
628931
  }
628629
628932
  };
628630
628933
  } catch (err2) {
628934
+ const failureDetail = sanitizeForDisplay(redactMcpErrorDetail(serverName, config7, errorMessage(err2), resolveUnexpanded));
628631
628935
  return {
628632
628936
  data: {
628633
628937
  status: "error",
628634
- message: `Failed to start OAuth flow for ${serverName}: ${errorMessage(err2)}. Ask the user to run /mcp and authenticate manually.`
628938
+ message: `Failed to start OAuth flow for ${displayName}: ${failureDetail}. Ask the user to run /mcp and authenticate manually.`
628635
628939
  }
628636
628940
  };
628637
628941
  }
@@ -628645,19 +628949,38 @@ Once they complete the flow, the server's tools will become available automatica
628645
628949
  }
628646
628950
  };
628647
628951
  }
628648
- var inputSchema45;
628952
+ function createMcpAuthStubTools(serverName, config7, resolveUnexpanded = resolveUnexpandedMcpServers) {
628953
+ if (getIsNonInteractiveSession()) {
628954
+ return [];
628955
+ }
628956
+ return [
628957
+ createMcpAuthTool(serverName, config7, resolveUnexpanded),
628958
+ createMcpCompleteAuthTool(serverName, config7, resolveUnexpanded)
628959
+ ];
628960
+ }
628961
+ var inputSchema46, ANTHROPIC_HOSTED_OAUTH_BLOCKED_HOSTS, COMMAND_ARG_SAFE_PATTERN;
628649
628962
  var init_McpAuthTool = __esm(() => {
628650
628963
  init_reject2();
628651
628964
  init_v4();
628965
+ init_state();
628652
628966
  init_auth11();
628653
628967
  init_client12();
628968
+ init_config6();
628654
628969
  init_displaySanitize();
628655
628970
  init_mcpStringUtils();
628656
628971
  init_redaction();
628657
628972
  init_utils9();
628658
628973
  init_errors();
628659
628974
  init_log3();
628660
- inputSchema45 = lazySchema(() => exports_external.object({}));
628975
+ init_McpCompleteAuthTool();
628976
+ init_mcpAuthStubShared();
628977
+ inputSchema46 = lazySchema(() => exports_external.object({}));
628978
+ ANTHROPIC_HOSTED_OAUTH_BLOCKED_HOSTS = [
628979
+ "microsoft365.mcp.claude.com",
628980
+ "gmail.mcp.claude.com",
628981
+ "gcal.mcp.claude.com"
628982
+ ];
628983
+ COMMAND_ARG_SAFE_PATTERN = /^\w[\w.@-]*$/;
628661
628984
  });
628662
628985
 
628663
628986
  // src/utils/mcpWebSocketTransport.ts
@@ -631858,7 +632181,7 @@ async function getMcpToolsCommandsAndResources(onConnectionAttempt, mcpConfigs)
631858
632181
  logMCPDebug(name3, `Skipping connection (cached needs-auth)`);
631859
632182
  onConnectionAttempt({
631860
632183
  client: { name: name3, type: "needs-auth", config: config7 },
631861
- tools: [createMcpAuthTool(name3, config7)],
632184
+ tools: createMcpAuthStubTools(name3, config7),
631862
632185
  commands: []
631863
632186
  });
631864
632187
  return;
@@ -631867,7 +632190,7 @@ async function getMcpToolsCommandsAndResources(onConnectionAttempt, mcpConfigs)
631867
632190
  if (client8.type !== "connected") {
631868
632191
  onConnectionAttempt({
631869
632192
  client: client8,
631870
- tools: client8.type === "needs-auth" ? [createMcpAuthTool(name3, config7)] : [],
632193
+ tools: client8.type === "needs-auth" ? createMcpAuthStubTools(name3, config7) : [],
631871
632194
  commands: []
631872
632195
  });
631873
632196
  return;
@@ -718166,9 +718489,9 @@ function RateLimitOptionsMenu(t0) {
718166
718489
  t5 = function handleSelect2(value) {
718167
718490
  if (value === "upgrade") {
718168
718491
  logEvent2("tengu_rate_limit_options_menu_select_upgrade", {});
718169
- call81(onDone, context8).then((jsx346) => {
718170
- if (jsx346) {
718171
- setSubCommandJSX(jsx346);
718492
+ call81(onDone, context8).then((upgradeJsx) => {
718493
+ if (upgradeJsx) {
718494
+ setSubCommandJSX(upgradeJsx);
718172
718495
  }
718173
718496
  });
718174
718497
  } else {
@@ -776622,7 +776945,7 @@ function ModeIndicator({
776622
776945
  if (mode === "bash") {
776623
776946
  return /* @__PURE__ */ jsx_runtime432.jsx(ThemedText, {
776624
776947
  color: "bashBorder",
776625
- children: "! for bash mode"
776948
+ children: "! for shell mode"
776626
776949
  });
776627
776950
  }
776628
776951
  const currentMode = toolPermissionContext?.mode;
@@ -779123,7 +779446,7 @@ function PromptInput({
779123
779446
  if (getPlatform() === "macos" && isMacosOptionChar(char)) {
779124
779447
  const shortcut = MACOS_OPTION_SPECIAL_CHARS[char];
779125
779448
  const terminalName = getNativeCSIuTerminalDisplayName();
779126
- const jsx430 = terminalName ? /* @__PURE__ */ jsx_runtime437.jsxs(ThemedText, {
779449
+ const hintJsx = terminalName ? /* @__PURE__ */ jsx_runtime437.jsxs(ThemedText, {
779127
779450
  dimColor: true,
779128
779451
  children: [
779129
779452
  "To enable ",
@@ -779148,7 +779471,7 @@ function PromptInput({
779148
779471
  });
779149
779472
  addNotification({
779150
779473
  key: "option-meta-hint",
779151
- jsx: jsx430,
779474
+ jsx: hintJsx,
779152
779475
  priority: "immediate",
779153
779476
  timeoutMs: 5000
779154
779477
  });
@@ -792719,9 +793042,9 @@ async function processBashCommand(inputString, precedingInputBlocks, attachmentM
792719
793042
  precedingInputBlocks
792720
793043
  })
792721
793044
  });
792722
- let jsx434;
793045
+ let backgroundJsx;
792723
793046
  setToolJSX({
792724
- jsx: /* @__PURE__ */ jsx434(BashModeProgress, {
793047
+ jsx: /* @__PURE__ */ jsx_runtime442.jsx(BashModeProgress, {
792725
793048
  input: inputString,
792726
793049
  progress: null,
792727
793050
  verbose: context8.options.verbose
@@ -792732,19 +793055,19 @@ async function processBashCommand(inputString, precedingInputBlocks, attachmentM
792732
793055
  const bashModeContext = {
792733
793056
  ...context8,
792734
793057
  setToolJSX: (_4) => {
792735
- jsx434 = _4?.jsx;
793058
+ backgroundJsx = _4?.jsx;
792736
793059
  }
792737
793060
  };
792738
793061
  const onProgress = (progress) => {
792739
793062
  setToolJSX({
792740
793063
  jsx: /* @__PURE__ */ jsx_runtime442.jsxs(jsx_runtime442.Fragment, {
792741
793064
  children: [
792742
- /* @__PURE__ */ jsx434(BashModeProgress, {
793065
+ /* @__PURE__ */ jsx_runtime442.jsx(BashModeProgress, {
792743
793066
  input: inputString,
792744
793067
  progress: progress.data,
792745
793068
  verbose: context8.options.verbose
792746
793069
  }),
792747
- jsx434
793070
+ backgroundJsx
792748
793071
  ]
792749
793072
  }),
792750
793073
  shouldHidePromptInput: false,
@@ -793578,6 +793901,7 @@ var exports_toolPool = {};
793578
793901
  __export(exports_toolPool, {
793579
793902
  mergeAndFilterTools: () => mergeAndFilterTools,
793580
793903
  isPrActivitySubscriptionTool: () => isPrActivitySubscriptionTool,
793904
+ deferInitialMcpToolsToLiveState: () => deferInitialMcpToolsToLiveState,
793581
793905
  applyCoordinatorToolFilter: () => applyCoordinatorToolFilter
793582
793906
  });
793583
793907
  function isPrActivitySubscriptionTool(name3) {
@@ -793597,18 +793921,48 @@ function mergeAndFilterTools(initialTools, assembled, mode) {
793597
793921
  }
793598
793922
  return tools;
793599
793923
  }
793600
- var PR_ACTIVITY_TOOL_SUFFIXES, coordinatorModeModule2;
793924
+ function isMcpAuthStubName(name3) {
793925
+ return name3.endsWith(`__${MCP_AUTH_TOOL_SUFFIX}`) || name3.endsWith(`__${MCP_COMPLETE_AUTH_TOOL_SUFFIX}`);
793926
+ }
793927
+ function deferInitialMcpToolsToLiveState(initialTools, liveClients, liveTools = []) {
793928
+ if (liveClients.length === 0) {
793929
+ return initialTools;
793930
+ }
793931
+ const clientsWithPrefix = liveClients.map((client8) => ({
793932
+ prefix: getMcpPrefix(client8.name),
793933
+ type: client8.type
793934
+ }));
793935
+ const allPrefixes = clientsWithPrefix.map((entry) => entry.prefix);
793936
+ const prefixesWithLiveTools = new Set(clientsWithPrefix.filter(({ prefix }) => liveTools.some((t4) => t4.name?.startsWith(prefix))).map(({ prefix }) => prefix));
793937
+ const stubPreservingPrefixes = new Set(clientsWithPrefix.filter(({ prefix, type }) => type !== undefined && AUTH_STUB_PRESERVING_STATES.has(type) && !prefixesWithLiveTools.has(prefix)).map(({ prefix }) => prefix));
793938
+ return initialTools.filter((tool) => {
793939
+ const name3 = tool.name;
793940
+ if (name3 === undefined) {
793941
+ return true;
793942
+ }
793943
+ for (const prefix of stubPreservingPrefixes) {
793944
+ if (name3.startsWith(prefix) && isMcpAuthStubName(name3)) {
793945
+ return true;
793946
+ }
793947
+ }
793948
+ return !allPrefixes.some((prefix) => name3.startsWith(prefix));
793949
+ });
793950
+ }
793951
+ var PR_ACTIVITY_TOOL_SUFFIXES, coordinatorModeModule2, AUTH_STUB_PRESERVING_STATES;
793601
793952
  var init_toolPool = __esm(() => {
793602
793953
  init_featureFlags();
793603
793954
  init_partition();
793604
793955
  init_uniqBy();
793605
793956
  init_tools();
793957
+ init_mcpStringUtils();
793606
793958
  init_utils9();
793959
+ init_mcpAuthStubShared();
793607
793960
  PR_ACTIVITY_TOOL_SUFFIXES = [
793608
793961
  "subscribe_pr_activity",
793609
793962
  "unsubscribe_pr_activity"
793610
793963
  ];
793611
793964
  coordinatorModeModule2 = feature("COORDINATOR_MODE") ? (init_coordinatorMode(), __toCommonJS(exports_coordinatorMode)) : null;
793965
+ AUTH_STUB_PRESERVING_STATES = new Set(["failed", "disabled"]);
793612
793966
  });
793613
793967
 
793614
793968
  // src/hooks/useMergedTools.ts
@@ -798931,13 +799285,13 @@ function permissionPromptToolResultToPermissionDecision(result, tool, input2, to
798931
799285
  decisionReason
798932
799286
  };
798933
799287
  }
798934
- var inputSchema46, decisionClassificationField, PermissionAllowResultSchema, PermissionDenyResultSchema, outputSchema41;
799288
+ var inputSchema47, decisionClassificationField, PermissionAllowResultSchema, PermissionDenyResultSchema, outputSchema41;
798935
799289
  var init_PermissionPromptToolResultSchema = __esm(() => {
798936
799290
  init_v4();
798937
799291
  init_debug();
798938
799292
  init_PermissionUpdate();
798939
799293
  init_PermissionUpdateSchema();
798940
- inputSchema46 = lazySchema(() => v4_default.object({
799294
+ inputSchema47 = lazySchema(() => v4_default.object({
798941
799295
  tool_name: v4_default.string().describe("The name of the tool requesting permission"),
798942
799296
  input: v4_default.record(v4_default.string(), v4_default.unknown()).describe("The input for the tool"),
798943
799297
  tool_use_id: v4_default.string().optional().describe("The unique tool use request ID")
@@ -805678,6 +806032,7 @@ function REPL({
805678
806032
  const combinedInitialTools = import_react321.useMemo(() => {
805679
806033
  return [...localTools, ...initialTools];
805680
806034
  }, [localTools, initialTools]);
806035
+ const effectiveInitialTools = import_react321.useMemo(() => deferInitialMcpToolsToLiveState(combinedInitialTools, mcp2.clients, mcp2.tools), [combinedInitialTools, mcp2.clients, mcp2.tools]);
805681
806036
  useManagePlugins({
805682
806037
  enabled: !isRemoteSession
805683
806038
  });
@@ -805699,7 +806054,7 @@ function REPL({
805699
806054
  useSwarmInitialization(setAppState, initialMessages, {
805700
806055
  enabled: !isRemoteSession
805701
806056
  });
805702
- const mergedTools = useMergedTools(combinedInitialTools, mcp2.tools, toolPermissionContext);
806057
+ const mergedTools = useMergedTools(effectiveInitialTools, mcp2.tools, toolPermissionContext);
805703
806058
  const {
805704
806059
  tools,
805705
806060
  allowedAgentTypes
@@ -806715,7 +807070,7 @@ Error: sandbox required but unavailable: ${reason}
806715
807070
  const computeTools = () => {
806716
807071
  const state4 = store.getState();
806717
807072
  const assembled = assembleToolPool(state4.toolPermissionContext, state4.mcp.tools);
806718
- const merged = mergeAndFilterTools(combinedInitialTools, assembled, state4.toolPermissionContext.mode);
807073
+ const merged = mergeAndFilterTools(deferInitialMcpToolsToLiveState(combinedInitialTools, state4.mcp.clients, state4.mcp.tools), assembled, state4.toolPermissionContext.mode);
806719
807074
  if (!mainThreadAgentDefinition)
806720
807075
  return merged;
806721
807076
  return resolveAgentTools(mainThreadAgentDefinition, merged, false, true).resolvedTools;
@@ -807284,10 +807639,10 @@ Error: sandbox required but unavailable: ${reason}
807284
807639
  };
807285
807640
  const context8 = getToolUseContext(messagesRef.current, [], createAbortController(), mainLoopModel);
807286
807641
  const mod2 = await matchingCommand.load();
807287
- const jsx463 = await mod2.call(onDone, context8, commandArgs);
807288
- if (jsx463 && !doneWasCalled) {
807642
+ const commandJsx = await mod2.call(onDone, context8, commandArgs);
807643
+ if (commandJsx && !doneWasCalled) {
807289
807644
  setToolJSX({
807290
- jsx: jsx463,
807645
+ jsx: commandJsx,
807291
807646
  shouldHidePromptInput: false,
807292
807647
  isLocalJSXCommand: true
807293
807648
  });
@@ -820046,6 +820401,42 @@ var init_remoteIO = __esm(() => {
820046
820401
  };
820047
820402
  });
820048
820403
 
820404
+ // src/cli/mcpOAuthCallbackControl.ts
820405
+ async function handleOAuthCallbackUrlControl(serverName, callbackUrl, deps) {
820406
+ const submit = deps.getSubmitter(serverName);
820407
+ if (!submit) {
820408
+ deps.respondError(`No active OAuth flow for server: ${serverName}`);
820409
+ return;
820410
+ }
820411
+ let hasCodeOrError = false;
820412
+ try {
820413
+ const parsed = new URL(callbackUrl);
820414
+ hasCodeOrError = parsed.searchParams.has("code") || parsed.searchParams.has("error");
820415
+ } catch {}
820416
+ if (!hasCodeOrError) {
820417
+ deps.respondError(CALLBACK_MISSING_CODE_MESSAGE);
820418
+ return;
820419
+ }
820420
+ const accepted = submit(callbackUrl);
820421
+ if (!accepted) {
820422
+ deps.respondError(CALLBACK_NOT_ACCEPTED_MESSAGE);
820423
+ return;
820424
+ }
820425
+ deps.markManualCallbackUsed(serverName);
820426
+ const authPromise = deps.getAuthPromise(serverName);
820427
+ if (!authPromise) {
820428
+ deps.respondSuccess();
820429
+ return;
820430
+ }
820431
+ try {
820432
+ await authPromise;
820433
+ deps.respondSuccess();
820434
+ } catch (error52) {
820435
+ deps.respondError(error52 instanceof Error ? error52.message : "OAuth authentication failed");
820436
+ }
820437
+ }
820438
+ var CALLBACK_NOT_ACCEPTED_MESSAGE = "Callback URL was not accepted: its state does not match the flow in progress (or it carries no authorization code). The OAuth flow is still waiting \u2014 send the redirect URL from the authorization page this flow opened.", CALLBACK_MISSING_CODE_MESSAGE = "Invalid callback URL: missing authorization code. Please paste the full redirect URL including the code parameter.";
820439
+
820049
820440
  // src/utils/streamlinedTransform.ts
820050
820441
  function categorizeToolName(toolName) {
820051
820442
  if (SEARCH_TOOLS2.some((t4) => toolName.startsWith(t4)))
@@ -822151,7 +822542,7 @@ function runHeadlessStreaming(structuredIO, mcpClients, commands7, tools, initia
822151
822542
  };
822152
822543
  const buildAllTools = (appState) => {
822153
822544
  const assembledTools = assembleToolPool(appState.toolPermissionContext, appState.mcp.tools);
822154
- let allTools = uniqBy_default(mergeAndFilterTools([...tools, ...sdkTools, ...dynamicMcpState.tools], assembledTools, appState.toolPermissionContext.mode), "name");
822545
+ let allTools = uniqBy_default(mergeAndFilterTools(deferInitialMcpToolsToLiveState([...tools, ...sdkTools, ...dynamicMcpState.tools], appState.mcp.clients, appState.mcp.tools), assembledTools, appState.toolPermissionContext.mode), "name");
822155
822546
  if (options.permissionPromptToolName) {
822156
822547
  allTools = allTools.filter((tool) => !toolMatchesName(tool, options.permissionPromptToolName));
822157
822548
  }
@@ -822899,8 +823290,8 @@ ${m5.text}
822899
823290
  }
822900
823291
  });
822901
823292
  });
822902
- const activeOAuthFlows = new Map;
822903
- const oauthCallbackSubmitters = new Map;
823293
+ const activeOAuthFlows2 = new Map;
823294
+ const oauthCallbackSubmitters2 = new Map;
822904
823295
  const oauthManualCallbackUsed = new Set;
822905
823296
  const oauthAuthPromises = new Map;
822906
823297
  let claudeOAuth = null;
@@ -823234,9 +823625,9 @@ ${m5.text}
823234
823625
  sendControlResponseError(message, `Server type "${config8.type}" does not support OAuth authentication`);
823235
823626
  } else {
823236
823627
  try {
823237
- activeOAuthFlows.get(serverName)?.abort();
823628
+ activeOAuthFlows2.get(serverName)?.abort();
823238
823629
  const controller = new AbortController;
823239
- activeOAuthFlows.set(serverName, controller);
823630
+ activeOAuthFlows2.set(serverName, controller);
823240
823631
  let resolveAuthUrl;
823241
823632
  const authUrlPromise = new Promise((resolve63) => {
823242
823633
  resolveAuthUrl = resolve63;
@@ -823244,7 +823635,7 @@ ${m5.text}
823244
823635
  const oauthPromise = performMCPOAuthFlow(serverName, config8, (url3) => resolveAuthUrl(url3), controller.signal, {
823245
823636
  skipBrowserOpen: true,
823246
823637
  onWaitingForCallback: (submit) => {
823247
- oauthCallbackSubmitters.set(serverName, submit);
823638
+ oauthCallbackSubmitters2.set(serverName, submit);
823248
823639
  }
823249
823640
  });
823250
823641
  const authUrl = await Promise.race([
@@ -823304,9 +823695,9 @@ ${m5.text}
823304
823695
  }).catch((error52) => {
823305
823696
  logForDebugging(`MCP OAuth failed for ${serverName}: ${error52}`, { level: "error" });
823306
823697
  }).finally(() => {
823307
- if (activeOAuthFlows.get(serverName) === controller) {
823308
- activeOAuthFlows.delete(serverName);
823309
- oauthCallbackSubmitters.delete(serverName);
823698
+ if (activeOAuthFlows2.get(serverName) === controller) {
823699
+ activeOAuthFlows2.delete(serverName);
823700
+ oauthCallbackSubmitters2.delete(serverName);
823310
823701
  oauthManualCallbackUsed.delete(serverName);
823311
823702
  oauthAuthPromises.delete(serverName);
823312
823703
  }
@@ -823317,33 +823708,15 @@ ${m5.text}
823317
823708
  }
823318
823709
  } else if (message.request.subtype === "mcp_oauth_callback_url") {
823319
823710
  const { serverName, callbackUrl } = message.request;
823320
- const submit = oauthCallbackSubmitters.get(serverName);
823321
- if (submit) {
823322
- let hasCodeOrError = false;
823323
- try {
823324
- const parsed = new URL(callbackUrl);
823325
- hasCodeOrError = parsed.searchParams.has("code") || parsed.searchParams.has("error");
823326
- } catch {}
823327
- if (!hasCodeOrError) {
823328
- sendControlResponseError(message, "Invalid callback URL: missing authorization code. Please paste the full redirect URL including the code parameter.");
823329
- } else {
823330
- oauthManualCallbackUsed.add(serverName);
823331
- submit(callbackUrl);
823332
- const authPromise = oauthAuthPromises.get(serverName);
823333
- if (authPromise) {
823334
- try {
823335
- await authPromise;
823336
- sendControlResponseSuccess(message);
823337
- } catch (error52) {
823338
- sendControlResponseError(message, error52 instanceof Error ? error52.message : "OAuth authentication failed");
823339
- }
823340
- } else {
823341
- sendControlResponseSuccess(message);
823342
- }
823343
- }
823344
- } else {
823345
- sendControlResponseError(message, `No active OAuth flow for server: ${serverName}`);
823346
- }
823711
+ await handleOAuthCallbackUrlControl(serverName, callbackUrl, {
823712
+ getSubmitter: (name3) => oauthCallbackSubmitters2.get(name3),
823713
+ getAuthPromise: (name3) => oauthAuthPromises.get(name3),
823714
+ markManualCallbackUsed: (name3) => {
823715
+ oauthManualCallbackUsed.add(name3);
823716
+ },
823717
+ respondError: (errorMessageText) => sendControlResponseError(message, errorMessageText),
823718
+ respondSuccess: () => sendControlResponseSuccess(message)
823719
+ });
823347
823720
  } else if (message.request.subtype === "claude_authenticate") {
823348
823721
  const { loginWithClaudeAi } = message.request;
823349
823722
  claudeOAuth?.service.cleanup();
@@ -825209,6 +825582,22 @@ var init_MCPServerDesktopImportDialog = __esm(() => {
825209
825582
  jsx_runtime498 = __toESM(require_jsx_runtime(), 1);
825210
825583
  });
825211
825584
 
825585
+ // src/cli/mcpOAuthPrompt.ts
825586
+ function promptForCallbackUrlWithRetry(io, submit) {
825587
+ const ask2 = () => {
825588
+ io.question("> ", (answer) => {
825589
+ if (submit(answer.trim())) {
825590
+ io.close();
825591
+ return;
825592
+ }
825593
+ io.notify(CALLBACK_REJECTED_RETRY_HINT);
825594
+ ask2();
825595
+ });
825596
+ };
825597
+ ask2();
825598
+ }
825599
+ var CALLBACK_REJECTED_RETRY_HINT = "That URL was not accepted: its state does not match the flow in progress (or it carries no authorization code). The flow is still waiting \u2014 paste the full redirect URL from the browser page this login opened:";
825600
+
825212
825601
  // node_modules/.bun/@modelcontextprotocol+sdk@1.29.0/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
825213
825602
  class ExperimentalServerTasks {
825214
825603
  constructor(_server) {
@@ -826202,10 +826591,17 @@ ${url3}`);
826202
826591
  console.log(`
826203
826592
  After authorizing, paste the full redirect URL here and press Enter:`);
826204
826593
  const rl = readline5.createInterface({ input: process.stdin });
826205
- rl.question("> ", (answer) => {
826206
- rl.close();
826207
- submit(answer.trim());
826208
- });
826594
+ promptForCallbackUrlWithRetry({
826595
+ question: (prompt, onAnswer) => {
826596
+ rl.question(prompt, onAnswer);
826597
+ },
826598
+ close: () => {
826599
+ rl.close();
826600
+ },
826601
+ notify: (message) => {
826602
+ console.log(message);
826603
+ }
826604
+ }, submit);
826209
826605
  } : undefined;
826210
826606
  try {
826211
826607
  await performMCPOAuthFlow(name3, server, onAuthorizationUrl, undefined, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnwenf/occ",
3
- "version": "2.1.339",
3
+ "version": "2.1.341",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {