mcp py存根
MCP服务器,在Python exe构建(PyInstaller/Nuitka/cx_Freeze)时自动检测存根可置换的包,生成最小存根代码。
______________________________________________________________________
一个MCP服务器,可以自动检测Python exe构建的可存根包(PyInstaller/Nuitka/cx_Freeze),并生成最小的存根代码以减少可执行文件的大小。
背景 / Background
当Python应用程序exe化时,依赖库在模块级import的重量包被整个捆绑在一起,exe尺寸膨胀。在实际的代码路径中不使用的包用最小虚拟(存根)置换的话可以大幅削减尺寸。
当将Python应用程序构建为可执行文件时,通过依赖关系在模块级别导入的重型包会被完全捆绑在一起,导致exe大小膨胀。用最少的存根替换未使用的包可以显著减小大小。
验证数据/验证结果
asammdf项目-已验证E2E行为:
|exe大小|动作|PySide6| |---|---|---|---| |无存根|431MB|确定|已加载| 应用asammdf.gui存根 259毫巴 好的 排除 | | 削减 | -40%(172毫巴) 没有影响
asammdf转换工具(分析结果):
stubbable: pandas (59.7 MB), canmatrix (4.0 MB) — 合計 63.7 MB
submodule hints: asammdf.gui → PySide6 (523 MB) 排除可能 — 50 hints 検出手动存根化的3个软件包(pandas,canmatrix,asammdf.gui)全部自动检测
机能/ Features
工具/工具说明/说明 |---|---| | analyze 分析import图表,自动检测存根候补。C扩展包的间接排除提示也输出/Auto-detect stubbable packages + submodule stub hints for C-extension elimination | | graph 在节点边可视化/可视化import graph as nodes and edges | check 详细分析特定软件包的使用情况/Deep analysis of a specific package's usage | generate 生成软件包存根的最小代码+构建过程输出/Generate minimal stub code + build instructions | | generate_submodule | C生成间接删除扩展包的子模块存根 /生成子模块存根以间接消除C扩展包|
判定结果/ Verdicts
| 判定 / Verdict | 意味 / Meaning |
|---|---|
| 倔强的 可以存根。未在项目执行路径中使用/Safe to stub.Not used in project's runtime path\` | |
不追踪 有保护。--nofollow-import-to で除外推奨 / Protected import. Use --nofollow-import-to | |
| 必需的 无法存根。实际使用的/Cannot stub.Actually used at runtime| |
能做的事
- 非固定库通用检测:仅通过AST结构判定。无硬代码
- 函数级使用跟踪:
mdf.get()使用,使用mdf.to_dataframe()不使用→pandas是stubbable - 区分日历和引用:
isinstance(x, pd.DataFrame)是stub-safepd.DataFrame(data)实际使用 - 发现类继承:
class User(BaseModel)→pydantic是required - 模块级调用检测:跟踪import时执行的代码
- 自动检测try/except保护:受保护的import
nofollow判定 - 存根代码自动生成:仅参考符号的最小存根+构建过程(备份恢复验证)
- 自动检测C扩展:包含.pyd/.so的软件包被判定为不能直接存根化
- C扩展间接排除 *(v0.2新)*:如果未使用import C扩展包的子模块,则可以将该子模块存根化,从而消除C扩展。PySide6(523MB)→asammdf.gui存根 exe 40%削减证实
- 复元安全设计 *(v0.2新)*:备份+固定版本pip+验证命令的三重安全措施
- PyInstaller挂钩信息:通知需要禁用的挂接文件
不能做的事/限制事项
- C扩展包(.pyd/.so)如果直接短截线化,则缺少C扩展,因此required判定。不过
generate_submodule的可间接排除(v0.2对应) - 动的import(
importlib.import_module(変数))通过静态分析无法跟踪(通过warnings通知) - PyInstaller定制挂钩:可能会与短截线碰撞,需要手动禁用挂接
- 延迟初始化模式:
__init__在后面的方法中使用的软件包检测精度下降(在安全方面判定为required) - pip名称与import名称不匹配:
python-dateutil→dateutil等映射不对应 - 运行时条件分支:
if sys.version =1.0.0-模型上下文协议SDK - 分析引擎仅使用Python标准库(ast,importlib,pathlib)
使用方法
启动/运行为MCP服务器
mcp-pystub克劳德桌面/克劳德代码設定
{
"mcpServers": {
"pystub": {
"command": "mcp-pystub"
}
}
}工具使用示例
分析
入力 / Input:
entry_point: "C:/project/converter.py"
python_path: "C:/project/.venv/Lib/site-packages"
出力 / Output:
{
"stubbable": [
{"package_name": "pandas", "estimated_size_mb": 59.7, "reason": "依存ライブラリ経由でのみ import..."}
],
"required": [
{"package_name": "numpy", "reason": "プロジェクトコードが直接 import し使用"},
{"package_name": "PySide6", "estimated_size_mb": 523.2,
"reason": "C 拡張...ただし asammdf.gui をスタブ化することで間接排除が可能",
"submodule_stubs": [{"submodule": "asammdf.gui", "target_package": "PySide6"}]}
],
"nofollow": [
{"package_name": "mpmath"}
],
"submodule_stub_hints": [
{"submodule": "asammdf.gui", "parent_package": "asammdf",
"target_package": "PySide6", "imported_symbols": ["plot"]}
],
"analysis_time_ms": 6478
}生成
入力 / Input:
entry_point: "C:/project/converter.py"
package_name: "pandas"
出力 / Output:
{
"files": {
"pandas/__init__.py": "...",
"pandas/core/api.py": "class DataFrame: pass\nclass Series: pass\n..."
},
"original_file_count": 2980,
"stub_file_count": 266,
"stub_total_bytes": 209530,
"build_instructions": {
"install_commands": ["pip uninstall -y pandas", "# cp stubs to site-packages"],
"uninstall_commands": ["pip install pandas"],
"hook_disable": ["# hook-pandas*.py → .disabled"]
}
}发电机子模块 *(v0.2新)*
入力 / Input:
entry_point: "C:/project/converter.py"
parent_package: "asammdf"
submodule: "asammdf.gui"
出力 / Output:
{
"parent_package": "asammdf",
"submodule": "asammdf.gui",
"files": {
"asammdf/gui/__init__.py": "\"\"\"Auto-generated stub...\"\"\"\ndef plot(*args, **kwargs): ..."
},
"eliminated_packages": ["PySide6", "scipy", "lxml"],
"original_size_bytes": 5907331,
"stub_size_bytes": 144,
"build_instructions": {
"backup_commands": ["cp -r .../asammdf/gui .../asammdf/gui.bak"],
"install_commands": ["rm -rf .../asammdf/gui", "cp -r _stubs/asammdf/gui/ .../asammdf/gui/"],
"uninstall_commands": ["mv .../asammdf/gui.bak .../asammdf/gui"],
"verify_commands": ["python -c \"import asammdf; print('OK')\""]
}
}性能/性能
|项目规模|分析时间|节点数| |-----------------|---------|---------| | 軽量 (click) | 335ms | 73 | |中规模(flask)| 1,743ms | 230 | |重量级(pandas)| 4,820ms | 491 | |超重量级(sympy)| 6,919ms | 681 |
测试/测试
python -m pytest tests/ -v测试结果
|测试种类|件数|结果| |-----------|------|------| |单元测试(9模块)|91|全部通过| PyPI库大规模测试(requests、flask、pandas等)|84|崩溃0| PyInstaller exe构建+动作测试|22| 全 PASS | \ exe 40%削减+正常动作 | |还原测试(备份→还原→验证)|4|全部成功|
许可证/许可证
麻省理工学院
