@alcyone-labs/arg-parser 1.1.0 → 2.0.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 (105) hide show
  1. package/README.md +460 -1179
  2. package/dist/assets/.dxtignore.template +38 -0
  3. package/dist/assets/logo_1_small.jpg +0 -0
  4. package/dist/assets/tsdown.dxt.config.ts +37 -0
  5. package/dist/index.cjs +23702 -2315
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.min.mjs +16360 -1725
  8. package/dist/index.min.mjs.map +1 -1
  9. package/dist/index.mjs +23694 -2315
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/src/config/ConfigurationManager.d.ts +74 -0
  12. package/dist/src/config/ConfigurationManager.d.ts.map +1 -0
  13. package/dist/src/config/plugins/ConfigPlugin.d.ts +60 -0
  14. package/dist/src/config/plugins/ConfigPlugin.d.ts.map +1 -0
  15. package/dist/src/config/plugins/ConfigPluginRegistry.d.ts +72 -0
  16. package/dist/src/config/plugins/ConfigPluginRegistry.d.ts.map +1 -0
  17. package/dist/src/config/plugins/TomlConfigPlugin.d.ts +30 -0
  18. package/dist/src/config/plugins/TomlConfigPlugin.d.ts.map +1 -0
  19. package/dist/src/config/plugins/YamlConfigPlugin.d.ts +29 -0
  20. package/dist/src/config/plugins/YamlConfigPlugin.d.ts.map +1 -0
  21. package/dist/src/config/plugins/index.d.ts +5 -0
  22. package/dist/src/config/plugins/index.d.ts.map +1 -0
  23. package/dist/src/core/ArgParser.d.ts +332 -0
  24. package/dist/src/core/ArgParser.d.ts.map +1 -0
  25. package/dist/src/{ArgParserBase.d.ts → core/ArgParserBase.d.ts} +84 -3
  26. package/dist/src/core/ArgParserBase.d.ts.map +1 -0
  27. package/dist/src/core/FlagManager.d.ts.map +1 -0
  28. package/dist/src/{types.d.ts → core/types.d.ts} +40 -0
  29. package/dist/src/core/types.d.ts.map +1 -0
  30. package/dist/src/dxt/DxtGenerator.d.ts +115 -0
  31. package/dist/src/dxt/DxtGenerator.d.ts.map +1 -0
  32. package/dist/src/index.d.ts +10 -6
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/mcp/ArgParserMcp.d.ts +21 -0
  35. package/dist/src/mcp/ArgParserMcp.d.ts.map +1 -0
  36. package/dist/src/mcp/mcp-integration.d.ts +83 -0
  37. package/dist/src/mcp/mcp-integration.d.ts.map +1 -0
  38. package/dist/src/mcp/mcp-notifications.d.ts +138 -0
  39. package/dist/src/mcp/mcp-notifications.d.ts.map +1 -0
  40. package/dist/src/mcp/mcp-prompts.d.ts +132 -0
  41. package/dist/src/mcp/mcp-prompts.d.ts.map +1 -0
  42. package/dist/src/mcp/mcp-resources.d.ts +133 -0
  43. package/dist/src/mcp/mcp-resources.d.ts.map +1 -0
  44. package/dist/src/testing/fuzzy-test-cli.d.ts +5 -0
  45. package/dist/src/testing/fuzzy-test-cli.d.ts.map +1 -0
  46. package/dist/src/{fuzzy-tester.d.ts → testing/fuzzy-tester.d.ts} +1 -1
  47. package/dist/src/testing/fuzzy-tester.d.ts.map +1 -0
  48. package/package.json +51 -17
  49. package/dist/examples/fuzzy-demo.d.ts +0 -8
  50. package/dist/examples/fuzzy-demo.d.ts.map +0 -1
  51. package/dist/examples/fuzzy-test-example.d.ts +0 -8
  52. package/dist/examples/fuzzy-test-example.d.ts.map +0 -1
  53. package/dist/examples/fzf-search-cli.d.ts +0 -8
  54. package/dist/examples/fzf-search-cli.d.ts.map +0 -1
  55. package/dist/examples/getting-started.d.ts +0 -27
  56. package/dist/examples/getting-started.d.ts.map +0 -1
  57. package/dist/examples/mcp-preset-transports.d.ts +0 -19
  58. package/dist/examples/mcp-preset-transports.d.ts.map +0 -1
  59. package/dist/examples/simple-cli.d.ts +0 -26
  60. package/dist/examples/simple-cli.d.ts.map +0 -1
  61. package/dist/examples/v1.1.0-showcase.d.ts +0 -16
  62. package/dist/examples/v1.1.0-showcase.d.ts.map +0 -1
  63. package/dist/examples/with-env-example.d.ts +0 -3
  64. package/dist/examples/with-env-example.d.ts.map +0 -1
  65. package/dist/index-6G9StDO_.js +0 -6445
  66. package/dist/index-6G9StDO_.js.map +0 -1
  67. package/dist/index-CqU7Fj3C.cjs +0 -6444
  68. package/dist/index-CqU7Fj3C.cjs.map +0 -1
  69. package/dist/index-Dx_q1msW.js +0 -4682
  70. package/dist/index-Dx_q1msW.js.map +0 -1
  71. package/dist/src/ArgParser.d.ts +0 -156
  72. package/dist/src/ArgParser.d.ts.map +0 -1
  73. package/dist/src/ArgParserBase.d.ts.map +0 -1
  74. package/dist/src/FlagManager.d.ts.map +0 -1
  75. package/dist/src/fuzzy-test-cli.d.ts +0 -5
  76. package/dist/src/fuzzy-test-cli.d.ts.map +0 -1
  77. package/dist/src/fuzzy-tester.d.ts.map +0 -1
  78. package/dist/src/mcp-integration.d.ts +0 -31
  79. package/dist/src/mcp-integration.d.ts.map +0 -1
  80. package/dist/src/types.d.ts.map +0 -1
  81. package/dist/sse-B5Jf_YpG.cjs +0 -121
  82. package/dist/sse-B5Jf_YpG.cjs.map +0 -1
  83. package/dist/sse-BDL3h2Ll.js +0 -121
  84. package/dist/sse-BDL3h2Ll.js.map +0 -1
  85. package/dist/sse-DSjLfGFo.js +0 -107
  86. package/dist/sse-DSjLfGFo.js.map +0 -1
  87. package/dist/stdio-Cf19UQO7.js +0 -70
  88. package/dist/stdio-Cf19UQO7.js.map +0 -1
  89. package/dist/stdio-DESvSONI.cjs +0 -94
  90. package/dist/stdio-DESvSONI.cjs.map +0 -1
  91. package/dist/stdio-DLOResWr.js +0 -94
  92. package/dist/stdio-DLOResWr.js.map +0 -1
  93. package/dist/streamableHttp-DXIdDSbF.js +0 -342
  94. package/dist/streamableHttp-DXIdDSbF.js.map +0 -1
  95. package/dist/streamableHttp-DsXlAnqJ.cjs +0 -456
  96. package/dist/streamableHttp-DsXlAnqJ.cjs.map +0 -1
  97. package/dist/streamableHttp-Vd4Qsgko.js +0 -456
  98. package/dist/streamableHttp-Vd4Qsgko.js.map +0 -1
  99. package/dist/types-DSxPEImy.cjs +0 -943
  100. package/dist/types-DSxPEImy.cjs.map +0 -1
  101. package/dist/types-DdsPVLQ5.js +0 -846
  102. package/dist/types-DdsPVLQ5.js.map +0 -1
  103. package/dist/types-DpK81FWv.js +0 -944
  104. package/dist/types-DpK81FWv.js.map +0 -1
  105. /package/dist/src/{FlagManager.d.ts → core/FlagManager.d.ts} +0 -0
package/README.md CHANGED
@@ -1,1373 +1,655 @@
1
1
  # ArgParser - Type-Safe Command Line Argument Parser
2
2
 
3
- ArgParser is a powerful and flexible library for building command-line interfaces (CLIs) in TypeScript and JavaScript. It helps you define, parse, validate, and handle command-line arguments and sub-commands in a structured, type-safe way.
3
+ A modern, type-safe command line argument parser with built-in MCP (Model Context Protocol) integration and automatic Claude Desktop Extension (DXT) generation.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features Overview](#features-overview)
8
+ - [Installation](#installation)
9
+ - [Quick Start: The Unified `addTool` API](#quick-start-the-unified-addtool-api)
10
+ - [How to Run It](#how-to-run-it)
11
+ - [Setting Up System-Wide CLI Access](#setting-up-system-wide-cli-access)
12
+ - [Parsing Command-Line Arguments](#parsing-command-line-arguments)
13
+ - [Cannonical Usage Pattern](#cannonical-usage-pattern)
14
+ - [Top-level await](#top-level-await)
15
+ - [Promise-based parsing](#promise-based-parsing)
16
+ - [Migrating from v1.x to the v2.0 `addTool` API](#migrating-from-v1x-to-the-v20-addtool-api)
17
+ - [Before v2.0: Separate Definitions](#before-v20-separate-definitions)
18
+ - [After v2.0: The Unified `addTool()` Method](#after-v20-the-unified-addtool-method)
19
+ - [Core Concepts](#core-concepts)
20
+ - [Defining Flags](#defining-flags)
21
+ - [Type Handling and Validation](#type-handling-and-validation)
22
+ - [Hierarchical CLIs (Sub-Commands)](#hierarchical-clis-sub-commands)
23
+ - [MCP Exposure Control](#mcp-exposure-control)
24
+ - [Flag Inheritance (`inheritParentFlags`)](#flag-inheritance-inheritparentflags)
25
+ - [MCP & Claude Desktop Integration](#mcp--claude-desktop-integration)
26
+ - [Automatic MCP Server Mode (`--s-mcp-serve`)](#automatic-mcp-server-mode---s-mcp-serve)
27
+ - [MCP Transports](#mcp-transports)
28
+ - [Automatic Console Safety](#automatic-console-safety)
29
+ - [Generating DXT Packages (`--s-build-dxt`)](#generating-dxt-packages---s-build-dxt)
30
+ - [Logo Configuration](#logo-configuration)
31
+ - [How DXT Generation Works](#how-dxt-generation-works)
32
+ - [System Flags & Configuration](#system-flags--configuration)
33
+ - [Changelog](#changelog)
34
+ - [Backlog](#backlog)
35
+
36
+ ## Features Overview
37
+
38
+ - **Unified Tool Architecture**: Define tools once with `addTool()` and they automatically function as both CLI subcommands and MCP tools.
39
+ - **Type-safe flag definitions** with full TypeScript support and autocompletion.
40
+ - **Automatic MCP Integration**: Transform any CLI into a compliant MCP server with a single command (`--s-mcp-serve`).
41
+ - **Console Safe**: `console.log` and other methods
42
+ are automatically handled in MCP mode to prevent protocol contamination, requiring no changes to your code.
43
+ - **DXT Package Generation**: Generate complete, ready-to-install Claude Desktop Extension (`.dxt`) packages with the `--s-build-dxt` command.
44
+ - **Hierarchical Sub-commands**: Create complex, nested sub-command structures (e.g., `git commit`, `docker container ls`) with flag inheritance.
45
+ - **Configuration Management**: Easily load (`--s-with-env`) and save (`--s-save-to-env`) configurations from/to `.env`, `.json`, `.yaml`, and `.toml` files.
46
+ - **Automatic Help & Error Handling**: Context-aware help text and user-friendly error messages are generated automatically.
47
+ - **Debugging Tools**: Built-in system flags like `--s-debug` and `--s-debug-print` for easy troubleshooting.
4
48
 
5
- Whether you're building a simple script, a complex nested CLI application, or an MCP (Model Context Protocol) server, ArgParser provides the tools to create robust and user-friendly interfaces with minimal boilerplate.
49
+ ---
50
+
51
+ ## Installation
6
52
 
7
- ## What's New in v1.1.0
53
+ ```bash
54
+ # Using PNPM (recommended)
55
+ pnpm add @alcyone-labs/arg-parser
56
+ ```
8
57
 
9
- ### **Major Features**
58
+ ---
10
59
 
11
- - **MCP (Model Context Protocol) Integration**: Transform any CLI into an MCP server with multiple transport support. Run MCP servers with stdio, SSE, and HTTP transports simultaneously, including streamable HTTP.
12
- - **System Flags**: Built-in `--s-debug-print`, `--s-with-env`, `--s-save-to-env`, and `--s-enable-fuzzy` for enhanced debugging, configuration, and testing
13
- - **Environment Loading**: Load configuration from `.env`, `.yaml`, `.json`, and `.toml` files
14
- - **Enhanced Debugging**: Comprehensive runtime debugging and configuration export tools
60
+ ## Quick Start: The Unified `addTool` API
15
61
 
16
- ### **Quick Start with MCP**
62
+ The modern way to build with ArgParser is using the `.addTool()` method. It creates a single, self-contained unit that works as both a CLI subcommand and an MCP tool.
17
63
 
18
64
  ```typescript
19
65
  import { ArgParser } from "@alcyone-labs/arg-parser";
20
66
 
67
+ // Use ArgParser.withMcp to enable MCP and DXT features
21
68
  const cli = ArgParser.withMcp({
22
- appName: "My CLI Tool",
23
- appCommandName: "my-tool",
24
- description: "A powerful CLI that can also run as an MCP server",
25
- handler: async (ctx) => ({ result: "success", args: ctx.args }),
69
+ appName: "My Awesome CLI",
70
+ appCommandName: "mycli",
71
+ description: "A tool that works in both CLI and MCP mode",
72
+ mcp: {
73
+ serverInfo: { name: "my-awesome-mcp-server", version: "1.0.0" },
74
+ },
26
75
  })
27
- .addFlags([
28
- { name: "input", options: ["--input", "-i"], type: "string", mandatory: true },
29
- { name: "verbose", options: ["--verbose", "-v"], type: "boolean", flagOnly: true },
30
- ])
31
- .addMcpSubCommand("serve", {
32
- name: "my-mcp-server",
33
- version: "1.1.0",
34
- description: "Expose this CLI as an MCP server",
35
- }, {
36
- // Optional: Configure default transports (CLI flags take precedence)
37
- defaultTransports: [
38
- { type: "stdio" },
39
- { type: "sse", port: 3001, host: "0.0.0.0" }
40
- ]
41
- });
42
-
43
- // Use as CLI: my-tool --input data.txt --verbose
44
- // Use as MCP server with defaults: my-tool serve
45
- // Use as MCP server with CLI override: my-tool serve --transport sse --port 3002
46
- // Use with multiple transports: my-tool serve --transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
47
- ```
48
-
49
- ## Features
50
-
51
- ### **Core CLI Features**
52
- - **Type Safety:** Define expected argument types (string, number, boolean, array, custom functions) and get type-safe parsed results
53
- - **Declarative API:** Configure your CLI structure, flags, and sub-commands using a clear, declarative syntax
54
- - **Automatic Help Generation:** Generate comprehensive and contextual help text based on your parser configuration
55
- - **Hierarchical Commands:** Easily define nested sub-commands to create complex command structures (e.g., `git commit`, `docker container ls`)
56
- - **Handler Execution:** Associate handler functions with commands and have them executed automatically upon successful parsing
57
- - **Validation:** Define custom validation rules for flag values with enum support and custom validators
58
- - **Conditional Requirements:** Make flags mandatory based on the presence or values of other arguments
59
- - **Default Values:** Specify default values for flags if they are not provided on the command line
60
- - **Flag Inheritance:** Share common flags between parent and child commands with an intuitive inheritance mechanism
61
- - **Error Handling:** Built-in, user-friendly error reporting for common parsing issues, with an option to handle errors manually
62
-
63
- ### **MCP Integration (v1.1.0+)**
64
- - **Automatic MCP Server Creation:** Transform any CLI into an MCP server with a single method call
65
- - **Multiple Transport Support:** Run stdio, SSE, and HTTP transports simultaneously on different ports
66
- - **Type-Safe Tool Generation:** Automatically generate MCP tools with Zod schema validation from CLI definitions
67
- - **Flexible Configuration:** Support for single transport or complex multi-transport JSON configurations
68
-
69
- ### **System & Configuration Features (v1.1.0+)**
70
- - **Environment Loading:** Load configuration from `.env`, `.yaml`, `.json`, and `.toml` files with `--s-with-env`
71
- - **Configuration Export:** Save current configuration to various formats with `--s-save-to-env`
72
- - **Advanced Debugging:** Runtime debugging with `--s-debug` and configuration inspection with `--s-debug-print`
73
- - **CLI Precedence:** Command line arguments always override file configuration
76
+ // Define a tool that works everywhere
77
+ .addTool({
78
+ name: "greet",
79
+ description: "A tool to greet someone",
80
+ flags: [
81
+ {
82
+ name: "name",
83
+ type: "string",
84
+ mandatory: true,
85
+ options: ["--name"],
86
+ description: "Name to greet",
87
+ },
88
+ {
89
+ name: "style",
90
+ type: "string",
91
+ enum: ["formal", "casual"],
92
+ defaultValue: "casual",
93
+ description: "Greeting style",
94
+ },
95
+ ],
96
+ handler: async (ctx) => {
97
+ // Use console.log freely - it's automatically safe in MCP mode!
98
+ console.log(`Greeting ${ctx.args.name} in a ${ctx.args.style} style...`);
99
+
100
+ const greeting =
101
+ ctx.args.style === "formal"
102
+ ? `Good day, ${ctx.args.name}.`
103
+ : `Hey ${ctx.args.name}!`;
104
+
105
+ console.log(greeting);
106
+ return { success: true, greeting, name: ctx.args.name };
107
+ },
108
+ });
74
109
 
75
- ## Installation
110
+ // parse() is async and works with both sync and async handlers
111
+ async function main() {
112
+ try {
113
+ await cli.parse(process.argv.slice(2));
114
+ } catch (error) {
115
+ console.error("Error:", error.message);
116
+ process.exit(1);
117
+ }
118
+ }
76
119
 
77
- You can install ArgParser using your preferred package manager:
120
+ main();
78
121
 
79
- ```bash
80
- pnpm add @alcyone-labs/arg-parser
81
- # or
82
- npm install @alcyone-labs/arg-parser
83
- # or
84
- yarn add @alcyone-labs/arg-parser
85
- # or
86
- bun add @alcyone-labs/arg-parser
87
- # or
88
- deno install npm:@alcyone-labs/arg-parser
122
+ // Export if you want to test, use the CLI programmatically
123
+ // or use the --s-enable-fuzzing system flag to run fuzzy tests on your CLI
124
+ export default cli;
89
125
  ```
90
126
 
91
- ### **For MCP Integration (Optional)**
92
-
93
- If you plan to use MCP server features, install the additional dependencies:
127
+ ## How to Run It
94
128
 
95
129
  ```bash
96
- pnpm add @modelcontextprotocol/sdk express
97
- # or
98
- npm install @modelcontextprotocol/sdk express
99
- ```
130
+ # This assumes `mycli` is your CLI's entry point
100
131
 
101
- **Note:** MCP dependencies are optional and only required if you use `ArgParser` with MCP features or MCP-related functionality.
132
+ # 1. As a standard CLI subcommand
133
+ mycli greet --name Jane --style formal
102
134
 
103
- ## Runtime Compatibility
135
+ # 2. As an MCP server, exposing the 'greet' tool
136
+ mycli --s-mcp-serve
104
137
 
105
- ArgParser is fully compatible with multiple JavaScript runtimes:
106
-
107
- ### **BunJS**
108
- ```bash
109
- # Run TypeScript directly
110
- bun your-cli.ts --flag value
111
-
112
- # Or compile and run
113
- bun build your-cli.ts --outdir ./dist
114
- bun ./dist/your-cli.js --flag value
138
+ # 3. Generate a DXT package for Claude Desktop (2-steps)
139
+ mycli --s-build-dxt ./my-dxt-package
115
140
  ```
116
141
 
117
- ### **Node.js**
118
- ```bash
119
- # Using tsx for TypeScript
120
- npx tsx your-cli.ts --flag value
142
+ Read more on generating the DXT package here: [Generating DXT Packages](#generating-dxt-packages---s-build-dxt)
121
143
 
122
- # Using ts-node
123
- npx ts-node your-cli.ts --flag value
144
+ ### Setting Up System-Wide CLI Access
124
145
 
125
- # Or compile and run
126
- npx tsc your-cli.ts
127
- node your-cli.js --flag value
128
- ```
146
+ To make your CLI available system-wide as a binary command, you need to configure the `bin` field in your `package.json` and use package linking:
129
147
 
130
- ### **Deno**
131
- ```bash
132
- # Run with required permissions
133
- deno run --unstable-sloppy-imports --allow-read --allow-write --allow-env your-cli.ts --flag value
148
+ **1. Configure your package.json:**
134
149
 
135
- # Or use the provided deno.json configuration for easier task management
136
- deno task example:simple-cli --env production --port 8080
150
+ ```json
151
+ {
152
+ "name": "my-cli-app",
153
+ "version": "1.0.0",
154
+ "type": "module",
155
+ "bin": {
156
+ "mycli": "./cli.js"
157
+ }
158
+ }
137
159
  ```
138
160
 
139
- ### **Using Built Artifacts**
140
-
141
- After building your project with `pnpm build` (or your preferred build tool), you can use the compiled JavaScript files directly:
161
+ **2. Make your CLI file executable:**
142
162
 
143
163
  ```bash
144
- # CommonJS (Node.js)
145
- node dist/index.cjs
146
-
147
- # ES Modules (Node.js with "type": "module" in package.json)
148
- node dist/index.mjs
149
-
150
- # Minified ES Modules (production)
151
- node dist/index.min.mjs
152
-
153
- # Import in your own projects
154
- const { ArgParser } = require('./dist/index.cjs'); // CommonJS
155
- import { ArgParser } from './dist/index.mjs'; // ES Modules
156
-
157
- # Example: Using built artifacts in production
158
- node -e "
159
- const { ArgParser } = require('./dist/index.cjs');
160
- const cli = new ArgParser({
161
- appName: 'Production CLI',
162
- handler: (ctx) => console.log('Production ready!', ctx.args)
163
- }).addFlags([
164
- { name: 'env', options: ['--env'], type: 'string', mandatory: true, description: 'Environment' }
165
- ]);
166
- cli.parse(['--env', 'production']);
167
- "
168
- ```
169
-
170
- All examples in this repository work seamlessly across all three runtimes, ensuring maximum compatibility for your CLI applications.
171
-
172
- ## Basic Usage
173
-
174
- ### **Standard CLI Usage**
175
-
176
- Here's a simple example demonstrating how to define flags and parse arguments:
177
-
178
- ```typescript
179
- import { ArgParser } from "@alcyone-labs/arg-parser";
180
-
181
- const parser = new ArgParser({
182
- appName: "Data Processor",
183
- appCommandName: "data-proc", // Used in help text and error messages
184
- description: "A tool for processing data phases",
185
- handler: async (ctx) => {
186
- console.log("Processing data with phase:", ctx.args.phase);
187
- return { success: true, phase: ctx.args.phase };
188
- },
189
- }).addFlags([
190
- {
191
- name: "phase",
192
- options: ["--phase"],
193
- type: "string", // Use "string", "number", "boolean", or native types
194
- mandatory: true,
195
- enum: ["chunking", "pairing", "analysis"],
196
- description: "Processing phase to execute",
197
- },
198
- {
199
- name: "batch",
200
- options: ["-b", "--batch-number"],
201
- type: "number",
202
- mandatory: (args) => args.phase !== "analysis", // Conditional requirement
203
- defaultValue: 0,
204
- description: "Batch number (required except for analysis phase)",
205
- },
206
- {
207
- name: "verbose",
208
- options: ["-v", "--verbose"],
209
- flagOnly: true, // This flag does not expect a value
210
- description: "Enable verbose logging",
211
- },
212
- ]);
213
-
214
- // Parse and execute
215
- const result = parser.parse(process.argv.slice(2));
216
- console.log("Result:", result);
164
+ chmod +x cli.js
217
165
  ```
218
166
 
219
- ### **MCP Server Usage (v1.1.0+)**
167
+ **3. Add a shebang to your CLI file:**
220
168
 
221
- Transform your CLI into an MCP server with minimal changes:
169
+ ```javascript
170
+ #!/usr/bin/env node
171
+ # or #!/usr/bin/env bun for native typescript runtime
222
172
 
223
- ```typescript
224
- import { ArgParser } from "@alcyone-labs/arg-parser";
173
+ import { ArgParser } from '@alcyone-labs/arg-parser';
225
174
 
226
175
  const cli = ArgParser.withMcp({
227
- appName: "Data Processor",
228
- appCommandName: "data-proc",
229
- description: "A tool for processing data phases (CLI + MCP server)",
230
- handler: async (ctx) => {
231
- console.log("Processing data with phase:", ctx.args.phase);
232
- return { success: true, phase: ctx.args.phase, batch: ctx.args.batch };
233
- },
234
- })
235
- .addFlags([
236
- {
237
- name: "phase",
238
- options: ["--phase"],
239
- type: "string",
240
- mandatory: true,
241
- enum: ["chunking", "pairing", "analysis"],
242
- description: "Processing phase to execute",
243
- },
244
- {
245
- name: "batch",
246
- options: ["-b", "--batch-number"],
247
- type: "number",
248
- defaultValue: 0,
249
- description: "Batch number for processing",
250
- },
251
- ])
252
- .addMcpSubCommand("serve", {
253
- name: "data-processor-mcp",
254
- version: "1.1.0",
255
- description: "Data Processor MCP Server",
176
+ appName: "My CLI",
177
+ appCommandName: "mycli",
178
+ // ... your configuration
256
179
  });
257
180
 
258
- // Use as CLI: data-proc --phase chunking --batch 5
259
- // Use as MCP server: data-proc serve
260
- // Use with custom transport: data-proc serve --transport sse --port 3001
181
+ // Parse command line arguments
182
+ await cli.parse(process.argv.slice(2));
261
183
  ```
262
184
 
263
- ## MCP Integration (v1.1.0+)
264
-
265
- ArgParser v1.1.0 introduces powerful Model Context Protocol (MCP) integration, allowing you to expose any CLI as an MCP server with minimal code changes.
266
-
267
- ### **Quick MCP Setup**
268
-
269
- 1. **Import the MCP-enabled class:**
270
- ```typescript
271
- import { ArgParser } from "@alcyone-labs/arg-parser";
272
- ```
273
-
274
- 2. **Create your CLI with MCP support:**
275
- ```typescript
276
- const cli = ArgParser.withMcp({
277
- appName: "My Tool",
278
- appCommandName: "my-tool",
279
- handler: async (ctx) => ({ result: "success", args: ctx.args }),
280
- })
281
- .addFlags([/* your flags */])
282
- .addMcpSubCommand("serve", {
283
- name: "my-mcp-server",
284
- version: "1.0.0",
285
- });
286
- ```
287
-
288
- 3. **Use as CLI or MCP server:**
289
- ```bash
290
- # CLI usage
291
- my-tool --input data.txt --verbose
292
-
293
- # MCP server (stdio)
294
- my-tool serve
295
-
296
- # MCP server (HTTP)
297
- my-tool serve --transport sse --port 3001
298
-
299
- # Multiple transports
300
- my-tool serve --transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
301
- ```
302
-
303
- ### **MCP Transport Options**
304
-
305
- - **`stdio`** (default): Standard input/output for CLI tools
306
- - **`sse`**: Server-Sent Events over HTTP for web applications
307
- - **`streamable-http`**: HTTP with streaming support for advanced integrations
308
-
309
- ### **Multiple Transports Simultaneously**
310
-
311
- Run multiple transport types at once for maximum flexibility:
185
+ **4. Link the package globally:**
312
186
 
313
187
  ```bash
314
- my-tool serve --transports '[
315
- {"type":"stdio"},
316
- {"type":"sse","port":3001,"path":"/sse"},
317
- {"type":"streamable-http","port":3002,"path":"/mcp","host":"0.0.0.0"}
318
- ]'
319
- ```
320
-
321
- ### **Automatic Tool Generation**
322
-
323
- Your CLI flags are automatically converted to MCP tools with:
324
- - **Type-safe schemas** using Zod validation
325
- - **Automatic documentation** from flag descriptions
326
- - **Enum validation** for restricted values
327
- - **Error handling** with detailed messages
328
-
329
- ## Core Concepts
188
+ # Using npm
189
+ npm link
330
190
 
331
- ### Defining Flags
191
+ # Using pnpm
192
+ pnpm link --global
332
193
 
333
- Flags are defined using the `.addFlag(flag)` method or by passing an array of flags as the second argument to the `ArgParser` constructor. Each flag is an object conforming to the `IFlag` interface:
194
+ # Using bun
195
+ bun link
334
196
 
335
- ```typescript
336
- interface IFlag {
337
- name: string; // Internal name for accessing the value in parsed args
338
- options: string[]; // Array of command-line options (e.g., ["-v", "--verbose"])
339
- type:
340
- | "string"
341
- | "boolean"
342
- | "number"
343
- | "array"
344
- | "object"
345
- | ((value: string) => any)
346
- | Constructor; // Expected type or a parsing function
347
- description: string | string[]; // Text description for help output
348
- mandatory?: boolean | ((args: TParsedArgs) => boolean); // Whether the flag is required, or a function that determines this
349
- defaultValue?: any; // Default value if the flag is not provided
350
- default?: any; // Alias for defaultValue
351
- flagOnly?: boolean; // If true, the flag does not consume the next argument as its value (e.g., `--verbose`)
352
- allowMultiple?: boolean; // If true, the flag can be provided multiple times (values are collected in an array)
353
- enum?: any[]; // Array of allowed values. Parser validates input against this list.
354
- validate?: (value: any) => boolean | string | void; // Custom validation function
355
- required?: boolean | ((args: any) => boolean); // Alias for mandatory
356
- }
197
+ # Using yarn
198
+ yarn link
357
199
  ```
358
200
 
359
- ### Type Handling and Validation
360
-
361
- ArgParser handles type conversion automatically based on the `type` property. You can use standard string types (`"string"`, `"number"`, `"boolean"`, `"array"`, `"object`), native constructors (`String`, `Number`, `Boolean`, `Array`, `Object`), or provide a custom function:
201
+ **5. Use your CLI from anywhere:**
362
202
 
363
- ```typescript
364
- .addFlag({
365
- name: "count",
366
- options: ["--count"],
367
- type: Number, // Automatically converts value to a number
368
- })
369
- .addFlag({
370
- name: "data",
371
- options: ["--data"],
372
- type: JSON.parse, // Use a function to parse complex types like JSON strings
373
- description: "JSON data to process"
374
- })
375
- .addFlag({
376
- name: "environment",
377
- options: ["--env"],
378
- type: "string",
379
- enum: ["dev", "staging", "prod"], // Validate value against this list
380
- description: "Deployment environment",
381
- })
382
- .addFlag({
383
- name: "id",
384
- options: ["--id"],
385
- type: "string",
386
- validate: (value) => /^[a-f0-9]+$/.test(value), // Custom validation function
387
- description: "Hexadecimal ID",
388
- })
389
- .addFlag({
390
- name: "config",
391
- options: ["-c"],
392
- allowMultiple: true,
393
- type: path => require(path), // Load config from path (example)
394
- description: "Load multiple configuration files"
395
- })
396
- ```
397
-
398
- ### Mandatory Flags
399
-
400
- Flags can be made mandatory using the `mandatory` property, or its alias "required". This can be a boolean or a function that receives the currently parsed arguments and returns a boolean.
203
+ ```bash
204
+ # Now you can run your CLI from any directory
205
+ mycli --help
206
+ mycli greet --name "World"
401
207
 
402
- ```typescript
403
- .addFlag({
404
- name: "input",
405
- options: ["--in"],
406
- type: String,
407
- mandatory: true, // Always mandatory
408
- description: "Input file path",
409
- })
410
- .addFlag({
411
- name: "output",
412
- options: ["--out"],
413
- type: String,
414
- mandatory: (args) => args.format === "json", // Mandatory only if --format is "json"
415
- description: "Output file path (required for JSON output)",
416
- })
208
+ # Or use with npx/pnpx if you prefer
209
+ npx mycli --help
210
+ pnpx mycli greet --name "World"
417
211
  ```
418
212
 
419
- If a mandatory flag is missing and default error handling is enabled (`handleErrors: true`), the parser will print an error and exit.
420
-
421
- ### Default Values
213
+ **To unlink later:**
422
214
 
423
- Set a `defaultValue` (or its alias `default`) for flags to provide a fallback value if the flag is not present in the arguments.
424
-
425
- ```typescript
426
- .addFlag({
427
- name: "port",
428
- options: ["-p", "--port"],
429
- type: Number,
430
- defaultValue: 3000, // Default port is 3000 if -p or --port is not used
431
- description: "Server port",
432
- })
433
- ```
215
+ ```bash
216
+ # Using npm
217
+ npm unlink --global my-cli-app
434
218
 
435
- ### Flag-Only Flags
219
+ # Using pnpm
220
+ pnpm unlink --global
436
221
 
437
- Flags that do not expect a value (like `--verbose` or `--force`) should have `flagOnly: true`. When `flagOnly` is false (the default), the parser expects the next argument to be the flag's value.
222
+ # Using bun
223
+ bun unlink
438
224
 
439
- ```typescript
440
- .addFlag({
441
- name: "verbose",
442
- options: ["-v"],
443
- type: Boolean, // Typically boolean for flag-only flags
444
- flagOnly: true,
445
- description: "Enable verbose output",
446
- })
225
+ # Using yarn
226
+ yarn unlink
447
227
  ```
448
228
 
449
- ### Alias Properties
450
-
451
- For convenience, `ArgParser` supports aliases for some flag properties:
452
-
453
- - `default` is an alias for `defaultValue`.
454
- - `required` is an alias for `mandatory`.
455
- If both the original property and its alias are provided, the original property (`defaultValue`, `mandatory`) takes precedence.
456
-
457
- ## Hierarchical CLIs (Sub-Commands)
458
-
459
- ArgParser excels at building CLIs with nested commands, like `git clone` or `docker build`.
229
+ ---
460
230
 
461
- ### Defining Sub-Commands
231
+ ## Parsing Command-Line Arguments
462
232
 
463
- Define sub-commands using the `subCommands` option in the `ArgParser` constructor or the `.addSubCommand(subCommand)` method. Each sub-command requires a `name`, `description`, and a dedicated `ArgParser` instance for its own flags and nested sub-commands.
233
+ ArgParser's `parse()` method is async and automatically handles both synchronous and asynchronous handlers:
464
234
 
465
- Note that each flag name set is debounced to make sure there are no duplicates, but the flags are sandboxed within their respective sub-commands. So it's ok to use the same flag on different sub-commands.
235
+ ### Cannonical Usage Pattern
466
236
 
467
237
  ```typescript
468
- import {
469
- ArgParser,
470
- HandlerContext,
471
- ISubCommand,
472
- } from "@alcyone-labs/arg-parser";
473
-
474
- const deployParser = new ArgParser().addFlags([
475
- { name: "target", options: ["-t"], type: String, mandatory: true },
476
- ]);
477
-
478
- const monitorLogsParser = new ArgParser().addFlags([
479
- { name: "follow", options: ["-f"], flagOnly: true, type: Boolean },
480
- ]);
481
-
482
- const monitorParser = new ArgParser().addSubCommand({
483
- name: "logs",
484
- description: "Show logs",
485
- parser: monitorLogsParser,
486
- handler: ({ args }) => {
487
- console.log(`Showing logs... Follow: ${args.follow}`);
488
- },
489
- });
490
-
491
- const cli = new ArgParser({
238
+ const cli = ArgParser.withMcp({
492
239
  appName: "My CLI",
493
- appCommandName: "my-cli",
494
- description: "Manage application resources",
495
- subCommands: [
496
- {
497
- name: "deploy",
498
- description: "Deploy resources",
499
- parser: deployParser,
500
- handler: ({ args }) => {
501
- console.log(`Deploying to ${args.target}`);
502
- },
503
- },
504
- {
505
- name: "monitor",
506
- description: "Monitoring commands",
507
- parser: monitorParser,
508
- },
509
- ],
240
+ handler: async (ctx) => {
241
+ // Works with both sync and async operations
242
+ const result = await someAsyncOperation(ctx.args.input);
243
+ return { success: true, result };
244
+ },
510
245
  });
511
246
 
512
- // Example usage:
513
- // my-cli deploy -t production
514
- // my-cli monitor logs -f
515
- ```
516
-
517
- ### Handler Execution
518
-
519
- A core feature is associating handler functions with commands. Handlers are functions (`(ctx: HandlerContext) => void`) that contain the logic to be executed when a specific command (root or sub-command) is successfully parsed and matched.
520
-
521
- Handlers can be defined in the `ISubCommand` object or set/updated later using the `.setHandler()` method on the command's parser instance.
522
-
523
- **By default, after successful parsing, ArgParser will execute the handler associated with the _final command_ matched in the argument chain.** For example, running `my-cli service start` will execute the handler for the `start` command, not `my-cli` or `service`.
524
-
525
- If you need to parse arguments but _prevent_ handler execution, you can pass the `skipHandlers: true` option to the `parse()` method:
526
-
527
- ```typescript
528
- const args = parser.parse(process.argv.slice(2), { skipHandlers: true });
529
- // Handlers will NOT be executed, you can inspect 'args' and decide what to do
530
- ```
531
-
532
- ### Handler Context
533
-
534
- Handler functions receive a single argument, a `HandlerContext` object, containing information about the parsing result and the command chain:
535
-
536
- ```typescript
537
- type HandlerContext = {
538
- args: TParsedArgs<any>; // Arguments parsed by and defined for the FINAL command's parser
539
- parentArgs?: TParsedArgs<any>; // Combined arguments from PARENT parsers (less relevant with inheritParentFlags)
540
- commandChain: string[]; // Array of command names from root to final command
541
- };
247
+ // parse() is async and works with both sync and async handlers
248
+ async function main() {
249
+ try {
250
+ const result = await cli.parse(process.argv.slice(2));
251
+ // Handler results are automatically awaited and merged
252
+ console.log(result.success); // true
253
+ } catch (error) {
254
+ console.error("Error:", error.message);
255
+ process.exit(1);
256
+ }
257
+ }
542
258
  ```
543
259
 
544
- The `args` property is the most commonly used, containing flags and their values relevant to the handler's specific command. If `inheritParentFlags` is used, inherited flags appear directly in `args`.
260
+ ### Top-level await
545
261
 
546
- ### Setting Handlers with `.setHandler()`
262
+ Works in ES modules or Node.js >=18 with top-level await
547
263
 
548
- You can define or override a parser instance's handler after its creation:
549
-
550
- ```typescript
551
- const myCommandParser = new ArgParser().addFlags(/* ... */);
552
-
553
- myCommandParser.setHandler((ctx) => {
554
- console.log(`Executing handler for ${ctx.commandChain.join(" -> ")}`);
555
- // ... command logic ...
556
- });
557
-
558
- // You can also retrieve a sub-parser and set its handler:
559
- const subParser = cli.getSubCommand("deploy")?.parser;
560
- if (subParser) {
561
- subParser.setHandler((ctx) => {
562
- console.log("Overridden deploy handler!");
563
- // ... new deploy logic ...
564
- });
264
+ ```javascript
265
+ try {
266
+ const result = await cli.parse(process.argv.slice(2));
267
+ console.log("Success:", result);
268
+ } catch (error) {
269
+ console.error("Error:", error.message);
270
+ process.exit(1);
565
271
  }
566
272
  ```
567
273
 
568
- ### Accessing Sub-Parsers with `.getSubCommand()`
274
+ ### Promise-based parsing
569
275
 
570
- Use the `.getSubCommand(name)` method on a parser instance to retrieve the `ISubCommand` definition for a specific sub-command by name. This allows you to access its parser instance to set handlers, add flags dynamically, or inspect its configuration.
276
+ If you need synchronous contexts, you can simply rely on promise-based APIs
571
277
 
572
- ```typescript
573
- const deploySubCommand = cli.getSubCommand("deploy");
574
- if (deploySubCommand) {
575
- console.log(`Description of deploy command: ${deploySubCommand.description}`);
576
- // Access the parser instance:
577
- const deployParserInstance = deploySubCommand.parser;
578
- // Add a flag specifically to the deploy command after initial setup:
579
- deployParserInstance.addFlag({
580
- name: "force",
581
- options: ["--force"],
582
- flagOnly: true,
583
- type: Boolean,
278
+ ```javascript
279
+ cli
280
+ .parse(process.argv.slice(2))
281
+ .then((result) => {
282
+ console.log("Success:", result);
283
+ })
284
+ .catch((error) => {
285
+ console.error("Error:", error.message);
286
+ process.exit(1);
584
287
  });
585
- }
586
288
  ```
587
289
 
588
- ### Flag Inheritance (`inheritParentFlags`)
290
+ ---
589
291
 
590
- Enable `inheritParentFlags: true` in a child parser's constructor options to automatically copy flags from its direct parent when added as a sub-command. This is useful for sharing common flags like `--verbose` across your CLI.
292
+ ## Migrating from v1.x to the v2.0 `addTool` API
591
293
 
592
- If a flag with the same name exists in both the parent and the child, the child's definition takes precedence. The built-in `--help` flag is never inherited.
294
+ Version 2.0 introduces the `addTool()` method to unify CLI subcommand and MCP tool creation. This simplifies development by removing boilerplate and conditional logic.
593
295
 
594
- ```typescript
595
- const parentParser = new ArgParser().addFlags([
596
- { name: "verbose", options: ["-v"], type: Boolean, flagOnly: true },
597
- { name: "config", options: ["-c"], type: String }, // Common config flag
598
- ]);
296
+ ### Before v2.0: Separate Definitions
599
297
 
600
- const childParser = new ArgParser({ inheritParentFlags: true }).addFlags([
601
- { name: "local", options: ["-l"], type: String }, // Child-specific flag
602
- { name: "config", options: ["--child-config"], type: Number }, // Override config flag
603
- ]);
298
+ Previously, you had to define CLI handlers and MCP tools separately, often with conditional logic inside the handler to manage different output formats.
604
299
 
605
- parentParser.addSubCommand({
606
- name: "child",
607
- description: "A child command",
608
- parser: childParser,
300
+ ```javascript
301
+ const cli = ArgParser.withMcp({
302
+ appName: "My Awesome CLI",
303
+ appCommandName: "mycli",
304
+ description: "A tool that works in both CLI and MCP mode",
305
+ mcp: {
306
+ serverInfo: { name: "my-awesome-mcp-server", version: "1.0.0" },
307
+ },
609
308
  });
610
309
 
611
- // The 'child' parser now effectively has flags: --help, -v, -l, --child-config
612
- // Running `parent child -v -l value --child-config 123` will parse all these flags.
310
+ // Old way: Separate CLI subcommands and MCP tools
311
+ cli
312
+ .addSubCommand({
313
+ name: "search",
314
+ handler: async (ctx) => {
315
+ // Manual MCP detection was required
316
+ if (ctx.isMcp) {
317
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
318
+ } else {
319
+ console.log("Search results...");
320
+ return result;
321
+ }
322
+ },
323
+ })
324
+ // And a separate command to start the server
325
+ .addMcpSubCommand("serve", {
326
+ /* MCP config */
327
+ });
613
328
  ```
614
329
 
615
- ## Automatic Help
616
-
617
- ArgParser provides robust automatic help generation.
330
+ ### After v2.0: The Unified `addTool()` Method
618
331
 
619
- ### Global Help Flag (`--help`, `-h`)
332
+ Now, a single `addTool()` definition creates both the CLI subcommand and the MCP tool. Console output is automatically managed, flags are converted to MCP schemas, and the server is started with a universal system flag.
620
333
 
621
- A `--help` (and `-h`) flag is automatically added to every parser instance (root and sub-commands). When this flag is encountered during parsing:
622
-
623
- 1. ArgParser stops processing arguments.
624
- 2. Generates and prints the help text relevant to the current command/sub-command context.
625
- 3. Exits the process with code 0.
626
-
627
- This behavior is triggered automatically unless `skipHelpHandling: true` is passed to the `parse()` method.
628
-
629
- ```bash
630
- # Shows help for the root command
631
- my-cli --help
632
-
633
- # Shows help for the 'deploy' sub-command
634
- my-cli deploy --help
635
- ```
636
-
637
- ### `helpText()` Method
334
+ ```javascript
335
+ const cli = ArgParser.withMcp({
336
+ appName: "My Awesome CLI",
337
+ appCommandName: "mycli",
338
+ description: "A tool that works in both CLI and MCP mode",
339
+ mcp: {
340
+ serverInfo: { name: "my-awesome-mcp-server", version: "1.0.0" },
341
+ },
342
+ });
638
343
 
639
- You can manually generate the help text for any parser instance at any time using the `helpText()` method. This returns a string containing the formatted help output.
344
+ // New way: A single tool definition for both CLI and MCP
345
+ cli.addTool({
346
+ name: "search",
347
+ description: "Search for items",
348
+ flags: [
349
+ { name: "query", type: "string", mandatory: true },
350
+ { name: "apiKey", type: "string", env: "API_KEY" }, // For DXT integration
351
+ ],
352
+ handler: async (ctx) => {
353
+ // No more MCP detection! Use console.log freely.
354
+ console.log(`Searching for: ${ctx.args.query}`);
355
+ const results = await performSearch(ctx.args.query, ctx.args.apiKey);
356
+ console.log(`Found ${results.length} results`);
357
+ return { success: true, results };
358
+ },
359
+ });
640
360
 
641
- ```typescript
642
- console.log(parser.helpText());
361
+ // CLI usage: mycli search --query "test"
362
+ // MCP usage: mycli --s-mcp-serve
643
363
  ```
644
364
 
645
- ### Auto-Help on Empty Invocation
646
-
647
- For the root command, if you invoke the script **without any arguments** and the root parser **does not have a handler defined**, ArgParser will automatically display the root help text and exit cleanly (code 0). This provides immediate guidance for users who just type the script name.
648
-
649
- If the root parser _does_ have a handler, it's assumed that the handler will manage the empty invocation case, and auto-help will not trigger.
650
-
651
- ## Error Handling
365
+ **Benefits of Migrating:**
652
366
 
653
- ArgParser includes built-in error handling for common parsing errors like missing mandatory flags, invalid types, or unknown commands.
367
+ - **Less Code**: A single definition replaces two or more complex ones.
368
+ - **Simpler Logic**: No more manual MCP mode detection or response formatting.
369
+ - **Automatic Schemas**: Flags are automatically converted into the `input_schema` for MCP tools.
370
+ - **Automatic Console Safety**: `console.log` is automatically redirected in MCP mode.
654
371
 
655
- By default (`handleErrors: true`):
656
-
657
- 1. A descriptive, colored error message is printed to `stderr`.
658
- 2. A suggestion to use `--help` is included, showing the correct command path.
659
- 3. The process exits with status code 1.
372
+ ---
660
373
 
661
- ```typescript
662
- // Example (assuming 'data-proc' is appCommandName and 'phase' is mandatory)
663
- // Running `data-proc` would output:
374
+ ## Core Concepts
664
375
 
665
- // Error: Missing mandatory flags: phase
666
- //
667
- // Try 'data-proc --help' for usage details.
668
- ```
376
+ ### Defining Flags
669
377
 
670
- You can disable this behavior by setting `handleErrors: false` in the `ArgParser` constructor options. When disabled, ArgParser will throw an `ArgParserError` exception on parsing errors, allowing you to catch and handle them programmatically.
378
+ Flags are defined using the `IFlag` interface within the `flags` array of a tool or command.
671
379
 
672
380
  ```typescript
673
- import { ArgParser, ArgParserError } from "@alcyone-labs/arg-parser";
674
-
675
- const parser = new ArgParser({
676
- appCommandName: "my-app",
677
- handleErrors: false, // Disable default handling
678
- });
679
-
680
- try {
681
- const args = parser.parse(process.argv.slice(2));
682
- // Process args if parsing succeeded
683
- } catch (error) {
684
- if (error instanceof ArgParserError) {
685
- console.error(`\nCustom Parse Error: ${error.message}`);
686
- // Implement custom logic (e.g., logging, different exit codes)
687
- process.exit(1);
688
- } else {
689
- // Handle unexpected errors
690
- console.error("An unexpected error occurred:", error);
691
- process.exit(1);
692
- }
381
+ interface IFlag {
382
+ name: string; // Internal name (e.g., 'verbose')
383
+ options: string[]; // Command-line options (e.g., ['--verbose', '-v'])
384
+ type: "string" | "number" | "boolean" | "array" | "object" | Function;
385
+ description?: string; // Help text
386
+ mandatory?: boolean | ((args: any) => boolean); // Whether the flag is required
387
+ defaultValue?: any; // Default value if not provided
388
+ flagOnly?: boolean; // A flag that doesn't consume a value (like --help)
389
+ enum?: any[]; // An array of allowed values
390
+ validate?: (value: any, parsedArgs?: any) => boolean | string | void; // Custom validation function
391
+ allowMultiple?: boolean; // Allow the flag to be provided multiple times
392
+ env?: string; // Links the flag to an environment variable for DXT packages, will automatically generate user_config entries in the DXT manifest and fill the flag value to the ENV value if found (process.env)
693
393
  }
694
394
  ```
695
395
 
696
- ## Environment Configuration Export
697
-
698
- ArgParser includes a built-in system flag `--s-save-to-env` that allows you to export the current parser's configuration and parsed arguments to various file formats. This is useful for creating configuration templates, documenting CLI usage, or generating environment files for deployment.
699
-
700
- ### Usage
701
-
702
- ```bash
703
- # Export to .env format (default for no extension)
704
- your-cli --flag1 value1 --flag2 --s-save-to-env config.env
705
-
706
- # Export to YAML format
707
- your-cli --flag1 value1 --flag2 --s-save-to-env config.yaml
708
-
709
- # Export to JSON format
710
- your-cli --flag1 value1 --flag2 --s-save-to-env config.json
711
-
712
- # Export to TOML format
713
- your-cli --flag1 value1 --flag2 --s-save-to-env config.toml
714
- ```
715
-
716
- ### Supported Formats
717
-
718
- The format is automatically detected based on the file extension:
396
+ ### Type Handling and Validation
719
397
 
720
- - **`.env`** (or no extension): Bash environment variable format
721
- - **`.yaml` / `.yml`**: YAML format
722
- - **`.json` / `.jsonc`**: JSON format with metadata
723
- - **`.toml` / `.tml`**: TOML format
398
+ ArgParser automatically handles type conversion and validation:
724
399
 
725
- ### Behavior
400
+ - **String flags**: `--name value` or `--name="quoted value"`
401
+ - **Number flags**: `--count 42` (automatically parsed)
402
+ - **Boolean flags**: `--verbose` (presence implies `true`)
403
+ - **Array flags**: `--tags tag1,tag2,tag3` or multiple `--tag value1 --tag value2` (requires `allowMultiple: true`)
726
404
 
727
- - **Works at any parser level**: Can be used with root commands or sub-commands
728
- - **Includes inherited flags**: Shows flags from the current parser and all parent parsers in the chain
729
- - **Comments optional flags**: Flags that are optional and not set are commented out but still documented
730
- - **Preserves values**: Set flags show their actual values, unset flags show default values or are commented out
731
- - **Rich documentation**: Each flag includes its description, options, type, and constraints
405
+ ### Hierarchical CLIs (Sub-Commands)
732
406
 
733
- ### Example Output
407
+ While `addTool()` is the recommended way to create subcommands that are also MCP-compatible, you can use `.addSubCommand()` for traditional CLI hierarchies.
734
408
 
735
- For a CLI with flags `--verbose`, `--output file.txt`, and `--count 5`:
409
+ > **Note**: By default, subcommands created with `.addSubCommand()` are exposed to MCP as tools. If you want to create CLI-only subcommands, set `includeSubCommands: false` when adding tools.
736
410
 
737
- **`.env` format:**
738
- ```bash
739
- # Environment configuration generated by ArgParser
740
- # Format: Bash .env style
741
-
742
- # verbose: Enable verbose output
743
- # Options: -v, --verbose
744
- # Type: Boolean
745
- # Default: false
746
- VERBOSE="true"
747
-
748
- # output: Output file path
749
- # Options: -o, --output
750
- # Type: String
751
- OUTPUT="file.txt"
752
-
753
- # count: Number of items to process
754
- # Options: -c, --count
755
- # Type: Number
756
- # Default: 10
757
- COUNT="5"
758
- ```
411
+ ```typescript
412
+ // Create a parser for a nested command
413
+ const logsParser = new ArgParser().addFlags([
414
+ { name: "follow", options: ["-f"], type: "boolean", flagOnly: true },
415
+ ]);
759
416
 
760
- **`.yaml` format:**
761
- ```yaml
762
- # Environment configuration generated by ArgParser
763
- # Format: YAML
417
+ // This creates a command group: `my-cli monitor`
418
+ const monitorParser = new ArgParser().addSubCommand({
419
+ name: "logs",
420
+ description: "Show application logs",
421
+ parser: logsParser,
422
+ handler: ({ args }) => console.log(`Following logs: ${args.follow}`),
423
+ });
764
424
 
765
- # verbose: Enable verbose output
766
- # Options: -v, --verbose
767
- # Type: Boolean
768
- # Default: false
425
+ // Attach the command group to the main CLI
426
+ const cli = new ArgParser().addSubCommand({
427
+ name: "monitor",
428
+ description: "Monitoring commands",
429
+ parser: monitorParser,
430
+ });
769
431
 
770
- verbose: true
771
- output: "file.txt"
772
- count: 5
432
+ // Usage: my-cli monitor logs -f
773
433
  ```
774
434
 
775
- ## System Flags (v1.1.0+)
776
-
777
- ArgParser includes several built-in system flags that provide debugging, configuration management, and introspection capabilities. These flags are processed before normal argument parsing and will cause the program to exit after execution.
435
+ #### MCP Exposure Control
778
436
 
779
- ### **Overview**
780
-
781
- System flags use the `--s-*` pattern and provide powerful development and deployment tools:
782
-
783
- - **`--s-debug`**: Runtime debugging with step-by-step parsing analysis
784
- - **`--s-with-env <file>`**: Load configuration from files (`.env`, `.yaml`, `.json`, `.toml`)
785
- - **`--s-save-to-env <file>`**: Export current configuration to various formats
786
- - **`--s-debug-print`**: Export complete parser configuration for inspection
787
- - **`--s-enable-fuzzy`**: Enable fuzzy testing mode (dry-run with no side effects)
788
-
789
- ### `--s-save-to-env <file>`
790
-
791
- Exports the current parser's configuration and parsed arguments to various file formats.
792
-
793
- ```bash
794
- # Export to .env format (default for no extension)
795
- your-cli --flag1 value1 --flag2 --s-save-to-env config.env
796
-
797
- # Export to YAML format
798
- your-cli --flag1 value1 --flag2 --s-save-to-env config.yaml
437
+ ```typescript
438
+ // By default, subcommands are exposed to MCP
439
+ const mcpTools = parser.toMcpTools(); // Includes all subcommands
799
440
 
800
- # Export to JSON format
801
- your-cli --flag1 value1 --flag2 --s-save-to-env config.json
441
+ // To exclude subcommands from MCP (CLI-only)
442
+ const mcpToolsOnly = parser.toMcpTools({ includeSubCommands: false });
802
443
 
803
- # Export to TOML format
804
- your-cli --flag1 value1 --flag2 --s-save-to-env config.toml
444
+ // Name conflicts: You cannot have both addSubCommand("name") and addTool({ name: "name" })
445
+ // This will throw an error:
446
+ parser.addSubCommand({ name: "process", parser: subParser });
447
+ parser.addTool({ name: "process", handler: async () => {} }); // ❌ Error: Sub-command 'process' already exists
805
448
  ```
806
449
 
807
- **Features:**
808
- - Works at any parser level (root command or sub-commands)
809
- - Includes inherited flags from parent parsers in the chain
810
- - Comments out optional flags that are not set
811
- - Rich documentation for each flag (description, options, type, constraints)
812
- - Automatic format detection based on file extension
813
-
814
- ### `--s-with-env <file>`
815
-
816
- Loads configuration from a file and merges it with command line arguments. CLI arguments take precedence over file configuration.
817
-
818
- ```bash
819
- # Load from .env format (default for no extension)
820
- your-cli --s-with-env config.env
450
+ ### Flag Inheritance (`inheritParentFlags`)
821
451
 
822
- # Load from YAML format
823
- your-cli --s-with-env config.yaml
452
+ To share common flags (like `--verbose` or `--config`) across sub-commands, set `inheritParentFlags: true` in the sub-command's parser.
824
453
 
825
- # Load from JSON format
826
- your-cli --s-with-env config.json
454
+ ```typescript
455
+ const parentParser = new ArgParser().addFlags([
456
+ { name: "verbose", options: ["-v"], type: "boolean" },
457
+ ]);
827
458
 
828
- # Load from TOML format
829
- your-cli --s-with-env config.toml
459
+ // This child parser will automatically have the --verbose flag
460
+ const childParser = new ArgParser({ inheritParentFlags: true }).addFlags([
461
+ { name: "target", options: ["-t"], type: "string" },
462
+ ]);
830
463
 
831
- # Combine with CLI arguments (CLI args override file config)
832
- your-cli --s-with-env config.yaml --verbose --output override.txt
464
+ parentParser.addSubCommand({ name: "deploy", parser: childParser });
833
465
  ```
834
466
 
835
- **Supported Formats:**
836
-
837
- The format is automatically detected based on the file extension:
838
-
839
- - **`.env`** (or no extension): Dotenv format with `KEY=value` pairs
840
- - **`.yaml` / `.yml`**: YAML format
841
- - **`.json` / `.jsonc`**: JSON format (metadata is ignored if present)
842
- - **`.toml` / `.tml`**: TOML format
467
+ ---
843
468
 
844
- **Behavior:**
469
+ ## MCP & Claude Desktop Integration
845
470
 
846
- - **File validation**: Checks if the file exists and can be parsed
847
- - **Type conversion**: Automatically converts values to match flag types (boolean, number, string, array)
848
- - **Enum validation**: Validates values against allowed enum options
849
- - **CLI precedence**: Command line arguments override file configuration
850
- - **Error handling**: Exits with error code 1 if file cannot be loaded or parsed
851
- - **Flag matching**: Only loads values for flags that exist in the current parser chain
471
+ ### Automatic MCP Server Mode (`--s-mcp-serve`)
852
472
 
853
- **Example Configuration Files:**
473
+ You don't need to write any server logic. Run your application with the `--s-mcp-serve` flag, and ArgParser will automatically start a compliant MCP server, exposing all tools defined with `.addTool()` and subcommands created with `.addSubCommand()` (unless `includeSubCommands: false` is set).
854
474
 
855
- **.env format:**
856
475
  ```bash
857
- VERBOSE=true
858
- OUTPUT=file.txt
859
- COUNT=5
860
- TAGS=tag1,tag2,tag3
861
- ```
862
-
863
- **YAML format:**
864
- ```yaml
865
- verbose: true
866
- output: file.txt
867
- count: 5
868
- tags:
869
- - tag1
870
- - tag2
871
- - tag3
872
- ```
873
-
874
- **JSON format:**
875
- ```json
876
- {
877
- "verbose": true,
878
- "output": "file.txt",
879
- "count": 5,
880
- "tags": ["tag1", "tag2", "tag3"]
881
- }
882
- ```
476
+ # This single command starts a fully compliant MCP server
477
+ my-cli-app --s-mcp-serve
883
478
 
884
- ### `--s-debug-print`
885
-
886
- Prints the complete parser configuration to a JSON file and console for debugging complex parser setups.
887
-
888
- ```bash
889
- your-cli --s-debug-print
479
+ # You can also override transports and ports using system flags
480
+ my-cli-app --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3001
890
481
  ```
891
482
 
892
- **Output:**
893
- - Creates `ArgParser.full.json` with the complete parser structure
894
- - Shows all flags, sub-commands, handlers, and configuration
895
- - Useful for debugging complex parser hierarchies
896
- - Human-readable console output with syntax highlighting
483
+ ### MCP Transports
897
484
 
898
- ### `--s-debug`
899
-
900
- Provides detailed runtime debugging information showing how arguments are parsed step-by-step.
485
+ You can define the transports directly in the .withMcp() settings, or override them via the `--s-mcp-transport(s)` flags.
901
486
 
902
487
  ```bash
903
- your-cli --flag1 value1 sub-command --flag2 value2 --s-debug
904
- ```
905
-
906
- **Output:**
907
- - Shows command chain identification process
908
- - Step-by-step argument parsing simulation
909
- - Final parser identification
910
- - Accumulated arguments at each level
911
- - Remaining arguments after parsing
912
- - Complete static configuration of the final parser
913
-
914
- **Useful for:**
915
- - Understanding complex command chains
916
- - Debugging argument parsing issues
917
- - Seeing how flags are inherited between parsers
918
- - Troubleshooting sub-command resolution
919
-
920
- ### Usage Notes
921
-
922
- - System flags are processed before normal argument parsing
923
- - They cause the program to exit after execution (exit code 0 for success)
924
- - Can be used with any combination of regular flags and sub-commands
925
- - Particularly useful during development and debugging
926
-
927
- ## Debugging
928
-
929
- ### Programmatic Debugging
930
-
931
- The `printAll(filePath?: string)` method is useful for debugging complex parser configurations programmatically. It recursively outputs the structure, options, flags, and handlers of a parser instance and its sub-commands.
932
-
933
- - `parser.printAll()`: Prints a colored, human-readable output to the console.
934
- - `parser.printAll('./config.json')`: Writes the configuration as a pretty-printed JSON file.
935
- - `parser.printAll('./config.log')`: Writes a plain text version to a file.
936
-
937
- ```typescript
938
- import { ArgParser } from "@alcyone-labs/arg-parser";
939
-
940
- const parser = new ArgParser({ appName: "Debug App" })
941
- .addFlags([
942
- /* ... */
943
- ])
944
- .addSubCommand(/* ... */);
945
-
946
- parser.printAll(); // Output to console
947
- ```
948
-
949
- ### Runtime Debugging
950
-
951
- For runtime debugging, use the system flags documented above:
952
-
953
- - `--s-debug-print`: Export complete parser configuration
954
- - `--s-debug`: Show step-by-step argument parsing process
955
- - `--s-save-to-env <file>`: Export current configuration to various formats
956
- - `--s-with-env <file>`: Load configuration from file and merge with CLI arguments
488
+ # Single transport
489
+ my-tool --s-mcp-serve --s-mcp-transport stdio
957
490
 
958
- ### `--s-enable-fuzzy`
491
+ # Multiple transports via JSON
492
+ my-tool --s-mcp-serve --s-mcp-transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
959
493
 
960
- Enables fuzzy testing mode, which acts as a dry-run mode for safe testing without side effects. **No boilerplate code required** - the system automatically prevents CLI execution during fuzzy testing.
494
+ # Single transport with custom options
495
+ my-tool --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3000 --s-mcp-host 0.0.0.0
961
496
 
962
- ```bash
963
- # Enable fuzzy mode for testing
964
- your-cli --s-enable-fuzzy --input test.txt --format json
965
- ```
966
-
967
- **Features:**
968
- - **Automatic execution prevention**: No need for complex conditional logic in your CLI code
969
- - **Zero boilerplate**: Simply export your CLI with `export default cli` and call `cli.parse()`
970
- - Disables error handling to allow error collection
971
- - Skips mandatory flag validation for comprehensive testing
972
- - **Prevents handler function execution** (no side effects)
973
- - **Logs what each handler would receive** for testing visibility
974
- - Recursively applies to all subcommand parsers
975
- - Safe for testing production CLIs with database operations, file modifications, or API calls
976
-
977
- **Example Output:**
978
- ```
979
- [--s-enable-fuzzy] handler() skipped for command chain: (root)
980
- Input args: [--s-enable-fuzzy --input test.txt --format json]
981
- Parsed args: {"input":"test.txt","format":"json"}
497
+ # Multiple transports (configured via --s-mcp-serve system flag)
498
+ const cli = ArgParser.withMcp({
499
+ appName: 'multi-tool',
500
+ appCommandName: 'multi-tool',
501
+ mcp: {
502
+ serverInfo: {
503
+ name: 'multi-tool-mcp',
504
+ version: '1.0.0'
505
+ },
506
+ transports: [
507
+ // Can be a single string...
508
+ "stdio",
509
+ // or one of the other transport types supported by @modelcontextprotocol/sdk
510
+ { type: "sse", port: 3000, host: "0.0.0.0" },
511
+ { type: "websocket", port: 3001, path: "/ws" }
512
+ ]
513
+ }
514
+ });
982
515
  ```
983
516
 
984
- **Use Cases:**
985
- - Fuzzy testing CLI argument parsing
986
- - Validating CLI configuration without executing business logic
987
- - Testing complex command hierarchies safely
988
- - Automated testing of CLI interfaces
989
-
990
- These system flags are particularly useful when you need to debug a CLI application without modifying the source code.
517
+ ### Automatic Console Safety
991
518
 
992
- ## Fuzzy Testing
519
+ A major challenge in MCP is preventing `console.log` from corrupting the JSON-RPC communication over `STDOUT`. ArgParser solves this automatically.
993
520
 
994
- ArgParser includes comprehensive fuzzy testing capabilities to automatically test CLI configurations and catch edge cases that manual testing might miss. The fuzzy testing utility systematically explores command paths and generates various flag combinations to ensure robustness.
521
+ - **How it works**: When `--s-mcp-serve` is active, ArgParser hijacks the global `console` object.
522
+ - **What it does**: It redirects `console.log`, `.info`, `.warn`, and `.debug` to `STDERR` with a prefix, making them visible for debugging without interfering with the protocol. `console.error` is preserved on `STDERR` as expected.
523
+ - **Your benefit**: You can write `console.log` statements freely in your handlers. They will work as expected in CLI mode and be safely handled in MCP mode with **zero code changes**.
995
524
 
996
- ### **Quick Start**
525
+ ### Generating DXT Packages (`--s-build-dxt`)
997
526
 
998
- Test any ArgParser configuration using the built-in fuzzy testing CLI:
527
+ A Desktop Extension (`.dxt`) is a standardized package for installing your tools into Claude Desktop. ArgParser automates this process.
999
528
 
1000
529
  ```bash
1001
- # Test an ArgParser file
1002
- bun src/fuzzy-test-cli.ts --file examples/getting-started.ts
1003
-
1004
- # Test with custom options and save results
1005
- bun src/fuzzy-test-cli.ts \
1006
- --file examples/getting-started.ts \
1007
- --output test-results.json \
1008
- --format json \
1009
- --max-depth 3 \
1010
- --random-tests 20 \
1011
- --verbose
1012
- ```
530
+ # 1. Generate the DXT package contents into a directory
531
+ my-cli-app --s-build-dxt ./my-dxt-package
1013
532
 
1014
- **Important Note**: Make sure that the `examples/getting-started.ts` file exports the parser instance using `export default` for the fuzzy testing CLI to work correctly.
533
+ # The output folder contains everything needed: manifest.json, entry point, etc.
534
+ # A default logo will be applied if you don't provide one.
1015
535
 
1016
- ### **System Flag Integration**
536
+ # 2. (Optional) Pack the folder into a .dxt file for distribution
537
+ npx @anthropic-ai/dxt pack ./my-dxt-package
1017
538
 
1018
- The `--s-enable-fuzzy` system flag makes any CLI fuzzy-test compatible **without any code modifications or boilerplate**:
1019
-
1020
- ```bash
1021
- # Enable fuzzy mode for safe testing (dry-run with no side effects)
1022
- your-cli --s-enable-fuzzy --input test.txt --format json
539
+ # 3. (Optional) Sign the DXT package
540
+ npx @anthropic-ai/dxt sign ./my-dxt-package.dxt
1023
541
 
1024
- # The fuzzy testing CLI automatically uses this flag
1025
- bun src/fuzzy-test-cli.ts --file your-cli.ts
542
+ # Then drag & drop the .dxt file into Claude Desktop to install it, in the Settings > Extensions screen.
1026
543
  ```
1027
544
 
1028
- **Fuzzy mode features:**
1029
- - **Zero boilerplate**: No conditional logic needed - just `export default cli` and `cli.parse()`
1030
- - **Automatic prevention**: System automatically prevents CLI execution during fuzzy testing
1031
- - **Dry-run execution**: Prevents handler function execution (no side effects)
1032
- - **Error collection**: Disables error handling to collect all parsing errors
1033
- - **Argument logging**: Shows what each handler would receive for testing visibility
1034
- - **Safe testing**: Test production CLIs with database operations, file modifications, or API calls
545
+ ### Logo Configuration
1035
546
 
1036
- ### **Testing Capabilities**
547
+ The logo will appear in Claude Desktop's Extensions settings and when users interact with your MCP tools. Note that neither ArgParser nor Anthropic packer will modify the logo, so make sure to use a reasonable size, such as 256x256 pixels or 512x512 pixels maximum. Any image type that can display in a browser is supported.
1037
548
 
1038
- The fuzzy tester automatically tests:
1039
-
1040
- - **Valid combinations**: Proper flag usage with correct types and values
1041
- - **Invalid combinations**: Wrong inputs to verify error handling
1042
- - **Random combinations**: Pseudo-random flag combinations for edge cases
1043
- - **Command paths**: All subcommand combinations up to configurable depth
1044
- - **Performance**: Execution timing for different input complexities
1045
-
1046
- ### **Programmatic Usage**
549
+ You can customize the logo/icon that appears in Claude Desktop for your DXT package by configuring the `logo` property in your `serverInfo`:
1047
550
 
1048
551
  ```typescript
1049
- import { ArgParserFuzzyTester } from "@alcyone-labs/arg-parser/fuzzy-tester";
1050
- import { myArgParser } from "./my-cli";
1051
-
1052
- const tester = new ArgParserFuzzyTester(myArgParser, {
1053
- maxDepth: 5,
1054
- randomTestCases: 10,
1055
- includePerformance: true,
1056
- testErrorCases: true,
1057
- verbose: false,
552
+ const cli = ArgParser.withMcp({
553
+ appName: "My CLI",
554
+ appCommandName: "mycli",
555
+ mcp: {
556
+ // This will appear in Claude Desktop's Extensions settings
557
+ serverInfo: {
558
+ name: "my-mcp-server",
559
+ version: "1.0.0",
560
+ description: "My CLI as an MCP server",
561
+ logo: "./assets/my-logo.png", // Local file path
562
+ },
563
+ },
1058
564
  });
1059
-
1060
- const report = await tester.runFuzzyTest();
1061
- console.log(`Success rate: ${(report.successfulTests / report.totalTests * 100).toFixed(1)}%`);
1062
565
  ```
1063
566
 
1064
- ### **Output Formats**
1065
-
1066
- Generate reports in multiple formats:
567
+ If no custom logo is provided or loading fails, a default ArgParser logo is included
1067
568
 
1068
- ```bash
1069
- # Human-readable console output
1070
- bun src/fuzzy-test-cli.ts --file my-cli.ts --format text
569
+ #### Supported Logo Sources
1071
570
 
1072
- # Machine-readable JSON
1073
- bun src/fuzzy-test-cli.ts --file my-cli.ts --format json --output results.json
571
+ **Local File Path:**
1074
572
 
1075
- # Documentation-friendly Markdown
1076
- bun src/fuzzy-test-cli.ts --file my-cli.ts --format markdown --output report.md
573
+ ```typescript
574
+ logo: "./assets/my-logo.png"; // Relative to your project
575
+ logo: "/absolute/path/to/logo.jpg"; // Absolute path
1077
576
  ```
1078
577
 
1079
- For complete documentation, examples, and advanced usage patterns, see the [Fuzzy Testing Documentation](docs/fuzzy-testing.md).
1080
-
1081
- ## API Reference
1082
-
1083
- This section provides a quick overview of the main components. See the sections above for detailed explanations and examples.
578
+ **HTTP/HTTPS URL:**
1084
579
 
1085
- ### **Core Classes**
1086
-
1087
- #### `ArgParserBase`
1088
-
1089
- Base class providing core CLI parsing functionality without MCP features. Use this for lightweight CLIs that don't need MCP server capabilities.
1090
-
1091
- **Constructor:**
1092
- - `new ArgParserBase(options?, initialFlags?)`: Create basic parser instance
1093
-
1094
- #### `ArgParser` (v1.1.0+)
1095
-
1096
- Main class with built-in MCP server capabilities. Extends `ArgParserBase` with MCP integration.
1097
-
1098
- **Constructors:**
1099
- - `new ArgParser(options?, initialFlags?)`: Create parser with MCP capabilities
1100
- - `ArgParser.withMcp(options?, initialFlags?)`: Factory method for MCP-enabled parser (same as constructor)
1101
- - `ArgParser.fromArgParser(parser)`: Convert existing ArgParserBase to MCP-enabled
1102
-
1103
- **MCP Methods:**
1104
- - `toMcpTools(options?)`: Generate MCP tool structures from CLI definition
1105
- - `createMcpServer(serverInfo, toolOptions?)`: Create MCP server instance
1106
- - `startMcpServer(serverInfo, toolOptions?)`: Start MCP server with stdio transport
1107
- - `startMcpServerWithTransport(serverInfo, transportType, transportOptions?, toolOptions?)`: Start with specific transport
1108
- - `startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions?)`: Start with multiple transports (manual approach)
1109
- - `addMcpSubCommand(name, serverInfo, options?)`: Add MCP server sub-command with optional preset transports (recommended approach)
1110
- - `parse(args, options?)`: Async version supporting async handlers
1111
-
1112
- **MCP Types:**
1113
- - `McpTransportConfig`: Configuration for a single transport (`{ type, port?, host?, path?, sessionIdGenerator? }`)
1114
- - `McpSubCommandOptions`: Options for MCP sub-command (`{ defaultTransport?, defaultTransports?, toolOptions? }`)
1115
-
1116
- **Transport Types:**
1117
- - `"stdio"`: Standard input/output
1118
- - `"sse"`: Server-Sent Events over HTTP
1119
- - `"streamable-http"`: HTTP with streaming support
1120
-
1121
- **Example:**
1122
580
  ```typescript
1123
- const cli = ArgParser.withMcp({
1124
- appName: "My CLI",
1125
- handler: async (ctx) => ({ result: ctx.args }),
1126
- })
1127
- .addFlags([/* flags */])
1128
- .addMcpSubCommand("serve", {
1129
- name: "my-mcp-server",
1130
- version: "1.0.0",
1131
- });
1132
-
1133
- // Elegant approach: Configure default transports in addMcpSubCommand
1134
- const cli = ArgParser.withMcp({
1135
- appName: "My Tool",
1136
- handler: async (ctx) => ({ result: ctx.args }),
1137
- })
1138
- .addFlags([/* your flags */])
1139
- .addMcpSubCommand("serve", {
1140
- name: "my-server",
1141
- version: "1.0.0",
1142
- }, {
1143
- // Default multiple transports - used when no CLI flags provided
1144
- defaultTransports: [
1145
- { type: "stdio" },
1146
- { type: "sse", port: 3001 },
1147
- { type: "streamable-http", port: 3002 }
1148
- ]
1149
- });
1150
-
1151
- // Usage: my-tool serve (uses all default transports)
1152
- // Usage: my-tool serve --transports '[{"type":"sse","port":4000}]' (overrides defaults)
581
+ logo: "https://example.com/logo.png"; // Downloaded automatically
582
+ logo: "https://cdn.example.com/icon.svg";
1153
583
  ```
1154
584
 
1155
- ### Constructors
1156
-
1157
- #### `new ArgParserBase(options?, initialFlags?)`
1158
-
1159
- Constructor for creating a basic parser instance without MCP capabilities.
1160
-
1161
- #### `new ArgParser(options?, initialFlags?)`
1162
-
1163
- Constructor for creating a parser instance with MCP capabilities.
1164
-
1165
- - `options`: An object (`IArgParserParams`) configuring the parser.
1166
- - `appName?: string`: Display name.
1167
- - `appCommandName?: string`: Command name for help/errors.
1168
- - `description?: string`: Parser description.
1169
- - `handler?: (ctx: HandlerContext) => void`: Handler function for this parser.
1170
- - `subCommands?: ISubCommand[]`: Array of sub-command definitions.
1171
- - `handleErrors?: boolean`: Enable/disable default error handling (default: `true`).
1172
- - `throwForDuplicateFlags?: boolean`: Throw error for duplicate flags (default: `false`).
1173
- - `inheritParentFlags?: boolean`: Enable flag inheritance when this parser is a sub-command (default: `false`).
1174
- - `initialFlags`: Optional array of `IFlag` objects to add during initialization.
1175
-
1176
- ### `parse(args, options?)`
1177
-
1178
- Parses an array of command-line arguments.
1179
-
1180
- - `args`: `string[]` - Array of arguments (usually `process.argv.slice(2)`).
1181
- - `options`: Optional object (`IParseOptions`).
1182
- - `skipHelpHandling?: boolean`: Prevents automatic help display/exit on `--help` (default: `false`).
1183
- - `skipHandlers?: boolean`: Prevents execution of any matched command handlers (default: `false`).
1184
- - Returns: `TParsedArgs & { $commandChain?: string[] }` - An object containing the parsed arguments and optionally the `$commandChain`. Throws `ArgParserError` if `handleErrors` is `false`.
1185
-
1186
- ### `.addFlag(flag)`
1187
-
1188
- Adds a single flag definition.
1189
-
1190
- - `flag`: `IFlag` - The flag object.
1191
- - Returns: `this` for chaining.
1192
-
1193
- ### `.addFlags(flags)`
1194
-
1195
- Adds multiple flag definitions.
1196
-
1197
- - `flags`: `IFlag[]` - Array of flag objects.
1198
- - Returns: `this` for chaining.
1199
-
1200
- ### `.addSubCommand(subCommand)`
1201
-
1202
- Adds a sub-command definition.
585
+ ### How DXT Generation Works
1203
586
 
1204
- - `subCommand`: `ISubCommand` - The sub-command object.
1205
- - Returns: `this` for chaining.
587
+ When you run `--s-build-dxt`, ArgParser performs several steps to create a self-contained, autonomous package:
1206
588
 
1207
- ### `.setHandler(handler)`
589
+ 1. **Introspection**: It analyzes all tools defined with `.addTool()`.
590
+ 2. **Manifest Generation**: It creates a `manifest.json` file.
591
+ - Tool flags are converted into a JSON Schema for the `input_schema`.
592
+ - Flags with an `env` property (e.g., `{ name: 'apiKey', env: 'API_KEY' }`) are automatically added to the `user_config` section, prompting the user for the value upon installation and making it available as an environment variable to your tool.
593
+ 3. **Autonomous Build**: It bundles your CLI's source code and its dependencies into a single entry point (e.g., `server.js`) that can run without `node_modules`. This ensures the DXT is portable and reliable.
594
+ 4. **Packaging**: It assembles all necessary files (manifest, server bundle, logo, etc.) into the specified output directory, ready to be used by Claude Desktop or packed with `npx @anthropic-ai/dxt`.
1208
595
 
1209
- Sets or overrides the handler function for this parser instance.
1210
-
1211
- - `handler`: `(ctx: HandlerContext) => void` - The handler function.
1212
- - Returns: `this` for chaining.
1213
-
1214
- ### `.getSubCommand(name)`
1215
-
1216
- Retrieves a defined sub-command by name.
1217
-
1218
- - `name`: `string` - The name of the sub-command.
1219
- - Returns: `ISubCommand | undefined` - The sub-command definition or `undefined` if not found.
1220
-
1221
- ### `.hasFlag(name)`
1222
-
1223
- Checks if a flag with the given name exists on this parser instance.
1224
-
1225
- - `name`: `string` - The name of the flag.
1226
- - Returns: `boolean`.
1227
-
1228
- ### `helpText()`
1229
-
1230
- Generates the formatted help text for this parser instance.
1231
-
1232
- - Returns: `string` - The generated help text.
1233
-
1234
- ### `printAll(filePath?)`
1235
-
1236
- Recursively prints the parser configuration.
1237
-
1238
- - `filePath`: `string?` - Optional path to write output to file. `.json` extension saves as JSON.
1239
-
1240
- ### Interfaces
1241
-
1242
- - `IFlag`: Defines the structure of a command-line flag.
1243
- - `ISubCommand`: Defines the structure of a sub-command.
1244
- - `HandlerContext`: The object passed to handler functions.
1245
- - `IParseOptions`: Options for the `parse()` method.
1246
- - `IArgParserParams`: Options for the `ArgParser` constructor.
1247
- - `ArgParserError`: Custom error class thrown on parsing failures when `handleErrors` is `false`.
1248
-
1249
- ## Quick Reference
1250
-
1251
- ### **Basic CLI Setup**
1252
- ```typescript
1253
- import { ArgParser } from "@alcyone-labs/arg-parser";
1254
-
1255
- const cli = new ArgParser({
1256
- appName: "My Tool",
1257
- appCommandName: "my-tool",
1258
- handler: async (ctx) => ({ result: ctx.args }),
1259
- })
1260
- .addFlags([
1261
- { name: "input", options: ["--input", "-i"], type: "string", mandatory: true },
1262
- { name: "verbose", options: ["--verbose", "-v"], type: "boolean", flagOnly: true },
1263
- ])
1264
- .addSubCommand({
1265
- name: "process",
1266
- description: "Process data",
1267
- handler: async (ctx) => ({ processed: true }),
1268
- parser: new ArgParser({}, [
1269
- { name: "format", options: ["--format"], type: "string", enum: ["json", "xml"] },
1270
- ]),
1271
- });
1272
- ```
1273
-
1274
- ### **MCP Integration**
1275
- ```typescript
1276
- import { ArgParser } from "@alcyone-labs/arg-parser";
596
+ ---
1277
597
 
1278
- const mcpCli = ArgParser.withMcp({ /* same options */ })
1279
- .addFlags([/* same flags */])
1280
- .addMcpSubCommand("serve", {
1281
- name: "my-mcp-server",
1282
- version: "1.0.0",
1283
- });
598
+ ## System Flags & Configuration
599
+
600
+ ArgParser includes built-in `--s-*` flags for development, debugging, and configuration. They are processed before normal arguments and will cause the program to exit after their task is complete.
601
+
602
+ | Flag | Description |
603
+ | --------------------------- | ---------------------------------------------------------------------------------------------- |
604
+ | **MCP & DXT** | |
605
+ | `--s-mcp-serve` | Starts the application in MCP server mode, exposing all tools. |
606
+ | `--s-build-dxt [dir]` | Generates a complete, autonomous DXT package for Claude Desktop. |
607
+ | `--s-mcp-transport <type>` | Overrides the MCP transport (`stdio`, `sse`, `streamable-http`). |
608
+ | `--s-mcp-transports <json>` | Overrides transports with a JSON array for multi-transport setups. |
609
+ | `--s-mcp-port <number>` | Sets the port for HTTP-based transports (`sse`, `streamable-http`). |
610
+ | `--s-mcp-host <string>` | Sets the host address for HTTP-based transports. |
611
+ | **Configuration** | |
612
+ | `--s-with-env <file>` | Loads configuration from a file (`.env`, `.json`, `.yaml`, `.toml`). CLI args take precedence. |
613
+ | `--s-save-to-env <file>` | Saves the current arguments to a configuration file, perfect for templates. |
614
+ | **Debugging** | |
615
+ | `--s-debug` | Prints a detailed, step-by-step log of the argument parsing process. |
616
+ | `--s-debug-print` | Exports the entire parser configuration to a JSON file for inspection. |
617
+ | `--s-enable-fuzzy` | Enables fuzzy testing mode—a dry run that parses args but skips handler execution. |
1284
618
 
1285
- // CLI: my-tool --input data.txt process --format json
1286
- // MCP: my-tool serve --transport sse --port 3001
1287
- ```
619
+ ---
1288
620
 
1289
- ### **MCP Preset Transport Configuration**
1290
- Configure default transports that will be used when no CLI transport flags are provided:
621
+ ## Changelog
1291
622
 
1292
- ```typescript
1293
- import { ArgParser, McpTransportConfig } from "@alcyone-labs/arg-parser";
623
+ ### v2.0.0
1294
624
 
1295
- // Single preset transport
1296
- const cliWithPreset = ArgParser.withMcp({
1297
- appName: "My Tool",
1298
- handler: async (ctx) => ({ result: ctx.args }),
1299
- })
1300
- .addMcpSubCommand("serve", {
1301
- name: "my-server",
1302
- version: "1.0.0",
1303
- }, {
1304
- defaultTransport: {
1305
- type: "sse",
1306
- port: 3001,
1307
- host: "0.0.0.0"
1308
- }
1309
- });
625
+ - **Unified Tool Architecture**: Introduced `.addTool()` to define CLI subcommands and MCP tools in a single declaration.
626
+ - **Environment Variables Support**: The `env` property on any IFlag now automatically pull value from the `process.env[${ENV}]` key and generates `user_config` entries in the DXT manifest and fills the flag value to the ENV value if found (process.env).
627
+ - **Enhanced DXT Generation**: The `env` property on flags now automatically generates `user_config` entries in the DXT manifest.
628
+ - **Automatic Console Safety**: Console output is automatically and safely redirected in MCP mode to prevent protocol contamination.
629
+ - **Breaking Changes**: The `addMcpSubCommand()` and separate `addSubCommand()` for MCP tools are deprecated in favor of `addTool()` and `--s-mcp-serve`.
1310
630
 
1311
- // Multiple preset transports
1312
- const cliWithMultiplePresets = ArgParser.withMcp({
1313
- appName: "Multi-Transport Tool",
1314
- handler: async (ctx) => ({ result: ctx.args }),
1315
- })
1316
- .addMcpSubCommand("serve", {
1317
- name: "multi-server",
1318
- version: "1.0.0",
1319
- }, {
1320
- defaultTransports: [
1321
- { type: "stdio" },
1322
- { type: "sse", port: 3001 },
1323
- { type: "streamable-http", port: 3002, path: "/api/mcp" }
1324
- ],
1325
- toolOptions: {
1326
- includeSubCommands: true
1327
- }
1328
- });
631
+ ### v1.3.0
1329
632
 
1330
- // CLI flags always take precedence over presets
1331
- // my-tool serve -> Uses preset transports
1332
- // my-tool serve --transport sse -> Overrides preset with CLI flags
1333
- ```
633
+ - **Plugin System & Architecture**: Refactored to a dependency-injection model, making the core library dependency-free. Optional plugins for TOML/YAML.
634
+ - **Global Console Replacement**: Implemented the first version of automatic console suppression for MCP compliance.
635
+ - **Autonomous Build Improvements**: Significantly reduced DXT bundle size and removed dynamic `require` issues.
1334
636
 
1335
- ### **System Flags**
1336
- ```bash
1337
- # Debug parsing
1338
- my-tool --s-debug --input data.txt process
637
+ ### v1.2.0
1339
638
 
1340
- # Load configuration
1341
- my-tool --s-with-env config.yaml --input override.txt
639
+ - **Critical MCP Fixes**: Resolved issues where MCP tools with output schemas would fail. Ensured correct JSON-RPC 2.0 response formatting.
640
+ - **Enhanced Handler Context**: Added `isMcp` flag to the handler context for more reliable mode detection.
1342
641
 
1343
- # Save configuration
1344
- my-tool --input data.txt --s-save-to-env template.yaml
1345
- ```
642
+ ### v1.1.0
1346
643
 
1347
- ### **Multiple MCP Transports**
1348
- ```bash
1349
- # Single transport
1350
- my-tool serve --transport sse --port 3001
1351
-
1352
- # Multiple transports
1353
- my-tool serve --transports '[
1354
- {"type":"stdio"},
1355
- {"type":"sse","port":3001},
1356
- {"type":"streamable-http","port":3002}
1357
- ]'
1358
- ```
644
+ - **Major Features**: First release with MCP Integration, System Flags (`--s-debug`, `--s-with-env`, etc.), and environment loading from files.
1359
645
 
1360
646
  ---
1361
647
 
1362
- **📖 For complete examples and tutorials, see the [`examples/`](./examples/) directory.**
1363
-
1364
- ---
1365
-
1366
648
  ## Backlog
1367
649
 
1368
650
  - [x] Publish as an open-source library
1369
651
  - [x] Make ArgParser compatible with MCP out-of-the-box
1370
- - [x] Rename --LIB-* flags to --s-*
652
+ - [x] Rename --LIB-\* flags to --s-\*
1371
653
  - [x] Make it possible to pass a `--s-save-to-env /path/to/file` parameter that saves all the parameters to a file (works with Bash-style .env, JSON, YAML, TOML)
1372
654
  - [x] Make it possible to pass a `--s-with-env /path/to/file` parameter that loads all the parameters from a file (works with Bash-style .env, JSON, YAML, TOML)
1373
655
  - [ ] Add System flags to args.systemArgs
@@ -1380,4 +662,3 @@ my-tool serve --transports '[
1380
662
  ### (known) Bugs / DX improvement points
1381
663
 
1382
664
  - [ ] When a flag with `flagOnly: false` is going to consume a value that appears like a valid flag from the set, raise the appropriate warning
1383
- - [ ] When a flag with `allowMultiple: false` and `flagOnly: true` is passed multiple times (regardless of the options, for example "-1" and later "--one", both being valid), raise the correct error