For example, when in a repo containing the following files:
$ tree
.
...
├── scripts
│ ├── hello_world_script.py # <-- Script containing a @click.command()
│ ├── options_test.py # <-- Script containing a @click.command()
│ ├── not_a_click_cmd.py
│ └── test
│ └── sup.py # <-- Script containing a @click.command()
...
...and run the following commands:
$ source .venv/bin/activate
$ pip install click-clack # Or wtv pip/uv command you use to setup your virtualenv.
$ click-clack
Running ClickClack.py ⚡
➜ URL: http://localhost:2718
...you'll get a minimalist UI that looks like this:
...simply enter any values, and click Run Command!
:
If you'd like to make your click commands accessible to MCP Clients such as Claude Desktop, simply add the following config to claude_desktop_config.json
(see https://modelcontextprotocol.io/quickstart/user for more info):
{
"mcpServers": {
"click_clack": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/directory/with/your/click/commands"
"--",
"click-clack",
"--mcp",
"--module-path",
"/path/to/directory/with/your/click/commands"
]
}
}
}
Note that for this to work as documented above, you'll need to install uv
globally first and the /path/to/directory/with/your/click/commands
directory must be a valid uv project (i.e. you ran uv init
there and uv add
ed the dependencies your commands need).
For example, in Claude Desktop once properly configured you'll be able to see the available tools provided by the click-clack
MCP server.
Click commands don't generally return values, so instead when running your commands as an MCP tool, Click Clack will capture all stdout/stderr output that your command emits, and redirect that to the MCP client as your tool's reponse. So, instead of returning your final tool response, use print(response)
instead.
This project crawls all .py
files at and below the directory where the click-clack
command is run. It then automatically traverses the Python AST looking for the @click.command()
decorator, and imports the decorated commands and generates a minimalist UI for them.
Support for click and asyncclick
Whether you're writing basic click
commands, or using asyncclick
to write async commands, click-clack
seamlessly supports your command by auto-detecting the command type.
UI Generation via Marimo
Marimo fundamentally underpins this package by providing an extremely simple framework for generating interactive UIs in pure python.
MCP Server Generation via FastMCP
MCP Server generation is entirely based on FastMCP, which does almost all of the heavy lifting. Click Clack just performs auto-discovery and does a bit of clever wrapping of your Click commands to be able to pass them off to FastMCP as tools.
The UI will generate an input for each command parameter, and will forward the data from the input to the command.
Currently this project only supports automatically discovering the following command parameter types:
str
int
float
bool
(includingis_flag=True
)click.Choice
click.File
(via a file browser UI element: TODO - support stdout via click's magic"-"
file arg support)click.Path
click.DateTime
click.IntRange
click.FloatRange
- ...literally everything else is a TODO...