MCPServerApprovalDialog.tsx
1 import React from 'react' 2 import { Box, Text, useInput } from 'ink' 3 import { getTheme } from '../utils/theme.js' 4 import { Select } from '@inkjs/ui' 5 import { 6 saveCurrentProjectConfig, 7 getCurrentProjectConfig, 8 } from '../utils/config.js' 9 import { MCPServerDialogCopy } from './MCPServerDialogCopy.js' 10 import { useExitOnCtrlCD } from '../hooks/useExitOnCtrlCD.js' 11 12 type Props = { 13 serverName: string 14 onDone(): void 15 } 16 17 export function MCPServerApprovalDialog({ 18 serverName, 19 onDone, 20 }: Props): React.ReactNode { 21 const theme = getTheme() 22 function onChange(value: 'yes' | 'no') { 23 const config = getCurrentProjectConfig() 24 switch (value) { 25 case 'yes': { 26 if (!config.approvedMcprcServers) { 27 config.approvedMcprcServers = [] 28 } 29 if (!config.approvedMcprcServers.includes(serverName)) { 30 config.approvedMcprcServers.push(serverName) 31 } 32 saveCurrentProjectConfig(config) 33 onDone() 34 break 35 } 36 case 'no': { 37 if (!config.rejectedMcprcServers) { 38 config.rejectedMcprcServers = [] 39 } 40 if (!config.rejectedMcprcServers.includes(serverName)) { 41 config.rejectedMcprcServers.push(serverName) 42 } 43 saveCurrentProjectConfig(config) 44 onDone() 45 break 46 } 47 } 48 } 49 50 const exitState = useExitOnCtrlCD(() => process.exit(0)) 51 52 useInput((_input, key) => { 53 if (key.escape) { 54 onDone() 55 return 56 } 57 }) 58 59 return ( 60 <> 61 <Box 62 flexDirection="column" 63 gap={1} 64 padding={1} 65 borderStyle="round" 66 borderColor={theme.warning} 67 > 68 <Text bold color={theme.warning}> 69 New MCP Server Detected 70 </Text> 71 <Text> 72 This project contains a .mcprc file with an MCP server that requires 73 your approval: 74 </Text> 75 <Text bold>{serverName}</Text> 76 77 <MCPServerDialogCopy /> 78 79 <Text>Do you want to approve this MCP server?</Text> 80 81 <Select 82 options={[ 83 { label: 'Yes, approve this server', value: 'yes' }, 84 { label: 'No, reject this server', value: 'no' }, 85 ]} 86 onChange={value => onChange(value as 'yes' | 'no')} 87 /> 88 </Box> 89 <Box marginLeft={3}> 90 <Text dimColor> 91 {exitState.pending ? ( 92 <>Press {exitState.keyName} again to exit</> 93 ) : ( 94 <>Enter to confirm ยท Esc to reject</> 95 )} 96 </Text> 97 </Box> 98 </> 99 ) 100 }