@adcp/client 2.4.1 → 2.5.1

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 (54) hide show
  1. package/README.md +66 -11
  2. package/bin/adcp-config.js +233 -0
  3. package/bin/adcp.js +321 -45
  4. package/dist/lib/core/ADCPClient.d.ts +33 -3
  5. package/dist/lib/core/ADCPClient.d.ts.map +1 -1
  6. package/dist/lib/core/ADCPClient.js +93 -16
  7. package/dist/lib/core/ADCPClient.js.map +1 -1
  8. package/dist/lib/core/ADCPMultiAgentClient.d.ts +8 -0
  9. package/dist/lib/core/ADCPMultiAgentClient.d.ts.map +1 -1
  10. package/dist/lib/core/ADCPMultiAgentClient.js +14 -0
  11. package/dist/lib/core/ADCPMultiAgentClient.js.map +1 -1
  12. package/dist/lib/core/AgentClient.d.ts +18 -2
  13. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  14. package/dist/lib/core/AgentClient.js +10 -3
  15. package/dist/lib/core/AgentClient.js.map +1 -1
  16. package/dist/lib/core/ResponseValidator.d.ts +13 -9
  17. package/dist/lib/core/ResponseValidator.d.ts.map +1 -1
  18. package/dist/lib/core/ResponseValidator.js +93 -33
  19. package/dist/lib/core/ResponseValidator.js.map +1 -1
  20. package/dist/lib/core/TaskExecutor.d.ts +12 -0
  21. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  22. package/dist/lib/core/TaskExecutor.js +88 -6
  23. package/dist/lib/core/TaskExecutor.js.map +1 -1
  24. package/dist/lib/index.d.ts +1 -0
  25. package/dist/lib/index.d.ts.map +1 -1
  26. package/dist/lib/index.js +4 -1
  27. package/dist/lib/index.js.map +1 -1
  28. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  29. package/dist/lib/protocols/mcp.js +9 -0
  30. package/dist/lib/protocols/mcp.js.map +1 -1
  31. package/dist/lib/types/adcp.d.ts +2 -6
  32. package/dist/lib/types/adcp.d.ts.map +1 -1
  33. package/dist/lib/types/schemas.generated.d.ts +0 -2
  34. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  35. package/dist/lib/types/schemas.generated.js +1 -2
  36. package/dist/lib/types/schemas.generated.js.map +1 -1
  37. package/dist/lib/types/tools.generated.d.ts +0 -8
  38. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  39. package/dist/lib/types/tools.generated.js.map +1 -1
  40. package/dist/lib/utils/index.d.ts +1 -0
  41. package/dist/lib/utils/index.d.ts.map +1 -1
  42. package/dist/lib/utils/index.js +9 -4
  43. package/dist/lib/utils/index.js.map +1 -1
  44. package/dist/lib/utils/logger.d.ts +55 -0
  45. package/dist/lib/utils/logger.d.ts.map +1 -0
  46. package/dist/lib/utils/logger.js +100 -0
  47. package/dist/lib/utils/logger.js.map +1 -0
  48. package/dist/lib/utils/protocol-detection.d.ts +26 -0
  49. package/dist/lib/utils/protocol-detection.d.ts.map +1 -0
  50. package/dist/lib/utils/protocol-detection.js +84 -0
  51. package/dist/lib/utils/protocol-detection.js.map +1 -0
  52. package/dist/lib/version.d.ts +3 -3
  53. package/dist/lib/version.js +3 -3
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -457,26 +457,81 @@ ORDER BY sequence_number;
457
457
 
458
458
  ## CLI Tool
459
459
 
460
- For development and testing, use the included CLI tool to interact with AdCP agents:
460
+ For development and testing, use the included CLI tool to interact with AdCP agents.
461
+
462
+ ### Quick Start with Aliases
463
+
464
+ Save agents for quick access:
461
465
 
462
466
  ```bash
463
- # List available tools from an agent
464
- npx @adcp/client mcp https://test-agent.adcontextprotocol.org
467
+ # Save an agent with an alias
468
+ npx @adcp/client --save-auth test https://test-agent.adcontextprotocol.org
465
469
 
466
- # Call a tool with inline JSON payload
467
- npx @adcp/client a2a https://agent.example.com get_products '{"brief":"Coffee brands"}'
470
+ # Use the alias
471
+ npx @adcp/client test get_products '{"brief":"Coffee brands"}'
468
472
 
469
- # Use a file for payload
470
- npx @adcp/client mcp https://agent.example.com create_media_buy @payload.json
473
+ # List saved agents
474
+ npx @adcp/client --list-agents
475
+ ```
476
+
477
+ ### Direct URL Usage
478
+
479
+ Auto-detect protocol and call directly:
480
+
481
+ ```bash
482
+ # Protocol auto-detection (default)
483
+ npx @adcp/client https://test-agent.adcontextprotocol.org get_products '{"brief":"Coffee"}'
484
+
485
+ # Force specific protocol with --protocol flag
486
+ npx @adcp/client https://agent.example.com get_products '{"brief":"Coffee"}' --protocol mcp
487
+ npx @adcp/client https://agent.example.com list_authorized_properties --protocol a2a
471
488
 
472
- # With authentication
473
- npx @adcp/client mcp https://agent.example.com get_products '{"brief":"..."}' --auth your-token
489
+ # List available tools
490
+ npx @adcp/client https://agent.example.com
491
+
492
+ # Use a file for payload
493
+ npx @adcp/client https://agent.example.com create_media_buy @payload.json
474
494
 
475
495
  # JSON output for scripting
476
- npx @adcp/client mcp https://agent.example.com get_products '{"brief":"..."}' --json
496
+ npx @adcp/client https://agent.example.com get_products '{"brief":"..."}' --json | jq '.products'
477
497
  ```
478
498
 
479
- **MCP Endpoint Discovery**: The client automatically discovers MCP endpoints. Just provide any URL - it tests your path first, and if no MCP server responds, it tries adding `/mcp`. Works with root domains, custom paths, anything.
499
+ ### Authentication
500
+
501
+ Three ways to provide auth tokens (priority order):
502
+
503
+ ```bash
504
+ # 1. Explicit flag (highest priority)
505
+ npx @adcp/client test get_products '{"brief":"..."}' --auth your-token
506
+
507
+ # 2. Saved in agent config (recommended)
508
+ npx @adcp/client --save-auth prod https://prod-agent.com
509
+ # Will prompt for auth token securely
510
+
511
+ # 3. Environment variable (fallback)
512
+ export ADCP_AUTH_TOKEN=your-token
513
+ npx @adcp/client test get_products '{"brief":"..."}'
514
+ ```
515
+
516
+ ### Agent Management
517
+
518
+ ```bash
519
+ # Save agent with auth
520
+ npx @adcp/client --save-auth prod https://prod-agent.com mcp
521
+
522
+ # List all saved agents
523
+ npx @adcp/client --list-agents
524
+
525
+ # Remove an agent
526
+ npx @adcp/client --remove-agent test
527
+
528
+ # Show config file location
529
+ npx @adcp/client --show-config
530
+ ```
531
+
532
+ **Protocol Auto-Detection**: The CLI automatically detects whether an endpoint uses MCP or A2A by checking URL patterns and discovery endpoints. Override with `--protocol mcp` or `--protocol a2a` if needed.
533
+
534
+ **Config File**: Agent configurations are saved to `~/.adcp/config.json` with secure file permissions (0600).
480
535
 
481
536
  See [docs/CLI.md](docs/CLI.md) for complete CLI documentation including webhook support for async operations.
482
537
 
@@ -0,0 +1,233 @@
1
+ /**
2
+ * AdCP CLI Configuration Manager
3
+ *
4
+ * Manages agent aliases and authentication configuration
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const os = require('os');
10
+
11
+ const CONFIG_DIR = path.join(os.homedir(), '.adcp');
12
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
13
+
14
+ /**
15
+ * Get the config file path
16
+ */
17
+ function getConfigPath() {
18
+ return CONFIG_FILE;
19
+ }
20
+
21
+ /**
22
+ * Ensure config directory exists
23
+ */
24
+ function ensureConfigDir() {
25
+ if (!fs.existsSync(CONFIG_DIR)) {
26
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Load configuration from disk
32
+ * @returns {Object} Configuration object
33
+ */
34
+ function loadConfig() {
35
+ try {
36
+ if (!fs.existsSync(CONFIG_FILE)) {
37
+ return { agents: {}, defaults: {} };
38
+ }
39
+
40
+ const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
41
+ return JSON.parse(content);
42
+ } catch (error) {
43
+ console.error(`Warning: Failed to load config from ${CONFIG_FILE}: ${error.message}`);
44
+ return { agents: {}, defaults: {} };
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Save configuration to disk
50
+ * @param {Object} config Configuration object
51
+ */
52
+ function saveConfig(config) {
53
+ try {
54
+ ensureConfigDir();
55
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
56
+ } catch (error) {
57
+ throw new Error(`Failed to save config to ${CONFIG_FILE}: ${error.message}`);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Get agent configuration by alias
63
+ * @param {string} alias Agent alias
64
+ * @returns {Object|null} Agent config or null if not found
65
+ */
66
+ function getAgent(alias) {
67
+ const config = loadConfig();
68
+ return config.agents[alias] || null;
69
+ }
70
+
71
+ /**
72
+ * List all saved agents
73
+ * @returns {Object} Map of alias to agent config
74
+ */
75
+ function listAgents() {
76
+ const config = loadConfig();
77
+ return config.agents || {};
78
+ }
79
+
80
+ /**
81
+ * Save an agent configuration
82
+ * @param {string} alias Agent alias
83
+ * @param {Object} agentConfig Agent configuration
84
+ */
85
+ function saveAgent(alias, agentConfig) {
86
+ const config = loadConfig();
87
+ if (!config.agents) {
88
+ config.agents = {};
89
+ }
90
+
91
+ config.agents[alias] = agentConfig;
92
+ saveConfig(config);
93
+ }
94
+
95
+ /**
96
+ * Remove an agent configuration
97
+ * @param {string} alias Agent alias
98
+ * @returns {boolean} True if agent was removed
99
+ */
100
+ function removeAgent(alias) {
101
+ const config = loadConfig();
102
+ if (config.agents && config.agents[alias]) {
103
+ delete config.agents[alias];
104
+ saveConfig(config);
105
+ return true;
106
+ }
107
+ return false;
108
+ }
109
+
110
+ /**
111
+ * Check if a string is an agent alias
112
+ * @param {string} str String to check
113
+ * @returns {boolean} True if string is a saved alias
114
+ */
115
+ function isAlias(str) {
116
+ const config = loadConfig();
117
+ return config.agents && config.agents[str] !== undefined;
118
+ }
119
+
120
+ /**
121
+ * Prompt for input securely (for passwords/tokens)
122
+ * @param {string} prompt Prompt message
123
+ * @param {boolean} hidden Hide input (for passwords)
124
+ * @returns {Promise<string>} User input
125
+ */
126
+ async function promptSecure(prompt, hidden = true) {
127
+ const readline = require('readline');
128
+
129
+ return new Promise((resolve) => {
130
+ const rl = readline.createInterface({
131
+ input: process.stdin,
132
+ output: process.stdout
133
+ });
134
+
135
+ if (hidden) {
136
+ // Disable echo for password input
137
+ const stdin = process.stdin;
138
+ const originalSetRawMode = stdin.setRawMode;
139
+
140
+ // Mute output
141
+ rl.stdoutMuted = true;
142
+ rl._writeToOutput = function _writeToOutput(stringToWrite) {
143
+ if (!rl.stdoutMuted) {
144
+ rl.output.write(stringToWrite);
145
+ }
146
+ };
147
+ }
148
+
149
+ rl.question(prompt, (answer) => {
150
+ rl.close();
151
+ if (hidden) {
152
+ console.log(''); // New line after hidden input
153
+ }
154
+ resolve(answer.trim());
155
+ });
156
+ });
157
+ }
158
+
159
+ /**
160
+ * Interactive agent setup
161
+ * @param {string} alias Agent alias
162
+ * @param {string} url Agent URL (optional)
163
+ * @param {string} protocol Protocol (optional)
164
+ * @param {string} authToken Auth token (optional)
165
+ * @param {boolean} nonInteractive Skip prompts if all required args provided
166
+ * @param {boolean} noAuth Explicitly skip auth (--no-auth flag)
167
+ */
168
+ async function interactiveSetup(alias, url = null, protocol = null, authToken = null, nonInteractive = false, noAuth = false) {
169
+ // Non-interactive mode: save immediately without prompts
170
+ if (nonInteractive && url) {
171
+ const agentConfig = { url };
172
+ if (protocol) agentConfig.protocol = protocol;
173
+ if (authToken) agentConfig.auth_token = authToken;
174
+ // noAuth flag means explicitly don't save auth
175
+
176
+ saveAgent(alias, agentConfig);
177
+ console.log(`\nāœ… Agent '${alias}' saved to ${CONFIG_FILE}`);
178
+ console.log(`\nYou can now use: adcp ${alias} <tool> <payload>`);
179
+ return;
180
+ }
181
+
182
+ console.log(`\nšŸ“ Setting up agent: ${alias}\n`);
183
+
184
+ // Get URL if not provided
185
+ if (!url) {
186
+ url = await promptSecure('Agent URL: ', false);
187
+ }
188
+
189
+ // Get protocol if not provided (optional, can auto-detect)
190
+ if (!protocol) {
191
+ const protocolInput = await promptSecure('Protocol (mcp/a2a, or leave blank to auto-detect): ', false);
192
+ protocol = protocolInput || null;
193
+ }
194
+
195
+ // Get auth token if not provided and not explicitly disabled
196
+ if (!authToken && !noAuth) {
197
+ process.stdout.write('Auth token (leave blank if not needed): ');
198
+ authToken = await promptSecure('', true);
199
+ authToken = authToken || null;
200
+ }
201
+
202
+ // Build config
203
+ const agentConfig = {
204
+ url: url
205
+ };
206
+
207
+ if (protocol) {
208
+ agentConfig.protocol = protocol;
209
+ }
210
+
211
+ if (authToken) {
212
+ agentConfig.auth_token = authToken;
213
+ }
214
+
215
+ // Save
216
+ saveAgent(alias, agentConfig);
217
+
218
+ console.log(`\nāœ… Agent '${alias}' saved to ${CONFIG_FILE}`);
219
+ console.log(`\nYou can now use: adcp ${alias} <tool> <payload>`);
220
+ }
221
+
222
+ module.exports = {
223
+ getConfigPath,
224
+ loadConfig,
225
+ saveConfig,
226
+ getAgent,
227
+ listAgents,
228
+ saveAgent,
229
+ removeAgent,
230
+ isAlias,
231
+ promptSecure,
232
+ interactiveSetup
233
+ };