Skip to content

MCP Main Module

Entry point and CLI for the MCP server application.

Overview

The MCP main module provides the command-line interface and entry point for running the Shannot MCP server. It handles argument parsing, executor initialization, and server lifecycle management.

Key Components:

  • entrypoint() - Main entry point for shannot-mcp command
  • parse_args() - Command-line argument parser
  • Server initialization - Sets up executor and server based on arguments
  • Logging configuration - Configures logging for debugging

Command-Line Interface

Basic Usage

# Start MCP server with default settings
shannot-mcp

# Use specific profile
shannot-mcp --profile diagnostics

# Use multiple profiles
shannot-mcp --profile minimal --profile diagnostics

# Enable verbose logging
shannot-mcp --verbose

# Use remote executor target
shannot-mcp --target production

Command-Line Options

Options:
  --profile PATH, -p     Profile to use (can be specified multiple times)
  --target NAME, -t      Remote executor target from config
  --verbose, -v          Enable verbose logging
  --help, -h            Show help message

Usage Patterns

Local Execution

# Run on local Linux system with diagnostics profile
shannot-mcp --profile diagnostics

The server will: 1. Create a LocalExecutor 2. Load the diagnostics profile 3. Start listening on stdio for MCP requests

Remote Execution

# Execute on remote system configured as "production"
shannot-mcp --target production --profile diagnostics

The server will: 1. Load configuration from ~/.config/shannot/config.toml 2. Create SSHExecutor for "production" target 3. Connect to remote system 4. Execute commands remotely in sandbox

Multiple Profiles

# Serve multiple profiles
shannot-mcp --profile minimal --profile diagnostics --profile readonly

Each profile is available as a separate MCP resource and can be used by the LLM client.

Debugging

# Enable verbose logging for troubleshooting
shannot-mcp --verbose --profile diagnostics 2> /tmp/shannot-mcp.log

Logs will show: - Profile loading - Executor initialization - Tool invocations - Command executions - Errors and warnings

Integration with LLM Clients

Claude Desktop Integration

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "shannot": {
      "command": "shannot-mcp",
      "args": ["--profile", "diagnostics"]
    }
  }
}

Or use the installer:

shannot mcp install claude-desktop --profile diagnostics

Claude Code Integration

Add to Claude Code config:

{
  "mcpServers": {
    "shannot": {
      "command": "shannot-mcp",
      "args": ["--profile", "diagnostics", "--verbose"]
    }
  }
}

Or use the installer:

shannot mcp install claude-code --profile diagnostics

Remote System Monitoring

Monitor production systems from Claude:

{
  "mcpServers": {
    "shannot-prod": {
      "command": "shannot-mcp",
      "args": ["--target", "production", "--profile", "diagnostics"]
    },
    "shannot-staging": {
      "command": "shannot-mcp",
      "args": ["--target", "staging", "--profile", "diagnostics"]
    }
  }
}

Now Claude can run diagnostics on both production and staging.

Server Lifecycle

The MCP server runs until: - The LLM client disconnects - SIGINT (Ctrl+C) is received - An unrecoverable error occurs

On shutdown: - Executor connections are closed - Resources are cleaned up - Exit code 0 indicates clean shutdown

Error Handling

Common errors and solutions:

Profile not found:

Error: Profile 'custom' not found
→ Ensure profile exists at ~/.config/shannot/custom.json or specify full path

Target not found:

Error: Target 'production' not configured
→ Add target to ~/.config/shannot/config.toml

Bubblewrap not found:

Error: Bubblewrap not found at /usr/bin/bwrap
→ Install bubblewrap: apt install bubblewrap (Linux only)

SSH connection failed:

Error: Failed to connect to host.example.com
→ Check SSH configuration, keys, and network connectivity

API Reference

mcp_main

Entry point for Shannot MCP server.

This module provides the main entry point for running the MCP server. It can be invoked via: - python -m shannot.mcp_main - shannot-mcp (if installed as separate package)

Classes

Functions

setup_logging(verbose=False)

Configure logging for the MCP server.

Source code in shannot/mcp_main.py
def setup_logging(verbose: bool = False) -> None:
    """Configure logging for the MCP server."""
    level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(
        level=level,
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        stream=sys.stderr,  # MCP uses stderr for logs, stdout for protocol
    )

main(argv=None) async

Main entry point for MCP server.

Source code in shannot/mcp_main.py
async def main(argv: Sequence[str] | None = None) -> None:
    """Main entry point for MCP server."""
    if argv is None:
        argv = sys.argv[1:]

    parser = _build_parser()
    args = parser.parse_args(list(argv))

    verbose: bool = bool(args.verbose)
    setup_logging(verbose)

    logger = logging.getLogger(__name__)
    logger.info("Starting Shannot MCP server")

    executor = None
    executor_profile: str | None = None

    target: str | None = args.target if args.target else None
    if target:
        logger.info("Using executor target: %s", target)
        try:
            config = load_config()
        except Exception as exc:  # pragma: no cover - defensive
            logger.error("Failed to load configuration: %s", exc)
            raise SystemExit(1) from exc

        if target not in config.executor:
            logger.error("Target '%s' not found in configuration", target)
            logger.info("List targets with: shannot remote list")
            raise SystemExit(1)

        executor_config = config.executor[target]
        executor_profile = executor_config.profile

        try:
            executor = create_executor(config, target)
        except Exception as exc:
            logger.error("Failed to create executor '%s': %s", target, exc)
            if "pip install shannot[remote]" in str(exc):
                logger.info("Install remote support with: pip install shannot[remote]")
            raise SystemExit(1) from exc

    profiles: list[str] | None = args.profiles if args.profiles else None
    profile_specs = _resolve_profiles(profiles, executor_profile)

    # Create and run server
    server = None
    try:
        server = ShannotMCPServer(profile_specs, executor, executor_label=target)
        logger.info("Loaded %s profiles", len(server.deps_by_profile))
        for name in server.deps_by_profile.keys():
            logger.info("  - %s", name)

        await server.run()
    except KeyboardInterrupt:
        logger.info("Server stopped by user")
    except SystemExit:
        raise
    except Exception as e:
        logger.error("Server error: %s", e, exc_info=True)
        raise SystemExit(1) from e
    finally:
        if server is not None:
            try:
                await server.cleanup()
            except Exception as exc:  # pragma: no cover - best effort cleanup
                logger.debug("Failed to cleanup server resources: %s", exc)

entrypoint()

Synchronous entrypoint for console_scripts.

Source code in shannot/mcp_main.py
def entrypoint() -> None:
    """Synchronous entrypoint for console_scripts."""

    asyncio.run(main())