@alcyone-labs/arg-parser 2.13.1 → 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.
Files changed (2) hide show
  1. package/README.md +45 -2728
  2. package/package.json +1 -1
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
- - [MCP & Claude Desktop Integration](#mcp--claude-desktop-integration)
40
- - [Output Schema Support](#output-schema-support)
41
- - [Basic Usage](#basic-usage)
42
- - [Predefined Schema Patterns](#predefined-schema-patterns)
43
- - [Custom Zod Schemas](#custom-zod-schemas)
44
- - [MCP Version Compatibility](#mcp-version-compatibility)
45
- - [Automatic Error Handling](#automatic-error-handling)
46
- - [Writing Effective MCP Tool Descriptions](#writing-effective-mcp-tool-descriptions)
47
- - [Best Practices for Tool Descriptions](#best-practices-for-tool-descriptions)
48
- - [Complete Example: Well-Documented Tool](#complete-example-well-documented-tool)
49
- - [Parameter Description Guidelines](#parameter-description-guidelines)
50
- - [Common Pitfalls to Avoid](#common-pitfalls-to-avoid)
51
- - [Automatic MCP Server Mode (`--s-mcp-serve`)](#automatic-mcp-server-mode---s-mcp-serve)
52
- - [MCP Transports](#mcp-transports)
53
- - [Adding custom HTTP routes (e.g., /health)](#adding-custom-http-routes-eg-health)
54
- - [CORS and Authentication for streamable-http](#cors-and-authentication-for-streamable-http)
55
- - [Multiple transports and improved logging](#multiple-transports-and-improved-logging)
56
- - [MCP Logging Configuration](#mcp-logging-configuration)
57
- - [Enhanced Logging (Recommended)](#enhanced-logging-recommended)
58
- - [Simple Logging Configuration](#simple-logging-configuration)
59
- - [Configuration Priority](#configuration-priority)
60
- - [Configuration Merging](#configuration-merging)
61
- - [Path Resolution Options](#path-resolution-options)
62
- - [MCP Lifecycle Events](#mcp-lifecycle-events)
63
- - [MCP Resources - Real-Time Data Feeds](#mcp-resources---real-time-data-feeds)
64
- - [Basic Resource Setup](#basic-resource-setup)
65
- - [URI Templates with Dynamic Parameters](#uri-templates-with-dynamic-parameters)
66
- - [MCP Subscription Lifecycle](#mcp-subscription-lifecycle)
67
- - [Usage Examples](#usage-examples)
68
- - [Design Patterns](#design-patterns)
69
- - [Automatic Console Safety](#automatic-console-safety)
70
- - [Generating DXT Packages (`--s-build-dxt`)](#generating-dxt-packages---s-build-dxt)
71
- - [Logo Configuration](#logo-configuration)
72
- - [Supported Logo Sources](#supported-logo-sources)
73
- - [Including Additional Files in DXT Packages](#including-additional-files-in-dxt-packages)
74
- - [Include Options](#include-options)
75
- - [How DXT Generation Works](#how-dxt-generation-works)
76
- - [DXT Bundling Strategies](#dxt-bundling-strategies)
77
- - [Standard Approach (Recommended for Most Projects)](#standard-approach-recommended-for-most-projects)
78
- - [Native Dependencies Approach](#native-dependencies-approach)
79
- - [Typical Errors](#typical-errors)
80
13
  - [System Flags & Configuration](#system-flags--configuration)
81
- - [Changelog](#changelog)
82
- - [v2.13.1](#v2131)
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,2169 +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
- });
797
- ```
798
-
799
- #### DXT Variables & Path Resolution
800
-
801
- ArgParser automatically resolves paths based on your runtime environment:
802
-
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
- ```
927
-
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
62
+ await cli.parse();
966
63
  ```
967
64
 
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"
65
+ ## Documentation
981
66
 
982
- // Number flags
983
- --count 42 → 42
984
- --port=8080 → 8080
67
+ For detailed information, please refer to the following guides:
985
68
 
986
- // Boolean flags (flagOnly: true)
987
- --verbose → true
988
- (no flag) false
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.
989
74
 
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
-
1210
- ```bash
1211
- workflow show --id 8fadf090-xxx
1212
- ```
1213
-
1214
- **After:**
1215
-
1216
- ```bash
1217
- workflow show 8fadf090-xxx
1218
- ```
1219
-
1220
- #### Basic Usage
1221
-
1222
- Add the `positional` property to a flag definition. The value is 1-indexed (first trailing arg = 1, second = 2, etc.):
1223
-
1224
- ```typescript
1225
- const cli = new ArgParser()
1226
- .addFlag({
1227
- name: "id",
1228
- type: "string",
1229
- mandatory: true,
1230
- options: ["--id"], // Fallback syntax: --id <value>
1231
- positional: 1, // Primary: captures first trailing arg
1232
- description: "Resource ID to show",
1233
- valueHint: "ID", // Used in help text: <ID>
1234
- })
1235
- .setHandler((ctx) => {
1236
- console.log(`Showing: ${ctx.args.id}`);
1237
- });
1238
-
1239
- // Both work:
1240
- // cli.parse(["abc123"]) → id = "abc123"
1241
- // cli.parse(["--id", "abc123"]) → id = "abc123"
1242
- ```
1243
-
1244
- #### Multiple Positional Arguments
1245
-
1246
- Capture multiple trailing arguments using different positional indices:
1247
-
1248
- ```typescript
1249
- const cli = new ArgParser().addFlags([
1250
- {
1251
- name: "source",
1252
- type: "string",
1253
- mandatory: true,
1254
- options: ["--source", "-s"],
1255
- positional: 1, // First trailing arg
1256
- valueHint: "SOURCE",
1257
- },
1258
- {
1259
- name: "dest",
1260
- type: "string",
1261
- mandatory: true,
1262
- options: ["--dest", "-d"],
1263
- positional: 2, // Second trailing arg
1264
- valueHint: "DEST",
1265
- },
1266
- ]);
1267
-
1268
- // Usage: copy file.txt backup/
1269
- // Result: source = "file.txt", dest = "backup/"
1270
- ```
1271
-
1272
- #### Precedence Rules
1273
-
1274
- - **Flag syntax takes priority**: If both `--flag value` AND a positional arg are provided, the flag value is used
1275
- - **Either satisfies mandatory**: A mandatory flag is satisfied by EITHER positional or flag syntax
1276
- - **Order matters**: Positional args are assigned in index order (1, 2, 3...)
1277
- - **Type coercion applies**: Positional values go through the same type coercion as flag values
1278
-
1279
- #### Help Text
1280
-
1281
- When positional arguments are defined, help text automatically shows a usage pattern:
1282
-
1283
- ```
1284
- Usage: workflow show [OPTIONS] <ID>
1285
-
1286
- Flags:
1287
- --id Resource ID to show
1288
- Type: string
1289
- Example: --id value
1290
- Positional argument #1
1291
- ```
1292
-
1293
- Mandatory positional args appear as `<NAME>`, optional as `[NAME]`.
1294
-
1295
- ### Automatic Help Display
1296
-
1297
- ArgParser provides features to automatically show help messages when a command is invoked incorrectly or as a "container" command.
1298
-
1299
- - **`ctx.displayHelp()`**: Programmatically trigger help for the current command from within its handler.
1300
- - **`autoHelpHandler`**: A pre-built handler for container commands (e.g., `git remote`) that simply displays the help text.
1301
- - **`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.
1302
-
1303
- For more details, see the [Automatic Help Display Guide](docs/DISPLAY_HELP.md) and the [example demo](examples/auto-help-demo.ts).
1304
-
1305
- ---
1306
-
1307
- ## MCP & Claude Desktop Integration
1308
-
1309
- ### Output Schema Support
1310
-
1311
- 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.
1312
-
1313
- **When do I need output schemas?**
1314
-
1315
- - ❌ **CLI-only usage**: Never needed - skip this section entirely
1316
- - ✅ **MCP integration**: Optional but recommended for better structured responses
1317
- - ✅ **Claude Desktop**: Helpful for Claude to understand your tool's output format
1318
-
1319
- **Key Points:**
1320
-
1321
- - ✅ **CLI works perfectly without them**: Your command-line interface is unaffected
1322
- - ✅ **MCP-only feature**: Only used when running with `--s-mcp-serve`
1323
- - ✅ **Version-aware**: Automatically included only for compatible MCP clients (v2025-06-18+)
1324
- - ✅ **Flexible**: Use predefined patterns or custom Zod schemas
1325
-
1326
- #### Basic Usage
1327
-
1328
- ```typescript
1329
- import { z } from "zod";
1330
-
1331
- .addTool({
1332
- name: "process-file",
1333
- description: "Process a file",
1334
- flags: [
1335
- { name: "path", options: ["--path"], type: "string", mandatory: true }
1336
- ],
1337
- // Optional: Only needed if you want structured MCP responses
1338
- // CLI mode works exactly the same whether this is present or not
1339
- outputSchema: {
1340
- success: z.boolean().describe("Whether processing succeeded"),
1341
- filePath: z.string().describe("Path to the processed file"),
1342
- size: z.number().describe("File size in bytes"),
1343
- lastModified: z.string().describe("Last modification timestamp")
1344
- },
1345
- handler: async (ctx) => {
1346
- // Your logic here - same code for both CLI and MCP
1347
- // The outputSchema doesn't change how this function works
1348
- return {
1349
- success: true,
1350
- filePath: ctx.args.path,
1351
- size: 1024,
1352
- lastModified: new Date().toISOString()
1353
- };
1354
- }
1355
- })
1356
-
1357
- // CLI usage (outputSchema ignored): mycli process-file --path /my/file.txt
1358
- // MCP usage (outputSchema provides structure): mycli --s-mcp-serve
1359
- ```
1360
-
1361
- #### Predefined Schema Patterns
1362
-
1363
- For common use cases, use predefined patterns:
1364
-
1365
- ```typescript
1366
- // For simple success/error responses
1367
- outputSchema: "successError";
1368
-
1369
- // For operations that return data
1370
- outputSchema: "successWithData";
1371
-
1372
- // For file operations
1373
- outputSchema: "fileOperation";
1374
-
1375
- // For process execution
1376
- outputSchema: "processExecution";
1377
-
1378
- // For list operations
1379
- outputSchema: "list";
1380
- ```
1381
-
1382
- #### Custom Zod Schemas
1383
-
1384
- For complex data structures:
1385
-
1386
- ```typescript
1387
- outputSchema: z.object({
1388
- analysis: z.object({
1389
- summary: z.string(),
1390
- wordCount: z.number(),
1391
- sentiment: z.enum(["positive", "negative", "neutral"]),
1392
- }),
1393
- metadata: z.object({
1394
- timestamp: z.string(),
1395
- processingTime: z.number(),
1396
- }),
1397
- });
1398
- ```
1399
-
1400
- #### MCP Version Compatibility
1401
-
1402
- Output schemas are automatically handled based on MCP client version:
1403
-
1404
- - **MCP v2025-06-18+**: Full output schema support with `structuredContent`
1405
- - **Earlier versions**: Schemas ignored, standard JSON text response only
1406
-
1407
- To explicitly set the MCP version for testing:
1408
-
1409
- ```typescript
1410
- const cli = ArgParser.withMcp({
1411
- // ... your config
1412
- }).setMcpProtocolVersion("2025-06-18"); // Enable output schema support
1413
- ```
1414
-
1415
- **Important**:
1416
-
1417
- - **CLI users**: You can ignore MCP versions entirely - they don't affect command-line usage
1418
- - **MCP users**: ArgParser handles version detection automatically based on client capabilities
1419
-
1420
- #### Automatic Error Handling
1421
-
1422
- ArgParser automatically handles errors differently based on execution context, so your handlers can simply throw errors without worrying about CLI vs MCP mode:
1423
-
1424
- ```typescript
1425
- const cli = ArgParser.withMcp({
1426
- // ... config
1427
- }).addTool({
1428
- name: "process-data",
1429
- handler: async (ctx) => {
1430
- // Simply throw errors - ArgParser handles the rest automatically
1431
- if (!ctx.args.apiKey) {
1432
- throw new Error("API key is required");
1433
- }
1434
-
1435
- // Do your work and return results
1436
- return { success: true, data: processedData };
1437
- },
1438
- });
1439
- ```
1440
-
1441
- **How it works:**
1442
-
1443
- - **CLI mode**: Thrown errors cause the process to exit with error code 1
1444
- - **MCP mode**: Thrown errors are automatically converted to structured MCP error responses
1445
- - **No manual checks needed**: Handlers don't need to check `ctx.isMcp` or handle different response formats
1446
-
1447
- ### Writing Effective MCP Tool Descriptions
1448
-
1449
- **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.
1450
-
1451
- #### Best Practices for Tool Descriptions
1452
-
1453
- **1. Start with the action** - Begin with a clear verb describing what the tool does:
1454
-
1455
- ```typescript
1456
- // ✅ Good: Action-first, specific
1457
- description: "Analyzes text files and returns detailed statistics including word count, character count, and sentiment analysis";
1458
-
1459
- // ❌ Avoid: Vague or noun-heavy
1460
- description: "File analysis tool";
1461
- ```
1462
-
1463
- **2. Include context and use cases** - Explain when and why to use the tool:
1464
-
1465
- ```typescript
1466
- // ✅ Good: Provides context
1467
- 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.";
1468
-
1469
- // ❌ Avoid: No context
1470
- description: "Converts images";
1471
- ```
1472
-
1473
- **3. Mention key parameters and constraints** - Reference important inputs and limitations:
1474
-
1475
- ```typescript
1476
- // ✅ Good: Mentions key parameters and constraints
1477
- 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.";
1478
-
1479
- // ❌ Avoid: No parameter guidance
1480
- description: "Searches files";
1481
- ```
1482
-
1483
- **4. Be specific about outputs** - Describe what the tool returns:
1484
-
1485
- ```typescript
1486
- // ✅ Good: Clear output description
1487
- 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.";
1488
-
1489
- // ❌ Avoid: Unclear output
1490
- description: "Analyzes code";
1491
- ```
1492
-
1493
- #### Complete Example: Well-Documented Tool
1494
-
1495
- ```typescript
1496
- .addTool({
1497
- name: "analyze-repository",
1498
- 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.",
1499
- flags: [
1500
- {
1501
- name: "path",
1502
- description: "Path to the Git repository root directory",
1503
- options: ["--path", "-p"],
1504
- type: "string",
1505
- mandatory: true,
1506
- },
1507
- {
1508
- name: "include-dependencies",
1509
- description: "Include analysis of package.json dependencies and security vulnerabilities",
1510
- options: ["--include-dependencies", "-d"],
1511
- type: "boolean",
1512
- flagOnly: true,
1513
- },
1514
- {
1515
- name: "output-format",
1516
- description: "Output format for the analysis report",
1517
- options: ["--output-format", "-f"],
1518
- type: "string",
1519
- choices: ["json", "markdown", "html"],
1520
- defaultValue: "json",
1521
- }
1522
- ],
1523
- handler: async (ctx) => {
1524
- // Implementation here
1525
- }
1526
- })
1527
- ```
1528
-
1529
- #### Parameter Description Guidelines
1530
-
1531
- Each flag should have a clear, concise description:
1532
-
1533
- ```typescript
1534
- // ✅ Good parameter descriptions
1535
- {
1536
- name: "timeout",
1537
- description: "Maximum execution time in seconds (default: 30, max: 300)",
1538
- options: ["--timeout", "-t"],
1539
- type: "number",
1540
- }
1541
-
1542
- {
1543
- name: "verbose",
1544
- description: "Enable detailed logging output including debug information",
1545
- options: ["--verbose", "-v"],
1546
- type: "boolean",
1547
- flagOnly: true,
1548
- }
1549
-
1550
- {
1551
- name: "format",
1552
- description: "Output format for results (json: structured data, csv: spreadsheet-friendly, pretty: human-readable)",
1553
- options: ["--format"],
1554
- type: "string",
1555
- choices: ["json", "csv", "pretty"],
1556
- }
1557
- ```
1558
-
1559
- #### Common Pitfalls to Avoid
1560
-
1561
- - **Don't be overly technical**: Avoid jargon that doesn't help with tool selection
1562
- - **Don't repeat the tool name**: The name is already visible, focus on functionality
1563
- - **Don't use generic terms**: "Process data" or "handle files" are too vague
1564
- - **Don't forget constraints**: Mention important limitations or requirements
1565
- - **Don't ignore parameter descriptions**: Each flag should have a helpful description
1566
-
1567
- **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.
1568
-
1569
- ### Automatic MCP Server Mode (`--s-mcp-serve`)
1570
-
1571
- 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).
1572
-
1573
- ```bash
1574
- # This single command starts a fully compliant MCP server
1575
- my-cli-app --s-mcp-serve
1576
-
1577
- # You can also override transports and ports using system flags
1578
- my-cli-app --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3001
1579
-
1580
- # Configure custom log file path for MCP server logs
1581
- my-cli-app --s-mcp-serve --s-mcp-log-path ./custom-logs/mcp-server.log
1582
-
1583
- # Or configure logging programmatically in withMcp()
1584
- const cli = ArgParser.withMcp({
1585
- appName: 'My CLI App',
1586
- appCommandName: 'my-cli-app',
1587
- mcp: {
1588
- serverInfo: { name: 'my-server', version: '1.0.0' },
1589
- // NEW: Improved logging with level control
1590
- log: {
1591
- level: 'info', // Captures info, warn, error
1592
- logToFile: './my-logs/mcp-server.log',
1593
- prefix: 'MyApp'
1594
- }
1595
- // LEGACY: logPath: './my-logs/mcp-server.log' // Still works
1596
- }
1597
- });
1598
- ```
1599
-
1600
- ### MCP Transports
1601
-
1602
- You can define the transports directly in the .withMcp() settings, or override them via the `--s-mcp-transport(s)` flags.
1603
-
1604
- ```bash
1605
- # Single transport
1606
- my-tool --s-mcp-serve --s-mcp-transport stdio
1607
-
1608
- # Multiple transports via JSON
1609
- my-tool --s-mcp-serve --s-mcp-transports '[{"type":"stdio"},{"type":"sse","port":3001}]'
1610
-
1611
- # Single transport with custom options
1612
- my-tool --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3000 --s-mcp-host 0.0.0.0
1613
-
1614
- # Streamable HTTP CORS/auth via CLI flags (JSON strings)
1615
- my-tool --s-mcp-serve \
1616
- --s-mcp-transport streamable-http \
1617
- --s-mcp-port 3002 --s-mcp-path /api/mcp \
1618
- --s-mcp-cors '{"origins":["http://localhost:5173"],"credentials":true,"methods":["GET","POST","OPTIONS"],"maxAge":600}' \
1619
- --s-mcp-auth '{"required":true,"scheme":"jwt","jwt":{"algorithms":["HS256"],"secret":"$MY_JWT_SECRET"},"publicPaths":["/health"]}'
1620
-
1621
-
1622
- # Custom log path via CLI flag (logs to specified file instead of ./logs/mcp.log)
1623
- my-tool --s-mcp-serve --s-mcp-log-path /var/log/my-mcp-server.log
1624
-
1625
- # Improved logging via programmatic configuration
1626
- const parser = ArgParser.withMcp({
1627
- mcp: {
1628
- serverInfo: { name: 'my-tool', version: '1.0.0' },
1629
-
1630
- ```
1631
-
1632
- ### CORS and Authentication for streamable-http
1633
-
1634
- CORS is often required when connecting a Web UI to an MCP server over HTTP.
1635
-
1636
- - Programmatic transport config:
1637
-
1638
- ```ts
1639
- import type { McpTransportConfig } from "@alcyone-labs/arg-parser";
1640
-
1641
- const defaultTransports: McpTransportConfig[] = [
1642
- {
1643
- type: "streamable-http",
1644
- port: 3002,
1645
- path: "/api/mcp",
1646
- cors: {
1647
- origins: ["http://localhost:5173", /^https?:\/\/example\.com$/],
1648
- methods: ["GET", "POST", "OPTIONS"],
1649
- headers: ["Content-Type", "Authorization", "MCP-Session-Id"],
1650
- exposedHeaders: ["MCP-Session-Id"],
1651
- credentials: true,
1652
- maxAge: 600,
1653
- },
1654
- auth: {
1655
- required: true,
1656
- scheme: "jwt", // or "bearer"
1657
- // Bearer allowlist:
1658
- // allowedTokens: ["token1","token2"],
1659
- // JWT verification (HS256):
1660
- // jwt: { algorithms: ["HS256"], secret: process.env.JWT_SECRET },
1661
- // JWT verification (RS256 with static public key):
1662
- // jwt: { algorithms: ["RS256"], publicKey: process.env.RS256_PUBLIC_KEY },
1663
- // JWT verification (RS256 with dynamic JWKS):
1664
- // jwt: { algorithms: ["RS256"], getPublicKey: async (header)=>{ /* fetch JWKS and return PEM */ } },
1665
- publicPaths: ["/health"],
1666
- protectedPaths: undefined, // if set, only listed paths require auth
1667
- // Optional custom validator to add extra checks
1668
- validator: async (req, token) => true,
1669
- },
1670
- },
1671
- ];
1672
- ```
1673
-
1674
- - CLI flags (JSON strings):
1675
-
1676
- ```bash
1677
- my-tool --s-mcp-serve \
1678
- --s-mcp-transport streamable-http \
1679
- --s-mcp-port 3002 --s-mcp-path /api/mcp \
1680
- --s-mcp-cors '{"origins":["http://localhost:5173"],"credentials":true,"methods":["GET","POST","OPTIONS"],"maxAge":600}' \
1681
- --s-mcp-auth '{"required":true,"scheme":"jwt","jwt":{"algorithms":["HS256"],"secret":"'$JWT_SECRET'"},"publicPaths":["/health"]}'
1682
- ```
1683
-
1684
- - Express hook for custom routes:
1685
-
1686
- ```ts
1687
- httpServer: {
1688
- configureExpress: (app) => {
1689
- app.get("/health", (_req, res) => res.json({ ok: true }));
1690
- },
1691
- }
1692
- ```
1693
-
1694
- See examples:
1695
-
1696
- - examples/streamable-http/secure-mcp.ts (HS256)
1697
- - examples/streamable-http/rs256-mcp.ts (RS256)
1698
- - examples/streamable-http/jwks-mcp.ts (JWKS)
1699
- - examples/streamable-http/bearer-mcp.ts (Bearer)
1700
- - examples/streamable-http/productized-mcp.ts (token + session usage)
1701
-
1702
- #### TypeScript types
1703
-
1704
- - CorsOptions
1705
-
1706
- ```ts
1707
- export type CorsOptions = {
1708
- origins?: "*" | string | RegExp | Array<string | RegExp>;
1709
- methods?: string[];
1710
- headers?: string[];
1711
- exposedHeaders?: string[];
1712
- credentials?: boolean;
1713
- maxAge?: number;
1714
- };
1715
- ```
1716
-
1717
- - AuthOptions and JwtVerifyOptions
1718
-
1719
- ```ts
1720
- export type JwtVerifyOptions = {
1721
- algorithms?: ("HS256" | "RS256")[];
1722
- secret?: string; // HS256
1723
- publicKey?: string; // RS256 static
1724
- getPublicKey?: (
1725
- header: Record<string, unknown>,
1726
- payload: Record<string, unknown>,
1727
- ) => Promise<string> | string; // RS256 dynamic
1728
- audience?: string | string[];
1729
- issuer?: string | string[];
1730
- clockToleranceSec?: number;
1731
- };
1732
-
1733
- export type AuthOptions = {
1734
- required?: boolean; // default true for MCP endpoint
1735
- scheme?: "bearer" | "jwt";
1736
- allowedTokens?: string[]; // simple bearer allowlist
1737
- validator?: (
1738
- req: any,
1739
- token: string | undefined,
1740
- ) => boolean | Promise<boolean>;
1741
- jwt?: JwtVerifyOptions;
1742
- publicPaths?: string[]; // paths that skip auth
1743
- protectedPaths?: string[]; // if provided, only these paths require auth
1744
- customMiddleware?: (req: any, res: any, next: any) => any; // full control hook
1745
- };
1746
- ```
1747
-
1748
- - HttpServerOptions
1749
-
1750
- ```ts
1751
- export type HttpServerOptions = {
1752
- configureExpress?: (app: any) => void;
1753
- };
1754
- ```
1755
-
1756
- Notes:
1757
-
1758
- - When credentials are true, Access-Control-Allow-Origin echoes the request Origin rather than using "\*".
1759
- - You can manage CORS for non-MCP routes in configureExpress.
1760
- - Use publicPaths to allow some routes without auth; use protectedPaths to only require auth for certain routes.
1761
-
1762
- log: {
1763
- level: 'debug', // Capture all log levels
1764
- logToFile: '/var/log/my-mcp-server.log',
1765
- prefix: 'MyTool'
1766
- }
1767
- // LEGACY: logPath: '/var/log/my-mcp-server.log' // Still works
1768
- }
1769
-
1770
- ### Adding custom HTTP routes (e.g., /health)
1771
-
1772
- Use the httpServer.configureExpress(app) hook to register routes before MCP endpoints are bound. Example:
1773
-
1774
- ```ts
1775
- const cli = ArgParser.withMcp({
1776
- mcp: {
1777
- serverInfo: { name: "my-mcp", version: "1.0.0" },
1778
- defaultTransports: [
1779
- {
1780
- type: "streamable-http",
1781
- port: 3002,
1782
- path: "/api/mcp",
1783
- auth: { required: true, publicPaths: ["/health"] },
1784
- },
1785
- ],
1786
- httpServer: {
1787
- configureExpress: (app) =>
1788
- app.get("/health", (_req, res) => res.json({ ok: true })),
1789
- },
1790
- },
1791
- });
1792
- ```
1793
-
1794
- - To make a route public (no auth), add it to auth.publicPaths.
1795
- - CORS headers for non-MCP paths can be applied by your own middleware inside the hook if desired.
1796
-
1797
- ### Multiple transports and improved logging
1798
-
1799
- const cli = ArgParser.withMcp({
1800
- appName: 'multi-tool',
1801
- appCommandName: 'multi-tool',
1802
- mcp: {
1803
- // NEW: improved logging configuration
1804
- log: {
1805
- level: 'info',
1806
- logToFile: './logs/multi-tool-mcp.log',
1807
- prefix: 'MultiTool'
1808
- },
1809
- serverInfo: {
1810
- name: 'multi-tool-mcp',
1811
- version: '1.0.0'
1812
- },
1813
- transports: [
1814
- // Can be a single string...
1815
- "stdio",
1816
- // or one of the other transport types supported by @modelcontextprotocol/sdk
1817
- { type: "sse", port: 3000, host: "0.0.0.0" },
1818
- { type: "websocket", port: 3001, path: "/ws" }
1819
- ]
1820
- }
1821
- });
1822
-
1823
- ````
1824
-
1825
- ### MCP Logging Configuration
1826
-
1827
- MCP server logging can be configured with McpLoggerOptions options using `@alcyone-labs/simple-mcp-logger`. You can control log levels, output destinations, and more.
1828
-
1829
- #### Enhanced Logging (Recommended)
1830
-
1831
- Use the new `log` property for comprehensive logging control:
1832
-
1833
- ```typescript
1834
- const parser = ArgParser.withMcp({
1835
- appName: "My MCP Server",
1836
- appCommandName: "my-mcp-server",
1837
- mcp: {
1838
- serverInfo: { name: "my-server", version: "1.0.0" },
1839
- log: {
1840
- level: "debug", // Captures debug, info, warn, error
1841
- logToFile: "./logs/comprehensive.log",
1842
- prefix: "MyServer",
1843
- mcpMode: true, // MCP compliant (default)
1844
- },
1845
- },
1846
- });
1847
- ````
1848
-
1849
- **Available log levels**: `"debug"` | `"info"` | `"warn"` | `"error"` | `"silent"`
1850
-
1851
- **Type Safety**: The `McpLoggerOptions` type is provided for full TypeScript support and matches the interface from `@alcyone-labs/simple-mcp-logger`.
1852
-
1853
- #### Simple Logging Configuration
1854
-
1855
- For basic use cases, you can use a simple string path:
1856
-
1857
- ```typescript
1858
- const parser = ArgParser.withMcp({
1859
- mcp: {
1860
- serverInfo: { name: "my-server", version: "1.0.0" },
1861
- log: "./logs/simple.log", // Simple string path
1862
- },
1863
- });
1864
- ```
1865
-
1866
- #### Configuration Priority
1867
-
1868
- Logging configuration follows this priority order:
1869
-
1870
- 1. **CLI Flag (Highest Priority)**: `--s-mcp-log-path <path>`
1871
- 2. **Merging**: When both `mcp.log` and `mcp.logPath` are present:
1872
- - `mcp.log` provides logger options (level, prefix, mcpMode)
1873
- - `mcp.logPath` provides flexible path resolution (relativeTo, basePath)
1874
- - Path resolution: `mcp.logPath` > `mcp.log.logToFile`
1875
- 3. **Log Config Only**: `mcp.log` object or string in `withMcp()`
1876
- 4. **Legacy Log Path Only**: `mcp.logPath` in `withMcp()`
1877
- 5. **Default Path (Fallback)**: `./logs/mcp.log`
1878
-
1879
- #### Configuration Merging
1880
-
1881
- When both `log` and `logPath` are specified:
1882
-
1883
- ```typescript
1884
- const parser = ArgParser.withMcp({
1885
- mcp: {
1886
- serverInfo: { name: "my-server", version: "1.0.0" },
1887
- // log provides logger options (level, prefix, mcpMode)
1888
- log: {
1889
- level: "debug",
1890
- prefix: "MyServer",
1891
- mcpMode: true,
1892
- // logToFile can be omitted when using logPath
1893
- },
1894
- // logPath provides flexible path resolution
1895
- logPath: {
1896
- path: "./logs/app.log",
1897
- relativeTo: "entry", // "entry" | "cwd" | "absolute"
1898
- basePath: "/custom/base", // Optional custom base path
1899
- },
1900
- },
1901
- });
1902
- ```
1903
-
1904
- **Merging behavior:**
1905
-
1906
- - `log` provides logger configuration (level, prefix, mcpMode)
1907
- - `logPath` provides flexible path resolution with `relativeTo` options
1908
- - If both specify a file path, `logPath` takes precedence for path resolution
1909
- - This preserves the powerful `LogPath` features while using `McpLoggerOptions` for logger settings
1910
-
1911
- #### Path Resolution Options
1912
-
1913
- Log paths are resolved with smart defaults for better DXT package compatibility:
1914
-
1915
- ```typescript
1916
- // Simple string paths (recommended)
1917
- const parser = ArgParser.withMcp({
1918
- appName: "My CLI",
1919
- appCommandName: "my-cli",
1920
- mcp: {
1921
- serverInfo: { name: "my-server", version: "1.0.0" },
1922
- logPath: "./logs/app.log", // Relative to entry point (default)
1923
- // logPath: "/tmp/app.log", // Absolute paths work too
1924
- // logPath: "cwd:./logs/app.log", // Explicit process.cwd() relative
1925
- },
1926
- });
1927
-
1928
- // Object configuration for more granular use cases
1929
- const parser = ArgParser.withMcp({
1930
- // ... other config
1931
- mcp: {
1932
- // ... server info
1933
- logPath: {
1934
- path: "./logs/app.log",
1935
- relativeTo: "entry", // "entry" | "cwd" | "absolute"
1936
- basePath: "/custom/base", // Optional custom base path
1937
- },
1938
- },
1939
- });
1940
-
1941
- // CLI flag overrides programmatic setting
1942
- // my-cli --s-mcp-serve --s-mcp-log-path ./override.log
1943
- ```
1944
-
1945
- 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.
1946
-
1947
- ### MCP Lifecycle Events
1948
-
1949
- 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.
1950
-
1951
- ```typescript
1952
- const cli = ArgParser.withMcp({
1953
- appName: "Database CLI",
1954
- appCommandName: "db-cli",
1955
- mcp: {
1956
- serverInfo: { name: "database-server", version: "1.0.0" },
1957
- lifecycle: {
1958
- onInitialize: async (ctx) => {
1959
- // Called when client sends "initialize" request
1960
- // Perfect for database connections, resource setup
1961
- ctx.logger.mcpError("Initializing server...");
1962
-
1963
- const dbUrl = ctx.getFlag("database_url");
1964
- if (dbUrl) {
1965
- await connectToDatabase(dbUrl);
1966
- ctx.logger.mcpError("Database connected successfully");
1967
- }
1968
- },
1969
-
1970
- onInitialized: async (ctx) => {
1971
- // Called when client sends "initialized" notification
1972
- // Server is ready for normal operations
1973
- ctx.logger.mcpError("Server ready for requests");
1974
- await startBackgroundTasks();
1975
- },
1976
-
1977
- onShutdown: async (ctx) => {
1978
- // Called during server shutdown
1979
- // Perfect for cleanup, closing connections
1980
- ctx.logger.mcpError(`Shutting down: ${ctx.reason}`);
1981
- await cleanupResources();
1982
- await closeDatabase();
1983
- },
1984
- },
1985
- },
1986
- });
1987
- ```
1988
-
1989
- **Lifecycle Events:**
1990
-
1991
- - **`onInitialize`**: Called when a client sends an "initialize" request. Ideal for database connections, resource initialization, configuration validation, and authentication setup.
1992
- - **`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.
1993
- - **`onShutdown`**: Called when the MCP server is shutting down. Essential for cleanup, resource disposal, and graceful shutdown procedures.
1994
-
1995
- **Context Properties:**
1996
-
1997
- Each lifecycle event receives a context object with:
1998
-
1999
- - `getFlag(name)`: Access parsed CLI flags and environment variables
2000
- - `logger`: MCP-compliant logger instance for the current context
2001
- - `serverInfo`: Server information (name, version, description)
2002
- - `clientInfo`: Client information (available in onInitialize and onInitialized)
2003
- - `protocolVersion`: MCP protocol version being used
2004
- - `reason`: Shutdown reason (only in onShutdown: "client_disconnect", "server_shutdown", "error", "signal")
2005
-
2006
- ### MCP Resources - Real-Time Data Feeds
2007
-
2008
- 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.
2009
-
2010
- **Key Benefits:**
2011
-
2012
- - **Real-time notifications**: AI assistants get notified when your data changes
2013
- - **Flexible URI templates**: Support dynamic parameters like `data://alerts/aged/gte:{threshold}`
2014
- - **Standard MCP pattern**: Full subscription lifecycle support
2015
- - **Zero CLI impact**: Resources only work in MCP mode, CLI usage unchanged
2016
-
2017
- #### Basic Resource Setup
2018
-
2019
- ```typescript
2020
- const parser = ArgParser.withMcp({
2021
- appName: "Data Monitor",
2022
- appCommandName: "data-monitor",
2023
- mcp: {
2024
- serverInfo: { name: "data-monitor", version: "1.0.0" },
2025
- },
2026
- }).addMcpResource({
2027
- name: "recent-data",
2028
- uriTemplate: "data://recent",
2029
- title: "Recent Data",
2030
- description: "Get the most recent data entries",
2031
- mimeType: "application/json",
2032
- handler: async (uri) => {
2033
- const recentData = await getRecentData();
2034
- return {
2035
- contents: [
2036
- {
2037
- uri: uri.href,
2038
- text: JSON.stringify(recentData, null, 2),
2039
- mimeType: "application/json",
2040
- },
2041
- ],
2042
- };
2043
- },
2044
- });
2045
- ```
2046
-
2047
- #### URI Templates with Dynamic Parameters
2048
-
2049
- Create flexible resources that accept parameters:
2050
-
2051
- ```typescript
2052
- .addMcpResource({
2053
- name: "aged-data-alert",
2054
- uriTemplate: "data://alerts/aged/gte:{threshold}",
2055
- title: "Aged Data Alert",
2056
- description: "Monitor data that has aged past a threshold (in milliseconds)",
2057
- handler: async (uri, { threshold }) => {
2058
- const thresholdMs = parseInt(threshold);
2059
- const agedData = await getDataOlderThan(new Date(Date.now() - thresholdMs));
2060
-
2061
- return {
2062
- contents: [{
2063
- uri: uri.href,
2064
- text: JSON.stringify({
2065
- threshold_ms: thresholdMs,
2066
- query_time: new Date().toISOString(),
2067
- aged_data: agedData,
2068
- count: agedData.length
2069
- }, null, 2),
2070
- mimeType: "application/json"
2071
- }]
2072
- };
2073
- }
2074
- });
2075
- ```
2076
-
2077
- #### MCP Subscription Lifecycle
2078
-
2079
- Resources support the full MCP subscription pattern:
2080
-
2081
- 1. **Client subscribes**: `resources/subscribe` → `"data://alerts/aged/gte:10000"`
2082
- 2. **Server monitors**: Your application detects data changes
2083
- 3. **Server notifies**: `notifications/resources/updated` sent to subscribed clients
2084
- 4. **Client reads fresh data**: `resources/read` → `"data://alerts/aged/gte:10000"`
2085
- 5. **Client unsubscribes**: `resources/unsubscribe` when done
2086
-
2087
- #### Usage Examples
2088
-
2089
- **AI Assistant Integration:**
2090
-
2091
- ```typescript
2092
- // AI assistant can subscribe to real-time data
2093
- await client.request("resources/subscribe", {
2094
- uri: "data://alerts/aged/gte:60000", // 1 minute threshold
2095
- });
2096
-
2097
- // Handle notifications
2098
- client.on("notifications/resources/updated", async (notification) => {
2099
- const response = await client.request("resources/read", {
2100
- uri: notification.uri,
2101
- });
2102
- console.log("Fresh data:", JSON.parse(response.contents[0].text));
2103
- });
2104
- ```
2105
-
2106
- **Command Line Testing:**
2107
-
2108
- ```bash
2109
- # Start MCP server
2110
- data-monitor --s-mcp-serve
2111
-
2112
- # Test resource (in another terminal)
2113
- echo '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"data://alerts/aged/gte:10000"}}' | data-monitor --s-mcp-serve
2114
- ```
2115
-
2116
- #### Design Patterns
2117
-
2118
- **Static Resources**: Use simple URIs for data that changes content but not structure
2119
-
2120
- ```typescript
2121
- uriTemplate: "logs://recent"; // Always available, content updates
2122
- uriTemplate: "status://system"; // System status, updates in real-time
2123
- ```
2124
-
2125
- **Parameterized Resources**: Use URI templates for flexible filtering
2126
-
2127
- ```typescript
2128
- uriTemplate: "data://type/{type}"; // Filter by type
2129
- uriTemplate: "alerts/{severity}/gte:{age}"; // Multiple parameters
2130
- uriTemplate: "search/{query}/limit:{count}"; // Search with limits
2131
- ```
2132
-
2133
- **Time-Based Resources**: Perfect for monitoring and alerting
2134
-
2135
- ```typescript
2136
- uriTemplate: "events/since:{timestamp}"; // Events since timestamp
2137
- uriTemplate: "metrics/aged/gte:{threshold}"; // Metrics past threshold
2138
- uriTemplate: "logs/errors/last:{duration}"; // Recent errors
2139
- ```
2140
-
2141
- > **💡 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.
2142
-
2143
- ### Automatic Console Safety
2144
-
2145
- A major challenge in MCP is preventing `console.log` from corrupting the JSON-RPC communication over `STDOUT`. ArgParser solves this automatically.
2146
-
2147
- - **How it works**: When `--s-mcp-serve` is active, ArgParser hijacks the global `console` object.
2148
- - **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.
2149
- - **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**.
2150
-
2151
- ### Generating DXT Packages (`--s-build-dxt`)
2152
-
2153
- A Desktop Extension (`.dxt`) is a standardized package for installing your tools into Claude Desktop. ArgParser automates this process.
2154
-
2155
- ```bash
2156
- # 1. Generate the DXT package contents into a directory
2157
- my-cli-app --s-build-dxt ./my-dxt-package
2158
-
2159
- # The output folder contains everything needed: manifest.json, entry point, etc.
2160
- # A default logo will be applied if you don't provide one.
2161
-
2162
- # 2. (Optional) Pack the folder into a .dxt file for distribution
2163
- # (you can install the unpacked folder) directly in Claude Desktop > Settings > Extensions > Advanced
2164
- npx @anthropic-ai/dxt pack ./my-dxt-package
2165
-
2166
- # 3. (Optional) Sign the DXT package - this has not been well tested yet
2167
- npx @anthropic-ai/dxt sign ./my-dxt-package.dxt
2168
-
2169
- # Then drag & drop the .dxt file into Claude Desktop to install it, in the Settings > Extensions screen.
2170
-
2171
- # **IMPORTANT**:
2172
- # If you use ML models or packages that include binaries such as Sqlite3 or sharp, etc...
2173
- # You need to bundle the node_modules folder with your DXT package
2174
- # In order to do this, you need to use the following flag:
2175
- # First hard-install all the packages
2176
- rm -rf node_moduels
2177
- pnpm install --prod --linker hoisted
2178
- # Then bundle with node_modules
2179
- mycli --s-build-dxt ./my-dxt-package --s-with-node-modules
2180
- # then build the dxt bundle
2181
- npx @anthropic-ai/dxt pack ./my-dxt-package
2182
- # then upload the dxt bundle to Claude Desktop from the settings > extensions > advanced
2183
- ```
2184
-
2185
- ### Logo Configuration
2186
-
2187
- 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.
2188
-
2189
- You can customize the logo/icon that appears in Claude Desktop for your DXT package by configuring the `logo` property in your `serverInfo`:
2190
-
2191
- ```typescript
2192
- const cli = ArgParser.withMcp({
2193
- appName: "My CLI",
2194
- appCommandName: "mycli",
2195
- mcp: {
2196
- // This will appear in Claude Desktop's Extensions settings
2197
- serverInfo: {
2198
- name: "my-mcp-server",
2199
- version: "1.0.0",
2200
- description: "My CLI as an MCP server",
2201
- logo: "./assets/my-logo.png", // Local file path
2202
- },
2203
- },
2204
- });
2205
- ```
2206
-
2207
- If no custom logo is provided or loading fails, a default ArgParser logo is included
2208
-
2209
- #### Supported Logo Sources
2210
-
2211
- **Local File Path:**
2212
-
2213
- ```typescript
2214
- logo: "./assets/my-logo.png"; // Relative to your project
2215
- logo: "/absolute/path/to/logo.jpg"; // Absolute path
2216
- ```
2217
-
2218
- **HTTP/HTTPS URL:**
2219
-
2220
- ```typescript
2221
- logo: "https://example.com/logo.png"; // Downloaded automatically
2222
- logo: "https://cdn.example.com/icon.svg";
2223
- ```
2224
-
2225
- ### Including Additional Files in DXT Packages
2226
-
2227
- 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.
2228
-
2229
- ```typescript
2230
- const cli = ArgParser.withMcp({
2231
- appName: "My CLI",
2232
- appCommandName: "mycli",
2233
- mcp: {
2234
- serverInfo: {
2235
- name: "my-mcp-server",
2236
- version: "1.0.0",
2237
- description: "My CLI as an MCP server",
2238
- },
2239
- dxt: {
2240
- include: [
2241
- "migrations", // Copy entire migrations folder
2242
- "config/production.json", // Copy specific file
2243
- { from: "assets/logo.png", to: "logo.png" }, // Copy and rename file
2244
- { from: "scripts", to: "bin" }, // Copy folder with new name
2245
- ],
2246
- },
2247
- },
2248
- });
2249
- ```
2250
-
2251
- #### Include Options
2252
-
2253
- **Simple string paths** - Copy files/directories to the same relative location:
2254
-
2255
- ```typescript
2256
- include: [
2257
- "migrations", // Copies ./migrations/ to dxt/migrations/
2258
- "config/default.json", // Copies ./config/default.json to dxt/config/default.json
2259
- ];
2260
- ```
2261
-
2262
- **Object mapping** - Copy with custom destination paths:
2263
-
2264
- ```typescript
2265
- include: [
2266
- { from: "config/prod.json", to: "config.json" }, // Rename during copy
2267
- { from: "database/schema", to: "db/schema" }, // Copy to different path
2268
- ];
2269
- ```
2270
-
2271
- **Path Resolution**: All paths in the `from` field are resolved relative to your project root (where `package.json` and `tsconfig.json` are located).
2272
-
2273
- **Example Use Cases**:
2274
-
2275
- - Database migration files for initialization
2276
- - Configuration templates or defaults
2277
- - Static assets like images or documents
2278
- - Scripts or utilities needed at runtime
2279
- - Documentation or help files
2280
-
2281
- ### How DXT Generation Works
2282
-
2283
- When you run `--s-build-dxt`, ArgParser performs several steps to create a self-contained, autonomous package:
2284
-
2285
- 1. **Introspection**: It analyzes all tools defined with `.addTool()`.
2286
- 2. **Manifest Generation**: It creates a `manifest.json` file.
2287
- - Tool flags are converted into a JSON Schema for the `input_schema`.
2288
- - 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.
2289
- 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.
2290
- 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`.
2291
-
2292
- ### DXT Bundling Strategies
2293
-
2294
- ArgParser offers two approaches for handling dependencies in DXT packages, depending on your project's needs.
2295
-
2296
- #### Standard Approach (Recommended for Most Projects)
2297
-
2298
- ```bash
2299
- # For pure JavaScript/TypeScript projects
2300
- your-cli --s-build-dxt
2301
- ```
2302
-
2303
- - **Best for**: Pure JS/TS projects without native dependencies
2304
- - **Bundle size**: Small (5-10MB typical)
2305
- - **Build time**: Fast
2306
- - **Dependencies**: Bundled automatically by TSDown
2307
-
2308
- #### Native Dependencies Approach
2309
-
2310
- ```bash
2311
- # For projects with native binaries (ONNX, Sharp, SQLite, etc.)
2312
- rm -rf node_modules
2313
- pnpm install --prod --node-linker=hoisted
2314
- your-cli --s-build-dxt --s-with-node-modules
2315
- ```
2316
-
2317
- - **Best for**: Projects using ONNX Runtime, Sharp, Canvas, SQLite, or other packages with `.node` binaries
2318
- - **Bundle size**: Larger (50-200MB typical)
2319
- - **Build time**: Longer (copies entire node_modules)
2320
- - **Dependencies**: Complete autonomy - no installation needed by Claude
2321
-
2322
- **When to use `--s-with-node-modules`:**
2323
-
2324
- - ✅ Your project uses machine learning packages (ONNX Runtime, TensorFlow bindings)
2325
- - ✅ You need image processing (Sharp, Canvas)
2326
- - ✅ You use database packages with native binaries (better-sqlite3, sqlite3)
2327
- - ✅ You want guaranteed compatibility without runtime installation
2328
- - ✅ Bundle size is acceptable for your use case
2329
-
2330
- **Required preparation steps:**
2331
-
2332
- 1. `rm -rf node_modules` - Clean slate for proper structure
2333
- 2. `pnpm install --prod --node-linker=hoisted` - Creates flat, symlink-free structure
2334
- 3. Add `--s-with-node-modules` flag to your build command
2335
-
2336
- The system automatically validates your setup and provides guidance if issues are detected.
2337
-
2338
- ### Typical Errors
2339
-
2340
- **Failed to run in Claude Desktop**:
2341
-
2342
- 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).
2343
- To resolve this, simply go to `Claude Desktop > Settings > Extensions > Advanced Settings` and turn **OFF** `Use Built-in Node.js for MCP`.
2344
-
2345
- 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)
2346
-
2347
- **Failed to attach to MCP when downloading external assets**
2348
-
2349
- 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.
2350
-
2351
- **Failed to generate DXT package**:
2352
-
2353
- If you encounter the following error running a command such as:
2354
-
2355
- ```bash
2356
- rm -rf node_modules
2357
- pnpm install --prod --node-linker=hoisted
2358
- bun src/index.ts --s-build-dxt ./dxt --s-with-node-modules
2359
-
2360
- -- Error generating DXT package: TSDown DXT build failed: EEXIST: file already exists, mkdir
2361
- ```
2362
-
2363
- Then run:
2364
-
2365
- ```bash
2366
- rm -rf ./dxt
2367
- bun src/index.ts --s-build-dxt ./dxt --s-with-node-modules
2368
- ```
2369
-
2370
- And it should work. TSDown is tasked to clean the outputDir first, but it won't if some files have been manually changed.
2371
-
2372
- ---
92
+ > 📖 **Full Documentation**: [docs/TUI.md](./docs/TUI.md) | [Component Reference](./docs/TUI_COMPONENTS.md)
2373
93
 
2374
94
  ## System Flags & Configuration
2375
95
 
2376
- 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.
2377
-
2378
- | Flag | Description |
2379
- | --------------------------- | -------------------------------------------------------------------------------------------------------------- |
2380
- | **MCP & DXT** | |
2381
- | `--s-mcp-serve` | Starts the application in MCP server mode, exposing all tools. |
2382
- | `--s-build-dxt [dir]` | Generates a complete, autonomous DXT package for Claude Desktop in the specified directory. |
2383
- | `--s-with-node-modules` | Use with `--s-build-dxt`. Includes complete node_modules in DXT package for projects with native dependencies. |
2384
- | `--s-mcp-transport <type>` | Overrides the MCP transport (`stdio`, `sse`, `streamable-http`). |
2385
- | `--s-mcp-transports <json>` | Overrides transports with a JSON array for multi-transport setups. |
2386
- | `--s-mcp-port <number>` | Sets the port for HTTP-based transports (`sse`, `streamable-http`). |
2387
- | `--s-mcp-host <string>` | Sets the host address for HTTP-based transports. |
2388
- | `--s-mcp-log-path <path>` | Sets the file path for MCP server logs (default: `./logs/mcp.log`). Overrides programmatic setting. |
2389
- | **Configuration** | |
2390
- | `--s-with-env <file>` | Loads configuration from a file (`.env`, `.json`, `.yaml`, `.toml`). CLI args take precedence. |
2391
- | `--s-save-to-env <file>` | Saves the current arguments to a configuration file, perfect for templates. |
2392
- | **Debugging** | |
2393
- | `--s-debug` | Prints a detailed, step-by-step log of the argument parsing process. |
2394
- | `--s-debug-print` | Exports the entire parser configuration to a JSON file for inspection. |
2395
- | `--s-enable-fuzzy` | Enables fuzzy testing mode—a dry run that parses args but skips handler execution. |
2396
-
2397
- ---
2398
-
2399
- ## Changelog
2400
-
2401
- ### v2.13.1
2402
-
2403
- **Fixes**
2404
-
2405
- - OpenTUI implementation now properly exits and cleans the context
2406
- - Sub-command description now properly displays in displayHelp() screen
2407
-
2408
- ### v2.13.0
2409
-
2410
- **New Feature: Positional Arguments**
2411
-
2412
- Added support for positional (trailing) arguments, enabling more natural CLI syntax:
2413
-
2414
- ```bash
2415
- # Before: flags required
2416
- workflow show --id 8fadf090-xxx
2417
-
2418
- # After: positional syntax works too!
2419
- workflow show 8fadf090-xxx
2420
- ```
2421
-
2422
- Flags can now specify `positional: N` (1-indexed) to capture trailing arguments:
2423
-
2424
- ```typescript
2425
- .addFlag({
2426
- name: "id",
2427
- type: "string",
2428
- mandatory: true,
2429
- options: ["--id"], // Still works as fallback
2430
- positional: 1, // Captures first trailing arg
2431
- description: "Resource ID",
2432
- })
2433
- ```
2434
-
2435
- Key features:
2436
-
2437
- - **Dual syntax**: Both `--flag value` and positional work interchangeably
2438
- - **Precedence**: Flag syntax takes priority if both provided
2439
- - **Multiple positional args**: Use `positional: 1`, `positional: 2`, etc.
2440
- - **Help text enhancement**: Shows usage pattern like `Usage: cmd [OPTIONS] <ID>`
2441
- - **Full validation**: Works with `mandatory`, type coercion, and enum validation
2442
-
2443
- See [Positional Arguments](#positional-arguments) for complete documentation.
2444
-
2445
- ### v2.12.3
2446
-
2447
- **Fixes**
2448
-
2449
- - Make sure that when setWorkingDir is used, the newly discovered .env override process.env variables
2450
- - Display subcommand descriptions on separate lines for better readability
2451
-
2452
- ### v2.12.2
2453
-
2454
- **Fixes**
2455
-
2456
- - Fix env config matching and improve working directory integration
2457
-
2458
- Explicitly call dotenv.config when an env file is auto-discovered
2459
- to populate process.env. This ensures flags with the 'env' property
2460
- can bind values from the discovered file.
2461
-
2462
- ### v2.12.0
2463
-
2464
- - 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.
2465
-
2466
- ### v2.11.0
2467
-
2468
- Working Directory Management & OpenTUI v2 Framework
2469
-
2470
- #### Working Directory Management (chdir)
2471
-
2472
- A major new capability for monorepo support and complex project structures:
2473
-
2474
- - **`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.
2475
- - **`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.
2476
- - **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).
2477
- - **Protected Validation**: Warnings for invalid paths (nonexistent, not a directory) and multiple workspace flags.
2478
-
2479
- ```typescript
2480
- const parser = new ArgParser({
2481
- appName: "Monorepo CLI",
2482
- handler: async (ctx) => {
2483
- console.log("Effective cwd:", process.cwd()); // Changed by --workspace
2484
- console.log("User's cwd:", ctx.rootPath); // Original location
2485
- },
2486
- }).addFlag({
2487
- name: "workspace",
2488
- options: ["--workspace", "-w"],
2489
- type: "string",
2490
- setWorkingDirectory: true, // Makes this flag control the working directory
2491
- });
2492
- ```
2493
-
2494
- See [Working Directory Documentation](./docs/WORKING_DIRECTORY.md) for complete examples.
2495
-
2496
- #### OpenTUI v2 - Complete TUI Rewrite
2497
-
2498
- The TUI framework has been completely rewritten using **SolidJS** and **SST's OpenTUI** for a reactive, component-based architecture:
2499
-
2500
- - **Reactive Components**: `TuiProvider`, `VirtualList`, `MasterDetail`, `Breadcrumb` built on SolidJS signals.
2501
- - **Unified Provider**: `TuiProvider` handles mouse wheel reporting, terminal resize, TTY cleanup, and theme/shortcut contexts automatically.
2502
- - **Rich Theme System**: 6 built-in themes (`dark`, `light`, `monokai`, `dracula`, `nord`, `solarized`) with `Theme.from().extend()` for custom themes.
2503
- - **VirtualList**: Efficient virtualized scrolling with `createVirtualListController` for navigation control.
2504
- - **Slot-Based Layouts**: `MasterDetail` component with header, breadcrumb, footer, and customizable panel widths.
2505
- - **Hooks**: `useTui()` for viewport/exit, `useTheme()` for theming, plus mouse and virtual scroll hooks.
2506
- - **TTY Utilities**: Exported `cleanupTerminal`, `enableMouseReporting`, etc. for custom terminal control.
2507
-
2508
- ```tsx
2509
- import {
2510
- MasterDetail,
2511
- TuiProvider,
2512
- useTui,
2513
- VirtualList,
2514
- } from "@alcyone-labs/arg-parser/tui";
2515
- import { render } from "@opentui/solid";
2516
-
2517
- function App() {
2518
- const { viewportHeight, exit } = useTui();
2519
- const [idx, setIdx] = createSignal(0);
2520
-
2521
- return (
2522
- <MasterDetail
2523
- header="My App"
2524
- master={
2525
- <VirtualList items={DATA} selectedIndex={idx()} onSelect={setIdx} />
2526
- }
2527
- detail={<Details item={DATA[idx()]} />}
2528
- />
2529
- );
2530
- }
2531
-
2532
- render(() => (
2533
- <TuiProvider theme="dark" onScroll={(d) => setIdx((i) => i + d)}>
2534
- <App />
2535
- </TuiProvider>
2536
- ));
2537
- ```
2538
-
2539
- See [TUI Documentation](./docs/TUI.md) for complete API reference and examples.
2540
-
2541
- #### Other Improvements
2542
-
2543
- - **Data-Safe Logging**: Integrated `@alcyone-labs/simple-mcp-logger` for STDOUT-safe logging.
2544
- - **Bun Configuration**: Added `bunfig.toml` with OpenTUI preload for native JSX support.
2545
- - **New Examples**: `aquaria-trace-viewer.tsx`, `framework-demo.tsx`, `template-demo.tsx`, `tui-demo-v2.tsx`.
2546
-
2547
- ### v2.10.3
2548
-
2549
- **Flag Inheritance Improvements**
2550
-
2551
- - **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.
2552
- - **Granular Control**: New `FlagInheritance` configuration object provides clear options: `NONE`, `DirectParentOnly` (legacy behavior), and `AllParents`.
2553
- - **Type Safety**: New `TFlagInheritance` type definition for better TypeScript support.
2554
- - **Backward Compatibility**: Kept `inheritParentFlags` for legacy behavior, but now it's just an alias for `FlagInheritance.DirectParentOnly`.
2555
-
2556
- **Auto-Help Features**
2557
-
2558
- - **Programmatic Help**: Added `ctx.displayHelp()` method to command handlers, allowing easy help display from within your logic.
2559
- - **Auto-Trigger**: Added `triggerAutoHelpIfNoHandler` option to automatically show help messages for "container" commands that don't have their own handler.
2560
- - **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.
2561
-
2562
- ### v2.10.2
2563
-
2564
- **OpenTUI Improvements**
2565
-
2566
- - **Soft Wrapping**: Added `wrapText` (boolean) to `ScrollArea` component. When enabled, text automatically reflows to fit the container width (preventing clipping).
2567
- - **ANSI Preservation**: Soft-wrapping logic is ANSI-aware; color and style states are correctly carried over to wrapped lines.
2568
-
2569
- ### v2.10.1
2570
-
2571
- - **Bug Fixes**:
2572
- - 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.
2573
-
2574
- ### v2.10.0 - OpenTUI integration + IFlag "env" property now first-class citizen
2575
-
2576
- #### OpenTUI Integration
2577
-
2578
- - **OpenTUI**: Integrated a complete Terminal User Interface (TUI) framework into the library core.
2579
- - **StackNavigator**: Standardized UX for deep navigation with `Enter`/`Right` to push and `Esc`/`Left` to pop views.
2580
- - **Reactive Themes**: Centralized `ThemeManager` with `Default`, `Ocean` (High-Contrast), and `Monokai` presets.
2581
- - **Scroll Performance**: ANSI-aware left-side scrollbars with automatic height calculation and scroll-state management.
2582
- - **Mouse Integration**: Native SGR mouse reporting for wheel scrolling and hit-detected clicks.
2583
- - **Safety**: Robust TTY restoration and process-level cleanup to prevent terminal lockups on exit or crash.
2584
- - **Components**: Exported `List`, `ScrollArea`, `Input`, and `SplitLayout` under the `UI` namespace.
2585
-
2586
- #### Universal Environment Variable Support
2587
-
2588
- - **Universal `env` Support**: The `env` property is now a core feature available to all commands and tools, not just DXT/MCP contexts.
2589
- - **Resolution Priority**: Implemented strict precedence: **CLI Flag > Environment Variable > Default Value**.
2590
- - **Reverse Sync**: Resolved flag values (from CLI or Env) are now automatically synced back to `process.env`, ensuring downstream code sees the correct configuration.
2591
- - **Flexible Mapping**: Supports both string and array-of-strings for `env` (first match wins).
2592
- - **Automatic Type Conversion**: Environment variables are automatically coerced to the flag's defined type (Number, Boolean, etc.).
2593
-
2594
- ### v2.8.2
2595
-
2596
- - 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.
2597
- - Types: Added `IFlag.valueHint?: string`; accepted by `zodFlagSchema`; included in processed flags; supported in manifest-driven dynamic flags.
2598
- - Examples: `examples/core/dynamic-flags-demo.ts` updated to demonstrate `valueHint` for `--url`.
2599
-
2600
- ### v2.8.1
2601
-
2602
- - Feature: Dynamic flags via `IFlag.dynamicRegister(ctx)` to register additional flags at runtime (e.g., from a manifest file)
2603
- - Help: `--help` preloads dynamic flags without executing handlers; help output includes both static and dynamic flags
2604
- - Flow: Two-phase parsing (load dynamic flags → re-parse with full flag set)
2605
- - Cleanup: Dynamically registered flags are reset between parses to avoid accumulation
2606
- - Types: Exported `DynamicRegisterContext` and `DynamicRegisterFn`
2607
- - Internal: `FlagManager.removeFlag(name)` to support cleanup
2608
-
2609
- ### v2.7.2
2610
-
2611
- **Feat**
2612
-
2613
- **MCP**:
2614
-
2615
- - 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.
2616
-
2617
- **Fixes and Changes**
2618
-
2619
- **MCP**:
2620
-
2621
- - The app parameter in configureExpress: (app) => {} is now fully typed to improve intellisense.
2622
- - Express' x-powered-by was disabled by default. It can be re-enabled or changed via configureExpress as needed.
2623
- - Logger parameters were still not fully functional and log level was still ignored, this has been fixed.
2624
-
2625
- ### v2.7.0
2626
-
2627
- **Feat**
2628
-
2629
- **MCP**:
2630
-
2631
- - Add support for CORS and authentication options, enabling powerful tools to serve Web UIs and publicly exposed APIs
2632
- - Add supports for configuring express by exposing the app before it runs
2633
-
2634
- **CLI**:
2635
-
2636
- - 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.
2637
-
2638
- ### v2.6.0
2639
-
2640
- **Feat**
2641
-
2642
- **DXT**:
2643
-
2644
- - 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()`.
2645
- - 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.
2646
-
2647
- Read more her: [DXT Package User Configuration & Path Handling](#dxt-package-user-configuration--path-handling)
2648
-
2649
- **Fixes and Changes**
2650
-
2651
- **DXT**:
2652
-
2653
- - Improve handling of sensitive env variable, they were previously always showing as sensitive.
2654
-
2655
- **Known Limitations**
2656
-
2657
- **DXT**:
2658
-
2659
- 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:
2660
-
2661
- 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)
2662
- 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)
2663
- 3. In some cases if your CLI entrypoint does not run a main loop (see documentation for working examples)
2664
- 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)
2665
-
2666
- ### v2.5.0
2667
-
2668
- **Feat**
2669
-
2670
- - **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.
2671
- - **Improved MCP Tool Documentation**: Zod schema descriptions automatically become MCP tool parameter documentation
2672
-
2673
- ### v2.4.2
2674
-
2675
- **Fixes and Changes**
2676
-
2677
- - add missing MCP lifecycle event documentation
2678
- - fix the behavior of the withMcp() options.mcp.log that was not working as expected
2679
-
2680
- ### v2.4.1
2681
-
2682
- **Fixes and Changes**
2683
-
2684
- - switch to NPM version of @alcyone-labs/modelcontextprotocol-sdk to freeze the dependency and avoid side-effects
2685
-
2686
- ### v2.4.0
2687
-
2688
- **Feat**
2689
-
2690
- - 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
2691
- - MCP client now sanitizes the method names to ensure spec-compliants MCP behavior, names that collision will be logged
2692
- - There were some use-cases where the DXT bundling failed, this new release addresses all of them, namely:
2693
- 1. Output structure will match that of the input so relative files (for example DB migrations) will work
2694
- 2. Deeper folder structure was previously not working
2695
- - DXT bundling now supports including resources via options: `{dxt: {include: ['TSDown blob-like paths']}`
2696
- - 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
2697
-
2698
- **Fixes and Changes**
2699
-
2700
- - 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).
2701
-
2702
- ### v2.3.0
2703
-
2704
- 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)
2705
-
2706
- Make sure to clearly identify if you need to include the node_modules or not. In doubt, include them using `--s-with-node-modules`
2707
-
2708
- **Feat**
2709
-
2710
- - **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.
2711
- 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`.
2712
-
2713
- ### v2.2.1
2714
-
2715
- **Feat**
2716
-
2717
- - You can now specify logPath for the MCP output and easily disambiguate what the path is relative to (`__dirname` versus `process.cwd()` versus absolute)
2718
-
2719
- **Fixes and changes**
2720
-
2721
- - 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.
2722
-
2723
- ### v2.2.0
2724
-
2725
- **Feat**
2726
-
2727
- - IFlag function-based `type` now supports async methods such as `type: async () => Promise<string>`.
2728
-
2729
- **Fixes and changes**
2730
-
2731
- - `.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.
2732
- - `--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).
2733
- - `--s-build-dxt` logo detection now resolves paths more accurately...
2734
-
2735
- ### v2.1.1
2736
-
2737
- **Fixes and changes**
2738
-
2739
- - Fix missing missing types fr
2740
-
2741
- ### v2.1.0
2742
-
2743
- **Feat**
2744
-
2745
- - 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
2746
- - 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
2747
-
2748
- **Fixes and changes**
2749
-
2750
- - Improved MCP version compliance
2751
-
2752
- ### v2.0.0
2753
-
2754
- - **Unified Tool Architecture**: Introduced `.addTool()` to define CLI subcommands and MCP tools in a single declaration.
2755
- - **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.
2756
- - **Enhanced DXT Generation**: The `env` property on flags now automatically generates `user_config` entries in the DXT manifest.
2757
- - **Automatic Console Safety**: Console output is automatically and safely redirected in MCP mode to prevent protocol contamination.
2758
- - **Breaking Changes**: The `addMcpSubCommand()` and separate `addSubCommand()` for MCP tools are deprecated in favor of `addTool()` and `--s-mcp-serve`.
2759
-
2760
- ### v1.3.0
2761
-
2762
- - **Plugin System & Architecture**: Refactored to a dependency-injection model, making the core library dependency-free. Optional plugins for TOML/YAML.
2763
- - **Global Console Replacement**: Implemented the first version of automatic console suppression for MCP compliance.
2764
- - **Autonomous Build Improvements**: Significantly reduced DXT bundle size and removed dynamic `require` issues.
2765
-
2766
- ### v1.2.0
2767
-
2768
- - **Critical MCP Fixes**: Resolved issues where MCP tools with output schemas would fail. Ensured correct JSON-RPC 2.0 response formatting.
2769
- - **Enhanced Handler Context**: Added `isMcp` flag to the handler context for more reliable mode detection.
2770
-
2771
- ### v1.1.0
2772
-
2773
- - **Major Features**: First release with MCP Integration, System Flags (`--s-debug`, `--s-with-env`, etc.), and environment loading from files.
2774
-
2775
- ---
2776
-
2777
- ## Backlog
96
+ ArgParser includes built-in `--s-*` flags for development and debugging.
2778
97
 
2779
- - [x] Publish as an open-source library
2780
- - [x] Make ArgParser compatible with MCP out-of-the-box
2781
- - [x] Rename --LIB-\* flags to --s-\*
2782
- - [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)
2783
- - [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)
2784
- - [x] Add support for async type function to enable more flexibility
2785
- - [x] Upgrade to Zod/V4 (V4 does not support functions well, this will take more time, not a priority)
2786
- - [ ] Add System flags to args.systemArgs
2787
- - [ ] Improve flag options collision prevention
2788
- - [ ] (potentially) add support for fully typed parsed output, this has proven very challenging
2789
- - [ ] 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. |
2790
105
 
2791
- ### (known) Bugs / DX improvement points
106
+ ## Links
2792
107
 
2793
- - [ ] 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)**