Universal converter between CLI (Typer), MCP (FastMCP), and API (FastAPI) interfaces
Project description
IntPot
Universal converter between CLI (Typer), MCP (FastMCP), and API (FastAPI) interfaces.
intpot bridges three popular Python frameworks:
Given a source file written in any of these frameworks, intpot detects the framework, inspects its functions/tools/endpoints, and generates equivalent code in the target framework.
Features
- 6 conversion directions — CLI to MCP, CLI to API, MCP to CLI, MCP to API, API to CLI, API to MCP
- Python API —
intpot.load()accepts file paths or live app instances for programmatic conversion - Directory auto-discovery — scan an entire directory and convert all found apps at once
- Auto-detection — automatically identifies the source framework by analyzing imports and patterns
- HTTP method preservation — API routes keep their GET/POST/PUT/DELETE methods through conversion
- Project scaffolding —
intpot initcreates new CLI, MCP, or API projects from templates - Jinja2 templates — clean, readable generated code with proper type hints
- Fully typed — PEP 561 compatible with
py.typedmarker - Zero config — just point at a Python file and specify the target
Installation
pip install intpot # core (CLI conversions only)
pip install intpot[mcp] # + FastMCP support
pip install intpot[api] # + FastAPI support
pip install intpot[all] # everything
Quick Start
Scaffold a new project
intpot init my-server --type mcp
intpot init my-app --type cli
intpot init my-api --type api
Convert between frameworks
# MCP server -> Typer CLI
intpot to cli server.py
# CLI app -> FastMCP server
intpot to mcp app.py
# CLI app -> FastAPI app
intpot to api app.py
# Write output to a file
intpot to cli server.py --output cli_app.py
# Convert all apps in a directory
intpot to cli ./myproject/
intpot to mcp ./myproject/ --output ./converted/
Python API
Use intpot programmatically from Python:
import intpot
# From a file
app = intpot.load("mcp_server.py")
cli_code = app.to_cli()
api_code = app.to_api()
# From a live instance
from fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
def greet(name: str) -> str:
return f"Hello, {name}!"
app = intpot.load(mcp)
print(app.to_cli())
# Write directly to a file
app.write("output/cli_app.py", "cli")
app.write("output/api_app.py", "api")
The load() function accepts file paths (str or Path) and live app instances (FastMCP, Typer, FastAPI). The returned IntpotApp object provides:
.to_cli(),.to_mcp(),.to_api()— return generated code as strings.write(path, target)— generate and write to a file in one step (targetis"cli","mcp","api", or aSourceTypeenum).tools— list of normalizedToolInfoobjects describing all detected functions.source_type— detected framework type (SourceType.CLI,SourceType.MCP, orSourceType.API)
Architecture
intpot uses a three-stage pipeline:
+-----------+
| SOURCE |
| (.py file)|
+-----+-----+
|
1. DETECT
(identify framework)
|
+-----v-----+
| SourceType|
| cli/mcp/api|
+-----+-----+
|
2. INSPECT
(extract functions)
|
+-----v-----+
| ToolInfo[] |
| (normalized|
| schema) |
+-----+-----+
|
3. GENERATE
(render template)
|
+-----v-----+
| OUTPUT |
| (.py code)|
+-----------+
- DETECT —
core/detector.pyimports the source file and identifies whether it's a Typer app, FastMCP server, or FastAPI app - INSPECT — Framework-specific inspectors (
core/inspectors/) extract function signatures, parameters, types, defaults, and docstrings into a normalizedToolInfoschema - GENERATE — Framework-specific generators (
core/generators/) render the normalized schema into target code using Jinja2 templates
Examples
MCP server to CLI app
Input (mcp_server.py):
from fastmcp import FastMCP
mcp = FastMCP("example-server")
@mcp.tool()
def greet(name: str, greeting: str = "Hello") -> str:
"""Greet someone by name."""
return f"{greeting}, {name}!"
Command: intpot to cli mcp_server.py
Output:
import typer
app = typer.Typer()
@app.command()
def greet(
name: str = typer.Argument(..., help=""),
greeting: str = typer.Option('Hello', help=""),
) -> None:
"""Greet someone by name."""
# TODO: implement
typer.echo("greet called")
CLI app to FastAPI
Input (cli_app.py):
import typer
app = typer.Typer()
@app.command()
def add(
a: int = typer.Argument(..., help="First number"),
b: int = typer.Argument(..., help="Second number"),
) -> None:
"""Add two numbers together."""
typer.echo(a + b)
Command: intpot to api cli_app.py
Output:
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class AddRequest(BaseModel):
a: int = Field(..., description="First number")
b: int = Field(..., description="Second number")
@app.post("/add")
def add(request: AddRequest) -> dict:
"""Add two numbers together."""
# TODO: implement
return {"result": "add called"}
API app to MCP server
Input (api_app.py):
from fastapi import FastAPI
app = FastAPI()
@app.post("/greet")
def greet(name: str, greeting: str = "Hello") -> dict:
"""Greet someone by name."""
return {"message": f"{greeting}, {name}!"}
Command: intpot to mcp api_app.py
Output:
from fastmcp import FastMCP
mcp = FastMCP("generated-server")
@mcp.tool()
def greet(
name: str,
greeting: str = 'Hello',
) -> dict:
"""Greet someone by name."""
# TODO: implement
return "greet called"
See the examples/ directory for all conversion outputs, including advanced examples with import json, Body(...), Depends(), async tools, and more. Run bash scripts/demo.sh to regenerate them all.
CLI Reference
intpot init
Scaffold a new project from a template.
intpot init <name> --type <mcp|cli|api>
| Argument/Option | Description |
|---|---|
name |
Project name (creates a directory) |
--type, -t |
Project type: mcp, cli, or api (required) |
intpot to cli
Convert an MCP or API source file to a Typer CLI app.
intpot to cli <source> [--output <path>]
intpot to mcp
Convert a CLI or API source file to a FastMCP server.
intpot to mcp <source> [--output <path>]
intpot to api
Convert a CLI or MCP source file to a FastAPI app.
intpot to api <source> [--output <path>]
| Argument/Option | Description |
|---|---|
source |
Path to a source Python file or directory |
--output, -o |
Output file path (prints to stdout if omitted) |
Development
Requires uv.
git clone https://github.com/tugrulguner/intpot.git
cd intpot
uv sync --all-extras
uv run pre-commit install
Run the full check suite:
make check # lint + typecheck + test
Individual targets:
make lint # ruff check + format check
make typecheck # pyright
make test # pytest
make format # auto-format code
See CONTRIBUTING.md for more details.
Roadmap
See ROADMAP.md for what's planned for v2 (full AST transform pipeline).
License
MIT
Project details
Release history Release notifications | RSS feed
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 intpot-0.2.6.tar.gz.
File metadata
- Download URL: intpot-0.2.6.tar.gz
- Upload date:
- Size: 2.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8508b51dbf3b45679aa72f66757c525cf86ea64840642d93916501d0228f6f85
|
|
| MD5 |
b46057b0d4f6a79376f45dc37ebe132b
|
|
| BLAKE2b-256 |
60429868d60e5b79a508fabb3f2b60a472ec4c30eb033f334e60541ee5eea53a
|
Provenance
The following attestation bundles were made for intpot-0.2.6.tar.gz:
Publisher:
release.yml on tugrulguner/intpot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
intpot-0.2.6.tar.gz -
Subject digest:
8508b51dbf3b45679aa72f66757c525cf86ea64840642d93916501d0228f6f85 - Sigstore transparency entry: 1113645818
- Sigstore integration time:
-
Permalink:
tugrulguner/intpot@33a1590f489da307782a1af2426125f7620690e8 -
Branch / Tag:
refs/tags/v0.2.6 - Owner: https://github.com/tugrulguner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@33a1590f489da307782a1af2426125f7620690e8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file intpot-0.2.6-py3-none-any.whl.
File metadata
- Download URL: intpot-0.2.6-py3-none-any.whl
- Upload date:
- Size: 30.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a329675aebb81353cd36476b742d1fbced8220f8e1392e142266e89055be5181
|
|
| MD5 |
c2f2287e5c282f8767331c802deeb8f4
|
|
| BLAKE2b-256 |
85f904469a8c8d807e7e464c94ec595b78c15ea28c8eb802e31c27cb4cd3103b
|
Provenance
The following attestation bundles were made for intpot-0.2.6-py3-none-any.whl:
Publisher:
release.yml on tugrulguner/intpot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
intpot-0.2.6-py3-none-any.whl -
Subject digest:
a329675aebb81353cd36476b742d1fbced8220f8e1392e142266e89055be5181 - Sigstore transparency entry: 1113645823
- Sigstore integration time:
-
Permalink:
tugrulguner/intpot@33a1590f489da307782a1af2426125f7620690e8 -
Branch / Tag:
refs/tags/v0.2.6 - Owner: https://github.com/tugrulguner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@33a1590f489da307782a1af2426125f7620690e8 -
Trigger Event:
push
-
Statement type: