diff --git a/src/cli/commands/add/__tests__/add-gateway-target.test.ts b/src/cli/commands/add/__tests__/add-gateway-target.test.ts index c6d9846b..4b0ee8ca 100644 --- a/src/cli/commands/add/__tests__/add-gateway-target.test.ts +++ b/src/cli/commands/add/__tests__/add-gateway-target.test.ts @@ -9,43 +9,19 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; describe.skip('add gateway-target command', () => { let testDir: string; let projectDir: string; - const agentName = 'TestAgent'; - const gatewayName = 'test-gateway'; // Used in skipped behind-gateway tests + const gatewayName = 'test-gateway'; beforeAll(async () => { testDir = join(tmpdir(), `agentcore-add-gateway-target-${randomUUID()}`); await mkdir(testDir, { recursive: true }); - // Create project with agent + // Create project const projectName = 'GatewayTargetProj'; - let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir); + const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir); if (result.exitCode !== 0) { throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`); } projectDir = join(testDir, projectName); - - // Add agent for mcp-runtime tests - result = await runCLI( - [ - 'add', - 'agent', - '--name', - agentName, - '--language', - 'Python', - '--framework', - 'Strands', - '--model-provider', - 'Bedrock', - '--memory', - 'none', - '--json', - ], - projectDir - ); - if (result.exitCode !== 0) { - throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`); - } }); afterAll(async () => { @@ -61,32 +37,9 @@ describe.skip('add gateway-target command', () => { expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy(); }); - it('requires exposure flag', async () => { - const result = await runCLI( - ['add', 'gateway-target', '--name', 'test', '--language', 'Python', '--json'], - projectDir - ); - expect(result.exitCode).toBe(1); - const json = JSON.parse(result.stdout); - expect(json.success).toBe(false); - expect(json.error.includes('--exposure'), `Error: ${json.error}`).toBeTruthy(); - }); - it('validates language', async () => { const result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - 'test', - '--language', - 'InvalidLang', - '--exposure', - 'mcp-runtime', - '--agents', - agentName, - '--json', - ], + ['add', 'gateway-target', '--name', 'test', '--language', 'InvalidLang', '--json'], projectDir ); expect(result.exitCode).toBe(1); @@ -100,19 +53,7 @@ describe.skip('add gateway-target command', () => { it('accepts Other as valid language option', async () => { const result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - 'container-tool', - '--language', - 'Other', - '--exposure', - 'mcp-runtime', - '--agents', - agentName, - '--json', - ], + ['add', 'gateway-target', '--name', 'container-tool', '--language', 'Other', '--json'], projectDir ); @@ -127,79 +68,6 @@ describe.skip('add gateway-target command', () => { }); }); - describe('mcp-runtime', () => { - it('creates mcp-runtime tool', async () => { - const toolName = `rttool${Date.now()}`; - const result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - toolName, - '--language', - 'Python', - '--exposure', - 'mcp-runtime', - '--agents', - agentName, - '--json', - ], - projectDir - ); - - expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); - const json = JSON.parse(result.stdout); - expect(json.success).toBe(true); - expect(json.toolName).toBe(toolName); - - // Verify in mcp.json - const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8')); - const tool = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === toolName); - expect(tool, 'Tool should be in mcpRuntimeTools').toBeTruthy(); - - // Verify agent has remote tool reference - const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8')); - const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName); - const hasRef = agent?.remoteTools?.some((rt: { mcpRuntimeName?: string }) => rt.mcpRuntimeName === toolName); - expect(hasRef, 'Agent should have remoteTools reference').toBeTruthy(); - }); - - it('requires agents for mcp-runtime', async () => { - const result = await runCLI( - ['add', 'gateway-target', '--name', 'no-agents', '--language', 'Python', '--exposure', 'mcp-runtime', '--json'], - projectDir - ); - expect(result.exitCode).toBe(1); - const json = JSON.parse(result.stdout); - expect(json.success).toBe(false); - expect(json.error.includes('--agents'), `Error: ${json.error}`).toBeTruthy(); - }); - - it('returns clear error for Other language with mcp-runtime', async () => { - const result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - 'runtime-container', - '--language', - 'Other', - '--exposure', - 'mcp-runtime', - '--agents', - agentName, - '--json', - ], - projectDir - ); - - expect(result.exitCode).toBe(1); - const json = JSON.parse(result.stdout); - expect(json.success).toBe(false); - expect(json.error.length > 0, 'Should have error message').toBeTruthy(); - }); - }); - // Gateway disabled - skip behind-gateway tests until gateway feature is enabled describe.skip('behind-gateway', () => { it('creates behind-gateway tool', async () => { @@ -212,8 +80,6 @@ describe.skip('add gateway-target command', () => { toolName, '--language', 'Python', - '--exposure', - 'behind-gateway', '--gateway', gatewayName, '--host', @@ -237,19 +103,7 @@ describe.skip('add gateway-target command', () => { it('requires gateway for behind-gateway', async () => { const result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - 'no-gw', - '--language', - 'Python', - '--exposure', - 'behind-gateway', - '--host', - 'Lambda', - '--json', - ], + ['add', 'gateway-target', '--name', 'no-gw', '--language', 'Python', '--host', 'Lambda', '--json'], projectDir ); expect(result.exitCode).toBe(1); @@ -260,19 +114,7 @@ describe.skip('add gateway-target command', () => { it('requires host for behind-gateway', async () => { const result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - 'no-host', - '--language', - 'Python', - '--exposure', - 'behind-gateway', - '--gateway', - gatewayName, - '--json', - ], + ['add', 'gateway-target', '--name', 'no-host', '--language', 'Python', '--gateway', gatewayName, '--json'], projectDir ); expect(result.exitCode).toBe(1); @@ -290,8 +132,6 @@ describe.skip('add gateway-target command', () => { 'gateway-container', '--language', 'Other', - '--exposure', - 'behind-gateway', '--gateway', gatewayName, '--host', diff --git a/src/cli/commands/add/__tests__/validate.test.ts b/src/cli/commands/add/__tests__/validate.test.ts index 1e14ef6a..f53b7187 100644 --- a/src/cli/commands/add/__tests__/validate.test.ts +++ b/src/cli/commands/add/__tests__/validate.test.ts @@ -46,17 +46,9 @@ const validGatewayOptionsJwt: AddGatewayOptions = { allowedClients: 'client1,client2', }; -const validGatewayTargetOptionsMcpRuntime: AddGatewayTargetOptions = { +const validGatewayTargetOptions: AddGatewayTargetOptions = { name: 'test-tool', language: 'Python', - exposure: 'mcp-runtime', - agents: 'Agent1,Agent2', -}; - -const validGatewayTargetOptionsBehindGateway: AddGatewayTargetOptions = { - name: 'test-tool', - language: 'Python', - exposure: 'behind-gateway', gateway: 'my-gateway', host: 'Lambda', }; @@ -241,11 +233,10 @@ describe('validate', () => { const requiredFields: { field: keyof AddGatewayTargetOptions; error: string }[] = [ { field: 'name', error: '--name is required' }, { field: 'language', error: '--language is required' }, - { field: 'exposure', error: '--exposure is required' }, ]; for (const { field, error } of requiredFields) { - const opts = { ...validGatewayTargetOptionsMcpRuntime, [field]: undefined }; + const opts = { ...validGatewayTargetOptions, [field]: undefined }; const result = await validateAddGatewayTargetOptions(opts); expect(result.valid, `Should fail for missing ${String(field)}`).toBe(false); expect(result.error).toBe(error); @@ -254,42 +245,19 @@ describe('validate', () => { // AC16: Invalid values rejected it('returns error for invalid values', async () => { - let result = await validateAddGatewayTargetOptions({ - ...validGatewayTargetOptionsMcpRuntime, + const result = await validateAddGatewayTargetOptions({ + ...validGatewayTargetOptions, language: 'Java' as any, }); expect(result.valid).toBe(false); expect(result.error?.includes('Invalid language')).toBeTruthy(); - - result = await validateAddGatewayTargetOptions({ - ...validGatewayTargetOptionsMcpRuntime, - exposure: 'invalid' as any, - }); - expect(result.valid).toBe(false); - expect(result.error?.includes('Invalid exposure')).toBeTruthy(); }); - // AC17: mcp-runtime exposure requires agents - it('returns error for mcp-runtime without agents', async () => { - let result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptionsMcpRuntime, agents: undefined }); - expect(result.valid).toBe(false); - expect(result.error).toBe('--agents is required for mcp-runtime exposure'); - - result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptionsMcpRuntime, agents: ',,,' }); - expect(result.valid).toBe(false); - expect(result.error).toBe('At least one agent is required'); - }); - - // AC18: behind-gateway exposure is enabled - it('passes for valid behind-gateway options', async () => { - const result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptionsBehindGateway }); + // AC18: Valid options pass + it('passes for valid gateway target options', async () => { + const result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptions }); expect(result.valid).toBe(true); }); - - // AC19: Valid options pass - it('passes for valid mcp-runtime options', async () => { - expect(await validateAddGatewayTargetOptions(validGatewayTargetOptionsMcpRuntime)).toEqual({ valid: true }); - }); }); describe('validateAddMemoryOptions', () => { diff --git a/src/cli/commands/add/actions.ts b/src/cli/commands/add/actions.ts index f52723cc..88c5dcc9 100644 --- a/src/cli/commands/add/actions.ts +++ b/src/cli/commands/add/actions.ts @@ -70,8 +70,6 @@ export interface ValidatedAddGatewayTargetOptions { source?: 'existing-endpoint' | 'create-new'; endpoint?: string; language: 'Python' | 'TypeScript' | 'Other'; - exposure: 'mcp-runtime' | 'behind-gateway'; - agents?: string; gateway?: string; host?: 'Lambda' | 'AgentCoreRuntime'; outboundAuthType?: 'OAUTH' | 'API_KEY' | 'NONE'; @@ -306,23 +304,15 @@ function buildGatewayTargetConfig(options: ValidatedAddGatewayTargetOptions): Ad description, sourcePath, language: options.language, - exposure: options.exposure, source: options.source, endpoint: options.endpoint, - host: options.exposure === 'mcp-runtime' ? 'AgentCoreRuntime' : options.host!, + host: options.host!, toolDefinition: { name: options.name, description, inputSchema: { type: 'object' }, }, - selectedAgents: - options.exposure === 'mcp-runtime' - ? options - .agents!.split(',') - .map(s => s.trim()) - .filter(Boolean) - : [], - gateway: options.exposure === 'behind-gateway' ? options.gateway : undefined, + gateway: options.gateway, outboundAuth, }; } diff --git a/src/cli/commands/add/command.tsx b/src/cli/commands/add/command.tsx index 89e8125f..cc5ae49c 100644 --- a/src/cli/commands/add/command.tsx +++ b/src/cli/commands/add/command.tsx @@ -111,8 +111,6 @@ async function handleAddGatewayTargetCLI(options: AddGatewayTargetOptions): Prom name: options.name!, description: options.description, language: options.language! as 'Python' | 'TypeScript', - exposure: options.exposure!, - agents: options.agents, gateway: options.gateway, host: options.host, }); @@ -266,10 +264,8 @@ export function registerAdd(program: Command) { .option('--source ', 'Source: existing-endpoint or create-new') .option('--endpoint ', 'MCP server endpoint URL') .option('--language ', 'Language: Python or TypeScript') - .option('--exposure ', 'Exposure mode: mcp-runtime or behind-gateway') - .option('--agents ', 'Comma-separated agent names (for mcp-runtime)') - .option('--gateway ', 'Gateway name (for behind-gateway)') - .option('--host ', 'Compute host: Lambda or AgentCoreRuntime (for behind-gateway)') + .option('--gateway ', 'Gateway name') + .option('--host ', 'Compute host: Lambda or AgentCoreRuntime') .option('--json', 'Output as JSON') .action(async options => { requireProject(); diff --git a/src/cli/commands/add/types.ts b/src/cli/commands/add/types.ts index 984351c0..b37785ba 100644 --- a/src/cli/commands/add/types.ts +++ b/src/cli/commands/add/types.ts @@ -49,8 +49,6 @@ export interface AddGatewayTargetOptions { source?: string; endpoint?: string; language?: 'Python' | 'TypeScript' | 'Other'; - exposure?: 'mcp-runtime' | 'behind-gateway'; - agents?: string; gateway?: string; host?: 'Lambda' | 'AgentCoreRuntime'; outboundAuthType?: 'OAUTH' | 'API_KEY' | 'NONE'; diff --git a/src/cli/commands/add/validate.ts b/src/cli/commands/add/validate.ts index 2331b369..0c4c0492 100644 --- a/src/cli/commands/add/validate.ts +++ b/src/cli/commands/add/validate.ts @@ -213,7 +213,6 @@ export async function validateAddGatewayTargetOptions(options: AddGatewayTargetO // Populate defaults for fields skipped by external endpoint flow options.language ??= 'Other'; - options.exposure ??= 'behind-gateway'; options.gateway ??= undefined; return { valid: true }; @@ -227,27 +226,6 @@ export async function validateAddGatewayTargetOptions(options: AddGatewayTargetO return { valid: false, error: 'Invalid language. Valid options: Python, TypeScript, Other' }; } - if (!options.exposure) { - return { valid: false, error: '--exposure is required' }; - } - - if (options.exposure !== 'mcp-runtime' && options.exposure !== 'behind-gateway') { - return { valid: false, error: "Invalid exposure. Use 'mcp-runtime' or 'behind-gateway'" }; - } - - if (options.exposure === 'mcp-runtime') { - if (!options.agents) { - return { valid: false, error: '--agents is required for mcp-runtime exposure' }; - } - const agents = options.agents - .split(',') - .map(s => s.trim()) - .filter(Boolean); - if (agents.length === 0) { - return { valid: false, error: 'At least one agent is required' }; - } - } - // Validate outbound auth configuration if (options.outboundAuthType && options.outboundAuthType !== 'NONE') { if (!options.credentialName) { diff --git a/src/cli/commands/remove/__tests__/remove-gateway-target.test.ts b/src/cli/commands/remove/__tests__/remove-gateway-target.test.ts index 00f01e9f..33c272fa 100644 --- a/src/cli/commands/remove/__tests__/remove-gateway-target.test.ts +++ b/src/cli/commands/remove/__tests__/remove-gateway-target.test.ts @@ -9,8 +9,6 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; describe.skip('remove gateway-target command', () => { let testDir: string; let projectDir: string; - const agentName = 'TestAgent'; - const runtimeToolName = 'RuntimeTool'; beforeAll(async () => { testDir = join(tmpdir(), `agentcore-remove-gateway-target-${randomUUID()}`); @@ -18,55 +16,11 @@ describe.skip('remove gateway-target command', () => { // Create project const projectName = 'RemoveGatewayTargetProj'; - let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir); + const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir); if (result.exitCode !== 0) { throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`); } projectDir = join(testDir, projectName); - - // Add agent - result = await runCLI( - [ - 'add', - 'agent', - '--name', - agentName, - '--language', - 'Python', - '--framework', - 'Strands', - '--model-provider', - 'Bedrock', - '--memory', - 'none', - '--json', - ], - projectDir - ); - if (result.exitCode !== 0) { - throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`); - } - - // Add mcp-runtime tool - result = await runCLI( - [ - 'add', - 'gateway-target', - '--name', - runtimeToolName, - '--language', - 'Python', - '--exposure', - 'mcp-runtime', - '--agents', - agentName, - '--json', - ], - projectDir - ); - if (result.exitCode !== 0) { - throw new Error(`Failed to create runtime tool: ${result.stdout} ${result.stderr}`); - } }); afterAll(async () => { @@ -91,45 +45,6 @@ describe.skip('remove gateway-target command', () => { }); }); - describe('remove mcp-runtime tool', () => { - it('removes mcp-runtime tool and cleans up agent references', async () => { - // Add a temp tool to remove - const tempTool = `tempRt${Date.now()}`; - await runCLI( - [ - 'add', - 'gateway-target', - '--name', - tempTool, - '--language', - 'Python', - '--exposure', - 'mcp-runtime', - '--agents', - agentName, - '--json', - ], - projectDir - ); - - const result = await runCLI(['remove', 'gateway-target', '--name', tempTool, '--json'], projectDir); - expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0); - const json = JSON.parse(result.stdout); - expect(json.success).toBe(true); - - // Verify tool is removed from mcp.json - const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8')); - const tool = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === tempTool); - expect(!tool, 'Tool should be removed from mcpRuntimeTools').toBeTruthy(); - - // Verify agent reference is cleaned up - const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8')); - const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName); - const hasRef = agent?.remoteTools?.some((rt: { mcpRuntimeName?: string }) => rt.mcpRuntimeName === tempTool); - expect(!hasRef, 'Agent should not have reference to removed tool').toBeTruthy(); - }); - }); - // Gateway disabled - skip behind-gateway tests until gateway feature is enabled describe.skip('remove behind-gateway tool', () => { it('removes behind-gateway tool from gateway targets', async () => { @@ -148,8 +63,6 @@ describe.skip('remove gateway-target command', () => { tempTool, '--language', 'Python', - '--exposure', - 'behind-gateway', '--gateway', tempGateway, '--host', diff --git a/src/cli/operations/mcp/create-mcp.ts b/src/cli/operations/mcp/create-mcp.ts index fe517515..4e9b7d56 100644 --- a/src/cli/operations/mcp/create-mcp.ts +++ b/src/cli/operations/mcp/create-mcp.ts @@ -3,9 +3,7 @@ import type { AgentCoreCliMcpDefs, AgentCoreGateway, AgentCoreGatewayTarget, - AgentCoreMcpRuntimeTool, AgentCoreMcpSpec, - CodeZipRuntimeConfig, DirectoryPath, FilePath, } from '../../../schema'; @@ -255,7 +253,7 @@ export async function createExternalGatewayTarget(config: AddGatewayTargetConfig } /** - * Create an MCP tool (MCP runtime or behind gateway). + * Create an MCP tool (behind gateway only). */ export async function createToolFromWizard(config: AddGatewayTargetConfig): Promise { validateGatewayTargetLanguage(config.language); @@ -280,117 +278,76 @@ export async function createToolFromWizard(config: AddGatewayTargetConfig): Prom ToolDefinitionSchema.parse(toolDef); } - if (config.exposure === 'mcp-runtime') { - // MCP Runtime tool - always AgentCoreRuntime (single tool) - // Build explicit CodeZipRuntimeConfig - no CLI-managed placeholders - const runtimeConfig: CodeZipRuntimeConfig = { - artifact: 'CodeZip', - pythonVersion: DEFAULT_PYTHON_VERSION, - name: config.name, - entrypoint: 'server.py:main' as FilePath, - codeLocation: config.sourcePath as DirectoryPath, - networkMode: 'PUBLIC', - }; - - // 'Other' language requires container config - not supported for mcp-runtime yet - if (config.language === 'Other') { - throw new Error('Language "Other" is not yet supported for MCP runtime tools. Use Python or TypeScript.'); - } - - const mcpRuntimeTool: AgentCoreMcpRuntimeTool = { - name: config.name, - toolDefinition: config.toolDefinition, - compute: { - host: 'AgentCoreRuntime', - implementation: { - path: config.sourcePath, - language: config.language, - handler: DEFAULT_HANDLER, - }, - runtime: runtimeConfig, - }, - }; - - const mcpRuntimeTools = mcpSpec.mcpRuntimeTools ?? []; - if (mcpRuntimeTools.some(tool => tool.name === mcpRuntimeTool.name)) { - throw new Error(`MCP runtime tool "${mcpRuntimeTool.name}" already exists.`); - } - mcpSpec.mcpRuntimeTools = [...mcpRuntimeTools, mcpRuntimeTool]; - - // Write mcp.json - await configIO.writeMcpSpec(mcpSpec); - } else { - // Behind gateway - if (!config.gateway) { - throw new Error('Gateway name is required for tools behind a gateway.'); - } + // Behind gateway + if (!config.gateway) { + throw new Error('Gateway name is required for tools behind a gateway.'); + } - const gateway = mcpSpec.agentCoreGateways.find(g => g.name === config.gateway); - if (!gateway) { - throw new Error(`Gateway "${config.gateway}" not found.`); - } + const gateway = mcpSpec.agentCoreGateways.find(g => g.name === config.gateway); + if (!gateway) { + throw new Error(`Gateway "${config.gateway}" not found.`); + } - // Check for duplicate target name - if (gateway.targets.some(t => t.name === config.name)) { - throw new Error(`Target "${config.name}" already exists in gateway "${gateway.name}".`); - } + // Check for duplicate target name + if (gateway.targets.some(t => t.name === config.name)) { + throw new Error(`Target "${config.name}" already exists in gateway "${gateway.name}".`); + } - // Check for duplicate tool names - for (const toolDef of toolDefs) { - for (const existingTarget of gateway.targets) { - if ((existingTarget.toolDefinitions ?? []).some(t => t.name === toolDef.name)) { - throw new Error(`Tool "${toolDef.name}" already exists in gateway "${gateway.name}".`); - } + // Check for duplicate tool names + for (const toolDef of toolDefs) { + for (const existingTarget of gateway.targets) { + if ((existingTarget.toolDefinitions ?? []).some(t => t.name === toolDef.name)) { + throw new Error(`Tool "${toolDef.name}" already exists in gateway "${gateway.name}".`); } } + } - // 'Other' language requires container config - not supported for gateway tools yet - if (config.language === 'Other') { - throw new Error('Language "Other" is not yet supported for gateway tools. Use Python or TypeScript.'); - } + // 'Other' language requires container config - not supported for gateway tools yet + if (config.language === 'Other') { + throw new Error('Language "Other" is not yet supported for gateway tools. Use Python or TypeScript.'); + } - // Create a single target with all tool definitions - const target: AgentCoreGatewayTarget = { - name: config.name, - targetType: config.host === 'AgentCoreRuntime' ? 'mcpServer' : 'lambda', - toolDefinitions: toolDefs, - compute: - config.host === 'Lambda' - ? { - host: 'Lambda', - implementation: { - path: config.sourcePath, - language: config.language, - handler: DEFAULT_HANDLER, - }, - ...(config.language === 'Python' - ? { pythonVersion: DEFAULT_PYTHON_VERSION } - : { nodeVersion: DEFAULT_NODE_VERSION }), - } - : { - host: 'AgentCoreRuntime', - implementation: { - path: config.sourcePath, - language: 'Python', - handler: 'server.py:main', - }, - runtime: { - artifact: 'CodeZip', - pythonVersion: DEFAULT_PYTHON_VERSION, - name: config.name, - entrypoint: 'server.py:main' as FilePath, - codeLocation: config.sourcePath as DirectoryPath, - networkMode: 'PUBLIC', - }, + // Create a single target with all tool definitions + const target: AgentCoreGatewayTarget = { + name: config.name, + targetType: config.host === 'AgentCoreRuntime' ? 'mcpServer' : 'lambda', + toolDefinitions: toolDefs, + compute: + config.host === 'Lambda' + ? { + host: 'Lambda', + implementation: { + path: config.sourcePath, + language: config.language, + handler: DEFAULT_HANDLER, + }, + ...(config.language === 'Python' + ? { pythonVersion: DEFAULT_PYTHON_VERSION } + : { nodeVersion: DEFAULT_NODE_VERSION }), + } + : { + host: 'AgentCoreRuntime', + implementation: { + path: config.sourcePath, + language: 'Python', + handler: 'server.py:main', }, - ...(config.outboundAuth && { outboundAuth: config.outboundAuth }), - }; + runtime: { + artifact: 'CodeZip', + pythonVersion: DEFAULT_PYTHON_VERSION, + name: config.name, + entrypoint: 'server.py:main' as FilePath, + codeLocation: config.sourcePath as DirectoryPath, + networkMode: 'PUBLIC', + }, + }, + ...(config.outboundAuth && { outboundAuth: config.outboundAuth }), + }; - gateway.targets.push(target); + gateway.targets.push(target); - // Write mcp.json for gateway case - await configIO.writeMcpSpec(mcpSpec); - } + // Write mcp.json for gateway case + await configIO.writeMcpSpec(mcpSpec); // Update mcp-defs.json with all tool definitions const mcpDefsPath = resolveMcpDefsPath(); diff --git a/src/cli/operations/remove/remove-gateway-target.ts b/src/cli/operations/remove/remove-gateway-target.ts index 5d37a3e6..f3aacb5d 100644 --- a/src/cli/operations/remove/remove-gateway-target.ts +++ b/src/cli/operations/remove/remove-gateway-target.ts @@ -10,7 +10,7 @@ import { join } from 'path'; */ export interface RemovableGatewayTarget { name: string; - type: 'mcp-runtime' | 'gateway-target'; + type: 'gateway-target'; gatewayName?: string; } @@ -26,11 +26,6 @@ export async function getRemovableGatewayTargets(): Promise t.name === tool.name); - if (!mcpTool) { - throw new Error(`MCP Runtime tool "${tool.name}" not found.`); - } + // Gateway target + const gateway = mcpSpec.agentCoreGateways.find(g => g.name === tool.gatewayName); + if (!gateway) { + throw new Error(`Gateway "${tool.gatewayName}" not found.`); + } - summary.push(`Removing MCP Runtime tool: ${tool.name}`); + const target = gateway.targets.find(t => t.name === tool.name); + if (!target) { + throw new Error(`Target "${tool.name}" not found in gateway "${tool.gatewayName}".`); + } - // Check for directory to delete - const implementation = mcpTool.compute.implementation; - const toolPath = 'path' in implementation ? implementation.path : undefined; - if (toolPath) { - const toolDir = join(projectRoot, toolPath); - if (existsSync(toolDir)) { - directoriesToDelete.push(toolDir); - summary.push(`Deleting directory: ${toolPath}`); - } - } + summary.push(`Removing gateway target: ${tool.name} (from ${tool.gatewayName})`); - // Tool definition in mcp-defs - if (mcpDefs.tools[mcpTool.toolDefinition.name]) { - summary.push(`Removing tool definition: ${mcpTool.toolDefinition.name}`); - } - } else { - // Gateway target - const gateway = mcpSpec.agentCoreGateways.find(g => g.name === tool.gatewayName); - if (!gateway) { - throw new Error(`Gateway "${tool.gatewayName}" not found.`); - } - - const target = gateway.targets.find(t => t.name === tool.name); - if (!target) { - throw new Error(`Target "${tool.name}" not found in gateway "${tool.gatewayName}".`); - } - - summary.push(`Removing gateway target: ${tool.name} (from ${tool.gatewayName})`); - - // Check for directory to delete - if (target.compute?.implementation && 'path' in target.compute.implementation) { - const toolPath = target.compute.implementation.path; - const toolDir = join(projectRoot, toolPath); - if (existsSync(toolDir)) { - directoriesToDelete.push(toolDir); - summary.push(`Deleting directory: ${toolPath}`); - } + // Check for directory to delete + if (target.compute?.implementation && 'path' in target.compute.implementation) { + const toolPath = target.compute.implementation.path; + const toolDir = join(projectRoot, toolPath); + if (existsSync(toolDir)) { + directoriesToDelete.push(toolDir); + summary.push(`Deleting directory: ${toolPath}`); } + } - // Tool definitions in mcp-defs - for (const toolDef of target.toolDefinitions ?? []) { - if (mcpDefs.tools[toolDef.name]) { - summary.push(`Removing tool definition: ${toolDef.name}`); - } + // Tool definitions in mcp-defs + for (const toolDef of target.toolDefinitions ?? []) { + if (mcpDefs.tools[toolDef.name]) { + summary.push(`Removing tool definition: ${toolDef.name}`); } } @@ -140,13 +110,6 @@ export async function previewRemoveGatewayTarget(tool: RemovableGatewayTarget): * Compute the MCP spec after removing a tool. */ function computeRemovedToolMcpSpec(mcpSpec: AgentCoreMcpSpec, tool: RemovableGatewayTarget): AgentCoreMcpSpec { - if (tool.type === 'mcp-runtime') { - return { - ...mcpSpec, - mcpRuntimeTools: (mcpSpec.mcpRuntimeTools ?? []).filter(t => t.name !== tool.name), - }; - } - // Gateway target return { ...mcpSpec, @@ -170,18 +133,11 @@ function computeRemovedToolMcpDefs( ): AgentCoreCliMcpDefs { const toolNamesToRemove: string[] = []; - if (tool.type === 'mcp-runtime') { - const mcpTool = mcpSpec.mcpRuntimeTools?.find(t => t.name === tool.name); - if (mcpTool) { - toolNamesToRemove.push(mcpTool.toolDefinition.name); - } - } else { - const gateway = mcpSpec.agentCoreGateways.find(g => g.name === tool.gatewayName); - const target = gateway?.targets.find(t => t.name === tool.name); - if (target) { - for (const toolDef of target.toolDefinitions ?? []) { - toolNamesToRemove.push(toolDef.name); - } + const gateway = mcpSpec.agentCoreGateways.find(g => g.name === tool.gatewayName); + const target = gateway?.targets.find(t => t.name === tool.name); + if (target) { + for (const toolDef of target.toolDefinitions ?? []) { + toolNamesToRemove.push(toolDef.name); } } @@ -206,25 +162,16 @@ export async function removeGatewayTarget(tool: RemovableGatewayTarget): Promise // Find the tool path for deletion let toolPath: string | undefined; - if (tool.type === 'mcp-runtime') { - const mcpTool = mcpSpec.mcpRuntimeTools?.find(t => t.name === tool.name); - if (!mcpTool) { - return { ok: false, error: `MCP Runtime tool "${tool.name}" not found.` }; - } - const impl = mcpTool.compute.implementation; - toolPath = 'path' in impl ? impl.path : undefined; - } else { - const gateway = mcpSpec.agentCoreGateways.find(g => g.name === tool.gatewayName); - if (!gateway) { - return { ok: false, error: `Gateway "${tool.gatewayName}" not found.` }; - } - const target = gateway.targets.find(t => t.name === tool.name); - if (!target) { - return { ok: false, error: `Target "${tool.name}" not found in gateway "${tool.gatewayName}".` }; - } - if (target.compute?.implementation && 'path' in target.compute.implementation) { - toolPath = target.compute.implementation.path; - } + const gateway = mcpSpec.agentCoreGateways.find(g => g.name === tool.gatewayName); + if (!gateway) { + return { ok: false, error: `Gateway "${tool.gatewayName}" not found.` }; + } + const target = gateway.targets.find(t => t.name === tool.name); + if (!target) { + return { ok: false, error: `Target "${tool.name}" not found in gateway "${tool.gatewayName}".` }; + } + if (target.compute?.implementation && 'path' in target.compute.implementation) { + toolPath = target.compute.implementation.path; } // Update MCP spec diff --git a/src/cli/tui/screens/add/AddFlow.tsx b/src/cli/tui/screens/add/AddFlow.tsx index 921da218..0f2b4fab 100644 --- a/src/cli/tui/screens/add/AddFlow.tsx +++ b/src/cli/tui/screens/add/AddFlow.tsx @@ -339,7 +339,6 @@ export function AddFlow(props: AddFlowProps) { return ( setFlow({ name: 'select' })} onDev={props.onDev} diff --git a/src/cli/tui/screens/mcp/AddGatewayFlow.tsx b/src/cli/tui/screens/mcp/AddGatewayFlow.tsx index 8eb895b3..36191b84 100644 --- a/src/cli/tui/screens/mcp/AddGatewayFlow.tsx +++ b/src/cli/tui/screens/mcp/AddGatewayFlow.tsx @@ -332,7 +332,7 @@ export function AddGatewayFlow({ void; onBack: () => void; /** Called when user selects dev from success screen to run agent locally */ @@ -40,7 +38,6 @@ const MODE_OPTIONS: SelectableItem[] = [ export function AddGatewayTargetFlow({ isInteractive = true, - existingAgents, onExit, onBack, onDev, @@ -166,7 +163,6 @@ export function AddGatewayTargetFlow({ return ( setFlow({ name: 'mode-select' })} diff --git a/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx b/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx index 6a447420..f8a2522e 100644 --- a/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx +++ b/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx @@ -1,21 +1,12 @@ import { ToolNameSchema } from '../../../../schema'; -import { - ConfirmReview, - Panel, - Screen, - StepIndicator, - TextInput, - WizardMultiSelect, - WizardSelect, -} from '../../components'; +import { ConfirmReview, Panel, Screen, StepIndicator, TextInput, WizardSelect } from '../../components'; import type { SelectableItem } from '../../components'; import { HELP_TEXT } from '../../constants'; -import { useListNavigation, useMultiSelectNavigation } from '../../hooks'; +import { useListNavigation } from '../../hooks'; import { generateUniqueName } from '../../utils'; -import type { AddGatewayTargetConfig, ComputeHost, ExposureMode, TargetLanguage } from './types'; +import type { AddGatewayTargetConfig, ComputeHost, TargetLanguage } from './types'; import { COMPUTE_HOST_OPTIONS, - EXPOSURE_MODE_OPTIONS, MCP_TOOL_STEP_LABELS, SKIP_FOR_NOW, SOURCE_OPTIONS, @@ -27,7 +18,6 @@ import React, { useMemo } from 'react'; interface AddGatewayTargetScreenProps { existingGateways: string[]; - existingAgents: string[]; existingToolNames: string[]; onComplete: (config: AddGatewayTargetConfig) => void; onExit: () => void; @@ -35,12 +25,11 @@ interface AddGatewayTargetScreenProps { export function AddGatewayTargetScreen({ existingGateways, - existingAgents, existingToolNames, onComplete, onExit, }: AddGatewayTargetScreenProps) { - const wizard = useAddGatewayTargetWizard(existingGateways, existingAgents); + const wizard = useAddGatewayTargetWizard(existingGateways); const sourceItems: SelectableItem[] = useMemo( () => SOURCE_OPTIONS.map(o => ({ id: o.id, title: o.title, description: o.description })), @@ -52,17 +41,6 @@ export function AddGatewayTargetScreen({ [] ); - const exposureItems: SelectableItem[] = useMemo( - () => - EXPOSURE_MODE_OPTIONS.map(o => ({ - id: o.id, - title: o.title, - description: o.description, - disabled: 'disabled' in o ? Boolean(o.disabled) : undefined, - })), - [] - ); - const gatewayItems: SelectableItem[] = useMemo( () => [ ...existingGateways.map(g => ({ id: g, title: g })), @@ -76,18 +54,13 @@ export function AddGatewayTargetScreen({ [] ); - const agentItems: SelectableItem[] = useMemo(() => existingAgents.map(a => ({ id: a, title: a })), [existingAgents]); - const isSourceStep = wizard.step === 'source'; const isLanguageStep = wizard.step === 'language'; - const isExposureStep = wizard.step === 'exposure'; - const isAgentsStep = wizard.step === 'agents'; const isGatewayStep = wizard.step === 'gateway'; const isHostStep = wizard.step === 'host'; const isTextStep = wizard.step === 'name' || wizard.step === 'endpoint'; const isConfirmStep = wizard.step === 'confirm'; const noGatewaysAvailable = isGatewayStep && existingGateways.length === 0; - const noAgentsAvailable = isAgentsStep && existingAgents.length === 0; const sourceNav = useListNavigation({ items: sourceItems, @@ -103,14 +76,6 @@ export function AddGatewayTargetScreen({ isActive: isLanguageStep, }); - const exposureNav = useListNavigation({ - items: exposureItems, - onSelect: item => wizard.setExposure(item.id as ExposureMode), - onExit: () => wizard.goBack(), - isActive: isExposureStep, - isDisabled: item => item.disabled === true, - }); - const gatewayNav = useListNavigation({ items: gatewayItems, onSelect: item => wizard.setGateway(item.id), @@ -125,14 +90,6 @@ export function AddGatewayTargetScreen({ isActive: isHostStep, }); - const agentsNav = useMultiSelectNavigation({ - items: agentItems, - getId: item => item.id, - onConfirm: selected => wizard.setAgents(selected), - onExit: () => wizard.goBack(), - isActive: isAgentsStep && !noAgentsAvailable, - }); - useListNavigation({ items: [{ id: 'confirm', title: 'Confirm' }], onSelect: () => onComplete(wizard.config), @@ -144,14 +101,10 @@ export function AddGatewayTargetScreen({ ? HELP_TEXT.CONFIRM_CANCEL : isTextStep ? HELP_TEXT.TEXT_INPUT - : isAgentsStep - ? HELP_TEXT.MULTI_SELECT - : HELP_TEXT.NAVIGATE_SELECT; + : HELP_TEXT.NAVIGATE_SELECT; const headerContent = ; - const isMcpRuntime = wizard.config.exposure === 'mcp-runtime'; - return ( @@ -168,15 +121,6 @@ export function AddGatewayTargetScreen({ )} - {isExposureStep && ( - - )} - {isGatewayStep && !noGatewaysAvailable && ( } - {isAgentsStep && !noAgentsAvailable && ( - - )} - - {noAgentsAvailable && } - {isHostStep && ( 0 - ? [{ label: 'Agents', value: wizard.config.selectedAgents.join(', ') }] - : []), - ...(!isMcpRuntime && wizard.config.gateway ? [{ label: 'Gateway', value: wizard.config.gateway }] : []), - ...(!isMcpRuntime && !wizard.config.gateway - ? [{ label: 'Gateway', value: '(none - assign later)' }] - : []), + ...(wizard.config.gateway ? [{ label: 'Gateway', value: wizard.config.gateway }] : []), + ...(!wizard.config.gateway ? [{ label: 'Gateway', value: '(none - assign later)' }] : []), ...(wizard.config.source === 'create-new' ? [{ label: 'Host', value: wizard.config.host }] : []), ...(wizard.config.source === 'create-new' ? [{ label: 'Source', value: wizard.config.sourcePath }] : []), ]} @@ -279,16 +203,3 @@ function NoGatewaysMessage() { ); } - -function NoAgentsMessage() { - return ( - - No agents found - Create an agent first to attach MCP runtime tools. - You can still create the tool and attach agents later. - - Enter to continue without agents · Esc back - - - ); -} diff --git a/src/cli/tui/screens/mcp/index.ts b/src/cli/tui/screens/mcp/index.ts index c7e6956a..4f7e44b1 100644 --- a/src/cli/tui/screens/mcp/index.ts +++ b/src/cli/tui/screens/mcp/index.ts @@ -10,5 +10,4 @@ export type { AddGatewayTargetConfig, AddGatewayTargetStep, ComputeHost, - ExposureMode, } from './types'; diff --git a/src/cli/tui/screens/mcp/types.ts b/src/cli/tui/screens/mcp/types.ts index 6307e77b..8a5ffeaa 100644 --- a/src/cli/tui/screens/mcp/types.ts +++ b/src/cli/tui/screens/mcp/types.ts @@ -33,30 +33,17 @@ export const GATEWAY_STEP_LABELS: Record = { // MCP Tool Flow Types // ───────────────────────────────────────────────────────────────────────────── -export type ExposureMode = 'mcp-runtime' | 'behind-gateway'; - export type ComputeHost = 'Lambda' | 'AgentCoreRuntime'; /** * MCP tool wizard steps. * - name: Tool name input * - language: Target language (Python or TypeScript) - * - exposure: MCP Runtime (standalone) or behind-gateway - * - agents: Select agents to attach (only if mcp-runtime) - * - gateway: Select existing gateway (only if behind-gateway) - * - host: Select compute host (only if behind-gateway) + * - gateway: Select existing gateway + * - host: Select compute host * - confirm: Review and confirm */ -export type AddGatewayTargetStep = - | 'name' - | 'source' - | 'endpoint' - | 'language' - | 'exposure' - | 'agents' - | 'gateway' - | 'host' - | 'confirm'; +export type AddGatewayTargetStep = 'name' | 'source' | 'endpoint' | 'language' | 'gateway' | 'host' | 'confirm'; export type TargetLanguage = 'Python' | 'TypeScript' | 'Other'; @@ -65,19 +52,16 @@ export interface AddGatewayTargetConfig { description: string; sourcePath: string; language: TargetLanguage; - exposure: ExposureMode; /** Source type for external endpoints */ source?: 'existing-endpoint' | 'create-new'; /** External endpoint URL */ endpoint?: string; - /** Gateway name (only when exposure = behind-gateway) */ + /** Gateway name */ gateway?: string; - /** Compute host (AgentCoreRuntime for mcp-runtime, Lambda or AgentCoreRuntime for behind-gateway) */ + /** Compute host (Lambda or AgentCoreRuntime) */ host: ComputeHost; /** Derived tool definition */ toolDefinition: ToolDefinition; - /** Agent names to attach (only when exposure = mcp-runtime) */ - selectedAgents: string[]; /** Outbound auth configuration */ outboundAuth?: { type: 'OAUTH' | 'API_KEY' | 'NONE'; @@ -91,8 +75,6 @@ export const MCP_TOOL_STEP_LABELS: Record = { source: 'Source', endpoint: 'Endpoint', language: 'Language', - exposure: 'Exposure', - agents: 'Agents', gateway: 'Gateway', host: 'Host', confirm: 'Confirm', @@ -121,15 +103,6 @@ export const TARGET_LANGUAGE_OPTIONS = [ { id: 'Other', title: 'Other', description: 'Container-based implementation' }, ] as const; -export const EXPOSURE_MODE_OPTIONS = [ - { id: 'mcp-runtime', title: 'MCP Runtime', description: 'Deploy as AgentCore MCP Runtime (select agents to attach)' }, - { - id: 'behind-gateway', - title: 'Behind Gateway', - description: 'Route through AgentCore Gateway', - }, -] as const; - export const COMPUTE_HOST_OPTIONS = [ { id: 'Lambda', title: 'Lambda', description: 'AWS Lambda function' }, { id: 'AgentCoreRuntime', title: 'AgentCore Runtime', description: 'AgentCore Runtime (Python only)' }, diff --git a/src/cli/tui/screens/mcp/useAddGatewayTargetWizard.ts b/src/cli/tui/screens/mcp/useAddGatewayTargetWizard.ts index e5934fd0..29aa54ac 100644 --- a/src/cli/tui/screens/mcp/useAddGatewayTargetWizard.ts +++ b/src/cli/tui/screens/mcp/useAddGatewayTargetWizard.ts @@ -1,23 +1,19 @@ import { APP_DIR, MCP_APP_SUBDIR } from '../../../../lib'; import type { ToolDefinition } from '../../../../schema'; -import type { AddGatewayTargetConfig, AddGatewayTargetStep, ComputeHost, ExposureMode, TargetLanguage } from './types'; +import type { AddGatewayTargetConfig, AddGatewayTargetStep, ComputeHost, TargetLanguage } from './types'; import { SKIP_FOR_NOW } from './types'; import { useCallback, useMemo, useState } from 'react'; /** - * Dynamic steps based on exposure mode and source. + * Dynamic steps based on source. * - Existing endpoint: name → source → endpoint → gateway → confirm - * - Create new MCP Runtime: name → source → language → exposure → agents → confirm - * - Create new Behind gateway: name → source → language → exposure → gateway → host → confirm + * - Create new: name → source → language → gateway → host → confirm */ -function getSteps(exposure: ExposureMode, source?: 'existing-endpoint' | 'create-new'): AddGatewayTargetStep[] { +function getSteps(source?: 'existing-endpoint' | 'create-new'): AddGatewayTargetStep[] { if (source === 'existing-endpoint') { return ['name', 'source', 'endpoint', 'gateway', 'confirm']; } - if (exposure === 'mcp-runtime') { - return ['name', 'source', 'language', 'exposure', 'agents', 'confirm']; - } - return ['name', 'source', 'language', 'exposure', 'gateway', 'host', 'confirm']; + return ['name', 'source', 'language', 'gateway', 'host', 'confirm']; } function deriveToolDefinition(name: string): ToolDefinition { @@ -34,27 +30,25 @@ function getDefaultConfig(): AddGatewayTargetConfig { description: '', sourcePath: '', language: 'Python', - exposure: 'mcp-runtime', - host: 'AgentCoreRuntime', + host: 'Lambda', toolDefinition: deriveToolDefinition(''), - selectedAgents: [], }; } -export function useAddGatewayTargetWizard(existingGateways: string[] = [], existingAgents: string[] = []) { +export function useAddGatewayTargetWizard(existingGateways: string[] = []) { const [config, setConfig] = useState(getDefaultConfig); const [step, setStep] = useState('name'); - const steps = useMemo(() => getSteps(config.exposure, config.source), [config.exposure, config.source]); + const steps = useMemo(() => getSteps(config.source), [config.source]); const currentIndex = steps.indexOf(step); const goBack = useCallback(() => { - // Recalculate steps in case exposure or source changed - const currentSteps = getSteps(config.exposure, config.source); + // Recalculate steps in case source changed + const currentSteps = getSteps(config.source); const idx = currentSteps.indexOf(step); const prevStep = currentSteps[idx - 1]; if (prevStep) setStep(prevStep); - }, [config.exposure, config.source, step]); + }, [config.source, step]); const setName = useCallback((name: string) => { setConfig(c => ({ @@ -92,37 +86,7 @@ export function useAddGatewayTargetWizard(existingGateways: string[] = [], exist ...c, language, })); - setStep('exposure'); - }, []); - - const setExposure = useCallback((exposure: ExposureMode) => { - if (exposure === 'mcp-runtime') { - // MCP Runtime: host is always AgentCoreRuntime, go to agents selection - setConfig(c => ({ - ...c, - exposure, - host: 'AgentCoreRuntime', - gateway: undefined, - })); - setStep('agents'); - } else { - // Behind gateway: need to select gateway next - setConfig(c => ({ - ...c, - exposure, - selectedAgents: [], // Clear selected agents when switching to gateway mode - })); - // If no gateways exist, we should handle this in the UI - setStep('gateway'); - } - }, []); - - const setAgents = useCallback((agents: string[]) => { - setConfig(c => ({ - ...c, - selectedAgents: agents, - })); - setStep('confirm'); + setStep('gateway'); }, []); const setGateway = useCallback((gateway: string) => { @@ -157,14 +121,11 @@ export function useAddGatewayTargetWizard(existingGateways: string[] = [], exist steps, currentIndex, existingGateways, - existingAgents, goBack, setName, setSource, setEndpoint, setLanguage, - setExposure, - setAgents, setGateway, setHost, reset, diff --git a/src/cli/tui/screens/remove/RemoveGatewayTargetScreen.tsx b/src/cli/tui/screens/remove/RemoveGatewayTargetScreen.tsx index e0253ddb..e61d599c 100644 --- a/src/cli/tui/screens/remove/RemoveGatewayTargetScreen.tsx +++ b/src/cli/tui/screens/remove/RemoveGatewayTargetScreen.tsx @@ -15,7 +15,7 @@ export function RemoveGatewayTargetScreen({ tools, onSelect, onExit }: RemoveGat const items = tools.map(tool => ({ id: tool.name, title: tool.name, - description: tool.type === 'mcp-runtime' ? 'MCP Runtime tool' : `Gateway target (${tool.gatewayName})`, + description: `Gateway target (${tool.gatewayName})`, })); // Create a map for quick lookup diff --git a/src/cli/tui/screens/schema/McpGuidedEditor.tsx b/src/cli/tui/screens/schema/McpGuidedEditor.tsx index 95977e9a..d0b0af33 100644 --- a/src/cli/tui/screens/schema/McpGuidedEditor.tsx +++ b/src/cli/tui/screens/schema/McpGuidedEditor.tsx @@ -1,7 +1,6 @@ import { type AgentCoreGateway, type AgentCoreGatewayTarget, - type AgentCoreMcpRuntimeTool, type AgentCoreMcpSpec, AgentCoreMcpSpecSchema, GatewayNameSchema, @@ -79,7 +78,7 @@ export function McpGuidedEditor(props: McpGuidedEditorProps) { ); } -type ViewMode = 'gateways' | 'mcp-runtime'; +// Gateways view is the only view mode type ScreenMode = 'list' | 'confirm-exit' | 'edit-item' | 'edit-field' | 'edit-targets' | 'edit-target-field'; function McpEditorBody(props: { @@ -91,13 +90,10 @@ function McpEditorBody(props: { onRequestAdd?: () => void; }) { const [gateways, setGateways] = useState(props.initialSpec.agentCoreGateways); - const [mcpRuntimeTools, setMcpRuntimeTools] = useState( - props.initialSpec.mcpRuntimeTools ?? [] - ); const [unassignedTargets, _setUnassignedTargets] = useState( props.initialSpec.unassignedTargets ?? [] ); - const [viewMode, setViewMode] = useState('gateways'); + // Only gateways view mode const [selectedIndex, setSelectedIndex] = useState(0); const [expandedIndex, setExpandedIndex] = useState(null); const [dirty, setDirty] = useState(false); @@ -110,18 +106,15 @@ function McpEditorBody(props: { const [selectedTargetIndex, setSelectedTargetIndex] = useState(0); const [editingTargetFieldId, setEditingTargetFieldId] = useState(null); - const hasMcpRuntimeTools = mcpRuntimeTools.length > 0 || (props.initialSpec.mcpRuntimeTools?.length ?? 0) > 0; - // Define editable fields for the current item - const currentGateway = viewMode === 'gateways' ? gateways[selectedIndex] : null; + const currentGateway = gateways[selectedIndex]; const targetCount = currentGateway?.targets?.length ?? 0; const gatewayFields = [ { id: 'name', label: 'Name' }, { id: 'description', label: 'Description' }, { id: 'targets', label: `Targets (${targetCount})` }, ]; - const mcpRuntimeFields = [{ id: 'name', label: 'Name' }]; - const currentFields = viewMode === 'gateways' ? gatewayFields : mcpRuntimeFields; + const currentFields = gatewayFields; // Target fields const currentTarget = currentGateway?.targets?.[selectedTargetIndex]; @@ -135,7 +128,6 @@ function McpEditorBody(props: { async function commitChanges() { const spec: AgentCoreMcpSpec & { unassignedTargets?: AgentCoreGatewayTarget[] } = { agentCoreGateways: gateways, - ...(mcpRuntimeTools.length > 0 ? { mcpRuntimeTools: mcpRuntimeTools } : {}), ...(unassignedTargets.length > 0 ? { unassignedTargets: unassignedTargets } : {}), }; const content = JSON.stringify(spec, null, 2); @@ -239,14 +231,6 @@ function McpEditorBody(props: { return; } - // Tab to switch between gateways and mcp-runtime views - if (key.tab && hasMcpRuntimeTools) { - setViewMode(prev => (prev === 'gateways' ? 'mcp-runtime' : 'gateways')); - setSelectedIndex(0); - setExpandedIndex(null); - return; - } - // A to add (works in both views) if (input.toLowerCase() === 'a' && props.onRequestAdd) { props.onRequestAdd(); @@ -254,7 +238,7 @@ function McpEditorBody(props: { } // View-specific navigation and actions - const items = viewMode === 'gateways' ? gateways : mcpRuntimeTools; + const items = gateways; const itemCount = items.length; if (key.upArrow && itemCount > 0) { @@ -282,13 +266,8 @@ function McpEditorBody(props: { // D to delete if (input.toLowerCase() === 'd' && itemCount > 0) { - if (viewMode === 'gateways') { - const next = gateways.filter((_, idx) => idx !== selectedIndex); - setGateways(next); - } else { - const next = mcpRuntimeTools.filter((_, idx) => idx !== selectedIndex); - setMcpRuntimeTools(next); - } + const next = gateways.filter((_, idx) => idx !== selectedIndex); + setGateways(next); setSelectedIndex(prev => Math.max(0, Math.min(prev, itemCount - 2))); setExpandedIndex(null); setDirty(true); @@ -298,24 +277,21 @@ function McpEditorBody(props: { // Edit item screen - shows list of editable fields if (screenMode === 'edit-item') { - const currentGateway = viewMode === 'gateways' ? gateways[selectedIndex] : null; - const currentTool = viewMode === 'mcp-runtime' ? mcpRuntimeTools[selectedIndex] : null; - const itemName = currentGateway?.name ?? currentTool?.name ?? 'Unknown'; + const currentGateway = gateways[selectedIndex]; + const itemName = currentGateway?.name ?? 'Unknown'; return ( -
+
↑↓ navigate · Enter edit · Esc back {currentFields.map((field, idx) => { const selected = idx === editFieldIndex; let value = ''; - if (viewMode === 'gateways' && currentGateway) { + if (currentGateway) { if (field.id === 'name') value = currentGateway.name; if (field.id === 'description') value = currentGateway.description ?? ''; - } else if (currentTool) { - if (field.id === 'name') value = currentTool.name; } return ( @@ -337,8 +313,7 @@ function McpEditorBody(props: { // Edit field screen - text input for the selected field if (screenMode === 'edit-field' && editingFieldId) { - const currentGateway = viewMode === 'gateways' ? gateways[selectedIndex] : null; - const currentTool = viewMode === 'mcp-runtime' ? mcpRuntimeTools[selectedIndex] : null; + const currentGateway = gateways[selectedIndex]; const field = currentFields.find(f => f.id === editingFieldId); if (!field) { @@ -347,51 +322,35 @@ function McpEditorBody(props: { } let initialValue = ''; - if (viewMode === 'gateways' && currentGateway) { + if (currentGateway) { if (editingFieldId === 'name') initialValue = currentGateway.name; if (editingFieldId === 'description') initialValue = currentGateway.description ?? ''; - } else if (currentTool) { - if (editingFieldId === 'name') initialValue = currentTool.name; } const handleSubmit = (value: string) => { - if (viewMode === 'gateways') { - if (editingFieldId === 'name') { - const next = gateways.map((g, idx) => (idx === selectedIndex ? { ...g, name: value } : g)); - setGateways(next); - } else if (editingFieldId === 'description') { - const next = gateways.map((g, idx) => - idx === selectedIndex ? { ...g, description: value || undefined } : g - ); - setGateways(next); - } - } else { - if (editingFieldId === 'name') { - const next = mcpRuntimeTools.map((t, idx) => (idx === selectedIndex ? { ...t, name: value } : t)); - setMcpRuntimeTools(next); - } + if (editingFieldId === 'name') { + const next = gateways.map((g, idx) => (idx === selectedIndex ? { ...g, name: value } : g)); + setGateways(next); + } else if (editingFieldId === 'description') { + const next = gateways.map((g, idx) => (idx === selectedIndex ? { ...g, description: value || undefined } : g)); + setGateways(next); } setDirty(true); setEditingFieldId(null); setScreenMode('edit-item'); }; - const isGatewayName = viewMode === 'gateways' && editingFieldId === 'name'; - const isToolName = viewMode === 'mcp-runtime' && editingFieldId === 'name'; + const isGatewayName = editingFieldId === 'name'; // Get existing names (excluding current) for uniqueness check let existingNames: string[] = []; if (isGatewayName) { existingNames = gateways.filter((_, idx) => idx !== selectedIndex).map(g => g.name); - } else if (isToolName) { - existingNames = mcpRuntimeTools.filter((_, idx) => idx !== selectedIndex).map(t => t.name); } - const customValidation = - isGatewayName || isToolName - ? (value: string) => - !existingNames.includes(value) || `${isGatewayName ? 'Gateway' : 'Tool'} name already exists` - : undefined; + const customValidation = isGatewayName + ? (value: string) => !existingNames.includes(value) || 'Gateway name already exists' + : undefined; return ( @@ -416,7 +375,7 @@ function McpEditorBody(props: { // Edit targets screen - shows list of targets in the current gateway if (screenMode === 'edit-targets') { - const gateway = viewMode === 'gateways' ? gateways[selectedIndex] : null; + const gateway = gateways[selectedIndex]; const targets = gateway?.targets ?? []; return ( @@ -456,7 +415,7 @@ function McpEditorBody(props: { // Edit target field screen - text input for the selected target field if (screenMode === 'edit-target-field' && editingTargetFieldId) { - const gateway = viewMode === 'gateways' ? gateways[selectedIndex] : null; + const gateway = gateways[selectedIndex]; const target = gateway?.targets?.[selectedTargetIndex]; const field = targetFields.find(f => f.id === editingTargetFieldId); @@ -478,7 +437,7 @@ function McpEditorBody(props: { } const handleSubmit = (value: string) => { - if (viewMode === 'gateways' && gateway) { + if (gateway) { const updatedTargets = [...(gateway.targets ?? [])]; const targetToUpdate = updatedTargets[selectedTargetIndex]; if (targetToUpdate) { @@ -546,7 +505,6 @@ function McpEditorBody(props: { if (screenMode === 'confirm-exit') { const spec: AgentCoreMcpSpec & { unassignedTargets?: AgentCoreGatewayTarget[] } = { agentCoreGateways: gateways, - ...(mcpRuntimeTools.length > 0 ? { mcpRuntimeTools: mcpRuntimeTools } : {}), ...(unassignedTargets.length > 0 ? { unassignedTargets: unassignedTargets } : {}), }; const currentText = JSON.stringify(spec, null, 2); @@ -595,108 +553,58 @@ function McpEditorBody(props: {
- - A add · D del · Space expand · Enter edit{hasMcpRuntimeTools ? ' · Tab switch' : ''} · Esc back - + A add · D del · Space expand · Enter edit · Esc back - {/* Tab bar */} - {hasMcpRuntimeTools && ( - - - [Gateways] - - - [MCP Runtime] - - - )} - - {viewMode === 'gateways' ? ( - - {gateways.length === 0 ? ( - No gateways configured. Press A to add one. - ) : ( - - {gateways.map((gateway, idx) => { - const selected = idx === selectedIndex; - const expanded = expandedIndex === idx; - const targetCount = gateway.targets?.length ?? 0; - return ( - - - {selected ? '>' : ' '} - {expanded ? '▼' : '▶'} - - {gateway.name} - - - ({targetCount} {targetCount === 1 ? 'target' : 'targets'}) - - {gateway.description && · {gateway.description}} - - {expanded && ( - - {targetCount === 0 ? ( - - No targets defined - - ) : ( - gateway.targets.map((target, tIdx) => ( - - · - {target.name ?? `Target ${tIdx + 1}`} - - ({target.toolDefinitions?.length ?? 0} tools ·{' '} - {target.compute?.host ?? target.targetType}) - - - )) - )} - - )} + + {gateways.length === 0 ? ( + No gateways configured. Press A to add one. + ) : ( + + {gateways.map((gateway, idx) => { + const selected = idx === selectedIndex; + const expanded = expandedIndex === idx; + const targetCount = gateway.targets?.length ?? 0; + return ( + + + {selected ? '>' : ' '} + {expanded ? '▼' : '▶'} + + {gateway.name} + + + ({targetCount} {targetCount === 1 ? 'target' : 'targets'}) + + {gateway.description && · {gateway.description}} - ); - })} - - )} - - ) : ( - - {mcpRuntimeTools.length === 0 ? ( - No MCP runtime tools configured. - ) : ( - - {mcpRuntimeTools.map((tool, idx) => { - const selected = idx === selectedIndex; - const expanded = expandedIndex === idx; - return ( - - - {selected ? '>' : ' '} - {expanded ? '▼' : '▶'} - - {tool.name} - - [{tool.compute.host}] + {expanded && ( + + {targetCount === 0 ? ( + + No targets defined + + ) : ( + gateway.targets.map((target, tIdx) => ( + + · + {target.name ?? `Target ${tIdx + 1}`} + + ({target.toolDefinitions?.length ?? 0} tools ·{' '} + {target.compute?.host ?? target.targetType}) + + + )) + )} - {expanded && ( - - Tool: {tool.toolDefinition?.name ?? '(unnamed)'} - Language: {tool.compute.implementation.language} - {'handler' in tool.compute.implementation && ( - Handler: {tool.compute.implementation.handler} - )} - - )} - - ); - })} - - )} - - )} + )} + + ); + })} + + )} + {/* Unassigned Targets */}