@alcyone-labs/arg-parser 2.13.0 → 2.13.2

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
@@ -7,109 +7,11 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
7
7
  - [Features Overview](#features-overview)
8
8
  - [Installation](#installation)
9
9
  - [Quick Start: The Unified `addTool` API](#quick-start-the-unified-addtool-api)
10
- - [Working Directory Management for Monorepos](#working-directory-management)
11
- - [MCP Tool Name Constraints](#mcp-tool-name-constraints)
10
+ - [Documentation](#documentation)
12
11
  - [How to Run It](#how-to-run-it)
13
- - [Setting Up System-Wide CLI Access](#setting-up-system-wide-cli-access)
14
12
  - [OpenTUI: Reactive Rich Terminal Interfaces](#opentui-reactive-rich-terminal-interfaces)
15
- - [Parsing Command-Line Arguments](#parsing-command-line-arguments)
16
- - [Automatic Argument Detection](#automatic-argument-detection)
17
- - [Cannonical Usage Pattern](#cannonical-usage-pattern)
18
- - [Top-level await](#top-level-await)
19
- - [Promise-based parsing](#promise-based-parsing)
20
- - [Migrating from v1.x to the v2.0 `addTool` API](#migrating-from-v1x-to-the-v20-addtool-api)
21
- - [Before v2.0: Separate Definitions](#before-v20-separate-definitions)
22
- - [After v2.0: The Unified `addTool()` Method](#after-v20-the-unified-addtool-method)
23
- - [Core Concepts](#core-concepts)
24
- - [Defining Flags](#defining-flags)
25
- - [Type Handling and Validation](#type-handling-and-validation)
26
- - [Supported Type Formats](#supported-type-formats)
27
- - [Runtime Type Validation](#runtime-type-validation)
28
- - [Automatic Type Processing](#automatic-type-processing)
29
- - [Async Custom Parser Support](#async-custom-parser-support)
30
- - [Zod Schema Flags (Structured JSON Validation)](#zod-schema-flags-structured-json-validation)
31
- - [Type Conversion Examples](#type-conversion-examples)
32
- - [DXT Package User Configuration & Path Handling](#dxt-package-user-configuration--path-handling)
33
- - [Hierarchical CLIs (Sub-Commands)](#hierarchical-clis-sub-commands)
34
- - [MCP Exposure Control](#mcp-exposure-control)
35
- - [Flag Inheritance (`inheritParentFlags`)](#flag-inheritance-inheritparentflags)
36
- - [Dynamic Flags (`dynamicRegister`)](#dynamic-flags-dynamicregister)
37
- - [Positional Arguments](#positional-arguments)
38
- - [Automatic Help Display](#automatic-help-display)
39
-
40
- - [MCP & Claude Desktop Integration](#mcp--claude-desktop-integration)
41
- - [Output Schema Support](#output-schema-support)
42
- - [Basic Usage](#basic-usage)
43
- - [Predefined Schema Patterns](#predefined-schema-patterns)
44
- - [Custom Zod Schemas](#custom-zod-schemas)
45
- - [MCP Version Compatibility](#mcp-version-compatibility)
46
- - [Automatic Error Handling](#automatic-error-handling)
47
- - [Writing Effective MCP Tool Descriptions](#writing-effective-mcp-tool-descriptions)
48
- - [Best Practices for Tool Descriptions](#best-practices-for-tool-descriptions)
49
- - [Complete Example: Well-Documented Tool](#complete-example-well-documented-tool)
50
- - [Parameter Description Guidelines](#parameter-description-guidelines)
51
- - [Common Pitfalls to Avoid](#common-pitfalls-to-avoid)
52
- - [Automatic MCP Server Mode (`--s-mcp-serve`)](#automatic-mcp-server-mode---s-mcp-serve)
53
- - [MCP Transports](#mcp-transports)
54
- - [Adding custom HTTP routes (e.g., /health)](#adding-custom-http-routes-eg-health)
55
- - [CORS and Authentication for streamable-http](#cors-and-authentication-for-streamable-http)
56
- - [Multiple transports and improved logging](#multiple-transports-and-improved-logging)
57
- - [MCP Logging Configuration](#mcp-logging-configuration)
58
- - [Enhanced Logging (Recommended)](#enhanced-logging-recommended)
59
- - [Simple Logging Configuration](#simple-logging-configuration)
60
- - [Configuration Priority](#configuration-priority)
61
- - [Configuration Merging](#configuration-merging)
62
- - [Path Resolution Options](#path-resolution-options)
63
- - [MCP Lifecycle Events](#mcp-lifecycle-events)
64
- - [MCP Resources - Real-Time Data Feeds](#mcp-resources---real-time-data-feeds)
65
- - [Basic Resource Setup](#basic-resource-setup)
66
- - [URI Templates with Dynamic Parameters](#uri-templates-with-dynamic-parameters)
67
- - [MCP Subscription Lifecycle](#mcp-subscription-lifecycle)
68
- - [Usage Examples](#usage-examples)
69
- - [Design Patterns](#design-patterns)
70
- - [Automatic Console Safety](#automatic-console-safety)
71
- - [Generating DXT Packages (`--s-build-dxt`)](#generating-dxt-packages---s-build-dxt)
72
- - [Logo Configuration](#logo-configuration)
73
- - [Supported Logo Sources](#supported-logo-sources)
74
- - [Including Additional Files in DXT Packages](#including-additional-files-in-dxt-packages)
75
- - [Include Options](#include-options)
76
- - [How DXT Generation Works](#how-dxt-generation-works)
77
- - [DXT Bundling Strategies](#dxt-bundling-strategies)
78
- - [Standard Approach (Recommended for Most Projects)](#standard-approach-recommended-for-most-projects)
79
- - [Native Dependencies Approach](#native-dependencies-approach)
80
- - [Typical Errors](#typical-errors)
81
13
  - [System Flags & Configuration](#system-flags--configuration)
82
- - [Changelog](#changelog)
83
- - [v2.13.0](#v2130)
84
- - [v2.12.3](#v2123)
85
- - [v2.12.2](#v2122)
86
- - [v2.12.0](#v2120)
87
- - [v2.11.0](#v2110)
88
- - [v2.10.3](#v2103)
89
- - [v2.10.2](#v2102)
90
- - [v2.10.1](#v2101)
91
- - [v2.10.0](#v2100)
92
- - [v2.8.2](#v282)
93
- - [v2.8.1](#v281)
94
- - [v2.7.2](#v272)
95
- - [v2.7.0](#v270)
96
- - [v2.6.0](#v260)
97
- - [v2.5.0](#v250)
98
- - [v2.4.2](#v242)
99
- - [v2.4.1](#v241)
100
- - [v2.4.0](#v240)
101
- - [v2.3.0](#v230)
102
- - [v2.2.1](#v221)
103
- - [v2.2.0](#v220)
104
- - [v2.1.1](#v211)
105
- - [v2.1.0](#v210)
106
- - [v2.0.0](#v200)
107
- - [v1.3.0](#v130)
108
- - [v1.2.0](#v120)
109
- - [v1.1.0](#v110)
110
-
111
- - [Backlog](#backlog)
112
- - [(known) Bugs / DX improvement points](#known-bugs--dx-improvement-points)
14
+ - [Links](#links)
113
15
 
114
16
  ## Features Overview
115
17
 
@@ -117,114 +19,11 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
117
19
  - **Type-safe flag definitions** with full TypeScript support and autocompletion.
118
20
  - **Automatic MCP Integration**: Transform any CLI into a compliant MCP server with a single command (`--s-mcp-serve`).
119
21
  - **MCP Resources with Real-Time Feeds** ⭐: Create subscription-based data feeds with URI templates for live notifications to AI assistants.
120
- - **Console Safe**: `console.log` and other methods
121
- are automatically handled in MCP mode to prevent protocol contamination, requiring no changes to your code.
122
- - **DXT Package Generation**: Generate complete, ready-to-install Claude Desktop Extension (`.dxt`) packages with the `--s-build-dxt` command and `--s-with-node-modules` for platform-dependent builds.
123
- - **Hierarchical Sub-commands**: Create complex, nested sub-command structures (e.g., `git commit`, `docker container ls`) with flag inheritance.
124
- - **Configuration Management**: Easily load (`--s-with-env`) and save (`--s-save-to-env`) configurations from/to `.env`, `.json`, `.yaml`, and `.toml` files.
125
- - **OpenTUI Framework** ⭐: A standardized, event-driven TUI engine with mouse support, multi-layer navigation, and reactive themes (Dark, Ocean, Monokai).
126
-
127
- ---
128
-
129
- ## OpenTUI: Reactive Rich Terminal Interfaces
130
-
131
- ArgParser includes **OpenTUI v2**, a reactive TUI framework built on SolidJS for building rich terminal applications with minimal boilerplate.
132
-
133
- > 📖 **Full Documentation**: [docs/TUI.md](./docs/TUI.md)
134
-
135
- - **Standardized Navigation**: `Enter` / `Right` to dive into details, `Esc` / `Left` to go back.
136
- - **Reactive Theming**: Cycle through built-in themes (`Default`, `Ocean`, `Monokai`) or create your own.
137
- - **Mouse & Scroll Performance**: Built-in SGR mouse reporting support with smooth scrolling and high-performance rendering.
138
- - **New Components**: `Label` (Text), `Button` (Interactive), `Card` (Container), `Toast` (Notification).
139
- - **Component Based**: Reusable `List`, `ScrollArea`, `Input`, and `SplitLayout` components.
140
- - **TuiProvider**: Unified provider handling mouse, resize, cleanup, themes, and shortcuts
141
- - **Virtual Scrolling**: Efficient list rendering with `VirtualList`
142
- - **Theme System**: 6 built-in themes + `Theme.from().extend()` for custom themes
143
- - **Slot-based Layouts**: `MasterDetail` with customizable panels
144
- - **Keyboard + Mouse**: Built-in navigation with useKeyboard and mouse wheel
145
-
146
- ### Quick Start
147
-
148
- ```tsx
149
- import { createSignal } from "solid-js";
150
- import {
151
- cleanupTerminal,
152
- createVirtualListController,
153
- MasterDetail,
154
- TuiProvider,
155
- useTheme,
156
- useTui,
157
- VirtualList,
158
- } from "@alcyone-labs/arg-parser/tui";
159
- import { render, useKeyboard } from "@opentui/solid";
160
-
161
- const DATA = [{ id: "1", name: "Item 1" } /* ... */];
162
-
163
- function App() {
164
- const { viewportHeight, exit } = useTui();
165
- const { current: theme, cycle } = useTheme();
166
- const [idx, setIdx] = createSignal(0);
167
-
168
- const list = createVirtualListController(
169
- () => DATA,
170
- idx,
171
- setIdx,
172
- viewportHeight,
173
- );
174
-
175
- useKeyboard((key) => {
176
- if (key.name === "q") exit(0);
177
- if (key.name === "t") cycle();
178
- if (key.name === "down") list.selectNext();
179
- if (key.name === "up") list.selectPrevious();
180
- });
181
-
182
- return (
183
- <MasterDetail
184
- header="My App"
185
- breadcrumb={["Items", DATA[idx()]!.name]}
186
- footer={`↑↓: Navigate | t: Theme (${theme().name}) | q: Quit`}
187
- master={
188
- <VirtualList
189
- items={DATA}
190
- selectedIndex={idx()}
191
- viewportHeight={viewportHeight()}
192
- getLabel={(item) => item.name}
193
- />
194
- }
195
- detail={<text>Selected: {DATA[idx()]!.name}</text>}
196
- />
197
- );
198
- }
199
-
200
- render(
201
- () => (
202
- <TuiProvider theme="dark">
203
- <App />
204
- </TuiProvider>
205
- ),
206
- { onDestroy: cleanupTerminal },
207
- );
208
- ```
209
-
210
- ### Theme Builder
211
-
212
- ```ts
213
- import { Theme, THEMES } from "@alcyone-labs/arg-parser/tui";
214
-
215
- // Built-in: dark, light, monokai, dracula, nord, solarized
216
- const custom = Theme.from(THEMES.dark).extend({
217
- name: "my-theme",
218
- colors: { background: "#1e1e1e", accent: "#ff6b6b" },
219
- });
220
- ```
221
-
222
- ### Run Examples
223
-
224
- ```bash
225
- bun examples/framework-demo.tsx # Simplified demo
226
- bun examples/aquaria-trace-viewer.tsx # Full-featured demo
227
- ```
22
+ - **Console Safe**: `console.log` and other methods are automatically handled in MCP mode to prevent protocol contamination.
23
+ - **DXT Package Generation**: Generate complete, ready-to-install Claude Desktop Extension (`.dxt`) packages.
24
+ - **Hierarchical Sub-commands**: Create complex, nested sub-command structures with flag inheritance.
25
+ - **Configuration Management**: Easily load (`--s-with-env`) and save (`--s-save-to-env`) configurations.
26
+ - **OpenTUI Framework** ⭐: A reactive TUI engine built on SolidJS with mouse support and themes.
228
27
 
229
28
  ## Installation
230
29
 
@@ -233,391 +32,14 @@ bun examples/aquaria-trace-viewer.tsx # Full-featured demo
233
32
  pnpm add @alcyone-labs/arg-parser
234
33
  ```
235
34
 
236
- ---
237
-
238
35
  ## Quick Start: The Unified `addTool` API
239
36
 
240
- 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.
37
+ The modern way to build with ArgParser is using the `.addTool()` method.
241
38
 
242
39
  ```typescript
243
40
  import { z } from "zod";
244
41
  import { ArgParser } from "@alcyone-labs/arg-parser";
245
42
 
246
- // Use ArgParser.withMcp to enable MCP and DXT features
247
- const cli = ArgParser.withMcp({
248
- appName: "My Awesome CLI",
249
- appCommandName: "mycli",
250
- description: "A tool that works in both CLI and MCP mode",
251
- mcp: {
252
- serverInfo: { name: "my-awesome-mcp-server", version: "1.0.0" },
253
- },
254
- })
255
- // Define a tool that works everywhere
256
- .addTool({
257
- name: "greet",
258
- description: "A tool to greet someone",
259
- flags: [
260
- {
261
- name: "name",
262
- type: "string",
263
- mandatory: true,
264
- options: ["--name"],
265
- description: "Name to greet",
266
- },
267
- {
268
- name: "style",
269
- type: "string",
270
- enum: ["formal", "casual"],
271
- defaultValue: "casual",
272
- description: "Greeting style",
273
- },
274
- ],
275
- // Optional: Define output schema for MCP clients (Claude Desktop, etc.)
276
- // This only affects MCP mode - CLI mode works the same regardless
277
- outputSchema: {
278
- success: z.boolean().describe("Whether the greeting was successful"),
279
- greeting: z.string().describe("The formatted greeting message"),
280
- name: z.string().describe("The name that was greeted"),
281
- },
282
- handler: async (ctx) => {
283
- // Use console.log freely - it's automatically safe in MCP mode!
284
- console.log(`Greeting ${ctx.args.name} in a ${ctx.args.style} style...`);
285
-
286
- const greeting =
287
- ctx.args.style === "formal"
288
- ? `Good day, ${ctx.args.name}.`
289
- : `Hey ${ctx.args.name}!`;
290
-
291
- console.log(greeting);
292
- return { success: true, greeting, name: ctx.args.name };
293
- },
294
- });
295
-
296
- // parse() is async and works with both sync and async handlers
297
- async function main() {
298
- try {
299
- await cli.parse(process.argv.slice(2));
300
- } catch (error) {
301
- console.error("Error:", error.message);
302
- process.exit(1);
303
- }
304
- }
305
-
306
- main();
307
-
308
- // Export if you want to test, use the CLI programmatically
309
- // or use the --s-enable-fuzzing system flag to run fuzzy tests on your CLI
310
- export default cli;
311
- ```
312
-
313
- ### MCP Tool Name Constraints
314
-
315
- When using `.addTool()` or `.addMcpTool()`, tool names are automatically sanitized for MCP compatibility. MCP tool names must follow the pattern `^[a-zA-Z0-9_-]{1,64}$` (only alphanumeric characters, underscores, and hyphens, with a maximum length of 64 characters).
316
-
317
- ```typescript
318
- // These names will be automatically sanitized:
319
- cli.addTool({
320
- name: "test.tool", // → "test_tool"
321
- // ... rest of config
322
- });
323
-
324
- cli.addTool({
325
- name: "my@tool", // → "my_tool"
326
- // ... rest of config
327
- });
328
-
329
- cli.addTool({
330
- name: "tool with spaces", // → "tool_with_spaces"
331
- // ... rest of config
332
- });
333
-
334
- cli.addTool({
335
- name: "very-long-tool-name-that-exceeds-the-64-character-limit-for-mcp", // → truncated to 64 chars
336
- // ... rest of config
337
- });
338
- ```
339
-
340
- The library will warn you when tool names are sanitized, but your tools will continue to work normally. For CLI usage, the original name is preserved as the subcommand name.
341
-
342
- ## How to Run It
343
-
344
- ```bash
345
- # This assumes `mycli` is your CLI's entry point
346
-
347
- # 1. As a standard CLI subcommand
348
- mycli greet --name Jane --style formal
349
-
350
- # 2. As an MCP server, exposing the 'greet' tool
351
- mycli --s-mcp-serve
352
-
353
- # 3. Generate a DXT package for Claude Desktop (2-steps)
354
- mycli --s-build-dxt ./my-dxt-package
355
-
356
- # If you use ML models or packages that include binaries such as Sqlite3 or sharp, etc...
357
- # You need to bundle the node_modules folder with your DXT package
358
- # In order to do this, you need to use the following flag:
359
- # First hard-install all the packages
360
- rm -rf node_moduels
361
- pnpm install --prod --node-linker=hoisted
362
- # Then bundle with node_modules
363
- mycli --s-build-dxt ./my-dxt-package --s-with-node-modules
364
- # then packages the dxt
365
- npx @anthropic-ai/dxt pack ./my-dxt-package
366
- # then upload the dxt bundle to Claude Desktop from the settings > extensions > advanced screen
367
- ```
368
-
369
- Read more on generating the DXT package here: [Generating DXT Packages](#generating-dxt-packages---s-build-dxt)
370
-
371
- ### Setting Up System-Wide CLI Access
372
-
373
- 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:
374
-
375
- **1. Configure your package.json:**
376
-
377
- ```json
378
- {
379
- "name": "my-cli-app",
380
- "version": "1.0.0",
381
- "type": "module",
382
- "bin": {
383
- "mycli": "./cli.js"
384
- }
385
- }
386
- ```
387
-
388
- **2. Make your CLI file executable:**
389
-
390
- ```bash
391
- chmod +x cli.js
392
- ```
393
-
394
- **3. Add a shebang to your CLI file:**
395
-
396
- ```javascript
397
- #!/usr/bin/env node
398
- # or #!/usr/bin/env bun for native typescript runtime
399
-
400
- import { ArgParser } from '@alcyone-labs/arg-parser';
401
-
402
- const cli = ArgParser.withMcp({
403
- appName: "My CLI",
404
- appCommandName: "mycli",
405
- // ... your configuration
406
- });
407
-
408
- // Parse command line arguments
409
- await cli.parse(process.argv.slice(2));
410
- ```
411
-
412
- **4. Link the package globally:**
413
-
414
- ```bash
415
- # Using npm
416
- npm link
417
-
418
- # Using pnpm
419
- pnpm link --global
420
-
421
- # Using bun
422
- bun link
423
-
424
- # Using yarn
425
- yarn link
426
- ```
427
-
428
- **5. Use your CLI from anywhere:**
429
-
430
- ```bash
431
- # Now you can run your CLI from any directory
432
- mycli --help
433
- mycli greet --name "World"
434
-
435
- # Or use with npx/pnpx if you prefer
436
- npx mycli --help
437
- pnpx mycli greet --name "World"
438
- ```
439
-
440
- **To unlink later:**
441
-
442
- ```bash
443
- # Using npm
444
- npm unlink --global my-cli-app
445
-
446
- # Using pnpm
447
- pnpm unlink --global
448
-
449
- # Using bun
450
- bun unlink
451
-
452
- # Using yarn
453
- yarn unlink
454
- ```
455
-
456
- ---
457
-
458
- ## Parsing Command-Line Arguments
459
-
460
- ArgParser's `parse()` method is async and automatically handles both synchronous and asynchronous handlers:
461
-
462
- ### Auto-Execution versus Import: No More Boilerplate
463
-
464
- ArgParser now provides auto-execution ability that eliminates the need for boilerplate code to check if your script is being run directly vs. imported. This enables use cases such as programmatically loading the CLI and scanning for tools or testing it from another script via the --s-enable-fuzzy flag or your own script.
465
-
466
- ```typescript
467
- const cli = ArgParser.withMcp({
468
- appName: "My CLI",
469
- appCommandName: "my-cli",
470
- handler: async (ctx) => ({ success: true, data: ctx.args }),
471
- });
472
-
473
- // Now, this will NOT automatically execute the parser if the script is imported, but will execute if called directly:
474
- await cli
475
- .parse(undefined, {
476
- importMetaUrl: import.meta.url,
477
- })
478
- .catch(handleError);
479
-
480
- // Or, using the manual APIs:
481
- await cli.parseIfExecutedDirectly(import.meta.url).catch((error) => {
482
- console.error(
483
- "Fatal error:",
484
- error instanceof Error ? error.message : String(error),
485
- );
486
- process.exit(1);
487
- });
488
- ```
489
-
490
- **Replaces previously confusing patterns:**
491
-
492
- ```typescript
493
- // Brittle and breaks in sandboxes
494
- if (import.meta.url === `file://${process.argv[1]}`) {
495
- await cli.parse().catch(handleError);
496
- }
497
- ```
498
-
499
- ### Cannonical Usage Pattern
500
-
501
- ```typescript
502
- const cli = ArgParser.withMcp({
503
- appName: "My CLI",
504
- handler: async (ctx) => {
505
- // Works with both sync and async operations
506
- const result = await someAsyncOperation(ctx.args.input);
507
- return { success: true, result };
508
- },
509
- });
510
-
511
- // parse() is async and works with both sync and async handlers
512
- async function main() {
513
- try {
514
- // Option 1: Auto-detection - convenient for simple scripts
515
- const result = await cli.parse();
516
-
517
- // Option 2: Explicit arguments - full control
518
- // const result = await cli.parse(process.argv.slice(2));
519
-
520
- // Handler results are automatically awaited and merged
521
- console.log(result.success); // true
522
- } catch (error) {
523
- console.error("Error:", error.message);
524
- process.exit(1);
525
- }
526
- }
527
- ```
528
-
529
- ### Top-level await
530
-
531
- Works in ES modules or Node.js >=18 with top-level await
532
-
533
- ```javascript
534
- try {
535
- // Auto-detection approach (recommended for simple scripts)
536
- const result = await cli.parse();
537
-
538
- // Or explicit approach for full control
539
- // const result = await cli.parse(process.argv.slice(2));
540
-
541
- console.log("Success:", result);
542
- } catch (error) {
543
- console.error("Error:", error.message);
544
- process.exit(1);
545
- }
546
- ```
547
-
548
- ### Promise-based parsing
549
-
550
- If you need synchronous contexts, you can simply rely on promise-based APIs
551
-
552
- ```javascript
553
- // Auto-detection approach
554
- cli
555
- .parse()
556
- .then((result) => {
557
- console.log("Success:", result);
558
- })
559
- .catch((error) => {
560
- console.error("Error:", error.message);
561
- process.exit(1);
562
- });
563
-
564
- // Or explicit approach
565
- // cli
566
- // .parse(process.argv.slice(2))
567
- // .then((result) => {
568
- // console.log("Success:", result);
569
- // })
570
- // .catch((error) => {
571
- // console.error("Error:", error.message);
572
- // process.exit(1);
573
- // });
574
- ```
575
-
576
- ---
577
-
578
- ## Migrating from v1.x to the v2.0 `addTool` API
579
-
580
- Version 2.0 introduces the `addTool()` method to unify CLI subcommand and MCP tool creation. This simplifies development by removing boilerplate and conditional logic.
581
-
582
- ### Before v2.0: Separate Definitions
583
-
584
- Previously, you had to define CLI handlers and MCP tools separately, often with conditional logic inside the handler to manage different output formats.
585
-
586
- ```javascript
587
- const cli = ArgParser.withMcp({
588
- appName: "My Awesome CLI",
589
- appCommandName: "mycli",
590
- description: "A tool that works in both CLI and MCP mode",
591
- mcp: {
592
- serverInfo: { name: "my-awesome-mcp-server", version: "1.0.0" },
593
- },
594
- });
595
-
596
- // Old way: Separate CLI subcommands and MCP tools
597
- cli
598
- .addSubCommand({
599
- name: "search",
600
- handler: async (ctx) => {
601
- // Manual MCP detection was required
602
- if (ctx.isMcp) {
603
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
604
- } else {
605
- console.log("Search results...");
606
- return result;
607
- }
608
- },
609
- })
610
- // And a separate command to start the server
611
- .addMcpSubCommand("serve", {
612
- /* MCP config */
613
- });
614
- ```
615
-
616
- ### After v2.0: The Unified `addTool()` Method
617
-
618
- 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.
619
-
620
- ```javascript
621
43
  const cli = ArgParser.withMcp({
622
44
  appName: "My Awesome CLI",
623
45
  appCommandName: "mycli",
@@ -625,2159 +47,64 @@ const cli = ArgParser.withMcp({
625
47
  mcp: {
626
48
  serverInfo: { name: "my-awesome-mcp-server", version: "1.0.0" },
627
49
  },
628
- });
629
-
630
- // New way: A single tool definition for both CLI and MCP
631
- cli.addTool({
632
- name: "search",
633
- description: "Search for items",
50
+ }).addTool({
51
+ name: "greet",
52
+ description: "A tool to greet someone",
634
53
  flags: [
635
- { name: "query", type: "string", mandatory: true },
636
- { name: "apiKey", type: "string", env: "API_KEY" }, // Universal Env support (also used for DXT)
54
+ { name: "name", type: "string", mandatory: true, options: ["--name"] },
637
55
  ],
638
56
  handler: async (ctx) => {
639
- // No more MCP detection! Use console.log freely.
640
- console.log(`Searching for: ${ctx.args.query}`);
641
- const results = await performSearch(ctx.args.query, ctx.args.apiKey);
642
- console.log(`Found ${results.length} results`);
643
- return { success: true, results };
57
+ console.log(`Hey ${ctx.args.name}!`);
58
+ return { success: true, greeting: `Hey ${ctx.args.name}!` };
644
59
  },
645
60
  });
646
61
 
647
- // CLI usage: mycli search --query "test"
648
- // MCP usage: mycli --s-mcp-serve
649
- ```
650
-
651
- **Benefits of Migrating:**
652
-
653
- - **Less Code**: A single definition replaces two or more complex ones.
654
- - **Simpler Logic**: No more manual MCP mode detection or response formatting.
655
- - **Automatic Schemas**: Flags are automatically converted into the `input_schema` for MCP tools.
656
- - **Automatic Console Safety**: `console.log` is automatically redirected in MCP mode.
657
- - **Optional Output Schemas**: Add `outputSchema` only if you want structured responses for MCP clients - CLI mode works perfectly without them.
658
-
659
- ---
660
-
661
- ## Core Concepts
662
-
663
- ### Defining Flags
664
-
665
- Flags are defined using the `IFlag` interface within the `flags` array of a tool or command.
666
-
667
- ```typescript
668
- interface IFlag {
669
- name: string; // Internal name (e.g., 'verbose')
670
- options: string[]; // Command-line options (e.g., ['--verbose', '-v'])
671
- type:
672
- | "string"
673
- | "number"
674
- | "boolean"
675
- | "array"
676
- | "object"
677
- | Function
678
- | ZodSchema;
679
- description?: string; // Help text
680
- mandatory?: boolean | ((args: any) => boolean); // Whether the flag is required
681
- defaultValue?: any; // Default value if not provided
682
- flagOnly?: boolean; // A flag that doesn't consume a value (like --help)
683
- enum?: any[]; // An array of allowed values
684
- validate?: (value: any, parsedArgs?: any) => boolean | string | void; // Custom validation function
685
- allowMultiple?: boolean; // Allow the flag to be provided multiple times
686
- env?: string | string[]; // Maps flag to environment variable(s). Logic: Fallback (Env -> Flag) and Sync (Flag -> Env). Precedence: Flag > Env > Default.
687
- positional?: number; // Captures Nth trailing positional argument (1-indexed). See Positional Arguments section.
688
- dxtOptions?: DxtOptions; // Customizes how this flag appears in DXT package user_config
689
- }
690
-
691
- interface DxtOptions {
692
- type?: "string" | "directory" | "file" | "boolean" | "number"; // UI input type in Claude Desktop
693
- title?: string; // Display name in Claude Desktop (defaults to formatted flag name)
694
- sensitive?: boolean; // Whether to hide the value in UI (defaults to true for security)
695
- default?: any; // Default value for the user_config entry
696
- min?: number; // Minimum value (for number types)
697
- max?: number; // Maximum value (for number types)
698
- }
699
- ```
700
-
701
- ### Environment Variable Support
702
-
703
- ArgParser provides universal support for environment variables across all commands.
704
-
705
- **Features:**
706
-
707
- 1. **Automatic Fallback**: If a flag is not provided via CLI, ArgParser looks for configured environment variables.
708
- 2. **Priority Handling**: `CLI Flag` > `Environment Variable` > `Default Value`.
709
- 3. **Reverse Sync**: Once a flag value is resolved (whether from CLI or Env), it is automatically written back to `process.env`. This ensures downstream code accessing `process.env` sees the consistent, final value.
710
- 4. **Array Support**: You can specify multiple env vars for a single flag; the first one found is used.
711
-
712
- **Example:**
713
-
714
- ```typescript
715
- parser.addFlag({
716
- name: "apiKey",
717
- type: "string",
718
- env: ["MY_APP_API_KEY", "LEGACY_API_KEY"], // First match wins
719
- defaultValue: "dev-key",
720
- });
721
- ```
722
-
723
- - If passed `--api-key val`: `apiKey` is "val", and `process.env.MY_APP_API_KEY` becomes "val".
724
- - If not passed, but `MY_APP_API_KEY` exists: `apiKey` uses the env value.
725
- - If neither: `apiKey` is "dev-key", and `process.env.MY_APP_API_KEY` is set to "dev-key".
726
-
727
- ### DXT Package User Configuration & Path Handling
728
-
729
- ArgParser v2.5.0 introduces comprehensive DXT (Desktop Extension Toolkit) support with rich user interfaces, automatic path resolution, and context-aware development tools.
730
-
731
- #### Enhanced dxtOptions
732
-
733
- When generating DXT packages with `--s-build-dxt`, you can create rich user configuration interfaces using `dxtOptions`:
734
-
735
- ```typescript
736
- import { ArgParser, DxtPathResolver } from "@alcyone-labs/arg-parser";
737
-
738
- const parser = new ArgParser()
739
- .withMcp({
740
- name: "file-processor",
741
- version: "1.0.0",
742
- logPath: "${HOME}/logs/file-processor.log", // DXT variables supported!
743
- })
744
- .addFlag({
745
- name: "input-file",
746
- description: "File to process",
747
- type: "string",
748
- mandatory: true,
749
- dxtOptions: {
750
- type: "file",
751
- title: "Select Input File",
752
- },
753
- })
754
- .addFlag({
755
- name: "output-dir",
756
- description: "Output directory for processed files",
757
- type: "string",
758
- dxtOptions: {
759
- type: "directory",
760
- localDefault: "${DOCUMENTS}/processed-files", // Smart defaults with DXT variables
761
- title: "Output Directory",
762
- },
763
- })
764
- .addFlag({
765
- name: "api-key",
766
- description: "API authentication key",
767
- type: "string",
768
- env: "API_KEY",
769
- dxtOptions: {
770
- type: "string",
771
- sensitive: true, // Excluded from DXT manifest for security
772
- title: "API Key",
773
- },
774
- })
775
- .addFlag({
776
- name: "quality",
777
- description: "Processing quality (1-100)",
778
- type: "number",
779
- dxtOptions: {
780
- type: "number",
781
- min: 1,
782
- max: 100,
783
- localDefault: 85,
784
- title: "Quality (%)",
785
- },
786
- })
787
- .addFlag({
788
- name: "parallel",
789
- description: "Enable parallel processing",
790
- type: "boolean",
791
- dxtOptions: {
792
- type: "boolean",
793
- localDefault: true,
794
- title: "Parallel Processing",
795
- },
796
- });
62
+ await cli.parse();
797
63
  ```
798
64
 
799
- #### DXT Variables & Path Resolution
65
+ ## Documentation
800
66
 
801
- ArgParser automatically resolves paths based on your runtime environment:
67
+ For detailed information, please refer to the following guides:
802
68
 
803
- ```typescript
804
- // DXT variables work everywhere - in flags, MCP config, and code
805
- const logPath = "${HOME}/logs/app.log";
806
- const configPath = "${DOCUMENTS}/myapp/config.json";
807
- const resourcePath = "${__dirname}/templates/default.hbs";
808
-
809
- // Helper functions for common patterns
810
- const userDataPath = DxtPathResolver.createUserDataPath("cache.db");
811
- const tempPath = DxtPathResolver.createTempPath("processing.tmp");
812
- const configPath = DxtPathResolver.createConfigPath("settings.json");
813
-
814
- // Context detection
815
- const context = DxtPathResolver.detectContext();
816
- if (context.isDxt) {
817
- console.log("Running in DXT environment");
818
- } else {
819
- console.log("Running in development");
820
- }
821
- ```
822
-
823
- **Supported DXT Variables:**
824
-
825
- - `${HOME}` - User's home directory
826
- - `${DOCUMENTS}` - Documents folder
827
- - `${DOWNLOADS}` - Downloads folder
828
- - `${DESKTOP}` - Desktop folder
829
- - `${__dirname}` - Entry point directory (DXT package root in DXT)
830
- - `${pathSeparator}` - Platform-specific path separator
831
- - `${DXT_DIR}` - DXT package directory (DXT only)
832
- - `${EXTENSION_DIR}` - Extension root directory (DXT only)
833
-
834
- #### dxtOptions Properties
835
-
836
- | Property | Type | Description |
837
- | -------------- | ------------------------------------------------------------ | ------------------------------------------------ |
838
- | `type` | `'string' \| 'file' \| 'directory' \| 'boolean' \| 'number'` | UI component type |
839
- | `sensitive` | `boolean` | Mark as sensitive (excluded from manifest) |
840
- | `localDefault` | `string \| number \| boolean` | Default for development (supports DXT variables) |
841
- | `multiple` | `boolean` | Allow multiple values |
842
- | `min` / `max` | `number` | Validation constraints |
843
- | `title` | `string` | Custom display name |
844
-
845
- #### Security & Best Practices
846
-
847
- - **Sensitive Data**: Use `sensitive: true` for passwords, API keys, tokens
848
- - **Smart Defaults**: Use DXT variables in `localDefault` for portable paths
849
- - **Type Safety**: Match `dxtOptions.type` with flag `type` for validation
850
- - **Cross-Platform**: Use `${pathSeparator}` for platform-independent paths
851
-
852
- #### Comprehensive Documentation
853
-
854
- For detailed guides and examples:
855
-
856
- - **[DXT Path Handling Guide](./docs/DXT_PATH_HANDLING.md)** - Complete path resolution guide
857
- - **[dxtOptions API Documentation](./docs/DXT_OPTIONS_API.md)** - Full API reference with examples
858
- - **[DXT Migration Guide](./docs/DXT_MIGRATION.md)** - Migrate existing applications
859
- - **[DXT Practical Examples](./docs/DXT_EXAMPLES.md)** - Real-world usage patterns
860
-
861
- ### Type Handling and Validation
862
-
863
- ArgParser provides **strong typing** for flag definitions with comprehensive validation at both compile-time and runtime. The `type` property accepts multiple formats and ensures type safety throughout your application.
864
-
865
- #### Supported Type Formats
866
-
867
- You can define flag types using either **constructor functions** or **string literals**:
868
-
869
- ```typescript
870
- const parser = new ArgParser({
871
- /* ... */
872
- }).addFlags([
873
- // Constructor functions (recommended for TypeScript)
874
- { name: "count", options: ["--count"], type: Number },
875
- { name: "enabled", options: ["--enabled"], type: Boolean, flagOnly: true },
876
- { name: "files", options: ["--files"], type: Array, allowMultiple: true },
877
-
878
- // String literals (case-insensitive)
879
- { name: "name", options: ["--name"], type: "string" },
880
- { name: "port", options: ["--port"], type: "number" },
881
- { name: "verbose", options: ["-v"], type: "boolean", flagOnly: true },
882
- { name: "tags", options: ["--tags"], type: "array", allowMultiple: true },
883
- { name: "config", options: ["--config"], type: "object" },
884
-
885
- // Custom parser functions (sync)
886
- {
887
- name: "date",
888
- options: ["--date"],
889
- type: (value: string) => new Date(value),
890
- },
891
-
892
- // Async custom parser functions
893
- {
894
- name: "config",
895
- options: ["--config"],
896
- type: async (filePath: string) => {
897
- const content = await fs.readFile(filePath, "utf8");
898
- return JSON.parse(content);
899
- },
900
- },
901
- {
902
- name: "user",
903
- options: ["--user-id"],
904
- type: async (userId: string) => {
905
- const response = await fetch(`/api/users/${userId}`);
906
- return response.json();
907
- },
908
- },
909
- ]);
910
- ```
911
-
912
- #### Runtime Type Validation
913
-
914
- The type system validates flag definitions at runtime and throws descriptive errors for invalid configurations:
915
-
916
- ```typescript
917
- // ✅ Valid - these work
918
- { name: "count", options: ["--count"], type: Number }
919
- { name: "count", options: ["--count"], type: "number" }
920
- { name: "count", options: ["--count"], type: "NUMBER" } // case-insensitive
921
-
922
- // ❌ Invalid - these throw ZodError
923
- { name: "count", options: ["--count"], type: "invalid-type" }
924
- { name: "count", options: ["--count"], type: 42 } // primitive instead of constructor
925
- { name: "count", options: ["--count"], type: null }
926
- ```
69
+ - 📖 **[Core Concepts](./docs/CORE_CONCEPTS.md)**: Flag definitions, type handling, validation, and positional arguments.
70
+ - 🤖 **[MCP & Claude Desktop Integration](./docs/MCP.md)**: Full guide on MCP servers, DXT bundling, and Claude integration.
71
+ - 🖥️ **[OpenTUI Reference](./docs/TUI.md)**: Building rich terminal interfaces with SolidJS.
72
+ - 📂 **[Working Directory Management](./docs/WORKING_DIRECTORY.md)**: Handling PWD and monorepos.
73
+ - 🚀 **[Migration Guide (v1 to v2)](./docs/MIGRATION_V2.md)**: Moving to the unified `addTool` API.
927
74
 
928
- #### Automatic Type Processing
929
-
930
- - **String literals** are automatically converted to constructor functions internally
931
- - **Constructor functions** are preserved as-is
932
- - **Custom parser functions** (sync and async) allow complex transformations
933
- - **undefined** falls back to the default `"string"` type
934
-
935
- #### Async Custom Parser Support
936
-
937
- Custom parser functions can be **asynchronous**, enabling powerful use cases like file I/O, API calls, and database lookups:
938
-
939
- ```typescript
940
- const parser = new ArgParser({
941
- /* ... */
942
- }).addFlags([
943
- {
944
- name: "config",
945
- options: ["--config"],
946
- type: async (filePath: string) => {
947
- const content = await fs.readFile(filePath, "utf8");
948
- return JSON.parse(content);
949
- },
950
- },
951
- {
952
- name: "user",
953
- options: ["--user-id"],
954
- type: async (userId: string) => {
955
- const response = await fetch(`/api/users/${userId}`);
956
- if (!response.ok) throw new Error(`User not found: ${userId}`);
957
- return response.json();
958
- },
959
- },
960
- ]);
961
-
962
- // Usage: --config ./settings.json --user-id 123
963
- const result = await parser.parse(process.argv.slice(2));
964
- // result.config contains parsed JSON from file
965
- // result.user contains user data from API
966
- ```
967
-
968
- **Key Features:**
969
-
970
- - ✅ **Backward compatible** - existing sync parsers continue to work
971
- - ✅ **Automatic detection** - no configuration needed, just return a Promise
972
- - ✅ **Error handling** - async errors are properly propagated
973
- - ✅ **Performance** - parsers run concurrently when possible
974
-
975
- #### Type Conversion Examples
976
-
977
- ```typescript
978
- // String flags
979
- --name value → "value"
980
- --name="quoted value" → "quoted value"
981
-
982
- // Number flags
983
- --count 42 → 42
984
- --port=8080 → 8080
985
-
986
- // Boolean flags (flagOnly: true)
987
- --verbose → true
988
- (no flag) → false
989
-
990
- // Array flags (allowMultiple: true)
991
- --tags tag1,tag2,tag3 → ["tag1", "tag2", "tag3"]
992
- --file file1.txt --file file2.txt → ["file1.txt", "file2.txt"]
75
+ ## How to Run It
993
76
 
994
- // Custom parser functions (sync)
995
- --date "2023-01-01" → Date object
996
- --json '{"key":"val"}' parsed JSON object
77
+ ```bash
78
+ # 1. As a standard CLI subcommand
79
+ mycli greet --name Jane
997
80
 
998
- // Async custom parser functions
999
- --config "./settings.json" → parsed JSON from file (async)
1000
- --user-id "123" → user data from API (async)
81
+ # 2. As an MCP server
82
+ mycli --s-mcp-serve
1001
83
 
1002
- // Zod schema validation (structured JSON)
1003
- --config '{"host":"localhost","port":5432}' → validated object
1004
- --deployment '{"env":"prod","region":"us-east-1"}' → validated object
84
+ # 3. Generate a DXT package
85
+ mycli --s-build-dxt ./my-dxt-package
1005
86
  ```
1006
87
 
1007
- #### Zod Schema Flags (Structured JSON Validation)
1008
-
1009
- **Since v2.5.0** - You can now use Zod schemas as flag types for structured JSON input with automatic validation and proper MCP JSON Schema generation:
88
+ ## OpenTUI: Reactive Rich Terminal Interfaces
1010
89
 
1011
- ```typescript
1012
- import { z } from "zod";
90
+ ArgParser includes **OpenTUI v2**, a reactive TUI framework built on SolidJS.
1013
91
 
1014
- const DatabaseConfigSchema = z.object({
1015
- host: z.string().describe("Database host address"),
1016
- port: z.number().min(1).max(65535).describe("Database port number"),
1017
- credentials: z.object({
1018
- username: z.string().describe("Database username"),
1019
- password: z.string().describe("Database password"),
1020
- }),
1021
- ssl: z.boolean().optional().describe("Enable SSL connection"),
1022
- });
1023
-
1024
- const cli = ArgParser.withMcp({
1025
- appName: "Database CLI",
1026
- appCommandName: "db-cli",
1027
- }).addTool({
1028
- name: "connect",
1029
- description: "Connect to database with structured configuration",
1030
- flags: [
1031
- {
1032
- name: "config",
1033
- options: ["--config", "-c"],
1034
- type: DatabaseConfigSchema, // 🎉 Zod schema as type!
1035
- description: "Database configuration as JSON object",
1036
- mandatory: true,
1037
- },
1038
- ],
1039
- handler: async (ctx) => {
1040
- // ctx.args.config is fully typed and validated!
1041
- const { host, port, credentials, ssl } = ctx.args.config;
1042
- console.log(`Connecting to ${host}:${port} as ${credentials.username}`);
1043
- return { success: true };
1044
- },
1045
- });
1046
-
1047
- // CLI usage with JSON validation:
1048
- // db-cli connect --config '{"host":"localhost","port":5432,"credentials":{"username":"admin","password":"secret"},"ssl":true}'
1049
-
1050
- // MCP usage: Generates proper JSON Schema for MCP clients
1051
- // db-cli --s-mcp-serve
1052
- ```
1053
-
1054
- **Example with Complex Nested Schema:**
1055
-
1056
- ```typescript
1057
- const DeploymentSchema = z.object({
1058
- environment: z.enum(["dev", "staging", "prod"]),
1059
- region: z.string(),
1060
- scaling: z.object({
1061
- minInstances: z.number().min(1),
1062
- maxInstances: z.number().min(1),
1063
- targetCpu: z.number().min(10).max(100),
1064
- }),
1065
- monitoring: z.object({
1066
- enabled: z.boolean(),
1067
- alertEmail: z.string().email().optional(),
1068
- metrics: z.array(z.string()),
1069
- }),
1070
- });
1071
-
1072
- // This generates comprehensive JSON Schema for MCP clients
1073
- // while providing full validation and type safety for CLI usage
1074
- ```
1075
-
1076
- ### Hierarchical CLIs (Sub-Commands)
1077
-
1078
- While `addTool()` is the recommended way to create subcommands that are also MCP-compatible, you can use `.addSubCommand()` for traditional CLI hierarchies.
1079
-
1080
- > **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.
1081
-
1082
- ```typescript
1083
- // Create a parser for a nested command
1084
- const logsParser = new ArgParser().addFlags([
1085
- { name: "follow", options: ["-f"], type: "boolean", flagOnly: true },
1086
- ]);
1087
-
1088
- // This creates a command group: `my-cli monitor`
1089
- const monitorParser = new ArgParser().addSubCommand({
1090
- name: "logs",
1091
- description: "Show application logs",
1092
- parser: logsParser,
1093
- handler: ({ args }) => console.log(`Following logs: ${args.follow}`),
1094
- });
1095
-
1096
- // Attach the command group to the main CLI
1097
- const cli = new ArgParser().addSubCommand({
1098
- name: "monitor",
1099
- description: "Monitoring commands",
1100
- parser: monitorParser,
1101
- });
1102
-
1103
- // Usage: my-cli monitor logs -f
1104
- ```
1105
-
1106
- #### MCP Exposure Control
1107
-
1108
- ```typescript
1109
- // By default, subcommands are exposed to MCP
1110
- const mcpTools = parser.toMcpTools(); // Includes all subcommands
1111
-
1112
- // To exclude subcommands from MCP (CLI-only)
1113
- const mcpToolsOnly = parser.toMcpTools({ includeSubCommands: false });
1114
-
1115
- // Name conflicts: You cannot have both addSubCommand("name") and addTool({ name: "name" })
1116
- // This will throw an error:
1117
- parser.addSubCommand({ name: "process", parser: subParser });
1118
- parser.addTool({ name: "process", handler: async () => {} }); // ❌ Error: Sub-command 'process' already exists
1119
- ```
1120
-
1121
- ### Flag Inheritance (`inheritParentFlags`)
1122
-
1123
- ArgParser supports flag inheritance for CLI hierarchies. By default, sub-commands do not inherit flags from their parents. You can control this behavior using the `inheritParentFlags` option, using either a boolean (for basic/legacy behavior) or the `FlagInheritance` configuration object (for advanced control).
1124
-
1125
- #### Basic Inheritance (Snapshot)
1126
-
1127
- Set `inheritParentFlags: true` (or `FlagInheritance.DirectParentOnly`) to inherit flags from the _direct parent_ at the moment the sub-command is attached.
1128
-
1129
- > **Note**: This is a snapshot of the parent's flags at the time `.addSubCommand()` is called. If the parent acquires new flags later (e.g., by inheriting from a grandparent), the child will NOT see them unless `FlagInheritance.AllParents` is used.
1130
-
1131
- ```typescript
1132
- // Child inherits current flags from parent
1133
- const childParser = new ArgParser({ inheritParentFlags: true });
1134
- ```
1135
-
1136
- #### Full Chain Inheritance
1137
-
1138
- For complex hierarchies (e.g. `root -> mid -> leaf`), especially when constructing parsers bottom-up, use `FlagInheritance.AllParents`. This ensures that flags propagate down the entire chain, even if the intermediate parent inherits them _after_ the leaf was attached.
1139
-
1140
- ```typescript
1141
- import { ArgParser, FlagInheritance } from "@alcyone-labs/arg-parser";
1142
-
1143
- const root = new ArgParser().addFlag({
1144
- name: "root-flag",
1145
- options: ["--root"],
1146
- });
1147
- const mid = new ArgParser({ inheritParentFlags: FlagInheritance.AllParents });
1148
- const leaf = new ArgParser({ inheritParentFlags: FlagInheritance.AllParents });
1149
-
1150
- // Even if you link bottom-up:
1151
- mid.addSubCommand({ name: "leaf", parser: leaf });
1152
- root.addSubCommand({ name: "mid", parser: mid });
1153
-
1154
- // 'leaf' will correctly have 'root-flag' thanks to deep propagation
1155
- ```
1156
-
1157
- #### Inheritance Options Reference
1158
-
1159
- | Value | Legacy Boolean | Behavior |
1160
- | ---------------------------------- | -------------- | ----------------------------------------------------------- |
1161
- | `FlagInheritance.NONE` | `false` | No flags are inherited (Default) |
1162
- | `FlagInheritance.DirectParentOnly` | `true` | Inherits from direct parent only (Snapshot) |
1163
- | `FlagInheritance.AllParents` | N/A | Inherits from entire ancestor chain (Recursive Propagation) |
1164
-
1165
- ### Dynamic Flags (`dynamicRegister`)
1166
-
1167
- Register flags at runtime from another flag's value (e.g., load a manifest and add flags programmatically). This works in normal runs and when showing `--help`.
1168
-
1169
- - Two-phase parsing: loader flags run first, can register more flags, then parsing continues with the full set
1170
- - Help preload: when `--help` is present, dynamic loaders run to show complete help (no command handlers execute)
1171
- - Cleanup: dynamic flags are removed between parses (no accumulation)
1172
- - Async-friendly: loaders can be async (e.g., `fs.readFile`)
1173
-
1174
- ```ts
1175
- import { readFile } from "node:fs/promises";
1176
- import { ArgParser } from "@alcyone-labs/arg-parser";
1177
-
1178
- const cli = new ArgParser().addFlags([
1179
- {
1180
- name: "manifest",
1181
- options: ["-w", "--manifest"],
1182
- type: "string",
1183
- description: "Path to manifest.json that defines extra flags",
1184
- dynamicRegister: async ({ value, registerFlags }) => {
1185
- const json = JSON.parse(await readFile(value, "utf8"));
1186
- if (Array.isArray(json.flags)) {
1187
- // Each entry should be a valid IFlag
1188
- registerFlags(json.flags);
1189
- }
1190
- },
1191
- },
1192
- ]);
1193
-
1194
- // Examples:
1195
- // my-cli -w manifest.json --help → help includes dynamic flags
1196
- // my-cli -w manifest.json --foo bar → dynamic flag "--foo" parsed/validated normally
1197
- ```
1198
-
1199
- Notes:
1200
-
1201
- - Inherited behavior works normally: if loader lives on a parent parser and children use `inheritParentFlags`, dynamic flags will be visible to children
1202
- - For heavy loaders, implement app-level caching inside your `dynamicRegister` (e.g., memoize by absolute path + mtime); library-level caching may be added later
1203
-
1204
- ### Positional Arguments
1205
-
1206
- ArgParser supports positional (trailing) arguments for a more natural CLI syntax. Instead of requiring flags for every value, you can capture trailing arguments by position.
1207
-
1208
- **Before:**
1209
- ```bash
1210
- workflow show --id 8fadf090-xxx
1211
- ```
1212
-
1213
- **After:**
1214
- ```bash
1215
- workflow show 8fadf090-xxx
1216
- ```
1217
-
1218
- #### Basic Usage
1219
-
1220
- Add the `positional` property to a flag definition. The value is 1-indexed (first trailing arg = 1, second = 2, etc.):
1221
-
1222
- ```typescript
1223
- const cli = new ArgParser()
1224
- .addFlag({
1225
- name: "id",
1226
- type: "string",
1227
- mandatory: true,
1228
- options: ["--id"], // Fallback syntax: --id <value>
1229
- positional: 1, // Primary: captures first trailing arg
1230
- description: "Resource ID to show",
1231
- valueHint: "ID", // Used in help text: <ID>
1232
- })
1233
- .setHandler((ctx) => {
1234
- console.log(`Showing: ${ctx.args.id}`);
1235
- });
1236
-
1237
- // Both work:
1238
- // cli.parse(["abc123"]) → id = "abc123"
1239
- // cli.parse(["--id", "abc123"]) → id = "abc123"
1240
- ```
1241
-
1242
- #### Multiple Positional Arguments
1243
-
1244
- Capture multiple trailing arguments using different positional indices:
1245
-
1246
- ```typescript
1247
- const cli = new ArgParser().addFlags([
1248
- {
1249
- name: "source",
1250
- type: "string",
1251
- mandatory: true,
1252
- options: ["--source", "-s"],
1253
- positional: 1, // First trailing arg
1254
- valueHint: "SOURCE",
1255
- },
1256
- {
1257
- name: "dest",
1258
- type: "string",
1259
- mandatory: true,
1260
- options: ["--dest", "-d"],
1261
- positional: 2, // Second trailing arg
1262
- valueHint: "DEST",
1263
- },
1264
- ]);
1265
-
1266
- // Usage: copy file.txt backup/
1267
- // Result: source = "file.txt", dest = "backup/"
1268
- ```
1269
-
1270
- #### Precedence Rules
1271
-
1272
- - **Flag syntax takes priority**: If both `--flag value` AND a positional arg are provided, the flag value is used
1273
- - **Either satisfies mandatory**: A mandatory flag is satisfied by EITHER positional or flag syntax
1274
- - **Order matters**: Positional args are assigned in index order (1, 2, 3...)
1275
- - **Type coercion applies**: Positional values go through the same type coercion as flag values
1276
-
1277
- #### Help Text
1278
-
1279
- When positional arguments are defined, help text automatically shows a usage pattern:
1280
-
1281
- ```
1282
- Usage: workflow show [OPTIONS] <ID>
1283
-
1284
- Flags:
1285
- --id Resource ID to show
1286
- Type: string
1287
- Example: --id value
1288
- Positional argument #1
1289
- ```
1290
-
1291
- Mandatory positional args appear as `<NAME>`, optional as `[NAME]`.
1292
-
1293
- ### Automatic Help Display
1294
-
1295
- ArgParser provides features to automatically show help messages when a command is invoked incorrectly or as a "container" command.
1296
-
1297
- - **`ctx.displayHelp()`**: Programmatically trigger help for the current command from within its handler.
1298
- - **`autoHelpHandler`**: A pre-built handler for container commands (e.g., `git remote`) that simply displays the help text.
1299
- - **`triggerAutoHelpIfNoHandler`**: A setting that, when enabled, automatically triggers the help display for any command or sub-command that does not have an explicit handler defined.
1300
-
1301
- For more details, see the [Automatic Help Display Guide](docs/DISPLAY_HELP.md) and the [example demo](examples/auto-help-demo.ts).
1302
-
1303
- ---
1304
-
1305
- ## MCP & Claude Desktop Integration
1306
-
1307
- ### Output Schema Support
1308
-
1309
- Output schemas are **completely optional** and **only affect MCP mode** (Claude Desktop, MCP clients). They have **zero impact** on CLI usage - your CLI will work exactly the same with or without them.
1310
-
1311
- **When do I need output schemas?**
1312
-
1313
- - ❌ **CLI-only usage**: Never needed - skip this section entirely
1314
- - ✅ **MCP integration**: Optional but recommended for better structured responses
1315
- - ✅ **Claude Desktop**: Helpful for Claude to understand your tool's output format
1316
-
1317
- **Key Points:**
1318
-
1319
- - ✅ **CLI works perfectly without them**: Your command-line interface is unaffected
1320
- - ✅ **MCP-only feature**: Only used when running with `--s-mcp-serve`
1321
- - ✅ **Version-aware**: Automatically included only for compatible MCP clients (v2025-06-18+)
1322
- - ✅ **Flexible**: Use predefined patterns or custom Zod schemas
1323
-
1324
- #### Basic Usage
1325
-
1326
- ```typescript
1327
- import { z } from "zod";
1328
-
1329
- .addTool({
1330
- name: "process-file",
1331
- description: "Process a file",
1332
- flags: [
1333
- { name: "path", options: ["--path"], type: "string", mandatory: true }
1334
- ],
1335
- // Optional: Only needed if you want structured MCP responses
1336
- // CLI mode works exactly the same whether this is present or not
1337
- outputSchema: {
1338
- success: z.boolean().describe("Whether processing succeeded"),
1339
- filePath: z.string().describe("Path to the processed file"),
1340
- size: z.number().describe("File size in bytes"),
1341
- lastModified: z.string().describe("Last modification timestamp")
1342
- },
1343
- handler: async (ctx) => {
1344
- // Your logic here - same code for both CLI and MCP
1345
- // The outputSchema doesn't change how this function works
1346
- return {
1347
- success: true,
1348
- filePath: ctx.args.path,
1349
- size: 1024,
1350
- lastModified: new Date().toISOString()
1351
- };
1352
- }
1353
- })
1354
-
1355
- // CLI usage (outputSchema ignored): mycli process-file --path /my/file.txt
1356
- // MCP usage (outputSchema provides structure): mycli --s-mcp-serve
1357
- ```
1358
-
1359
- #### Predefined Schema Patterns
1360
-
1361
- For common use cases, use predefined patterns:
1362
-
1363
- ```typescript
1364
- // For simple success/error responses
1365
- outputSchema: "successError";
1366
-
1367
- // For operations that return data
1368
- outputSchema: "successWithData";
1369
-
1370
- // For file operations
1371
- outputSchema: "fileOperation";
1372
-
1373
- // For process execution
1374
- outputSchema: "processExecution";
1375
-
1376
- // For list operations
1377
- outputSchema: "list";
1378
- ```
1379
-
1380
- #### Custom Zod Schemas
1381
-
1382
- For complex data structures:
1383
-
1384
- ```typescript
1385
- outputSchema: z.object({
1386
- analysis: z.object({
1387
- summary: z.string(),
1388
- wordCount: z.number(),
1389
- sentiment: z.enum(["positive", "negative", "neutral"]),
1390
- }),
1391
- metadata: z.object({
1392
- timestamp: z.string(),
1393
- processingTime: z.number(),
1394
- }),
1395
- });
1396
- ```
1397
-
1398
- #### MCP Version Compatibility
1399
-
1400
- Output schemas are automatically handled based on MCP client version:
1401
-
1402
- - **MCP v2025-06-18+**: Full output schema support with `structuredContent`
1403
- - **Earlier versions**: Schemas ignored, standard JSON text response only
1404
-
1405
- To explicitly set the MCP version for testing:
1406
-
1407
- ```typescript
1408
- const cli = ArgParser.withMcp({
1409
- // ... your config
1410
- }).setMcpProtocolVersion("2025-06-18"); // Enable output schema support
1411
- ```
1412
-
1413
- **Important**:
1414
-
1415
- - **CLI users**: You can ignore MCP versions entirely - they don't affect command-line usage
1416
- - **MCP users**: ArgParser handles version detection automatically based on client capabilities
1417
-
1418
- #### Automatic Error Handling
1419
-
1420
- ArgParser automatically handles errors differently based on execution context, so your handlers can simply throw errors without worrying about CLI vs MCP mode:
1421
-
1422
- ```typescript
1423
- const cli = ArgParser.withMcp({
1424
- // ... config
1425
- }).addTool({
1426
- name: "process-data",
1427
- handler: async (ctx) => {
1428
- // Simply throw errors - ArgParser handles the rest automatically
1429
- if (!ctx.args.apiKey) {
1430
- throw new Error("API key is required");
1431
- }
1432
-
1433
- // Do your work and return results
1434
- return { success: true, data: processedData };
1435
- },
1436
- });
1437
- ```
1438
-
1439
- **How it works:**
1440
-
1441
- - **CLI mode**: Thrown errors cause the process to exit with error code 1
1442
- - **MCP mode**: Thrown errors are automatically converted to structured MCP error responses
1443
- - **No manual checks needed**: Handlers don't need to check `ctx.isMcp` or handle different response formats
1444
-
1445
- ### Writing Effective MCP Tool Descriptions
1446
-
1447
- **Why descriptions matter**: When your tools are exposed to Claude Desktop or other MCP clients, the `description` field is the primary way LLMs understand what your tool does and when to use it. A well-written description significantly improves tool selection accuracy and user experience.
1448
-
1449
- #### Best Practices for Tool Descriptions
1450
-
1451
- **1. Start with the action** - Begin with a clear verb describing what the tool does:
1452
-
1453
- ```typescript
1454
- // ✅ Good: Action-first, specific
1455
- description: "Analyzes text files and returns detailed statistics including word count, character count, and sentiment analysis";
1456
-
1457
- // ❌ Avoid: Vague or noun-heavy
1458
- description: "File analysis tool";
1459
- ```
1460
-
1461
- **2. Include context and use cases** - Explain when and why to use the tool:
1462
-
1463
- ```typescript
1464
- // ✅ Good: Provides context
1465
- description: "Converts image files between formats (PNG, JPEG, WebP). Use this when you need to change image format, resize images, or optimize file sizes. Supports batch processing of multiple files.";
1466
-
1467
- // ❌ Avoid: No context
1468
- description: "Converts images";
1469
- ```
1470
-
1471
- **3. Mention key parameters and constraints** - Reference important inputs and limitations:
1472
-
1473
- ```typescript
1474
- // ✅ Good: Mentions key parameters and constraints
1475
- description: "Searches through project files using regex patterns. Specify the search pattern and optionally filter by file type. Supports JavaScript, TypeScript, Python, and text files up to 10MB.";
1476
-
1477
- // ❌ Avoid: No parameter guidance
1478
- description: "Searches files";
1479
- ```
1480
-
1481
- **4. Be specific about outputs** - Describe what the tool returns:
1482
-
1483
- ```typescript
1484
- // ✅ Good: Clear output description
1485
- description: "Analyzes code complexity and returns metrics including cyclomatic complexity, lines of code, and maintainability index. Results include detailed breakdown by function and overall file scores.";
1486
-
1487
- // ❌ Avoid: Unclear output
1488
- description: "Analyzes code";
1489
- ```
1490
-
1491
- #### Complete Example: Well-Documented Tool
1492
-
1493
- ```typescript
1494
- .addTool({
1495
- name: "analyze-repository",
1496
- description: "Analyzes a Git repository and generates comprehensive statistics including commit history, contributor activity, code quality metrics, and dependency analysis. Use this to understand project health, identify bottlenecks, or prepare reports. Supports Git repositories up to 1GB with history up to 5 years.",
1497
- flags: [
1498
- {
1499
- name: "path",
1500
- description: "Path to the Git repository root directory",
1501
- options: ["--path", "-p"],
1502
- type: "string",
1503
- mandatory: true,
1504
- },
1505
- {
1506
- name: "include-dependencies",
1507
- description: "Include analysis of package.json dependencies and security vulnerabilities",
1508
- options: ["--include-dependencies", "-d"],
1509
- type: "boolean",
1510
- flagOnly: true,
1511
- },
1512
- {
1513
- name: "output-format",
1514
- description: "Output format for the analysis report",
1515
- options: ["--output-format", "-f"],
1516
- type: "string",
1517
- choices: ["json", "markdown", "html"],
1518
- defaultValue: "json",
1519
- }
1520
- ],
1521
- handler: async (ctx) => {
1522
- // Implementation here
1523
- }
1524
- })
1525
- ```
1526
-
1527
- #### Parameter Description Guidelines
1528
-
1529
- Each flag should have a clear, concise description:
1530
-
1531
- ```typescript
1532
- // ✅ Good parameter descriptions
1533
- {
1534
- name: "timeout",
1535
- description: "Maximum execution time in seconds (default: 30, max: 300)",
1536
- options: ["--timeout", "-t"],
1537
- type: "number",
1538
- }
1539
-
1540
- {
1541
- name: "verbose",
1542
- description: "Enable detailed logging output including debug information",
1543
- options: ["--verbose", "-v"],
1544
- type: "boolean",
1545
- flagOnly: true,
1546
- }
1547
-
1548
- {
1549
- name: "format",
1550
- description: "Output format for results (json: structured data, csv: spreadsheet-friendly, pretty: human-readable)",
1551
- options: ["--format"],
1552
- type: "string",
1553
- choices: ["json", "csv", "pretty"],
1554
- }
1555
- ```
1556
-
1557
- #### Common Pitfalls to Avoid
1558
-
1559
- - **Don't be overly technical**: Avoid jargon that doesn't help with tool selection
1560
- - **Don't repeat the tool name**: The name is already visible, focus on functionality
1561
- - **Don't use generic terms**: "Process data" or "handle files" are too vague
1562
- - **Don't forget constraints**: Mention important limitations or requirements
1563
- - **Don't ignore parameter descriptions**: Each flag should have a helpful description
1564
-
1565
- **Remember**: A good description helps the LLM choose the right tool for the task and use it correctly. Invest time in writing clear, comprehensive descriptions - it directly impacts the user experience in Claude Desktop and other MCP clients.
1566
-
1567
- ### Automatic MCP Server Mode (`--s-mcp-serve`)
1568
-
1569
- 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).
1570
-
1571
- ```bash
1572
- # This single command starts a fully compliant MCP server
1573
- my-cli-app --s-mcp-serve
1574
-
1575
- # You can also override transports and ports using system flags
1576
- my-cli-app --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3001
1577
-
1578
- # Configure custom log file path for MCP server logs
1579
- my-cli-app --s-mcp-serve --s-mcp-log-path ./custom-logs/mcp-server.log
1580
-
1581
- # Or configure logging programmatically in withMcp()
1582
- const cli = ArgParser.withMcp({
1583
- appName: 'My CLI App',
1584
- appCommandName: 'my-cli-app',
1585
- mcp: {
1586
- serverInfo: { name: 'my-server', version: '1.0.0' },
1587
- // NEW: Improved logging with level control
1588
- log: {
1589
- level: 'info', // Captures info, warn, error
1590
- logToFile: './my-logs/mcp-server.log',
1591
- prefix: 'MyApp'
1592
- }
1593
- // LEGACY: logPath: './my-logs/mcp-server.log' // Still works
1594
- }
1595
- });
1596
- ```
1597
-
1598
- ### MCP Transports
1599
-
1600
- You can define the transports directly in the .withMcp() settings, or override them via the `--s-mcp-transport(s)` flags.
1601
-
1602
- ```bash
1603
- # Single transport
1604
- my-tool --s-mcp-serve --s-mcp-transport stdio
1605
-
1606
- # Multiple transports via JSON
1607
- my-tool --s-mcp-serve --s-mcp-transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
1608
-
1609
- # Single transport with custom options
1610
- my-tool --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3000 --s-mcp-host 0.0.0.0
1611
-
1612
- # Streamable HTTP CORS/auth via CLI flags (JSON strings)
1613
- my-tool --s-mcp-serve \
1614
- --s-mcp-transport streamable-http \
1615
- --s-mcp-port 3002 --s-mcp-path /api/mcp \
1616
- --s-mcp-cors '{"origins":["http://localhost:5173"],"credentials":true,"methods":["GET","POST","OPTIONS"],"maxAge":600}' \
1617
- --s-mcp-auth '{"required":true,"scheme":"jwt","jwt":{"algorithms":["HS256"],"secret":"$MY_JWT_SECRET"},"publicPaths":["/health"]}'
1618
-
1619
-
1620
- # Custom log path via CLI flag (logs to specified file instead of ./logs/mcp.log)
1621
- my-tool --s-mcp-serve --s-mcp-log-path /var/log/my-mcp-server.log
1622
-
1623
- # Improved logging via programmatic configuration
1624
- const parser = ArgParser.withMcp({
1625
- mcp: {
1626
- serverInfo: { name: 'my-tool', version: '1.0.0' },
1627
-
1628
- ```
1629
-
1630
- ### CORS and Authentication for streamable-http
1631
-
1632
- CORS is often required when connecting a Web UI to an MCP server over HTTP.
1633
-
1634
- - Programmatic transport config:
1635
-
1636
- ```ts
1637
- import type { McpTransportConfig } from "@alcyone-labs/arg-parser";
1638
-
1639
- const defaultTransports: McpTransportConfig[] = [
1640
- {
1641
- type: "streamable-http",
1642
- port: 3002,
1643
- path: "/api/mcp",
1644
- cors: {
1645
- origins: ["http://localhost:5173", /^https?:\/\/example\.com$/],
1646
- methods: ["GET", "POST", "OPTIONS"],
1647
- headers: ["Content-Type", "Authorization", "MCP-Session-Id"],
1648
- exposedHeaders: ["MCP-Session-Id"],
1649
- credentials: true,
1650
- maxAge: 600,
1651
- },
1652
- auth: {
1653
- required: true,
1654
- scheme: "jwt", // or "bearer"
1655
- // Bearer allowlist:
1656
- // allowedTokens: ["token1","token2"],
1657
- // JWT verification (HS256):
1658
- // jwt: { algorithms: ["HS256"], secret: process.env.JWT_SECRET },
1659
- // JWT verification (RS256 with static public key):
1660
- // jwt: { algorithms: ["RS256"], publicKey: process.env.RS256_PUBLIC_KEY },
1661
- // JWT verification (RS256 with dynamic JWKS):
1662
- // jwt: { algorithms: ["RS256"], getPublicKey: async (header)=>{ /* fetch JWKS and return PEM */ } },
1663
- publicPaths: ["/health"],
1664
- protectedPaths: undefined, // if set, only listed paths require auth
1665
- // Optional custom validator to add extra checks
1666
- validator: async (req, token) => true,
1667
- },
1668
- },
1669
- ];
1670
- ```
1671
-
1672
- - CLI flags (JSON strings):
1673
-
1674
- ```bash
1675
- my-tool --s-mcp-serve \
1676
- --s-mcp-transport streamable-http \
1677
- --s-mcp-port 3002 --s-mcp-path /api/mcp \
1678
- --s-mcp-cors '{"origins":["http://localhost:5173"],"credentials":true,"methods":["GET","POST","OPTIONS"],"maxAge":600}' \
1679
- --s-mcp-auth '{"required":true,"scheme":"jwt","jwt":{"algorithms":["HS256"],"secret":"'$JWT_SECRET'"},"publicPaths":["/health"]}'
1680
- ```
1681
-
1682
- - Express hook for custom routes:
1683
-
1684
- ```ts
1685
- httpServer: {
1686
- configureExpress: (app) => {
1687
- app.get("/health", (_req, res) => res.json({ ok: true }));
1688
- },
1689
- }
1690
- ```
1691
-
1692
- See examples:
1693
-
1694
- - examples/streamable-http/secure-mcp.ts (HS256)
1695
- - examples/streamable-http/rs256-mcp.ts (RS256)
1696
- - examples/streamable-http/jwks-mcp.ts (JWKS)
1697
- - examples/streamable-http/bearer-mcp.ts (Bearer)
1698
- - examples/streamable-http/productized-mcp.ts (token + session usage)
1699
-
1700
- #### TypeScript types
1701
-
1702
- - CorsOptions
1703
-
1704
- ```ts
1705
- export type CorsOptions = {
1706
- origins?: "*" | string | RegExp | Array<string | RegExp>;
1707
- methods?: string[];
1708
- headers?: string[];
1709
- exposedHeaders?: string[];
1710
- credentials?: boolean;
1711
- maxAge?: number;
1712
- };
1713
- ```
1714
-
1715
- - AuthOptions and JwtVerifyOptions
1716
-
1717
- ```ts
1718
- export type JwtVerifyOptions = {
1719
- algorithms?: ("HS256" | "RS256")[];
1720
- secret?: string; // HS256
1721
- publicKey?: string; // RS256 static
1722
- getPublicKey?: (
1723
- header: Record<string, unknown>,
1724
- payload: Record<string, unknown>,
1725
- ) => Promise<string> | string; // RS256 dynamic
1726
- audience?: string | string[];
1727
- issuer?: string | string[];
1728
- clockToleranceSec?: number;
1729
- };
1730
-
1731
- export type AuthOptions = {
1732
- required?: boolean; // default true for MCP endpoint
1733
- scheme?: "bearer" | "jwt";
1734
- allowedTokens?: string[]; // simple bearer allowlist
1735
- validator?: (
1736
- req: any,
1737
- token: string | undefined,
1738
- ) => boolean | Promise<boolean>;
1739
- jwt?: JwtVerifyOptions;
1740
- publicPaths?: string[]; // paths that skip auth
1741
- protectedPaths?: string[]; // if provided, only these paths require auth
1742
- customMiddleware?: (req: any, res: any, next: any) => any; // full control hook
1743
- };
1744
- ```
1745
-
1746
- - HttpServerOptions
1747
-
1748
- ```ts
1749
- export type HttpServerOptions = {
1750
- configureExpress?: (app: any) => void;
1751
- };
1752
- ```
1753
-
1754
- Notes:
1755
-
1756
- - When credentials are true, Access-Control-Allow-Origin echoes the request Origin rather than using "\*".
1757
- - You can manage CORS for non-MCP routes in configureExpress.
1758
- - Use publicPaths to allow some routes without auth; use protectedPaths to only require auth for certain routes.
1759
-
1760
- log: {
1761
- level: 'debug', // Capture all log levels
1762
- logToFile: '/var/log/my-mcp-server.log',
1763
- prefix: 'MyTool'
1764
- }
1765
- // LEGACY: logPath: '/var/log/my-mcp-server.log' // Still works
1766
- }
1767
-
1768
- ### Adding custom HTTP routes (e.g., /health)
1769
-
1770
- Use the httpServer.configureExpress(app) hook to register routes before MCP endpoints are bound. Example:
1771
-
1772
- ```ts
1773
- const cli = ArgParser.withMcp({
1774
- mcp: {
1775
- serverInfo: { name: "my-mcp", version: "1.0.0" },
1776
- defaultTransports: [
1777
- {
1778
- type: "streamable-http",
1779
- port: 3002,
1780
- path: "/api/mcp",
1781
- auth: { required: true, publicPaths: ["/health"] },
1782
- },
1783
- ],
1784
- httpServer: {
1785
- configureExpress: (app) =>
1786
- app.get("/health", (_req, res) => res.json({ ok: true })),
1787
- },
1788
- },
1789
- });
1790
- ```
1791
-
1792
- - To make a route public (no auth), add it to auth.publicPaths.
1793
- - CORS headers for non-MCP paths can be applied by your own middleware inside the hook if desired.
1794
-
1795
- ### Multiple transports and improved logging
1796
-
1797
- const cli = ArgParser.withMcp({
1798
- appName: 'multi-tool',
1799
- appCommandName: 'multi-tool',
1800
- mcp: {
1801
- // NEW: improved logging configuration
1802
- log: {
1803
- level: 'info',
1804
- logToFile: './logs/multi-tool-mcp.log',
1805
- prefix: 'MultiTool'
1806
- },
1807
- serverInfo: {
1808
- name: 'multi-tool-mcp',
1809
- version: '1.0.0'
1810
- },
1811
- transports: [
1812
- // Can be a single string...
1813
- "stdio",
1814
- // or one of the other transport types supported by @modelcontextprotocol/sdk
1815
- { type: "sse", port: 3000, host: "0.0.0.0" },
1816
- { type: "websocket", port: 3001, path: "/ws" }
1817
- ]
1818
- }
1819
- });
1820
-
1821
- ````
1822
-
1823
- ### MCP Logging Configuration
1824
-
1825
- MCP server logging can be configured with McpLoggerOptions options using `@alcyone-labs/simple-mcp-logger`. You can control log levels, output destinations, and more.
1826
-
1827
- #### Enhanced Logging (Recommended)
1828
-
1829
- Use the new `log` property for comprehensive logging control:
1830
-
1831
- ```typescript
1832
- const parser = ArgParser.withMcp({
1833
- appName: "My MCP Server",
1834
- appCommandName: "my-mcp-server",
1835
- mcp: {
1836
- serverInfo: { name: "my-server", version: "1.0.0" },
1837
- log: {
1838
- level: "debug", // Captures debug, info, warn, error
1839
- logToFile: "./logs/comprehensive.log",
1840
- prefix: "MyServer",
1841
- mcpMode: true, // MCP compliant (default)
1842
- },
1843
- },
1844
- });
1845
- ````
1846
-
1847
- **Available log levels**: `"debug"` | `"info"` | `"warn"` | `"error"` | `"silent"`
1848
-
1849
- **Type Safety**: The `McpLoggerOptions` type is provided for full TypeScript support and matches the interface from `@alcyone-labs/simple-mcp-logger`.
1850
-
1851
- #### Simple Logging Configuration
1852
-
1853
- For basic use cases, you can use a simple string path:
1854
-
1855
- ```typescript
1856
- const parser = ArgParser.withMcp({
1857
- mcp: {
1858
- serverInfo: { name: "my-server", version: "1.0.0" },
1859
- log: "./logs/simple.log", // Simple string path
1860
- },
1861
- });
1862
- ```
1863
-
1864
- #### Configuration Priority
1865
-
1866
- Logging configuration follows this priority order:
1867
-
1868
- 1. **CLI Flag (Highest Priority)**: `--s-mcp-log-path <path>`
1869
- 2. **Merging**: When both `mcp.log` and `mcp.logPath` are present:
1870
- - `mcp.log` provides logger options (level, prefix, mcpMode)
1871
- - `mcp.logPath` provides flexible path resolution (relativeTo, basePath)
1872
- - Path resolution: `mcp.logPath` > `mcp.log.logToFile`
1873
- 3. **Log Config Only**: `mcp.log` object or string in `withMcp()`
1874
- 4. **Legacy Log Path Only**: `mcp.logPath` in `withMcp()`
1875
- 5. **Default Path (Fallback)**: `./logs/mcp.log`
1876
-
1877
- #### Configuration Merging
1878
-
1879
- When both `log` and `logPath` are specified:
1880
-
1881
- ```typescript
1882
- const parser = ArgParser.withMcp({
1883
- mcp: {
1884
- serverInfo: { name: "my-server", version: "1.0.0" },
1885
- // log provides logger options (level, prefix, mcpMode)
1886
- log: {
1887
- level: "debug",
1888
- prefix: "MyServer",
1889
- mcpMode: true,
1890
- // logToFile can be omitted when using logPath
1891
- },
1892
- // logPath provides flexible path resolution
1893
- logPath: {
1894
- path: "./logs/app.log",
1895
- relativeTo: "entry", // "entry" | "cwd" | "absolute"
1896
- basePath: "/custom/base", // Optional custom base path
1897
- },
1898
- },
1899
- });
1900
- ```
1901
-
1902
- **Merging behavior:**
1903
-
1904
- - `log` provides logger configuration (level, prefix, mcpMode)
1905
- - `logPath` provides flexible path resolution with `relativeTo` options
1906
- - If both specify a file path, `logPath` takes precedence for path resolution
1907
- - This preserves the powerful `LogPath` features while using `McpLoggerOptions` for logger settings
1908
-
1909
- #### Path Resolution Options
1910
-
1911
- Log paths are resolved with smart defaults for better DXT package compatibility:
1912
-
1913
- ```typescript
1914
- // Simple string paths (recommended)
1915
- const parser = ArgParser.withMcp({
1916
- appName: "My CLI",
1917
- appCommandName: "my-cli",
1918
- mcp: {
1919
- serverInfo: { name: "my-server", version: "1.0.0" },
1920
- logPath: "./logs/app.log", // Relative to entry point (default)
1921
- // logPath: "/tmp/app.log", // Absolute paths work too
1922
- // logPath: "cwd:./logs/app.log", // Explicit process.cwd() relative
1923
- },
1924
- });
1925
-
1926
- // Object configuration for more granular use cases
1927
- const parser = ArgParser.withMcp({
1928
- // ... other config
1929
- mcp: {
1930
- // ... server info
1931
- logPath: {
1932
- path: "./logs/app.log",
1933
- relativeTo: "entry", // "entry" | "cwd" | "absolute"
1934
- basePath: "/custom/base", // Optional custom base path
1935
- },
1936
- },
1937
- });
1938
-
1939
- // CLI flag overrides programmatic setting
1940
- // my-cli --s-mcp-serve --s-mcp-log-path ./override.log
1941
- ```
1942
-
1943
- The CLI flag always takes precedence, allowing users to override the developer's programmatic configuration when needed. By default, relative paths resolve relative to the application's entry point, making logs predictably located near DXT packages.
1944
-
1945
- ### MCP Lifecycle Events
1946
-
1947
- ArgParser MCP servers support lifecycle events that allow you to perform initialization, cleanup, and other operations at specific points in the MCP protocol flow. These events are particularly useful for database connections, resource setup, and graceful shutdown procedures.
1948
-
1949
- ```typescript
1950
- const cli = ArgParser.withMcp({
1951
- appName: "Database CLI",
1952
- appCommandName: "db-cli",
1953
- mcp: {
1954
- serverInfo: { name: "database-server", version: "1.0.0" },
1955
- lifecycle: {
1956
- onInitialize: async (ctx) => {
1957
- // Called when client sends "initialize" request
1958
- // Perfect for database connections, resource setup
1959
- ctx.logger.mcpError("Initializing server...");
1960
-
1961
- const dbUrl = ctx.getFlag("database_url");
1962
- if (dbUrl) {
1963
- await connectToDatabase(dbUrl);
1964
- ctx.logger.mcpError("Database connected successfully");
1965
- }
1966
- },
1967
-
1968
- onInitialized: async (ctx) => {
1969
- // Called when client sends "initialized" notification
1970
- // Server is ready for normal operations
1971
- ctx.logger.mcpError("Server ready for requests");
1972
- await startBackgroundTasks();
1973
- },
1974
-
1975
- onShutdown: async (ctx) => {
1976
- // Called during server shutdown
1977
- // Perfect for cleanup, closing connections
1978
- ctx.logger.mcpError(`Shutting down: ${ctx.reason}`);
1979
- await cleanupResources();
1980
- await closeDatabase();
1981
- },
1982
- },
1983
- },
1984
- });
1985
- ```
1986
-
1987
- **Lifecycle Events:**
1988
-
1989
- - **`onInitialize`**: Called when a client sends an "initialize" request. Ideal for database connections, resource initialization, configuration validation, and authentication setup.
1990
- - **`onInitialized`**: Called when a client sends an "initialized" notification, indicating the client is ready for normal operations. Perfect for final setup steps and background task initialization.
1991
- - **`onShutdown`**: Called when the MCP server is shutting down. Essential for cleanup, resource disposal, and graceful shutdown procedures.
1992
-
1993
- **Context Properties:**
1994
-
1995
- Each lifecycle event receives a context object with:
1996
-
1997
- - `getFlag(name)`: Access parsed CLI flags and environment variables
1998
- - `logger`: MCP-compliant logger instance for the current context
1999
- - `serverInfo`: Server information (name, version, description)
2000
- - `clientInfo`: Client information (available in onInitialize and onInitialized)
2001
- - `protocolVersion`: MCP protocol version being used
2002
- - `reason`: Shutdown reason (only in onShutdown: "client_disconnect", "server_shutdown", "error", "signal")
2003
-
2004
- ### MCP Resources - Real-Time Data Feeds
2005
-
2006
- MCP Resources enable your CLI tools to provide **real-time, subscription-based data feeds** to AI assistants. Unlike tools (which are called once), resources can be subscribed to and provide live updates when data changes.
2007
-
2008
- **Key Benefits:**
2009
-
2010
- - **Real-time notifications**: AI assistants get notified when your data changes
2011
- - **Flexible URI templates**: Support dynamic parameters like `data://alerts/aged/gte:{threshold}`
2012
- - **Standard MCP pattern**: Full subscription lifecycle support
2013
- - **Zero CLI impact**: Resources only work in MCP mode, CLI usage unchanged
2014
-
2015
- #### Basic Resource Setup
2016
-
2017
- ```typescript
2018
- const parser = ArgParser.withMcp({
2019
- appName: "Data Monitor",
2020
- appCommandName: "data-monitor",
2021
- mcp: {
2022
- serverInfo: { name: "data-monitor", version: "1.0.0" },
2023
- },
2024
- }).addMcpResource({
2025
- name: "recent-data",
2026
- uriTemplate: "data://recent",
2027
- title: "Recent Data",
2028
- description: "Get the most recent data entries",
2029
- mimeType: "application/json",
2030
- handler: async (uri) => {
2031
- const recentData = await getRecentData();
2032
- return {
2033
- contents: [
2034
- {
2035
- uri: uri.href,
2036
- text: JSON.stringify(recentData, null, 2),
2037
- mimeType: "application/json",
2038
- },
2039
- ],
2040
- };
2041
- },
2042
- });
2043
- ```
2044
-
2045
- #### URI Templates with Dynamic Parameters
2046
-
2047
- Create flexible resources that accept parameters:
2048
-
2049
- ```typescript
2050
- .addMcpResource({
2051
- name: "aged-data-alert",
2052
- uriTemplate: "data://alerts/aged/gte:{threshold}",
2053
- title: "Aged Data Alert",
2054
- description: "Monitor data that has aged past a threshold (in milliseconds)",
2055
- handler: async (uri, { threshold }) => {
2056
- const thresholdMs = parseInt(threshold);
2057
- const agedData = await getDataOlderThan(new Date(Date.now() - thresholdMs));
2058
-
2059
- return {
2060
- contents: [{
2061
- uri: uri.href,
2062
- text: JSON.stringify({
2063
- threshold_ms: thresholdMs,
2064
- query_time: new Date().toISOString(),
2065
- aged_data: agedData,
2066
- count: agedData.length
2067
- }, null, 2),
2068
- mimeType: "application/json"
2069
- }]
2070
- };
2071
- }
2072
- });
2073
- ```
2074
-
2075
- #### MCP Subscription Lifecycle
2076
-
2077
- Resources support the full MCP subscription pattern:
2078
-
2079
- 1. **Client subscribes**: `resources/subscribe` → `"data://alerts/aged/gte:10000"`
2080
- 2. **Server monitors**: Your application detects data changes
2081
- 3. **Server notifies**: `notifications/resources/updated` sent to subscribed clients
2082
- 4. **Client reads fresh data**: `resources/read` → `"data://alerts/aged/gte:10000"`
2083
- 5. **Client unsubscribes**: `resources/unsubscribe` when done
2084
-
2085
- #### Usage Examples
2086
-
2087
- **AI Assistant Integration:**
2088
-
2089
- ```typescript
2090
- // AI assistant can subscribe to real-time data
2091
- await client.request("resources/subscribe", {
2092
- uri: "data://alerts/aged/gte:60000", // 1 minute threshold
2093
- });
2094
-
2095
- // Handle notifications
2096
- client.on("notifications/resources/updated", async (notification) => {
2097
- const response = await client.request("resources/read", {
2098
- uri: notification.uri,
2099
- });
2100
- console.log("Fresh data:", JSON.parse(response.contents[0].text));
2101
- });
2102
- ```
2103
-
2104
- **Command Line Testing:**
2105
-
2106
- ```bash
2107
- # Start MCP server
2108
- data-monitor --s-mcp-serve
2109
-
2110
- # Test resource (in another terminal)
2111
- echo '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"data://alerts/aged/gte:10000"}}' | data-monitor --s-mcp-serve
2112
- ```
2113
-
2114
- #### Design Patterns
2115
-
2116
- **Static Resources**: Use simple URIs for data that changes content but not structure
2117
-
2118
- ```typescript
2119
- uriTemplate: "logs://recent"; // Always available, content updates
2120
- uriTemplate: "status://system"; // System status, updates in real-time
2121
- ```
2122
-
2123
- **Parameterized Resources**: Use URI templates for flexible filtering
2124
-
2125
- ```typescript
2126
- uriTemplate: "data://type/{type}"; // Filter by type
2127
- uriTemplate: "alerts/{severity}/gte:{age}"; // Multiple parameters
2128
- uriTemplate: "search/{query}/limit:{count}"; // Search with limits
2129
- ```
2130
-
2131
- **Time-Based Resources**: Perfect for monitoring and alerting
2132
-
2133
- ```typescript
2134
- uriTemplate: "events/since:{timestamp}"; // Events since timestamp
2135
- uriTemplate: "metrics/aged/gte:{threshold}"; // Metrics past threshold
2136
- uriTemplate: "logs/errors/last:{duration}"; // Recent errors
2137
- ```
2138
-
2139
- > **💡 Pro Tip**: Resources are perfect for monitoring, alerting, and real-time data feeds. They complement tools (one-time actions) by providing continuous data streams that AI assistants can subscribe to.
2140
-
2141
- ### Automatic Console Safety
2142
-
2143
- A major challenge in MCP is preventing `console.log` from corrupting the JSON-RPC communication over `STDOUT`. ArgParser solves this automatically.
2144
-
2145
- - **How it works**: When `--s-mcp-serve` is active, ArgParser hijacks the global `console` object.
2146
- - **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.
2147
- - **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**.
2148
-
2149
- ### Generating DXT Packages (`--s-build-dxt`)
2150
-
2151
- A Desktop Extension (`.dxt`) is a standardized package for installing your tools into Claude Desktop. ArgParser automates this process.
2152
-
2153
- ```bash
2154
- # 1. Generate the DXT package contents into a directory
2155
- my-cli-app --s-build-dxt ./my-dxt-package
2156
-
2157
- # The output folder contains everything needed: manifest.json, entry point, etc.
2158
- # A default logo will be applied if you don't provide one.
2159
-
2160
- # 2. (Optional) Pack the folder into a .dxt file for distribution
2161
- # (you can install the unpacked folder) directly in Claude Desktop > Settings > Extensions > Advanced
2162
- npx @anthropic-ai/dxt pack ./my-dxt-package
2163
-
2164
- # 3. (Optional) Sign the DXT package - this has not been well tested yet
2165
- npx @anthropic-ai/dxt sign ./my-dxt-package.dxt
2166
-
2167
- # Then drag & drop the .dxt file into Claude Desktop to install it, in the Settings > Extensions screen.
2168
-
2169
- # **IMPORTANT**:
2170
- # If you use ML models or packages that include binaries such as Sqlite3 or sharp, etc...
2171
- # You need to bundle the node_modules folder with your DXT package
2172
- # In order to do this, you need to use the following flag:
2173
- # First hard-install all the packages
2174
- rm -rf node_moduels
2175
- pnpm install --prod --linker hoisted
2176
- # Then bundle with node_modules
2177
- mycli --s-build-dxt ./my-dxt-package --s-with-node-modules
2178
- # then build the dxt bundle
2179
- npx @anthropic-ai/dxt pack ./my-dxt-package
2180
- # then upload the dxt bundle to Claude Desktop from the settings > extensions > advanced
2181
- ```
2182
-
2183
- ### Logo Configuration
2184
-
2185
- 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.
2186
-
2187
- You can customize the logo/icon that appears in Claude Desktop for your DXT package by configuring the `logo` property in your `serverInfo`:
2188
-
2189
- ```typescript
2190
- const cli = ArgParser.withMcp({
2191
- appName: "My CLI",
2192
- appCommandName: "mycli",
2193
- mcp: {
2194
- // This will appear in Claude Desktop's Extensions settings
2195
- serverInfo: {
2196
- name: "my-mcp-server",
2197
- version: "1.0.0",
2198
- description: "My CLI as an MCP server",
2199
- logo: "./assets/my-logo.png", // Local file path
2200
- },
2201
- },
2202
- });
2203
- ```
2204
-
2205
- If no custom logo is provided or loading fails, a default ArgParser logo is included
2206
-
2207
- #### Supported Logo Sources
2208
-
2209
- **Local File Path:**
2210
-
2211
- ```typescript
2212
- logo: "./assets/my-logo.png"; // Relative to your project
2213
- logo: "/absolute/path/to/logo.jpg"; // Absolute path
2214
- ```
2215
-
2216
- **HTTP/HTTPS URL:**
2217
-
2218
- ```typescript
2219
- logo: "https://example.com/logo.png"; // Downloaded automatically
2220
- logo: "https://cdn.example.com/icon.svg";
2221
- ```
2222
-
2223
- ### Including Additional Files in DXT Packages
2224
-
2225
- You can include additional files and directories in your DXT package using the `dxt.include` configuration. This is useful for bundling database migrations, configuration files, assets, or any other files your MCP server needs at runtime.
2226
-
2227
- ```typescript
2228
- const cli = ArgParser.withMcp({
2229
- appName: "My CLI",
2230
- appCommandName: "mycli",
2231
- mcp: {
2232
- serverInfo: {
2233
- name: "my-mcp-server",
2234
- version: "1.0.0",
2235
- description: "My CLI as an MCP server",
2236
- },
2237
- dxt: {
2238
- include: [
2239
- "migrations", // Copy entire migrations folder
2240
- "config/production.json", // Copy specific file
2241
- { from: "assets/logo.png", to: "logo.png" }, // Copy and rename file
2242
- { from: "scripts", to: "bin" }, // Copy folder with new name
2243
- ],
2244
- },
2245
- },
2246
- });
2247
- ```
2248
-
2249
- #### Include Options
2250
-
2251
- **Simple string paths** - Copy files/directories to the same relative location:
2252
-
2253
- ```typescript
2254
- include: [
2255
- "migrations", // Copies ./migrations/ to dxt/migrations/
2256
- "config/default.json", // Copies ./config/default.json to dxt/config/default.json
2257
- ];
2258
- ```
2259
-
2260
- **Object mapping** - Copy with custom destination paths:
2261
-
2262
- ```typescript
2263
- include: [
2264
- { from: "config/prod.json", to: "config.json" }, // Rename during copy
2265
- { from: "database/schema", to: "db/schema" }, // Copy to different path
2266
- ];
2267
- ```
2268
-
2269
- **Path Resolution**: All paths in the `from` field are resolved relative to your project root (where `package.json` and `tsconfig.json` are located).
2270
-
2271
- **Example Use Cases**:
2272
-
2273
- - Database migration files for initialization
2274
- - Configuration templates or defaults
2275
- - Static assets like images or documents
2276
- - Scripts or utilities needed at runtime
2277
- - Documentation or help files
2278
-
2279
- ### How DXT Generation Works
2280
-
2281
- When you run `--s-build-dxt`, ArgParser performs several steps to create a self-contained, autonomous package:
2282
-
2283
- 1. **Introspection**: It analyzes all tools defined with `.addTool()`.
2284
- 2. **Manifest Generation**: It creates a `manifest.json` file.
2285
- - Tool flags are converted into a JSON Schema for the `input_schema`.
2286
- - Flags with an `env` property (e.g., `{ name: 'apiKey', env: 'API_KEY' }`) provide universal `process.env` fallback/sync and are automatically added to the `user_config` section of the DXT manifest.
2287
- 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. If you have properly setup your node_modules (via `pnpm install --prod --node-linker=hoisted`) and pass `--s-with-node-nodules` to the bundling process, the resulting DXT will include all necessary dependencies, this is useful for projects that require native dependencies or have complex dependency trees.
2288
- 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`.
2289
-
2290
- ### DXT Bundling Strategies
2291
-
2292
- ArgParser offers two approaches for handling dependencies in DXT packages, depending on your project's needs.
2293
-
2294
- #### Standard Approach (Recommended for Most Projects)
2295
-
2296
- ```bash
2297
- # For pure JavaScript/TypeScript projects
2298
- your-cli --s-build-dxt
2299
- ```
2300
-
2301
- - **Best for**: Pure JS/TS projects without native dependencies
2302
- - **Bundle size**: Small (5-10MB typical)
2303
- - **Build time**: Fast
2304
- - **Dependencies**: Bundled automatically by TSDown
2305
-
2306
- #### Native Dependencies Approach
2307
-
2308
- ```bash
2309
- # For projects with native binaries (ONNX, Sharp, SQLite, etc.)
2310
- rm -rf node_modules
2311
- pnpm install --prod --node-linker=hoisted
2312
- your-cli --s-build-dxt --s-with-node-modules
2313
- ```
2314
-
2315
- - **Best for**: Projects using ONNX Runtime, Sharp, Canvas, SQLite, or other packages with `.node` binaries
2316
- - **Bundle size**: Larger (50-200MB typical)
2317
- - **Build time**: Longer (copies entire node_modules)
2318
- - **Dependencies**: Complete autonomy - no installation needed by Claude
2319
-
2320
- **When to use `--s-with-node-modules`:**
2321
-
2322
- - ✅ Your project uses machine learning packages (ONNX Runtime, TensorFlow bindings)
2323
- - ✅ You need image processing (Sharp, Canvas)
2324
- - ✅ You use database packages with native binaries (better-sqlite3, sqlite3)
2325
- - ✅ You want guaranteed compatibility without runtime installation
2326
- - ✅ Bundle size is acceptable for your use case
2327
-
2328
- **Required preparation steps:**
2329
-
2330
- 1. `rm -rf node_modules` - Clean slate for proper structure
2331
- 2. `pnpm install --prod --node-linker=hoisted` - Creates flat, symlink-free structure
2332
- 3. Add `--s-with-node-modules` flag to your build command
2333
-
2334
- The system automatically validates your setup and provides guidance if issues are detected.
2335
-
2336
- ### Typical Errors
2337
-
2338
- **Failed to run in Claude Desktop**:
2339
-
2340
- Claude Desktop is pretty finicky (as of Claude 0.12.28), and the built-in Node.js does not work with extensions built with `--s-with-node-modules` and installed via ArgParser (and I have no idea why because there's no debug info).
2341
- To resolve this, simply go to `Claude Desktop > Settings > Extensions > Advanced Settings` and turn **OFF** `Use Built-in Node.js for MCP`.
2342
-
2343
- Note that there are _many_ reasons for extensions not to work, if it does not work with Built-in or System Node.js, then something in your app is wrong. Feel free to join Alcyone Labs' discord for support: [Alcyone Labs' Discord](https://discord.gg/rRHhpz5nS5)
2344
-
2345
- **Failed to attach to MCP when downloading external assets**
2346
-
2347
- Sometimes, the MCP client needs to install external files, for example an ML model from HuggingFace or some task that takes more than 10 seconds to run. While it's working, Claude Desktop will display a `Cannot attach to MCP`, simply ignore it, Claude Desktop runs a ping every X seconds, and when it is running a long-running task, the ping will fail, but the task itself will still finish correctly.
2348
-
2349
- **Failed to generate DXT package**:
2350
-
2351
- If you encounter the following error running a command such as:
2352
-
2353
- ```bash
2354
- rm -rf node_modules
2355
- pnpm install --prod --node-linker=hoisted
2356
- bun src/index.ts --s-build-dxt ./dxt --s-with-node-modules
2357
-
2358
- -- Error generating DXT package: TSDown DXT build failed: EEXIST: file already exists, mkdir
2359
- ```
2360
-
2361
- Then run:
2362
-
2363
- ```bash
2364
- rm -rf ./dxt
2365
- bun src/index.ts --s-build-dxt ./dxt --s-with-node-modules
2366
- ```
2367
-
2368
- And it should work. TSDown is tasked to clean the outputDir first, but it won't if some files have been manually changed.
2369
-
2370
- ---
92
+ > 📖 **Full Documentation**: [docs/TUI.md](./docs/TUI.md) | [Component Reference](./docs/TUI_COMPONENTS.md)
2371
93
 
2372
94
  ## System Flags & Configuration
2373
95
 
2374
- 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.
2375
-
2376
- | Flag | Description |
2377
- | --------------------------- | -------------------------------------------------------------------------------------------------------------- |
2378
- | **MCP & DXT** | |
2379
- | `--s-mcp-serve` | Starts the application in MCP server mode, exposing all tools. |
2380
- | `--s-build-dxt [dir]` | Generates a complete, autonomous DXT package for Claude Desktop in the specified directory. |
2381
- | `--s-with-node-modules` | Use with `--s-build-dxt`. Includes complete node_modules in DXT package for projects with native dependencies. |
2382
- | `--s-mcp-transport <type>` | Overrides the MCP transport (`stdio`, `sse`, `streamable-http`). |
2383
- | `--s-mcp-transports <json>` | Overrides transports with a JSON array for multi-transport setups. |
2384
- | `--s-mcp-port <number>` | Sets the port for HTTP-based transports (`sse`, `streamable-http`). |
2385
- | `--s-mcp-host <string>` | Sets the host address for HTTP-based transports. |
2386
- | `--s-mcp-log-path <path>` | Sets the file path for MCP server logs (default: `./logs/mcp.log`). Overrides programmatic setting. |
2387
- | **Configuration** | |
2388
- | `--s-with-env <file>` | Loads configuration from a file (`.env`, `.json`, `.yaml`, `.toml`). CLI args take precedence. |
2389
- | `--s-save-to-env <file>` | Saves the current arguments to a configuration file, perfect for templates. |
2390
- | **Debugging** | |
2391
- | `--s-debug` | Prints a detailed, step-by-step log of the argument parsing process. |
2392
- | `--s-debug-print` | Exports the entire parser configuration to a JSON file for inspection. |
2393
- | `--s-enable-fuzzy` | Enables fuzzy testing mode—a dry run that parses args but skips handler execution. |
2394
-
2395
- ---
2396
-
2397
- ## Changelog
2398
-
2399
- ### v2.13.0
2400
-
2401
- **New Feature: Positional Arguments**
2402
-
2403
- Added support for positional (trailing) arguments, enabling more natural CLI syntax:
2404
-
2405
- ```bash
2406
- # Before: flags required
2407
- workflow show --id 8fadf090-xxx
2408
-
2409
- # After: positional syntax works too!
2410
- workflow show 8fadf090-xxx
2411
- ```
2412
-
2413
- Flags can now specify `positional: N` (1-indexed) to capture trailing arguments:
2414
-
2415
- ```typescript
2416
- .addFlag({
2417
- name: "id",
2418
- type: "string",
2419
- mandatory: true,
2420
- options: ["--id"], // Still works as fallback
2421
- positional: 1, // Captures first trailing arg
2422
- description: "Resource ID",
2423
- })
2424
- ```
2425
-
2426
- Key features:
2427
- - **Dual syntax**: Both `--flag value` and positional work interchangeably
2428
- - **Precedence**: Flag syntax takes priority if both provided
2429
- - **Multiple positional args**: Use `positional: 1`, `positional: 2`, etc.
2430
- - **Help text enhancement**: Shows usage pattern like `Usage: cmd [OPTIONS] <ID>`
2431
- - **Full validation**: Works with `mandatory`, type coercion, and enum validation
2432
-
2433
- See [Positional Arguments](#positional-arguments) for complete documentation.
2434
-
2435
- ### v2.12.3
2436
-
2437
- **Fixes**
2438
-
2439
- - Make sure that when setWorkingDir is used, the newly discovered .env override process.env variables
2440
- - Display subcommand descriptions on separate lines for better readability
2441
-
2442
- ### v2.12.2
2443
-
2444
- **Fixes**
2445
-
2446
- - Fix env config matching and improve working directory integration
2447
-
2448
- Explicitly call dotenv.config when an env file is auto-discovered
2449
- to populate process.env. This ensures flags with the 'env' property
2450
- can bind values from the discovered file.
2451
-
2452
- ### v2.12.0
2453
-
2454
- - Switch back to official @modelcontextprotocol/sdk as it now supports Zod V4, this resolves a security issue from a dependency in MCP SDK @ 1.16.0 branch.
2455
-
2456
- ### v2.11.0
2457
-
2458
- Working Directory Management & OpenTUI v2 Framework
2459
-
2460
- #### Working Directory Management (chdir)
2461
-
2462
- A major new capability for monorepo support and complex project structures:
2463
-
2464
- - **`setWorkingDirectory` Flag Property**: Designate any flag's value as the effective working directory. When used, `.env` file loading and relative path operations automatically resolve from this directory.
2465
- - **`rootPath` in Handler Context**: Access the original working directory (where the user ran the command) via `ctx.rootPath`. Perfect for displaying user-friendly paths or resolving user-provided files relative to their PWD.
2466
- - **Smart `.env` Auto-Discovery**: When used with `--s-with-env`, automatically discovers `.env.local`, `.env.dev`, `.env.test`, or `.env` in the effective working directory (priority order).
2467
- - **Protected Validation**: Warnings for invalid paths (nonexistent, not a directory) and multiple workspace flags.
2468
-
2469
- ```typescript
2470
- const parser = new ArgParser({
2471
- appName: "Monorepo CLI",
2472
- handler: async (ctx) => {
2473
- console.log("Effective cwd:", process.cwd()); // Changed by --workspace
2474
- console.log("User's cwd:", ctx.rootPath); // Original location
2475
- },
2476
- }).addFlag({
2477
- name: "workspace",
2478
- options: ["--workspace", "-w"],
2479
- type: "string",
2480
- setWorkingDirectory: true, // Makes this flag control the working directory
2481
- });
2482
- ```
2483
-
2484
- See [Working Directory Documentation](./docs/WORKING_DIRECTORY.md) for complete examples.
2485
-
2486
- #### OpenTUI v2 - Complete TUI Rewrite
2487
-
2488
- The TUI framework has been completely rewritten using **SolidJS** and **SST's OpenTUI** for a reactive, component-based architecture:
2489
-
2490
- - **Reactive Components**: `TuiProvider`, `VirtualList`, `MasterDetail`, `Breadcrumb` built on SolidJS signals.
2491
- - **Unified Provider**: `TuiProvider` handles mouse wheel reporting, terminal resize, TTY cleanup, and theme/shortcut contexts automatically.
2492
- - **Rich Theme System**: 6 built-in themes (`dark`, `light`, `monokai`, `dracula`, `nord`, `solarized`) with `Theme.from().extend()` for custom themes.
2493
- - **VirtualList**: Efficient virtualized scrolling with `createVirtualListController` for navigation control.
2494
- - **Slot-Based Layouts**: `MasterDetail` component with header, breadcrumb, footer, and customizable panel widths.
2495
- - **Hooks**: `useTui()` for viewport/exit, `useTheme()` for theming, plus mouse and virtual scroll hooks.
2496
- - **TTY Utilities**: Exported `cleanupTerminal`, `enableMouseReporting`, etc. for custom terminal control.
2497
-
2498
- ```tsx
2499
- import {
2500
- MasterDetail,
2501
- TuiProvider,
2502
- useTui,
2503
- VirtualList,
2504
- } from "@alcyone-labs/arg-parser/tui";
2505
- import { render } from "@opentui/solid";
2506
-
2507
- function App() {
2508
- const { viewportHeight, exit } = useTui();
2509
- const [idx, setIdx] = createSignal(0);
2510
-
2511
- return (
2512
- <MasterDetail
2513
- header="My App"
2514
- master={
2515
- <VirtualList items={DATA} selectedIndex={idx()} onSelect={setIdx} />
2516
- }
2517
- detail={<Details item={DATA[idx()]} />}
2518
- />
2519
- );
2520
- }
2521
-
2522
- render(() => (
2523
- <TuiProvider theme="dark" onScroll={(d) => setIdx((i) => i + d)}>
2524
- <App />
2525
- </TuiProvider>
2526
- ));
2527
- ```
2528
-
2529
- See [TUI Documentation](./docs/TUI.md) for complete API reference and examples.
2530
-
2531
- #### Other Improvements
2532
-
2533
- - **Data-Safe Logging**: Integrated `@alcyone-labs/simple-mcp-logger` for STDOUT-safe logging.
2534
- - **Bun Configuration**: Added `bunfig.toml` with OpenTUI preload for native JSX support.
2535
- - **New Examples**: `aquaria-trace-viewer.tsx`, `framework-demo.tsx`, `template-demo.tsx`, `tui-demo-v2.tsx`.
2536
-
2537
- ### v2.10.3
2538
-
2539
- **Flag Inheritance Improvements**
2540
-
2541
- - **Full Chain Inheritance**: Introduced `FlagInheritance.AllParents` option to support deep flag propagation. This fixes issues where nested sub-commands (e.g., `root > mid > leaf`) failed to inherit root flags when constructed bottom-up.
2542
- - **Granular Control**: New `FlagInheritance` configuration object provides clear options: `NONE`, `DirectParentOnly` (legacy behavior), and `AllParents`.
2543
- - **Type Safety**: New `TFlagInheritance` type definition for better TypeScript support.
2544
- - **Backward Compatibility**: Kept `inheritParentFlags` for legacy behavior, but now it's just an alias for `FlagInheritance.DirectParentOnly`.
2545
-
2546
- **Auto-Help Features**
2547
-
2548
- - **Programmatic Help**: Added `ctx.displayHelp()` method to command handlers, allowing easy help display from within your logic.
2549
- - **Auto-Trigger**: Added `triggerAutoHelpIfNoHandler` option to automatically show help messages for "container" commands that don't have their own handler.
2550
- - **Helper Function**: Exported `autoHelpHandler` utility for quick setup of help-only commands. This can be passed as `setHandler(autoHelpHandler)` or `handler: autoHelpHandler` depending on your API of choice.
2551
-
2552
- ### v2.10.2
2553
-
2554
- **OpenTUI Improvements**
2555
-
2556
- - **Soft Wrapping**: Added `wrapText` (boolean) to `ScrollArea` component. When enabled, text automatically reflows to fit the container width (preventing clipping).
2557
- - **ANSI Preservation**: Soft-wrapping logic is ANSI-aware; color and style states are correctly carried over to wrapped lines.
2558
-
2559
- ### v2.10.1
2560
-
2561
- - **Bug Fixes**:
2562
- - Fixed a crash in `Terminal.moveCursor` when running in certain environments where `node:readline` utilities were inaccessible. Switched to direct ANSI escape codes for cursor positioning.
2563
-
2564
- ### v2.10.0 - OpenTUI integration + IFlag "env" property now first-class citizen
2565
-
2566
- #### OpenTUI Integration
2567
-
2568
- - **OpenTUI**: Integrated a complete Terminal User Interface (TUI) framework into the library core.
2569
- - **StackNavigator**: Standardized UX for deep navigation with `Enter`/`Right` to push and `Esc`/`Left` to pop views.
2570
- - **Reactive Themes**: Centralized `ThemeManager` with `Default`, `Ocean` (High-Contrast), and `Monokai` presets.
2571
- - **Scroll Performance**: ANSI-aware left-side scrollbars with automatic height calculation and scroll-state management.
2572
- - **Mouse Integration**: Native SGR mouse reporting for wheel scrolling and hit-detected clicks.
2573
- - **Safety**: Robust TTY restoration and process-level cleanup to prevent terminal lockups on exit or crash.
2574
- - **Components**: Exported `List`, `ScrollArea`, `Input`, and `SplitLayout` under the `UI` namespace.
2575
-
2576
- #### Universal Environment Variable Support
2577
-
2578
- - **Universal `env` Support**: The `env` property is now a core feature available to all commands and tools, not just DXT/MCP contexts.
2579
- - **Resolution Priority**: Implemented strict precedence: **CLI Flag > Environment Variable > Default Value**.
2580
- - **Reverse Sync**: Resolved flag values (from CLI or Env) are now automatically synced back to `process.env`, ensuring downstream code sees the correct configuration.
2581
- - **Flexible Mapping**: Supports both string and array-of-strings for `env` (first match wins).
2582
- - **Automatic Type Conversion**: Environment variables are automatically coerced to the flag's defined type (Number, Boolean, etc.).
2583
-
2584
- ### v2.8.2
2585
-
2586
- - UX: Help shows example values via `valueHint` for non-boolean flags; repeatable flags display 'Multiple values allowed (repeat flag)' with example; examples use `valueHint` when present.
2587
- - Types: Added `IFlag.valueHint?: string`; accepted by `zodFlagSchema`; included in processed flags; supported in manifest-driven dynamic flags.
2588
- - Examples: `examples/core/dynamic-flags-demo.ts` updated to demonstrate `valueHint` for `--url`.
2589
-
2590
- ### v2.8.1
2591
-
2592
- - Feature: Dynamic flags via `IFlag.dynamicRegister(ctx)` to register additional flags at runtime (e.g., from a manifest file)
2593
- - Help: `--help` preloads dynamic flags without executing handlers; help output includes both static and dynamic flags
2594
- - Flow: Two-phase parsing (load dynamic flags → re-parse with full flag set)
2595
- - Cleanup: Dynamically registered flags are reset between parses to avoid accumulation
2596
- - Types: Exported `DynamicRegisterContext` and `DynamicRegisterFn`
2597
- - Internal: `FlagManager.removeFlag(name)` to support cleanup
2598
-
2599
- ### v2.7.2
2600
-
2601
- **Feat**
2602
-
2603
- **MCP**:
2604
-
2605
- - outputSchema is now included in MCP tool registration for MCP 2025-06-18+ clients and will generate a JSON Schema in `tools/list` responses to make JSON introspection easier.
2606
-
2607
- **Fixes and Changes**
2608
-
2609
- **MCP**:
2610
-
2611
- - The app parameter in configureExpress: (app) => {} is now fully typed to improve intellisense.
2612
- - Express' x-powered-by was disabled by default. It can be re-enabled or changed via configureExpress as needed.
2613
- - Logger parameters were still not fully functional and log level was still ignored, this has been fixed.
2614
-
2615
- ### v2.7.0
2616
-
2617
- **Feat**
2618
-
2619
- **MCP**:
2620
-
2621
- - Add support for CORS and authentication options, enabling powerful tools to serve Web UIs and publicly exposed APIs
2622
- - Add supports for configuring express by exposing the app before it runs
2623
-
2624
- **CLI**:
2625
-
2626
- - Add support for NOT automatically executing the CLI if the script is imported, but will execute if called directly as a CLI. This enables use cases such as programmatically loading the CLI and scanning for tools or testing it from another script via the --s-enable-fuzzy flag or your own script.
2627
-
2628
- ### v2.6.0
2629
-
2630
- **Feat**
2631
-
2632
- **DXT**:
2633
-
2634
- - Improve how paths and dynamic variables are handled when bundling into a DXT, to improve compatibility and reduce paths that will fail in a sandbox when the CLI / MCP expects path available on the system. Dynamic path resolution with `${VARIABLE}` syntax supporting `${HOME}`, `${DOCUMENTS}`, `${__dirname}`, `${DXT_DIR}`, and more. Context-aware path resolution with `DxtPathResolver.createUserDataPath()`, `createTempPath()`, `createConfigPath()`.
2635
- - Add new IFlag.dxtOption set of options for each flag to allow finer control on how the flags are perceived on the DXT manifest / Claude Desktop.
2636
-
2637
- Read more her: [DXT Package User Configuration & Path Handling](#dxt-package-user-configuration--path-handling)
2638
-
2639
- **Fixes and Changes**
2640
-
2641
- **DXT**:
2642
-
2643
- - Improve handling of sensitive env variable, they were previously always showing as sensitive.
2644
-
2645
- **Known Limitations**
2646
-
2647
- **DXT**:
2648
-
2649
- The DXT bundling / packing / unpacking / launching process is notoriously early and brittle. There are many reasons something is not working, but **MOST** importantly it will not work if:
2650
-
2651
- 1. You are bundling a package in a mono-repo (you will need to temporarily create a pnpm-workspace.yaml file for example to break the hierarchy)
2652
- 2. You do _not_ hard-install your node_modules as detailed in the documentation (it will only work if the node_modules are hard installed)
2653
- 3. In some cases if your CLI entrypoint does not run a main loop (see documentation for working examples)
2654
- 4. If you use PATH-dependent variables (for example relying on ~/.config/path/to/some.json). This has been addressed in v2.6.0, but you have to make sure you use the correct patterns (see documentation)
2655
-
2656
- ### v2.5.0
2657
-
2658
- **Feat**
2659
-
2660
- - **Zod Schema Flags**: You can now use Zod schemas as flag types for structured JSON input validation. This enables complex object validation with automatic JSON Schema generation for MCP clients while maintaining full type safety and CLI compatibility.
2661
- - **Improved MCP Tool Documentation**: Zod schema descriptions automatically become MCP tool parameter documentation
2662
-
2663
- ### v2.4.2
2664
-
2665
- **Fixes and Changes**
2666
-
2667
- - add missing MCP lifecycle event documentation
2668
- - fix the behavior of the withMcp() options.mcp.log that was not working as expected
2669
-
2670
- ### v2.4.1
2671
-
2672
- **Fixes and Changes**
2673
-
2674
- - switch to NPM version of @alcyone-labs/modelcontextprotocol-sdk to freeze the dependency and avoid side-effects
2675
-
2676
- ### v2.4.0
2677
-
2678
- **Feat**
2679
-
2680
- - MCP client now supports initialization during the client 'initialize' call, which allows to do certain things such as establishing database connection or even running migrations
2681
- - MCP client now sanitizes the method names to ensure spec-compliants MCP behavior, names that collision will be logged
2682
- - There were some use-cases where the DXT bundling failed, this new release addresses all of them, namely:
2683
- 1. Output structure will match that of the input so relative files (for example DB migrations) will work
2684
- 2. Deeper folder structure was previously not working
2685
- - DXT bundling now supports including resources via options: `{dxt: {include: ['TSDown blob-like paths']}`
2686
- - Logger was improved to support log level via `options:{ log: {} }` so you can set it to level: 'debug' and the MCP log will contain 100% of the console output, logPath setting was not impacted
2687
-
2688
- **Fixes and Changes**
2689
-
2690
- - Zod has been upgraded to V4 and no issue was identified (but @modelcontextprotocol/sdk had to be upgraded to V4 as well, which was more challenging).
2691
-
2692
- ### v2.3.0
2693
-
2694
- The DXT bundling is working pretty well now, and we have had a lot of success building, bundling and running various extensions. If you see issues, feel free to open an Issue on GitHub with details, or ask about it on [Alcyone Labs' Discord](https://discord.gg/rRHhpz5nS5)
2695
-
2696
- Make sure to clearly identify if you need to include the node_modules or not. In doubt, include them using `--s-with-node-modules`
2697
-
2698
- **Feat**
2699
-
2700
- - **New `--s-with-node-modules` flag**: Create fully autonomous DXT packages that include complete native dependencies. Perfect for projects using ONNX Runtime, Sharp, SQLite, or other packages with `.node` binaries. Use `rm -rf ./node_modules && pnpm install --prod --node-linker=hoisted` followed by `my-cli --s-build-dxt ./dxt --s-with-node-modules` to create self-contained packages that work without Claude needing to install dependencies.
2701
- Note that when bundling with node_modules, it's likely that the built-in Node.js will not work with that extension, so go to `Claude Desktop > Settings > Extensions > Advanced Settings` and turn **OFF** `Use Built-in Node.js for MCP`.
2702
-
2703
- ### v2.2.1
2704
-
2705
- **Feat**
2706
-
2707
- - You can now specify logPath for the MCP output and easily disambiguate what the path is relative to (`__dirname` versus `process.cwd()` versus absolute)
2708
-
2709
- **Fixes and changes**
2710
-
2711
- - Fixes an issue where building a DXT package via `--s-build-dxt` would generate an invalid package if the entry_point was a TypeScript .ts file.
2712
-
2713
- ### v2.2.0
2714
-
2715
- **Feat**
2716
-
2717
- - IFlag function-based `type` now supports async methods such as `type: async () => Promise<string>`.
2718
-
2719
- **Fixes and changes**
2720
-
2721
- - `.parse()` can now work without arguments, it will try to infer that if you are in CLI mode and on a Node environment, it should use `process.argv` as the input. You can still pass parameters to control more granularly.
2722
- - `--s-build-dxt` now takes an optional path to specify where to prepare the assets prior to packing, the path you pass is in relation to process.cwd() (current working directory).
2723
- - `--s-build-dxt` logo detection now resolves paths more accurately...
2724
-
2725
- ### v2.1.1
2726
-
2727
- **Fixes and changes**
2728
-
2729
- - Fix missing missing types fr
2730
-
2731
- ### v2.1.0
2732
-
2733
- **Feat**
2734
-
2735
- - IFlag function-based `type` handling must now define the type it returns, this unlocks nice features such as providing nicer Intellisense, `output schemas` support and makes it easier to upgrade to Zod V4
2736
- - Add support for MCP output_schema field for clients that support it, CLI isn't impacted by it, this helps a lot the interactivity, self-documentation, and improves the API guarantees
2737
-
2738
- **Fixes and changes**
2739
-
2740
- - Improved MCP version compliance
2741
-
2742
- ### v2.0.0
2743
-
2744
- - **Unified Tool Architecture**: Introduced `.addTool()` to define CLI subcommands and MCP tools in a single declaration.
2745
- - **Universal Environment Variables Support**: The `env` property on any `IFlag` now provides native `process.env` fallback/sync logic for all commands, while maintaining its role in generating `user_config` entries for DXT manifests.
2746
- - **Enhanced DXT Generation**: The `env` property on flags now automatically generates `user_config` entries in the DXT manifest.
2747
- - **Automatic Console Safety**: Console output is automatically and safely redirected in MCP mode to prevent protocol contamination.
2748
- - **Breaking Changes**: The `addMcpSubCommand()` and separate `addSubCommand()` for MCP tools are deprecated in favor of `addTool()` and `--s-mcp-serve`.
2749
-
2750
- ### v1.3.0
2751
-
2752
- - **Plugin System & Architecture**: Refactored to a dependency-injection model, making the core library dependency-free. Optional plugins for TOML/YAML.
2753
- - **Global Console Replacement**: Implemented the first version of automatic console suppression for MCP compliance.
2754
- - **Autonomous Build Improvements**: Significantly reduced DXT bundle size and removed dynamic `require` issues.
2755
-
2756
- ### v1.2.0
2757
-
2758
- - **Critical MCP Fixes**: Resolved issues where MCP tools with output schemas would fail. Ensured correct JSON-RPC 2.0 response formatting.
2759
- - **Enhanced Handler Context**: Added `isMcp` flag to the handler context for more reliable mode detection.
2760
-
2761
- ### v1.1.0
2762
-
2763
- - **Major Features**: First release with MCP Integration, System Flags (`--s-debug`, `--s-with-env`, etc.), and environment loading from files.
2764
-
2765
- ---
2766
-
2767
- ## Backlog
96
+ ArgParser includes built-in `--s-*` flags for development and debugging.
2768
97
 
2769
- - [x] Publish as an open-source library
2770
- - [x] Make ArgParser compatible with MCP out-of-the-box
2771
- - [x] Rename --LIB-\* flags to --s-\*
2772
- - [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)
2773
- - [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)
2774
- - [x] Add support for async type function to enable more flexibility
2775
- - [x] Upgrade to Zod/V4 (V4 does not support functions well, this will take more time, not a priority)
2776
- - [ ] Add System flags to args.systemArgs
2777
- - [ ] Improve flag options collision prevention
2778
- - [ ] (potentially) add support for fully typed parsed output, this has proven very challenging
2779
- - [ ] Add support for locales / translations
98
+ | Flag | Description |
99
+ | --------------------------- | --------------------------------------------------------------------------- |
100
+ | `--s-mcp-serve` | Starts the application in MCP server mode. |
101
+ | `--s-build-dxt [dir]` | Generates a DXT package for Claude Desktop. |
102
+ | `--s-with-env <file>` | Loads configuration from a file (`.env`, `.json`, etc.). |
103
+ | `--s-save-to-env <file>` | Saves current arguments to a configuration file. |
104
+ | `--s-debug` | Prints a detailed log of the argument parsing process. |
2780
105
 
2781
- ### (known) Bugs / DX improvement points
106
+ ## Links
2782
107
 
2783
- - [ ] 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
108
+ - 📜 **[Changelog](./CHANGELOG.md)**
109
+ - 📋 **[Backlog](./BACKLOG.md)**
110
+ - 💬 **[Discord Support](https://discord.gg/rRHhpz5nS5)**