typer-mcp
Allows AI agents to call any Typer CLI command as a tool via the Model Context Protocol, without modifying existing code.
🚀 Typer-MCP
Instantly convert any Typer CLI into an MCP Server – empower AI agents with your command‑line tools.
🧠 Core idea: Just as
FastAPI-MCPlets your APIs talk to AI,Typer-MCPdoes the same for every CLI you build with Typer. Without changing your original code, your CLI tools becometoolsthat large language models (Claude, Gemini, GPT, …) can call directly.
📋 Table of Contents
✨ Features
Zero‑intrusion conversion – Turn any Typer CLI into an MCP server without modifying your existing code.
Full parameter support –
str,int,float,bool,Optional,Enum,list, numeric ranges (min/max), regex patterns,minLength/maxLength,uniqueItems.Nested commands (subgroups) – Fully recursive discovery of commands inside Typer groups.
Smart validation – Required/optional parameters, type checking, and JSON Schema generation.
Secure subprocess execution – Uses
subprocess.Popenwith real timeout and process termination (no zombie processes).Environment variable filtering – Only a safe allowlist is exposed;
PATHand dangerous vars are blocked by default.Graceful shutdown – Responds to
SIGINT/SIGTERMand exits cleanly.Flexible variable naming – Works with any Typer instance name (not just
app).Timeout management – Global or per‑command timeout (default 30 seconds) with forced termination.
Debug mode – Detailed logs written to
stderrfor easy troubleshooting.Lightweight – Only depends on
typer>=0.12.0(no extra SDKs).MCP compliant – Implements
initialize,tools/list,tools/call, andnotifications/initialized.Standalone CLI – Comes with
run,list-tools, andversioncommands.
📦 Installation
From PyPI (stable)
pip install typer-mcpNote: The package does not depend on the official MCP SDK. The JSON‑RPC protocol is implemented natively, keeping the installation lean.
From source (latest)
git clone https://github.com/Darussalamnoor/typer-mcp.git
cd typer-mcp
pip install -e .For development and testing
pip install -e ".[test,dev]"🚀 Quick Start
Create a normal Typer CLI (my_cli.py)
import typer
app = typer.Typer()
@app.command()
def greet(name: str, excited: bool = False):
"""Greet someone."""
msg = f"Hello {name}!"
if excited:
msg = msg.upper() + "!!!"
print(msg)
@app.command()
def add(a: float, b: float):
"""Add two numbers."""
print(f"{a} + {b} = {a + b}")
if __name__ == "__main__":
app()Run the MCP server (no code changes)
typer-mcp run --app my_cli:appTest with an MCP client (e.g., mcp-cli)
pip install mcp-cli
mcp-cli call --server "typer-mcp run --app my_cli:app" \
--tool greet \
--args '{"name": "World", "excited": true}'Output:
HELLO, WORLD!!!!Connect to Claude Desktop
Edit your Claude Desktop configuration:
· macOS: ~/Library/Application Support/Claude/claude_desktop_config.json · Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"my-typer-cli": {
"command": "typer-mcp",
"args": ["run", "--app", "my_cli:app"],
"env": {}
}
}
}Restart Claude Desktop – your tools (greet, add) will be automatically available.
🛠️ CLI Commands
Command Description Example run Start MCP server for a Typer app typer-mcp run --app my_cli:app list-tools List all discoverable tools without starting the server typer-mcp list-tools --app my_cli:app --format json version Show current version typer-mcp version
run options
Option Description Default --app (required) Import path to Typer instance (e.g., my_cli:app) – --debug / -d Enable debug logging to stderr False --timeout / -t Default tool execution timeout (seconds) 30.0
list-tools options
Option Description Default --app (required) Import path to Typer instance – --format / -f Output format: text or json text
📖 API Documentation
TyperMCP class
The main programmatic entry point.
from typer_mcp import TyperMCP
import typer
app = typer.Typer()
# ... define commands ...
mcp = TyperMCP(app, debug=True, tool_timeout=60.0, app_var_name="app")
mcp.run() # blocks, starts MCP serverConstructor parameters:
· app (typer.Typer): Your Typer application. · debug (bool, default False): Enable debug logging. · tool_timeout (float, default 30.0): Default timeout for tools. · app_var_name (str, default "app"): Name of the variable that holds the Typer instance. This is automatically extracted from the import path when using the CLI, so you rarely need to set it manually.
Methods:
· run(block: bool = True): Start the MCP server. If block=True (default), it runs forever; if block=False, it runs in a background thread. · get_tools() -> list[MCPTool]: Return a list of MCPTool objects derived from the Typer commands. · version() -> str: Return the library version. · close(): Stop the server gracefully (works only in non‑blocking mode).
Data types (typer_mcp.types)
· ParameterType: Enum with "string", "integer", "number", "boolean", "array", "object", "null". · MCPParameter: Parameter specification (name, type, description, required, default, enum, range, pattern, min/max length, array items, uniqueItems, is_positional). · MCPTool: Contains name, description, and a tuple of MCPParameter. Provides to_schema() and validate_arguments(). · MCPRequest / MCPResponse: JSON‑RPC models following the MCP protocol. · ToolResult: Execution result (content, error flag, stdout, stderr, metadata).
Example:
from typer_mcp import MCPTool, MCPParameter, ParameterType
tool = MCPTool(
name="calculate",
description="Multiply two integers",
parameters=(
MCPParameter(name="x", type=ParameterType.INTEGER, required=True, minimum=0, maximum=100),
MCPParameter(name="y", type=ParameterType.INTEGER, required=True),
)
)
tool.validate_arguments({"x": 5, "y": 10}) # True🔬 Advanced Examples
Complex parameters (Enum, list, numeric range)
from enum import Enum
import typer
from click import IntRange
class LogLevel(str, Enum):
DEBUG = "debug"
INFO = "info"
ERROR = "error"
app = typer.Typer()
@app.command()
def process(
level: LogLevel = typer.Option(LogLevel.INFO, help="Log level"),
numbers: list[int] = typer.Argument(..., help="List of integers"),
timeout: int = typer.Option(30, help="Timeout", clamp=IntRange(1, 120))
):
"""Process with advanced parameters."""
print(f"Level: {level.value}, Numbers: {numbers}, Timeout: {timeout}")After running typer-mcp run --app my_cli:app, the MCP tools will automatically include:
· level with enum: ["debug", "info", "error"] · numbers with type: "array" and items: {"type": "integer"} · timeout with type: "integer", minimum: 1, maximum: 120
Nested commands (subgroups)
import typer
app = typer.Typer()
user_app = typer.Typer()
app.add_typer(user_app, name="user")
@user_app.command("create")
def user_create(name: str):
"""Create a new user."""
print(f"User {name} created.")
@user_app.command("delete")
def user_delete(user_id: int):
"""Delete a user by ID."""
print(f"User {user_id} deleted.")Tools discovered: user_create and user_delete (with full parameter validation).
Adjust timeout
typer-mcp run --app my_cli:app --timeout 120.0Debug mode
typer-mcp run --app my_cli:app --debugLogs appear on stderr.
📂 Project Structure
typer-mcp/
├── Typer-MCP/
│ ├── src/
│ │ └── typer_mcp/
│ │ ├── __init__.py # Main exports (TyperMCP, helpers)
│ │ ├── core.py # TyperMCP class (with non‑blocking support)
│ │ ├── types.py # Data models (ParameterType, MCPParameter, ...)
│ │ ├── converter.py # Convert Typer app to MCP tools (supports subgroups)
│ │ ├── server.py # MCP server (JSON‑RPC) with graceful shutdown
│ │ ├── utils.py # SecureProcess, environment sanitization, docstring extraction
│ │ └── cli.py # typer-mcp command line tool
│ ├── tests/ # Unit tests (pytest)
│ └── examples/ # Example CLI scripts
├── pyproject.toml # Project configuration and dependencies
├── README.md # This file
├── LICENSE # Full AGPLv3 text
└── COMMERCIAL-LICENSE # (Optional) brief explanation of commercial terms🛡️ Security & Timeout Handling
Typer-MCP implements enterprise‑grade security measures:
· Environment variable filtering: Only a safe allowlist (HOME, USER, LANG, TZ, TERM, SHELL) is passed to subprocesses. PATH and other dangerous variables are not exposed, preventing injection attacks. · Command argument sanitization: Null bytes and shell metacharacters (;, &, |, ` , $, (, ), <, >) are rejected. · Real timeout with process termination: Uses subprocess.Popen and a custom SecureProcess class. On timeout, the entire process tree is terminated (SIGTERM then SIGKILL), leaving no zombie processes. · Graceful shutdown: The server responds to SIGINT/SIGTERM, finishes the current message, and exits cleanly.
These features make Typer-MCP suitable for production environments where reliability and security are critical.
🧪 Development & Contribution
We welcome contributions! Please follow these steps:
Fork the repository.
Create a feature/bugfix branch:
git checkout -b feature/your-feature-nameMake your changes. Follow PEP 8 and use type hints.
Write tests and run them:
pip install -e ".[test]" pytest tests/ -vSubmit a Pull Request to the main branch.
Guidelines:
· All code must pass mypy and ruff checks (config in pyproject.toml). · New features must include tests and documentation. · Use black for formatting.
🐛 Troubleshooting
ModuleNotFoundError: No module named 'typer_mcp'
· Ensure the package is installed: pip install -e . (in development mode). · Or add the src directory to your PYTHONPATH.
Connection refused or Server not responding in Claude Desktop
· Verify the command path in the Claude Desktop config (use which typer-mcp). · Check Claude Desktop logs (usually ~/Library/Logs/Claude on macOS).
Command times out
· Increase the timeout with --timeout. · If the command inherently takes long, redesign it to work incrementally.
Output contains extra formatting (colors)
· Typer produces colored output by default. To disable colors while running under MCP, set the environment variable NO_COLOR=1.
Tool calls fail with ImportError: cannot import name 'app'
· This means your Typer instance has a different variable name (e.g., cli instead of app). The CLI automatically extracts the correct name from the import path (e.g., my_cli:cli). If you are using the API directly, pass the app_var_name argument to TyperMCP.
For other issues, please open a GitHub Issue.
📄 Dual License
This project is released under a Dual Licensing model to support both the open‑source community and the author’s ability to earn a living.
Free / Open‑Source License (Non‑commercial, educational, open‑source)
You may use, modify, and distribute the software under the terms of the GNU Affero General Public License version 3 (AGPLv3). The full license text is in the LICENSE file.
Key requirements of AGPLv3:
· Any distribution (including network‑based provision, e.g., SaaS) requires you to release the full source code of your changes. · If you run the software as a web service, end users have the right to receive the source code. · This license is suitable for academic, educational, personal, and open‑source projects.
Commercial License (For companies and closed‑source products)
If you wish to use this library in a commercial product, closed‑source software, or a cloud service where source code is not disclosed to users, you must purchase a separate commercial license from the author.
A commercial license allows you to:
· Use the code in proprietary products without being required to release your source code. · Be exempt from the AGPLv3 obligations (e.g., publishing server‑side source code). · Receive priority support and updates.
To obtain a commercial license and for pricing information, please contact: 📧 mg.gmqmw.rtrt@gmail.com (Please include “Commercial License – Typer-MCP” in the subject line.)
💖 Financial Support
We have released this project as free and open‑source for everyone around the world to help the developer community. However, due to unfair sanctions against our beloved country, Iran, common funding methods (such as PayPal, GitHub Sponsors, or Stripe) are not available to us.
If you benefit from this project and would like to support us, please consider one of the following options:
· Send international gift cards (Amazon, Google Play, Apple App Store, Steam, or other gifts you prefer) to the email address below. · Purchase a commercial license for your commercial projects (contact us via email). · Spread the word about the project and star the repository on GitHub.
Email for support and commercial inquiries: 📧 mg.gmqmw.rtrt@gmail.com Please mention the project name (Typer-MCP) and the type of support you wish to provide. We appreciate every contribution, even a small gift card, to continue development, fix bugs, and start new projects.
Thank you for your support ❤️
⭐ If you find this project useful, please give it a star on GitHub!
https://img.shields.io/github/stars/Darussalamnoor/typer-mcp?style=social
Built by Darussalamnoor (sole author and developer)
This server cannot be installed
Maintenance
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Darussalamnoor/typer-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server