@alcyone-labs/arg-parser 1.0.0 → 1.2.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.
package/README.md CHANGED
@@ -2,37 +2,122 @@
2
2
 
3
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.
4
4
 
5
- Whether you're building a simple script or a complex nested CLI application, ArgParser provides the tools to create robust and user-friendly interfaces.
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.
6
6
 
7
- ## TODOs
7
+ ## What's New in v1.2.0
8
8
 
9
- ### Features
9
+ ### **Critical MCP Fixes & Improvements**
10
10
 
11
- - [] Publish as an open-source library
12
- - [] Upgrade to Zod/V4
13
- - [] Add support for locales / translations
14
- - [] (potentially) support for async type function to enable more flexibility (but at the cost of a potentially much larger issue surface)
15
- - [] (potentially) add support for fully typed parsed output, this has proven very challenging
11
+ - **Fixed MCP Output Schema Support**: Resolved the critical issue where MCP tools with output schemas failed with `"Tool has an output schema but no structured content was provided"` error
12
+ - **Enhanced Handler Context**: Added `isMcp` flag to handler context, enabling proper MCP mode detection in handlers
13
+ - **Improved Response Format**: MCP tools now correctly return both `content` and `structuredContent` fields as required by the JSON-RPC 2.0 specification
14
+ - **Better Integration**: Handlers can now reliably detect when they're being called from MCP mode vs CLI mode
16
15
 
17
- ### (known) Bugs / DX improvement points
16
+ ### **What Was Fixed**
17
+
18
+ **Before v1.2.0**: MCP servers would fail when tools had output schemas defined:
19
+ ```
20
+ MCP error -32602: Tool canny-search has an output schema but no structured content was provided
21
+ ```
18
22
 
19
- - [] 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
20
- - [] 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
23
+ **After v1.2.0**: MCP tools with output schemas work correctly, returning proper JSON-RPC 2.0 responses:
24
+ ```json
25
+ {
26
+ "jsonrpc": "2.0",
27
+ "id": 3,
28
+ "result": {
29
+ "content": [{"type": "text", "text": "..."}],
30
+ "structuredContent": { /* validated against output schema */ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ ### **Handler Context Enhancement**
36
+
37
+ Handlers now receive an `isMcp` flag to detect execution context:
38
+
39
+ ```typescript
40
+ const cli = ArgParser.withMcp({
41
+ handler: async (ctx) => {
42
+ if (ctx.isMcp) {
43
+ // Running in MCP mode - return structured data
44
+ return { success: true, data: processedData };
45
+ } else {
46
+ // Running in CLI mode - can use console output
47
+ console.log("Processing complete!");
48
+ return processedData;
49
+ }
50
+ }
51
+ });
52
+ ```
53
+
54
+ ## What's New in v1.1.0
55
+
56
+ ### **Major Features**
57
+
58
+ - **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.
59
+ - **System Flags**: Built-in `--s-debug-print`, `--s-with-env`, `--s-save-to-env`, `--s-enable-fuzzy`, and `--s-save-DXT` for enhanced debugging, configuration, testing, and MCP distribution
60
+ - **Environment Loading**: Load configuration from `.env`, `.yaml`, `.json`, and `.toml` files
61
+ - **Enhanced Debugging**: Comprehensive runtime debugging and configuration export tools
62
+
63
+ ### **Quick Start with MCP**
64
+
65
+ ```typescript
66
+ import { ArgParser } from "@alcyone-labs/arg-parser";
67
+
68
+ const cli = ArgParser.withMcp({
69
+ appName: "My CLI Tool",
70
+ appCommandName: "my-tool",
71
+ description: "A powerful CLI that can also run as an MCP server",
72
+ handler: async (ctx) => ({ result: "success", args: ctx.args }),
73
+ })
74
+ .addFlags([
75
+ { name: "input", options: ["--input", "-i"], type: "string", mandatory: true },
76
+ { name: "verbose", options: ["--verbose", "-v"], type: "boolean", flagOnly: true },
77
+ ])
78
+ .addMcpSubCommand("serve", {
79
+ name: "my-mcp-server",
80
+ version: "1.1.0",
81
+ description: "Expose this CLI as an MCP server",
82
+ }, {
83
+ // Optional: Configure default transports (CLI flags take precedence)
84
+ defaultTransports: [
85
+ { type: "stdio" },
86
+ { type: "sse", port: 3001, host: "0.0.0.0" }
87
+ ]
88
+ });
89
+
90
+ // Use as CLI: my-tool --input data.txt --verbose
91
+ // Use as MCP server with defaults: my-tool serve
92
+ // Use as MCP server with CLI override: my-tool serve --transport sse --port 3002
93
+ // Use with multiple transports: my-tool serve --transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
94
+ ```
21
95
 
22
96
  ## Features
23
97
 
24
- - **Type Safety:** Define expected argument types (string, number, boolean, array, custom functions) and get type-safe parsed results.
25
- - **Optionally Complex Dynamic Types** Provide a method to trigger arbitrary logic when a flag is encountered and return the output to the parsed flag.
26
- - **Declarative API:** Configure your CLI structure, flags, and sub-commands using a clear, declarative syntax.
27
- - **Automatic Help Generation:** Generate comprehensive and contextual help text based on your parser configuration.
28
- - **Hierarchical Commands:** Easily define nested sub-commands to create complex command structures (e.g., `git commit`, `docker container ls`).
29
- - **Handler Execution:** Associate handler functions with commands and have them executed automatically upon successful parsing (or manually control execution).
30
- - **Validation:** Define custom validation rules for flag values.
31
- - **Conditional Requirements:** Make flags mandatory based on the presence or values of other arguments.
32
- - **Default Values:** Specify default values for flags if they are not provided on the command line.
33
- - **Flag Inheritance:** Share common flags between parent and child commands with an intuitive inheritance mechanism.
34
- - **Error Handling:** Built-in, user-friendly error reporting for common parsing issues, with an option to handle errors manually.
35
- - **Debugging Tools:** Easily inspect your parser's configuration for complex setups.
98
+ ### **Core CLI Features**
99
+ - **Type Safety:** Define expected argument types (string, number, boolean, array, custom functions) and get type-safe parsed results
100
+ - **Declarative API:** Configure your CLI structure, flags, and sub-commands using a clear, declarative syntax
101
+ - **Automatic Help Generation:** Generate comprehensive and contextual help text based on your parser configuration
102
+ - **Hierarchical Commands:** Easily define nested sub-commands to create complex command structures (e.g., `git commit`, `docker container ls`)
103
+ - **Handler Execution:** Associate handler functions with commands and have them executed automatically upon successful parsing
104
+ - **Validation:** Define custom validation rules for flag values with enum support and custom validators
105
+ - **Conditional Requirements:** Make flags mandatory based on the presence or values of other arguments
106
+ - **Default Values:** Specify default values for flags if they are not provided on the command line
107
+ - **Flag Inheritance:** Share common flags between parent and child commands with an intuitive inheritance mechanism
108
+ - **Error Handling:** Built-in, user-friendly error reporting for common parsing issues, with an option to handle errors manually
109
+
110
+ ### **MCP Integration (v1.1.0+)**
111
+ - **Automatic MCP Server Creation:** Transform any CLI into an MCP server with a single method call
112
+ - **Multiple Transport Support:** Run stdio, SSE, and HTTP transports simultaneously on different ports
113
+ - **Type-Safe Tool Generation:** Automatically generate MCP tools with Zod schema validation from CLI definitions
114
+ - **Flexible Configuration:** Support for single transport or complex multi-transport JSON configurations
115
+
116
+ ### **System & Configuration Features (v1.1.0+)**
117
+ - **Environment Loading:** Load configuration from `.env`, `.yaml`, `.json`, and `.toml` files with `--s-with-env`
118
+ - **Configuration Export:** Save current configuration to various formats with `--s-save-to-env`
119
+ - **Advanced Debugging:** Runtime debugging with `--s-debug` and configuration inspection with `--s-debug-print`
120
+ - **CLI Precedence:** Command line arguments always override file configuration
36
121
 
37
122
  ## Installation
38
123
 
@@ -50,8 +135,89 @@ bun add @alcyone-labs/arg-parser
50
135
  deno install npm:@alcyone-labs/arg-parser
51
136
  ```
52
137
 
138
+ ### **For MCP Integration (Optional)**
139
+
140
+ If you plan to use MCP server features, install the additional dependencies:
141
+
142
+ ```bash
143
+ pnpm add @modelcontextprotocol/sdk express
144
+ # or
145
+ npm install @modelcontextprotocol/sdk express
146
+ ```
147
+
148
+ **Note:** MCP dependencies are optional and only required if you use `ArgParser` with MCP features or MCP-related functionality.
149
+
150
+ ## Runtime Compatibility
151
+
152
+ ArgParser is fully compatible with multiple JavaScript runtimes:
153
+
154
+ ### **BunJS**
155
+ ```bash
156
+ # Run TypeScript directly
157
+ bun your-cli.ts --flag value
158
+
159
+ # Or compile and run
160
+ bun build your-cli.ts --outdir ./dist
161
+ bun ./dist/your-cli.js --flag value
162
+ ```
163
+
164
+ ### **Node.js**
165
+ ```bash
166
+ # Using tsx for TypeScript
167
+ npx tsx your-cli.ts --flag value
168
+
169
+ # Using ts-node
170
+ npx ts-node your-cli.ts --flag value
171
+
172
+ # Or compile and run
173
+ npx tsc your-cli.ts
174
+ node your-cli.js --flag value
175
+ ```
176
+
177
+ ### **Deno**
178
+ ```bash
179
+ # Run with required permissions
180
+ deno run --unstable-sloppy-imports --allow-read --allow-write --allow-env your-cli.ts --flag value
181
+
182
+ # Or use the provided deno.json configuration for easier task management
183
+ deno task example:simple-cli --env production --port 8080
184
+ ```
185
+
186
+ ### **Using the Library in Your Projects**
187
+
188
+ Install the library and use it in your projects:
189
+
190
+ ```bash
191
+ # Install the library
192
+ pnpm add @alcyone-labs/arg-parser
193
+
194
+ # Use in your project
195
+ import { ArgParser } from '@alcyone-labs/arg-parser';
196
+ // or
197
+ const { ArgParser } = require('@alcyone-labs/arg-parser');
198
+ ```
199
+
200
+ ### **Running Examples**
201
+
202
+ Examples are provided as TypeScript source files for educational purposes. Run them directly with your preferred runtime:
203
+
204
+ ```bash
205
+ # BunJS (recommended)
206
+ bun examples/simple-cli.ts --env production --port 8080
207
+
208
+ # Node.js with tsx
209
+ npx tsx examples/simple-cli.ts --env production --port 8080
210
+
211
+ # Deno (use predefined tasks)
212
+ deno task example:simple-cli --env production --port 8080
213
+ ```
214
+
215
+ All examples work seamlessly across all three runtimes, ensuring maximum compatibility for your CLI applications.
216
+
53
217
  ## Basic Usage
54
218
 
219
+ ### **Standard CLI Usage**
220
+
55
221
  Here's a simple example demonstrating how to define flags and parse arguments:
56
222
 
57
223
  ```typescript
@@ -61,13 +227,15 @@ const parser = new ArgParser({
61
227
  appName: "Data Processor",
62
228
  appCommandName: "data-proc", // Used in help text and error messages
63
229
  description: "A tool for processing data phases",
64
- // By default, if a handler is set, it will be executed after successful parsing.
65
- // Set handler: () => { ... } here for a root command handler.
230
+ handler: async (ctx) => {
231
+ console.log("Processing data with phase:", ctx.args.phase);
232
+ return { success: true, phase: ctx.args.phase };
233
+ },
66
234
  }).addFlags([
67
235
  {
68
236
  name: "phase",
69
237
  options: ["--phase"],
70
- type: String, // Use native types or typeof string equivalents ("string", "number", "boolean", etc.)
238
+ type: "string", // Use "string", "number", "boolean", or native types
71
239
  mandatory: true,
72
240
  enum: ["chunking", "pairing", "analysis"],
73
241
  description: "Processing phase to execute",
@@ -76,36 +244,133 @@ const parser = new ArgParser({
76
244
  name: "batch",
77
245
  options: ["-b", "--batch-number"],
78
246
  type: "number",
79
- mandatory: (args) => args.phase !== "analysis", // Mandatory based on another flag's value
247
+ mandatory: (args) => args.phase !== "analysis", // Conditional requirement
80
248
  defaultValue: 0,
81
249
  description: "Batch number (required except for analysis phase)",
82
250
  },
83
251
  {
84
252
  name: "verbose",
85
- options: ["-v"],
253
+ options: ["-v", "--verbose"],
86
254
  flagOnly: true, // This flag does not expect a value
87
255
  description: "Enable verbose logging",
88
256
  },
89
257
  ]);
90
258
 
91
- // Parse command line arguments (excluding 'node' and script path)
92
- // If parsing fails (e.g., missing mandatory flag), ArgParser handles the error
93
- // by printing a message and exiting (process.exit(1)) by default.
94
- const args = parser.parse(process.argv.slice(2));
259
+ // Parse and execute
260
+ const result = parser.parse(process.argv.slice(2));
261
+ console.log("Result:", result);
262
+ ```
263
+
264
+ ### **MCP Server Usage (v1.1.0+)**
95
265
 
96
- // If parsing succeeds and no command handler was executed,
97
- // execution continues here with the parsed args.
98
- console.log("Parsing successful! Arguments:", args);
266
+ Transform your CLI into an MCP server with minimal changes:
99
267
 
100
- // Example of using parsed arguments:
101
- if (args.phase === "chunking") {
102
- if (args.verbose) {
103
- console.debug("Starting the chunking phase...");
104
- }
105
- // Perform chunking logic...
106
- }
268
+ ```typescript
269
+ import { ArgParser } from "@alcyone-labs/arg-parser";
270
+
271
+ const cli = ArgParser.withMcp({
272
+ appName: "Data Processor",
273
+ appCommandName: "data-proc",
274
+ description: "A tool for processing data phases (CLI + MCP server)",
275
+ handler: async (ctx) => {
276
+ console.log("Processing data with phase:", ctx.args.phase);
277
+ return { success: true, phase: ctx.args.phase, batch: ctx.args.batch };
278
+ },
279
+ })
280
+ .addFlags([
281
+ {
282
+ name: "phase",
283
+ options: ["--phase"],
284
+ type: "string",
285
+ mandatory: true,
286
+ enum: ["chunking", "pairing", "analysis"],
287
+ description: "Processing phase to execute",
288
+ },
289
+ {
290
+ name: "batch",
291
+ options: ["-b", "--batch-number"],
292
+ type: "number",
293
+ defaultValue: 0,
294
+ description: "Batch number for processing",
295
+ },
296
+ ])
297
+ .addMcpSubCommand("serve", {
298
+ name: "data-processor-mcp",
299
+ version: "1.1.0",
300
+ description: "Data Processor MCP Server",
301
+ });
302
+
303
+ // Use as CLI: data-proc --phase chunking --batch 5
304
+ // Use as MCP server: data-proc serve
305
+ // Use with custom transport: data-proc serve --transport sse --port 3001
306
+ ```
307
+
308
+ ## MCP Integration (v1.1.0+)
309
+
310
+ 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.
311
+
312
+ ### **Quick MCP Setup**
313
+
314
+ 1. **Import the MCP-enabled class:**
315
+ ```typescript
316
+ import { ArgParser } from "@alcyone-labs/arg-parser";
317
+ ```
318
+
319
+ 2. **Create your CLI with MCP support:**
320
+ ```typescript
321
+ const cli = ArgParser.withMcp({
322
+ appName: "My Tool",
323
+ appCommandName: "my-tool",
324
+ handler: async (ctx) => ({ result: "success", args: ctx.args }),
325
+ })
326
+ .addFlags([/* your flags */])
327
+ .addMcpSubCommand("serve", {
328
+ name: "my-mcp-server",
329
+ version: "1.0.0",
330
+ });
331
+ ```
332
+
333
+ 3. **Use as CLI or MCP server:**
334
+ ```bash
335
+ # CLI usage
336
+ my-tool --input data.txt --verbose
337
+
338
+ # MCP server (stdio)
339
+ my-tool serve
340
+
341
+ # MCP server (HTTP)
342
+ my-tool serve --transport sse --port 3001
343
+
344
+ # Multiple transports
345
+ my-tool serve --transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
346
+ ```
347
+
348
+ ### **MCP Transport Options**
349
+
350
+ - **`stdio`** (default): Standard input/output for CLI tools
351
+ - **`sse`**: Server-Sent Events over HTTP for web applications
352
+ - **`streamable-http`**: HTTP with streaming support for advanced integrations
353
+
354
+ ### **Multiple Transports Simultaneously**
355
+
356
+ Run multiple transport types at once for maximum flexibility:
357
+
358
+ ```bash
359
+ my-tool serve --transports '[
360
+ {"type":"stdio"},
361
+ {"type":"sse","port":3001,"path":"/sse"},
362
+ {"type":"streamable-http","port":3002,"path":"/mcp","host":"0.0.0.0"}
363
+ ]'
107
364
  ```
108
365
 
366
+ ### **Automatic Tool Generation**
367
+
368
+ Your CLI flags are automatically converted to MCP tools with:
369
+ - **Type-safe schemas** using Zod validation
370
+ - **Automatic documentation** from flag descriptions
371
+ - **Enum validation** for restricted values
372
+ - **Error handling** with detailed messages
373
+
109
374
  ## Core Concepts
110
375
 
111
376
  ### Defining Flags
@@ -242,6 +507,8 @@ ArgParser excels at building CLIs with nested commands, like `git clone` or `doc
242
507
 
243
508
  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.
244
509
 
510
+ 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.
511
+
245
512
  ```typescript
246
513
  import {
247
514
  ArgParser,
@@ -471,9 +738,243 @@ try {
471
738
  }
472
739
  ```
473
740
 
741
+ ## Environment Configuration Export
742
+
743
+ 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.
744
+
745
+ ### Usage
746
+
747
+ ```bash
748
+ # Export to .env format (default for no extension)
749
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.env
750
+
751
+ # Export to YAML format
752
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.yaml
753
+
754
+ # Export to JSON format
755
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.json
756
+
757
+ # Export to TOML format
758
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.toml
759
+ ```
760
+
761
+ ### Supported Formats
762
+
763
+ The format is automatically detected based on the file extension:
764
+
765
+ - **`.env`** (or no extension): Bash environment variable format
766
+ - **`.yaml` / `.yml`**: YAML format
767
+ - **`.json` / `.jsonc`**: JSON format with metadata
768
+ - **`.toml` / `.tml`**: TOML format
769
+
770
+ ### Behavior
771
+
772
+ - **Works at any parser level**: Can be used with root commands or sub-commands
773
+ - **Includes inherited flags**: Shows flags from the current parser and all parent parsers in the chain
774
+ - **Comments optional flags**: Flags that are optional and not set are commented out but still documented
775
+ - **Preserves values**: Set flags show their actual values, unset flags show default values or are commented out
776
+ - **Rich documentation**: Each flag includes its description, options, type, and constraints
777
+
778
+ ### Example Output
779
+
780
+ For a CLI with flags `--verbose`, `--output file.txt`, and `--count 5`:
781
+
782
+ **`.env` format:**
783
+ ```bash
784
+ # Environment configuration generated by ArgParser
785
+ # Format: Bash .env style
786
+
787
+ # verbose: Enable verbose output
788
+ # Options: -v, --verbose
789
+ # Type: Boolean
790
+ # Default: false
791
+ VERBOSE="true"
792
+
793
+ # output: Output file path
794
+ # Options: -o, --output
795
+ # Type: String
796
+ OUTPUT="file.txt"
797
+
798
+ # count: Number of items to process
799
+ # Options: -c, --count
800
+ # Type: Number
801
+ # Default: 10
802
+ COUNT="5"
803
+ ```
804
+
805
+ **`.yaml` format:**
806
+ ```yaml
807
+ # Environment configuration generated by ArgParser
808
+ # Format: YAML
809
+
810
+ # verbose: Enable verbose output
811
+ # Options: -v, --verbose
812
+ # Type: Boolean
813
+ # Default: false
814
+
815
+ verbose: true
816
+ output: "file.txt"
817
+ count: 5
818
+ ```
819
+
820
+ ## System Flags (v1.1.0+)
821
+
822
+ 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.
823
+
824
+ ### **Overview**
825
+
826
+ System flags use the `--s-*` pattern and provide powerful development and deployment tools:
827
+
828
+ - **`--s-debug`**: Runtime debugging with step-by-step parsing analysis
829
+ - **`--s-with-env <file>`**: Load configuration from files (`.env`, `.yaml`, `.json`, `.toml`)
830
+ - **`--s-save-to-env <file>`**: Export current configuration to various formats
831
+ - **`--s-debug-print`**: Export complete parser configuration for inspection
832
+ - **`--s-enable-fuzzy`**: Enable fuzzy testing mode (dry-run with no side effects)
833
+ - **`--s-save-DXT [dir]`**: Generate DXT packages for MCP servers (Desktop Extensions)
834
+
835
+ ### `--s-save-to-env <file>`
836
+
837
+ Exports the current parser's configuration and parsed arguments to various file formats.
838
+
839
+ ```bash
840
+ # Export to .env format (default for no extension)
841
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.env
842
+
843
+ # Export to YAML format
844
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.yaml
845
+
846
+ # Export to JSON format
847
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.json
848
+
849
+ # Export to TOML format
850
+ your-cli --flag1 value1 --flag2 --s-save-to-env config.toml
851
+ ```
852
+
853
+ **Features:**
854
+ - Works at any parser level (root command or sub-commands)
855
+ - Includes inherited flags from parent parsers in the chain
856
+ - Comments out optional flags that are not set
857
+ - Rich documentation for each flag (description, options, type, constraints)
858
+ - Automatic format detection based on file extension
859
+
860
+ ### `--s-with-env <file>`
861
+
862
+ Loads configuration from a file and merges it with command line arguments. CLI arguments take precedence over file configuration.
863
+
864
+ ```bash
865
+ # Load from .env format (default for no extension)
866
+ your-cli --s-with-env config.env
867
+
868
+ # Load from YAML format
869
+ your-cli --s-with-env config.yaml
870
+
871
+ # Load from JSON format
872
+ your-cli --s-with-env config.json
873
+
874
+ # Load from TOML format
875
+ your-cli --s-with-env config.toml
876
+
877
+ # Combine with CLI arguments (CLI args override file config)
878
+ your-cli --s-with-env config.yaml --verbose --output override.txt
879
+ ```
880
+
881
+ **Supported Formats:**
882
+
883
+ The format is automatically detected based on the file extension:
884
+
885
+ - **`.env`** (or no extension): Dotenv format with `KEY=value` pairs
886
+ - **`.yaml` / `.yml`**: YAML format
887
+ - **`.json` / `.jsonc`**: JSON format (metadata is ignored if present)
888
+ - **`.toml` / `.tml`**: TOML format
889
+
890
+ **Behavior:**
891
+
892
+ - **File validation**: Checks if the file exists and can be parsed
893
+ - **Type conversion**: Automatically converts values to match flag types (boolean, number, string, array)
894
+ - **Enum validation**: Validates values against allowed enum options
895
+ - **CLI precedence**: Command line arguments override file configuration
896
+ - **Error handling**: Exits with error code 1 if file cannot be loaded or parsed
897
+ - **Flag matching**: Only loads values for flags that exist in the current parser chain
898
+
899
+ **Example Configuration Files:**
900
+
901
+ **.env format:**
902
+ ```bash
903
+ VERBOSE=true
904
+ OUTPUT=file.txt
905
+ COUNT=5
906
+ TAGS=tag1,tag2,tag3
907
+ ```
908
+
909
+ **YAML format:**
910
+ ```yaml
911
+ verbose: true
912
+ output: file.txt
913
+ count: 5
914
+ tags:
915
+ - tag1
916
+ - tag2
917
+ - tag3
918
+ ```
919
+
920
+ **JSON format:**
921
+ ```json
922
+ {
923
+ "verbose": true,
924
+ "output": "file.txt",
925
+ "count": 5,
926
+ "tags": ["tag1", "tag2", "tag3"]
927
+ }
928
+ ```
929
+
930
+ ### `--s-debug-print`
931
+
932
+ Prints the complete parser configuration to a JSON file and console for debugging complex parser setups.
933
+
934
+ ```bash
935
+ your-cli --s-debug-print
936
+ ```
937
+
938
+ **Output:**
939
+ - Creates `ArgParser.full.json` with the complete parser structure
940
+ - Shows all flags, sub-commands, handlers, and configuration
941
+ - Useful for debugging complex parser hierarchies
942
+ - Human-readable console output with syntax highlighting
943
+
944
+ ### `--s-debug`
945
+
946
+ Provides detailed runtime debugging information showing how arguments are parsed step-by-step.
947
+
948
+ ```bash
949
+ your-cli --flag1 value1 sub-command --flag2 value2 --s-debug
950
+ ```
951
+
952
+ **Output:**
953
+ - Shows command chain identification process
954
+ - Step-by-step argument parsing simulation
955
+ - Final parser identification
956
+ - Accumulated arguments at each level
957
+ - Remaining arguments after parsing
958
+ - Complete static configuration of the final parser
959
+
960
+ **Useful for:**
961
+ - Understanding complex command chains
962
+ - Debugging argument parsing issues
963
+ - Seeing how flags are inherited between parsers
964
+ - Troubleshooting sub-command resolution
965
+
966
+ ### Usage Notes
967
+
968
+ - System flags are processed before normal argument parsing
969
+ - They cause the program to exit after execution (exit code 0 for success)
970
+ - Can be used with any combination of regular flags and sub-commands
971
+ - Particularly useful during development and debugging
972
+
474
973
  ## Debugging
475
974
 
476
- The `printAll(filePath?: string)` method is useful for debugging complex parser configurations. It recursively outputs the structure, options, flags, and handlers of a parser instance and its sub-commands.
975
+ ### Programmatic Debugging
976
+
977
+ 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.
477
978
 
478
979
  - `parser.printAll()`: Prints a colored, human-readable output to the console.
479
980
  - `parser.printAll('./config.json')`: Writes the configuration as a pretty-printed JSON file.
@@ -491,13 +992,301 @@ const parser = new ArgParser({ appName: "Debug App" })
491
992
  parser.printAll(); // Output to console
492
993
  ```
493
994
 
995
+ ### Runtime Debugging
996
+
997
+ For runtime debugging, use the system flags documented above:
998
+
999
+ - `--s-debug-print`: Export complete parser configuration
1000
+ - `--s-debug`: Show step-by-step argument parsing process
1001
+ - `--s-save-to-env <file>`: Export current configuration to various formats
1002
+ - `--s-with-env <file>`: Load configuration from file and merge with CLI arguments
1003
+
1004
+ ### `--s-enable-fuzzy`
1005
+
1006
+ 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.
1007
+
1008
+ ```bash
1009
+ # Enable fuzzy mode for testing
1010
+ your-cli --s-enable-fuzzy --input test.txt --format json
1011
+ ```
1012
+
1013
+ **Features:**
1014
+ - **Automatic execution prevention**: No need for complex conditional logic in your CLI code
1015
+ - **Zero boilerplate**: Simply export your CLI with `export default cli` and call `cli.parse()`
1016
+ - Disables error handling to allow error collection
1017
+ - Skips mandatory flag validation for comprehensive testing
1018
+ - **Prevents handler function execution** (no side effects)
1019
+ - **Logs what each handler would receive** for testing visibility
1020
+ - Recursively applies to all subcommand parsers
1021
+ - Safe for testing production CLIs with database operations, file modifications, or API calls
1022
+
1023
+ **Example Output:**
1024
+ ```
1025
+ [--s-enable-fuzzy] handler() skipped for command chain: (root)
1026
+ Input args: [--s-enable-fuzzy --input test.txt --format json]
1027
+ Parsed args: {"input":"test.txt","format":"json"}
1028
+ ```
1029
+
1030
+ **Use Cases:**
1031
+ - Fuzzy testing CLI argument parsing
1032
+ - Validating CLI configuration without executing business logic
1033
+ - Testing complex command hierarchies safely
1034
+ - Automated testing of CLI interfaces
1035
+
1036
+ These system flags are particularly useful when you need to debug a CLI application without modifying the source code.
1037
+
1038
+ ## Fuzzy Testing
1039
+
1040
+ 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.
1041
+
1042
+ ### **Quick Start**
1043
+
1044
+ Test any ArgParser configuration using the built-in fuzzy testing CLI:
1045
+
1046
+ ```bash
1047
+ # Test an ArgParser file
1048
+ bun src/fuzzy-test-cli.ts --file examples/getting-started.ts
1049
+
1050
+ # Test with custom options and save results
1051
+ bun src/fuzzy-test-cli.ts \
1052
+ --file examples/getting-started.ts \
1053
+ --output test-results.json \
1054
+ --format json \
1055
+ --max-depth 3 \
1056
+ --random-tests 20 \
1057
+ --verbose
1058
+ ```
1059
+
1060
+ **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.
1061
+
1062
+ ### **System Flag Integration**
1063
+
1064
+ The `--s-enable-fuzzy` system flag makes any CLI fuzzy-test compatible **without any code modifications or boilerplate**:
1065
+
1066
+ ```bash
1067
+ # Enable fuzzy mode for safe testing (dry-run with no side effects)
1068
+ your-cli --s-enable-fuzzy --input test.txt --format json
1069
+
1070
+ # The fuzzy testing CLI automatically uses this flag
1071
+ bun src/fuzzy-test-cli.ts --file your-cli.ts
1072
+ ```
1073
+
1074
+ **Fuzzy mode features:**
1075
+ - **Zero boilerplate**: No conditional logic needed - just `export default cli` and `cli.parse()`
1076
+ - **Automatic prevention**: System automatically prevents CLI execution during fuzzy testing
1077
+ - **Dry-run execution**: Prevents handler function execution (no side effects)
1078
+ - **Error collection**: Disables error handling to collect all parsing errors
1079
+ - **Argument logging**: Shows what each handler would receive for testing visibility
1080
+ - **Safe testing**: Test production CLIs with database operations, file modifications, or API calls
1081
+
1082
+ ### **Testing Capabilities**
1083
+
1084
+ The fuzzy tester automatically tests:
1085
+
1086
+ - **Valid combinations**: Proper flag usage with correct types and values
1087
+ - **Invalid combinations**: Wrong inputs to verify error handling
1088
+ - **Random combinations**: Pseudo-random flag combinations for edge cases
1089
+ - **Command paths**: All subcommand combinations up to configurable depth
1090
+ - **Performance**: Execution timing for different input complexities
1091
+
1092
+ ### **Programmatic Usage**
1093
+
1094
+ ```typescript
1095
+ import { ArgParserFuzzyTester } from "@alcyone-labs/arg-parser/fuzzy-tester";
1096
+ import { myArgParser } from "./my-cli";
1097
+
1098
+ const tester = new ArgParserFuzzyTester(myArgParser, {
1099
+ maxDepth: 5,
1100
+ randomTestCases: 10,
1101
+ includePerformance: true,
1102
+ testErrorCases: true,
1103
+ verbose: false,
1104
+ });
1105
+
1106
+ const report = await tester.runFuzzyTest();
1107
+ console.log(`Success rate: ${(report.successfulTests / report.totalTests * 100).toFixed(1)}%`);
1108
+ ```
1109
+
1110
+ ### **Output Formats**
1111
+
1112
+ Generate reports in multiple formats:
1113
+
1114
+ ```bash
1115
+ # Human-readable console output
1116
+ bun src/fuzzy-test-cli.ts --file my-cli.ts --format text
1117
+
1118
+ # Machine-readable JSON
1119
+ bun src/fuzzy-test-cli.ts --file my-cli.ts --format json --output results.json
1120
+
1121
+ # Documentation-friendly Markdown
1122
+ bun src/fuzzy-test-cli.ts --file my-cli.ts --format markdown --output report.md
1123
+ ```
1124
+
1125
+ For complete documentation, examples, and advanced usage patterns, see the [Fuzzy Testing Documentation](docs/fuzzy-testing.md).
1126
+
1127
+ ### `--s-save-DXT [directory]`
1128
+
1129
+ Generates Desktop Extension (DXT) packages for all MCP servers defined in your ArgParser instance. DXT files are zip archives containing a manifest.json and server files, enabling single-click installation of MCP servers in compatible applications like Claude Desktop.
1130
+
1131
+ ```bash
1132
+ # Generate DXT packages in current directory
1133
+ your-cli --s-save-DXT
1134
+
1135
+ # Generate DXT packages in specific directory
1136
+ your-cli --s-save-DXT ./dxt-packages
1137
+
1138
+ # Example with multiple MCP servers
1139
+ my-tool --s-save-DXT ./extensions
1140
+ ```
1141
+
1142
+ **Features:**
1143
+ - **Automatic detection**: Finds all MCP servers added via `addMcpSubCommand()`
1144
+ - **Multiple servers**: Generates separate DXT files for each MCP server
1145
+ - **Complete tool listing**: Includes all MCP tools in the manifest
1146
+ - **Proper metadata**: Uses actual server names, versions, and descriptions
1147
+ - **Ready to install**: Generated DXT files work with DXT-compatible applications
1148
+
1149
+ **Generated Structure:**
1150
+ ```
1151
+ your-server.dxt (ZIP file)
1152
+ ├── manifest.json # Server metadata and tool definitions
1153
+ └── server/
1154
+ └── index.js # Server entry point
1155
+ ```
1156
+
1157
+ **Example Output:**
1158
+ ```
1159
+ 🔧 Generating DXT packages for 2 MCP server(s)...
1160
+ ✓ Generated: primary-server.dxt
1161
+ Server: primary-server v1.0.0
1162
+ Tools: 3 tool(s)
1163
+ ✓ Generated: analytics-server.dxt
1164
+ Server: analytics-server v2.1.0
1165
+ Tools: 5 tool(s)
1166
+
1167
+ ✅ DXT package generation completed!
1168
+ Output directory: /path/to/dxt-packages
1169
+ ```
1170
+
1171
+ **Use Cases:**
1172
+ - **Distribution**: Package MCP servers for easy sharing and installation
1173
+ - **Development**: Create test packages during MCP server development
1174
+ - **Deployment**: Generate production-ready DXT files for distribution
1175
+ - **Integration**: Prepare MCP servers for Claude Desktop or other DXT-compatible applications
1176
+
1177
+ ## Changelog
1178
+
1179
+ ### v1.2.0 (2025-01-02)
1180
+
1181
+ **🔧 Critical MCP Fixes & Improvements**
1182
+
1183
+ - **Fixed MCP Output Schema Support**: Resolved the critical issue where MCP tools with output schemas failed with `"Tool has an output schema but no structured content was provided"` error
1184
+ - **Enhanced Handler Context**: Added `isMcp` flag to handler context for proper MCP mode detection
1185
+ - **Improved Response Format**: MCP tools now correctly return both `content` and `structuredContent` fields as required by JSON-RPC 2.0
1186
+ - **Better Integration**: Handlers can reliably detect when they're being called from MCP mode vs CLI mode
1187
+
1188
+ **What was broken before v1.2.0:**
1189
+ - MCP servers would fail when tools had output schemas defined
1190
+ - Handlers couldn't reliably detect MCP execution context
1191
+ - Response format didn't comply with MCP specification for structured content
1192
+
1193
+ **What works now:**
1194
+ - ✅ MCP tools with output schemas work correctly
1195
+ - ✅ Proper JSON-RPC 2.0 response format with both `content` and `structuredContent`
1196
+ - ✅ Handler context includes `isMcp` flag for mode detection
1197
+ - ✅ Full compatibility with MCP clients and the Model Context Protocol specification
1198
+
1199
+ ### v1.1.0 (2024-12-XX)
1200
+
1201
+ **Major Features**
1202
+ - MCP (Model Context Protocol) Integration with multiple transport support
1203
+ - System Flags: `--s-debug-print`, `--s-with-env`, `--s-save-to-env`, `--s-enable-fuzzy`, `--s-save-DXT`
1204
+ - Environment Loading from `.env`, `.yaml`, `.json`, and `.toml` files
1205
+ - Enhanced Debugging and configuration export tools
1206
+
494
1207
  ## API Reference
495
1208
 
496
1209
  This section provides a quick overview of the main components. See the sections above for detailed explanations and examples.
497
1210
 
498
- ### `new ArgParser(options?, initialFlags?)`
1211
+ ### **Core Classes**
1212
+
1213
+ #### `ArgParserBase`
1214
+
1215
+ Base class providing core CLI parsing functionality without MCP features. Use this for lightweight CLIs that don't need MCP server capabilities.
1216
+
1217
+ **Constructor:**
1218
+ - `new ArgParserBase(options?, initialFlags?)`: Create basic parser instance
1219
+
1220
+ #### `ArgParser` (v1.1.0+)
1221
+
1222
+ Main class with built-in MCP server capabilities. Extends `ArgParserBase` with MCP integration.
1223
+
1224
+ **Constructors:**
1225
+ - `new ArgParser(options?, initialFlags?)`: Create parser with MCP capabilities
1226
+ - `ArgParser.withMcp(options?, initialFlags?)`: Factory method for MCP-enabled parser (same as constructor)
1227
+ - `ArgParser.fromArgParser(parser)`: Convert existing ArgParserBase to MCP-enabled
1228
+
1229
+ **MCP Methods:**
1230
+ - `toMcpTools(options?)`: Generate MCP tool structures from CLI definition
1231
+ - `createMcpServer(serverInfo, toolOptions?)`: Create MCP server instance
1232
+ - `startMcpServer(serverInfo, toolOptions?)`: Start MCP server with stdio transport
1233
+ - `startMcpServerWithTransport(serverInfo, transportType, transportOptions?, toolOptions?)`: Start with specific transport
1234
+ - `startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions?)`: Start with multiple transports (manual approach)
1235
+ - `addMcpSubCommand(name, serverInfo, options?)`: Add MCP server sub-command with optional preset transports (recommended approach)
1236
+ - `parse(args, options?)`: Async version supporting async handlers
1237
+
1238
+ **MCP Types:**
1239
+ - `McpTransportConfig`: Configuration for a single transport (`{ type, port?, host?, path?, sessionIdGenerator? }`)
1240
+ - `McpSubCommandOptions`: Options for MCP sub-command (`{ defaultTransport?, defaultTransports?, toolOptions? }`)
1241
+
1242
+ **Transport Types:**
1243
+ - `"stdio"`: Standard input/output
1244
+ - `"sse"`: Server-Sent Events over HTTP
1245
+ - `"streamable-http"`: HTTP with streaming support
499
1246
 
500
- Constructor for creating a parser instance.
1247
+ **Example:**
1248
+ ```typescript
1249
+ const cli = ArgParser.withMcp({
1250
+ appName: "My CLI",
1251
+ handler: async (ctx) => ({ result: ctx.args }),
1252
+ })
1253
+ .addFlags([/* flags */])
1254
+ .addMcpSubCommand("serve", {
1255
+ name: "my-mcp-server",
1256
+ version: "1.0.0",
1257
+ });
1258
+
1259
+ // Elegant approach: Configure default transports in addMcpSubCommand
1260
+ const cli = ArgParser.withMcp({
1261
+ appName: "My Tool",
1262
+ handler: async (ctx) => ({ result: ctx.args }),
1263
+ })
1264
+ .addFlags([/* your flags */])
1265
+ .addMcpSubCommand("serve", {
1266
+ name: "my-server",
1267
+ version: "1.0.0",
1268
+ }, {
1269
+ // Default multiple transports - used when no CLI flags provided
1270
+ defaultTransports: [
1271
+ { type: "stdio" },
1272
+ { type: "sse", port: 3001 },
1273
+ { type: "streamable-http", port: 3002 }
1274
+ ]
1275
+ });
1276
+
1277
+ // Usage: my-tool serve (uses all default transports)
1278
+ // Usage: my-tool serve --transports '[{"type":"sse","port":4000}]' (overrides defaults)
1279
+ ```
1280
+
1281
+ ### Constructors
1282
+
1283
+ #### `new ArgParserBase(options?, initialFlags?)`
1284
+
1285
+ Constructor for creating a basic parser instance without MCP capabilities.
1286
+
1287
+ #### `new ArgParser(options?, initialFlags?)`
1288
+
1289
+ Constructor for creating a parser instance with MCP capabilities.
501
1290
 
502
1291
  - `options`: An object (`IArgParserParams`) configuring the parser.
503
1292
  - `appName?: string`: Display name.
@@ -582,3 +1371,139 @@ Recursively prints the parser configuration.
582
1371
  - `IParseOptions`: Options for the `parse()` method.
583
1372
  - `IArgParserParams`: Options for the `ArgParser` constructor.
584
1373
  - `ArgParserError`: Custom error class thrown on parsing failures when `handleErrors` is `false`.
1374
+
1375
+ ## Quick Reference
1376
+
1377
+ ### **Basic CLI Setup**
1378
+ ```typescript
1379
+ import { ArgParser } from "@alcyone-labs/arg-parser";
1380
+
1381
+ const cli = new ArgParser({
1382
+ appName: "My Tool",
1383
+ appCommandName: "my-tool",
1384
+ handler: async (ctx) => ({ result: ctx.args }),
1385
+ })
1386
+ .addFlags([
1387
+ { name: "input", options: ["--input", "-i"], type: "string", mandatory: true },
1388
+ { name: "verbose", options: ["--verbose", "-v"], type: "boolean", flagOnly: true },
1389
+ ])
1390
+ .addSubCommand({
1391
+ name: "process",
1392
+ description: "Process data",
1393
+ handler: async (ctx) => ({ processed: true }),
1394
+ parser: new ArgParser({}, [
1395
+ { name: "format", options: ["--format"], type: "string", enum: ["json", "xml"] },
1396
+ ]),
1397
+ });
1398
+ ```
1399
+
1400
+ ### **MCP Integration**
1401
+ ```typescript
1402
+ import { ArgParser } from "@alcyone-labs/arg-parser";
1403
+
1404
+ const mcpCli = ArgParser.withMcp({ /* same options */ })
1405
+ .addFlags([/* same flags */])
1406
+ .addMcpSubCommand("serve", {
1407
+ name: "my-mcp-server",
1408
+ version: "1.0.0",
1409
+ });
1410
+
1411
+ // CLI: my-tool --input data.txt process --format json
1412
+ // MCP: my-tool serve --transport sse --port 3001
1413
+ ```
1414
+
1415
+ ### **MCP Preset Transport Configuration**
1416
+ Configure default transports that will be used when no CLI transport flags are provided:
1417
+
1418
+ ```typescript
1419
+ import { ArgParser, McpTransportConfig } from "@alcyone-labs/arg-parser";
1420
+
1421
+ // Single preset transport
1422
+ const cliWithPreset = ArgParser.withMcp({
1423
+ appName: "My Tool",
1424
+ handler: async (ctx) => ({ result: ctx.args }),
1425
+ })
1426
+ .addMcpSubCommand("serve", {
1427
+ name: "my-server",
1428
+ version: "1.0.0",
1429
+ }, {
1430
+ defaultTransport: {
1431
+ type: "sse",
1432
+ port: 3001,
1433
+ host: "0.0.0.0"
1434
+ }
1435
+ });
1436
+
1437
+ // Multiple preset transports
1438
+ const cliWithMultiplePresets = ArgParser.withMcp({
1439
+ appName: "Multi-Transport Tool",
1440
+ handler: async (ctx) => ({ result: ctx.args }),
1441
+ })
1442
+ .addMcpSubCommand("serve", {
1443
+ name: "multi-server",
1444
+ version: "1.0.0",
1445
+ }, {
1446
+ defaultTransports: [
1447
+ { type: "stdio" },
1448
+ { type: "sse", port: 3001 },
1449
+ { type: "streamable-http", port: 3002, path: "/api/mcp" }
1450
+ ],
1451
+ toolOptions: {
1452
+ includeSubCommands: true
1453
+ }
1454
+ });
1455
+
1456
+ // CLI flags always take precedence over presets
1457
+ // my-tool serve -> Uses preset transports
1458
+ // my-tool serve --transport sse -> Overrides preset with CLI flags
1459
+ ```
1460
+
1461
+ ### **System Flags**
1462
+ ```bash
1463
+ # Debug parsing
1464
+ my-tool --s-debug --input data.txt process
1465
+
1466
+ # Load configuration
1467
+ my-tool --s-with-env config.yaml --input override.txt
1468
+
1469
+ # Save configuration
1470
+ my-tool --input data.txt --s-save-to-env template.yaml
1471
+ ```
1472
+
1473
+ ### **Multiple MCP Transports**
1474
+ ```bash
1475
+ # Single transport
1476
+ my-tool serve --transport sse --port 3001
1477
+
1478
+ # Multiple transports
1479
+ my-tool serve --transports '[
1480
+ {"type":"stdio"},
1481
+ {"type":"sse","port":3001},
1482
+ {"type":"streamable-http","port":3002}
1483
+ ]'
1484
+ ```
1485
+
1486
+ ---
1487
+
1488
+ **📖 For complete examples and tutorials, see the [`examples/`](./examples/) directory.**
1489
+
1490
+ ---
1491
+
1492
+ ## Backlog
1493
+
1494
+ - [x] Publish as an open-source library
1495
+ - [x] Make ArgParser compatible with MCP out-of-the-box
1496
+ - [x] Rename --LIB-* flags to --s-*
1497
+ - [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)
1498
+ - [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)
1499
+ - [ ] Add System flags to args.systemArgs
1500
+ - [ ] Improve flag options collision prevention
1501
+ - [ ] Add support for locales / translations
1502
+ - [ ] Add support for async type function to enable more flexibility
1503
+ - [ ] (potentially) add support for fully typed parsed output, this has proven very challenging
1504
+ - [ ] Upgrade to Zod/V4 (V4 does not support functions well, this will take more time, not a priority)
1505
+
1506
+ ### (known) Bugs / DX improvement points
1507
+
1508
+ - [ ] 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
1509
+ - [ ] 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