Output Management

August 22, 2025 · View on GitHub

Overview

MCP CLI provides a centralized output management system that ensures consistent formatting, colors, and styles across the entire application. The Output class serves as a singleton manager for all console output, supporting multiple themes, output modes, and Rich formatting capabilities.

Key Features

  • Singleton Pattern: Single instance manages all output for consistency
  • Theme Support: Adapts output to different themes (default, dark, light, minimal, terminal)
  • Output Modes: Quiet mode suppresses non-essential output, verbose mode shows debug info
  • Rich Integration: Full support for Rich library components (panels, tables, markdown)
  • Platform Compatibility: Works across Windows, macOS, and Linux
  • Error Handling: Separate console for stderr output
  • Progressive Enhancement: Gracefully degrades for non-TTY environments

Basic Usage

Getting the Output Instance

from mcp_cli.ui.output import get_output

# Get the singleton instance
ui = get_output()

# Or use convenience imports
from mcp_cli.ui.output import info, success, error

info("Information message")
success("Operation completed")
error("Something went wrong")

Output Levels

The output system provides different message levels for various scenarios:

ui = get_output()

# Debug - only shown in verbose mode
ui.debug("Detailed debug information")

# Info - general information
ui.info("Processing file...")

# Success - positive outcomes
ui.success("✓ File processed successfully")

# Warning - potential issues
ui.warning("File size exceeds recommended limit")

# Error - recoverable errors
ui.error("Failed to process file")

# Fatal - unrecoverable errors
ui.fatal("Critical system error - exiting")

Output Modes

Quiet Mode

Suppress non-essential output for scripting or automation:

ui = get_output()
ui.set_output_mode(quiet=True)

# These will be suppressed
ui.info("Processing...")
ui.status("Current status")
ui.tip("Helpful tip")

# These will still show (errors and success)
ui.success("Completed")
ui.error("Failed")

Verbose Mode

Show additional debug information:

ui = get_output()
ui.set_output_mode(verbose=True)

# Debug messages now visible
ui.debug("Entering function X")
ui.debug("Variable state: ...")

Formatted Output

Tips and Hints

# Helpful tips with emoji (theme-dependent)
ui.tip("Use 'mcp-cli --help' for more options")

# Subtle hints
ui.hint("Press Ctrl+C to cancel")

# Command suggestions
ui.command("git status", "Check repository status")
ui.command("npm install")  # Without description

# Status messages
ui.status("Connecting to server...")

Panels

Display content in bordered panels:

# Simple panel
ui.panel("Important information", title="Notice")

# Panel with markdown content
from rich.markdown import Markdown
content = Markdown("# Heading\n\nSome **bold** text")
ui.panel(content, title="Documentation")

# Styled panel
ui.panel(
    "Error details here",
    title="Error",
    style="red"
)

Tables

Create and display formatted tables:

# Create a table
table = ui.table(title="Results")
table.add_column("Name", style="cyan")
table.add_column("Status", style="green")
table.add_column("Time")

# Add rows
table.add_row("Task 1", "✓ Complete", "1.23s")
table.add_row("Task 2", "✓ Complete", "0.45s")
table.add_row("Task 3", "✗ Failed", "0.12s")

# Display the table
ui.print_table(table)

Markdown

Render markdown content with formatting:

ui.markdown("""
# Project Setup

1. Install dependencies: `npm install`
2. Configure environment: `.env`
3. Run development server: `npm run dev`

**Note**: Requires Node.js 18+
""")

Rules

Create horizontal dividers:

# Simple rule
ui.rule()

# Rule with title
ui.rule("Configuration")

# Styled rule
ui.rule("⚡ Performance", style="yellow")

Special Outputs

User and Assistant Messages

For chat-like interfaces:

# User message
ui.user_message("How do I configure the database?")

# Assistant response
ui.assistant_message(
    "To configure the database, update the `.env` file...",
    elapsed=1.23  # Optional response time
)

Tool Calls

Display tool or function invocations:

# Simple tool call
ui.tool_call("fetch_data")

# Tool call with arguments
ui.tool_call("query_database", {
    "table": "users",
    "limit": 10,
    "filter": {"active": True}
})

Progress and Loading

Progress Context Manager

with ui.progress("Processing files...") as progress:
    # Work happens here
    for file in files:
        process_file(file)

Loading Spinner

with ui.loading("Downloading..."):
    # Long-running operation
    download_large_file()

# Custom spinner
with ui.loading("Thinking...", spinner="dots"):
    analyze_data()

Interactive Prompts

Text Input

# Simple prompt
name = ui.prompt("Enter your name")

# Prompt with default
env = ui.prompt("Environment", default="production")

Confirmation

# Yes/no confirmation
if ui.confirm("Continue with deployment?"):
    deploy()

# With default value
if ui.confirm("Delete file?", default=False):
    delete_file()

Theme Integration

The output system automatically adapts to the current theme:

Default/Dark/Light Themes

  • Full Rich formatting with colors and styles
  • Emoji icons in messages
  • Bordered panels and formatted tables
  • Syntax highlighting in code blocks

Minimal Theme

  • Plain text output without ANSI codes
  • No emoji or special characters
  • Simple text-based tables
  • Suitable for logging or non-interactive environments

Terminal Theme

  • Basic ANSI colors only
  • No emoji, simplified formatting
  • ASCII-style panels and tables
  • Optimized for basic terminal emulators
from mcp_cli.ui.theme import set_theme

# Switch to minimal theme
set_theme("minimal")
ui.info("This will be plain text: INFO: This will be plain text")

# Switch to terminal theme
set_theme("terminal")
ui.success("This will be: OK: This will be green")

# Switch back to default
set_theme("default")
ui.success("✓ Full formatting restored")

Console Access

For advanced usage, access the underlying Rich console:

# Get raw console
console = ui.get_raw_console()

# Use Rich features directly
from rich.syntax import Syntax
code = Syntax(python_code, "python", theme="monokai")
console.print(code)

Best Practices

1. Use Appropriate Message Levels

# ✅ GOOD
ui.debug("Entering validation loop")  # Debug info
ui.info("Validating configuration")   # General info
ui.success("Configuration valid")     # Positive outcome
ui.warning("Using default value")     # Potential issue
ui.error("Invalid configuration")     # Error

# ❌ BAD
ui.info("ERROR: Failed!")  # Wrong level
ui.debug("Success!")        # Confusing

2. Respect Output Modes

# ✅ GOOD
def process_files(files, verbose=False):
    ui.set_output_mode(verbose=verbose)
    
    for file in files:
        ui.debug(f"Processing {file}")  # Only in verbose
        # ... process ...
        ui.success(f"✓ {file}")  # Always shown

# ❌ BAD
def process_files(files, verbose=False):
    if verbose:
        print(f"Processing...")  # Don't use print directly

3. Handle Non-TTY Environments

# ✅ GOOD
import sys

if not sys.stdout.isatty():
    # Output automatically adapts
    ui.info("Running in non-interactive mode")

4. Use Theme-Agnostic Code

# ✅ GOOD
ui.success("Operation completed")  # Theme handles formatting

# ❌ BAD
if theme == "minimal":
    print("OK: Operation completed")
else:
    ui.success("✓ Operation completed")

5. Consistent Error Output

# ✅ GOOD
try:
    risky_operation()
except ValueError as e:
    ui.error(f"Invalid value: {e}")
except Exception as e:
    ui.fatal(f"Unexpected error: {e}")
    sys.exit(1)

Demo Script

A comprehensive output demo is available:

# Run the output demo
uv run examples/ui_output_demo.py

The demo showcases:

  • All message levels and formatting
  • Theme switching and adaptation
  • Rich components (panels, tables, markdown)
  • Progress and loading indicators
  • Interactive prompts
  • Special outputs (user/assistant/tool)
  • Error handling and fallbacks

Module Reference

Core Functions

FunctionDescriptionExample
get_output()Get singleton instanceui = get_output()
print()General outputprint("Message")
debug()Debug message (verbose only)debug("Details")
info()Information messageinfo("Processing...")
success()Success messagesuccess("Complete")
warning()Warning messagewarning("Caution")
error()Error message (stderr)error("Failed")
fatal()Fatal error (stderr)fatal("Critical")
tip()Helpful tiptip("Try this")
hint()Subtle hinthint("Note: ...")
status()Status updatestatus("Working...")
command()Command suggestioncommand("npm install")
clear()Clear screenclear()
rule()Horizontal dividerrule("Section")

Output Class Methods

MethodDescription
set_output_mode(quiet, verbose)Set output verbosity
set_theme(theme)Change output theme
panel(content, title, style)Display panel
markdown(text)Render markdown
table(title)Create table
print_table(table)Display table
progress(description)Progress context
loading(message, spinner)Loading spinner
user_message(message)User input display
assistant_message(message, elapsed)Assistant response
tool_call(name, arguments)Tool invocation
prompt(message, default)Text input
confirm(message, default)Yes/no prompt
get_raw_console()Access Rich console

Testing

The output module includes comprehensive tests:

# Run output tests
uv run pytest tests/mcp_cli/ui/test_output.py -v

# With coverage
uv run pytest tests/mcp_cli/ui/test_output.py --cov=mcp_cli.ui.output

Test coverage includes:

  • Singleton behavior
  • Output modes (quiet/verbose)
  • All message levels
  • Theme integration
  • Rich components
  • Error handling
  • Platform compatibility