Skip to content

Commit 12cb4ff

Browse files
committed
feat: add target type picker to gateway target wizard (#496)
* feat: add target type picker to gateway target wizard - Add targetType field to AddGatewayTargetConfig and 'target-type' wizard step - Convert wizard from static to dynamic steps (useMemo with config.targetType dep) - Fix goBack() to use memoized steps instead of stale getSteps() call - Add TARGET_TYPE_OPTIONS with mcpServer as initial option - Add WizardSelect UI for target type selection in AddGatewayTargetScreen - Route flow on config.targetType instead of config.source - Remove source field, SOURCE_OPTIONS, and 'source' step (dead code) * feat: make --type required and remove --source for gateway-target CLI - Make --type required with kebab-case input (mcp-server -> mcpServer) - Remove --source option entirely (was dead code, only existing-endpoint worked) - Wire options.type through buildGatewayTargetConfig to config.targetType - Route handleAddGatewayTarget on config.targetType instead of config.source - Use config.targetType in createExternalGatewayTarget instead of hardcoding * test: update gateway-target tests for target type picker - Replace source: 'existing-endpoint' with type: 'mcp-server' in all fixtures - Add type: 'mcpServer' to ValidatedAddGatewayTargetOptions test objects - Add tests for --type required validation and invalid type rejection - Replace SOURCE_OPTIONS test with TARGET_TYPE_OPTIONS test - Fix shared fixture mutation bug (spread before passing to validation) - Add --type mcp-server to CLI integration test args * docs: update gateway-target examples to use --type mcp-server - Replace --source existing-endpoint with --type mcp-server in all examples - Update flags table: --source -> --type (required) - Update commands.md, gateway.md, and local-development.md * fix: reset command.tsx and create-mcp.test.ts to main versions These files were incorrectly carried from our pre-rebase branch during conflict resolution (--theirs/--ours reversed in rebase context). The modular primitive PR moved their contents to GatewayTargetPrimitive.ts. * ci: retrigger checks * test: add missing --type flag to remove gateway-target tests
1 parent 5f0695d commit 12cb4ff

File tree

16 files changed

+153
-82
lines changed

16 files changed

+153
-82
lines changed

docs/commands.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,14 @@ agentcore add
198198
# External MCP server endpoint
199199
agentcore add gateway-target \
200200
--name WeatherTools \
201-
--source existing-endpoint \
201+
--type mcp-server \
202202
--endpoint https://mcp.example.com/mcp \
203203
--gateway MyGateway
204204

205205
# External endpoint with OAuth outbound auth
206206
agentcore add gateway-target \
207207
--name SecureTools \
208-
--source existing-endpoint \
208+
--type mcp-server \
209209
--endpoint https://api.example.com/mcp \
210210
--gateway MyGateway \
211211
--outbound-auth oauth \
@@ -218,7 +218,7 @@ agentcore add gateway-target \
218218
| -------------------------------- | ----------------------------------------------- |
219219
| `--name <name>` | Target name |
220220
| `--description <desc>` | Target description |
221-
| `--source <source>` | `existing-endpoint` |
221+
| `--type <type>` | Target type (required): `mcp-server` |
222222
| `--endpoint <url>` | MCP server endpoint URL |
223223
| `--gateway <name>` | Gateway to attach target to |
224224
| `--outbound-auth <type>` | `oauth`, `api-key`, or `none` |
@@ -382,7 +382,7 @@ agentcore deploy -y
382382
agentcore add gateway --name MyGateway
383383
agentcore add gateway-target \
384384
--name WeatherTools \
385-
--source existing-endpoint \
385+
--type mcp-server \
386386
--endpoint https://mcp.example.com/mcp \
387387
--gateway MyGateway
388388
agentcore deploy -y

docs/gateway.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ agentcore add gateway --name my-gateway
1818

1919
# 3. Add a target (external MCP server)
2020
agentcore add gateway-target \
21-
--source existing-endpoint \
21+
--type mcp-server \
2222
--name weather-tools \
2323
--endpoint https://mcp.example.com/mcp \
2424
--gateway my-gateway
@@ -39,7 +39,7 @@ requests to.
3939

4040
```bash
4141
agentcore add gateway-target \
42-
--source existing-endpoint \
42+
--type mcp-server \
4343
--name my-tools \
4444
--endpoint https://mcp.example.com/mcp \
4545
--gateway my-gateway
@@ -87,7 +87,7 @@ Controls how the gateway authenticates with upstream MCP servers. Configured per
8787

8888
```bash
8989
agentcore add gateway-target \
90-
--source existing-endpoint \
90+
--type mcp-server \
9191
--name secure-tools \
9292
--endpoint https://api.example.com/mcp \
9393
--gateway my-gateway \
@@ -108,7 +108,7 @@ agentcore add identity \
108108
--client-secret my-secret
109109

110110
agentcore add gateway-target \
111-
--source existing-endpoint \
111+
--type mcp-server \
112112
--name secure-tools \
113113
--endpoint https://api.example.com/mcp \
114114
--gateway my-gateway \
@@ -129,7 +129,7 @@ include gateway client code with the correct authentication for your framework.
129129
# 1. Add gateway and targets
130130
agentcore add gateway --name my-gateway
131131
agentcore add gateway-target \
132-
--source existing-endpoint \
132+
--type mcp-server \
133133
--name my-tools \
134134
--endpoint https://mcp.example.com/mcp \
135135
--gateway my-gateway

docs/local-development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ populated by `agentcore deploy`. If you haven't deployed yet, no gateway env var
142142
```bash
143143
# 1. Add a gateway and target
144144
agentcore add gateway --name my-gateway
145-
agentcore add gateway-target --name my-tools --source existing-endpoint \
145+
agentcore add gateway-target --name my-tools --type mcp-server \
146146
--endpoint https://mcp.example.com/mcp --gateway my-gateway
147147

148148
# 2. Deploy to create the gateway

integ-tests/add-remove-gateway.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ describe('integration: add and remove gateway with external MCP server', () => {
4242
'gateway-target',
4343
'--name',
4444
targetName,
45+
'--type',
46+
'mcp-server',
4547
'--endpoint',
4648
'https://mcp.exa.ai/mcp',
4749
'--gateway',

src/cli/commands/add/__tests__/add-gateway-target.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('add gateway-target command', () => {
4444

4545
it('requires endpoint', async () => {
4646
const result = await runCLI(
47-
['add', 'gateway-target', '--name', 'noendpoint', '--gateway', gatewayName, '--json'],
47+
['add', 'gateway-target', '--name', 'noendpoint', '--type', 'mcp-server', '--gateway', gatewayName, '--json'],
4848
projectDir
4949
);
5050
expect(result.exitCode).toBe(1);
@@ -63,6 +63,8 @@ describe('add gateway-target command', () => {
6363
'gateway-target',
6464
'--name',
6565
targetName,
66+
'--type',
67+
'mcp-server',
6668
'--endpoint',
6769
'https://mcp.exa.ai/mcp',
6870
'--gateway',

src/cli/commands/add/__tests__/validate.test.ts

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const validGatewayOptionsJwt: AddGatewayOptions = {
6060

6161
const validGatewayTargetOptions: AddGatewayTargetOptions = {
6262
name: 'test-tool',
63-
source: 'existing-endpoint',
63+
type: 'mcp-server',
6464
endpoint: 'https://example.com/mcp',
6565
gateway: 'my-gateway',
6666
};
@@ -326,15 +326,15 @@ describe('validate', () => {
326326

327327
it('returns error when no gateways exist', async () => {
328328
mockReadMcpSpec.mockResolvedValue({ agentCoreGateways: [] });
329-
const result = await validateAddGatewayTargetOptions(validGatewayTargetOptions);
329+
const result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptions });
330330
expect(result.valid).toBe(false);
331331
expect(result.error).toContain('No gateways found');
332332
expect(result.error).toContain('agentcore add gateway');
333333
});
334334

335335
it('returns error when specified gateway does not exist', async () => {
336336
mockReadMcpSpec.mockResolvedValue({ agentCoreGateways: [{ name: 'other-gateway' }] });
337-
const result = await validateAddGatewayTargetOptions(validGatewayTargetOptions);
337+
const result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptions });
338338
expect(result.valid).toBe(false);
339339
expect(result.error).toContain('Gateway "my-gateway" not found');
340340
expect(result.error).toContain('other-gateway');
@@ -345,22 +345,21 @@ describe('validate', () => {
345345
const result = await validateAddGatewayTargetOptions({ ...validGatewayTargetOptions });
346346
expect(result.valid).toBe(true);
347347
});
348-
// AC20: existing-endpoint source validation
349-
it('rejects create-new source', async () => {
348+
// AC20: type validation
349+
it('returns error when --type is missing', async () => {
350350
const options: AddGatewayTargetOptions = {
351351
name: 'test-tool',
352-
source: 'create-new' as any,
353352
gateway: 'my-gateway',
354353
};
355354
const result = await validateAddGatewayTargetOptions(options);
356355
expect(result.valid).toBe(false);
357-
expect(result.error).toBe("Only 'existing-endpoint' source is currently supported");
356+
expect(result.error).toContain('--type is required');
358357
});
359358

360-
it('passes for valid existing-endpoint with https', async () => {
359+
it('accepts --type mcp-server', async () => {
361360
const options: AddGatewayTargetOptions = {
362361
name: 'test-tool',
363-
source: 'existing-endpoint',
362+
type: 'mcp-server',
364363
endpoint: 'https://example.com/mcp',
365364
gateway: 'my-gateway',
366365
};
@@ -369,32 +368,54 @@ describe('validate', () => {
369368
expect(options.language).toBe('Other');
370369
});
371370

372-
it('passes for valid existing-endpoint with http', async () => {
371+
it('returns error for invalid --type', async () => {
372+
const options: AddGatewayTargetOptions = {
373+
name: 'test-tool',
374+
type: 'invalid',
375+
gateway: 'my-gateway',
376+
};
377+
const result = await validateAddGatewayTargetOptions(options);
378+
expect(result.valid).toBe(false);
379+
expect(result.error).toContain('Invalid type');
380+
});
381+
382+
it('passes for mcp-server with https endpoint', async () => {
383+
const options: AddGatewayTargetOptions = {
384+
name: 'test-tool',
385+
type: 'mcp-server',
386+
endpoint: 'https://example.com/mcp',
387+
gateway: 'my-gateway',
388+
};
389+
const result = await validateAddGatewayTargetOptions(options);
390+
expect(result.valid).toBe(true);
391+
});
392+
393+
it('passes for mcp-server with http endpoint', async () => {
373394
const options: AddGatewayTargetOptions = {
374395
name: 'test-tool',
375-
source: 'existing-endpoint',
396+
type: 'mcp-server',
376397
endpoint: 'http://localhost:3000/mcp',
377398
gateway: 'my-gateway',
378399
};
379400
const result = await validateAddGatewayTargetOptions(options);
380401
expect(result.valid).toBe(true);
381402
});
382403

383-
it('returns error for existing-endpoint without endpoint', async () => {
404+
it('returns error for mcp-server without endpoint', async () => {
384405
const options: AddGatewayTargetOptions = {
385406
name: 'test-tool',
386-
source: 'existing-endpoint',
407+
type: 'mcp-server',
387408
gateway: 'my-gateway',
388409
};
389410
const result = await validateAddGatewayTargetOptions(options);
390411
expect(result.valid).toBe(false);
391-
expect(result.error).toBe('--endpoint is required when source is existing-endpoint');
412+
expect(result.error).toContain('--endpoint is required');
392413
});
393414

394-
it('returns error for existing-endpoint with non-http(s) URL', async () => {
415+
it('returns error for mcp-server with non-http(s) URL', async () => {
395416
const options: AddGatewayTargetOptions = {
396417
name: 'test-tool',
397-
source: 'existing-endpoint',
418+
type: 'mcp-server',
398419
endpoint: 'ftp://example.com/mcp',
399420
gateway: 'my-gateway',
400421
};
@@ -403,10 +424,10 @@ describe('validate', () => {
403424
expect(result.error).toBe('Endpoint must use http:// or https:// protocol');
404425
});
405426

406-
it('returns error for existing-endpoint with invalid URL', async () => {
427+
it('returns error for mcp-server with invalid URL', async () => {
407428
const options: AddGatewayTargetOptions = {
408429
name: 'test-tool',
409-
source: 'existing-endpoint',
430+
type: 'mcp-server',
410431
endpoint: 'not-a-url',
411432
gateway: 'my-gateway',
412433
};
@@ -423,6 +444,7 @@ describe('validate', () => {
423444

424445
const options: AddGatewayTargetOptions = {
425446
name: 'test-tool',
447+
type: 'mcp-server',
426448
endpoint: 'https://example.com/mcp',
427449
gateway: 'my-gateway',
428450
outboundAuthType: 'API_KEY',
@@ -440,6 +462,7 @@ describe('validate', () => {
440462

441463
const options: AddGatewayTargetOptions = {
442464
name: 'test-tool',
465+
type: 'mcp-server',
443466
endpoint: 'https://example.com/mcp',
444467
gateway: 'my-gateway',
445468
outboundAuthType: 'API_KEY',
@@ -457,6 +480,7 @@ describe('validate', () => {
457480

458481
const options: AddGatewayTargetOptions = {
459482
name: 'test-tool',
483+
type: 'mcp-server',
460484
endpoint: 'https://example.com/mcp',
461485
gateway: 'my-gateway',
462486
outboundAuthType: 'API_KEY',
@@ -531,17 +555,17 @@ describe('validate', () => {
531555
expect(result.error).toBe('--oauth-discovery-url must be a valid URL');
532556
});
533557

534-
it('rejects --host with existing-endpoint', async () => {
558+
it('rejects --host with mcp-server type', async () => {
535559
const options: AddGatewayTargetOptions = {
536560
name: 'test-tool',
537-
source: 'existing-endpoint',
561+
type: 'mcp-server',
538562
endpoint: 'https://example.com/mcp',
539563
host: 'Lambda',
540564
gateway: 'my-gateway',
541565
};
542566
const result = await validateAddGatewayTargetOptions(options);
543567
expect(result.valid).toBe(false);
544-
expect(result.error).toBe('--host is not applicable for existing endpoint targets');
568+
expect(result.error).toBe('--host is not applicable for MCP server targets');
545569
});
546570
});
547571

src/cli/commands/add/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export interface AddGatewayTargetOptions {
4949
name?: string;
5050
description?: string;
5151
type?: string;
52-
source?: string;
5352
endpoint?: string;
5453
language?: 'Python' | 'TypeScript' | 'Other';
5554
gateway?: string;

src/cli/commands/add/validate.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,16 @@ export async function validateAddGatewayTargetOptions(options: AddGatewayTargetO
219219
return { valid: false, error: '--name is required' };
220220
}
221221

222-
if (options.type && options.type !== 'mcpServer' && options.type !== 'lambda') {
223-
return { valid: false, error: 'Invalid type. Valid options: mcpServer, lambda' };
222+
if (!options.type) {
223+
return { valid: false, error: '--type is required. Valid options: mcp-server' };
224224
}
225225

226-
if (options.source && options.source !== 'existing-endpoint') {
227-
return { valid: false, error: "Only 'existing-endpoint' source is currently supported" };
226+
const typeMap: Record<string, string> = { 'mcp-server': 'mcpServer' };
227+
const mappedType = typeMap[options.type];
228+
if (!mappedType) {
229+
return { valid: false, error: `Invalid type: ${options.type}. Valid options: mcp-server` };
228230
}
231+
options.type = mappedType;
229232

230233
// Gateway is required — a gateway target must be attached to a gateway
231234
if (!options.gateway) {
@@ -260,10 +263,7 @@ export async function validateAddGatewayTargetOptions(options: AddGatewayTargetO
260263
};
261264
}
262265

263-
// Default to existing-endpoint (only supported source for now)
264-
options.source ??= 'existing-endpoint';
265-
266-
// Validate outbound auth configuration (applies to all source types)
266+
// Validate outbound auth configuration
267267
if (options.outboundAuthType && options.outboundAuthType !== 'NONE') {
268268
const hasInlineOAuth = !!(options.oauthClientId ?? options.oauthClientSecret ?? options.oauthDiscoveryUrl);
269269

@@ -309,12 +309,12 @@ export async function validateAddGatewayTargetOptions(options: AddGatewayTargetO
309309
}
310310
}
311311

312-
if (options.source === 'existing-endpoint') {
312+
if (mappedType === 'mcpServer') {
313313
if (options.host) {
314-
return { valid: false, error: '--host is not applicable for existing endpoint targets' };
314+
return { valid: false, error: '--host is not applicable for MCP server targets' };
315315
}
316316
if (!options.endpoint) {
317-
return { valid: false, error: '--endpoint is required when source is existing-endpoint' };
317+
return { valid: false, error: '--endpoint is required for mcp-server type' };
318318
}
319319

320320
try {

src/cli/commands/remove/__tests__/remove-gateway-target.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ describe('remove gateway-target command', () => {
6363
'https://example.com/mcp',
6464
'--gateway',
6565
tempGateway,
66+
'--type',
67+
'mcp-server',
6668
'--json',
6769
],
6870
projectDir

src/cli/commands/remove/__tests__/remove-gateway.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ describe('remove gateway command', () => {
108108
'https://example.com/mcp',
109109
'--gateway',
110110
gatewayName,
111+
'--type',
112+
'mcp-server',
111113
'--json',
112114
],
113115
projectDir

0 commit comments

Comments
 (0)