Skip to main content

A reusable framework and scaffold for Python CLI applications with MCP, REST, and service-layer architecture

Project description

click-clop

A Python framework and project generator where every feature is simultaneously a CLI command (Click), MCP tool (FastMCP), and REST endpoint (FastAPI).

Write your business logic once as a service class — click-clop exposes it everywhere.

Service method  ──►  CLI command  (Click)
                ──►  MCP tool     (FastMCP)
                ──►  REST endpoint (FastAPI)

Quick Start

Install

pip install click-clop

Generate a new project

click-clop new my-app --description "My awesome CLI"
cd my-app
make install-dev

This scaffolds a complete project with a Makefile, Dockerfile, Helm charts, telemetry config, BDD tests, and documentation — with intelligent defaults based on your system.

Write a service

# src/my_app/services/greet.py
from click_clop import Service

class GreetService(Service):
    """Greeting service."""

    name = "greet"
    description = "Say hello"

    def hello(self, name: str = "world") -> str:
        """Say hello to someone."""
        return f"Hello, {name}!"

    def farewell(self, name: str = "world") -> str:
        """Say goodbye to someone."""
        return f"Goodbye, {name}!"

_service = GreetService()  # auto-registers

Expose as CLI

import click
from click_clop import expose_cli

@click.group()
def main():
    """My CLI app."""

expose_cli(main)  # all registered services become subcommands
$ my-app greet hello --name Claude
Hello, Claude!

Expose as REST

from click_clop import expose_rest

app = expose_rest()  # creates /api/greet/hello, /api/greet/farewell

Expose as MCP tools

from fastmcp import FastMCP
from click_clop import expose_mcp

mcp = FastMCP("my-service")
expose_mcp(mcp)  # registers greet_hello, greet_farewell tools

CLI

click-clop new <PROJECT_NAME>   Create a new project from template
  -d, --description TEXT         Project description
  -a, --author TEXT              Author name (auto-detected from git)
  -o, --output-dir PATH          Parent directory (default: cwd)

click-clop detect                Show detected system capabilities

Library API

from click_clop import (
    Service,            # Base class for services
    ServiceRegistry,    # Global registry of all services
    load_config,        # Load TOML config with env overrides
    expose_cli,         # Add services to a Click group
    expose_mcp,         # Add services as MCP tools
    expose_rest,        # Add services as FastAPI endpoints
)

Configuration

load_config() merges TOML files in order (later wins):

  1. config.toml — base defaults
  2. config.dev.toml — development overrides
  3. config.local.toml — local/gitignored overrides
  4. Environment variables with prefix
from click_clop import load_config

config = load_config(prefix="APP")

Environment variables map with double-underscore nesting:

APP_SERVER__HOST=0.0.0.0  →  config["server"]["host"]
APP_DATABASE__PORT=5432   →  config["database"]["port"]

Secrets (1Password)

from click_clop.secrets import get_secret_field, ensure_secret

# Read a secret
api_key = get_secret_field("vault-name", "item-name", "api_key")

# Create or update a secret
ensure_secret("vault-name", "item-name", {"api_key": "sk-..."})

Requires the 1Password CLI (op) installed and authenticated.

Telemetry (OpenTelemetry)

from click_clop.telemetry import setup_telemetry, get_tracer

setup_telemetry(service_name="my-service", otlp_endpoint="http://localhost:4317")

tracer = get_tracer("my_module")
with tracer.start_as_current_span("operation"):
    ...

Logging (structlog)

from click_clop.logging import setup_logging, get_logger

setup_logging(level="INFO", json_output=True, service_name="my-service")
log = get_logger("my_module")
log.info("event", key="value")

System Detection

from click_clop.system_detect import detect_system

info = detect_system()
print(info.summary())

Detects Docker/Podman, Helm, 1Password CLI, Python, uv, Git, OS, and architecture.

Generated Project Structure

my_app/
├── src/my_app/
│   ├── __main__.py          # Entry point
│   ├── cli.py               # CLI main group
│   ├── server.py            # MCP + REST server
│   └── services/
│       └── hello.py         # Example service
├── tests/
│   └── unit/
│       └── test_hello.py
├── features/                # BDD/Gherkin tests
├── helm/my_app/             # Kubernetes Helm charts
├── alloy/config.alloy       # Grafana Alloy telemetry config
├── docs/                    # Sphinx documentation
├── config.toml              # Application config
├── Makefile                 # Development tasks
├── Dockerfile
└── pyproject.toml

Generated project commands

make install-dev    # Install with dev dependencies
make test           # Run pytest
make test-bdd       # Run BDD tests
make lint           # Lint with ruff + mypy
make format         # Format with ruff
make serve          # Run REST + MCP server (Swagger at localhost:8000/docs)
make build-image    # Build container image
make helm-install   # Deploy via Helm
make docs           # Build Sphinx docs

Development

git clone https://github.com/bpayne/click-clop.git
cd click-clop
make install-dev
make test
make lint

Type Mapping

Service method parameters are automatically mapped:

Python type CLI (Click) REST (FastAPI)
str STRING str
int INT int
float FLOAT float
bool --flag/--no-flag bool

Parameters without type annotations default to str.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

click_clop-0.3.0.tar.gz (92.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

click_clop-0.3.0-py3-none-any.whl (39.1 kB view details)

Uploaded Python 3

File details

Details for the file click_clop-0.3.0.tar.gz.

File metadata

  • Download URL: click_clop-0.3.0.tar.gz
  • Upload date:
  • Size: 92.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for click_clop-0.3.0.tar.gz
Algorithm Hash digest
SHA256 d933d04f8f343fe67fc354fa95f1bdfbbf6986654e6dd6e47c6b79f45816913c
MD5 31c3bfc7e36eacd7a6e6fea0a963393c
BLAKE2b-256 a0b58f9fe528653bf75efcfeb94ac963b90c53bd2bf7a60408a5454ae70387f4

See more details on using hashes here.

File details

Details for the file click_clop-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: click_clop-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 39.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for click_clop-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b6573a30db974f1afdde3b30ae2dd4d8c8cbf56a4fcbdb9295a4242d7d854e74
MD5 b3c6c830955b3489920707ef54d3f94c
BLAKE2b-256 e5b4f1f5b95299013de9c8dd7df418fd3d4d6540973b82b20c912035a96ffb6d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page