Add MTP --describe support to any Click CLI
Project description
mtp-sdk
Add MTP --mtp-describe support to any Click CLI. One function call, zero boilerplate.
Install
pip install mtp-sdk click
Quick Start
import click
from mtp_sdk import with_describe, DescribeOptions, CommandAnnotation, Example, IODescriptor
@click.group()
def cli():
"""Convert and validate files"""
@cli.command()
@click.argument("input")
@click.option("--format", default="json", help="Output format")
@click.option("--pretty", is_flag=True, help="Pretty-print output")
def convert(input, format, pretty):
"""Convert a file"""
with_describe(cli, DescribeOptions(
version="1.0.0",
commands={
"convert": CommandAnnotation(
arg_descriptions={"input": "Input file path"},
stdin=IODescriptor(content_type="text/plain", description="Raw input"),
stdout=IODescriptor(content_type="application/json"),
examples=[
Example(description="Convert CSV", command="filetool convert data.csv --format json"),
],
),
},
))
if __name__ == "__main__":
cli()
$ filetool --mtp-describe # MTP JSON schema
$ filetool convert data.csv # normal operation
API
with_describe(cli, options?)
Adds --mtp-describe to an existing Click command or group. When invoked, outputs MTP-compliant JSON and exits.
- cli - a Click
BaseCommandinstance (your root command or group) - options.version - version string for the tool
- options.commands - per-command annotations keyed by command name (stdin, stdout, examples, arg_types, arg_descriptions)
- options.auth - authentication config to include in the schema
- Returns the cli for chaining
describe(cli, options?)
Pure function. Returns the ToolSchema object without side effects. Useful for testing or programmatic access.
How It Works
The SDK introspects Click's own data structures (params, type objects, subcommands) so you never duplicate information. Supplemental metadata (stdin/stdout/examples) that Click doesn't model is provided via the options map.
Type Inference
Arg types describe flags and positional arguments, which are always scalar on the command line:
| Click signal | MTP type |
|---|---|
Option.is_flag |
"boolean" |
click.Choice(...) |
"enum" + values |
Option.multiple / nargs=-1 |
"array" |
click.INT / IntRange |
"integer" |
click.FLOAT / FloatRange |
"number" |
click.BOOL |
"boolean" |
click.Path(...) |
"path" |
Option.count |
"integer" |
explicit arg_types override |
whatever you say |
| everything else | "string" |
For structured data flowing through stdin/stdout, use the schema field in IO descriptors. This supports full JSON Schema (draft 2020-12): nested objects, arrays, unions, pattern validation, conditional fields.
Structured IO
When a command accepts or produces JSON, describe the shape with a JSON Schema:
with_describe(cli, DescribeOptions(
version="1.0.0",
commands={
"process": CommandAnnotation(
stdin=IODescriptor(
content_type="application/json",
description="Configuration to process",
schema={
"type": "object",
"properties": {
"name": {"type": "string"},
"settings": {
"type": "object",
"properties": {
"retries": {"type": "integer"},
"endpoints": {
"type": "array",
"items": {"type": "string", "format": "uri"},
},
},
},
},
"required": ["name"],
},
),
stdout=IODescriptor(
content_type="application/json",
schema={
"type": "object",
"properties": {
"status": {"type": "string", "enum": ["ok", "error"]},
"results": {"type": "array", "items": {"type": "object"}},
},
},
),
),
},
))
### Command Naming
- Groups with subcommands: each leaf command gets a space-separated path (e.g., `"auth login"`)
- Commands with no subcommands: single command named `"_root"`
- Hidden commands and options are excluded
### Argument Descriptions
Click arguments don't support `help` text natively. Use `arg_descriptions` in your annotation:
```python
CommandAnnotation(
arg_descriptions={"input_file": "Input file path"},
)
Filtered Options
These are automatically excluded from schema output: --help, --version, --mtp-describe, and any hidden options.
Single-Command Tools
Tools with no subcommands work the same way:
import click
from mtp_sdk import with_describe, DescribeOptions
@click.command()
@click.argument("name")
@click.option("--loud", is_flag=True, help="Shout the greeting")
def greet(name, loud):
"""Greet someone"""
msg = f"Hello, {name}!"
click.echo(msg.upper() if loud else msg)
with_describe(greet, DescribeOptions(version="1.0.0"))
if __name__ == "__main__":
greet()
This produces a schema with a single _root command.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mtp_sdk-0.2.0.tar.gz.
File metadata
- Download URL: mtp_sdk-0.2.0.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af5acd85b14c41768281ec8210d949f6829f71e35284f88359ba49791eea30d6
|
|
| MD5 |
4021f3945ea28eebbb9b16aaffbf6608
|
|
| BLAKE2b-256 |
ed632d05fdaabea1addf129f8d034764f061d92a192fe803d4df3a94483c2149
|
File details
Details for the file mtp_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mtp_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4e310279ba54801b432612685c853494cd4b966629893de60eb2538ee667c66
|
|
| MD5 |
065f5c9bfbf42c18666a5c556bac09cf
|
|
| BLAKE2b-256 |
8ae806532ad359a62896b12cb65389543e118bf7124ba1d16fb6d57ed81a34b4
|