typer-mcp
Automatically converts any CLI built with Python's Typer into an MCP server without changing code. Gives AI agents instant access to thousands of CLI tools.
README
🚀 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
- Installation
- Quick Start
- Step‑by‑Step Tutorial
- CLI Commands
- API Documentation
- Advanced Examples
- Project Structure
- Security & Timeout Handling
- Development & Contribution
- Troubleshooting
- Dual License
- Financial Support
✨ 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-mcp
Note: 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:app
- Test 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 server
Constructor 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.0
Debug mode
typer-mcp run --app my_cli:app --debug
Logs appear on stderr.
📂 Project Structure
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-name - Make your changes. Follow PEP 8 and use type hints.
- Write tests and run them:
pip install -e ".[test]" pytest tests/ -v - Submit 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)
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。