@alcyone-labs/arg-parser 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,6 +27,7 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
27
27
  - [Async Custom Parser Support](#async-custom-parser-support)
28
28
  - [Zod Schema Flags (Structured JSON Validation)](#zod-schema-flags-structured-json-validation)
29
29
  - [Type Conversion Examples](#type-conversion-examples)
30
+ - [DXT Package User Configuration & Path Handling](#dxt-package-user-configuration--path-handling)
30
31
  - [Hierarchical CLIs (Sub-Commands)](#hierarchical-clis-sub-commands)
31
32
  - [MCP Exposure Control](#mcp-exposure-control)
32
33
  - [Flag Inheritance (`inheritParentFlags`)](#flag-inheritance-inheritparentflags)
@@ -44,6 +45,9 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
44
45
  - [Common Pitfalls to Avoid](#common-pitfalls-to-avoid)
45
46
  - [Automatic MCP Server Mode (`--s-mcp-serve`)](#automatic-mcp-server-mode---s-mcp-serve)
46
47
  - [MCP Transports](#mcp-transports)
48
+ - [Adding custom HTTP routes (e.g., /health)](#adding-custom-http-routes-eg-health)
49
+ - [CORS and Authentication for streamable-http](#cors-and-authentication-for-streamable-http)
50
+ - [Multiple transports and improved logging](#multiple-transports-and-improved-logging)
47
51
  - [MCP Logging Configuration](#mcp-logging-configuration)
48
52
  - [Enhanced Logging (Recommended)](#enhanced-logging-recommended)
49
53
  - [Simple Logging Configuration](#simple-logging-configuration)
@@ -70,6 +74,8 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
70
74
  - [Typical Errors](#typical-errors)
71
75
  - [System Flags & Configuration](#system-flags--configuration)
72
76
  - [Changelog](#changelog)
77
+ - [v2.7.0](#v270)
78
+ - [v2.6.0](#v260)
73
79
  - [v2.5.0](#v250)
74
80
  - [v2.4.2](#v242)
75
81
  - [v2.4.1](#v241)
@@ -86,70 +92,6 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
86
92
  - [Backlog](#backlog)
87
93
  - [(known) Bugs / DX improvement points](#known-bugs--dx-improvement-points)
88
94
 
89
- - [Features Overview](#features-overview)
90
- - [Installation](#installation)
91
- - [Quick Start: The Unified `addTool` API](#quick-start-the-unified-addtool-api)
92
- - [How to Run It](#how-to-run-it)
93
- - [Setting Up System-Wide CLI Access](#setting-up-system-wide-cli-access)
94
- - [Parsing Command-Line Arguments](#parsing-command-line-arguments)
95
- - [Automatic Argument Detection](#automatic-argument-detection)
96
- - [Cannonical Usage Pattern](#cannonical-usage-pattern)
97
- - [Top-level await](#top-level-await)
98
- - [Promise-based parsing](#promise-based-parsing)
99
- - [Migrating from v1.x to the v2.0 `addTool` API](#migrating-from-v1x-to-the-v20-addtool-api)
100
- - [Before v2.0: Separate Definitions](#before-v20-separate-definitions)
101
- - [After v2.0: The Unified `addTool()` Method](#after-v20-the-unified-addtool-method)
102
- - [Core Concepts](#core-concepts)
103
- - [Defining Flags](#defining-flags)
104
- - [Type Handling and Validation](#type-handling-and-validation)
105
- - [Supported Type Formats](#supported-type-formats)
106
- - [Runtime Type Validation](#runtime-type-validation)
107
- - [Automatic Type Processing](#automatic-type-processing)
108
- - [Async Custom Parser Support](#async-custom-parser-support)
109
- - [Zod Schema Flags (Structured JSON Validation)](#zod-schema-flags-structured-json-validation)
110
- - [Type Conversion Examples](#type-conversion-examples)
111
- - [Hierarchical CLIs (Sub-Commands)](#hierarchical-clis-sub-commands)
112
- - [MCP Exposure Control](#mcp-exposure-control)
113
- - [Flag Inheritance (`inheritParentFlags`)](#flag-inheritance-inheritparentflags)
114
- - [MCP & Claude Desktop Integration](#mcp--claude-desktop-integration)
115
- - [Output Schema Support](#output-schema-support)
116
- - [Basic Usage](#basic-usage)
117
- - [Predefined Schema Patterns](#predefined-schema-patterns)
118
- - [Custom Zod Schemas](#custom-zod-schemas)
119
- - [MCP Version Compatibility](#mcp-version-compatibility)
120
- - [Automatic Error Handling](#automatic-error-handling)
121
- - [Writing Effective MCP Tool Descriptions](#writing-effective-mcp-tool-descriptions)
122
- - [Best Practices for Tool Descriptions](#best-practices-for-tool-descriptions)
123
- - [Complete Example: Well-Documented Tool](#complete-example-well-documented-tool)
124
- - [Parameter Description Guidelines](#parameter-description-guidelines)
125
- - [Common Pitfalls to Avoid](#common-pitfalls-to-avoid)
126
- - [Automatic MCP Server Mode (`--s-mcp-serve`)](#automatic-mcp-server-mode---s-mcp-serve)
127
- - [MCP Transports](#mcp-transports)
128
- - [MCP Log Path Configuration](#mcp-log-path-configuration)
129
- - [MCP Resources - Real-Time Data Feeds](#mcp-resources---real-time-data-feeds) ⭐
130
- - [Automatic Console Safety](#automatic-console-safety)
131
- - [Generating DXT Packages (`--s-build-dxt`)](#generating-dxt-packages---s-build-dxt)
132
- - [Logo Configuration](#logo-configuration)
133
- - [Supported Logo Sources](#supported-logo-sources)
134
- - [How DXT Generation Works](#how-dxt-generation-works)
135
- - [DXT Bundling Strategies](#dxt-bundling-strategies)
136
- - [Standard Approach (Recommended for Most Projects)](#standard-approach-recommended-for-most-projects)
137
- - [Native Dependencies Approach](#native-dependencies-approach)
138
- - [Typical Errors](#typical-errors)
139
- - [System Flags & Configuration](#system-flags--configuration)
140
- - [Changelog](#changelog)
141
- - [v2.3.0](#v230)
142
- - [v2.2.1](#v221)
143
- - [v2.2.0](#v220)
144
- - [v2.1.1](#v211)
145
- - [v2.1.0](#v210)
146
- - [v2.0.0](#v200)
147
- - [v1.3.0](#v130)
148
- - [v1.2.0](#v120)
149
- - [v1.1.0](#v110)
150
- - [Backlog](#backlog)
151
- - [(known) Bugs / DX improvement points](#known-bugs--dx-improvement-points)
152
-
153
95
  ## Features Overview
154
96
 
155
97
  - **Unified Tool Architecture**: Define tools once with `addTool()` and they automatically function as both CLI subcommands and MCP tools.
@@ -399,9 +341,9 @@ yarn unlink
399
341
 
400
342
  ArgParser's `parse()` method is async and automatically handles both synchronous and asynchronous handlers:
401
343
 
402
- ### Automatic Argument Detection
344
+ ### Auto-Execution versus Import: No More Boilerplate
403
345
 
404
- `parse()` can now be called without arguments for improved developer experience:
346
+ 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.
405
347
 
406
348
  ```typescript
407
349
  const cli = ArgParser.withMcp({
@@ -410,32 +352,27 @@ const cli = ArgParser.withMcp({
410
352
  handler: async (ctx) => ({ success: true, data: ctx.args }),
411
353
  });
412
354
 
413
- // You can call parse() without arguments
414
- // Automatically detects Node.js environment and uses process.argv.slice(2)
415
- async function main() {
416
- try {
417
- const result = await cli.parse(); // No arguments needed!
418
- console.log("Success:", result);
419
- } catch (error) {
420
- console.error("Error:", error.message);
421
- process.exit(1);
422
- }
423
- }
424
- ```
355
+ // Now, this will NOT automatically execute the parser if the script is imported, but will execute if called directly:
356
+ await cli.parse(undefined, {
357
+ importMetaUrl: import.meta.url
358
+ }).catch(handleError);
425
359
 
426
- **How it works:**
427
360
 
428
- - ✅ **Auto-detection**: When `parse()` is called without arguments, ArgParser automatically detects if it's running in Node.js
429
- - ✅ **Smart fallback**: Uses `process.argv.slice(2)` automatically in Node.js environments
430
- - **User-friendly warning**: Shows a helpful warning in CLI mode to inform users about the behavior
431
- - ✅ **Error handling**: Throws a clear error in non-Node.js environments when arguments are required
432
- - ✅ **Backward compatible**: Explicit arguments still work exactly as before
361
+ // Or, using the manual APIs:
362
+ await cli.parseIfExecutedDirectly(import.meta.url).catch((error) => {
363
+ console.error("Fatal error:", error instanceof Error ? error.message : String(error));
364
+ process.exit(1);
365
+ });
366
+ ```
433
367
 
434
- **When warnings are shown:**
368
+ **Replaces previously confusing patterns:**
435
369
 
436
- - ✅ CLI mode (when `appCommandName` is set)
437
- - Library/programmatic usage (no `appCommandName`)
438
- - ❌ MCP mode (warnings suppressed for clean MCP output)
370
+ ```typescript
371
+ // Brittle and breaks in sandboxes
372
+ if (import.meta.url === `file://${process.argv[1]}`) {
373
+ await cli.parse().catch(handleError);
374
+ }
375
+ ```
439
376
 
440
377
  ### Cannonical Usage Pattern
441
378
 
@@ -609,7 +546,14 @@ Flags are defined using the `IFlag` interface within the `flags` array of a tool
609
546
  interface IFlag {
610
547
  name: string; // Internal name (e.g., 'verbose')
611
548
  options: string[]; // Command-line options (e.g., ['--verbose', '-v'])
612
- type: "string" | "number" | "boolean" | "array" | "object" | Function | ZodSchema;
549
+ type:
550
+ | "string"
551
+ | "number"
552
+ | "boolean"
553
+ | "array"
554
+ | "object"
555
+ | Function
556
+ | ZodSchema;
613
557
  description?: string; // Help text
614
558
  mandatory?: boolean | ((args: any) => boolean); // Whether the flag is required
615
559
  defaultValue?: any; // Default value if not provided
@@ -618,9 +562,153 @@ interface IFlag {
618
562
  validate?: (value: any, parsedArgs?: any) => boolean | string | void; // Custom validation function
619
563
  allowMultiple?: boolean; // Allow the flag to be provided multiple times
620
564
  env?: string; // Links the flag to an environment variable for DXT packages, will automatically generate user_config entries in the DXT manifest and fill the flag value to the ENV value if found (process.env)
565
+ dxtOptions?: DxtOptions; // Customizes how this flag appears in DXT package user_config
566
+ }
567
+
568
+ interface DxtOptions {
569
+ type?: "string" | "directory" | "file" | "boolean" | "number"; // UI input type in Claude Desktop
570
+ title?: string; // Display name in Claude Desktop (defaults to formatted flag name)
571
+ sensitive?: boolean; // Whether to hide the value in UI (defaults to true for security)
572
+ default?: any; // Default value for the user_config entry
573
+ min?: number; // Minimum value (for number types)
574
+ max?: number; // Maximum value (for number types)
575
+ }
576
+ ```
577
+
578
+ ### DXT Package User Configuration & Path Handling
579
+
580
+ ArgParser v2.5.0 introduces comprehensive DXT (Desktop Extension Toolkit) support with rich user interfaces, automatic path resolution, and context-aware development tools.
581
+
582
+ #### Enhanced dxtOptions
583
+
584
+ When generating DXT packages with `--s-build-dxt`, you can create rich user configuration interfaces using `dxtOptions`:
585
+
586
+ ```typescript
587
+ import { ArgParser, DxtPathResolver } from "@alcyone-labs/arg-parser";
588
+
589
+ const parser = new ArgParser()
590
+ .withMcp({
591
+ name: "file-processor",
592
+ version: "1.0.0",
593
+ logPath: "${HOME}/logs/file-processor.log", // DXT variables supported!
594
+ })
595
+ .addFlag({
596
+ name: "input-file",
597
+ description: "File to process",
598
+ type: "string",
599
+ mandatory: true,
600
+ dxtOptions: {
601
+ type: "file",
602
+ title: "Select Input File",
603
+ },
604
+ })
605
+ .addFlag({
606
+ name: "output-dir",
607
+ description: "Output directory for processed files",
608
+ type: "string",
609
+ dxtOptions: {
610
+ type: "directory",
611
+ localDefault: "${DOCUMENTS}/processed-files", // Smart defaults with DXT variables
612
+ title: "Output Directory",
613
+ },
614
+ })
615
+ .addFlag({
616
+ name: "api-key",
617
+ description: "API authentication key",
618
+ type: "string",
619
+ env: "API_KEY",
620
+ dxtOptions: {
621
+ type: "string",
622
+ sensitive: true, // Excluded from DXT manifest for security
623
+ title: "API Key",
624
+ },
625
+ })
626
+ .addFlag({
627
+ name: "quality",
628
+ description: "Processing quality (1-100)",
629
+ type: "number",
630
+ dxtOptions: {
631
+ type: "number",
632
+ min: 1,
633
+ max: 100,
634
+ localDefault: 85,
635
+ title: "Quality (%)",
636
+ },
637
+ })
638
+ .addFlag({
639
+ name: "parallel",
640
+ description: "Enable parallel processing",
641
+ type: "boolean",
642
+ dxtOptions: {
643
+ type: "boolean",
644
+ localDefault: true,
645
+ title: "Parallel Processing",
646
+ },
647
+ });
648
+ ```
649
+
650
+ #### DXT Variables & Path Resolution
651
+
652
+ ArgParser automatically resolves paths based on your runtime environment:
653
+
654
+ ```typescript
655
+ // DXT variables work everywhere - in flags, MCP config, and code
656
+ const logPath = "${HOME}/logs/app.log";
657
+ const configPath = "${DOCUMENTS}/myapp/config.json";
658
+ const resourcePath = "${__dirname}/templates/default.hbs";
659
+
660
+ // Helper functions for common patterns
661
+ const userDataPath = DxtPathResolver.createUserDataPath("cache.db");
662
+ const tempPath = DxtPathResolver.createTempPath("processing.tmp");
663
+ const configPath = DxtPathResolver.createConfigPath("settings.json");
664
+
665
+ // Context detection
666
+ const context = DxtPathResolver.detectContext();
667
+ if (context.isDxt) {
668
+ console.log("Running in DXT environment");
669
+ } else {
670
+ console.log("Running in development");
621
671
  }
622
672
  ```
623
673
 
674
+ **Supported DXT Variables:**
675
+
676
+ - `${HOME}` - User's home directory
677
+ - `${DOCUMENTS}` - Documents folder
678
+ - `${DOWNLOADS}` - Downloads folder
679
+ - `${DESKTOP}` - Desktop folder
680
+ - `${__dirname}` - Entry point directory (DXT package root in DXT)
681
+ - `${pathSeparator}` - Platform-specific path separator
682
+ - `${DXT_DIR}` - DXT package directory (DXT only)
683
+ - `${EXTENSION_DIR}` - Extension root directory (DXT only)
684
+
685
+ #### dxtOptions Properties
686
+
687
+ | Property | Type | Description |
688
+ | -------------- | ------------------------------------------------------------ | ------------------------------------------------ |
689
+ | `type` | `'string' \| 'file' \| 'directory' \| 'boolean' \| 'number'` | UI component type |
690
+ | `sensitive` | `boolean` | Mark as sensitive (excluded from manifest) |
691
+ | `localDefault` | `string \| number \| boolean` | Default for development (supports DXT variables) |
692
+ | `multiple` | `boolean` | Allow multiple values |
693
+ | `min` / `max` | `number` | Validation constraints |
694
+ | `title` | `string` | Custom display name |
695
+
696
+ #### Security & Best Practices
697
+
698
+ - **Sensitive Data**: Use `sensitive: true` for passwords, API keys, tokens
699
+ - **Smart Defaults**: Use DXT variables in `localDefault` for portable paths
700
+ - **Type Safety**: Match `dxtOptions.type` with flag `type` for validation
701
+ - **Cross-Platform**: Use `${pathSeparator}` for platform-independent paths
702
+
703
+ #### Comprehensive Documentation
704
+
705
+ For detailed guides and examples:
706
+
707
+ - **[DXT Path Handling Guide](./docs/DXT_PATH_HANDLING.md)** - Complete path resolution guide
708
+ - **[dxtOptions API Documentation](./docs/DXT_OPTIONS_API.md)** - Full API reference with examples
709
+ - **[DXT Migration Guide](./docs/DXT_MIGRATION.md)** - Migrate existing applications
710
+ - **[DXT Practical Examples](./docs/DXT_EXAMPLES.md)** - Real-world usage patterns
711
+
624
712
  ### Type Handling and Validation
625
713
 
626
714
  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.
@@ -1207,6 +1295,14 @@ my-tool --s-mcp-serve --s-mcp-transports '[{"type":"stdio"},{"type":"sse","port"
1207
1295
  # Single transport with custom options
1208
1296
  my-tool --s-mcp-serve --s-mcp-transport sse --s-mcp-port 3000 --s-mcp-host 0.0.0.0
1209
1297
 
1298
+ # Streamable HTTP CORS/auth via CLI flags (JSON strings)
1299
+ my-tool --s-mcp-serve \
1300
+ --s-mcp-transport streamable-http \
1301
+ --s-mcp-port 3002 --s-mcp-path /api/mcp \
1302
+ --s-mcp-cors '{"origins":["http://localhost:5173"],"credentials":true,"methods":["GET","POST","OPTIONS"],"maxAge":600}' \
1303
+ --s-mcp-auth '{"required":true,"scheme":"jwt","jwt":{"algorithms":["HS256"],"secret":"$MY_JWT_SECRET"},"publicPaths":["/health"]}'
1304
+
1305
+
1210
1306
  # Custom log path via CLI flag (logs to specified file instead of ./logs/mcp.log)
1211
1307
  my-tool --s-mcp-serve --s-mcp-log-path /var/log/my-mcp-server.log
1212
1308
 
@@ -1214,6 +1310,130 @@ my-tool --s-mcp-serve --s-mcp-log-path /var/log/my-mcp-server.log
1214
1310
  const parser = ArgParser.withMcp({
1215
1311
  mcp: {
1216
1312
  serverInfo: { name: 'my-tool', version: '1.0.0' },
1313
+
1314
+ ```
1315
+
1316
+ ### CORS and Authentication for streamable-http
1317
+
1318
+ CORS is often required when connecting a Web UI to an MCP server over HTTP.
1319
+
1320
+ - Programmatic transport config:
1321
+
1322
+ ```ts
1323
+ import type { McpTransportConfig } from "@alcyone-labs/arg-parser";
1324
+
1325
+ const defaultTransports: McpTransportConfig[] = [{
1326
+ type: "streamable-http",
1327
+ port: 3002,
1328
+ path: "/api/mcp",
1329
+ cors: {
1330
+ origins: ["http://localhost:5173", /^https?:\/\/example\.com$/],
1331
+ methods: ["GET","POST","OPTIONS"],
1332
+ headers: ["Content-Type","Authorization","MCP-Session-Id"],
1333
+ exposedHeaders: ["MCP-Session-Id"],
1334
+ credentials: true,
1335
+ maxAge: 600,
1336
+ },
1337
+ auth: {
1338
+ required: true,
1339
+ scheme: "jwt", // or "bearer"
1340
+ // Bearer allowlist:
1341
+ // allowedTokens: ["token1","token2"],
1342
+ // JWT verification (HS256):
1343
+ // jwt: { algorithms: ["HS256"], secret: process.env.JWT_SECRET },
1344
+ // JWT verification (RS256 with static public key):
1345
+ // jwt: { algorithms: ["RS256"], publicKey: process.env.RS256_PUBLIC_KEY },
1346
+ // JWT verification (RS256 with dynamic JWKS):
1347
+ // jwt: { algorithms: ["RS256"], getPublicKey: async (header)=>{ /* fetch JWKS and return PEM */ } },
1348
+ publicPaths: ["/health"],
1349
+ protectedPaths: undefined, // if set, only listed paths require auth
1350
+ // Optional custom validator to add extra checks
1351
+ validator: async (req, token) => true,
1352
+ },
1353
+ }];
1354
+ ```
1355
+
1356
+ - CLI flags (JSON strings):
1357
+
1358
+ ```bash
1359
+ my-tool --s-mcp-serve \
1360
+ --s-mcp-transport streamable-http \
1361
+ --s-mcp-port 3002 --s-mcp-path /api/mcp \
1362
+ --s-mcp-cors '{"origins":["http://localhost:5173"],"credentials":true,"methods":["GET","POST","OPTIONS"],"maxAge":600}' \
1363
+ --s-mcp-auth '{"required":true,"scheme":"jwt","jwt":{"algorithms":["HS256"],"secret":"'$JWT_SECRET'"},"publicPaths":["/health"]}'
1364
+ ```
1365
+
1366
+ - Express hook for custom routes:
1367
+
1368
+ ```ts
1369
+ httpServer: {
1370
+ configureExpress: (app) => {
1371
+ app.get("/health", (_req, res) => res.json({ ok: true }));
1372
+ },
1373
+ }
1374
+ ```
1375
+
1376
+ See examples:
1377
+ - examples/streamable-http/secure-mcp.ts (HS256)
1378
+ - examples/streamable-http/rs256-mcp.ts (RS256)
1379
+ - examples/streamable-http/jwks-mcp.ts (JWKS)
1380
+ - examples/streamable-http/bearer-mcp.ts (Bearer)
1381
+ - examples/streamable-http/productized-mcp.ts (token + session usage)
1382
+
1383
+ #### TypeScript types
1384
+
1385
+ - CorsOptions
1386
+
1387
+ ```ts
1388
+ export type CorsOptions = {
1389
+ origins?: "*" | string | RegExp | Array<string | RegExp>;
1390
+ methods?: string[];
1391
+ headers?: string[];
1392
+ exposedHeaders?: string[];
1393
+ credentials?: boolean;
1394
+ maxAge?: number;
1395
+ };
1396
+ ```
1397
+
1398
+ - AuthOptions and JwtVerifyOptions
1399
+
1400
+ ```ts
1401
+ export type JwtVerifyOptions = {
1402
+ algorithms?: ("HS256" | "RS256")[];
1403
+ secret?: string; // HS256
1404
+ publicKey?: string; // RS256 static
1405
+ getPublicKey?: (header: Record<string, unknown>, payload: Record<string, unknown>) => Promise<string> | string; // RS256 dynamic
1406
+ audience?: string | string[];
1407
+ issuer?: string | string[];
1408
+ clockToleranceSec?: number;
1409
+ };
1410
+
1411
+ export type AuthOptions = {
1412
+ required?: boolean; // default true for MCP endpoint
1413
+ scheme?: "bearer" | "jwt";
1414
+ allowedTokens?: string[]; // simple bearer allowlist
1415
+ validator?: (req: any, token: string | undefined) => boolean | Promise<boolean>;
1416
+ jwt?: JwtVerifyOptions;
1417
+ publicPaths?: string[]; // paths that skip auth
1418
+ protectedPaths?: string[]; // if provided, only these paths require auth
1419
+ customMiddleware?: (req: any, res: any, next: any) => any; // full control hook
1420
+ };
1421
+ ```
1422
+
1423
+ - HttpServerOptions
1424
+
1425
+ ```ts
1426
+ export type HttpServerOptions = {
1427
+ configureExpress?: (app: any) => void;
1428
+ };
1429
+ ```
1430
+
1431
+ Notes:
1432
+ - When credentials are true, Access-Control-Allow-Origin echoes the request Origin rather than using "*".
1433
+ - You can manage CORS for non-MCP routes in configureExpress.
1434
+ - Use publicPaths to allow some routes without auth; use protectedPaths to only require auth for certain routes.
1435
+
1436
+
1217
1437
  log: {
1218
1438
  level: 'debug', // Capture all log levels
1219
1439
  logToFile: '/var/log/my-mcp-server.log',
@@ -1221,9 +1441,28 @@ const parser = ArgParser.withMcp({
1221
1441
  }
1222
1442
  // LEGACY: logPath: '/var/log/my-mcp-server.log' // Still works
1223
1443
  }
1444
+
1445
+ ### Adding custom HTTP routes (e.g., /health)
1446
+
1447
+ Use the httpServer.configureExpress(app) hook to register routes before MCP endpoints are bound. Example:
1448
+
1449
+ ```ts
1450
+ const cli = ArgParser.withMcp({
1451
+ mcp: {
1452
+ serverInfo: { name: "my-mcp", version: "1.0.0" },
1453
+ defaultTransports: [
1454
+ { type: "streamable-http", port: 3002, path: "/api/mcp", auth: { required: true, publicPaths: ["/health"] } }
1455
+ ],
1456
+ httpServer: { configureExpress: (app) => app.get("/health", (_req, res) => res.json({ ok: true })) },
1457
+ }
1224
1458
  });
1459
+ ```
1460
+
1461
+ - To make a route public (no auth), add it to auth.publicPaths.
1462
+ - CORS headers for non-MCP paths can be applied by your own middleware inside the hook if desired.
1463
+
1464
+ ### Multiple transports and improved logging
1225
1465
 
1226
- # Multiple transports and improved logging (configured via --s-mcp-serve system flag)
1227
1466
  const cli = ArgParser.withMcp({
1228
1467
  appName: 'multi-tool',
1229
1468
  appCommandName: 'multi-tool',
@@ -1407,9 +1646,9 @@ const cli = ArgParser.withMcp({
1407
1646
  ctx.logger.mcpError(`Shutting down: ${ctx.reason}`);
1408
1647
  await cleanupResources();
1409
1648
  await closeDatabase();
1410
- }
1411
- }
1412
- }
1649
+ },
1650
+ },
1651
+ },
1413
1652
  });
1414
1653
  ```
1415
1654
 
@@ -1422,6 +1661,7 @@ const cli = ArgParser.withMcp({
1422
1661
  **Context Properties:**
1423
1662
 
1424
1663
  Each lifecycle event receives a context object with:
1664
+
1425
1665
  - `getFlag(name)`: Access parsed CLI flags and environment variables
1426
1666
  - `logger`: MCP-compliant logger instance for the current context
1427
1667
  - `serverInfo`: Server information (name, version, description)
@@ -1824,6 +2064,47 @@ ArgParser includes built-in `--s-*` flags for development, debugging, and config
1824
2064
 
1825
2065
  ## Changelog
1826
2066
 
2067
+ ### v2.7.0
2068
+
2069
+ **Feat**
2070
+
2071
+ **MCP**:
2072
+
2073
+ - Add support for CORS and authentication options, enabling powerful tools to serve Web UIs and publicly exposed APIs
2074
+ - Add supports for configuring express by exposing the app before it runs
2075
+
2076
+ **CLI**:
2077
+
2078
+ - 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.
2079
+
2080
+ ### v2.6.0
2081
+
2082
+ **Feat**
2083
+
2084
+ **DXT**:
2085
+
2086
+ - 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()`.
2087
+ - 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.
2088
+
2089
+ Read more her: [DXT Package User Configuration & Path Handling](#dxt-package-user-configuration--path-handling)
2090
+
2091
+ **Fixes and Changes**
2092
+
2093
+ **DXT**:
2094
+
2095
+ - Improve handling of sensitive env variable, they were previously always showing as sensitive.
2096
+
2097
+ **Known Limitations**
2098
+
2099
+ **DXT**:
2100
+
2101
+ 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:
2102
+
2103
+ 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)
2104
+ 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)
2105
+ 3. In some cases if your CLI entrypoint does not run a main loop (see documentation for working examples)
2106
+ 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)
2107
+
1827
2108
  ### v2.5.0
1828
2109
 
1829
2110
  **Feat**
@@ -1852,7 +2133,7 @@ ArgParser includes built-in `--s-*` flags for development, debugging, and config
1852
2133
  - MCP client now sanitizes the method names to ensure spec-compliants MCP behavior, names that collision will be logged
1853
2134
  - There were some use-cases where the DXT bundling failed, this new release addresses all of them, namely:
1854
2135
  1. Output structure will match that of the input so relative files (for example DB migrations) will work
1855
- 2.
2136
+ 2. Deeper folder structure was previously not working
1856
2137
  - DXT bundling now supports including resources via options: `{dxt: {include: ['TSDown blob-like paths']}`
1857
2138
  - 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
1858
2139
 
@@ -1946,8 +2227,8 @@ Make sure to clearly identify if you need to include the node_modules or not. In
1946
2227
  - [x] Upgrade to Zod/V4 (V4 does not support functions well, this will take more time, not a priority)
1947
2228
  - [ ] Add System flags to args.systemArgs
1948
2229
  - [ ] Improve flag options collision prevention
1949
- - [ ] Add support for locales / translations
1950
2230
  - [ ] (potentially) add support for fully typed parsed output, this has proven very challenging
2231
+ - [ ] Add support for locales / translations
1951
2232
 
1952
2233
  ### (known) Bugs / DX improvement points
1953
2234