Skip to content

Commit 7b69759

Browse files
v0.2.1: pytest suite, MCP integration examples, agent workflow docs
- Replace script-style tests with 12 proper pytest tests (TestAdapter, TestServer, TestDiscover) - Add examples/api_contract_guardian_mcp.py: mock ACG wrapped as MCP server - Add examples/quick_start.py: minimal 3-line integration demo - Enhanced README with MCP workflow for Claude Code, Cursor, Cline/VS Code - Add 'How It Works' table mapping Click concepts to MCP - GitHub pip install as primary install path - Bump version to 0.2.1
1 parent 3b11176 commit 7b69759

10 files changed

Lines changed: 468 additions & 148 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
All notable changes to click-to-mcp will be documented in this file.
44

5+
## [0.2.1] — 2026-05-15
6+
7+
### Added
8+
9+
- Comprehensive pytest test suite (12 tests): TestAdapter, TestServer, TestDiscover
10+
- MCP integration examples: `examples/api_contract_guardian_mcp.py`, `examples/quick_start.py`
11+
- Blog-style README with MCP workflow sections for Claude Code, Cursor, and Cline/VS Code
12+
- Install-from-GitHub instructions as primary path (PyPI blocked by hCaptcha)
13+
- "How It Works" table mapping Click concepts to MCP equivalents
14+
15+
### Changed
16+
17+
- Replaced script-style tests with proper pytest test functions
18+
- README restructured with agent integration workflows as primary value proposition
19+
520
## [0.1.0] — 2026-05-14
621

722
### Added

README.md

Lines changed: 152 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@ Works great with [Revenue Holdings CLI tools](https://coding-dev-tools.github.io
1313

1414
## Quick Start
1515

16-
```bash
17-
pip install click-to-mcp
18-
```
19-
20-
Or install directly from GitHub:
16+
Install directly from GitHub (PyPI coming soon):
2117

2218
```bash
2319
pip install git+https://github.com/Coding-Dev-Tools/click-to-mcp.git
2420
```
21+
22+
```bash
2523
# Discover all Click/typer CLIs installed in your environment
2624
click-to-mcp discover
2725

@@ -34,6 +32,152 @@ click-to-mcp demo
3432

3533
Then configure your MCP client to run `click-to-mcp serve <name>` as a stdio transport.
3634

35+
## How It Works
36+
37+
click-to-mcp introspects your Click/typer CLI at runtime and maps every command to an MCP tool:
38+
39+
| Click Concept | MCP Mapping |
40+
|---|---|
41+
| `@click.command()` | MCP tool |
42+
| `@click.argument()` | Required input property |
43+
| `@click.option()` | Optional input property with default |
44+
| `click.Choice` | JSON Schema `enum` |
45+
| `click.INT/FLOAT` | JSON Schema `integer`/`number` |
46+
| `click.BOOL` / `is_flag` | JSON Schema `boolean` |
47+
| Nested `click.Group` | Prefixed tools (e.g. `config_show`) |
48+
49+
No annotations, no decorators, no boilerplate. Your existing Click CLI *is* the MCP server.
50+
51+
## MCP Workflow with AI Coding Agents
52+
53+
This section shows how to integrate click-to-mcp with popular AI coding tools so your CLIs become first-class tools that AI agents can invoke directly.
54+
55+
### Claude Code
56+
57+
Add your CLI as an MCP server in your project's `.claude/settings.json`:
58+
59+
```json
60+
{
61+
"mcpServers": {
62+
"api-contract-guardian": {
63+
"command": "click-to-mcp",
64+
"args": ["serve", "api-contract-guardian"]
65+
},
66+
"json2sql": {
67+
"command": "click-to-mcp",
68+
"args": ["serve", "json2sql"]
69+
},
70+
"deploydiff": {
71+
"command": "click-to-mcp",
72+
"args": ["serve", "deploydiff"]
73+
}
74+
}
75+
}
76+
```
77+
78+
Now when you ask Claude Code to "validate my API contracts", it will automatically call the `acg_validate` MCP tool with the right arguments — no manual command-line invocation needed.
79+
80+
### Cursor
81+
82+
Add to your Cursor MCP settings (`.cursor/mcp.json`):
83+
84+
```json
85+
{
86+
"mcpServers": {
87+
"api-contract-guardian": {
88+
"command": "click-to-mcp",
89+
"args": ["serve", "api-contract-guardian"]
90+
}
91+
}
92+
}
93+
```
94+
95+
### Cline / VS Code
96+
97+
Add to `.vscode/mcp.json`:
98+
99+
```json
100+
{
101+
"servers": {
102+
"api-contract-guardian": {
103+
"command": "click-to-mcp",
104+
"args": ["serve", "api-contract-guardian"]
105+
}
106+
}
107+
}
108+
```
109+
110+
### Custom Integration (Programmatic)
111+
112+
For CLIs that aren't installed as entry points, use the library API:
113+
114+
```python
115+
# my_mcp_server.py
116+
from click_to_mcp import run
117+
from my_cli import app # Your Click/typer CLI
118+
119+
run(app, prefix="my-cli", name="my-cli-mcp")
120+
```
121+
122+
Then reference the script directly:
123+
124+
```json
125+
{
126+
"mcpServers": {
127+
"my-cli": {
128+
"command": "python",
129+
"args": ["my_mcp_server.py"]
130+
}
131+
}
132+
}
133+
```
134+
135+
### What the Agent Sees
136+
137+
When your MCP server is configured, the AI agent sees your CLI commands as native tools. For example, with api-contract-guardian:
138+
139+
```
140+
Agent: "I need to validate the API contract against the staging server."
141+
→ Calls MCP tool: acg_validate
142+
Arguments: { "spec_file": "openapi.yaml", "base_url": "https://staging.api.com", "strict": true, "output_format": "json" }
143+
← Result: "Validating openapi.yaml against https://staging.api.com...\n✓ All contracts pass"
144+
```
145+
146+
The agent doesn't need to know shell syntax, argument flags, or command names. It just calls the tool with structured arguments, and click-to-mcp handles the rest.
147+
148+
## Examples
149+
150+
### Quick Start (3 lines)
151+
152+
```python
153+
import click
154+
from click_to_mcp import run
155+
156+
@click.group()
157+
def my_cli():
158+
"""My awesome CLI tool."""
159+
pass
160+
161+
@my_cli.command()
162+
@click.argument("name")
163+
@click.option("--loud", is_flag=True, help="Shout the greeting")
164+
def hello(name: str, loud: bool):
165+
"""Say hello to someone."""
166+
msg = f"Hello, {name}!"
167+
if loud:
168+
msg = msg.upper()
169+
click.echo(msg)
170+
171+
if __name__ == "__main__":
172+
run(my_cli, prefix="my-cli", name="my-cli-mcp")
173+
```
174+
175+
See [examples/quick_start.py](examples/quick_start.py) for the full runnable example.
176+
177+
### Wrapping api-contract-guardian
178+
179+
See [examples/api_contract_guardian_mcp.py](examples/api_contract_guardian_mcp.py) for a demo showing how to wrap API Contract Guardian as an MCP server with `validate`, `extract`, and `monitor` commands.
180+
37181
## Usage
38182

39183
### CLI — Discover and Serve
@@ -127,9 +271,9 @@ Then agents can use it as: `your-cli mcp`
127271
```bash
128272
git clone https://github.com/Coding-Dev-Tools/click-to-mcp
129273
cd click-to-mcp
130-
pip install -e .
131-
python -m click_to_mcp discover
132-
click-to-mcp demo # starts MCP server for demo CLI
274+
pip install -e ".[dev]"
275+
python -m pytest tests/ -v # 12 tests
276+
click-to-mcp demo # starts MCP server for demo CLI
133277
```
134278

135279
## Pricing

click_to_mcp/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from .server import serve_stdio
2323
from .discover import scan_entry_points, load_cli, find_our_clis, DiscoveredCLI
2424

25-
__version__ = "0.2.0"
25+
__version__ = "0.2.1"
2626

2727

2828
def run(app: Any, prefix: str = "", name: str = "") -> None:
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Example: Wrap api-contract-guardian as an MCP server.
4+
5+
This demonstrates how click-to-mcp can turn any Click/typer CLI into an MCP server
6+
that AI coding agents (Claude Code, Cursor, Copilot) can use directly.
7+
8+
Run this example:
9+
pip install click-to-mcp
10+
python examples/api_contract_guardian_mcp.py
11+
12+
Then configure your MCP client (e.g. Claude Code):
13+
# .claude/settings.json
14+
{
15+
"mcpServers": {
16+
"api-contract-guardian": {
17+
"command": "python",
18+
"args": ["examples/api_contract_guardian_mcp.py"]
19+
}
20+
}
21+
}
22+
"""
23+
24+
import click
25+
from click_to_mcp import run
26+
27+
# --- Mock api-contract-guardian CLI (replace with real import) ---
28+
# In production, you would do:
29+
# from api_contract_guardian.cli import app
30+
# run(app, prefix="acg")
31+
32+
@click.group()
33+
def acg():
34+
"""API Contract Guardian — validate API contracts against live endpoints."""
35+
pass
36+
37+
@acg.command()
38+
@click.argument("spec_file", type=click.Path(exists=False))
39+
@click.option("--base-url", default="http://localhost:8000", help="Base URL of the API")
40+
@click.option("--strict/--no-strict", default=False, help="Fail on any contract violation")
41+
@click.option("--format", "-f", "output_format", type=click.Choice(["json", "table", "junit"]), default="table", help="Output format")
42+
def validate(spec_file: str, base_url: str, strict: bool, output_format: str):
43+
"""Validate an OpenAPI spec against a live API."""
44+
click.echo(f"Validating {spec_file} against {base_url}...")
45+
click.echo(f" Format: {output_format}")
46+
click.echo(f" Strict: {strict}")
47+
click.echo("✓ All contracts pass")
48+
49+
@acg.command()
50+
@click.argument("spec_file", type=click.Path(exists=False))
51+
@click.option("--output", "-o", default="contracts.json", help="Output file path")
52+
def extract(spec_file: str, output: str):
53+
"""Extract contracts from an OpenAPI spec file."""
54+
click.echo(f"Extracting contracts from {spec_file}...")
55+
click.echo(f" Output: {output}")
56+
click.echo("✓ 12 contracts extracted")
57+
58+
@acg.command()
59+
@click.option("--watch/--no-watch", default=False, help="Watch for spec changes")
60+
@click.option("--interval", default=30, type=int, help="Watch interval in seconds")
61+
def monitor(watch: bool, interval: int):
62+
"""Monitor API endpoints for contract drift."""
63+
click.echo(f"Monitoring contracts... (watch={watch}, interval={interval}s)")
64+
click.echo("✓ No drift detected")
65+
66+
if __name__ == "__main__":
67+
run(acg, prefix="acg", name="api-contract-guardian")

examples/quick_start.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Quick Start: Turn any Click CLI into an MCP server in 3 lines.
4+
5+
Usage:
6+
pip install click-to-mcp
7+
python examples/quick_start.py
8+
"""
9+
10+
import click
11+
from click_to_mcp import run
12+
13+
@click.group()
14+
def my_cli():
15+
"""My awesome CLI tool."""
16+
pass
17+
18+
@my_cli.command()
19+
@click.argument("name")
20+
@click.option("--loud", is_flag=True, help="Shout the greeting")
21+
def hello(name: str, loud: bool):
22+
"""Say hello to someone."""
23+
msg = f"Hello, {name}!"
24+
if loud:
25+
msg = msg.upper()
26+
click.echo(msg)
27+
28+
@my_cli.command()
29+
@click.argument("numbers", nargs=-1, type=float)
30+
@click.option("--operation", type=click.Choice(["sum", "avg", "max", "min"]), default="sum")
31+
def math(numbers: tuple, operation: str):
32+
"""Perform math on a list of numbers."""
33+
if not numbers:
34+
click.echo("No numbers provided")
35+
return
36+
result = {"sum": sum, "avg": lambda x: sum(x)/len(x), "max": max, "min": min}[operation](numbers)
37+
click.echo(f"{operation}({numbers}) = {result}")
38+
39+
if __name__ == "__main__":
40+
# That's it! Your CLI is now an MCP server.
41+
run(my_cli, prefix="my-cli", name="my-cli-mcp")

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "click-to-mcp"
7-
version = "0.2.0"
7+
version = "0.2.1"
88
description = "Auto-wrap any Click/typer CLI as an MCP (Model Context Protocol) server — with auto-discovery"
99
readme = "README.md"
1010
license = { text = "Apache-2.0" }

0 commit comments

Comments
 (0)