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)
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.