feat: build

This commit is contained in:
claude-code-best committed 2026-03-31 19:22:47 +08:00
commit f90eee85d8
1906 files changed
+514339

No files matched your search

@@ -0,0 +1,61 @@
import { c as _c } from "react/compiler-runtime";
import React from 'react';
import { Box, Text } from '../../ink.js';
import { Byline } from '../design-system/Byline.js';
type Props = {
serverToolsCount: number;
serverPromptsCount: number;
serverResourcesCount: number;
};
export function CapabilitiesSection(t0) {
const $ = _c(9);
const {
serverToolsCount,
serverPromptsCount,
serverResourcesCount
} = t0;
let capabilities;
if ($[0] !== serverPromptsCount || $[1] !== serverResourcesCount || $[2] !== serverToolsCount) {
capabilities = [];
if (serverToolsCount > 0) {
capabilities.push("tools");
}
if (serverResourcesCount > 0) {
capabilities.push("resources");
}
if (serverPromptsCount > 0) {
capabilities.push("prompts");
}
$[0] = serverPromptsCount;
$[1] = serverResourcesCount;
$[2] = serverToolsCount;
$[3] = capabilities;
} else {
capabilities = $[3];
}
let t1;
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Text bold={true}>Capabilities: </Text>;
$[4] = t1;
} else {
t1 = $[4];
}
let t2;
if ($[5] !== capabilities) {
t2 = capabilities.length > 0 ? <Byline>{capabilities}</Byline> : "none";
$[5] = capabilities;
$[6] = t2;
} else {
t2 = $[6];
}
let t3;
if ($[7] !== t2) {
t3 = <Box>{t1}<Text color="text">{t2}</Text></Box>;
$[7] = t2;
$[8] = t3;
} else {
t3 = $[8];
}
return t3;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIlRleHQiLCJCeWxpbmUiLCJQcm9wcyIsInNlcnZlclRvb2xzQ291bnQiLCJzZXJ2ZXJQcm9tcHRzQ291bnQiLCJzZXJ2ZXJSZXNvdXJjZXNDb3VudCIsIkNhcGFiaWxpdGllc1NlY3Rpb24iLCJ0MCIsIiQiLCJfYyIsImNhcGFiaWxpdGllcyIsInB1c2giLCJ0MSIsIlN5bWJvbCIsImZvciIsInQyIiwibGVuZ3RoIiwidDMiXSwic291cmNlcyI6WyJDYXBhYmlsaXRpZXNTZWN0aW9uLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBCb3gsIFRleHQgfSBmcm9tICcuLi8uLi9pbmsuanMnXG5pbXBvcnQgeyBCeWxpbmUgfSBmcm9tICcuLi9kZXNpZ24tc3lzdGVtL0J5bGluZS5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgc2VydmVyVG9vbHNDb3VudDogbnVtYmVyXG4gIHNlcnZlclByb21wdHNDb3VudDogbnVtYmVyXG4gIHNlcnZlclJlc291cmNlc0NvdW50OiBudW1iZXJcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENhcGFiaWxpdGllc1NlY3Rpb24oe1xuICBzZXJ2ZXJUb29sc0NvdW50LFxuICBzZXJ2ZXJQcm9tcHRzQ291bnQsXG4gIHNlcnZlclJlc291cmNlc0NvdW50LFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBjYXBhYmlsaXRpZXMgPSBbXVxuICBpZiAoc2VydmVyVG9vbHNDb3VudCA+IDApIHtcbiAgICBjYXBhYmlsaXRpZXMucHVzaCgndG9vbHMnKVxuICB9XG4gIGlmIChzZXJ2ZXJSZXNvdXJjZXNDb3VudCA+IDApIHtcbiAgICBjYXBhYmlsaXRpZXMucHVzaCgncmVzb3VyY2VzJylcbiAgfVxuICBpZiAoc2VydmVyUHJvbXB0c0NvdW50ID4gMCkge1xuICAgIGNhcGFiaWxpdGllcy5wdXNoKCdwcm9tcHRzJylcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPEJveD5cbiAgICAgIDxUZXh0IGJvbGQ+Q2FwYWJpbGl0aWVzOiA8L1RleHQ+XG4gICAgICA8VGV4dCBjb2xvcj1cInRleHRcIj5cbiAgICAgICAge2NhcGFiaWxpdGllcy5sZW5ndGggPiAwID8gPEJ5bGluZT57Y2FwYWJpbGl0aWVzfTwvQnlsaW5lPiA6ICdub25lJ31cbiAgICAgIDwvVGV4dD5cbiAgICA8L0JveD5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsU0FBU0MsR0FBRyxFQUFFQyxJQUFJLFFBQVEsY0FBYztBQUN4QyxTQUFTQyxNQUFNLFFBQVEsNEJBQTRCO0FBRW5ELEtBQUtDLEtBQUssR0FBRztFQUNYQyxnQkFBZ0IsRUFBRSxNQUFNO0VBQ3hCQyxrQkFBa0IsRUFBRSxNQUFNO0VBQzFCQyxvQkFBb0IsRUFBRSxNQUFNO0FBQzlCLENBQUM7QUFFRCxPQUFPLFNBQUFDLG9CQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQTZCO0lBQUFOLGdCQUFBO0lBQUFDLGtCQUFBO0lBQUFDO0VBQUEsSUFBQUUsRUFJNUI7RUFBQSxJQUFBRyxZQUFBO0VBQUEsSUFBQUYsQ0FBQSxRQUFBSixrQkFBQSxJQUFBSSxDQUFBLFFBQUFILG9CQUFBLElBQUFHLENBQUEsUUFBQUwsZ0JBQUE7SUFDTk8sWUFBQSxHQUFxQixFQUFFO0lBQ3ZCLElBQUlQLGdCQUFnQixHQUFHLENBQUM7TUFDdEJPLFlBQVksQ0FBQUMsSUFBSyxDQUFDLE9BQU8sQ0FBQztJQUFBO0lBRTVCLElBQUlOLG9CQUFvQixHQUFHLENBQUM7TUFDMUJLLFlBQVksQ0FBQUMsSUFBSyxDQUFDLFdBQVcsQ0FBQztJQUFBO0lBRWhDLElBQUlQLGtCQUFrQixHQUFHLENBQUM7TUFDeEJNLFlBQVksQ0FBQUMsSUFBSyxDQUFDLFNBQVMsQ0FBQztJQUFBO0lBQzdCSCxDQUFBLE1BQUFKLGtCQUFBO0lBQUFJLENBQUEsTUFBQUgsb0JBQUE7SUFBQUcsQ0FBQSxNQUFBTCxnQkFBQTtJQUFBSyxDQUFBLE1BQUFFLFlBQUE7RUFBQTtJQUFBQSxZQUFBLEdBQUFGLENBQUE7RUFBQTtFQUFBLElBQUFJLEVBQUE7RUFBQSxJQUFBSixDQUFBLFFBQUFLLE1BQUEsQ0FBQUMsR0FBQTtJQUlHRixFQUFBLElBQUMsSUFBSSxDQUFDLElBQUksQ0FBSixLQUFHLENBQUMsQ0FBQyxjQUFjLEVBQXhCLElBQUksQ0FBMkI7SUFBQUosQ0FBQSxNQUFBSSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBSixDQUFBO0VBQUE7RUFBQSxJQUFBTyxFQUFBO0VBQUEsSUFBQVAsQ0FBQSxRQUFBRSxZQUFBO0lBRTdCSyxFQUFBLEdBQUFMLFlBQVksQ0FBQU0sTUFBTyxHQUFHLENBQTRDLEdBQXhDLENBQUMsTUFBTSxDQUFFTixhQUFXLENBQUUsRUFBckIsTUFBTSxDQUFpQyxHQUFsRSxNQUFrRTtJQUFBRixDQUFBLE1BQUFFLFlBQUE7SUFBQUYsQ0FBQSxNQUFBTyxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBUCxDQUFBO0VBQUE7RUFBQSxJQUFBUyxFQUFBO0VBQUEsSUFBQVQsQ0FBQSxRQUFBTyxFQUFBO0lBSHZFRSxFQUFBLElBQUMsR0FBRyxDQUNGLENBQUFMLEVBQStCLENBQy9CLENBQUMsSUFBSSxDQUFPLEtBQU0sQ0FBTixNQUFNLENBQ2YsQ0FBQUcsRUFBaUUsQ0FDcEUsRUFGQyxJQUFJLENBR1AsRUFMQyxHQUFHLENBS0U7SUFBQVAsQ0FBQSxNQUFBTyxFQUFBO0lBQUFQLENBQUEsTUFBQVMsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQVQsQ0FBQTtFQUFBO0VBQUEsT0FMTlMsRUFLTTtBQUFBIiwiaWdub3JlTGlzdCI6W119
File diff suppressed because it is too large. Load diff
+183
View File
@@ -0,0 +1,183 @@
import figures from 'figures';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { CommandResultDisplay } from '../../commands.js';
import { Box, color, Link, Text, useTheme } from '../../ink.js';
import { useKeybinding } from '../../keybindings/useKeybinding.js';
import { AuthenticationCancelledError, performMCPOAuthFlow } from '../../services/mcp/auth.js';
import { capitalize } from '../../utils/stringUtils.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Select } from '../CustomSelect/index.js';
import { Byline } from '../design-system/Byline.js';
import { Dialog } from '../design-system/Dialog.js';
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js';
import { Spinner } from '../Spinner.js';
import type { AgentMcpServerInfo } from './types.js';
type Props = {
agentServer: AgentMcpServerInfo;
onCancel: () => void;
onComplete?: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
};
/**
* Menu for agent-specific MCP servers.
* These servers are defined in agent frontmatter and only connect when the agent runs.
* For HTTP/SSE servers, this allows pre-authentication before using the agent.
*/
export function MCPAgentServerMenu({
agentServer,
onCancel,
onComplete
}: Props): React.ReactNode {
const [theme] = useTheme();
const [isAuthenticating, setIsAuthenticating] = useState(false);
const [error, setError] = useState<string | null>(null);
const [authorizationUrl, setAuthorizationUrl] = useState<string | null>(null);
const authAbortControllerRef = useRef<AbortController | null>(null);
// Abort OAuth flow on unmount so the callback server is closed even if a
// parent component's Esc handler navigates away before ours fires.
useEffect(() => () => authAbortControllerRef.current?.abort(), []);
// Handle ESC to cancel authentication flow
const handleEscCancel = useCallback(() => {
if (isAuthenticating) {
authAbortControllerRef.current?.abort();
authAbortControllerRef.current = null;
setIsAuthenticating(false);
setAuthorizationUrl(null);
}
}, [isAuthenticating]);
useKeybinding('confirm:no', handleEscCancel, {
context: 'Confirmation',
isActive: isAuthenticating
});
const handleAuthenticate = useCallback(async () => {
if (!agentServer.needsAuth || !agentServer.url) {
return;
}
setIsAuthenticating(true);
setError(null);
const controller = new AbortController();
authAbortControllerRef.current = controller;
try {
// Create a temporary config for OAuth
const tempConfig = {
type: agentServer.transport as 'http' | 'sse',
url: agentServer.url
};
await performMCPOAuthFlow(agentServer.name, tempConfig, setAuthorizationUrl, controller.signal);
onComplete?.(`Authentication successful for ${agentServer.name}. The server will connect when the agent runs.`);
} catch (err) {
// Don't show error if it was a cancellation
if (err instanceof Error && !(err instanceof AuthenticationCancelledError)) {
setError(err.message);
}
} finally {
setIsAuthenticating(false);
authAbortControllerRef.current = null;
}
}, [agentServer, onComplete]);
const capitalizedServerName = capitalize(String(agentServer.name));
if (isAuthenticating) {
return <Box flexDirection="column" gap={1} padding={1}>
<Text color="claude">Authenticating with {agentServer.name}…</Text>
<Box>
<Spinner />
<Text> A browser window will open for authentication</Text>
</Box>
{authorizationUrl && <Box flexDirection="column">
<Text dimColor>
If your browser doesn&apos;t open automatically, copy this URL
manually:
</Text>
<Link url={authorizationUrl} />
</Box>}
<Box marginLeft={3}>
<Text dimColor>
Return here after authenticating in your browser.{' '}
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="go back" />
</Text>
</Box>
</Box>;
}
const menuOptions = [];
// Only show authenticate option for HTTP/SSE servers
if (agentServer.needsAuth) {
menuOptions.push({
label: agentServer.isAuthenticated ? 'Re-authenticate' : 'Authenticate',
value: 'auth'
});
}
menuOptions.push({
label: 'Back',
value: 'back'
});
return <Dialog title={`${capitalizedServerName} MCP Server`} subtitle="agent-only" onCancel={onCancel} inputGuide={exitState => exitState.pending ? <Text>Press {exitState.keyName} again to exit</Text> : <Byline>
<KeyboardShortcutHint shortcut="↑↓" action="navigate" />
<KeyboardShortcutHint shortcut="Enter" action="confirm" />
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="go back" />
</Byline>}>
<Box flexDirection="column" gap={0}>
<Box>
<Text bold>Type: </Text>
<Text dimColor>{agentServer.transport}</Text>
</Box>
{agentServer.url && <Box>
<Text bold>URL: </Text>
<Text dimColor>{agentServer.url}</Text>
</Box>}
{agentServer.command && <Box>
<Text bold>Command: </Text>
<Text dimColor>{agentServer.command}</Text>
</Box>}
<Box>
<Text bold>Used by: </Text>
<Text dimColor>{agentServer.sourceAgents.join(', ')}</Text>
</Box>
<Box marginTop={1}>
<Text bold>Status: </Text>
<Text>
{color('inactive', theme)(figures.radioOff)} not connected
(agent-only)
</Text>
</Box>
{agentServer.needsAuth && <Box>
<Text bold>Auth: </Text>
{agentServer.isAuthenticated ? <Text>{color('success', theme)(figures.tick)} authenticated</Text> : <Text>
{color('warning', theme)(figures.triangleUpOutline)} may need
authentication
</Text>}
</Box>}
</Box>
<Box>
<Text dimColor>This server connects only when running the agent.</Text>
</Box>
{error && <Box>
<Text color="error">Error: {error}</Text>
</Box>}
<Box>
<Select options={menuOptions} onChange={async value => {
switch (value) {
case 'auth':
await handleAuthenticate();
break;
case 'back':
onCancel();
break;
}
}} onCancel={onCancel} />
</Box>
</Dialog>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJ1c2VDYWxsYmFjayIsInVzZUVmZmVjdCIsInVzZVJlZiIsInVzZVN0YXRlIiwiQ29tbWFuZFJlc3VsdERpc3BsYXkiLCJCb3giLCJjb2xvciIsIkxpbmsiLCJUZXh0IiwidXNlVGhlbWUiLCJ1c2VLZXliaW5kaW5nIiwiQXV0aGVudGljYXRpb25DYW5jZWxsZWRFcnJvciIsInBlcmZvcm1NQ1BPQXV0aEZsb3ciLCJjYXBpdGFsaXplIiwiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IiwiU2VsZWN0IiwiQnlsaW5lIiwiRGlhbG9nIiwiS2V5Ym9hcmRTaG9ydGN1dEhpbnQiLCJTcGlubmVyIiwiQWdlbnRNY3BTZXJ2ZXJJbmZvIiwiUHJvcHMiLCJhZ2VudFNlcnZlciIsIm9uQ2FuY2VsIiwib25Db21wbGV0ZSIsInJlc3VsdCIsIm9wdGlvbnMiLCJkaXNwbGF5IiwiTUNQQWdlbnRTZXJ2ZXJNZW51IiwiUmVhY3ROb2RlIiwidGhlbWUiLCJpc0F1dGhlbnRpY2F0aW5nIiwic2V0SXNBdXRoZW50aWNhdGluZyIsImVycm9yIiwic2V0RXJyb3IiLCJhdXRob3JpemF0aW9uVXJsIiwic2V0QXV0aG9yaXphdGlvblVybCIsImF1dGhBYm9ydENvbnRyb2xsZXJSZWYiLCJBYm9ydENvbnRyb2xsZXIiLCJjdXJyZW50IiwiYWJvcnQiLCJoYW5kbGVFc2NDYW5jZWwiLCJjb250ZXh0IiwiaXNBY3RpdmUiLCJoYW5kbGVBdXRoZW50aWNhdGUiLCJuZWVkc0F1dGgiLCJ1cmwiLCJjb250cm9sbGVyIiwidGVtcENvbmZpZyIsInR5cGUiLCJ0cmFuc3BvcnQiLCJuYW1lIiwic2lnbmFsIiwiZXJyIiwiRXJyb3IiLCJtZXNzYWdlIiwiY2FwaXRhbGl6ZWRTZXJ2ZXJOYW1lIiwiU3RyaW5nIiwibWVudU9wdGlvbnMiLCJwdXNoIiwibGFiZWwiLCJpc0F1dGhlbnRpY2F0ZWQiLCJ2YWx1ZSIsImV4aXRTdGF0ZSIsInBlbmRpbmciLCJrZXlOYW1lIiwiY29tbWFuZCIsInNvdXJjZUFnZW50cyIsImpvaW4iLCJyYWRpb09mZiIsInRpY2siLCJ0cmlhbmdsZVVwT3V0bGluZSJdLCJzb3VyY2VzIjpbIk1DUEFnZW50U2VydmVyTWVudS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZpZ3VyZXMgZnJvbSAnZmlndXJlcydcbmltcG9ydCBSZWFjdCwgeyB1c2VDYWxsYmFjaywgdXNlRWZmZWN0LCB1c2VSZWYsIHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgdHlwZSB7IENvbW1hbmRSZXN1bHREaXNwbGF5IH0gZnJvbSAnLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgeyBCb3gsIGNvbG9yLCBMaW5rLCBUZXh0LCB1c2VUaGVtZSB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB7IHVzZUtleWJpbmRpbmcgfSBmcm9tICcuLi8uLi9rZXliaW5kaW5ncy91c2VLZXliaW5kaW5nLmpzJ1xuaW1wb3J0IHtcbiAgQXV0aGVudGljYXRpb25DYW5jZWxsZWRFcnJvcixcbiAgcGVyZm9ybU1DUE9BdXRoRmxvdyxcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvbWNwL2F1dGguanMnXG5pbXBvcnQgeyBjYXBpdGFsaXplIH0gZnJvbSAnLi4vLi4vdXRpbHMvc3RyaW5nVXRpbHMuanMnXG5pbXBvcnQgeyBDb25maWd1cmFibGVTaG9ydGN1dEhpbnQgfSBmcm9tICcuLi9Db25maWd1cmFibGVTaG9ydGN1dEhpbnQuanMnXG5pbXBvcnQgeyBTZWxlY3QgfSBmcm9tICcuLi9DdXN0b21TZWxlY3QvaW5kZXguanMnXG5pbXBvcnQgeyBCeWxpbmUgfSBmcm9tICcuLi9kZXNpZ24tc3lzdGVtL0J5bGluZS5qcydcbmltcG9ydCB7IERpYWxvZyB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vRGlhbG9nLmpzJ1xuaW1wb3J0IHsgS2V5Ym9hcmRTaG9ydGN1dEhpbnQgfSBmcm9tICcuLi9kZXNpZ24tc3lzdGVtL0tleWJvYXJkU2hvcnRjdXRIaW50LmpzJ1xuaW1wb3J0IHsgU3Bpbm5lciB9IGZyb20gJy4uL1NwaW5uZXIuanMnXG5pbXBvcnQgdHlwZSB7IEFnZW50TWNwU2VydmVySW5mbyB9IGZyb20gJy4vdHlwZXMuanMnXG5cbnR5cGUgUHJvcHMgPSB7XG4gIGFnZW50U2VydmVyOiBBZ2VudE1jcFNlcnZlckluZm9cbiAgb25DYW5jZWw6ICgpID0+IHZvaWRcbiAgb25Db21wbGV0ZT86IChcbiAgICByZXN1bHQ/OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHsgZGlzcGxheT86IENvbW1hbmRSZXN1bHREaXNwbGF5IH0sXG4gICkgPT4gdm9pZFxufVxuXG4vKipcbiAqIE1lbnUgZm9yIGFnZW50LXNwZWNpZmljIE1DUCBzZXJ2ZXJzLlxuICogVGhlc2Ugc2VydmVycyBhcmUgZGVmaW5lZCBpbiBhZ2VudCBmcm9udG1hdHRlciBhbmQgb25seSBjb25uZWN0IHdoZW4gdGhlIGFnZW50IHJ1bnMuXG4gKiBGb3IgSFRUUC9TU0Ugc2VydmVycywgdGhpcyBhbGxvd3MgcHJlLWF1dGhlbnRpY2F0aW9uIGJlZm9yZSB1c2luZyB0aGUgYWdlbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBNQ1BBZ2VudFNlcnZlck1lbnUoe1xuICBhZ2VudFNlcnZlcixcbiAgb25DYW5jZWwsXG4gIG9uQ29tcGxldGUsXG59OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IFt0aGVtZV0gPSB1c2VUaGVtZSgpXG4gIGNvbnN0IFtpc0F1dGhlbnRpY2F0aW5nLCBzZXRJc0F1dGhlbnRpY2F0aW5nXSA9IHVzZVN0YXRlKGZhbHNlKVxuICBjb25zdCBbZXJyb3IsIHNldEVycm9yXSA9IHVzZVN0YXRlPHN0cmluZyB8IG51bGw+KG51bGwpXG4gIGNvbnN0IFthdXRob3JpemF0aW9uVXJsLCBzZXRBdXRob3JpemF0aW9uVXJsXSA9IHVzZVN0YXRlPHN0cmluZyB8IG51bGw+KG51bGwpXG4gIGNvbnN0IGF1dGhBYm9ydENvbnRyb2xsZXJSZWYgPSB1c2VSZWY8QWJvcnRDb250cm9sbGVyIHwgbnVsbD4obnVsbClcblxuICAvLyBBYm9ydCBPQXV0aCBmbG93IG9uIHVubW91bnQgc28gdGhlIGNhbGxiYWNrIHNlcnZlciBpcyBjbG9zZWQgZXZlbiBpZiBhXG4gIC8vIHBhcmVudCBjb21wb25lbnQncyBFc2MgaGFuZGxlciBuYXZpZ2F0ZXMgYXdheSBiZWZvcmUgb3VycyBmaXJlcy5cbiAgdXNlRWZmZWN0KCgpID0+ICgpID0+IGF1dGhBYm9ydENvbnRyb2xsZXJSZWYuY3VycmVudD8uYWJvcnQoKSwgW10pXG5cbiAgLy8gSGFuZGxlIEVTQyB0byBjYW5jZWwgYXV0aGVudGljYXRpb24gZmxvd1xuICBjb25zdCBoYW5kbGVFc2NDYW5jZWwgPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgaWYgKGlzQXV0aGVudGljYXRpbmcpIHtcbiAgICAgIGF1dGhBYm9ydENvbnRyb2xsZXJSZWYuY3VycmVudD8uYWJvcnQoKVxuICAgICAgYXV0aEFib3J0Q29udHJvbGxlclJlZi5jdXJyZW50ID0gbnVsbFxuICAgICAgc2V0SXNBdXRoZW50aWNhdGluZyhmYWxzZSlcbiAgICAgIHNldEF1dGhvcml6YXRpb25VcmwobnVsbClcbiAgICB9XG4gIH0sIFtpc0F1dGhlbnRpY2F0aW5nXSlcblxuICB1c2VLZXliaW5kaW5nKCdjb25maXJtOm5vJywgaGFuZGxlRXNjQ2FuY2VsLCB7XG4gICAgY29udGV4dDogJ0NvbmZpcm1hdGlvbicsXG4gICAgaXNBY3RpdmU6IGlzQXV0aGVudGljYXRpbmcsXG4gIH0pXG5cbiAgY29uc3QgaGFuZGxlQXV0aGVudGljYXRlID0gdXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIGlmICghYWdlbnRTZXJ2ZXIubmVlZHNBdXRoIHx8ICFhZ2VudFNlcnZlci51cmwpIHtcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHNldElzQXV0aGVudGljYXRpbmcodHJ1ZSlcbiAgICBzZXRFcnJvcihudWxsKVxuXG4gICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKVxuICAgIGF1dGhBYm9ydENvbnRyb2xsZXJSZWYuY3VycmVudCA9IGNvbnRyb2xsZXJcblxuICAgIHRyeSB7XG4gICAgICAvLyBDcmVhdGUgYSB0ZW1wb3J Line truncated
+504
View File
@@ -0,0 +1,504 @@
import { c as _c } from "react/compiler-runtime";
import figures from 'figures';
import React, { useCallback, useState } from 'react';
import type { CommandResultDisplay } from '../../commands.js';
import { Box, color, Link, Text, useTheme } from '../../ink.js';
import { useKeybindings } from '../../keybindings/useKeybinding.js';
import type { ConfigScope } from '../../services/mcp/types.js';
import { describeMcpConfigFilePath } from '../../services/mcp/utils.js';
import { isDebugMode } from '../../utils/debug.js';
import { plural } from '../../utils/stringUtils.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Byline } from '../design-system/Byline.js';
import { Dialog } from '../design-system/Dialog.js';
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js';
import { McpParsingWarnings } from './McpParsingWarnings.js';
import type { AgentMcpServerInfo, ServerInfo } from './types.js';
type Props = {
servers: ServerInfo[];
agentServers?: AgentMcpServerInfo[];
onSelectServer: (server: ServerInfo) => void;
onSelectAgentServer?: (agentServer: AgentMcpServerInfo) => void;
onComplete: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
defaultTab?: string;
};
type SelectableItem = {
type: 'server';
server: ServerInfo;
} | {
type: 'agent-server';
agentServer: AgentMcpServerInfo;
};
// Define scope order for display (constant, outside component)
// 'dynamic' (built-in) is rendered separately at the end
const SCOPE_ORDER: ConfigScope[] = ['project', 'local', 'user', 'enterprise'];
// Get scope heading parts (label is bold, path is grey)
function getScopeHeading(scope: ConfigScope): {
label: string;
path?: string;
} {
switch (scope) {
case 'project':
return {
label: 'Project MCPs',
path: describeMcpConfigFilePath(scope)
};
case 'user':
return {
label: 'User MCPs',
path: describeMcpConfigFilePath(scope)
};
case 'local':
return {
label: 'Local MCPs',
path: describeMcpConfigFilePath(scope)
};
case 'enterprise':
return {
label: 'Enterprise MCPs'
};
case 'dynamic':
return {
label: 'Built-in MCPs',
path: 'always available'
};
default:
return {
label: scope
};
}
}
// Group servers by scope
function groupServersByScope(serverList: ServerInfo[]): Map<ConfigScope, ServerInfo[]> {
const groups = new Map<ConfigScope, ServerInfo[]>();
for (const server of serverList) {
const scope = server.scope;
if (!groups.has(scope)) {
groups.set(scope, []);
}
groups.get(scope)!.push(server);
}
// Sort servers within each group alphabetically
for (const [, groupServers] of groups) {
groupServers.sort((a, b) => a.name.localeCompare(b.name));
}
return groups;
}
export function MCPListPanel(t0) {
const $ = _c(78);
const {
servers,
agentServers: t1,
onSelectServer,
onSelectAgentServer,
onComplete
} = t0;
let t2;
if ($[0] !== t1) {
t2 = t1 === undefined ? [] : t1;
$[0] = t1;
$[1] = t2;
} else {
t2 = $[1];
}
const agentServers = t2;
const [theme] = useTheme();
const [selectedIndex, setSelectedIndex] = useState(0);
let t3;
if ($[2] !== servers) {
const regularServers = servers.filter(_temp);
t3 = groupServersByScope(regularServers);
$[2] = servers;
$[3] = t3;
} else {
t3 = $[3];
}
const serversByScope = t3;
let t4;
if ($[4] !== servers) {
t4 = servers.filter(_temp2).sort(_temp3);
$[4] = servers;
$[5] = t4;
} else {
t4 = $[5];
}
const claudeAiServers = t4;
let t5;
if ($[6] !== serversByScope) {
t5 = (serversByScope.get("dynamic") ?? []).sort(_temp4);
$[6] = serversByScope;
$[7] = t5;
} else {
t5 = $[7];
}
const dynamicServers = t5;
let t6;
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
t6 = getScopeHeading("dynamic");
$[8] = t6;
} else {
t6 = $[8];
}
const dynamicHeading = t6;
let items;
if ($[9] !== agentServers || $[10] !== claudeAiServers || $[11] !== dynamicServers || $[12] !== serversByScope) {
items = [];
for (const scope of SCOPE_ORDER) {
const scopeServers = serversByScope.get(scope) ?? [];
for (const server of scopeServers) {
items.push({
type: "server",
server
});
}
}
for (const server_0 of claudeAiServers) {
items.push({
type: "server",
server: server_0
});
}
for (const agentServer of agentServers) {
items.push({
type: "agent-server",
agentServer
});
}
for (const server_1 of dynamicServers) {
items.push({
type: "server",
server: server_1
});
}
$[9] = agentServers;
$[10] = claudeAiServers;
$[11] = dynamicServers;
$[12] = serversByScope;
$[13] = items;
} else {
items = $[13];
}
const selectableItems = items;
let t7;
if ($[14] !== onComplete) {
t7 = () => {
onComplete("MCP dialog dismissed", {
display: "system"
});
};
$[14] = onComplete;
$[15] = t7;
} else {
t7 = $[15];
}
const handleCancel = t7;
let t8;
if ($[16] !== onSelectAgentServer || $[17] !== onSelectServer || $[18] !== selectableItems || $[19] !== selectedIndex) {
t8 = () => {
const item = selectableItems[selectedIndex];
if (!item) {
return;
}
if (item.type === "server") {
onSelectServer(item.server);
} else {
if (item.type === "agent-server" && onSelectAgentServer) {
onSelectAgentServer(item.agentServer);
}
}
};
$[16] = onSelectAgentServer;
$[17] = onSelectServer;
$[18] = selectableItems;
$[19] = selectedIndex;
$[20] = t8;
} else {
t8 = $[20];
}
const handleSelect = t8;
let t10;
let t9;
if ($[21] !== selectableItems) {
t9 = () => setSelectedIndex(prev => prev === 0 ? selectableItems.length - 1 : prev - 1);
t10 = () => setSelectedIndex(prev_0 => prev_0 === selectableItems.length - 1 ? 0 : prev_0 + 1);
$[21] = selectableItems;
$[22] = t10;
$[23] = t9;
} else {
t10 = $[22];
t9 = $[23];
}
let t11;
if ($[24] !== handleCancel || $[25] !== handleSelect || $[26] !== t10 || $[27] !== t9) {
t11 = {
"confirm:previous": t9,
"confirm:next": t10,
"confirm:yes": handleSelect,
"confirm:no": handleCancel
};
$[24] = handleCancel;
$[25] = handleSelect;
$[26] = t10;
$[27] = t9;
$[28] = t11;
} else {
t11 = $[28];
}
let t12;
if ($[29] === Symbol.for("react.memo_cache_sentinel")) {
t12 = {
context: "Confirmation"
};
$[29] = t12;
} else {
t12 = $[29];
}
useKeybindings(t11, t12);
let t13;
if ($[30] !== selectableItems) {
t13 = server_2 => selectableItems.findIndex(item_0 => item_0.type === "server" && item_0.server === server_2);
$[30] = selectableItems;
$[31] = t13;
} else {
t13 = $[31];
}
const getServerIndex = t13;
let t14;
if ($[32] !== selectableItems) {
t14 = agentServer_0 => selectableItems.findIndex(item_1 => item_1.type === "agent-server" && item_1.agentServer === agentServer_0);
$[32] = selectableItems;
$[33] = t14;
} else {
t14 = $[33];
}
const getAgentServerIndex = t14;
let t15;
if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
t15 = isDebugMode();
$[34] = t15;
} else {
t15 = $[34];
}
const debugMode = t15;
let t16;
if ($[35] !== servers) {
t16 = servers.some(_temp5);
$[35] = servers;
$[36] = t16;
} else {
t16 = $[36];
}
const hasFailedClients = t16;
if (servers.length === 0 && agentServers.length === 0) {
return null;
}
let t17;
if ($[37] !== getServerIndex || $[38] !== selectedIndex || $[39] !== theme) {
t17 = server_3 => {
const index = getServerIndex(server_3);
const isSelected = selectedIndex === index;
let statusIcon;
let statusText;
if (server_3.client.type === "disabled") {
statusIcon = color("inactive", theme)(figures.radioOff);
statusText = "disabled";
} else {
if (server_3.client.type === "connected") {
statusIcon = color("success", theme)(figures.tick);
statusText = "connected";
} else {
if (server_3.client.type === "pending") {
statusIcon = color("inactive", theme)(figures.radioOff);
const {
reconnectAttempt,
maxReconnectAttempts
} = server_3.client;
if (reconnectAttempt && maxReconnectAttempts) {
statusText = `reconnecting (${reconnectAttempt}/${maxReconnectAttempts})…`;
} else {
statusText = "connecting\u2026";
}
} else {
if (server_3.client.type === "needs-auth") {
statusIcon = color("warning", theme)(figures.triangleUpOutline);
statusText = "needs authentication";
} else {
statusIcon = color("error", theme)(figures.cross);
statusText = "failed";
}
}
}
}
return <Box key={`${server_3.name}-${index}`}><Text color={isSelected ? "suggestion" : undefined}>{isSelected ? `${figures.pointer} ` : " "}</Text><Text color={isSelected ? "suggestion" : undefined}>{server_3.name}</Text><Text dimColor={!isSelected}> · {statusIcon} </Text><Text dimColor={!isSelected}>{statusText}</Text></Box>;
};
$[37] = getServerIndex;
$[38] = selectedIndex;
$[39] = theme;
$[40] = t17;
} else {
t17 = $[40];
}
const renderServerItem = t17;
let t18;
if ($[41] !== getAgentServerIndex || $[42] !== selectedIndex || $[43] !== theme) {
t18 = agentServer_1 => {
const index_0 = getAgentServerIndex(agentServer_1);
const isSelected_0 = selectedIndex === index_0;
const statusIcon_0 = agentServer_1.needsAuth ? color("warning", theme)(figures.triangleUpOutline) : color("inactive", theme)(figures.radioOff);
const statusText_0 = agentServer_1.needsAuth ? "may need auth" : "agent-only";
return <Box key={`agent-${agentServer_1.name}-${index_0}`}><Text color={isSelected_0 ? "suggestion" : undefined}>{isSelected_0 ? `${figures.pointer} ` : " "}</Text><Text color={isSelected_0 ? "suggestion" : undefined}>{agentServer_1.name}</Text><Text dimColor={!isSelected_0}> · {statusIcon_0} </Text><Text dimColor={!isSelected_0}>{statusText_0}</Text></Box>;
};
$[41] = getAgentServerIndex;
$[42] = selectedIndex;
$[43] = theme;
$[44] = t18;
} else {
t18 = $[44];
}
const renderAgentServerItem = t18;
const totalServers = servers.length + agentServers.length;
let t19;
if ($[45] === Symbol.for("react.memo_cache_sentinel")) {
t19 = <McpParsingWarnings />;
$[45] = t19;
} else {
t19 = $[45];
}
let t20;
if ($[46] !== totalServers) {
t20 = plural(totalServers, "server");
$[46] = totalServers;
$[47] = t20;
} else {
t20 = $[47];
}
const t21 = `${totalServers} ${t20}`;
let t22;
if ($[48] !== renderServerItem || $[49] !== serversByScope) {
t22 = SCOPE_ORDER.map(scope_0 => {
const scopeServers_0 = serversByScope.get(scope_0);
if (!scopeServers_0 || scopeServers_0.length === 0) {
return null;
}
const heading = getScopeHeading(scope_0);
return <Box key={scope_0} flexDirection="column" marginBottom={1}><Box paddingLeft={2}><Text bold={true}>{heading.label}</Text>{heading.path && <Text dimColor={true}> ({heading.path})</Text>}</Box>{scopeServers_0.map(server_4 => renderServerItem(server_4))}</Box>;
});
$[48] = renderServerItem;
$[49] = serversByScope;
$[50] = t22;
} else {
t22 = $[50];
}
let t23;
if ($[51] !== claudeAiServers || $[52] !== renderServerItem) {
t23 = claudeAiServers.length > 0 && <Box flexDirection="column" marginBottom={1}><Box paddingLeft={2}><Text bold={true}>claude.ai</Text></Box>{claudeAiServers.map(server_5 => renderServerItem(server_5))}</Box>;
$[51] = claudeAiServers;
$[52] = renderServerItem;
$[53] = t23;
} else {
t23 = $[53];
}
let t24;
if ($[54] !== agentServers || $[55] !== renderAgentServerItem) {
t24 = agentServers.length > 0 && <Box flexDirection="column" marginBottom={1}><Box paddingLeft={2}><Text bold={true}>Agent MCPs</Text></Box>{[...new Set(agentServers.flatMap(_temp6))].map(agentName => <Box key={agentName} flexDirection="column" marginTop={1}><Box paddingLeft={2}><Text dimColor={true}>@{agentName}</Text></Box>{agentServers.filter(s_3 => s_3.sourceAgents.includes(agentName)).map(agentServer_2 => renderAgentServerItem(agentServer_2))}</Box>)}</Box>;
$[54] = agentServers;
$[55] = renderAgentServerItem;
$[56] = t24;
} else {
t24 = $[56];
}
let t25;
if ($[57] !== dynamicServers || $[58] !== renderServerItem) {
t25 = dynamicServers.length > 0 && <Box flexDirection="column" marginBottom={1}><Box paddingLeft={2}><Text bold={true}>{dynamicHeading.label}</Text>{dynamicHeading.path && <Text dimColor={true}> ({dynamicHeading.path})</Text>}</Box>{dynamicServers.map(server_6 => renderServerItem(server_6))}</Box>;
$[57] = dynamicServers;
$[58] = renderServerItem;
$[59] = t25;
} else {
t25 = $[59];
}
let t26;
if ($[60] !== hasFailedClients) {
t26 = hasFailedClients && <Text dimColor={true}>{debugMode ? "\u203B Error logs shown inline with --debug" : "\u203B Run claude --debug to see error logs"}</Text>;
$[60] = hasFailedClients;
$[61] = t26;
} else {
t26 = $[61];
}
let t27;
if ($[62] === Symbol.for("react.memo_cache_sentinel")) {
t27 = <Text dimColor={true}><Link url="https://code.claude.com/docs/en/mcp">https://code.claude.com/docs/en/mcp</Link>{" "}for help</Text>;
$[62] = t27;
} else {
t27 = $[62];
}
let t28;
if ($[63] !== t26) {
t28 = <Box flexDirection="column">{t26}{t27}</Box>;
$[63] = t26;
$[64] = t28;
} else {
t28 = $[64];
}
let t29;
if ($[65] !== t22 || $[66] !== t23 || $[67] !== t24 || $[68] !== t25 || $[69] !== t28) {
t29 = <Box flexDirection="column">{t22}{t23}{t24}{t25}{t28}</Box>;
$[65] = t22;
$[66] = t23;
$[67] = t24;
$[68] = t25;
$[69] = t28;
$[70] = t29;
} else {
t29 = $[70];
}
let t30;
if ($[71] !== handleCancel || $[72] !== t21 || $[73] !== t29) {
t30 = <Dialog title="Manage MCP servers" subtitle={t21} onCancel={handleCancel} hideInputGuide={true}>{t29}</Dialog>;
$[71] = handleCancel;
$[72] = t21;
$[73] = t29;
$[74] = t30;
} else {
t30 = $[74];
}
let t31;
if ($[75] === Symbol.for("react.memo_cache_sentinel")) {
t31 = <Box paddingX={1}><Text dimColor={true} italic={true}><Byline><KeyboardShortcutHint shortcut={"\u2191\u2193"} action="navigate" /><KeyboardShortcutHint shortcut="Enter" action="confirm" /><ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="cancel" /></Byline></Text></Box>;
$[75] = t31;
} else {
t31 = $[75];
}
let t32;
if ($[76] !== t30) {
t32 = <Box flexDirection="column">{t19}{t30}{t31}</Box>;
$[76] = t30;
$[77] = t32;
} else {
t32 = $[77];
}
return t32;
}
function _temp6(s_2) {
return s_2.sourceAgents;
}
function _temp5(s_1) {
return s_1.client.type === "failed";
}
function _temp4(a_0, b_0) {
return a_0.name.localeCompare(b_0.name);
}
function _temp3(a, b) {
return a.name.localeCompare(b.name);
}
function _temp2(s_0) {
return s_0.client.config.type === "claudeai-proxy";
}
function _temp(s) {
return s.client.config.type !== "claudeai-proxy";
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJ1c2VDYWxsYmFjayIsInVzZVN0YXRlIiwiQ29tbWFuZFJlc3VsdERpc3BsYXkiLCJCb3giLCJjb2xvciIsIkxpbmsiLCJUZXh0IiwidXNlVGhlbWUiLCJ1c2VLZXliaW5kaW5ncyIsIkNvbmZpZ1Njb3BlIiwiZGVzY3JpYmVNY3BDb25maWdGaWxlUGF0aCIsImlzRGVidWdNb2RlIiwicGx1cmFsIiwiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IiwiQnlsaW5lIiwiRGlhbG9nIiwiS2V5Ym9hcmRTaG9ydGN1dEhpbnQiLCJNY3BQYXJzaW5nV2FybmluZ3MiLCJBZ2VudE1jcFNlcnZlckluZm8iLCJTZXJ2ZXJJbmZvIiwiUHJvcHMiLCJzZXJ2ZXJzIiwiYWdlbnRTZXJ2ZXJzIiwib25TZWxlY3RTZXJ2ZXIiLCJzZXJ2ZXIiLCJvblNlbGVjdEFnZW50U2VydmVyIiwiYWdlbnRTZXJ2ZXIiLCJvbkNvbXBsZXRlIiwicmVzdWx0Iiwib3B0aW9ucyIsImRpc3BsYXkiLCJkZWZhdWx0VGFiIiwiU2VsZWN0YWJsZUl0ZW0iLCJ0eXBlIiwiU0NPUEVfT1JERVIiLCJnZXRTY29wZUhlYWRpbmciLCJzY29wZSIsImxhYmVsIiwicGF0aCIsImdyb3VwU2VydmVyc0J5U2NvcGUiLCJzZXJ2ZXJMaXN0IiwiTWFwIiwiZ3JvdXBzIiwiaGFzIiwic2V0IiwiZ2V0IiwicHVzaCIsImdyb3VwU2VydmVycyIsInNvcnQiLCJhIiwiYiIsIm5hbWUiLCJsb2NhbGVDb21wYXJlIiwiTUNQTGlzdFBhbmVsIiwidDAiLCIkIiwiX2MiLCJ0MSIsInQyIiwidW5kZWZpbmVkIiwidGhlbWUiLCJzZWxlY3RlZEluZGV4Iiwic2V0U2VsZWN0ZWRJbmRleCIsInQzIiwicmVndWxhclNlcnZlcnMiLCJmaWx0ZXIiLCJfdGVtcCIsInNlcnZlcnNCeVNjb3BlIiwidDQiLCJfdGVtcDIiLCJfdGVtcDMiLCJjbGF1ZGVBaVNlcnZlcnMiLCJ0NSIsIl90ZW1wNCIsImR5bmFtaWNTZXJ2ZXJzIiwidDYiLCJTeW1ib2wiLCJmb3IiLCJkeW5hbWljSGVhZGluZyIsIml0ZW1zIiwic2NvcGVTZXJ2ZXJzIiwic2VydmVyXzAiLCJzZXJ2ZXJfMSIsInNlbGVjdGFibGVJdGVtcyIsInQ3IiwiaGFuZGxlQ2FuY2VsIiwidDgiLCJpdGVtIiwiaGFuZGxlU2VsZWN0IiwidDEwIiwidDkiLCJwcmV2IiwibGVuZ3RoIiwicHJldl8wIiwidDExIiwidDEyIiwiY29udGV4dCIsInQxMyIsInNlcnZlcl8yIiwiZmluZEluZGV4IiwiaXRlbV8wIiwiZ2V0U2VydmVySW5kZXgiLCJ0MTQiLCJhZ2VudFNlcnZlcl8wIiwiaXRlbV8xIiwiZ2V0QWdlbnRTZXJ2ZXJJbmRleCIsInQxNSIsImRlYnVnTW9kZSIsInQxNiIsInNvbWUiLCJfdGVtcDUiLCJoYXNGYWlsZWRDbGllbnRzIiwidDE3Iiwic2VydmVyXzMiLCJpbmRleCIsImlzU2VsZWN0ZWQiLCJzdGF0dXNJY29uIiwic3RhdHVzVGV4dCIsImNsaWVudCIsInJhZGlvT2ZmIiwidGljayIsInJlY29ubmVjdEF0dGVtcHQiLCJtYXhSZWNvbm5lY3RBdHRlbXB0cyIsInRyaWFuZ2xlVXBPdXRsaW5lIiwiY3Jvc3MiLCJwb2ludGVyIiwicmVuZGVyU2VydmVySXRlbSIsInQxOCIsImFnZW50U2VydmVyXzEiLCJpbmRleF8wIiwiaXNTZWxlY3RlZF8wIiwic3RhdHVzSWNvbl8wIiwibmVlZHNBdXRoIiwic3RhdHVzVGV4dF8wIiwicmVuZGVyQWdlbnRTZXJ2ZXJJdGVtIiwidG90YWxTZXJ2ZXJzIiwidDE5IiwidDIwIiwidDIxIiwidDIyIiwibWFwIiwic2NvcGVfMCIsInNjb3BlU2VydmVyc18wIiwiaGVhZGluZyIsInNlcnZlcl80IiwidDIzIiwic2VydmVyXzUiLCJ0MjQiLCJTZXQiLCJmbGF0TWFwIiwiX3RlbXA2IiwiYWdlbnROYW1lIiwic18zIiwicyIsInNvdXJjZUFnZW50cyIsImluY2x1ZGVzIiwiYWdlbnRTZXJ2ZXJfMiIsInQyNSIsInNlcnZlcl82IiwidDI2IiwidDI3IiwidDI4IiwidDI5IiwidDMwIiwidDMxIiwidDMyIiwic18yIiwic18xIiwiYV8wIiwiYl8wIiwic18wIiwiY29uZmlnIl0sInNvdXJjZXMiOlsiTUNQTGlzdFBhbmVsLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZmlndXJlcyBmcm9tICdmaWd1cmVzJ1xuaW1wb3J0IFJlYWN0LCB7IHVzZUNhbGxiYWNrLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHR5cGUgeyBDb21tYW5kUmVzdWx0RGlzcGxheSB9IGZyb20gJy4uLy4uL2NvbW1hbmRzLmpzJ1xuaW1wb3J0IHsgQm94LCBjb2xvciwgTGluaywgVGV4dCwgdXNlVGhlbWUgfSBmcm9tICcuLi8uLi9pbmsuanMnXG5pbXBvcnQgeyB1c2VLZXliaW5kaW5ncyB9IGZyb20gJy4uLy4uL2tleWJpbmRpbmdzL3VzZUtleWJpbmRpbmcuanMnXG5pbXBvcnQgdHlwZSB7IENvbmZpZ1Njb3BlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvbWNwL3R5cGVzLmpzJ1xuaW1wb3J0IHsgZGVzY3JpYmVNY3BDb25maWdGaWxlUGF0aCB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL21jcC91dGlscy5qcydcbmltcG9ydCB7IGlzRGVidWdNb2RlIH0gZnJvbSAnLi4vLi4vdXRpbHMvZGVidWcuanMnXG5pbXBvcnQgeyBwbHVyYWwgfSBmcm9tICcuLi8uLi91dGlscy9zdHJpbmdVdGlscy5qcydcbmltcG9ydCB7IENvbmZpZ3VyYWJsZVNob3J0Y3V0SGludCB9IGZyb20gJy4uL0NvbmZpZ3VyYWJsZVNob3J0Y3V0SGludC5qcydcbmltcG9ydCB7IEJ5bGluZSB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vQnlsaW5lLmpzJ1xuaW1wb3J0IHsgRGlhbG9nIH0gZnJvbSAnLi4vZGVzaWduLXN5c3RlbS9EaWFsb2cuanMnXG5pbXBvcnQgeyBLZXlib2FyZFNob3J0Y3V0SGludCB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vS2V5Ym9hcmRTaG9ydGN1dEhpbnQuanMnXG5pbXBvcnQgeyBNY3BQYXJzaW5nV2FybmluZ3MgfSBmcm9tICcuL01jcFBhcnNpbmdXYXJuaW5ncy5qcydcbmltcG9ydCB0eXBlIHsgQWdlbnRNY3BTZXJ2ZXJJbmZvLCBTZXJ2ZXJJbmZvIH0gZnJvbSAnLi90eXBlcy5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgc2VydmVyczogU2VydmVySW5mb1tdXG4gIGFnZW50U2VydmVycz86IEFnZW50TWNwU2VydmVySW5mb1tdXG4gIG9uU2VsZWN0U2VydmVyOiAoc2VydmVyOiBTZXJ2ZXJJbmZvKSA9PiB2b2lkXG4gIG9uU2VsZWN0QWdlbnRTZXJ2ZXI/OiAoYWdlbnRTZXJ2ZXI6IEFnZW50TWNwU2VydmVySW5mbykgPT4gdm9pZFxuICBvbkNvbXBsZXRlOiAoXG4gICAgcmVzdWx0Pzogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGRpc3BsYXk/OiBDb21tYW5kUmVzdWx0RGlzcGxheSB9LFxuICApID0+IHZvaWRcbiAgZGVmYXVsdFRhYj86IHN0cmluZ1xufVxuXG50eXBlIFNlbGVjdGFibGVJdGVtID1cbiAgfCB7IHR5cGU6ICdzZXJ2ZXInOyBzZXJ2ZXI6IFNlcnZlckluZm8gfVxuICB8IHsgdHlwZTogJ2FnZW50LXNlcnZlcic7IGFnZW50U2VydmVyOiBBZ2VudE1jcFNlcnZlckluZm8gfVxuXG4vLyBEZWZpbmUgc2NvcGUgb3JkZXIgZm9yIGRpc3BsYXkgKGNvbnN0YW50LCBvdXRzaWRlIGNvbXBvbmVudClcbi8vICdkeW5hbWljJyAoYnVpbHQtaW4pIGlzIHJlbmRlcmVkIHNlcGFyYXRlbHkgYXQgdGhlIGVuZFxuY29uc3QgU0NPUEVfT1JERVI6IENvbmZpZ1Njb3BlW10gPSBbJ3Byb2plY3QnLCAnbG9jYWwnLCAndXNlcicsICdlbnRlcnByaXNlJ11cblxuLy8gR2V0IHNjb3BlIGhlYWRpbmcgcGFydHMgKGxhYmVsIGlzIGJvbGQsIHBhdGggaXMgZ3JleSlcbmZ1bmN0aW9uIGdldFNjb3BlSGVhZGluZyhzY29wZTogQ29uZmlnU2NvcGUpOiB7IGxhYmVsOiBzdHJpbmc7IHBhdGg/OiBzdHJpbmcgfSB7XG4gIHN3aXRjaCAoc2NvcGUpIHtcbiAgICBjYXNlICdwcm9qZWN0JzpcbiA Line truncated
+167
View File
@@ -0,0 +1,167 @@
import { c as _c } from "react/compiler-runtime";
import figures from 'figures';
import React, { useEffect, useState } from 'react';
import type { CommandResultDisplay } from '../../commands.js';
import { Box, color, Text, useTheme } from '../../ink.js';
import { useMcpReconnect } from '../../services/mcp/MCPConnectionManager.js';
import { useAppStateStore } from '../../state/AppState.js';
import { Spinner } from '../Spinner.js';
type Props = {
serverName: string;
onComplete: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
};
export function MCPReconnect(t0) {
const $ = _c(25);
const {
serverName,
onComplete
} = t0;
const [theme] = useTheme();
const store = useAppStateStore();
const reconnectMcpServer = useMcpReconnect();
const [isReconnecting, setIsReconnecting] = useState(true);
const [error, setError] = useState(null);
let t1;
let t2;
if ($[0] !== onComplete || $[1] !== reconnectMcpServer || $[2] !== serverName || $[3] !== store) {
t1 = () => {
const attemptReconnect = async function attemptReconnect() {
;
try {
const server = store.getState().mcp.clients.find(c => c.name === serverName);
if (!server) {
setError(`MCP server "${serverName}" not found`);
setIsReconnecting(false);
onComplete(`MCP server "${serverName}" not found`);
return;
}
const result = await reconnectMcpServer(serverName);
bb43: switch (result.client.type) {
case "connected":
{
setIsReconnecting(false);
onComplete(`Successfully reconnected to ${serverName}`);
break bb43;
}
case "needs-auth":
{
setError(`${serverName} requires authentication`);
setIsReconnecting(false);
onComplete(`${serverName} requires authentication. Use /mcp to authenticate.`);
break bb43;
}
case "pending":
case "failed":
case "disabled":
{
setError(`Failed to reconnect to ${serverName}`);
setIsReconnecting(false);
onComplete(`Failed to reconnect to ${serverName}`);
}
}
} catch (t3) {
const err = t3;
const errorMessage = err instanceof Error ? err.message : String(err);
setError(errorMessage);
setIsReconnecting(false);
onComplete(`Error: ${errorMessage}`);
}
};
attemptReconnect();
};
t2 = [serverName, reconnectMcpServer, store, onComplete];
$[0] = onComplete;
$[1] = reconnectMcpServer;
$[2] = serverName;
$[3] = store;
$[4] = t1;
$[5] = t2;
} else {
t1 = $[4];
t2 = $[5];
}
useEffect(t1, t2);
if (isReconnecting) {
let t3;
if ($[6] !== serverName) {
t3 = <Text color="text">Reconnecting to <Text bold={true}>{serverName}</Text></Text>;
$[6] = serverName;
$[7] = t3;
} else {
t3 = $[7];
}
let t4;
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
t4 = <Box><Spinner /><Text> Establishing connection to MCP server</Text></Box>;
$[8] = t4;
} else {
t4 = $[8];
}
let t5;
if ($[9] !== t3) {
t5 = <Box flexDirection="column" gap={1} padding={1}>{t3}{t4}</Box>;
$[9] = t3;
$[10] = t5;
} else {
t5 = $[10];
}
return t5;
}
if (error) {
let t3;
if ($[11] !== theme) {
t3 = color("error", theme)(figures.cross);
$[11] = theme;
$[12] = t3;
} else {
t3 = $[12];
}
let t4;
if ($[13] !== t3) {
t4 = <Text>{t3} </Text>;
$[13] = t3;
$[14] = t4;
} else {
t4 = $[14];
}
let t5;
if ($[15] !== serverName) {
t5 = <Text color="error">Failed to reconnect to {serverName}</Text>;
$[15] = serverName;
$[16] = t5;
} else {
t5 = $[16];
}
let t6;
if ($[17] !== t4 || $[18] !== t5) {
t6 = <Box>{t4}{t5}</Box>;
$[17] = t4;
$[18] = t5;
$[19] = t6;
} else {
t6 = $[19];
}
let t7;
if ($[20] !== error) {
t7 = <Text dimColor={true}>Error: {error}</Text>;
$[20] = error;
$[21] = t7;
} else {
t7 = $[21];
}
let t8;
if ($[22] !== t6 || $[23] !== t7) {
t8 = <Box flexDirection="column" gap={1} padding={1}>{t6}{t7}</Box>;
$[22] = t6;
$[23] = t7;
$[24] = t8;
} else {
t8 = $[24];
}
return t8;
}
return null;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJ1c2VFZmZlY3QiLCJ1c2VTdGF0ZSIsIkNvbW1hbmRSZXN1bHREaXNwbGF5IiwiQm94IiwiY29sb3IiLCJUZXh0IiwidXNlVGhlbWUiLCJ1c2VNY3BSZWNvbm5lY3QiLCJ1c2VBcHBTdGF0ZVN0b3JlIiwiU3Bpbm5lciIsIlByb3BzIiwic2VydmVyTmFtZSIsIm9uQ29tcGxldGUiLCJyZXN1bHQiLCJvcHRpb25zIiwiZGlzcGxheSIsIk1DUFJlY29ubmVjdCIsInQwIiwiJCIsIl9jIiwidGhlbWUiLCJzdG9yZSIsInJlY29ubmVjdE1jcFNlcnZlciIsImlzUmVjb25uZWN0aW5nIiwic2V0SXNSZWNvbm5lY3RpbmciLCJlcnJvciIsInNldEVycm9yIiwidDEiLCJ0MiIsImF0dGVtcHRSZWNvbm5lY3QiLCJzZXJ2ZXIiLCJnZXRTdGF0ZSIsIm1jcCIsImNsaWVudHMiLCJmaW5kIiwiYyIsIm5hbWUiLCJiYjQzIiwiY2xpZW50IiwidHlwZSIsInQzIiwiZXJyIiwiZXJyb3JNZXNzYWdlIiwiRXJyb3IiLCJtZXNzYWdlIiwiU3RyaW5nIiwidDQiLCJTeW1ib2wiLCJmb3IiLCJ0NSIsImNyb3NzIiwidDYiLCJ0NyIsInQ4Il0sInNvdXJjZXMiOlsiTUNQUmVjb25uZWN0LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZmlndXJlcyBmcm9tICdmaWd1cmVzJ1xuaW1wb3J0IFJlYWN0LCB7IHVzZUVmZmVjdCwgdXNlU3RhdGUgfSBmcm9tICdyZWFjdCdcbmltcG9ydCB0eXBlIHsgQ29tbWFuZFJlc3VsdERpc3BsYXkgfSBmcm9tICcuLi8uLi9jb21tYW5kcy5qcydcbmltcG9ydCB7IEJveCwgY29sb3IsIFRleHQsIHVzZVRoZW1lIH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuaW1wb3J0IHsgdXNlTWNwUmVjb25uZWN0IH0gZnJvbSAnLi4vLi4vc2VydmljZXMvbWNwL01DUENvbm5lY3Rpb25NYW5hZ2VyLmpzJ1xuaW1wb3J0IHsgdXNlQXBwU3RhdGVTdG9yZSB9IGZyb20gJy4uLy4uL3N0YXRlL0FwcFN0YXRlLmpzJ1xuaW1wb3J0IHsgU3Bpbm5lciB9IGZyb20gJy4uL1NwaW5uZXIuanMnXG5cbnR5cGUgUHJvcHMgPSB7XG4gIHNlcnZlck5hbWU6IHN0cmluZ1xuICBvbkNvbXBsZXRlOiAoXG4gICAgcmVzdWx0Pzogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGRpc3BsYXk/OiBDb21tYW5kUmVzdWx0RGlzcGxheSB9LFxuICApID0+IHZvaWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIE1DUFJlY29ubmVjdCh7XG4gIHNlcnZlck5hbWUsXG4gIG9uQ29tcGxldGUsXG59OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IFt0aGVtZV0gPSB1c2VUaGVtZSgpXG4gIGNvbnN0IHN0b3JlID0gdXNlQXBwU3RhdGVTdG9yZSgpXG4gIGNvbnN0IHJlY29ubmVjdE1jcFNlcnZlciA9IHVzZU1jcFJlY29ubmVjdCgpXG4gIGNvbnN0IFtpc1JlY29ubmVjdGluZywgc2V0SXNSZWNvbm5lY3RpbmddID0gdXNlU3RhdGUodHJ1ZSlcbiAgY29uc3QgW2Vycm9yLCBzZXRFcnJvcl0gPSB1c2VTdGF0ZTxzdHJpbmcgfCBudWxsPihudWxsKVxuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgYXN5bmMgZnVuY3Rpb24gYXR0ZW1wdFJlY29ubmVjdCgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIENoZWNrIGlmIHNlcnZlciBleGlzdHMuIFJlYWQgdmlhIHN0b3JlLmdldFN0YXRlKCkgaW5zdGVhZCBvZiBhXG4gICAgICAgIC8vIHJlYWN0aXZlIHNlbGVjdG9yIHNvIHRoaXMgZWZmZWN0IGRvZXMgbm90IHJlLWZpcmUgd2hlblxuICAgICAgICAvLyByZWNvbm5lY3RNY3BTZXJ2ZXIgdXBkYXRlcyBtY3AuY2xpZW50cyB2aWEgb25Db25uZWN0aW9uQXR0ZW1wdC5cbiAgICAgICAgY29uc3Qgc2VydmVyID0gc3RvcmVcbiAgICAgICAgICAuZ2V0U3RhdGUoKVxuICAgICAgICAgIC5tY3AuY2xpZW50cy5maW5kKGMgPT4gYy5uYW1lID09PSBzZXJ2ZXJOYW1lKVxuICAgICAgICBpZiAoIXNlcnZlcikge1xuICAgICAgICAgIHNldEVycm9yKGBNQ1Agc2VydmVyIFwiJHtzZXJ2ZXJOYW1lfVwiIG5vdCBmb3VuZGApXG4gICAgICAgICAgc2V0SXNSZWNvbm5lY3RpbmcoZmFsc2UpXG4gICAgICAgICAgb25Db21wbGV0ZShgTUNQIHNlcnZlciBcIiR7c2VydmVyTmFtZX1cIiBub3QgZm91bmRgKVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgLy8gQXR0ZW1wdCByZWNvbm5lY3Rpb25cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcmVjb25uZWN0TWNwU2VydmVyKHNlcnZlck5hbWUpXG5cbiAgICAgICAgc3dpdGNoIChyZXN1bHQuY2xpZW50LnR5cGUpIHtcbiAgICAgICAgICBjYXNlICdjb25uZWN0ZWQnOlxuICAgICAgICAgICAgc2V0SXNSZWNvbm5lY3RpbmcoZmFsc2UpXG4gICAgICAgICAgICBvbkNvbXBsZXRlKGBTdWNjZXNzZnVsbHkgcmVjb25uZWN0ZWQgdG8gJHtzZXJ2ZXJOYW1lfWApXG4gICAgICAgICAgICBicmVha1xuICAgICAgICAgIGNhc2UgJ25lZWRzLWF1dGgnOlxuICAgICAgICAgICAgc2V0RXJyb3IoYCR7c2VydmVyTmFtZX0gcmVxdWlyZXMgYXV0aGVudGljYXRpb25gKVxuICAgICAgICAgICAgc2V0SXNSZWNvbm5lY3RpbmcoZmFsc2UpXG4gICAgICAgICAgICBvbkNvbXBsZXRlKFxuICAgICAgICAgICAgICBgJHtzZXJ2ZXJOYW1lfSByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gVXNlIC9tY3AgdG8gYXV0aGVudGljYXRlLmAsXG4gICAgICAgICAgICApXG4gICAgICAgICAgICBicmVha1xuICAgICAgICAgIGNhc2UgJ3BlbmRpbmcnOlxuICAgICAgICAgIGNhc2UgJ2ZhaWxlZCc6XG4gICAgICAgICAgY2FzZSAnZGlzYWJsZWQnOlxuICAgICAgICAgICAgc2V0RXJyb3IoYEZhaWxlZCB0byByZWNvbm5lY3QgdG8gJHtzZXJ2ZXJOYW1lfWApXG4gICAgICAgICAgICBzZXRJc1JlY29ubmVjdGluZyhmYWxzZSlcbiAgICAgICAgICAgIG9uQ29tcGxldGUoYEZhaWxlZCB0byByZWNvbm5lY3QgdG8gJHtzZXJ2ZXJOYW1lfWApXG4gICAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8gT25seSBjYXRjaCBhY3R1YWwgZXJyb3JzIChsaWtlIHNlcnZlciBub3QgZm91bmQpXG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKVxuICAgICAgICBzZXRFcnJvcihlcnJvck1lc3NhZ2UpXG4gICAgICAgIHNldElzUmVjb25uZWN0aW5nKGZhbHNlKVxuICAgICAgICBvbkNvbXBsZXRlKGBFcnJvcjogJHtlcnJvck1lc3NhZ2V9YClcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2b2lkIGF0dGVtcHRSZWNvbm5lY3QoKVxuICB9LCBbc2VydmVyTmFtZSwgcmVjb25uZWN0TWNwU2VydmVyLCBzdG9yZSwgb25Db21wbGV0ZV0pXG5cbiAgaWYgKGlzUmVjb25uZWN0aW5nKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiIGdhcD17MX0gcGFkZGluZz17MX0+XG4gICAgICAgIDxUZXh0IGNvbG9yPVwidGV4dFwiPlxuICAgICAgICAgIFJlY29ubmVjdGluZyB0byA8VGV4dCBib2xkPntzZXJ2ZXJOYW1lfTwvVGV4dD5cbiAgICAgICAgPC9UZXh0PlxuICAgICAgICA8Qm94PlxuICAgICAgICAgIDxTcGlubmVyIC8+XG4gICAgICAgICAgPFRleHQ+IEVzdGFibGlzaGluZyBjb25uZWN0aW9uIHRvIE1DUCBzZXJ2ZXI8L1RleHQ+XG4gICAgICAgIDwvQm94PlxuICAgICAgPC9Cb3g+XG4gICAgKVxuICB9XG5cbiAgaWYgKGVycm9yKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxCb3ggZmx Line truncated
+649
View File
@@ -0,0 +1,649 @@
import figures from 'figures';
import React, { useEffect, useRef, useState } from 'react';
import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent } from 'src/services/analytics/index.js';
import type { CommandResultDisplay } from '../../commands.js';
import { getOauthConfig } from '../../constants/oauth.js';
import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithKeybindings.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import { setClipboard } from '../../ink/termio/osc.js';
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- raw j/k/arrow menu navigation
import { Box, color, Link, Text, useInput, useTheme } from '../../ink.js';
import { useKeybinding } from '../../keybindings/useKeybinding.js';
import { AuthenticationCancelledError, performMCPOAuthFlow, revokeServerTokens } from '../../services/mcp/auth.js';
import { clearServerCache } from '../../services/mcp/client.js';
import { useMcpReconnect, useMcpToggleEnabled } from '../../services/mcp/MCPConnectionManager.js';
import { describeMcpConfigFilePath, excludeCommandsByServer, excludeResourcesByServer, excludeToolsByServer, filterMcpPromptsByServer } from '../../services/mcp/utils.js';
import { useAppState, useSetAppState } from '../../state/AppState.js';
import { getOauthAccountInfo } from '../../utils/auth.js';
import { openBrowser } from '../../utils/browser.js';
import { errorMessage } from '../../utils/errors.js';
import { logMCPDebug } from '../../utils/log.js';
import { capitalize } from '../../utils/stringUtils.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Select } from '../CustomSelect/index.js';
import { Byline } from '../design-system/Byline.js';
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js';
import { Spinner } from '../Spinner.js';
import TextInput from '../TextInput.js';
import { CapabilitiesSection } from './CapabilitiesSection.js';
import type { ClaudeAIServerInfo, HTTPServerInfo, SSEServerInfo } from './types.js';
import { handleReconnectError, handleReconnectResult } from './utils/reconnectHelpers.js';
type Props = {
server: SSEServerInfo | HTTPServerInfo | ClaudeAIServerInfo;
serverToolsCount: number;
onViewTools: () => void;
onCancel: () => void;
onComplete?: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
borderless?: boolean;
};
export function MCPRemoteServerMenu({
server,
serverToolsCount,
onViewTools,
onCancel,
onComplete,
borderless = false
}: Props): React.ReactNode {
const [theme] = useTheme();
const exitState = useExitOnCtrlCDWithKeybindings();
const {
columns: terminalColumns
} = useTerminalSize();
const [isAuthenticating, setIsAuthenticating] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
const mcp = useAppState(s => s.mcp);
const setAppState = useSetAppState();
const [authorizationUrl, setAuthorizationUrl] = React.useState<string | null>(null);
const [isReconnecting, setIsReconnecting] = useState(false);
const authAbortControllerRef = useRef<AbortController | null>(null);
const [isClaudeAIAuthenticating, setIsClaudeAIAuthenticating] = useState(false);
const [claudeAIAuthUrl, setClaudeAIAuthUrl] = useState<string | null>(null);
const [isClaudeAIClearingAuth, setIsClaudeAIClearingAuth] = useState(false);
const [claudeAIClearAuthUrl, setClaudeAIClearAuthUrl] = useState<string | null>(null);
const [claudeAIClearAuthBrowserOpened, setClaudeAIClearAuthBrowserOpened] = useState(false);
const [urlCopied, setUrlCopied] = useState(false);
const copyTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
const unmountedRef = useRef(false);
const [callbackUrlInput, setCallbackUrlInput] = useState('');
const [callbackUrlCursorOffset, setCallbackUrlCursorOffset] = useState(0);
const [manualCallbackSubmit, setManualCallbackSubmit] = useState<((url: string) => void) | null>(null);
// If the component unmounts mid-auth (e.g. a parent component's Esc handler
// navigates away before ours fires), abort the OAuth flow so the callback
// server is closed. Without this, the server stays bound and the process
// can outlive the terminal. Also clear the copy-feedback timer and mark
// unmounted so the async setClipboard callback doesn't setUrlCopied /
// schedule a new timer after unmount.
useEffect(() => () => {
unmountedRef.current = true;
authAbortControllerRef.current?.abort();
if (copyTimeoutRef.current !== undefined) {
clearTimeout(copyTimeoutRef.current);
}
}, []);
// A server is effectively authenticated if:
// 1. It has OAuth tokens (server.isAuthenticated), OR
// 2. It's connected and has tools (meaning it's working via some auth mechanism)
const isEffectivelyAuthenticated = server.isAuthenticated || server.client.type === 'connected' && serverToolsCount > 0;
const reconnectMcpServer = useMcpReconnect();
const handleClaudeAIAuthComplete = React.useCallback(async () => {
setIsClaudeAIAuthenticating(false);
setClaudeAIAuthUrl(null);
setIsReconnecting(true);
try {
const result = await reconnectMcpServer(server.name);
const success = result.client.type === 'connected';
logEvent('tengu_claudeai_mcp_auth_completed', {
success
});
if (success) {
onComplete?.(`Authentication successful. Connected to ${server.name}.`);
} else if (result.client.type === 'needs-auth') {
onComplete?.('Authentication successful, but server still requires authentication. You may need to manually restart Claude Code.');
} else {
onComplete?.('Authentication successful, but server reconnection failed. You may need to manually restart Claude Code for the changes to take effect.');
}
} catch (err) {
logEvent('tengu_claudeai_mcp_auth_completed', {
success: false
});
onComplete?.(handleReconnectError(err, server.name));
} finally {
setIsReconnecting(false);
}
}, [reconnectMcpServer, server.name, onComplete]);
const handleClaudeAIClearAuthComplete = React.useCallback(async () => {
await clearServerCache(server.name, {
...server.config,
scope: server.scope
});
setAppState(prev => {
const newClients = prev.mcp.clients.map(c => c.name === server.name ? {
...c,
type: 'needs-auth' as const
} : c);
const newTools = excludeToolsByServer(prev.mcp.tools, server.name);
const newCommands = excludeCommandsByServer(prev.mcp.commands, server.name);
const newResources = excludeResourcesByServer(prev.mcp.resources, server.name);
return {
...prev,
mcp: {
...prev.mcp,
clients: newClients,
tools: newTools,
commands: newCommands,
resources: newResources
}
};
});
logEvent('tengu_claudeai_mcp_clear_auth_completed', {});
onComplete?.(`Disconnected from ${server.name}.`);
setIsClaudeAIClearingAuth(false);
setClaudeAIClearAuthUrl(null);
setClaudeAIClearAuthBrowserOpened(false);
}, [server.name, server.config, server.scope, setAppState, onComplete]);
// Escape to cancel authentication flow
useKeybinding('confirm:no', () => {
authAbortControllerRef.current?.abort();
authAbortControllerRef.current = null;
setIsAuthenticating(false);
setAuthorizationUrl(null);
}, {
context: 'Confirmation',
isActive: isAuthenticating
});
// Escape to cancel Claude AI authentication
useKeybinding('confirm:no', () => {
setIsClaudeAIAuthenticating(false);
setClaudeAIAuthUrl(null);
}, {
context: 'Confirmation',
isActive: isClaudeAIAuthenticating
});
// Escape to cancel Claude AI clear auth
useKeybinding('confirm:no', () => {
setIsClaudeAIClearingAuth(false);
setClaudeAIClearAuthUrl(null);
setClaudeAIClearAuthBrowserOpened(false);
}, {
context: 'Confirmation',
isActive: isClaudeAIClearingAuth
});
// Return key handling for authentication flows and 'c' to copy URL
useInput((input, key) => {
if (key.return && isClaudeAIAuthenticating) {
void handleClaudeAIAuthComplete();
}
if (key.return && isClaudeAIClearingAuth) {
if (claudeAIClearAuthBrowserOpened) {
void handleClaudeAIClearAuthComplete();
} else {
// First Enter: open the browser
const connectorsUrl = `${getOauthConfig().CLAUDE_AI_ORIGIN}/settings/connectors`;
setClaudeAIClearAuthUrl(connectorsUrl);
setClaudeAIClearAuthBrowserOpened(true);
void openBrowser(connectorsUrl);
}
}
if (input === 'c' && !urlCopied) {
const urlToCopy = authorizationUrl || claudeAIAuthUrl || claudeAIClearAuthUrl;
if (urlToCopy) {
void setClipboard(urlToCopy).then(raw => {
if (unmountedRef.current) return;
if (raw) process.stdout.write(raw);
setUrlCopied(true);
if (copyTimeoutRef.current !== undefined) {
clearTimeout(copyTimeoutRef.current);
}
copyTimeoutRef.current = setTimeout(setUrlCopied, 2000, false);
});
}
}
});
const capitalizedServerName = capitalize(String(server.name));
// Count MCP prompts for this server (skills are shown in /skills, not here)
const serverCommandsCount = filterMcpPromptsByServer(mcp.commands, server.name).length;
const toggleMcpServer = useMcpToggleEnabled();
const handleClaudeAIAuth = React.useCallback(async () => {
const claudeAiBaseUrl = getOauthConfig().CLAUDE_AI_ORIGIN;
const accountInfo = getOauthAccountInfo();
const orgUuid = accountInfo?.organizationUuid;
let authUrl: string;
if (orgUuid && server.config.type === 'claudeai-proxy' && server.config.id) {
// Use the direct auth URL with org and server IDs
// Replace 'mcprs' prefix with 'mcpsrv' if present
const serverId = server.config.id.startsWith('mcprs') ? 'mcpsrv' + server.config.id.slice(5) : server.config.id;
const productSurface = encodeURIComponent(process.env.CLAUDE_CODE_ENTRYPOINT || 'cli');
authUrl = `${claudeAiBaseUrl}/api/organizations/${orgUuid}/mcp/start-auth/${serverId}?product_surface=${productSurface}`;
} else {
// Fall back to settings/connectors if we don't have the required IDs
authUrl = `${claudeAiBaseUrl}/settings/connectors`;
}
setClaudeAIAuthUrl(authUrl);
setIsClaudeAIAuthenticating(true);
logEvent('tengu_claudeai_mcp_auth_started', {});
await openBrowser(authUrl);
}, [server.config]);
const handleClaudeAIClearAuth = React.useCallback(() => {
setIsClaudeAIClearingAuth(true);
logEvent('tengu_claudeai_mcp_clear_auth_started', {});
}, []);
const handleToggleEnabled = React.useCallback(async () => {
const wasEnabled = server.client.type !== 'disabled';
try {
await toggleMcpServer(server.name);
if (server.config.type === 'claudeai-proxy') {
logEvent('tengu_claudeai_mcp_toggle', {
new_state: (wasEnabled ? 'disabled' : 'enabled') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
});
}
// Return to the server list so user can continue managing other servers
onCancel();
} catch (err_0) {
const action = wasEnabled ? 'disable' : 'enable';
onComplete?.(`Failed to ${action} MCP server '${server.name}': ${errorMessage(err_0)}`);
}
}, [server.client.type, server.config.type, server.name, toggleMcpServer, onCancel, onComplete]);
const handleAuthenticate = React.useCallback(async () => {
if (server.config.type === 'claudeai-proxy') return;
setIsAuthenticating(true);
setError(null);
const controller = new AbortController();
authAbortControllerRef.current = controller;
try {
// Revoke existing tokens if re-authenticating, but preserve step-up
// auth state so the next OAuth flow can reuse cached scope/discovery.
if (server.isAuthenticated && server.config) {
await revokeServerTokens(server.name, server.config, {
preserveStepUpState: true
});
}
if (server.config) {
await performMCPOAuthFlow(server.name, server.config, setAuthorizationUrl, controller.signal, {
onWaitingForCallback: submit => {
setManualCallbackSubmit(() => submit);
}
});
logEvent('tengu_mcp_auth_config_authenticate', {
wasAuthenticated: server.isAuthenticated
});
const result_0 = await reconnectMcpServer(server.name);
if (result_0.client.type === 'connected') {
const message = isEffectivelyAuthenticated ? `Authentication successful. Reconnected to ${server.name}.` : `Authentication successful. Connected to ${server.name}.`;
onComplete?.(message);
} else if (result_0.client.type === 'needs-auth') {
onComplete?.('Authentication successful, but server still requires authentication. You may need to manually restart Claude Code.');
} else {
// result.client.type === 'failed'
logMCPDebug(server.name, `Reconnection failed after authentication`);
onComplete?.('Authentication successful, but server reconnection failed. You may need to manually restart Claude Code for the changes to take effect.');
}
}
} catch (err_1) {
// Don't show error if it was a cancellation
if (err_1 instanceof Error && !(err_1 instanceof AuthenticationCancelledError)) {
setError(err_1.message);
}
} finally {
setIsAuthenticating(false);
authAbortControllerRef.current = null;
setManualCallbackSubmit(null);
setCallbackUrlInput('');
}
}, [server.isAuthenticated, server.config, server.name, onComplete, reconnectMcpServer, isEffectivelyAuthenticated]);
const handleClearAuth = async () => {
if (server.config.type === 'claudeai-proxy') return;
if (server.config) {
// First revoke the authentication tokens and clear all auth state
await revokeServerTokens(server.name, server.config);
logEvent('tengu_mcp_auth_config_clear', {});
// Disconnect the client and clear the cache
await clearServerCache(server.name, {
...server.config,
scope: server.scope
});
// Update app state to remove the disconnected server's tools, commands, and resources
setAppState(prev_0 => {
const newClients_0 = prev_0.mcp.clients.map(c_0 =>
// 'failed' is a misnomer here, but we don't really differentiate between "not connected" and "failed" at the moment
c_0.name === server.name ? {
...c_0,
type: 'failed' as const
} : c_0);
const newTools_0 = excludeToolsByServer(prev_0.mcp.tools, server.name);
const newCommands_0 = excludeCommandsByServer(prev_0.mcp.commands, server.name);
const newResources_0 = excludeResourcesByServer(prev_0.mcp.resources, server.name);
return {
...prev_0,
mcp: {
...prev_0.mcp,
clients: newClients_0,
tools: newTools_0,
commands: newCommands_0,
resources: newResources_0
}
};
});
onComplete?.(`Authentication cleared for ${server.name}.`);
}
};
if (isAuthenticating) {
// XAA: silent exchange (cached id_token → no browser), so don't claim
// one will open. If IdP login IS needed, authorizationUrl populates and
// the URL fallback block below still renders.
const authCopy = server.config.type !== 'claudeai-proxy' && server.config.oauth?.xaa ? ' Authenticating via your identity provider' : ' A browser window will open for authentication';
return <Box flexDirection="column" gap={1} padding={1}>
<Text color="claude">Authenticating with {server.name}…</Text>
<Box>
<Spinner />
<Text>{authCopy}</Text>
</Box>
{authorizationUrl && <Box flexDirection="column">
<Box>
<Text dimColor>
If your browser doesn&apos;t open automatically, copy this URL
manually{' '}
</Text>
{urlCopied ? <Text color="success">(Copied!)</Text> : <Text dimColor>
<KeyboardShortcutHint shortcut="c" action="copy" parens />
</Text>}
</Box>
<Link url={authorizationUrl} />
</Box>}
{isAuthenticating && authorizationUrl && manualCallbackSubmit && <Box flexDirection="column" marginTop={1}>
<Text dimColor>
If the redirect page shows a connection error, paste the URL from
your browser&apos;s address bar:
</Text>
<Box>
<Text dimColor>URL {'>'} </Text>
<TextInput value={callbackUrlInput} onChange={setCallbackUrlInput} onSubmit={(value: string) => {
manualCallbackSubmit(value.trim());
setCallbackUrlInput('');
}} cursorOffset={callbackUrlCursorOffset} onChangeCursorOffset={setCallbackUrlCursorOffset} columns={terminalColumns - 8} />
</Box>
</Box>}
<Box marginLeft={3}>
<Text dimColor>
Return here after authenticating in your browser. Press Esc to go
back.
</Text>
</Box>
</Box>;
}
if (isClaudeAIAuthenticating) {
return <Box flexDirection="column" gap={1} padding={1}>
<Text color="claude">Authenticating with {server.name}…</Text>
<Box>
<Spinner />
<Text> A browser window will open for authentication</Text>
</Box>
{claudeAIAuthUrl && <Box flexDirection="column">
<Box>
<Text dimColor>
If your browser doesn&apos;t open automatically, copy this URL
manually{' '}
</Text>
{urlCopied ? <Text color="success">(Copied!)</Text> : <Text dimColor>
<KeyboardShortcutHint shortcut="c" action="copy" parens />
</Text>}
</Box>
<Link url={claudeAIAuthUrl} />
</Box>}
<Box marginLeft={3} flexDirection="column">
<Text color="permission">
Press <Text bold>Enter</Text> after authenticating in your browser.
</Text>
<Text dimColor italic>
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="back" />
</Text>
</Box>
</Box>;
}
if (isClaudeAIClearingAuth) {
return <Box flexDirection="column" gap={1} padding={1}>
<Text color="claude">Clear authentication for {server.name}</Text>
{claudeAIClearAuthBrowserOpened ? <>
<Text>
Find the MCP server in the browser and click
&quot;Disconnect&quot;.
</Text>
{claudeAIClearAuthUrl && <Box flexDirection="column">
<Box>
<Text dimColor>
If your browser didn&apos;t open automatically, copy this
URL manually{' '}
</Text>
{urlCopied ? <Text color="success">(Copied!)</Text> : <Text dimColor>
<KeyboardShortcutHint shortcut="c" action="copy" parens />
</Text>}
</Box>
<Link url={claudeAIClearAuthUrl} />
</Box>}
<Box marginLeft={3} flexDirection="column">
<Text color="permission">
Press <Text bold>Enter</Text> when done.
</Text>
<Text dimColor italic>
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="back" />
</Text>
</Box>
</> : <>
<Text>
This will open claude.ai in the browser. Find the MCP server in
the list and click &quot;Disconnect&quot;.
</Text>
<Box marginLeft={3} flexDirection="column">
<Text color="permission">
Press <Text bold>Enter</Text> to open the browser.
</Text>
<Text dimColor italic>
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="back" />
</Text>
</Box>
</>}
</Box>;
}
if (isReconnecting) {
return <Box flexDirection="column" gap={1} padding={1}>
<Text color="text">
Connecting to <Text bold>{server.name}</Text>…
</Text>
<Box>
<Spinner />
<Text> Establishing connection to MCP server</Text>
</Box>
<Text dimColor>This may take a few moments.</Text>
</Box>;
}
const menuOptions = [];
// If server is disabled, show Enable first as the primary action
if (server.client.type === 'disabled') {
menuOptions.push({
label: 'Enable',
value: 'toggle-enabled'
});
}
if (server.client.type === 'connected' && serverToolsCount > 0) {
menuOptions.push({
label: 'View tools',
value: 'tools'
});
}
if (server.config.type === 'claudeai-proxy') {
if (server.client.type === 'connected') {
menuOptions.push({
label: 'Clear authentication',
value: 'claudeai-clear-auth'
});
} else if (server.client.type !== 'disabled') {
menuOptions.push({
label: 'Authenticate',
value: 'claudeai-auth'
});
}
} else {
if (isEffectivelyAuthenticated) {
menuOptions.push({
label: 'Re-authenticate',
value: 'reauth'
});
menuOptions.push({
label: 'Clear authentication',
value: 'clear-auth'
});
}
if (!isEffectivelyAuthenticated) {
menuOptions.push({
label: 'Authenticate',
value: 'auth'
});
}
}
if (server.client.type !== 'disabled') {
if (server.client.type !== 'needs-auth') {
menuOptions.push({
label: 'Reconnect',
value: 'reconnectMcpServer'
});
}
menuOptions.push({
label: 'Disable',
value: 'toggle-enabled'
});
}
// If there are no other options, add a back option so Select handles escape
if (menuOptions.length === 0) {
menuOptions.push({
label: 'Back',
value: 'back'
});
}
return <Box flexDirection="column">
<Box flexDirection="column" paddingX={1} borderStyle={borderless ? undefined : 'round'}>
<Box marginBottom={1}>
<Text bold>{capitalizedServerName} MCP Server</Text>
</Box>
<Box flexDirection="column" gap={0}>
<Box>
<Text bold>Status: </Text>
{server.client.type === 'disabled' ? <Text>{color('inactive', theme)(figures.radioOff)} disabled</Text> : server.client.type === 'connected' ? <Text>{color('success', theme)(figures.tick)} connected</Text> : server.client.type === 'pending' ? <>
<Text dimColor>{figures.radioOff}</Text>
<Text> connecting…</Text>
</> : server.client.type === 'needs-auth' ? <Text>
{color('warning', theme)(figures.triangleUpOutline)} needs
authentication
</Text> : <Text>{color('error', theme)(figures.cross)} failed</Text>}
</Box>
{server.transport !== 'claudeai-proxy' && <Box>
<Text bold>Auth: </Text>
{isEffectivelyAuthenticated ? <Text>
{color('success', theme)(figures.tick)} authenticated
</Text> : <Text>
{color('error', theme)(figures.cross)} not authenticated
</Text>}
</Box>}
<Box>
<Text bold>URL: </Text>
<Text dimColor>{server.config.url}</Text>
</Box>
<Box>
<Text bold>Config location: </Text>
<Text dimColor>{describeMcpConfigFilePath(server.scope)}</Text>
</Box>
{server.client.type === 'connected' && <CapabilitiesSection serverToolsCount={serverToolsCount} serverPromptsCount={serverCommandsCount} serverResourcesCount={mcp.resources[server.name]?.length || 0} />}
{server.client.type === 'connected' && serverToolsCount > 0 && <Box>
<Text bold>Tools: </Text>
<Text dimColor>{serverToolsCount} tools</Text>
</Box>}
</Box>
{error && <Box marginTop={1}>
<Text color="error">Error: {error}</Text>
</Box>}
{menuOptions.length > 0 && <Box marginTop={1}>
<Select options={menuOptions} onChange={async value_0 => {
switch (value_0) {
case 'tools':
onViewTools();
break;
case 'auth':
case 'reauth':
await handleAuthenticate();
break;
case 'clear-auth':
await handleClearAuth();
break;
case 'claudeai-auth':
await handleClaudeAIAuth();
break;
case 'claudeai-clear-auth':
handleClaudeAIClearAuth();
break;
case 'reconnectMcpServer':
setIsReconnecting(true);
try {
const result_1 = await reconnectMcpServer(server.name);
if (server.config.type === 'claudeai-proxy') {
logEvent('tengu_claudeai_mcp_reconnect', {
success: result_1.client.type === 'connected'
});
}
const {
message: message_0
} = handleReconnectResult(result_1, server.name);
onComplete?.(message_0);
} catch (err_2) {
if (server.config.type === 'claudeai-proxy') {
logEvent('tengu_claudeai_mcp_reconnect', {
success: false
});
}
onComplete?.(handleReconnectError(err_2, server.name));
} finally {
setIsReconnecting(false);
}
break;
case 'toggle-enabled':
await handleToggleEnabled();
break;
case 'back':
onCancel();
break;
}
}} onCancel={onCancel} />
</Box>}
</Box>
<Box marginTop={1}>
<Text dimColor italic>
{exitState.pending ? <>Press {exitState.keyName} again to exit</> : <Byline>
<KeyboardShortcutHint shortcut="↑↓" action="navigate" />
<KeyboardShortcutHint shortcut="Enter" action="select" />
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="back" />
</Byline>}
</Text>
</Box>
</Box>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJ1c2VFZmZlY3QiLCJ1c2VSZWYiLCJ1c2VTdGF0ZSIsIkFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMiLCJsb2dFdmVudCIsIkNvbW1hbmRSZXN1bHREaXNwbGF5IiwiZ2V0T2F1dGhDb25maWciLCJ1c2VFeGl0T25DdHJsQ0RXaXRoS2V5YmluZGluZ3MiLCJ1c2VUZXJtaW5hbFNpemUiLCJzZXRDbGlwYm9hcmQiLCJCb3giLCJjb2xvciIsIkxpbmsiLCJUZXh0IiwidXNlSW5wdXQiLCJ1c2VUaGVtZSIsInVzZUtleWJpbmRpbmciLCJBdXRoZW50aWNhdGlvbkNhbmNlbGxlZEVycm9yIiwicGVyZm9ybU1DUE9BdXRoRmxvdyIsInJldm9rZVNlcnZlclRva2VucyIsImNsZWFyU2VydmVyQ2FjaGUiLCJ1c2VNY3BSZWNvbm5lY3QiLCJ1c2VNY3BUb2dnbGVFbmFibGVkIiwiZGVzY3JpYmVNY3BDb25maWdGaWxlUGF0aCIsImV4Y2x1ZGVDb21tYW5kc0J5U2VydmVyIiwiZXhjbHVkZVJlc291cmNlc0J5U2VydmVyIiwiZXhjbHVkZVRvb2xzQnlTZXJ2ZXIiLCJmaWx0ZXJNY3BQcm9tcHRzQnlTZXJ2ZXIiLCJ1c2VBcHBTdGF0ZSIsInVzZVNldEFwcFN0YXRlIiwiZ2V0T2F1dGhBY2NvdW50SW5mbyIsIm9wZW5Ccm93c2VyIiwiZXJyb3JNZXNzYWdlIiwibG9nTUNQRGVidWciLCJjYXBpdGFsaXplIiwiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IiwiU2VsZWN0IiwiQnlsaW5lIiwiS2V5Ym9hcmRTaG9ydGN1dEhpbnQiLCJTcGlubmVyIiwiVGV4dElucHV0IiwiQ2FwYWJpbGl0aWVzU2VjdGlvbiIsIkNsYXVkZUFJU2VydmVySW5mbyIsIkhUVFBTZXJ2ZXJJbmZvIiwiU1NFU2VydmVySW5mbyIsImhhbmRsZVJlY29ubmVjdEVycm9yIiwiaGFuZGxlUmVjb25uZWN0UmVzdWx0IiwiUHJvcHMiLCJzZXJ2ZXIiLCJzZXJ2ZXJUb29sc0NvdW50Iiwib25WaWV3VG9vbHMiLCJvbkNhbmNlbCIsIm9uQ29tcGxldGUiLCJyZXN1bHQiLCJvcHRpb25zIiwiZGlzcGxheSIsImJvcmRlcmxlc3MiLCJNQ1BSZW1vdGVTZXJ2ZXJNZW51IiwiUmVhY3ROb2RlIiwidGhlbWUiLCJleGl0U3RhdGUiLCJjb2x1bW5zIiwidGVybWluYWxDb2x1bW5zIiwiaXNBdXRoZW50aWNhdGluZyIsInNldElzQXV0aGVudGljYXRpbmciLCJlcnJvciIsInNldEVycm9yIiwibWNwIiwicyIsInNldEFwcFN0YXRlIiwiYXV0aG9yaXphdGlvblVybCIsInNldEF1dGhvcml6YXRpb25VcmwiLCJpc1JlY29ubmVjdGluZyIsInNldElzUmVjb25uZWN0aW5nIiwiYXV0aEFib3J0Q29udHJvbGxlclJlZiIsIkFib3J0Q29udHJvbGxlciIsImlzQ2xhdWRlQUlBdXRoZW50aWNhdGluZyIsInNldElzQ2xhdWRlQUlBdXRoZW50aWNhdGluZyIsImNsYXVkZUFJQXV0aFVybCIsInNldENsYXVkZUFJQXV0aFVybCIsImlzQ2xhdWRlQUlDbGVhcmluZ0F1dGgiLCJzZXRJc0NsYXVkZUFJQ2xlYXJpbmdBdXRoIiwiY2xhdWRlQUlDbGVhckF1dGhVcmwiLCJzZXRDbGF1ZGVBSUNsZWFyQXV0aFVybCIsImNsYXVkZUFJQ2xlYXJBdXRoQnJvd3Nlck9wZW5lZCIsInNldENsYXVkZUFJQ2xlYXJBdXRoQnJvd3Nlck9wZW5lZCIsInVybENvcGllZCIsInNldFVybENvcGllZCIsImNvcHlUaW1lb3V0UmVmIiwiUmV0dXJuVHlwZSIsInNldFRpbWVvdXQiLCJ1bmRlZmluZWQiLCJ1bm1vdW50ZWRSZWYiLCJjYWxsYmFja1VybElucHV0Iiwic2V0Q2FsbGJhY2tVcmxJbnB1dCIsImNhbGxiYWNrVXJsQ3Vyc29yT2Zmc2V0Iiwic2V0Q2FsbGJhY2tVcmxDdXJzb3JPZmZzZXQiLCJtYW51YWxDYWxsYmFja1N1Ym1pdCIsInNldE1hbnVhbENhbGxiYWNrU3VibWl0IiwidXJsIiwiY3VycmVudCIsImFib3J0IiwiY2xlYXJUaW1lb3V0IiwiaXNFZmZlY3RpdmVseUF1dGhlbnRpY2F0ZWQiLCJpc0F1dGhlbnRpY2F0ZWQiLCJjbGllbnQiLCJ0eXBlIiwicmVjb25uZWN0TWNwU2VydmVyIiwiaGFuZGxlQ2xhdWRlQUlBdXRoQ29tcGxldGUiLCJ1c2VDYWxsYmFjayIsIm5hbWUiLCJzdWNjZXNzIiwiZXJyIiwiaGFuZGxlQ2xhdWRlQUlDbGVhckF1dGhDb21wbGV0ZSIsImNvbmZpZyIsInNjb3BlIiwicHJldiIsIm5ld0NsaWVudHMiLCJjbGllbnRzIiwibWFwIiwiYyIsImNvbnN0IiwibmV3VG9vbHMiLCJ0b29scyIsIm5ld0NvbW1hbmRzIiwiY29tbWFuZHMiLCJuZXdSZXNvdXJjZXMiLCJyZXNvdXJjZXMiLCJjb250ZXh0IiwiaXNBY3RpdmUiLCJpbnB1dCIsImtleSIsInJldHVybiIsImNvbm5lY3RvcnNVcmwiLCJDTEFVREVfQUlfT1JJR0lOIiwidXJsVG9Db3B5IiwidGhlbiIsInJhdyIsInByb2Nlc3MiLCJzdGRvdXQiLCJ3cml0ZSIsImNhcGl0YWxpemVkU2VydmVyTmFtZSIsIlN0cmluZyIsInNlcnZlckNvbW1hbmRzQ291bnQiLCJsZW5ndGgiLCJ0b2dnbGVNY3BTZXJ2ZXIiLCJoYW5kbGVDbGF1ZGVBSUF1dGgiLCJjbGF1ZGVBaUJhc2VVcmwiLCJhY2NvdW50SW5mbyIsIm9yZ1V1aWQiLCJvcmdhbml6YXRpb25VdWlkIiwiYXV0aFVybCIsImlkIiwic2VydmVySWQiLCJzdGFydHNXaXRoIiwic2xpY2UiLCJwcm9kdWN0U3VyZmFjZSIsImVuY29kZVVSSUNvbXBvbmVudCIsImVudiIsIkNMQVVERV9DT0RFX0VOVFJZUE9JTlQiLCJoYW5kbGVDbGF1ZGVBSUNsZWFyQXV0aCIsImhhbmRsZVRvZ2dsZUVuYWJsZWQiLCJ3YXNFbmFibGVkIiwibmV3X3N0YXRlIiwiYWN0aW9uIiwiaGFuZGxlQXV0aGVudGljYXRlIiwiY29udHJvbGxlciIsInByZXNlcnZlU3RlcFVwU3RhdGUiLCJzaWduYWwiLCJvbldhaXRpbmdGb3JDYWxsYmFjayIsInN1Ym1pdCIsIndhc0F1dGhlbnRpY2F0ZWQiLCJtZXNzYWdlIiwiRXJyb3IiLCJoYW5kbGVDbGVhckF1dGgiLCJhdXRoQ29weSIsIm9hdXRoIiwieGFhIiwidmFsdWUiLCJ0cmltIiwibWVudU9wdGlvbnMiLCJwdXNoIiwibGFiZWwiLCJyYWRpb09mZiIsInRpY2siLCJ0cmlhbmdsZVVwT3V0bGluZSIsImNyb3NzIiwidHJhbnNwb3J0IiwicGVuZGluZyIsImtleU5hbWUiXSwic291cmNlcyI6WyJNQ1BSZW1vdGVTZXJ2ZXJNZW51LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZmlndXJlcyBmcm9tICdmaWd1cmVzJ1xuaW1wb3J0IFJlYWN0LCB7IHVzZUVmZmVjdCwgdXNlUmVmLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHtcbiAgdHlwZSBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICBsb2dFdmVudCxcbn0gZnJvbSAnc3JjL3NlcnZpY2VzL2FuYWx5dGljcy9pbmRleC5qcydcbmltcG9ydCB0eXBlIHsgQ29tbWFuZFJlc3VsdERpc3BsYXkgfSBmcm9tICcuLi8uLi9jb21tYW5kcy5qcydcbmltcG9ydCB7IGdldE9hdXRoQ29uZmlnIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL29hdXRoLmpzJ1xuaW1wb3J0IHsgdXNlRXhpdE9uQ3RybENEV2l0aEtleWJpbmRpbmdzIH0gZnJvbSAnLi4vLi4vaG9va3MvdXNlRXhpdE9uQ3RybENEV2l0aEtleWJpbmRpbmdzLmpzJ1xuaW1wb3J0IHsgdXNlVGVybWluYWxTaXplIH0gZnJvbSAnLi4vLi4vaG9va3MvdXNlVGVybWluYWxTaXplLmpzJ1xuaW1wb3J0IHsgc2V0Q2xpcGJvYXJkIH0gZnJvbSAnLi4vLi4vaW5rL3Rlcm1pby9vc2MuanMnXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY3VzdG9tLXJ1bGVzL3ByZWZlci11c2Uta2V5YmluZGluZ3MgLS0gcmF3IGovay9hcnJvdyBtZW51IG5hdmlnYXRpb25cbmltcG9ydCB7IEJveCwgY29 Line truncated
+398
View File
@@ -0,0 +1,398 @@
import { c as _c } from "react/compiler-runtime";
import React, { useEffect, useMemo } from 'react';
import type { CommandResultDisplay } from '../../commands.js';
import { ClaudeAuthProvider } from '../../services/mcp/auth.js';
import type { McpClaudeAIProxyServerConfig, McpHTTPServerConfig, McpSSEServerConfig, McpStdioServerConfig } from '../../services/mcp/types.js';
import { extractAgentMcpServers, filterToolsByServer } from '../../services/mcp/utils.js';
import { useAppState } from '../../state/AppState.js';
import { getSessionIngressAuthToken } from '../../utils/sessionIngressAuth.js';
import { MCPAgentServerMenu } from './MCPAgentServerMenu.js';
import { MCPListPanel } from './MCPListPanel.js';
import { MCPRemoteServerMenu } from './MCPRemoteServerMenu.js';
import { MCPStdioServerMenu } from './MCPStdioServerMenu.js';
import { MCPToolDetailView } from './MCPToolDetailView.js';
import { MCPToolListView } from './MCPToolListView.js';
import type { AgentMcpServerInfo, MCPViewState, ServerInfo } from './types.js';
type Props = {
onComplete: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
};
export function MCPSettings(t0) {
const $ = _c(66);
const {
onComplete
} = t0;
const mcp = useAppState(_temp);
const agentDefinitions = useAppState(_temp2);
const mcpClients = mcp.clients;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = {
type: "list"
};
$[0] = t1;
} else {
t1 = $[0];
}
const [viewState, setViewState] = React.useState(t1);
let t2;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [];
$[1] = t2;
} else {
t2 = $[1];
}
const [servers, setServers] = React.useState(t2);
let t3;
if ($[2] !== agentDefinitions.allAgents) {
t3 = extractAgentMcpServers(agentDefinitions.allAgents);
$[2] = agentDefinitions.allAgents;
$[3] = t3;
} else {
t3 = $[3];
}
const agentMcpServers = t3;
let t4;
if ($[4] !== mcpClients) {
t4 = mcpClients.filter(_temp3).sort(_temp4);
$[4] = mcpClients;
$[5] = t4;
} else {
t4 = $[5];
}
const filteredClients = t4;
let t5;
let t6;
if ($[6] !== filteredClients || $[7] !== mcp.tools) {
t5 = () => {
let cancelled = false;
const prepareServers = async function prepareServers() {
const serverInfos = await Promise.all(filteredClients.map(async client_0 => {
const scope = client_0.config.scope;
const isSSE = client_0.config.type === "sse";
const isHTTP = client_0.config.type === "http";
const isClaudeAIProxy = client_0.config.type === "claudeai-proxy";
let isAuthenticated = undefined;
if (isSSE || isHTTP) {
const authProvider = new ClaudeAuthProvider(client_0.name, client_0.config as McpSSEServerConfig | McpHTTPServerConfig);
const tokens = await authProvider.tokens();
const hasSessionAuth = getSessionIngressAuthToken() !== null && client_0.type === "connected";
const hasToolsAndConnected = client_0.type === "connected" && filterToolsByServer(mcp.tools, client_0.name).length > 0;
isAuthenticated = Boolean(tokens) || hasSessionAuth || hasToolsAndConnected;
}
const baseInfo = {
name: client_0.name,
client: client_0,
scope
};
if (isClaudeAIProxy) {
return {
...baseInfo,
transport: "claudeai-proxy" as const,
isAuthenticated: false,
config: client_0.config as McpClaudeAIProxyServerConfig
};
} else {
if (isSSE) {
return {
...baseInfo,
transport: "sse" as const,
isAuthenticated,
config: client_0.config as McpSSEServerConfig
};
} else {
if (isHTTP) {
return {
...baseInfo,
transport: "http" as const,
isAuthenticated,
config: client_0.config as McpHTTPServerConfig
};
} else {
return {
...baseInfo,
transport: "stdio" as const,
config: client_0.config as McpStdioServerConfig
};
}
}
}
}));
if (cancelled) {
return;
}
setServers(serverInfos);
};
prepareServers();
return () => {
cancelled = true;
};
};
t6 = [filteredClients, mcp.tools];
$[6] = filteredClients;
$[7] = mcp.tools;
$[8] = t5;
$[9] = t6;
} else {
t5 = $[8];
t6 = $[9];
}
React.useEffect(t5, t6);
let t7;
let t8;
if ($[10] !== agentMcpServers.length || $[11] !== filteredClients.length || $[12] !== onComplete || $[13] !== servers.length) {
t7 = () => {
if (servers.length === 0 && filteredClients.length > 0) {
return;
}
if (servers.length === 0 && agentMcpServers.length === 0) {
onComplete("No MCP servers configured. Please run /doctor if this is unexpected. Otherwise, run `claude mcp --help` or visit https://code.claude.com/docs/en/mcp to learn more.");
}
};
t8 = [servers.length, filteredClients.length, agentMcpServers.length, onComplete];
$[10] = agentMcpServers.length;
$[11] = filteredClients.length;
$[12] = onComplete;
$[13] = servers.length;
$[14] = t7;
$[15] = t8;
} else {
t7 = $[14];
t8 = $[15];
}
useEffect(t7, t8);
switch (viewState.type) {
case "list":
{
let t10;
let t9;
if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
t9 = server => setViewState({
type: "server-menu",
server
});
t10 = agentServer => setViewState({
type: "agent-server-menu",
agentServer
});
$[16] = t10;
$[17] = t9;
} else {
t10 = $[16];
t9 = $[17];
}
let t11;
if ($[18] !== agentMcpServers || $[19] !== onComplete || $[20] !== servers || $[21] !== viewState.defaultTab) {
t11 = <MCPListPanel servers={servers} agentServers={agentMcpServers} onSelectServer={t9} onSelectAgentServer={t10} onComplete={onComplete} defaultTab={viewState.defaultTab} />;
$[18] = agentMcpServers;
$[19] = onComplete;
$[20] = servers;
$[21] = viewState.defaultTab;
$[22] = t11;
} else {
t11 = $[22];
}
return t11;
}
case "server-menu":
{
let t9;
if ($[23] !== mcp.tools || $[24] !== viewState.server.name) {
t9 = filterToolsByServer(mcp.tools, viewState.server.name);
$[23] = mcp.tools;
$[24] = viewState.server.name;
$[25] = t9;
} else {
t9 = $[25];
}
const serverTools_0 = t9;
const defaultTab = viewState.server.transport === "claudeai-proxy" ? "claude.ai" : "Claude Code";
if (viewState.server.transport === "stdio") {
let t10;
if ($[26] !== viewState.server) {
t10 = () => setViewState({
type: "server-tools",
server: viewState.server
});
$[26] = viewState.server;
$[27] = t10;
} else {
t10 = $[27];
}
let t11;
if ($[28] !== defaultTab) {
t11 = () => setViewState({
type: "list",
defaultTab
});
$[28] = defaultTab;
$[29] = t11;
} else {
t11 = $[29];
}
let t12;
if ($[30] !== onComplete || $[31] !== serverTools_0.length || $[32] !== t10 || $[33] !== t11 || $[34] !== viewState.server) {
t12 = <MCPStdioServerMenu server={viewState.server} serverToolsCount={serverTools_0.length} onViewTools={t10} onCancel={t11} onComplete={onComplete} />;
$[30] = onComplete;
$[31] = serverTools_0.length;
$[32] = t10;
$[33] = t11;
$[34] = viewState.server;
$[35] = t12;
} else {
t12 = $[35];
}
return t12;
} else {
let t10;
if ($[36] !== viewState.server) {
t10 = () => setViewState({
type: "server-tools",
server: viewState.server
});
$[36] = viewState.server;
$[37] = t10;
} else {
t10 = $[37];
}
let t11;
if ($[38] !== defaultTab) {
t11 = () => setViewState({
type: "list",
defaultTab
});
$[38] = defaultTab;
$[39] = t11;
} else {
t11 = $[39];
}
let t12;
if ($[40] !== onComplete || $[41] !== serverTools_0.length || $[42] !== t10 || $[43] !== t11 || $[44] !== viewState.server) {
t12 = <MCPRemoteServerMenu server={viewState.server} serverToolsCount={serverTools_0.length} onViewTools={t10} onCancel={t11} onComplete={onComplete} />;
$[40] = onComplete;
$[41] = serverTools_0.length;
$[42] = t10;
$[43] = t11;
$[44] = viewState.server;
$[45] = t12;
} else {
t12 = $[45];
}
return t12;
}
}
case "server-tools":
{
let t10;
let t9;
if ($[46] !== viewState.server) {
t9 = (_, index) => setViewState({
type: "server-tool-detail",
server: viewState.server,
toolIndex: index
});
t10 = () => setViewState({
type: "server-menu",
server: viewState.server
});
$[46] = viewState.server;
$[47] = t10;
$[48] = t9;
} else {
t10 = $[47];
t9 = $[48];
}
let t11;
if ($[49] !== t10 || $[50] !== t9 || $[51] !== viewState.server) {
t11 = <MCPToolListView server={viewState.server} onSelectTool={t9} onBack={t10} />;
$[49] = t10;
$[50] = t9;
$[51] = viewState.server;
$[52] = t11;
} else {
t11 = $[52];
}
return t11;
}
case "server-tool-detail":
{
let t9;
if ($[53] !== mcp.tools || $[54] !== viewState.server.name) {
t9 = filterToolsByServer(mcp.tools, viewState.server.name);
$[53] = mcp.tools;
$[54] = viewState.server.name;
$[55] = t9;
} else {
t9 = $[55];
}
const serverTools = t9;
const tool = serverTools[viewState.toolIndex];
if (!tool) {
setViewState({
type: "server-tools",
server: viewState.server
});
return null;
}
let t10;
if ($[56] !== viewState.server) {
t10 = () => setViewState({
type: "server-tools",
server: viewState.server
});
$[56] = viewState.server;
$[57] = t10;
} else {
t10 = $[57];
}
let t11;
if ($[58] !== t10 || $[59] !== tool || $[60] !== viewState.server) {
t11 = <MCPToolDetailView tool={tool} server={viewState.server} onBack={t10} />;
$[58] = t10;
$[59] = tool;
$[60] = viewState.server;
$[61] = t11;
} else {
t11 = $[61];
}
return t11;
}
case "agent-server-menu":
{
let t9;
if ($[62] === Symbol.for("react.memo_cache_sentinel")) {
t9 = () => setViewState({
type: "list",
defaultTab: "Agents"
});
$[62] = t9;
} else {
t9 = $[62];
}
let t10;
if ($[63] !== onComplete || $[64] !== viewState.agentServer) {
t10 = <MCPAgentServerMenu agentServer={viewState.agentServer} onCancel={t9} onComplete={onComplete} />;
$[63] = onComplete;
$[64] = viewState.agentServer;
$[65] = t10;
} else {
t10 = $[65];
}
return t10;
}
}
}
function _temp4(a, b) {
return a.name.localeCompare(b.name);
}
function _temp3(client) {
return client.name !== "ide";
}
function _temp2(s_0) {
return s_0.agentDefinitions;
}
function _temp(s) {
return s.mcp;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZUVmZmVjdCIsInVzZU1lbW8iLCJDb21tYW5kUmVzdWx0RGlzcGxheSIsIkNsYXVkZUF1dGhQcm92aWRlciIsIk1jcENsYXVkZUFJUHJveHlTZXJ2ZXJDb25maWciLCJNY3BIVFRQU2VydmVyQ29uZmlnIiwiTWNwU1NFU2VydmVyQ29uZmlnIiwiTWNwU3RkaW9TZXJ2ZXJDb25maWciLCJleHRyYWN0QWdlbnRNY3BTZXJ2ZXJzIiwiZmlsdGVyVG9vbHNCeVNlcnZlciIsInVzZUFwcFN0YXRlIiwiZ2V0U2Vzc2lvbkluZ3Jlc3NBdXRoVG9rZW4iLCJNQ1BBZ2VudFNlcnZlck1lbnUiLCJNQ1BMaXN0UGFuZWwiLCJNQ1BSZW1vdGVTZXJ2ZXJNZW51IiwiTUNQU3RkaW9TZXJ2ZXJNZW51IiwiTUNQVG9vbERldGFpbFZpZXciLCJNQ1BUb29sTGlzdFZpZXciLCJBZ2VudE1jcFNlcnZlckluZm8iLCJNQ1BWaWV3U3RhdGUiLCJTZXJ2ZXJJbmZvIiwiUHJvcHMiLCJvbkNvbXBsZXRlIiwicmVzdWx0Iiwib3B0aW9ucyIsImRpc3BsYXkiLCJNQ1BTZXR0aW5ncyIsInQwIiwiJCIsIl9jIiwibWNwIiwiX3RlbXAiLCJhZ2VudERlZmluaXRpb25zIiwiX3RlbXAyIiwibWNwQ2xpZW50cyIsImNsaWVudHMiLCJ0MSIsIlN5bWJvbCIsImZvciIsInR5cGUiLCJ2aWV3U3RhdGUiLCJzZXRWaWV3U3RhdGUiLCJ1c2VTdGF0ZSIsInQyIiwic2VydmVycyIsInNldFNlcnZlcnMiLCJ0MyIsImFsbEFnZW50cyIsImFnZW50TWNwU2VydmVycyIsInQ0IiwiZmlsdGVyIiwiX3RlbXAzIiwic29ydCIsIl90ZW1wNCIsImZpbHRlcmVkQ2xpZW50cyIsInQ1IiwidDYiLCJ0b29scyIsImNhbmNlbGxlZCIsInByZXBhcmVTZXJ2ZXJzIiwic2VydmVySW5mb3MiLCJQcm9taXNlIiwiYWxsIiwibWFwIiwiY2xpZW50XzAiLCJzY29wZSIsImNsaWVudCIsImNvbmZpZyIsImlzU1NFIiwiaXNIVFRQIiwiaXNDbGF1ZGVBSVByb3h5IiwiaXNBdXRoZW50aWNhdGVkIiwidW5kZWZpbmVkIiwiYXV0aFByb3ZpZGVyIiwibmFtZSIsInRva2VucyIsImhhc1Nlc3Npb25BdXRoIiwiaGFzVG9vbHNBbmRDb25uZWN0ZWQiLCJsZW5ndGgiLCJCb29sZWFuIiwiYmFzZUluZm8iLCJ0cmFuc3BvcnQiLCJjb25zdCIsInQ3IiwidDgiLCJ0MTAiLCJ0OSIsInNlcnZlciIsImFnZW50U2VydmVyIiwidDExIiwiZGVmYXVsdFRhYiIsInNlcnZlclRvb2xzXzAiLCJ0MTIiLCJzZXJ2ZXJUb29scyIsIl8iLCJpbmRleCIsInRvb2xJbmRleCIsInRvb2wiLCJhIiwiYiIsImxvY2FsZUNvbXBhcmUiLCJzXzAiLCJzIl0sInNvdXJjZXMiOlsiTUNQU2V0dGluZ3MudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBSZWFjdCwgeyB1c2VFZmZlY3QsIHVzZU1lbW8gfSBmcm9tICdyZWFjdCdcbmltcG9ydCB0eXBlIHsgQ29tbWFuZFJlc3VsdERpc3BsYXkgfSBmcm9tICcuLi8uLi9jb21tYW5kcy5qcydcbmltcG9ydCB7IENsYXVkZUF1dGhQcm92aWRlciB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL21jcC9hdXRoLmpzJ1xuaW1wb3J0IHR5cGUge1xuICBNY3BDbGF1ZGVBSVByb3h5U2VydmVyQ29uZmlnLFxuICBNY3BIVFRQU2VydmVyQ29uZmlnLFxuICBNY3BTU0VTZXJ2ZXJDb25maWcsXG4gIE1jcFN0ZGlvU2VydmVyQ29uZmlnLFxufSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9tY3AvdHlwZXMuanMnXG5pbXBvcnQge1xuICBleHRyYWN0QWdlbnRNY3BTZXJ2ZXJzLFxuICBmaWx0ZXJUb29sc0J5U2VydmVyLFxufSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9tY3AvdXRpbHMuanMnXG5pbXBvcnQgeyB1c2VBcHBTdGF0ZSB9IGZyb20gJy4uLy4uL3N0YXRlL0FwcFN0YXRlLmpzJ1xuaW1wb3J0IHsgZ2V0U2Vzc2lvbkluZ3Jlc3NBdXRoVG9rZW4gfSBmcm9tICcuLi8uLi91dGlscy9zZXNzaW9uSW5ncmVzc0F1dGguanMnXG5pbXBvcnQgeyBNQ1BBZ2VudFNlcnZlck1lbnUgfSBmcm9tICcuL01DUEFnZW50U2VydmVyTWVudS5qcydcbmltcG9ydCB7IE1DUExpc3RQYW5lbCB9IGZyb20gJy4vTUNQTGlzdFBhbmVsLmpzJ1xuaW1wb3J0IHsgTUNQUmVtb3RlU2VydmVyTWVudSB9IGZyb20gJy4vTUNQUmVtb3RlU2VydmVyTWVudS5qcydcbmltcG9ydCB7IE1DUFN0ZGlvU2VydmVyTWVudSB9IGZyb20gJy4vTUNQU3RkaW9TZXJ2ZXJNZW51LmpzJ1xuaW1wb3J0IHsgTUNQVG9vbERldGFpbFZpZXcgfSBmcm9tICcuL01DUFRvb2xEZXRhaWxWaWV3LmpzJ1xuaW1wb3J0IHsgTUNQVG9vbExpc3RWaWV3IH0gZnJvbSAnLi9NQ1BUb29sTGlzdFZpZXcuanMnXG5pbXBvcnQgdHlwZSB7IEFnZW50TWNwU2VydmVySW5mbywgTUNQVmlld1N0YXRlLCBTZXJ2ZXJJbmZvIH0gZnJvbSAnLi90eXBlcy5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgb25Db21wbGV0ZTogKFxuICAgIHJlc3VsdD86IHN0cmluZyxcbiAgICBvcHRpb25zPzogeyBkaXNwbGF5PzogQ29tbWFuZFJlc3VsdERpc3BsYXkgfSxcbiAgKSA9PiB2b2lkXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBNQ1BTZXR0aW5ncyh7IG9uQ29tcGxldGUgfTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBtY3AgPSB1c2VBcHBTdGF0ZShzID0+IHMubWNwKVxuICBjb25zdCBhZ2VudERlZmluaXRpb25zID0gdXNlQXBwU3RhdGUocyA9PiBzLmFnZW50RGVmaW5pdGlvbnMpXG4gIGNvbnN0IG1jcENsaWVudHMgPSBtY3AuY2xpZW50c1xuICBjb25zdCBbdmlld1N0YXRlLCBzZXRWaWV3U3RhdGVdID0gUmVhY3QudXNlU3RhdGU8TUNQVmlld1N0YXRlPih7XG4gICAgdHlwZTogJ2xpc3QnLFxuICB9KVxuICBjb25zdCBbc2VydmVycywgc2V0U2VydmVyc10gPSBSZWFjdC51c2VTdGF0ZTxTZXJ2ZXJJbmZvW10+KFtdKVxuXG4gIC8vIEV4dHJhY3QgYWdlbnQtc3BlY2lmaWMgTUNQIHNlcnZlcnMgZnJvbSBhZ2VudCBkZWZpbml0aW9uc1xuICBjb25zdCBhZ2VudE1jcFNlcnZlcnMgPSB1c2VNZW1vKFxuICAgICgpID0+IGV4dHJhY3RBZ2VudE1jcFNlcnZlcnMoYWdlbnREZWZpbml0aW9ucy5hbGxBZ2VudHMpLFxuICAgIFthZ2VudERlZmluaXRpb25zLmFsbEFnZW50c10sXG4gIClcblxuICBjb25zdCBmaWx0ZXJlZENsaWVudHMgPSBSZWFjdC51c2VNZW1vKFxuICAgICgpID0+XG4gICAgICBtY3BDbGllbnRzXG4gICAgICAgIC5maWx0ZXIoY2xpZW50ID0+IGNsaWVudC5uYW1lICE9PSAnaWRlJylcbiAgICAgICAgLnNvcnQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpLFxuICAgIFttY3BDbGllbnRzXSxcbiAgKVxuXG4gIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgbGV0IGNhbmNlbGxlZCA9IGZhbHNlXG4gICAgYXN5bmMgZnVuY3Rpb24gcHJlcGFyZVNlcnZlcnMoKSB7XG4gICAgICBjb25zdCBzZXJ2ZXJJbmZvcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBmaWx0ZXJlZENsaWVudHMubWFwKGFzeW5jIGNsaWVudCA9PiB7XG4gICAgICAgICAgY29uc3Qgc2NvcGUgPSBjbGllbnQuY29uZmlnLnNjb3BlXG4gICAgICAgICAgY29uc3QgaXNTU0UgPSBjbGllbnQuY29uZmlnLnR5cGUgPT09ICdzc2UnXG4gICAgICAgICAgY29uc3QgaXNIVFRQID0gY2xpZW50LmNvbmZpZy50eXBlID09PSAnaHR0cCdcbiAgICAgICAgICBjb25zdCBpc0NsYXVkZUFJUHJveHkgPSBjbGllbnQuY29uZmlnLnR5cGUgPT09ICdjbGF1ZGVhaS1wcm94eSdcbiAgICAgICAgICBsZXQgaXNBdXRoZW50aWNhdGVkOiBib29sZWFuIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG5cbiAgICAgICAgICBpZiA Line truncated
+177
View File
@@ -0,0 +1,177 @@
import figures from 'figures';
import React, { useState } from 'react';
import type { CommandResultDisplay } from '../../commands.js';
import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithKeybindings.js';
import { Box, color, Text, useTheme } from '../../ink.js';
import { getMcpConfigByName } from '../../services/mcp/config.js';
import { useMcpReconnect, useMcpToggleEnabled } from '../../services/mcp/MCPConnectionManager.js';
import { describeMcpConfigFilePath, filterMcpPromptsByServer } from '../../services/mcp/utils.js';
import { useAppState } from '../../state/AppState.js';
import { errorMessage } from '../../utils/errors.js';
import { capitalize } from '../../utils/stringUtils.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Select } from '../CustomSelect/index.js';
import { Byline } from '../design-system/Byline.js';
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js';
import { Spinner } from '../Spinner.js';
import { CapabilitiesSection } from './CapabilitiesSection.js';
import type { StdioServerInfo } from './types.js';
import { handleReconnectError, handleReconnectResult } from './utils/reconnectHelpers.js';
type Props = {
server: StdioServerInfo;
serverToolsCount: number;
onViewTools: () => void;
onCancel: () => void;
onComplete: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
borderless?: boolean;
};
export function MCPStdioServerMenu({
server,
serverToolsCount,
onViewTools,
onCancel,
onComplete,
borderless = false
}: Props): React.ReactNode {
const [theme] = useTheme();
const exitState = useExitOnCtrlCDWithKeybindings();
const mcp = useAppState(s => s.mcp);
const reconnectMcpServer = useMcpReconnect();
const toggleMcpServer = useMcpToggleEnabled();
const [isReconnecting, setIsReconnecting] = useState(false);
const handleToggleEnabled = React.useCallback(async () => {
const wasEnabled = server.client.type !== 'disabled';
try {
await toggleMcpServer(server.name);
// Return to the server list so user can continue managing other servers
onCancel();
} catch (err) {
const action = wasEnabled ? 'disable' : 'enable';
onComplete(`Failed to ${action} MCP server '${server.name}': ${errorMessage(err)}`);
}
}, [server.client.type, server.name, toggleMcpServer, onCancel, onComplete]);
const capitalizedServerName = capitalize(String(server.name));
// Count MCP prompts for this server (skills are shown in /skills, not here)
const serverCommandsCount = filterMcpPromptsByServer(mcp.commands, server.name).length;
const menuOptions = [];
// Only show "View tools" if server is not disabled and has tools
if (server.client.type !== 'disabled' && serverToolsCount > 0) {
menuOptions.push({
label: 'View tools',
value: 'tools'
});
}
// Only show reconnect option if the server is not disabled
if (server.client.type !== 'disabled') {
menuOptions.push({
label: 'Reconnect',
value: 'reconnectMcpServer'
});
}
menuOptions.push({
label: server.client.type !== 'disabled' ? 'Disable' : 'Enable',
value: 'toggle-enabled'
});
// If there are no other options, add a back option so Select handles escape
if (menuOptions.length === 0) {
menuOptions.push({
label: 'Back',
value: 'back'
});
}
if (isReconnecting) {
return <Box flexDirection="column" gap={1} padding={1}>
<Text color="text">
Reconnecting to <Text bold>{server.name}</Text>
</Text>
<Box>
<Spinner />
<Text> Restarting MCP server process</Text>
</Box>
<Text dimColor>This may take a few moments.</Text>
</Box>;
}
return <Box flexDirection="column">
<Box flexDirection="column" paddingX={1} borderStyle={borderless ? undefined : 'round'}>
<Box marginBottom={1}>
<Text bold>{capitalizedServerName} MCP Server</Text>
</Box>
<Box flexDirection="column" gap={0}>
<Box>
<Text bold>Status: </Text>
{server.client.type === 'disabled' ? <Text>{color('inactive', theme)(figures.radioOff)} disabled</Text> : server.client.type === 'connected' ? <Text>{color('success', theme)(figures.tick)} connected</Text> : server.client.type === 'pending' ? <>
<Text dimColor>{figures.radioOff}</Text>
<Text> connecting…</Text>
</> : <Text>{color('error', theme)(figures.cross)} failed</Text>}
</Box>
<Box>
<Text bold>Command: </Text>
<Text dimColor>{server.config.command}</Text>
</Box>
{server.config.args && server.config.args.length > 0 && <Box>
<Text bold>Args: </Text>
<Text dimColor>{server.config.args.join(' ')}</Text>
</Box>}
<Box>
<Text bold>Config location: </Text>
<Text dimColor>
{describeMcpConfigFilePath(getMcpConfigByName(server.name)?.scope ?? 'dynamic')}
</Text>
</Box>
{server.client.type === 'connected' && <CapabilitiesSection serverToolsCount={serverToolsCount} serverPromptsCount={serverCommandsCount} serverResourcesCount={mcp.resources[server.name]?.length || 0} />}
{server.client.type === 'connected' && serverToolsCount > 0 && <Box>
<Text bold>Tools: </Text>
<Text dimColor>{serverToolsCount} tools</Text>
</Box>}
</Box>
{menuOptions.length > 0 && <Box marginTop={1}>
<Select options={menuOptions} onChange={async value => {
if (value === 'tools') {
onViewTools();
} else if (value === 'reconnectMcpServer') {
setIsReconnecting(true);
try {
const result = await reconnectMcpServer(server.name);
const {
message
} = handleReconnectResult(result, server.name);
onComplete?.(message);
} catch (err_0) {
onComplete?.(handleReconnectError(err_0, server.name));
} finally {
setIsReconnecting(false);
}
} else if (value === 'toggle-enabled') {
await handleToggleEnabled();
} else if (value === 'back') {
onCancel();
}
}} onCancel={onCancel} />
</Box>}
</Box>
<Box marginTop={1}>
<Text dimColor italic>
{exitState.pending ? <>Press {exitState.keyName} again to exit</> : <Byline>
<KeyboardShortcutHint shortcut="↑↓" action="navigate" />
<KeyboardShortcutHint shortcut="Enter" action="select" />
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="back" />
</Byline>}
</Text>
</Box>
</Box>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJ1c2VTdGF0ZSIsIkNvbW1hbmRSZXN1bHREaXNwbGF5IiwidXNlRXhpdE9uQ3RybENEV2l0aEtleWJpbmRpbmdzIiwiQm94IiwiY29sb3IiLCJUZXh0IiwidXNlVGhlbWUiLCJnZXRNY3BDb25maWdCeU5hbWUiLCJ1c2VNY3BSZWNvbm5lY3QiLCJ1c2VNY3BUb2dnbGVFbmFibGVkIiwiZGVzY3JpYmVNY3BDb25maWdGaWxlUGF0aCIsImZpbHRlck1jcFByb21wdHNCeVNlcnZlciIsInVzZUFwcFN0YXRlIiwiZXJyb3JNZXNzYWdlIiwiY2FwaXRhbGl6ZSIsIkNvbmZpZ3VyYWJsZVNob3J0Y3V0SGludCIsIlNlbGVjdCIsIkJ5bGluZSIsIktleWJvYXJkU2hvcnRjdXRIaW50IiwiU3Bpbm5lciIsIkNhcGFiaWxpdGllc1NlY3Rpb24iLCJTdGRpb1NlcnZlckluZm8iLCJoYW5kbGVSZWNvbm5lY3RFcnJvciIsImhhbmRsZVJlY29ubmVjdFJlc3VsdCIsIlByb3BzIiwic2VydmVyIiwic2VydmVyVG9vbHNDb3VudCIsIm9uVmlld1Rvb2xzIiwib25DYW5jZWwiLCJvbkNvbXBsZXRlIiwicmVzdWx0Iiwib3B0aW9ucyIsImRpc3BsYXkiLCJib3JkZXJsZXNzIiwiTUNQU3RkaW9TZXJ2ZXJNZW51IiwiUmVhY3ROb2RlIiwidGhlbWUiLCJleGl0U3RhdGUiLCJtY3AiLCJzIiwicmVjb25uZWN0TWNwU2VydmVyIiwidG9nZ2xlTWNwU2VydmVyIiwiaXNSZWNvbm5lY3RpbmciLCJzZXRJc1JlY29ubmVjdGluZyIsImhhbmRsZVRvZ2dsZUVuYWJsZWQiLCJ1c2VDYWxsYmFjayIsIndhc0VuYWJsZWQiLCJjbGllbnQiLCJ0eXBlIiwibmFtZSIsImVyciIsImFjdGlvbiIsImNhcGl0YWxpemVkU2VydmVyTmFtZSIsIlN0cmluZyIsInNlcnZlckNvbW1hbmRzQ291bnQiLCJjb21tYW5kcyIsImxlbmd0aCIsIm1lbnVPcHRpb25zIiwicHVzaCIsImxhYmVsIiwidmFsdWUiLCJ1bmRlZmluZWQiLCJyYWRpb09mZiIsInRpY2siLCJjcm9zcyIsImNvbmZpZyIsImNvbW1hbmQiLCJhcmdzIiwiam9pbiIsInNjb3BlIiwicmVzb3VyY2VzIiwibWVzc2FnZSIsInBlbmRpbmciLCJrZXlOYW1lIl0sInNvdXJjZXMiOlsiTUNQU3RkaW9TZXJ2ZXJNZW51LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZmlndXJlcyBmcm9tICdmaWd1cmVzJ1xuaW1wb3J0IFJlYWN0LCB7IHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgdHlwZSB7IENvbW1hbmRSZXN1bHREaXNwbGF5IH0gZnJvbSAnLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgeyB1c2VFeGl0T25DdHJsQ0RXaXRoS2V5YmluZGluZ3MgfSBmcm9tICcuLi8uLi9ob29rcy91c2VFeGl0T25DdHJsQ0RXaXRoS2V5YmluZGluZ3MuanMnXG5pbXBvcnQgeyBCb3gsIGNvbG9yLCBUZXh0LCB1c2VUaGVtZSB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB7IGdldE1jcENvbmZpZ0J5TmFtZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL21jcC9jb25maWcuanMnXG5pbXBvcnQge1xuICB1c2VNY3BSZWNvbm5lY3QsXG4gIHVzZU1jcFRvZ2dsZUVuYWJsZWQsXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL21jcC9NQ1BDb25uZWN0aW9uTWFuYWdlci5qcydcbmltcG9ydCB7XG4gIGRlc2NyaWJlTWNwQ29uZmlnRmlsZVBhdGgsXG4gIGZpbHRlck1jcFByb21wdHNCeVNlcnZlcixcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvbWNwL3V0aWxzLmpzJ1xuaW1wb3J0IHsgdXNlQXBwU3RhdGUgfSBmcm9tICcuLi8uLi9zdGF0ZS9BcHBTdGF0ZS5qcydcbmltcG9ydCB7IGVycm9yTWVzc2FnZSB9IGZyb20gJy4uLy4uL3V0aWxzL2Vycm9ycy5qcydcbmltcG9ydCB7IGNhcGl0YWxpemUgfSBmcm9tICcuLi8uLi91dGlscy9zdHJpbmdVdGlscy5qcydcbmltcG9ydCB7IENvbmZpZ3VyYWJsZVNob3J0Y3V0SGludCB9IGZyb20gJy4uL0NvbmZpZ3VyYWJsZVNob3J0Y3V0SGludC5qcydcbmltcG9ydCB7IFNlbGVjdCB9IGZyb20gJy4uL0N1c3RvbVNlbGVjdC9pbmRleC5qcydcbmltcG9ydCB7IEJ5bGluZSB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vQnlsaW5lLmpzJ1xuaW1wb3J0IHsgS2V5Ym9hcmRTaG9ydGN1dEhpbnQgfSBmcm9tICcuLi9kZXNpZ24tc3lzdGVtL0tleWJvYXJkU2hvcnRjdXRIaW50LmpzJ1xuaW1wb3J0IHsgU3Bpbm5lciB9IGZyb20gJy4uL1NwaW5uZXIuanMnXG5pbXBvcnQgeyBDYXBhYmlsaXRpZXNTZWN0aW9uIH0gZnJvbSAnLi9DYXBhYmlsaXRpZXNTZWN0aW9uLmpzJ1xuaW1wb3J0IHR5cGUgeyBTdGRpb1NlcnZlckluZm8gfSBmcm9tICcuL3R5cGVzLmpzJ1xuaW1wb3J0IHtcbiAgaGFuZGxlUmVjb25uZWN0RXJyb3IsXG4gIGhhbmRsZVJlY29ubmVjdFJlc3VsdCxcbn0gZnJvbSAnLi91dGlscy9yZWNvbm5lY3RIZWxwZXJzLmpzJ1xuXG50eXBlIFByb3BzID0ge1xuICBzZXJ2ZXI6IFN0ZGlvU2VydmVySW5mb1xuICBzZXJ2ZXJUb29sc0NvdW50OiBudW1iZXJcbiAgb25WaWV3VG9vbHM6ICgpID0+IHZvaWRcbiAgb25DYW5jZWw6ICgpID0+IHZvaWRcbiAgb25Db21wbGV0ZTogKFxuICAgIHJlc3VsdD86IHN0cmluZyxcbiAgICBvcHRpb25zPzogeyBkaXNwbGF5PzogQ29tbWFuZFJlc3VsdERpc3BsYXkgfSxcbiAgKSA9PiB2b2lkXG4gIGJvcmRlcmxlc3M/OiBib29sZWFuXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBNQ1BTdGRpb1NlcnZlck1lbnUoe1xuICBzZXJ2ZXIsXG4gIHNlcnZlclRvb2xzQ291bnQsXG4gIG9uVmlld1Rvb2xzLFxuICBvbkNhbmNlbCxcbiAgb25Db21wbGV0ZSxcbiAgYm9yZGVybGVzcyA9IGZhbHNlLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBbdGhlbWVdID0gdXNlVGhlbWUoKVxuICBjb25zdCBleGl0U3RhdGUgPSB1c2VFeGl0T25DdHJsQ0RXaXRoS2V5YmluZGluZ3MoKVxuICBjb25zdCBtY3AgPSB1c2VBcHBTdGF0ZShzID0+IHMubWNwKVxuICBjb25zdCByZWNvbm5lY3RNY3BTZXJ2ZXIgPSB1c2VNY3BSZWNvbm5lY3QoKVxuICBjb25zdCB0b2dnbGVNY3BTZXJ2ZXIgPSB1c2VNY3BUb2dnbGVFbmFibGVkKClcbiAgY29uc3QgW2lzUmVjb25uZWN0aW5nLCBzZXRJc1JlY29ubmVjdGluZ10gPSB1c2VTdGF0ZShmYWxzZSlcblxuICBjb25zdCBoYW5kbGVUb2dnbGVFbmFibGVkID0gUmVhY3QudXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHdhc0VuYWJsZWQgPSBzZXJ2ZXIuY2xpZW50LnR5cGUgIT09ICdkaXNhYmxlZCdcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0b2dnbGVNY3BTZXJ2ZXIoc2VydmVyLm5hbWUpXG4gICAgICAvLyBSZXR1cm4gdG8gdGhlIHNlcnZlciBsaXN0IHNvIHVzZXIgY2FuIGNvbnRpbnVlIG1hbmFnaW5nIG90aGVyIHNlcnZlcnNcbiAgICAgIG9uQ2FuY2VsKClcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnN0IGFjdGlvbiA9IHdhc0VuYWJsZWQgPyAnZGlzYWJsZScgOiAnZW5hYmxlJ1xuICAgICAgb25Db21wbGV0ZShcbiAgICAgICAgYEZhaWxlZCB0byAke2FjdGlvbn0gTUNQIHNlcnZlciAnJHtzZXJ2ZXIubmFtZX0nOiAke2Vycm9yTWVzc2FnZShlcnIpfWAsXG4gICAgICApXG4gICAgfVxuICB9LCBbc2VydmVyLmNsaWVudC50eXBlLCBzZXJ2ZXIubmFtZSwgdG9nZ2xlTWNwU2VydmVyLCBvbkNhbmNlbCwgb25Db21wbGV0ZV0pXG5cbiAgY29uc3QgY2FwaXRhbGl6ZWRTZXJ2ZXJOYW1lID0gY2FwaXRhbGl6ZShTdHJpbmcoc2VydmVyLm5hbWUpKVxuXG4gIC8vIENvdW50IE1DUCBwcm9tcHRzIGZvciB0aGl Line truncated
+212
View File
@@ -0,0 +1,212 @@
import { c as _c } from "react/compiler-runtime";
import React from 'react';
import { Box, Text } from '../../ink.js';
import { extractMcpToolDisplayName, getMcpDisplayName } from '../../services/mcp/mcpStringUtils.js';
import type { Tool } from '../../Tool.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Dialog } from '../design-system/Dialog.js';
import type { ServerInfo } from './types.js';
type Props = {
tool: Tool;
server: ServerInfo;
onBack: () => void;
};
export function MCPToolDetailView(t0) {
const $ = _c(44);
const {
tool,
server,
onBack
} = t0;
const [toolDescription, setToolDescription] = React.useState("");
let t1;
let toolName;
if ($[0] !== server.name || $[1] !== tool) {
toolName = getMcpDisplayName(tool.name, server.name);
const fullDisplayName = tool.userFacingName ? tool.userFacingName({}) : toolName;
t1 = extractMcpToolDisplayName(fullDisplayName);
$[0] = server.name;
$[1] = tool;
$[2] = t1;
$[3] = toolName;
} else {
t1 = $[2];
toolName = $[3];
}
const displayName = t1;
let t2;
if ($[4] !== tool) {
t2 = tool.isReadOnly?.({}) ?? false;
$[4] = tool;
$[5] = t2;
} else {
t2 = $[5];
}
const isReadOnly = t2;
let t3;
if ($[6] !== tool) {
t3 = tool.isDestructive?.({}) ?? false;
$[6] = tool;
$[7] = t3;
} else {
t3 = $[7];
}
const isDestructive = t3;
let t4;
if ($[8] !== tool) {
t4 = tool.isOpenWorld?.({}) ?? false;
$[8] = tool;
$[9] = t4;
} else {
t4 = $[9];
}
const isOpenWorld = t4;
let t5;
let t6;
if ($[10] !== tool) {
t5 = () => {
const loadDescription = async function loadDescription() {
try {
const desc = await tool.description({}, {
isNonInteractiveSession: false,
toolPermissionContext: {
mode: "default" as const,
additionalWorkingDirectories: new Map(),
alwaysAllowRules: {},
alwaysDenyRules: {},
alwaysAskRules: {},
isBypassPermissionsModeAvailable: false
},
tools: []
});
setToolDescription(desc);
} catch {
setToolDescription("Failed to load description");
}
};
loadDescription();
};
t6 = [tool];
$[10] = tool;
$[11] = t5;
$[12] = t6;
} else {
t5 = $[11];
t6 = $[12];
}
React.useEffect(t5, t6);
let t7;
if ($[13] !== isReadOnly) {
t7 = isReadOnly && <Text color="success"> [read-only]</Text>;
$[13] = isReadOnly;
$[14] = t7;
} else {
t7 = $[14];
}
let t8;
if ($[15] !== isDestructive) {
t8 = isDestructive && <Text color="error"> [destructive]</Text>;
$[15] = isDestructive;
$[16] = t8;
} else {
t8 = $[16];
}
let t9;
if ($[17] !== isOpenWorld) {
t9 = isOpenWorld && <Text dimColor={true}> [open-world]</Text>;
$[17] = isOpenWorld;
$[18] = t9;
} else {
t9 = $[18];
}
let t10;
if ($[19] !== displayName || $[20] !== t7 || $[21] !== t8 || $[22] !== t9) {
t10 = <>{displayName}{t7}{t8}{t9}</>;
$[19] = displayName;
$[20] = t7;
$[21] = t8;
$[22] = t9;
$[23] = t10;
} else {
t10 = $[23];
}
const titleContent = t10;
let t11;
if ($[24] === Symbol.for("react.memo_cache_sentinel")) {
t11 = <Text bold={true}>Tool name: </Text>;
$[24] = t11;
} else {
t11 = $[24];
}
let t12;
if ($[25] !== toolName) {
t12 = <Box>{t11}<Text dimColor={true}>{toolName}</Text></Box>;
$[25] = toolName;
$[26] = t12;
} else {
t12 = $[26];
}
let t13;
if ($[27] === Symbol.for("react.memo_cache_sentinel")) {
t13 = <Text bold={true}>Full name: </Text>;
$[27] = t13;
} else {
t13 = $[27];
}
let t14;
if ($[28] !== tool.name) {
t14 = <Box>{t13}<Text dimColor={true}>{tool.name}</Text></Box>;
$[28] = tool.name;
$[29] = t14;
} else {
t14 = $[29];
}
let t15;
if ($[30] !== toolDescription) {
t15 = toolDescription && <Box flexDirection="column" marginTop={1}><Text bold={true}>Description:</Text><Text wrap="wrap">{toolDescription}</Text></Box>;
$[30] = toolDescription;
$[31] = t15;
} else {
t15 = $[31];
}
let t16;
if ($[32] !== tool.inputJSONSchema) {
t16 = tool.inputJSONSchema && tool.inputJSONSchema.properties && Object.keys(tool.inputJSONSchema.properties).length > 0 && <Box flexDirection="column" marginTop={1}><Text bold={true}>Parameters:</Text><Box marginLeft={2} flexDirection="column">{Object.entries(tool.inputJSONSchema.properties).map(t17 => {
const [key, value] = t17;
const required = tool.inputJSONSchema?.required as string[] | undefined;
const isRequired = required?.includes(key);
return <Text key={key}>• {key}{isRequired && <Text dimColor={true}> (required)</Text>}:{" "}<Text dimColor={true}>{typeof value === "object" && value && "type" in value ? String(value.type) : "unknown"}</Text>{typeof value === "object" && value && "description" in value && <Text dimColor={true}> - {String(value.description)}</Text>}</Text>;
})}</Box></Box>;
$[32] = tool.inputJSONSchema;
$[33] = t16;
} else {
t16 = $[33];
}
let t17;
if ($[34] !== t12 || $[35] !== t14 || $[36] !== t15 || $[37] !== t16) {
t17 = <Box flexDirection="column">{t12}{t14}{t15}{t16}</Box>;
$[34] = t12;
$[35] = t14;
$[36] = t15;
$[37] = t16;
$[38] = t17;
} else {
t17 = $[38];
}
let t18;
if ($[39] !== onBack || $[40] !== server.name || $[41] !== t17 || $[42] !== titleContent) {
t18 = <Dialog title={titleContent} subtitle={server.name} onCancel={onBack} inputGuide={_temp}>{t17}</Dialog>;
$[39] = onBack;
$[40] = server.name;
$[41] = t17;
$[42] = titleContent;
$[43] = t18;
} else {
t18 = $[43];
}
return t18;
}
function _temp(exitState) {
return exitState.pending ? <Text>Press {exitState.keyName} again to exit</Text> : <ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="go back" />;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIlRleHQiLCJleHRyYWN0TWNwVG9vbERpc3BsYXlOYW1lIiwiZ2V0TWNwRGlzcGxheU5hbWUiLCJUb29sIiwiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IiwiRGlhbG9nIiwiU2VydmVySW5mbyIsIlByb3BzIiwidG9vbCIsInNlcnZlciIsIm9uQmFjayIsIk1DUFRvb2xEZXRhaWxWaWV3IiwidDAiLCIkIiwiX2MiLCJ0b29sRGVzY3JpcHRpb24iLCJzZXRUb29sRGVzY3JpcHRpb24iLCJ1c2VTdGF0ZSIsInQxIiwidG9vbE5hbWUiLCJuYW1lIiwiZnVsbERpc3BsYXlOYW1lIiwidXNlckZhY2luZ05hbWUiLCJkaXNwbGF5TmFtZSIsInQyIiwiaXNSZWFkT25seSIsInQzIiwiaXNEZXN0cnVjdGl2ZSIsInQ0IiwiaXNPcGVuV29ybGQiLCJ0NSIsInQ2IiwibG9hZERlc2NyaXB0aW9uIiwiZGVzYyIsImRlc2NyaXB0aW9uIiwiaXNOb25JbnRlcmFjdGl2ZVNlc3Npb24iLCJ0b29sUGVybWlzc2lvbkNvbnRleHQiLCJtb2RlIiwiY29uc3QiLCJhZGRpdGlvbmFsV29ya2luZ0RpcmVjdG9yaWVzIiwiTWFwIiwiYWx3YXlzQWxsb3dSdWxlcyIsImFsd2F5c0RlbnlSdWxlcyIsImFsd2F5c0Fza1J1bGVzIiwiaXNCeXBhc3NQZXJtaXNzaW9uc01vZGVBdmFpbGFibGUiLCJ0b29scyIsInVzZUVmZmVjdCIsInQ3IiwidDgiLCJ0OSIsInQxMCIsInRpdGxlQ29udGVudCIsInQxMSIsIlN5bWJvbCIsImZvciIsInQxMiIsInQxMyIsInQxNCIsInQxNSIsInQxNiIsImlucHV0SlNPTlNjaGVtYSIsInByb3BlcnRpZXMiLCJPYmplY3QiLCJrZXlzIiwibGVuZ3RoIiwiZW50cmllcyIsIm1hcCIsInQxNyIsImtleSIsInZhbHVlIiwicmVxdWlyZWQiLCJpc1JlcXVpcmVkIiwiaW5jbHVkZXMiLCJTdHJpbmciLCJ0eXBlIiwidDE4IiwiX3RlbXAiLCJleGl0U3RhdGUiLCJwZW5kaW5nIiwia2V5TmFtZSJdLCJzb3VyY2VzIjpbIk1DUFRvb2xEZXRhaWxWaWV3LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBCb3gsIFRleHQgfSBmcm9tICcuLi8uLi9pbmsuanMnXG5pbXBvcnQge1xuICBleHRyYWN0TWNwVG9vbERpc3BsYXlOYW1lLFxuICBnZXRNY3BEaXNwbGF5TmFtZSxcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvbWNwL21jcFN0cmluZ1V0aWxzLmpzJ1xuaW1wb3J0IHR5cGUgeyBUb29sIH0gZnJvbSAnLi4vLi4vVG9vbC5qcydcbmltcG9ydCB7IENvbmZpZ3VyYWJsZVNob3J0Y3V0SGludCB9IGZyb20gJy4uL0NvbmZpZ3VyYWJsZVNob3J0Y3V0SGludC5qcydcbmltcG9ydCB7IERpYWxvZyB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vRGlhbG9nLmpzJ1xuaW1wb3J0IHR5cGUgeyBTZXJ2ZXJJbmZvIH0gZnJvbSAnLi90eXBlcy5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgdG9vbDogVG9vbFxuICBzZXJ2ZXI6IFNlcnZlckluZm9cbiAgb25CYWNrOiAoKSA9PiB2b2lkXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBNQ1BUb29sRGV0YWlsVmlldyh7XG4gIHRvb2wsXG4gIHNlcnZlcixcbiAgb25CYWNrLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBbdG9vbERlc2NyaXB0aW9uLCBzZXRUb29sRGVzY3JpcHRpb25dID0gUmVhY3QudXNlU3RhdGU8c3RyaW5nPignJylcblxuICBjb25zdCB0b29sTmFtZSA9IGdldE1jcERpc3BsYXlOYW1lKHRvb2wubmFtZSwgc2VydmVyLm5hbWUpXG4gIGNvbnN0IGZ1bGxEaXNwbGF5TmFtZSA9IHRvb2wudXNlckZhY2luZ05hbWVcbiAgICA/IHRvb2wudXNlckZhY2luZ05hbWUoe30pXG4gICAgOiB0b29sTmFtZVxuICBjb25zdCBkaXNwbGF5TmFtZSA9IGV4dHJhY3RNY3BUb29sRGlzcGxheU5hbWUoZnVsbERpc3BsYXlOYW1lKVxuXG4gIGNvbnN0IGlzUmVhZE9ubHkgPSB0b29sLmlzUmVhZE9ubHk/Lih7fSkgPz8gZmFsc2VcbiAgY29uc3QgaXNEZXN0cnVjdGl2ZSA9IHRvb2wuaXNEZXN0cnVjdGl2ZT8uKHt9KSA/PyBmYWxzZVxuICBjb25zdCBpc09wZW5Xb3JsZCA9IHRvb2wuaXNPcGVuV29ybGQ/Lih7fSkgPz8gZmFsc2VcblxuICBSZWFjdC51c2VFZmZlY3QoKCkgPT4ge1xuICAgIGFzeW5jIGZ1bmN0aW9uIGxvYWREZXNjcmlwdGlvbigpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRlc2MgPSBhd2FpdCB0b29sLmRlc2NyaXB0aW9uKFxuICAgICAgICAgIHt9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGlzTm9uSW50ZXJhY3RpdmVTZXNzaW9uOiBmYWxzZSxcbiAgICAgICAgICAgIHRvb2xQZXJtaXNzaW9uQ29udGV4dDoge1xuICAgICAgICAgICAgICBtb2RlOiAnZGVmYXVsdCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgIGFkZGl0aW9uYWxXb3JraW5nRGlyZWN0b3JpZXM6IG5ldyBNYXAoKSxcbiAgICAgICAgICAgICAgYWx3YXlzQWxsb3dSdWxlczoge30sXG4gICAgICAgICAgICAgIGFsd2F5c0RlbnlSdWxlczoge30sXG4gICAgICAgICAgICAgIGFsd2F5c0Fza1J1bGVzOiB7fSxcbiAgICAgICAgICAgICAgaXNCeXBhc3NQZXJtaXNzaW9uc01vZGVBdmFpbGFibGU6IGZhbHNlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHRvb2xzOiBbXSxcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICAgIHNldFRvb2xEZXNjcmlwdGlvbihkZXNjKVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHNldFRvb2xEZXNjcmlwdGlvbignRmFpbGVkIHRvIGxvYWQgZGVzY3JpcHRpb24nKVxuICAgICAgfVxuICAgIH1cbiAgICB2b2lkIGxvYWREZXNjcmlwdGlvbigpXG4gIH0sIFt0b29sXSlcblxuICBjb25zdCB0aXRsZUNvbnRlbnQgPSAoXG4gICAgPD5cbiAgICAgIHtkaXNwbGF5TmFtZX1cbiAgICAgIHtpc1JlYWRPbmx5ICYmIDxUZXh0IGNvbG9yPVwic3VjY2Vzc1wiPiBbcmVhZC1vbmx5XTwvVGV4dD59XG4gICAgICB7aXNEZXN0cnVjdGl2ZSAmJiA8VGV4dCBjb2xvcj1cImVycm9yXCI+IFtkZXN0cnVjdGl2ZV08L1RleHQ+fVxuICAgICAge2lzT3BlbldvcmxkICYmIDxUZXh0IGRpbUNvbG9yPiBbb3Blbi13b3JsZF08L1RleHQ+fVxuICAgIDwvPlxuICApXG5cbiAgcmV0dXJuIChcbiAgICA8RGlhbG9nXG4gICAgICB0aXRsZT17dGl0bGVDb250ZW50fVxuICAgICAgc3VidGl0bGU9e3NlcnZlci5uYW1lfVxuICAgICAgb25DYW5jZWw9e29uQmFja31cbiAgICAgIGlucHV0R3VpZGU9e2V4aXRTdGF0ZSA9PlxuICAgICAgICBleGl0U3RhdGUucGVuZGluZyA/IChcbiAgICAgICAgICA8VGV4dD5QcmVzcyB7ZXhpdFN0YXRlLmtleU5hbWV9IGFnYWluIHRvIGV4aXQ8L1RleHQ+XG4gICAgICAgICkgOiAoXG4gICAgICAgICAgPENvbmZpZ3VyYWJsZVNob3J0Y3V0SGludFxuICAgICAgICAgICAgYWN0aW9uPVwiY29uZmlybTpub1wiXG4gICAgICAgICAgICBjb250ZXh0PVwiQ29uZmlybWF0aW9uXCJcbiAgICAgICAgICAgIGZhbGxiYWNrPVwiRXNjXCJcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uPVwiZ28gYmFja1wiXG4gICAgICAgICAgLz5cbiAgICAgICAgKVxuICAgICAgfVxuICAgID5cbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgICA8Qm94PlxuICAgICAgICAgIDxUZXh0IGJvbGQ+VG9vbCBuYW1lOiA8L1RleHQ+XG4gICAgICAgICAgPFRleHQgZGltQ29sb3I+e3Rvb2xOYW1lfTwvVGV4dD5cbiAgICAgICAgPC9Cb3g+XG5cbiAgICAgICAgPEJveD5cbiAgICAgICAgICA8VGV4dCBib2xkPkZ1bGwgbmFtZTo Line truncated
+141
View File
@@ -0,0 +1,141 @@
import { c as _c } from "react/compiler-runtime";
import React from 'react';
import { Text } from '../../ink.js';
import { extractMcpToolDisplayName, getMcpDisplayName } from '../../services/mcp/mcpStringUtils.js';
import { filterToolsByServer } from '../../services/mcp/utils.js';
import { useAppState } from '../../state/AppState.js';
import type { Tool } from '../../Tool.js';
import { plural } from '../../utils/stringUtils.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Select } from '../CustomSelect/index.js';
import { Byline } from '../design-system/Byline.js';
import { Dialog } from '../design-system/Dialog.js';
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js';
import type { ServerInfo } from './types.js';
type Props = {
server: ServerInfo;
onSelectTool: (tool: Tool, index: number) => void;
onBack: () => void;
};
export function MCPToolListView(t0) {
const $ = _c(21);
const {
server,
onSelectTool,
onBack
} = t0;
const mcpTools = useAppState(_temp);
let t1;
bb0: {
if (server.client.type !== "connected") {
let t2;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [];
$[0] = t2;
} else {
t2 = $[0];
}
t1 = t2;
break bb0;
}
let t2;
if ($[1] !== mcpTools || $[2] !== server.name) {
t2 = filterToolsByServer(mcpTools, server.name);
$[1] = mcpTools;
$[2] = server.name;
$[3] = t2;
} else {
t2 = $[3];
}
t1 = t2;
}
const serverTools = t1;
let t2;
if ($[4] !== server.name || $[5] !== serverTools) {
let t3;
if ($[7] !== server.name) {
t3 = (tool, index) => {
const toolName = getMcpDisplayName(tool.name, server.name);
const fullDisplayName = tool.userFacingName ? tool.userFacingName({}) : toolName;
const displayName = extractMcpToolDisplayName(fullDisplayName);
const isReadOnly = tool.isReadOnly?.({}) ?? false;
const isDestructive = tool.isDestructive?.({}) ?? false;
const isOpenWorld = tool.isOpenWorld?.({}) ?? false;
const annotations = [];
if (isReadOnly) {
annotations.push("read-only");
}
if (isDestructive) {
annotations.push("destructive");
}
if (isOpenWorld) {
annotations.push("open-world");
}
return {
label: displayName,
value: index.toString(),
description: annotations.length > 0 ? annotations.join(", ") : undefined,
descriptionColor: isDestructive ? "error" : isReadOnly ? "success" : undefined
};
};
$[7] = server.name;
$[8] = t3;
} else {
t3 = $[8];
}
t2 = serverTools.map(t3);
$[4] = server.name;
$[5] = serverTools;
$[6] = t2;
} else {
t2 = $[6];
}
const toolOptions = t2;
const t3 = `Tools for ${server.name}`;
const t4 = serverTools.length;
let t5;
if ($[9] !== serverTools.length) {
t5 = plural(serverTools.length, "tool");
$[9] = serverTools.length;
$[10] = t5;
} else {
t5 = $[10];
}
const t6 = `${t4} ${t5}`;
let t7;
if ($[11] !== onBack || $[12] !== onSelectTool || $[13] !== serverTools || $[14] !== toolOptions) {
t7 = serverTools.length === 0 ? <Text dimColor={true}>No tools available</Text> : <Select options={toolOptions} onChange={value => {
const index_0 = parseInt(value);
const tool_0 = serverTools[index_0];
if (tool_0) {
onSelectTool(tool_0, index_0);
}
}} onCancel={onBack} />;
$[11] = onBack;
$[12] = onSelectTool;
$[13] = serverTools;
$[14] = toolOptions;
$[15] = t7;
} else {
t7 = $[15];
}
let t8;
if ($[16] !== onBack || $[17] !== t3 || $[18] !== t6 || $[19] !== t7) {
t8 = <Dialog title={t3} subtitle={t6} onCancel={onBack} inputGuide={_temp2}>{t7}</Dialog>;
$[16] = onBack;
$[17] = t3;
$[18] = t6;
$[19] = t7;
$[20] = t8;
} else {
t8 = $[20];
}
return t8;
}
function _temp2(exitState) {
return exitState.pending ? <Text>Press {exitState.keyName} again to exit</Text> : <Byline><KeyboardShortcutHint shortcut={"\u2191\u2193"} action="navigate" /><KeyboardShortcutHint shortcut="Enter" action="select" /><ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="back" /></Byline>;
}
function _temp(s) {
return s.mcp.tools;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlRleHQiLCJleHRyYWN0TWNwVG9vbERpc3BsYXlOYW1lIiwiZ2V0TWNwRGlzcGxheU5hbWUiLCJmaWx0ZXJUb29sc0J5U2VydmVyIiwidXNlQXBwU3RhdGUiLCJUb29sIiwicGx1cmFsIiwiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IiwiU2VsZWN0IiwiQnlsaW5lIiwiRGlhbG9nIiwiS2V5Ym9hcmRTaG9ydGN1dEhpbnQiLCJTZXJ2ZXJJbmZvIiwiUHJvcHMiLCJzZXJ2ZXIiLCJvblNlbGVjdFRvb2wiLCJ0b29sIiwiaW5kZXgiLCJvbkJhY2siLCJNQ1BUb29sTGlzdFZpZXciLCJ0MCIsIiQiLCJfYyIsIm1jcFRvb2xzIiwiX3RlbXAiLCJ0MSIsImJiMCIsImNsaWVudCIsInR5cGUiLCJ0MiIsIlN5bWJvbCIsImZvciIsIm5hbWUiLCJzZXJ2ZXJUb29scyIsInQzIiwidG9vbE5hbWUiLCJmdWxsRGlzcGxheU5hbWUiLCJ1c2VyRmFjaW5nTmFtZSIsImRpc3BsYXlOYW1lIiwiaXNSZWFkT25seSIsImlzRGVzdHJ1Y3RpdmUiLCJpc09wZW5Xb3JsZCIsImFubm90YXRpb25zIiwicHVzaCIsImxhYmVsIiwidmFsdWUiLCJ0b1N0cmluZyIsImRlc2NyaXB0aW9uIiwibGVuZ3RoIiwiam9pbiIsInVuZGVmaW5lZCIsImRlc2NyaXB0aW9uQ29sb3IiLCJtYXAiLCJ0b29sT3B0aW9ucyIsInQ0IiwidDUiLCJ0NiIsInQ3IiwiaW5kZXhfMCIsInBhcnNlSW50IiwidG9vbF8wIiwidDgiLCJfdGVtcDIiLCJleGl0U3RhdGUiLCJwZW5kaW5nIiwia2V5TmFtZSIsInMiLCJtY3AiLCJ0b29scyJdLCJzb3VyY2VzIjpbIk1DUFRvb2xMaXN0Vmlldy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgVGV4dCB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB7XG4gIGV4dHJhY3RNY3BUb29sRGlzcGxheU5hbWUsXG4gIGdldE1jcERpc3BsYXlOYW1lLFxufSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9tY3AvbWNwU3RyaW5nVXRpbHMuanMnXG5pbXBvcnQgeyBmaWx0ZXJUb29sc0J5U2VydmVyIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvbWNwL3V0aWxzLmpzJ1xuaW1wb3J0IHsgdXNlQXBwU3RhdGUgfSBmcm9tICcuLi8uLi9zdGF0ZS9BcHBTdGF0ZS5qcydcbmltcG9ydCB0eXBlIHsgVG9vbCB9IGZyb20gJy4uLy4uL1Rvb2wuanMnXG5pbXBvcnQgeyBwbHVyYWwgfSBmcm9tICcuLi8uLi91dGlscy9zdHJpbmdVdGlscy5qcydcbmltcG9ydCB7IENvbmZpZ3VyYWJsZVNob3J0Y3V0SGludCB9IGZyb20gJy4uL0NvbmZpZ3VyYWJsZVNob3J0Y3V0SGludC5qcydcbmltcG9ydCB7IFNlbGVjdCB9IGZyb20gJy4uL0N1c3RvbVNlbGVjdC9pbmRleC5qcydcbmltcG9ydCB7IEJ5bGluZSB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vQnlsaW5lLmpzJ1xuaW1wb3J0IHsgRGlhbG9nIH0gZnJvbSAnLi4vZGVzaWduLXN5c3RlbS9EaWFsb2cuanMnXG5pbXBvcnQgeyBLZXlib2FyZFNob3J0Y3V0SGludCB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vS2V5Ym9hcmRTaG9ydGN1dEhpbnQuanMnXG5pbXBvcnQgdHlwZSB7IFNlcnZlckluZm8gfSBmcm9tICcuL3R5cGVzLmpzJ1xuXG50eXBlIFByb3BzID0ge1xuICBzZXJ2ZXI6IFNlcnZlckluZm9cbiAgb25TZWxlY3RUb29sOiAodG9vbDogVG9vbCwgaW5kZXg6IG51bWJlcikgPT4gdm9pZFxuICBvbkJhY2s6ICgpID0+IHZvaWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIE1DUFRvb2xMaXN0Vmlldyh7XG4gIHNlcnZlcixcbiAgb25TZWxlY3RUb29sLFxuICBvbkJhY2ssXG59OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IG1jcFRvb2xzID0gdXNlQXBwU3RhdGUocyA9PiBzLm1jcC50b29scylcblxuICBjb25zdCBzZXJ2ZXJUb29scyA9IFJlYWN0LnVzZU1lbW8oKCkgPT4ge1xuICAgIGlmIChzZXJ2ZXIuY2xpZW50LnR5cGUgIT09ICdjb25uZWN0ZWQnKSByZXR1cm4gW11cbiAgICByZXR1cm4gZmlsdGVyVG9vbHNCeVNlcnZlcihtY3BUb29scywgc2VydmVyLm5hbWUpXG4gIH0sIFtzZXJ2ZXIsIG1jcFRvb2xzXSlcblxuICBjb25zdCB0b29sT3B0aW9ucyA9IHNlcnZlclRvb2xzLm1hcCgodG9vbCwgaW5kZXgpID0+IHtcbiAgICBjb25zdCB0b29sTmFtZSA9IGdldE1jcERpc3BsYXlOYW1lKHRvb2wubmFtZSwgc2VydmVyLm5hbWUpXG4gICAgY29uc3QgZnVsbERpc3BsYXlOYW1lID0gdG9vbC51c2VyRmFjaW5nTmFtZVxuICAgICAgPyB0b29sLnVzZXJGYWNpbmdOYW1lKHt9KVxuICAgICAgOiB0b29sTmFtZVxuICAgIC8vIEV4dHJhY3QganVzdCB0aGUgdG9vbCBkaXNwbGF5IG5hbWUgd2l0aG91dCBzZXJ2ZXIgcHJlZml4XG4gICAgY29uc3QgZGlzcGxheU5hbWUgPSBleHRyYWN0TWNwVG9vbERpc3BsYXlOYW1lKGZ1bGxEaXNwbGF5TmFtZSlcblxuICAgIGNvbnN0IGlzUmVhZE9ubHkgPSB0b29sLmlzUmVhZE9ubHk/Lih7fSkgPz8gZmFsc2VcbiAgICBjb25zdCBpc0Rlc3RydWN0aXZlID0gdG9vbC5pc0Rlc3RydWN0aXZlPy4oe30pID8/IGZhbHNlXG4gICAgY29uc3QgaXNPcGVuV29ybGQgPSB0b29sLmlzT3BlbldvcmxkPy4oe30pID8/IGZhbHNlXG5cbiAgICBjb25zdCBhbm5vdGF0aW9ucyA9IFtdXG4gICAgaWYgKGlzUmVhZE9ubHkpIGFubm90YXRpb25zLnB1c2goJ3JlYWQtb25seScpXG4gICAgaWYgKGlzRGVzdHJ1Y3RpdmUpIGFubm90YXRpb25zLnB1c2goJ2Rlc3RydWN0aXZlJylcbiAgICBpZiAoaXNPcGVuV29ybGQpIGFubm90YXRpb25zLnB1c2goJ29wZW4td29ybGQnKVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGxhYmVsOiBkaXNwbGF5TmFtZSxcbiAgICAgIHZhbHVlOiBpbmRleC50b1N0cmluZygpLFxuICAgICAgZGVzY3JpcHRpb246IGFubm90YXRpb25zLmxlbmd0aCA+IDAgPyBhbm5vdGF0aW9ucy5qb2luKCcsICcpIDogdW5kZWZpbmVkLFxuICAgICAgZGVzY3JpcHRpb25Db2xvcjogaXNEZXN0cnVjdGl2ZVxuICAgICAgICA/ICdlcnJvcidcbiAgICAgICAgOiBpc1JlYWRPbmx5XG4gICAgICAgICAgPyAnc3VjY2VzcydcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICB9XG4gIH0pXG5cbiAgcmV0dXJuIChcbiAgICA8RGlhbG9nXG4gICAgICB0aXRsZT17YFRvb2xzIGZvciAke3NlcnZlci5uYW1lfWB9XG4gICAgICBzdWJ0aXRsZT17YCR7c2VydmVyVG9vbHMubGVuZ3RofSAke3BsdXJhbChzZXJ2ZXJUb29scy5sZW5ndGgsICd0b29sJyl9YH1cbiAgICAgIG9uQ2FuY2VsPXtvbkJhY2t9XG4gICAgICBpbnB1dEd1aWRlPXtleGl0U3RhdGUgPT5cbiAgICAgICAgZXhpdFN0YXRlLnBlbmRpbmcgPyAoXG4gICAgICAgICAgPFRleHQ+UHJlc3Mge2V4aXRTdGF0ZS5rZXlOYW1lfSBhZ2FpbiB0byBleGl0PC9UZXh0PlxuICAgICAgICApIDogKFxuICAgICAgICAgIDxCeWxpbmU+XG4gICAgICAgICAgICA8S2V5Ym9hcmRTaG9ydGN1dEhpbnQgc2hvcnRjdXQ9XCLihpHihpNcIiBhY3Rpb249XCJuYXZpZ2F0ZVwiIC8+XG4gICAgICAgICAgICA8S2V5Ym9hcmRTaG9ydGN1dEhpbnQgc2hvcnRjdXQ9XCJFbnRlclwiIGFjdGlvbj1cInNlbGVjdFwiIC8+XG4gICAgICAgICAgICA8Q29uZmlndXJhYmxlU2hvcnRjdXRIaW50XG4gICAgICAgICAgICAgIGFjdGlvbj1cImNvbmZpcm06bm9cIlxuICAgICAgICAgICAgICBjb250ZXh0PVwiQ29uZmlybWF0aW9uXCJcbiAgICAgICAgICAgICAgZmFsbGJhY2s9XCJFc2NcIlxuICAgICAgICAgICAgICBkZXNjcmlwdGlvbj1cImJhY2t Line truncated
+213
View File
@@ -0,0 +1,213 @@
import { c as _c } from "react/compiler-runtime";
import React, { useMemo } from 'react';
import { getMcpConfigsByScope } from 'src/services/mcp/config.js';
import type { ConfigScope } from 'src/services/mcp/types.js';
import { describeMcpConfigFilePath, getScopeLabel } from 'src/services/mcp/utils.js';
import type { ValidationError } from 'src/utils/settings/validation.js';
import { Box, Link, Text } from '../../ink.js';
function McpConfigErrorSection(t0) {
const $ = _c(26);
const {
scope,
parsingErrors,
warnings
} = t0;
const hasErrors = parsingErrors.length > 0;
const hasWarnings = warnings.length > 0;
if (!hasErrors && !hasWarnings) {
return null;
}
let t1;
if ($[0] !== hasErrors || $[1] !== hasWarnings) {
t1 = (hasErrors || hasWarnings) && <Text color={hasErrors ? "error" : "warning"}>[{hasErrors ? "Failed to parse" : "Contains warnings"}]{" "}</Text>;
$[0] = hasErrors;
$[1] = hasWarnings;
$[2] = t1;
} else {
t1 = $[2];
}
let t2;
if ($[3] !== scope) {
t2 = getScopeLabel(scope);
$[3] = scope;
$[4] = t2;
} else {
t2 = $[4];
}
let t3;
if ($[5] !== t2) {
t3 = <Text>{t2}</Text>;
$[5] = t2;
$[6] = t3;
} else {
t3 = $[6];
}
let t4;
if ($[7] !== t1 || $[8] !== t3) {
t4 = <Box>{t1}{t3}</Box>;
$[7] = t1;
$[8] = t3;
$[9] = t4;
} else {
t4 = $[9];
}
let t5;
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
t5 = <Text dimColor={true}>Location: </Text>;
$[10] = t5;
} else {
t5 = $[10];
}
let t6;
if ($[11] !== scope) {
t6 = describeMcpConfigFilePath(scope);
$[11] = scope;
$[12] = t6;
} else {
t6 = $[12];
}
let t7;
if ($[13] !== t6) {
t7 = <Box>{t5}<Text dimColor={true}>{t6}</Text></Box>;
$[13] = t6;
$[14] = t7;
} else {
t7 = $[14];
}
let t8;
if ($[15] !== parsingErrors) {
t8 = parsingErrors.map(_temp);
$[15] = parsingErrors;
$[16] = t8;
} else {
t8 = $[16];
}
let t9;
if ($[17] !== warnings) {
t9 = warnings.map(_temp2);
$[17] = warnings;
$[18] = t9;
} else {
t9 = $[18];
}
let t10;
if ($[19] !== t8 || $[20] !== t9) {
t10 = <Box marginLeft={1} flexDirection="column">{t8}{t9}</Box>;
$[19] = t8;
$[20] = t9;
$[21] = t10;
} else {
t10 = $[21];
}
let t11;
if ($[22] !== t10 || $[23] !== t4 || $[24] !== t7) {
t11 = <Box flexDirection="column" marginTop={1}>{t4}{t7}{t10}</Box>;
$[22] = t10;
$[23] = t4;
$[24] = t7;
$[25] = t11;
} else {
t11 = $[25];
}
return t11;
}
function _temp2(warning, i_0) {
const serverName_0 = warning.mcpErrorMetadata?.serverName;
return <Box key={`warning-${i_0}`}><Text><Text dimColor={true}>└ </Text><Text color="warning">[Warning]</Text><Text dimColor={true}>{" "}{serverName_0 && `[${serverName_0}] `}{warning.path && warning.path !== "" ? `${warning.path}: ` : ""}{warning.message}</Text></Text></Box>;
}
function _temp(error, i) {
const serverName = error.mcpErrorMetadata?.serverName;
return <Box key={`error-${i}`}><Text><Text dimColor={true}>└ </Text><Text color="error">[Error]</Text><Text dimColor={true}>{" "}{serverName && `[${serverName}] `}{error.path && error.path !== "" ? `${error.path}: ` : ""}{error.message}</Text></Text></Box>;
}
export function McpParsingWarnings() {
const $ = _c(6);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = {
scope: "user",
config: getMcpConfigsByScope("user")
};
$[0] = t0;
} else {
t0 = $[0];
}
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = {
scope: "project",
config: getMcpConfigsByScope("project")
};
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = {
scope: "local",
config: getMcpConfigsByScope("local")
};
$[2] = t2;
} else {
t2 = $[2];
}
let t3;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t3 = [t0, t1, t2, {
scope: "enterprise",
config: getMcpConfigsByScope("enterprise")
}];
$[3] = t3;
} else {
t3 = $[3];
}
const scopes = t3 satisfies Array<{
scope: ConfigScope;
config: {
errors: ValidationError[];
};
}>;
const hasParsingErrors = scopes.some(_temp3);
const hasWarnings = scopes.some(_temp4);
if (!hasParsingErrors && !hasWarnings) {
return null;
}
let t4;
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
t4 = <Text bold={true}>MCP Config Diagnostics</Text>;
$[4] = t4;
} else {
t4 = $[4];
}
let t5;
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
t5 = <Box flexDirection="column" marginTop={1} marginBottom={1}>{t4}<Box marginTop={1}><Text dimColor={true}>For help configuring MCP servers, see:{" "}<Link url="https://code.claude.com/docs/en/mcp">https://code.claude.com/docs/en/mcp</Link></Text></Box>{scopes.map(_temp5)}</Box>;
$[5] = t5;
} else {
t5 = $[5];
}
return t5;
}
function _temp5(t0) {
const {
scope,
config: config_1
} = t0;
return <McpConfigErrorSection key={scope} scope={scope} parsingErrors={filterErrors(config_1.errors, "fatal")} warnings={filterErrors(config_1.errors, "warning")} />;
}
function _temp4(t0) {
const {
config: config_0
} = t0;
return filterErrors(config_0.errors, "warning").length > 0;
}
function _temp3(t0) {
const {
config
} = t0;
return filterErrors(config.errors, "fatal").length > 0;
}
function filterErrors(errors: ValidationError[], severity: 'fatal' | 'warning'): ValidationError[] {
return errors.filter(e => e.mcpErrorMetadata?.severity === severity);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZU1lbW8iLCJnZXRNY3BDb25maWdzQnlTY29wZSIsIkNvbmZpZ1Njb3BlIiwiZGVzY3JpYmVNY3BDb25maWdGaWxlUGF0aCIsImdldFNjb3BlTGFiZWwiLCJWYWxpZGF0aW9uRXJyb3IiLCJCb3giLCJMaW5rIiwiVGV4dCIsIk1jcENvbmZpZ0Vycm9yU2VjdGlvbiIsInQwIiwiJCIsIl9jIiwic2NvcGUiLCJwYXJzaW5nRXJyb3JzIiwid2FybmluZ3MiLCJoYXNFcnJvcnMiLCJsZW5ndGgiLCJoYXNXYXJuaW5ncyIsInQxIiwidDIiLCJ0MyIsInQ0IiwidDUiLCJTeW1ib2wiLCJmb3IiLCJ0NiIsInQ3IiwidDgiLCJtYXAiLCJfdGVtcCIsInQ5IiwiX3RlbXAyIiwidDEwIiwidDExIiwid2FybmluZyIsImlfMCIsInNlcnZlck5hbWVfMCIsIm1jcEVycm9yTWV0YWRhdGEiLCJzZXJ2ZXJOYW1lIiwiaSIsInBhdGgiLCJtZXNzYWdlIiwiZXJyb3IiLCJNY3BQYXJzaW5nV2FybmluZ3MiLCJjb25maWciLCJzY29wZXMiLCJBcnJheSIsImVycm9ycyIsImhhc1BhcnNpbmdFcnJvcnMiLCJzb21lIiwiX3RlbXAzIiwiX3RlbXA0IiwiX3RlbXA1IiwiY29uZmlnXzEiLCJmaWx0ZXJFcnJvcnMiLCJjb25maWdfMCIsInNldmVyaXR5IiwiZmlsdGVyIiwiZSJdLCJzb3VyY2VzIjpbIk1jcFBhcnNpbmdXYXJuaW5ncy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0LCB7IHVzZU1lbW8gfSBmcm9tICdyZWFjdCdcbmltcG9ydCB7IGdldE1jcENvbmZpZ3NCeVNjb3BlIH0gZnJvbSAnc3JjL3NlcnZpY2VzL21jcC9jb25maWcuanMnXG5pbXBvcnQgdHlwZSB7IENvbmZpZ1Njb3BlIH0gZnJvbSAnc3JjL3NlcnZpY2VzL21jcC90eXBlcy5qcydcbmltcG9ydCB7XG4gIGRlc2NyaWJlTWNwQ29uZmlnRmlsZVBhdGgsXG4gIGdldFNjb3BlTGFiZWwsXG59IGZyb20gJ3NyYy9zZXJ2aWNlcy9tY3AvdXRpbHMuanMnXG5pbXBvcnQgdHlwZSB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gJ3NyYy91dGlscy9zZXR0aW5ncy92YWxpZGF0aW9uLmpzJ1xuaW1wb3J0IHsgQm94LCBMaW5rLCBUZXh0IH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuXG5mdW5jdGlvbiBNY3BDb25maWdFcnJvclNlY3Rpb24oe1xuICBzY29wZSxcbiAgcGFyc2luZ0Vycm9ycyxcbiAgd2FybmluZ3MsXG59OiB7XG4gIHNjb3BlOiBDb25maWdTY29wZVxuICBwYXJzaW5nRXJyb3JzOiBWYWxpZGF0aW9uRXJyb3JbXVxuICB3YXJuaW5nczogVmFsaWRhdGlvbkVycm9yW11cbn0pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBoYXNFcnJvcnMgPSBwYXJzaW5nRXJyb3JzLmxlbmd0aCA+IDBcbiAgY29uc3QgaGFzV2FybmluZ3MgPSB3YXJuaW5ncy5sZW5ndGggPiAwXG5cbiAgaWYgKCFoYXNFcnJvcnMgJiYgIWhhc1dhcm5pbmdzKSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPEJveCBmbGV4RGlyZWN0aW9uPVwiY29sdW1uXCIgbWFyZ2luVG9wPXsxfT5cbiAgICAgIDxCb3g+XG4gICAgICAgIHsoaGFzRXJyb3JzIHx8IGhhc1dhcm5pbmdzKSAmJiAoXG4gICAgICAgICAgPFRleHQgY29sb3I9e2hhc0Vycm9ycyA/ICdlcnJvcicgOiAnd2FybmluZyd9PlxuICAgICAgICAgICAgW3toYXNFcnJvcnMgPyAnRmFpbGVkIHRvIHBhcnNlJyA6ICdDb250YWlucyB3YXJuaW5ncyd9XXsnICd9XG4gICAgICAgICAgPC9UZXh0PlxuICAgICAgICApfVxuICAgICAgICA8VGV4dD57Z2V0U2NvcGVMYWJlbChzY29wZSl9PC9UZXh0PlxuICAgICAgPC9Cb3g+XG4gICAgICA8Qm94PlxuICAgICAgICA8VGV4dCBkaW1Db2xvcj5Mb2NhdGlvbjogPC9UZXh0PlxuICAgICAgICA8VGV4dCBkaW1Db2xvcj57ZGVzY3JpYmVNY3BDb25maWdGaWxlUGF0aChzY29wZSl9PC9UZXh0PlxuICAgICAgPC9Cb3g+XG4gICAgICA8Qm94IG1hcmdpbkxlZnQ9ezF9IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIj5cbiAgICAgICAge3BhcnNpbmdFcnJvcnMubWFwKChlcnJvciwgaSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHNlcnZlck5hbWUgPSBlcnJvci5tY3BFcnJvck1ldGFkYXRhPy5zZXJ2ZXJOYW1lXG4gICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIDxCb3gga2V5PXtgZXJyb3ItJHtpfWB9PlxuICAgICAgICAgICAgICA8VGV4dD5cbiAgICAgICAgICAgICAgICA8VGV4dCBkaW1Db2xvcj7ilJQgPC9UZXh0PlxuICAgICAgICAgICAgICAgIDxUZXh0IGNvbG9yPVwiZXJyb3JcIj5bRXJyb3JdPC9UZXh0PlxuICAgICAgICAgICAgICAgIDxUZXh0IGRpbUNvbG9yPlxuICAgICAgICAgICAgICAgICAgeycgJ31cbiAgICAgICAgICAgICAgICAgIHtzZXJ2ZXJOYW1lICYmIGBbJHtzZXJ2ZXJOYW1lfV0gYH1cbiAgICAgICAgICAgICAgICAgIHtlcnJvci5wYXRoICYmIGVycm9yLnBhdGggIT09ICcnID8gYCR7ZXJyb3IucGF0aH06IGAgOiAnJ31cbiAgICAgICAgICAgICAgICAgIHtlcnJvci5tZXNzYWdlfVxuICAgICAgICAgICAgICAgIDwvVGV4dD5cbiAgICAgICAgICAgICAgPC9UZXh0PlxuICAgICAgICAgICAgPC9Cb3g+XG4gICAgICAgICAgKVxuICAgICAgICB9KX1cbiAgICAgICAge3dhcm5pbmdzLm1hcCgod2FybmluZywgaSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHNlcnZlck5hbWUgPSB3YXJuaW5nLm1jcEVycm9yTWV0YWRhdGE/LnNlcnZlck5hbWVcblxuICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8Qm94IGtleT17YHdhcm5pbmctJHtpfWB9PlxuICAgICAgICAgICAgICA8VGV4dD5cbiAgICAgICAgICAgICAgICA8VGV4dCBkaW1Db2xvcj7ilJQgPC9UZXh0PlxuICAgICAgICAgICAgICAgIDxUZXh0IGNvbG9yPVwid2FybmluZ1wiPltXYXJuaW5nXTwvVGV4dD5cbiAgICAgICAgICAgICAgICA8VGV4dCBkaW1Db2xvcj5cbiAgICAgICAgICAgICAgICAgIHsnICd9XG4gICAgICAgICAgICAgICAgICB7c2VydmVyTmFtZSAmJiBgWyR7c2VydmVyTmFtZX1dIGB9XG4gICAgICAgICAgICAgICAgICB7d2FybmluZy5wYXRoICYmIHdhcm5pbmcucGF0aCAhPT0gJydcbiAgICAgICAgICAgICAgICAgICAgPyBgJHt3YXJuaW5nLnBhdGh9OiBgXG4gICAgICAgICAgICAgICAgICAgIDogJyd9XG4gICAgICAgICAgICAgICAgICB7d2FybmluZy5tZXNzYWdlfVxuICAgICAgICAgICAgICAgIDwvVGV4dD5cbiAgICAgICAgICAgICAgPC9UZXh0PlxuICAgICAgICAgICAgPC9Cb3g+XG4gICAgICAgICAgKVxuICAgICAgICB9KX1cbiAgICAgIDwvQm94PlxuICAgIDwvQm94PlxuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBNY3BQYXJzaW5nV2FybmluZ3MoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgLy8gQ29uZmlnIGZpbGVzIGRvbid0IGNoYW5nZSBkdXJpbmcgZGlhbG9nIGxpZmV0aW1lOyByZWFkIG9uY2Ugb24gbW91bnRcbiAgLy8gdG8gYXZvaWQgYmxvY2tpbmcgZmlsZSBJTyBvbiBldmVyeSByZS1yZW5kZXIuXG4gIGNvbnN0IHNjb3BlcyA9IHVzZU1lbW8oXG4gICAgKCkgPT5cbiAgICAgIFtcbiAgICAgICAgeyBzY29wZTogJ3VzZXInLCBjb25maWc6IGdldE1jcENvbmZpZ3NCeVNjb3BlKCd1c2VyJykgfSxcbiAgICAgICAgeyBzY29wZTogJ3Byb2plY3QnLCBjb25maWc6IGdldE1jcENvbmZpZ3NCeVNjb3BlKCdwcm9qZWN0JykgfSxcbiAgICAgICAgeyBzY29wZTogJ2xvY2FsJywgY29uZmlnOiBnZXRNY3BDb25maWdzQnlTY29wZSgnbG9jYWwnKSB9LFxuICAgICAgICB7IHNjb3BlOiAnZW5 Line truncated
+9
View File
@@ -0,0 +1,9 @@
export { MCPAgentServerMenu } from './MCPAgentServerMenu.js'
export { MCPListPanel } from './MCPListPanel.js'
export { MCPReconnect } from './MCPReconnect.js'
export { MCPRemoteServerMenu } from './MCPRemoteServerMenu.js'
export { MCPSettings } from './MCPSettings.js'
export { MCPStdioServerMenu } from './MCPStdioServerMenu.js'
export { MCPToolDetailView } from './MCPToolDetailView.js'
export { MCPToolListView } from './MCPToolListView.js'
export type { AgentMcpServerInfo, MCPViewState, ServerInfo } from './types.js'
@@ -0,0 +1,49 @@
import type { Command } from '../../../commands.js';
import type { MCPServerConnection, ServerResource } from '../../../services/mcp/types.js';
import type { Tool } from '../../../Tool.js';
export interface ReconnectResult {
message: string;
success: boolean;
}
/**
* Handles the result of a reconnect attempt and returns an appropriate user message
*/
export function handleReconnectResult(result: {
client: MCPServerConnection;
tools: Tool[];
commands: Command[];
resources?: ServerResource[];
}, serverName: string): ReconnectResult {
switch (result.client.type) {
case 'connected':
return {
message: `Reconnected to ${serverName}.`,
success: true
};
case 'needs-auth':
return {
message: `${serverName} requires authentication. Use the 'Authenticate' option.`,
success: false
};
case 'failed':
return {
message: `Failed to reconnect to ${serverName}.`,
success: false
};
default:
return {
message: `Unknown result when reconnecting to ${serverName}.`,
success: false
};
}
}
/**
* Handles errors from reconnect attempts
*/
export function handleReconnectError(error: unknown, serverName: string): string {
const errorMessage = error instanceof Error ? error.message : String(error);
return `Error reconnecting to ${serverName}: ${errorMessage}`;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDb21tYW5kIiwiTUNQU2VydmVyQ29ubmVjdGlvbiIsIlNlcnZlclJlc291cmNlIiwiVG9vbCIsIlJlY29ubmVjdFJlc3VsdCIsIm1lc3NhZ2UiLCJzdWNjZXNzIiwiaGFuZGxlUmVjb25uZWN0UmVzdWx0IiwicmVzdWx0IiwiY2xpZW50IiwidG9vbHMiLCJjb21tYW5kcyIsInJlc291cmNlcyIsInNlcnZlck5hbWUiLCJ0eXBlIiwiaGFuZGxlUmVjb25uZWN0RXJyb3IiLCJlcnJvciIsImVycm9yTWVzc2FnZSIsIkVycm9yIiwiU3RyaW5nIl0sInNvdXJjZXMiOlsicmVjb25uZWN0SGVscGVycy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSAnLi4vLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgdHlwZSB7XG4gIE1DUFNlcnZlckNvbm5lY3Rpb24sXG4gIFNlcnZlclJlc291cmNlLFxufSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9tY3AvdHlwZXMuanMnXG5pbXBvcnQgdHlwZSB7IFRvb2wgfSBmcm9tICcuLi8uLi8uLi9Ub29sLmpzJ1xuXG5leHBvcnQgaW50ZXJmYWNlIFJlY29ubmVjdFJlc3VsdCB7XG4gIG1lc3NhZ2U6IHN0cmluZ1xuICBzdWNjZXNzOiBib29sZWFuXG59XG5cbi8qKlxuICogSGFuZGxlcyB0aGUgcmVzdWx0IG9mIGEgcmVjb25uZWN0IGF0dGVtcHQgYW5kIHJldHVybnMgYW4gYXBwcm9wcmlhdGUgdXNlciBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYW5kbGVSZWNvbm5lY3RSZXN1bHQoXG4gIHJlc3VsdDoge1xuICAgIGNsaWVudDogTUNQU2VydmVyQ29ubmVjdGlvblxuICAgIHRvb2xzOiBUb29sW11cbiAgICBjb21tYW5kczogQ29tbWFuZFtdXG4gICAgcmVzb3VyY2VzPzogU2VydmVyUmVzb3VyY2VbXVxuICB9LFxuICBzZXJ2ZXJOYW1lOiBzdHJpbmcsXG4pOiBSZWNvbm5lY3RSZXN1bHQge1xuICBzd2l0Y2ggKHJlc3VsdC5jbGllbnQudHlwZSkge1xuICAgIGNhc2UgJ2Nvbm5lY3RlZCc6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBgUmVjb25uZWN0ZWQgdG8gJHtzZXJ2ZXJOYW1lfS5gLFxuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgfVxuXG4gICAgY2FzZSAnbmVlZHMtYXV0aCc6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBgJHtzZXJ2ZXJOYW1lfSByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gVXNlIHRoZSAnQXV0aGVudGljYXRlJyBvcHRpb24uYCxcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICB9XG5cbiAgICBjYXNlICdmYWlsZWQnOlxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byByZWNvbm5lY3QgdG8gJHtzZXJ2ZXJOYW1lfS5gLFxuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgIH1cblxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBgVW5rbm93biByZXN1bHQgd2hlbiByZWNvbm5lY3RpbmcgdG8gJHtzZXJ2ZXJOYW1lfS5gLFxuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEhhbmRsZXMgZXJyb3JzIGZyb20gcmVjb25uZWN0IGF0dGVtcHRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYW5kbGVSZWNvbm5lY3RFcnJvcihcbiAgZXJyb3I6IHVua25vd24sXG4gIHNlcnZlck5hbWU6IHN0cmluZyxcbik6IHN0cmluZyB7XG4gIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICByZXR1cm4gYEVycm9yIHJlY29ubmVjdGluZyB0byAke3NlcnZlck5hbWV9OiAke2Vycm9yTWVzc2FnZX1gXG59XG4iXSwibWFwcGluZ3MiOiJBQUFBLGNBQWNBLE9BQU8sUUFBUSxzQkFBc0I7QUFDbkQsY0FDRUMsbUJBQW1CLEVBQ25CQyxjQUFjLFFBQ1QsZ0NBQWdDO0FBQ3ZDLGNBQWNDLElBQUksUUFBUSxrQkFBa0I7QUFFNUMsT0FBTyxVQUFVQyxlQUFlLENBQUM7RUFDL0JDLE9BQU8sRUFBRSxNQUFNO0VBQ2ZDLE9BQU8sRUFBRSxPQUFPO0FBQ2xCOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sU0FBU0MscUJBQXFCQSxDQUNuQ0MsTUFBTSxFQUFFO0VBQ05DLE1BQU0sRUFBRVIsbUJBQW1CO0VBQzNCUyxLQUFLLEVBQUVQLElBQUksRUFBRTtFQUNiUSxRQUFRLEVBQUVYLE9BQU8sRUFBRTtFQUNuQlksU0FBUyxDQUFDLEVBQUVWLGNBQWMsRUFBRTtBQUM5QixDQUFDLEVBQ0RXLFVBQVUsRUFBRSxNQUFNLENBQ25CLEVBQUVULGVBQWUsQ0FBQztFQUNqQixRQUFRSSxNQUFNLENBQUNDLE1BQU0sQ0FBQ0ssSUFBSTtJQUN4QixLQUFLLFdBQVc7TUFDZCxPQUFPO1FBQ0xULE9BQU8sRUFBRSxrQkFBa0JRLFVBQVUsR0FBRztRQUN4Q1AsT0FBTyxFQUFFO01BQ1gsQ0FBQztJQUVILEtBQUssWUFBWTtNQUNmLE9BQU87UUFDTEQsT0FBTyxFQUFFLEdBQUdRLFVBQVUsMERBQTBEO1FBQ2hGUCxPQUFPLEVBQUU7TUFDWCxDQUFDO0lBRUgsS0FBSyxRQUFRO01BQ1gsT0FBTztRQUNMRCxPQUFPLEVBQUUsMEJBQTBCUSxVQUFVLEdBQUc7UUFDaERQLE9BQU8sRUFBRTtNQUNYLENBQUM7SUFFSDtNQUNFLE9BQU87UUFDTEQsT0FBTyxFQUFFLHVDQUF1Q1EsVUFBVSxHQUFHO1FBQzdEUCxPQUFPLEVBQUU7TUFDWCxDQUFDO0VBQ0w7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLFNBQVNTLG9CQUFvQkEsQ0FDbENDLEtBQUssRUFBRSxPQUFPLEVBQ2RILFVBQVUsRUFBRSxNQUFNLENBQ25CLEVBQUUsTUFBTSxDQUFDO0VBQ1IsTUFBTUksWUFBWSxHQUFHRCxLQUFLLFlBQVlFLEtBQUssR0FBR0YsS0FBSyxDQUFDWCxPQUFPLEdBQUdjLE1BQU0sQ0FBQ0gsS0FBSyxDQUFDO0VBQzNFLE9BQU8seUJBQXlCSCxVQUFVLEtBQUtJLFlBQVksRUFBRTtBQUMvRCIsImlnbm9yZUxpc3QiOltdfQ==