Skip to content

Commit 7a16f22

Browse files
authored
Fix: Use helpful typer and invoke for root cli commands (#444)
* Use helpful typer and invoke for root cli commands * Fix lint
1 parent ad946ab commit 7a16f22

File tree

4 files changed

+90
-56
lines changed

4 files changed

+90
-56
lines changed

src/mcp_agent/cli/cloud/main.py

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22

33
import logging
44
import os
5+
from importlib.metadata import version as metadata_version
56
from logging.handlers import RotatingFileHandler
67
from pathlib import Path
78
from typing import Optional
8-
from importlib.metadata import version as metadata_version
99

10-
import click
1110
import typer
12-
from rich.console import Console
13-
from rich.panel import Panel
14-
from typer.core import TyperGroup
1511

1612
from mcp_agent.cli.cloud.commands import (
1713
configure_app,
@@ -20,27 +16,27 @@
2016
logout,
2117
whoami,
2218
)
23-
from mcp_agent.cli.cloud.commands.logger import tail_logs
2419
from mcp_agent.cli.cloud.commands.app import (
2520
delete_app,
2621
get_app_status,
2722
list_app_workflows,
2823
)
2924
from mcp_agent.cli.cloud.commands.apps import list_apps
25+
from mcp_agent.cli.cloud.commands.logger import tail_logs
26+
from mcp_agent.cli.cloud.commands.servers import (
27+
delete_server,
28+
describe_server,
29+
list_servers,
30+
)
3031
from mcp_agent.cli.cloud.commands.workflows import (
32+
cancel_workflow,
3133
describe_workflow,
34+
list_workflow_runs,
35+
list_workflows,
3236
resume_workflow,
3337
suspend_workflow,
34-
cancel_workflow,
35-
list_workflows,
36-
list_workflow_runs,
3738
)
38-
from mcp_agent.cli.cloud.commands.servers import (
39-
list_servers,
40-
describe_server,
41-
delete_server,
42-
)
43-
from mcp_agent.cli.exceptions import CLIError
39+
from mcp_agent.cli.utils.typer_utils import HelpfulTyperGroup
4440
from mcp_agent.cli.utils.ux import print_error
4541

4642
# Setup file logging
@@ -63,36 +59,6 @@
6359
logging.basicConfig(level=logging.INFO, handlers=[file_handler])
6460

6561

66-
class HelpfulTyperGroup(TyperGroup):
67-
"""Typer group that shows help before usage errors for better UX."""
68-
69-
def resolve_command(self, ctx, args):
70-
try:
71-
return super().resolve_command(ctx, args)
72-
except click.UsageError as e:
73-
click.echo(ctx.get_help())
74-
75-
console = Console(stderr=True)
76-
error_panel = Panel(
77-
str(e),
78-
title="Error",
79-
title_align="left",
80-
border_style="red",
81-
expand=True,
82-
)
83-
console.print(error_panel)
84-
ctx.exit(2)
85-
86-
def invoke(self, ctx):
87-
try:
88-
return super().invoke(ctx)
89-
except CLIError as e:
90-
# Handle CLIError cleanly - show error message and exit
91-
logging.error(f"CLI error: {str(e)}")
92-
print_error(str(e))
93-
ctx.exit(e.exit_code)
94-
95-
9662
# Root typer for `mcp-agent` CLI commands
9763
app = typer.Typer(
9864
help="MCP Agent Cloud CLI for deployment and management",

src/mcp_agent/cli/main.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99

1010
from __future__ import annotations
1111

12+
import logging
1213

1314
import typer
1415
from rich.console import Console
1516

17+
from mcp_agent.cli.utils.ux import print_error
18+
1619
# Mount existing cloud CLI
1720
try:
1821
from mcp_agent.cli.cloud.main import app as cloud_app # type: ignore
@@ -21,23 +24,36 @@
2124

2225

2326
# Local command groups (scaffolded)
27+
from mcp_agent.cli.cloud.commands import deploy_config, login, logout, whoami
28+
from mcp_agent.cli.commands import (
29+
check as check_cmd,
30+
)
2431
from mcp_agent.cli.commands import (
25-
init as init_cmd,
26-
quickstart as quickstart_cmd,
2732
config as config_cmd,
33+
)
34+
from mcp_agent.cli.commands import (
35+
go as go_cmd,
36+
)
37+
from mcp_agent.cli.commands import (
38+
init as init_cmd,
39+
)
40+
from mcp_agent.cli.commands import (
2841
keys as keys_cmd,
42+
)
43+
from mcp_agent.cli.commands import (
2944
models as models_cmd,
30-
go as go_cmd,
31-
check as check_cmd,
3245
)
33-
34-
from mcp_agent.cli.cloud.commands import deploy_config, login, logout, whoami
46+
from mcp_agent.cli.commands import (
47+
quickstart as quickstart_cmd,
48+
)
49+
from mcp_agent.cli.utils.typer_utils import HelpfulTyperGroup
3550

3651
app = typer.Typer(
3752
help="mcp-agent CLI",
3853
add_completion=False,
3954
no_args_is_help=False,
4055
context_settings={"help_option_names": ["-h", "--help"]},
56+
cls=HelpfulTyperGroup,
4157
)
4258

4359

@@ -139,8 +155,14 @@ def main(
139155

140156

141157
def run() -> None:
142-
"""Entry for __main__."""
143-
app()
158+
"""Run the CLI application."""
159+
try:
160+
app()
161+
except Exception as e:
162+
# Unexpected errors - log full exception and show clean error to user
163+
logging.exception("Unhandled exception in CLI")
164+
print_error(f"An unexpected error occurred: {str(e)}")
165+
raise typer.Exit(1) from e
144166

145167

146168
if __name__ == "__main__":
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Shared Typer utilities for MCP Agent CLI."""
2+
3+
import logging
4+
import click
5+
from rich.console import Console
6+
from rich.panel import Panel
7+
from typer.core import TyperGroup
8+
9+
from mcp_agent.cli.exceptions import CLIError
10+
from mcp_agent.cli.utils.ux import print_error
11+
12+
13+
class HelpfulTyperGroup(TyperGroup):
14+
"""Typer group that shows help before usage errors for better UX."""
15+
16+
def resolve_command(self, ctx, args):
17+
try:
18+
return super().resolve_command(ctx, args)
19+
except click.UsageError as e:
20+
click.echo(ctx.get_help())
21+
22+
console = Console(stderr=True)
23+
error_panel = Panel(
24+
str(e),
25+
title="Error",
26+
title_align="left",
27+
border_style="red",
28+
expand=True,
29+
)
30+
console.print(error_panel)
31+
ctx.exit(2)
32+
33+
def invoke(self, ctx):
34+
try:
35+
return super().invoke(ctx)
36+
except CLIError as e:
37+
# Handle CLIError cleanly - show error message and exit
38+
logging.error(f"CLI error: {str(e)}")
39+
print_error(str(e))
40+
ctx.exit(e.exit_code)

src/mcp_agent/server/app_server.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,9 @@ async def _relay_notify(request: Request):
338338
if gw_token:
339339
bearer = request.headers.get("Authorization", "")
340340
bearer_token = (
341-
bearer.split(" ", 1)[1] if bearer.lower().startswith("bearer ") else ""
341+
bearer.split(" ", 1)[1]
342+
if bearer.lower().startswith("bearer ")
343+
else ""
342344
)
343345
header_tok = request.headers.get("X-MCP-Gateway-Token", "")
344346
if not (
@@ -512,7 +514,9 @@ async def _internal_workflows_log(request: Request):
512514
if gw_token:
513515
bearer = request.headers.get("Authorization", "")
514516
bearer_token = (
515-
bearer.split(" ", 1)[1] if bearer.lower().startswith("bearer ") else ""
517+
bearer.split(" ", 1)[1]
518+
if bearer.lower().startswith("bearer ")
519+
else ""
516520
)
517521
header_tok = request.headers.get("X-MCP-Gateway-Token", "")
518522
if not (
@@ -558,7 +562,9 @@ async def _internal_human_prompts(request: Request):
558562
if gw_token:
559563
bearer = request.headers.get("Authorization", "")
560564
bearer_token = (
561-
bearer.split(" ", 1)[1] if bearer.lower().startswith("bearer ") else ""
565+
bearer.split(" ", 1)[1]
566+
if bearer.lower().startswith("bearer ")
567+
else ""
562568
)
563569
header_tok = request.headers.get("X-MCP-Gateway-Token", "")
564570
if not (

0 commit comments

Comments
 (0)