From eb2df7524e4fd9f4b80cdd8366da3ffa00aae0ae Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Sat, 14 Feb 2026 16:52:02 -0500 Subject: [PATCH] refactor: make --config a true global CLI option - Restructured argument parser using argparse parents pattern - Created _create_global_options_parser() for shared global options - Updated all subparsers to inherit global options - Removed redundant --config definitions from run and test commands - Updated documentation to show both usage positions - --config now works before or after command name --- CHANGELOG.md | 5 ++++ README.md | 9 ++++++ src/itential_mcp/runtime/constants.py | 3 +- src/itential_mcp/runtime/parser.py | 42 ++++++++++++++++++++++----- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abff011c..2110e4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed +- **CLI**: Restructured argument parser to make `--config` a true global option + ## [0.11.1] - 2026-01-16 ### Fixed diff --git a/README.md b/README.md index 2ab4cb23..35a40367 100644 --- a/README.md +++ b/README.md @@ -204,10 +204,19 @@ itential-mcp run --transport sse --host 0.0.0.0 --port 8000 ### General Options +Global options can be specified before or after the command name. + | Option | Description | Default | |------------|-------------------------|---------| | `--config` | Path to the config file | none | +**Examples:** +```bash +# Both of these work identically: +itential-mcp --config config.conf run +itential-mcp run --config config.conf +``` + ### Server Options | Option | Description | Default | diff --git a/src/itential_mcp/runtime/constants.py b/src/itential_mcp/runtime/constants.py index 89695afe..1e252483 100644 --- a/src/itential_mcp/runtime/constants.py +++ b/src/itential_mcp/runtime/constants.py @@ -45,7 +45,7 @@ class CommandConfig: CommandConfig( name="run", description="Run the MCP server", - arguments={"--config": {"help": CONFIG_HELP_MESSAGE}}, + arguments={}, add_platform_group=True, add_server_group=True, ), @@ -80,7 +80,6 @@ class CommandConfig: name="test", description="Test connection to Itential Platform", arguments={ - "--config": {"help": CONFIG_HELP_MESSAGE}, "--timeout": { "type": int, "default": 30, diff --git a/src/itential_mcp/runtime/parser.py b/src/itential_mcp/runtime/parser.py index 8e350271..49ec45b6 100644 --- a/src/itential_mcp/runtime/parser.py +++ b/src/itential_mcp/runtime/parser.py @@ -18,10 +18,31 @@ from .handlers import get_command_handler -def _create_main_parser() -> cli.Parser: +def _create_global_options_parser() -> cli.Parser: + """ + Create parser for global options that apply to all commands. + + This parser is used as a parent parser for all subcommands to ensure + global options like --config are available to all commands. + + Returns: + cli.Parser: Parser with global options (add_help=False for parent) + + Raises: + None + """ + parser = cli.Parser(add_help=False) + parser.add_argument("--config", metavar="FILE", help=constants.CONFIG_HELP_MESSAGE) + return parser + + +def _create_main_parser(global_options_parser: cli.Parser) -> cli.Parser: """ Create and configure the main argument parser. + Args: + global_options_parser: Parser with global options to inherit + Returns: cli.Parser: The configured main parser @@ -32,9 +53,9 @@ def _create_main_parser() -> cli.Parser: prog=constants.APP_NAME, add_help=False, description=constants.APP_DESCRIPTION, + parents=[global_options_parser], ) - parser.add_argument("--config", help=constants.CONFIG_HELP_MESSAGE) parser.add_argument( "-h", "--help", action="store_true", help=constants.GLOBAL_HELP_MESSAGE ) @@ -42,12 +63,13 @@ def _create_main_parser() -> cli.Parser: return parser -def _create_subparsers(parser: cli.Parser) -> None: +def _create_subparsers(parser: cli.Parser, global_options_parser: cli.Parser) -> None: """ Create and configure subparsers for different commands using configuration. Args: - parser (cli.Parser): The main parser to add subparsers to + parser: The main parser to add subparsers to + global_options_parser: Parser with global options to inherit Returns: None @@ -59,11 +81,16 @@ def _create_subparsers(parser: cli.Parser) -> None: for command_config in constants.COMMANDS: cmd = subparsers.add_parser( - command_config.name, description=command_config.description + command_config.name, + description=command_config.description, + parents=[global_options_parser], ) # Add command-specific arguments for arg_name, arg_config in command_config.arguments.items(): + # Skip --config as it comes from parent parser + if arg_name == "--config": + continue if arg_name.startswith("--"): cmd.add_argument(arg_name, **arg_config) else: @@ -143,8 +170,9 @@ def parse_args(args: Sequence) -> Tuple[Callable, Tuple[Any, ...], dict]: TypeError: If the command handler is invalid AttributeError: If the command doesn't exist """ - parser = _create_main_parser() - _create_subparsers(parser) + global_options_parser = _create_global_options_parser() + parser = _create_main_parser(global_options_parser) + _create_subparsers(parser, global_options_parser) parsed_args = parser.parse_args(args=args)