@@ -13,7 +13,14 @@ import { HELP_TEXT } from '../../constants';
1313import { useListNavigation , useMultiSelectNavigation } from '../../hooks' ;
1414import { generateUniqueName } from '../../utils' ;
1515import type { AddGatewayTargetConfig , ComputeHost , ExposureMode , TargetLanguage } from './types' ;
16- import { COMPUTE_HOST_OPTIONS , EXPOSURE_MODE_OPTIONS , MCP_TOOL_STEP_LABELS , TARGET_LANGUAGE_OPTIONS } from './types' ;
16+ import {
17+ COMPUTE_HOST_OPTIONS ,
18+ EXPOSURE_MODE_OPTIONS ,
19+ MCP_TOOL_STEP_LABELS ,
20+ SKIP_FOR_NOW ,
21+ SOURCE_OPTIONS ,
22+ TARGET_LANGUAGE_OPTIONS ,
23+ } from './types' ;
1724import { useAddGatewayTargetWizard } from './useAddGatewayTargetWizard' ;
1825import { Box , Text } from 'ink' ;
1926import React , { useMemo } from 'react' ;
@@ -35,6 +42,11 @@ export function AddGatewayTargetScreen({
3542} : AddGatewayTargetScreenProps ) {
3643 const wizard = useAddGatewayTargetWizard ( existingGateways , existingAgents ) ;
3744
45+ const sourceItems : SelectableItem [ ] = useMemo (
46+ ( ) => SOURCE_OPTIONS . map ( o => ( { id : o . id , title : o . title , description : o . description } ) ) ,
47+ [ ]
48+ ) ;
49+
3850 const languageItems : SelectableItem [ ] = useMemo (
3951 ( ) => TARGET_LANGUAGE_OPTIONS . map ( o => ( { id : o . id , title : o . title , description : o . description } ) ) ,
4052 [ ]
@@ -52,7 +64,10 @@ export function AddGatewayTargetScreen({
5264 ) ;
5365
5466 const gatewayItems : SelectableItem [ ] = useMemo (
55- ( ) => existingGateways . map ( g => ( { id : g , title : g } ) ) ,
67+ ( ) => [
68+ ...existingGateways . map ( g => ( { id : g , title : g } ) ) ,
69+ { id : SKIP_FOR_NOW , title : 'Skip for now' , description : 'Create unassigned target' } ,
70+ ] ,
5671 [ existingGateways ]
5772 ) ;
5873
@@ -63,16 +78,24 @@ export function AddGatewayTargetScreen({
6378
6479 const agentItems : SelectableItem [ ] = useMemo ( ( ) => existingAgents . map ( a => ( { id : a , title : a } ) ) , [ existingAgents ] ) ;
6580
81+ const isSourceStep = wizard . step === 'source' ;
6682 const isLanguageStep = wizard . step === 'language' ;
6783 const isExposureStep = wizard . step === 'exposure' ;
6884 const isAgentsStep = wizard . step === 'agents' ;
6985 const isGatewayStep = wizard . step === 'gateway' ;
7086 const isHostStep = wizard . step === 'host' ;
71- const isTextStep = wizard . step === 'name' ;
87+ const isTextStep = wizard . step === 'name' || wizard . step === 'endpoint' ;
7288 const isConfirmStep = wizard . step === 'confirm' ;
7389 const noGatewaysAvailable = isGatewayStep && existingGateways . length === 0 ;
7490 const noAgentsAvailable = isAgentsStep && existingAgents . length === 0 ;
7591
92+ const sourceNav = useListNavigation ( {
93+ items : sourceItems ,
94+ onSelect : item => wizard . setSource ( item . id as 'existing-endpoint' | 'create-new' ) ,
95+ onExit : ( ) => wizard . goBack ( ) ,
96+ isActive : isSourceStep ,
97+ } ) ;
98+
7699 const languageNav = useListNavigation ( {
77100 items : languageItems ,
78101 onSelect : item => wizard . setLanguage ( item . id as TargetLanguage ) ,
@@ -132,6 +155,15 @@ export function AddGatewayTargetScreen({
132155 return (
133156 < Screen title = "Add MCP Tool" onExit = { onExit } helpText = { helpText } headerContent = { headerContent } >
134157 < Panel >
158+ { isSourceStep && (
159+ < WizardSelect
160+ title = "Select source"
161+ description = "How would you like to create this MCP tool?"
162+ items = { sourceItems }
163+ selectedIndex = { sourceNav . selectedIndex }
164+ />
165+ ) }
166+
135167 { isLanguageStep && (
136168 < WizardSelect title = "Select language" items = { languageItems } selectedIndex = { languageNav . selectedIndex } />
137169 ) }
@@ -180,27 +212,54 @@ export function AddGatewayTargetScreen({
180212 { isTextStep && (
181213 < TextInput
182214 key = { wizard . step }
183- prompt = { MCP_TOOL_STEP_LABELS [ wizard . step ] }
184- initialValue = { generateUniqueName ( 'mytool' , existingToolNames ) }
185- onSubmit = { wizard . setName }
215+ prompt = { wizard . step === 'endpoint' ? 'MCP server endpoint URL' : MCP_TOOL_STEP_LABELS [ wizard . step ] }
216+ initialValue = { wizard . step === 'endpoint' ? undefined : generateUniqueName ( 'mytool' , existingToolNames ) }
217+ placeholder = { wizard . step === 'endpoint' ? 'https://example.com/mcp' : undefined }
218+ onSubmit = { wizard . step === 'endpoint' ? wizard . setEndpoint : wizard . setName }
186219 onCancel = { ( ) => ( wizard . currentIndex === 0 ? onExit ( ) : wizard . goBack ( ) ) }
187- schema = { ToolNameSchema }
188- customValidation = { value => ! existingToolNames . includes ( value ) || 'Tool name already exists' }
220+ schema = { wizard . step === 'name' ? ToolNameSchema : undefined }
221+ customValidation = {
222+ wizard . step === 'name'
223+ ? value => ! existingToolNames . includes ( value ) || 'Tool name already exists'
224+ : wizard . step === 'endpoint'
225+ ? value => {
226+ try {
227+ const url = new URL ( value ) ;
228+ if ( url . protocol !== 'http:' && url . protocol !== 'https:' ) {
229+ return 'Endpoint must use http:// or https:// protocol' ;
230+ }
231+ return true ;
232+ } catch {
233+ return 'Must be a valid URL (e.g. https://example.com/mcp)' ;
234+ }
235+ }
236+ : undefined
237+ }
189238 />
190239 ) }
191240
192241 { isConfirmStep && (
193242 < ConfirmReview
194243 fields = { [
195244 { label : 'Name' , value : wizard . config . name } ,
196- { label : 'Language' , value : wizard . config . language } ,
197- { label : 'Exposure' , value : isMcpRuntime ? 'MCP Runtime' : 'Behind Gateway' } ,
245+ {
246+ label : 'Source' ,
247+ value : wizard . config . source === 'existing-endpoint' ? 'Existing endpoint' : 'Create new' ,
248+ } ,
249+ ...( wizard . config . endpoint ? [ { label : 'Endpoint' , value : wizard . config . endpoint } ] : [ ] ) ,
250+ ...( wizard . config . source === 'create-new' ? [ { label : 'Language' , value : wizard . config . language } ] : [ ] ) ,
251+ ...( wizard . config . source === 'create-new'
252+ ? [ { label : 'Exposure' , value : isMcpRuntime ? 'MCP Runtime' : 'Behind Gateway' } ]
253+ : [ ] ) ,
198254 ...( isMcpRuntime && wizard . config . selectedAgents . length > 0
199255 ? [ { label : 'Agents' , value : wizard . config . selectedAgents . join ( ', ' ) } ]
200256 : [ ] ) ,
201257 ...( ! isMcpRuntime && wizard . config . gateway ? [ { label : 'Gateway' , value : wizard . config . gateway } ] : [ ] ) ,
202- { label : 'Host' , value : wizard . config . host } ,
203- { label : 'Source' , value : wizard . config . sourcePath } ,
258+ ...( ! isMcpRuntime && ! wizard . config . gateway
259+ ? [ { label : 'Gateway' , value : '(none - assign later)' } ]
260+ : [ ] ) ,
261+ ...( wizard . config . source === 'create-new' ? [ { label : 'Host' , value : wizard . config . host } ] : [ ] ) ,
262+ ...( wizard . config . source === 'create-new' ? [ { label : 'Source' , value : wizard . config . sourcePath } ] : [ ] ) ,
204263 ] }
205264 />
206265 ) }
0 commit comments