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