@adcp/client 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/bin/adcp.js +536 -20
  2. package/dist/lib/agents/index.generated.d.ts +9 -1
  3. package/dist/lib/agents/index.generated.d.ts.map +1 -1
  4. package/dist/lib/agents/index.generated.js +12 -0
  5. package/dist/lib/agents/index.generated.js.map +1 -1
  6. package/dist/lib/auth/index.d.ts +1 -0
  7. package/dist/lib/auth/index.d.ts.map +1 -1
  8. package/dist/lib/auth/index.js +16 -0
  9. package/dist/lib/auth/index.js.map +1 -1
  10. package/dist/lib/auth/oauth/CLIFlowHandler.d.ts +61 -0
  11. package/dist/lib/auth/oauth/CLIFlowHandler.d.ts.map +1 -0
  12. package/dist/lib/auth/oauth/CLIFlowHandler.js +287 -0
  13. package/dist/lib/auth/oauth/CLIFlowHandler.js.map +1 -0
  14. package/dist/lib/auth/oauth/MCPOAuthProvider.d.ts +126 -0
  15. package/dist/lib/auth/oauth/MCPOAuthProvider.d.ts.map +1 -0
  16. package/dist/lib/auth/oauth/MCPOAuthProvider.js +236 -0
  17. package/dist/lib/auth/oauth/MCPOAuthProvider.js.map +1 -0
  18. package/dist/lib/auth/oauth/index.d.ts +104 -0
  19. package/dist/lib/auth/oauth/index.d.ts.map +1 -0
  20. package/dist/lib/auth/oauth/index.js +168 -0
  21. package/dist/lib/auth/oauth/index.js.map +1 -0
  22. package/dist/lib/auth/oauth/types.d.ts +114 -0
  23. package/dist/lib/auth/oauth/types.d.ts.map +1 -0
  24. package/dist/lib/auth/oauth/types.js +104 -0
  25. package/dist/lib/auth/oauth/types.js.map +1 -0
  26. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  27. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  28. package/dist/lib/core/TaskExecutor.js +46 -10
  29. package/dist/lib/core/TaskExecutor.js.map +1 -1
  30. package/dist/lib/index.d.ts +1 -0
  31. package/dist/lib/index.d.ts.map +1 -1
  32. package/dist/lib/index.js +11 -3
  33. package/dist/lib/index.js.map +1 -1
  34. package/dist/lib/protocols/index.d.ts +2 -1
  35. package/dist/lib/protocols/index.d.ts.map +1 -1
  36. package/dist/lib/protocols/index.js +4 -1
  37. package/dist/lib/protocols/index.js.map +1 -1
  38. package/dist/lib/protocols/mcp.d.ts +80 -0
  39. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  40. package/dist/lib/protocols/mcp.js +158 -0
  41. package/dist/lib/protocols/mcp.js.map +1 -1
  42. package/dist/lib/testing/agent-tester.d.ts +1 -1
  43. package/dist/lib/testing/agent-tester.d.ts.map +1 -1
  44. package/dist/lib/testing/agent-tester.js +39 -1
  45. package/dist/lib/testing/agent-tester.js.map +1 -1
  46. package/dist/lib/testing/index.d.ts +1 -1
  47. package/dist/lib/testing/index.d.ts.map +1 -1
  48. package/dist/lib/testing/index.js +11 -1
  49. package/dist/lib/testing/index.js.map +1 -1
  50. package/dist/lib/testing/scenarios/capabilities.d.ts +27 -0
  51. package/dist/lib/testing/scenarios/capabilities.d.ts.map +1 -0
  52. package/dist/lib/testing/scenarios/capabilities.js +250 -0
  53. package/dist/lib/testing/scenarios/capabilities.js.map +1 -0
  54. package/dist/lib/testing/scenarios/governance.d.ts +35 -0
  55. package/dist/lib/testing/scenarios/governance.d.ts.map +1 -0
  56. package/dist/lib/testing/scenarios/governance.js +428 -0
  57. package/dist/lib/testing/scenarios/governance.js.map +1 -0
  58. package/dist/lib/testing/scenarios/index.d.ts +3 -0
  59. package/dist/lib/testing/scenarios/index.d.ts.map +1 -1
  60. package/dist/lib/testing/scenarios/index.js +15 -1
  61. package/dist/lib/testing/scenarios/index.js.map +1 -1
  62. package/dist/lib/testing/scenarios/sponsored-intelligence.d.ts +34 -0
  63. package/dist/lib/testing/scenarios/sponsored-intelligence.d.ts.map +1 -0
  64. package/dist/lib/testing/scenarios/sponsored-intelligence.js +318 -0
  65. package/dist/lib/testing/scenarios/sponsored-intelligence.js.map +1 -0
  66. package/dist/lib/testing/types.d.ts +9 -1
  67. package/dist/lib/testing/types.d.ts.map +1 -1
  68. package/dist/lib/types/adcp.d.ts +47 -1
  69. package/dist/lib/types/adcp.d.ts.map +1 -1
  70. package/dist/lib/types/core.generated.d.ts +393 -164
  71. package/dist/lib/types/core.generated.d.ts.map +1 -1
  72. package/dist/lib/types/core.generated.js +2 -2
  73. package/dist/lib/types/core.generated.js.map +1 -1
  74. package/dist/lib/types/schemas.generated.d.ts +1275 -845
  75. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  76. package/dist/lib/types/schemas.generated.js +300 -198
  77. package/dist/lib/types/schemas.generated.js.map +1 -1
  78. package/dist/lib/types/tools.generated.d.ts +461 -167
  79. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  80. package/dist/lib/types/tools.generated.js +1 -1
  81. package/dist/lib/types/tools.generated.js.map +1 -1
  82. package/dist/lib/version.d.ts +5 -5
  83. package/dist/lib/version.d.ts.map +1 -1
  84. package/dist/lib/version.js +5 -5
  85. package/dist/lib/version.js.map +1 -1
  86. package/package.json +2 -2
package/bin/adcp.js CHANGED
@@ -17,7 +17,21 @@
17
17
  const { AdCPClient, detectProtocol, usesDeprecatedAssetsField } = require('../dist/lib/index.js');
18
18
  const { readFileSync } = require('fs');
19
19
  const { AsyncWebhookHandler } = require('./adcp-async-handler.js');
20
- const { getAgent, listAgents, isAlias, interactiveSetup, removeAgent, getConfigPath } = require('./adcp-config.js');
20
+ const {
21
+ getAgent,
22
+ listAgents,
23
+ isAlias,
24
+ interactiveSetup,
25
+ removeAgent,
26
+ getConfigPath,
27
+ saveAgent,
28
+ } = require('./adcp-config.js');
29
+ const {
30
+ createCLIOAuthProvider,
31
+ hasValidOAuthTokens,
32
+ clearOAuthTokens,
33
+ getEffectiveAuthToken,
34
+ } = require('../dist/lib/auth/oauth/index.js');
21
35
 
22
36
  // Test scenarios available
23
37
  const TEST_SCENARIOS = [
@@ -35,13 +49,19 @@ const TEST_SCENARIOS = [
35
49
  'temporal_validation',
36
50
  'behavior_analysis',
37
51
  'response_consistency',
52
+ // v3 protocol scenarios
53
+ 'capability_discovery',
54
+ 'governance_property_lists',
55
+ 'governance_content_standards',
56
+ 'si_session_lifecycle',
57
+ 'si_availability',
38
58
  ];
39
59
 
40
60
  // Built-in test agent aliases (shared between main CLI and test command)
41
61
  // Note: These tokens are intentionally public for the AdCP test infrastructure.
42
62
  // They provide rate-limited access to test agents for SDK development and examples.
43
63
  const BUILT_IN_AGENTS = {
44
- test: {
64
+ 'test-mcp': {
45
65
  url: 'https://test-agent.adcontextprotocol.org/mcp/',
46
66
  protocol: 'mcp',
47
67
  auth_token: '1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ',
@@ -221,6 +241,12 @@ async function handleTestCommand(args) {
221
241
  temporal_validation: 'Test date/time ordering and format validation',
222
242
  behavior_analysis: 'Analyze agent behavior: auth, brief relevance, filtering',
223
243
  response_consistency: 'Check for schema errors, pagination bugs, data mismatches',
244
+ // v3 protocol scenarios
245
+ capability_discovery: 'Test get_adcp_capabilities and verify v3 protocol support',
246
+ governance_property_lists: 'Test property list CRUD (create, get, update, delete)',
247
+ governance_content_standards: 'Test content standards listing and calibration',
248
+ si_session_lifecycle: 'Test full SI session: initiate → messages → terminate',
249
+ si_availability: 'Quick check for SI offering availability',
224
250
  };
225
251
 
226
252
  for (const scenario of TEST_SCENARIOS) {
@@ -318,7 +344,7 @@ async function handleTestCommand(args) {
318
344
  agentUrl = agentArg;
319
345
  } else {
320
346
  console.error(`ERROR: '${agentArg}' is not a valid agent alias or URL\n`);
321
- console.error('Built-in aliases: test, test-a2a, creative');
347
+ console.error('Built-in aliases: test-mcp, test-a2a, creative');
322
348
  console.error(`Saved aliases: ${Object.keys(listAgents()).join(', ') || 'none'}\n`);
323
349
  process.exit(2);
324
350
  }
@@ -402,7 +428,7 @@ USAGE:
402
428
  npx @adcp/client <agent-alias|url> [tool-name] [payload] [options]
403
429
 
404
430
  ARGUMENTS:
405
- agent-alias|url Saved agent alias (e.g., 'test') or full URL to agent endpoint
431
+ agent-alias|url Saved agent alias (e.g., 'test-mcp') or full URL to agent endpoint
406
432
  tool-name Name of the tool to call (optional - omit to list available tools)
407
433
  payload JSON payload for the tool (default: {})
408
434
  - Can be inline JSON: '{"brief":"text"}'
@@ -412,6 +438,8 @@ ARGUMENTS:
412
438
  OPTIONS:
413
439
  --protocol PROTO Force protocol: 'mcp' or 'a2a' (default: auto-detect)
414
440
  --auth TOKEN Authentication token for the agent
441
+ --oauth Use OAuth for authentication (MCP only, opens browser)
442
+ --clear-oauth Clear saved OAuth tokens for an agent
415
443
  --wait Wait for async/webhook responses (requires ngrok or --local)
416
444
  --local Use local webhook without ngrok (for local agents only)
417
445
  --timeout MS Webhook timeout in milliseconds (default: 300000 = 5min)
@@ -420,16 +448,18 @@ OPTIONS:
420
448
  --debug Show debug information
421
449
 
422
450
  BUILT-IN TEST AGENTS:
423
- test AdCP public test agent (MCP, with auth)
451
+ test-mcp AdCP public test agent (MCP, with auth)
424
452
  test-a2a AdCP public test agent (A2A, with auth)
425
453
  test-no-auth AdCP public test agent (MCP, no auth - demonstrates errors)
426
454
  test-a2a-no-auth AdCP public test agent (A2A, no auth - demonstrates errors)
427
455
  creative Official AdCP creative agent (MCP only)
428
456
 
429
457
  AGENT MANAGEMENT:
430
- --save-auth <alias> [url] [protocol] [--auth token | --no-auth]
458
+ --save-auth <alias> [url] [protocol] [--auth token | --no-auth | --oauth]
431
459
  Save agent configuration with an alias name
432
- Requires --auth or --no-auth for non-interactive mode
460
+ --auth TOKEN: Save with static auth token
461
+ --no-auth: Save without authentication
462
+ --oauth: Authenticate via OAuth and save tokens (MCP only)
433
463
  --list-agents List all saved agents
434
464
  --remove-agent <alias> Remove saved agent configuration
435
465
  --show-config Show config file location
@@ -443,8 +473,8 @@ AGENT TESTING:
443
473
 
444
474
  EXAMPLES:
445
475
  # Use built-in test agent (zero config!)
446
- npx @adcp/client test
447
- npx @adcp/client test get_products '{"brief":"coffee brands"}'
476
+ npx @adcp/client test-mcp
477
+ npx @adcp/client test-mcp get_products '{"brief":"coffee brands"}'
448
478
  npx @adcp/client creative list_creative_formats
449
479
 
450
480
  # Use built-in test agent with A2A protocol
@@ -459,6 +489,9 @@ EXAMPLES:
459
489
  # Non-interactive: save without auth
460
490
  adcp --save-auth myagent https://test-agent.adcontextprotocol.org --no-auth
461
491
 
492
+ # Save with OAuth (opens browser, saves tokens)
493
+ adcp --save-auth myagent https://oauth-server.com/mcp --oauth
494
+
462
495
  # Interactive setup (prompts for URL, protocol, and auth)
463
496
  adcp --save-auth myagent
464
497
 
@@ -479,6 +512,17 @@ EXAMPLES:
479
512
  # Override saved auth token
480
513
  adcp myagent get_products '{"brief":"..."}' --auth different-token
481
514
 
515
+ # OAuth authentication (opens browser for login)
516
+ adcp https://oauth-agent.example.com/mcp --oauth
517
+ adcp myagent get_products '{"brief":"..."}' --oauth # Saves tokens to alias
518
+
519
+ # Auto-detect OAuth (automatically starts OAuth if server requires it)
520
+ adcp https://oauth-server.com/mcp get_products '{"brief":"..."}' # Auto-detects!
521
+
522
+ # Clear OAuth tokens and re-authenticate
523
+ adcp myagent --clear-oauth
524
+ adcp myagent --oauth
525
+
482
526
  # Wait for async response (requires ngrok)
483
527
  adcp myagent create_media_buy @payload.json --wait
484
528
 
@@ -490,9 +534,9 @@ EXAMPLES:
490
534
  adcp myagent get_products '{"brief":"travel"}' --json | jq '.products[0]'
491
535
 
492
536
  # Run agent tests
493
- adcp test test # Test built-in test agent with discovery scenario
494
- adcp test test discovery # Explicit discovery scenario
495
- adcp test test full_sales_flow # Full media buy lifecycle test
537
+ adcp test test-mcp # Test built-in test agent with discovery scenario
538
+ adcp test test-mcp discovery # Explicit discovery scenario
539
+ adcp test test-mcp full_sales_flow # Full media buy lifecycle test
496
540
  adcp test https://my-agent.com discovery --auth $TOKEN
497
541
  adcp test myagent error_handling --json # JSON output for CI
498
542
  adcp test --list-scenarios # Show all available scenarios
@@ -526,12 +570,13 @@ async function main() {
526
570
  // Parse flags first
527
571
  const authFlagIndex = args.indexOf('--auth');
528
572
  const noAuthFlag = args.includes('--no-auth');
573
+ const oauthFlag = args.includes('--oauth');
529
574
  const providedAuthToken = authFlagIndex !== -1 ? args[authFlagIndex + 1] : null;
530
575
 
531
576
  // Filter out flags to get positional args
532
577
  const saveAuthPositional = args
533
578
  .slice(1)
534
- .filter(arg => arg !== '--auth' && arg !== '--no-auth' && arg !== providedAuthToken);
579
+ .filter(arg => arg !== '--auth' && arg !== '--no-auth' && arg !== '--oauth' && arg !== providedAuthToken);
535
580
 
536
581
  let alias = saveAuthPositional[0];
537
582
  let url = saveAuthPositional[1] || null;
@@ -539,8 +584,9 @@ async function main() {
539
584
 
540
585
  if (!alias) {
541
586
  console.error('ERROR: --save-auth requires an alias\n');
542
- console.error('Usage: adcp --save-auth <alias> [url] [protocol] [--auth token | --no-auth]\n');
587
+ console.error('Usage: adcp --save-auth <alias> [url] [protocol] [--auth token | --no-auth | --oauth]\n');
543
588
  console.error('Example: adcp --save-auth myagent https://agent.example.com --auth your_token\n');
589
+ console.error(' adcp --save-auth myagent https://oauth-server.com/mcp --oauth\n');
544
590
  process.exit(2);
545
591
  }
546
592
 
@@ -554,12 +600,98 @@ async function main() {
554
600
  process.exit(2);
555
601
  }
556
602
 
557
- // Validate flags
558
- if (providedAuthToken && noAuthFlag) {
559
- console.error('ERROR: Cannot use both --auth and --no-auth\n');
603
+ // Validate flags - only one auth method allowed
604
+ const authMethods = [providedAuthToken !== null, noAuthFlag, oauthFlag].filter(Boolean).length;
605
+ if (authMethods > 1) {
606
+ console.error('ERROR: Cannot use multiple auth methods (--auth, --no-auth, --oauth)\n');
560
607
  process.exit(2);
561
608
  }
562
609
 
610
+ // Handle OAuth save flow
611
+ if (oauthFlag) {
612
+ if (!url) {
613
+ console.error('ERROR: --oauth requires a URL\n');
614
+ console.error('Usage: adcp --save-auth <alias> <url> --oauth\n');
615
+ process.exit(2);
616
+ }
617
+
618
+ // OAuth is only for MCP
619
+ const detectedProtocol = protocol || (url.includes('/mcp') ? 'mcp' : null);
620
+ if (detectedProtocol && detectedProtocol !== 'mcp') {
621
+ console.error('ERROR: OAuth is only supported for MCP protocol\n');
622
+ process.exit(2);
623
+ }
624
+
625
+ console.log(`\nšŸ” Setting up OAuth for '${alias}'...`);
626
+ console.log(`URL: ${url}\n`);
627
+
628
+ // Create a temporary agent config for OAuth
629
+ const tempAgent = {
630
+ id: alias,
631
+ name: alias,
632
+ agent_uri: url,
633
+ protocol: 'mcp',
634
+ };
635
+
636
+ const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
637
+ const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
638
+ const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
639
+
640
+ const oauthProvider = createCLIOAuthProvider(tempAgent);
641
+ const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
642
+ const createTransport = () => new StreamableHTTPClientTransport(new URL(url), { authProvider: oauthProvider });
643
+
644
+ let transport = createTransport();
645
+
646
+ try {
647
+ console.log('Connecting to verify OAuth support...');
648
+ await mcpClient.connect(transport);
649
+ // If we connected without OAuth, the server doesn't require it
650
+ console.log('\nāš ļø Server connected without requiring OAuth.');
651
+ console.log('Saving agent without OAuth tokens.\n');
652
+ await oauthProvider.cleanup();
653
+ await mcpClient.close();
654
+ saveAgent(alias, { url, protocol: 'mcp' });
655
+ console.log(`āœ… Agent '${alias}' saved.`);
656
+ console.log(`Use: adcp ${alias} <tool> <payload>\n`);
657
+ } catch (error) {
658
+ if (error instanceof UnauthorizedError || error.name === 'UnauthorizedError') {
659
+ console.log('OAuth authorization required.');
660
+ console.log('Opening browser for authentication...\n');
661
+
662
+ try {
663
+ const code = await oauthProvider.waitForCallback();
664
+ console.log('Authorization received!');
665
+ await transport.finishAuth(code);
666
+
667
+ // Save agent with OAuth tokens
668
+ const agentConfig = {
669
+ url,
670
+ protocol: 'mcp',
671
+ oauth_tokens: tempAgent.oauth_tokens,
672
+ oauth_client: tempAgent.oauth_client,
673
+ };
674
+ saveAgent(alias, agentConfig);
675
+
676
+ console.log(`\nāœ… Agent '${alias}' saved with OAuth tokens.`);
677
+ console.log(`Use: adcp ${alias} <tool> <payload>\n`);
678
+
679
+ await oauthProvider.cleanup();
680
+ await mcpClient.close();
681
+ } catch (authError) {
682
+ await oauthProvider.cleanup();
683
+ console.error('\nāŒ OAuth failed:', authError.message);
684
+ process.exit(1);
685
+ }
686
+ } else {
687
+ await oauthProvider.cleanup();
688
+ console.error('\nāŒ Connection failed:', error.message);
689
+ process.exit(1);
690
+ }
691
+ }
692
+ process.exit(0);
693
+ }
694
+
563
695
  // Determine mode:
564
696
  // - If URL provided AND (--auth or --no-auth): fully non-interactive
565
697
  // - Otherwise: interactive (prompts for missing values)
@@ -589,7 +721,11 @@ async function main() {
589
721
  console.log(` Protocol: ${agent.protocol}`);
590
722
  }
591
723
  if (agent.auth_token) {
592
- console.log(` Auth: configured`);
724
+ console.log(` Auth: token configured`);
725
+ }
726
+ if (agent.oauth_tokens) {
727
+ const hasValid = hasValidOAuthTokens(agent);
728
+ console.log(` OAuth: ${hasValid ? 'valid tokens' : 'expired (use --oauth to refresh)'}`);
593
729
  }
594
730
  console.log('');
595
731
  });
@@ -619,6 +755,39 @@ async function main() {
619
755
  process.exit(0);
620
756
  }
621
757
 
758
+ // Handle --clear-oauth command
759
+ if (args.includes('--clear-oauth')) {
760
+ const positionalArgs = args.filter(arg => !arg.startsWith('--'));
761
+ const alias = positionalArgs[0];
762
+
763
+ if (!alias) {
764
+ console.error('ERROR: --clear-oauth requires an agent alias\n');
765
+ console.error('Usage: adcp <alias> --clear-oauth\n');
766
+ process.exit(2);
767
+ }
768
+
769
+ if (!isAlias(alias)) {
770
+ console.error(`ERROR: '${alias}' is not a saved agent alias\n`);
771
+ process.exit(2);
772
+ }
773
+
774
+ const agentConfig = getAgent(alias);
775
+ if (!agentConfig.oauth_tokens) {
776
+ console.log(`\nAgent '${alias}' has no OAuth tokens to clear.\n`);
777
+ process.exit(0);
778
+ }
779
+
780
+ // Clear OAuth tokens from agent config
781
+ delete agentConfig.oauth_tokens;
782
+ delete agentConfig.oauth_client;
783
+ delete agentConfig.oauth_code_verifier;
784
+ saveAgent(alias, agentConfig);
785
+
786
+ console.log(`\nāœ… Cleared OAuth tokens for '${alias}'`);
787
+ console.log('Use --oauth to re-authenticate.\n');
788
+ process.exit(0);
789
+ }
790
+
622
791
  // Handle test command (handleTestCommand calls process.exit internally)
623
792
  if (args[0] === 'test') {
624
793
  await handleTestCommand(args.slice(1));
@@ -643,6 +812,8 @@ async function main() {
643
812
  const useLocalWebhook = args.includes('--local');
644
813
  const timeoutIndex = args.indexOf('--timeout');
645
814
  const timeout = timeoutIndex !== -1 ? parseInt(args[timeoutIndex + 1]) : 300000;
815
+ const useOAuth = args.includes('--oauth');
816
+ const clearOAuth = args.includes('--clear-oauth');
646
817
 
647
818
  // Validate protocol flag if provided
648
819
  if (protocolFlag && protocolFlag !== 'mcp' && protocolFlag !== 'a2a') {
@@ -778,18 +949,46 @@ async function main() {
778
949
  console.error(` Protocol: ${protocol}`);
779
950
  console.error(` Agent URL: ${agentUrl}`);
780
951
  console.error(` Tool: ${toolName || '(list tools)'}`);
781
- console.error(` Auth: ${authToken ? 'provided' : 'none'}`);
952
+ console.error(` Auth: ${authToken ? 'provided' : useOAuth ? 'oauth' : 'none'}`);
782
953
  console.error(` Payload: ${JSON.stringify(payload, null, 2)}`);
783
954
  console.error('');
784
955
  }
785
956
 
957
+ // Check OAuth requirements
958
+ if (useOAuth && protocol !== 'mcp') {
959
+ console.error('\nāŒ ERROR: OAuth is only supported for MCP protocol\n');
960
+ console.error('Use --auth TOKEN for A2A protocol authentication.\n');
961
+ process.exit(2);
962
+ }
963
+
964
+ // Build agent config
965
+ // If using OAuth with a saved alias, we need to load existing OAuth tokens
966
+ let agentOAuthTokens = null;
967
+ let agentOAuthClient = null;
968
+ let agentAlias = null;
969
+
970
+ if (useOAuth && savedAgent && isAlias(firstArg)) {
971
+ agentAlias = firstArg;
972
+ // Reload the full saved config to get OAuth tokens
973
+ const fullSavedConfig = getAgent(firstArg);
974
+ if (fullSavedConfig.oauth_tokens) {
975
+ agentOAuthTokens = fullSavedConfig.oauth_tokens;
976
+ agentOAuthClient = fullSavedConfig.oauth_client;
977
+ if (!jsonOutput && hasValidOAuthTokens({ oauth_tokens: agentOAuthTokens })) {
978
+ console.log('Using saved OAuth tokens...\n');
979
+ }
980
+ }
981
+ }
982
+
786
983
  // Create agent config
787
984
  const agentConfig = {
788
985
  id: 'cli-agent',
789
986
  name: 'CLI Agent',
790
987
  agent_uri: agentUrl,
791
988
  protocol: protocol,
792
- ...(authToken && { auth_token: authToken, requiresAuth: true }),
989
+ ...(authToken && !useOAuth && { auth_token: authToken, requiresAuth: true }),
990
+ ...(agentOAuthTokens && { oauth_tokens: agentOAuthTokens }),
991
+ ...(agentOAuthClient && { oauth_client: agentOAuthClient }),
793
992
  };
794
993
 
795
994
  try {
@@ -799,6 +998,76 @@ async function main() {
799
998
  console.error('DEBUG: No tool specified, displaying agent info...\n');
800
999
  }
801
1000
 
1001
+ // For OAuth without a tool, just authenticate and list tools
1002
+ if (useOAuth && protocol === 'mcp') {
1003
+ const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
1004
+ const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
1005
+ const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
1006
+
1007
+ const oauthProvider = createCLIOAuthProvider(agentConfig, { quiet: jsonOutput });
1008
+ const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
1009
+ const createTransport = () =>
1010
+ new StreamableHTTPClientTransport(new URL(agentUrl), { authProvider: oauthProvider });
1011
+
1012
+ let transport = createTransport();
1013
+
1014
+ try {
1015
+ if (!jsonOutput) {
1016
+ console.log('Connecting to MCP agent...');
1017
+ }
1018
+ await mcpClient.connect(transport);
1019
+ } catch (error) {
1020
+ if (error instanceof UnauthorizedError || error.name === 'UnauthorizedError') {
1021
+ if (!jsonOutput) {
1022
+ console.log('\nOAuth authorization required.');
1023
+ console.log('Opening browser for authentication...\n');
1024
+ }
1025
+ const code = await oauthProvider.waitForCallback();
1026
+ await transport.finishAuth(code);
1027
+ if (agentAlias && agentConfig.oauth_tokens) {
1028
+ const savedConfig = getAgent(agentAlias);
1029
+ savedConfig.oauth_tokens = agentConfig.oauth_tokens;
1030
+ savedConfig.oauth_client = agentConfig.oauth_client;
1031
+ saveAgent(agentAlias, savedConfig);
1032
+ if (!jsonOutput) {
1033
+ console.log(`OAuth tokens saved to '${agentAlias}'.\n`);
1034
+ }
1035
+ }
1036
+ transport = createTransport();
1037
+ await mcpClient.connect(transport);
1038
+ } else {
1039
+ await oauthProvider.cleanup();
1040
+ throw error;
1041
+ }
1042
+ }
1043
+
1044
+ if (!jsonOutput) {
1045
+ console.log('Connected!\n');
1046
+ }
1047
+
1048
+ // List tools
1049
+ const toolsResult = await mcpClient.listTools();
1050
+ await oauthProvider.cleanup();
1051
+ await mcpClient.close();
1052
+
1053
+ if (jsonOutput) {
1054
+ console.log(JSON.stringify({ tools: toolsResult.tools, protocol: 'mcp', oauth: true }, null, 2));
1055
+ } else {
1056
+ console.log(`\nšŸ“‹ Agent Information (OAuth)\n`);
1057
+ console.log(`Protocol: MCP`);
1058
+ console.log(`URL: ${agentUrl}`);
1059
+ console.log(`\nAvailable Tools (${toolsResult.tools.length}):\n`);
1060
+ toolsResult.tools.forEach((tool, i) => {
1061
+ console.log(`${i + 1}. ${tool.name}`);
1062
+ if (tool.description) {
1063
+ console.log(` ${tool.description}`);
1064
+ }
1065
+ console.log('');
1066
+ });
1067
+ }
1068
+ process.exit(0);
1069
+ }
1070
+
802
1071
  await displayAgentInfo(agentConfig, jsonOutput);
803
1072
  process.exit(0);
804
1073
  }
@@ -856,6 +1125,138 @@ async function main() {
856
1125
  }
857
1126
  }
858
1127
 
1128
+ // Handle OAuth flow for MCP if --oauth is specified
1129
+ if (useOAuth && protocol === 'mcp') {
1130
+ const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
1131
+ const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
1132
+ const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
1133
+
1134
+ // Create OAuth provider
1135
+ const oauthProvider = createCLIOAuthProvider(agentConfig, {
1136
+ quiet: jsonOutput,
1137
+ });
1138
+
1139
+ // Create MCP client
1140
+ const mcpClient = new MCPClient({
1141
+ name: 'adcp-cli',
1142
+ version: '1.0.0',
1143
+ });
1144
+
1145
+ const createTransport = () =>
1146
+ new StreamableHTTPClientTransport(new URL(agentUrl), {
1147
+ authProvider: oauthProvider,
1148
+ });
1149
+
1150
+ let transport = createTransport();
1151
+ let needsOAuth = !hasValidOAuthTokens(agentConfig);
1152
+
1153
+ try {
1154
+ if (!jsonOutput) {
1155
+ console.log('Connecting to MCP agent...');
1156
+ }
1157
+ await mcpClient.connect(transport);
1158
+ } catch (error) {
1159
+ if (error instanceof UnauthorizedError || error.name === 'UnauthorizedError') {
1160
+ needsOAuth = true;
1161
+ if (!jsonOutput) {
1162
+ console.log('\nOAuth authorization required.');
1163
+ console.log('Opening browser for authentication...\n');
1164
+ }
1165
+
1166
+ try {
1167
+ // Wait for user to complete OAuth in browser
1168
+ const code = await oauthProvider.waitForCallback();
1169
+ if (!jsonOutput) {
1170
+ console.log('Authorization received!');
1171
+ }
1172
+
1173
+ // Finish OAuth flow
1174
+ await transport.finishAuth(code);
1175
+
1176
+ // Save tokens to alias if using a saved agent
1177
+ if (agentAlias && agentConfig.oauth_tokens) {
1178
+ const savedConfig = getAgent(agentAlias);
1179
+ savedConfig.oauth_tokens = agentConfig.oauth_tokens;
1180
+ savedConfig.oauth_client = agentConfig.oauth_client;
1181
+ saveAgent(agentAlias, savedConfig);
1182
+ if (!jsonOutput) {
1183
+ console.log(`OAuth tokens saved to '${agentAlias}'.\n`);
1184
+ }
1185
+ }
1186
+
1187
+ // Reconnect with new tokens
1188
+ if (!jsonOutput) {
1189
+ console.log('Reconnecting with OAuth tokens...');
1190
+ }
1191
+ transport = createTransport();
1192
+ await mcpClient.connect(transport);
1193
+ } catch (authError) {
1194
+ await oauthProvider.cleanup();
1195
+ throw authError;
1196
+ }
1197
+ } else {
1198
+ await oauthProvider.cleanup();
1199
+ throw error;
1200
+ }
1201
+ }
1202
+
1203
+ if (!jsonOutput) {
1204
+ console.log('Connected!\n');
1205
+ }
1206
+
1207
+ // Execute tool call directly via MCP
1208
+ try {
1209
+ const startTime = Date.now();
1210
+ const toolResult = await mcpClient.callTool({ name: toolName, arguments: payload });
1211
+ const responseTime = Date.now() - startTime;
1212
+
1213
+ await oauthProvider.cleanup();
1214
+ await mcpClient.close();
1215
+
1216
+ // Format result similar to AdCPClient response
1217
+ let resultData = toolResult;
1218
+ if (toolResult.content && Array.isArray(toolResult.content)) {
1219
+ const textContent = toolResult.content.find(c => c.type === 'text');
1220
+ if (textContent && textContent.text) {
1221
+ try {
1222
+ resultData = JSON.parse(textContent.text);
1223
+ } catch {
1224
+ resultData = textContent.text;
1225
+ }
1226
+ }
1227
+ }
1228
+
1229
+ if (jsonOutput) {
1230
+ console.log(
1231
+ JSON.stringify(
1232
+ {
1233
+ data: resultData,
1234
+ metadata: {
1235
+ protocol: 'mcp',
1236
+ responseTimeMs: responseTime,
1237
+ oauth: true,
1238
+ },
1239
+ },
1240
+ null,
1241
+ 2
1242
+ )
1243
+ );
1244
+ } else {
1245
+ console.log('\nāœ… SUCCESS\n');
1246
+ console.log('Response:');
1247
+ console.log(JSON.stringify(resultData, null, 2));
1248
+ console.log('');
1249
+ console.log(`Protocol: MCP (OAuth)`);
1250
+ console.log(`Response Time: ${responseTime}ms`);
1251
+ }
1252
+ process.exit(0);
1253
+ } catch (toolError) {
1254
+ await oauthProvider.cleanup();
1255
+ await mcpClient.close();
1256
+ throw toolError;
1257
+ }
1258
+ }
1259
+
859
1260
  // Create ADCP client with optional webhook configuration
860
1261
  // Note: AdCPClient (multi-agent) expects an array of configs
861
1262
  const client = new AdCPClient([agentConfig], {
@@ -1008,6 +1409,121 @@ async function main() {
1008
1409
  process.exit(3);
1009
1410
  }
1010
1411
  } catch (error) {
1412
+ // Check if this is an OAuth-required error for MCP and offer auto-authentication
1413
+ const isUnauthorized =
1414
+ error.name === 'UnauthorizedError' ||
1415
+ error.message?.toLowerCase().includes('unauthorized') ||
1416
+ error.message?.includes('401');
1417
+
1418
+ if (isUnauthorized && protocol === 'mcp' && !useOAuth && !authToken) {
1419
+ console.log('\nšŸ” Server requires authentication.');
1420
+ console.log('Starting OAuth authentication...\n');
1421
+
1422
+ // Run OAuth flow automatically
1423
+ const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
1424
+ const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
1425
+ const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
1426
+
1427
+ const oauthProvider = createCLIOAuthProvider(agentConfig, { quiet: jsonOutput });
1428
+ const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
1429
+ const createTransport = () =>
1430
+ new StreamableHTTPClientTransport(new URL(agentUrl), { authProvider: oauthProvider });
1431
+
1432
+ let transport = createTransport();
1433
+
1434
+ try {
1435
+ await mcpClient.connect(transport);
1436
+ } catch (connectError) {
1437
+ if (connectError instanceof UnauthorizedError || connectError.name === 'UnauthorizedError') {
1438
+ console.log('Opening browser for authentication...\n');
1439
+ const code = await oauthProvider.waitForCallback();
1440
+ console.log('Authorization received!');
1441
+ await transport.finishAuth(code);
1442
+
1443
+ // Save tokens if using a saved alias
1444
+ if (agentAlias && agentConfig.oauth_tokens) {
1445
+ const savedConfig = getAgent(agentAlias);
1446
+ savedConfig.oauth_tokens = agentConfig.oauth_tokens;
1447
+ savedConfig.oauth_client = agentConfig.oauth_client;
1448
+ saveAgent(agentAlias, savedConfig);
1449
+ console.log(`OAuth tokens saved to '${agentAlias}'.\n`);
1450
+ }
1451
+
1452
+ // Reconnect and execute
1453
+ console.log('Reconnecting with OAuth tokens...');
1454
+ transport = createTransport();
1455
+ await mcpClient.connect(transport);
1456
+ console.log('Connected!\n');
1457
+
1458
+ // Execute the tool if specified
1459
+ if (toolName) {
1460
+ const startTime = Date.now();
1461
+ const toolResult = await mcpClient.callTool({ name: toolName, arguments: payload });
1462
+ const responseTime = Date.now() - startTime;
1463
+
1464
+ await oauthProvider.cleanup();
1465
+ await mcpClient.close();
1466
+
1467
+ let resultData = toolResult;
1468
+ if (toolResult.content && Array.isArray(toolResult.content)) {
1469
+ const textContent = toolResult.content.find(c => c.type === 'text');
1470
+ if (textContent && textContent.text) {
1471
+ try {
1472
+ resultData = JSON.parse(textContent.text);
1473
+ } catch {
1474
+ resultData = textContent.text;
1475
+ }
1476
+ }
1477
+ }
1478
+
1479
+ if (jsonOutput) {
1480
+ console.log(
1481
+ JSON.stringify(
1482
+ {
1483
+ data: resultData,
1484
+ metadata: { protocol: 'mcp', responseTimeMs: responseTime, oauth: true },
1485
+ },
1486
+ null,
1487
+ 2
1488
+ )
1489
+ );
1490
+ } else {
1491
+ console.log('\nāœ… SUCCESS\n');
1492
+ console.log('Response:');
1493
+ console.log(JSON.stringify(resultData, null, 2));
1494
+ console.log('');
1495
+ console.log(`Protocol: MCP (OAuth)`);
1496
+ console.log(`Response Time: ${responseTime}ms`);
1497
+ }
1498
+ process.exit(0);
1499
+ } else {
1500
+ // List tools
1501
+ const toolsResult = await mcpClient.listTools();
1502
+ await oauthProvider.cleanup();
1503
+ await mcpClient.close();
1504
+
1505
+ if (jsonOutput) {
1506
+ console.log(JSON.stringify({ tools: toolsResult.tools, protocol: 'mcp', oauth: true }, null, 2));
1507
+ } else {
1508
+ console.log(`\nšŸ“‹ Agent Information (OAuth)\n`);
1509
+ console.log(`Protocol: MCP`);
1510
+ console.log(`URL: ${agentUrl}`);
1511
+ console.log(`\nAvailable Tools (${toolsResult.tools.length}):\n`);
1512
+ toolsResult.tools.forEach((tool, i) => {
1513
+ console.log(`${i + 1}. ${tool.name}`);
1514
+ if (tool.description) console.log(` ${tool.description}`);
1515
+ console.log('');
1516
+ });
1517
+ }
1518
+ process.exit(0);
1519
+ }
1520
+ } else {
1521
+ await oauthProvider.cleanup();
1522
+ throw connectError;
1523
+ }
1524
+ }
1525
+ }
1526
+
1011
1527
  console.error('\nāŒ ERROR\n');
1012
1528
  console.error(error.message);
1013
1529
  if (debug) {