mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 13:55:50 +00:00
115 lines
3.9 KiB
TypeScript
115 lines
3.9 KiB
TypeScript
import React, { useCallback, useEffect, useState } from 'react';
|
|
import { gracefulShutdown } from 'src/utils/gracefulShutdown.js';
|
|
import { writeToStdout } from 'src/utils/process.js';
|
|
import { Box, color, Text, useTheme, Byline, Dialog, KeyboardShortcutHint } from '@anthropic/ink';
|
|
import { addMcpConfig, getAllMcpConfigs } from '../services/mcp/config.js';
|
|
import type { ConfigScope, McpServerConfig, ScopedMcpServerConfig } from '../services/mcp/types.js';
|
|
import { plural } from '../utils/stringUtils.js';
|
|
import { ConfigurableShortcutHint } from './ConfigurableShortcutHint.js';
|
|
import { SelectMulti } from './CustomSelect/SelectMulti.js';
|
|
|
|
type Props = {
|
|
servers: Record<string, McpServerConfig>;
|
|
scope: ConfigScope;
|
|
onDone(): void;
|
|
};
|
|
|
|
export function MCPServerDesktopImportDialog({ servers, scope, onDone }: Props): React.ReactNode {
|
|
const serverNames = Object.keys(servers);
|
|
const [existingServers, setExistingServers] = useState<Record<string, ScopedMcpServerConfig>>({});
|
|
|
|
useEffect(() => {
|
|
void getAllMcpConfigs().then(({ servers }) => setExistingServers(servers));
|
|
}, []);
|
|
|
|
const collisions = serverNames.filter(name => existingServers[name] !== undefined);
|
|
|
|
async function onSubmit(selectedServers: string[]) {
|
|
let importedCount = 0;
|
|
|
|
for (const serverName of selectedServers) {
|
|
const serverConfig = servers[serverName];
|
|
if (serverConfig) {
|
|
// If the server name already exists, find a new name with _1, _2, etc.
|
|
let finalName = serverName;
|
|
if (existingServers[finalName] !== undefined) {
|
|
let counter = 1;
|
|
while (existingServers[`${serverName}_${counter}`] !== undefined) {
|
|
counter++;
|
|
}
|
|
finalName = `${serverName}_${counter}`;
|
|
}
|
|
|
|
await addMcpConfig(finalName, serverConfig, scope);
|
|
importedCount++;
|
|
}
|
|
}
|
|
|
|
done(importedCount);
|
|
}
|
|
|
|
const [theme] = useTheme();
|
|
|
|
// Define done before using in useCallback
|
|
const done = useCallback(
|
|
(importedCount: number) => {
|
|
if (importedCount > 0) {
|
|
writeToStdout(
|
|
`\n${color('success', theme)(`Successfully imported ${importedCount} MCP ${plural(importedCount, 'server')} to ${scope} config.`)}\n`,
|
|
);
|
|
} else {
|
|
writeToStdout('\nNo servers were imported.');
|
|
}
|
|
onDone();
|
|
|
|
void gracefulShutdown();
|
|
},
|
|
[theme, scope, onDone],
|
|
);
|
|
|
|
// Handle ESC to cancel (import 0 servers)
|
|
const handleEscCancel = useCallback(() => {
|
|
done(0);
|
|
}, [done]);
|
|
|
|
return (
|
|
<>
|
|
<Dialog
|
|
title="Import MCP Servers from Claude Desktop"
|
|
subtitle={`Found ${serverNames.length} MCP ${plural(serverNames.length, 'server')} in Claude Desktop.`}
|
|
color="success"
|
|
onCancel={handleEscCancel}
|
|
hideInputGuide
|
|
>
|
|
{collisions.length > 0 && (
|
|
<Text color="warning">
|
|
Note: Some servers already exist with the same name. If selected, they will be imported with a numbered
|
|
suffix.
|
|
</Text>
|
|
)}
|
|
<Text>Please select the servers you want to import:</Text>
|
|
|
|
<SelectMulti
|
|
options={serverNames.map(server => ({
|
|
label: `${server}${collisions.includes(server) ? ' (already exists)' : ''}`,
|
|
value: server,
|
|
}))}
|
|
defaultValue={serverNames.filter(name => !collisions.includes(name))} // Only preselect non-colliding servers
|
|
onSubmit={onSubmit}
|
|
onCancel={handleEscCancel}
|
|
hideIndexes
|
|
/>
|
|
</Dialog>
|
|
<Box paddingX={1}>
|
|
<Text dimColor italic>
|
|
<Byline>
|
|
<KeyboardShortcutHint shortcut="Space" action="select" />
|
|
<KeyboardShortcutHint shortcut="Enter" action="confirm" />
|
|
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="cancel" />
|
|
</Byline>
|
|
</Text>
|
|
</Box>
|
|
</>
|
|
);
|
|
}
|