mcpField
P
pystub

pystub

本地服务
github.com/KoyoYeager开发工具030 周前更新

关于 pystub

pystub 是面向 Python 打包开发者的 MCP 服务,适用于 PyInstaller、Nuitka 和 cx_Freeze。它分析导入关系与运行时使用情况,识别可替换为桩代码的包,并生成最小桩代码和构建指引。

主要功能

  1. 01识别可安全替换为桩代码的包
  2. 02分析导入关系和包使用情况
  3. 03可视化依赖图
  4. 04生成包及子模块桩代码
  5. 05标记受保护导入和 C 扩展

适用场景

  1. 01通过桩化未使用依赖缩小可执行文件
  2. 02检查包是否为运行所必需
  3. 03生成桩代码以排除 C 扩展依赖
  4. 04在打包前检查依赖路径

MCP 相关

向 MCP 客户端提供分析、依赖图、包检查和桩代码生成工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"koyoyeager-pystub": {
"command": "uvx",
"args": [
"mcp-pystub"
]
}
}
}
启动命令uvx mcp-pystub

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypimcp-pystub0.1.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

mcp-pystub

一个 MCP 服务,可在 Python exe 构建(PyInstaller / Nuitka / cx_Freeze)时自动检测可替换为存根的包,并生成最小存根代码。


一个 MCP 服务,可在 Python exe 构建(PyInstaller / Nuitka / cx_Freeze)时自动检测可替换为存根的包,并生成最小存根代码,以减小可执行文件的体积。

背景

将 Python 应用构建为可执行文件时,依赖项在模块级别导入的重量级包会被完整打包,导致 exe 体积膨胀。将实际代码路径中未使用的包替换为最小化的虚拟包(存根),即可大幅减小体积。

实证数据

asammdf 项目 — PyInstaller exe 构建(已通过端到端运行验证):

exe 体积运行状态PySide6
未使用存根431 MB正常已加载
应用 asammdf.gui 存根259 MB正常已排除
减少-40%(172 MB)无影响

asammdf 转换工具(analyze 结果):

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)均已自动检测

功能

工具说明
analyze分析 import 图并自动检测可存根化的候选包。还会输出用于间接排除 C 扩展包的提示
graph将 import 图显示为节点和边
check深入分析特定包的使用情况
generate生成最小包存根代码 + 构建说明
generate_submodule生成子模块存根,以间接排除 C 扩展包
判定结果
判定含义
stubbable可以存根化。在项目的运行路径中未使用
nofollow有 try/except 保护。建议使用 --nofollow-import-to 排除
required不可存根化。运行时实际使用

可以做什么

  • 通用检测,不绑定特定库:仅根据 AST 结构判定,不使用硬编码规则
  • 追踪函数级别的使用情况:使用 mdf.get(),但不使用 mdf.to_dataframe() → pandas 可存根化
  • 区分调用与引用:isinstance(x, pd.DataFrame) 可安全使用存根;pd.DataFrame(data) 则属于实际使用
  • 检测类继承:class User(BaseModel) → pydantic 为 required
  • 检测模块级调用:追踪导入时执行的代码
  • 自动检测 try/except 保护:将受保护的 import 判定为 nofollow
  • 自动生成存根代码:仅包含被引用符号的最小存根 + 构建说明(备份、恢复、验证)
  • 自动检测 C 扩展:判定包含 .pyd / .so 的包不可直接存根化
  • 间接排除 C 扩展 (v0.2 新增):如果导入 C 扩展包的子模块未被使用,则可以存根化该子模块以排除 C 扩展。已验证 PySide6(523 MB)→ 使用 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 < (3,11) 中的 import
安全策略

设计目标是**绝不发生“判定为可存根化,但实际上必需”**的情况。难以确定时,将判定为 required,以确保安全。相反方向的误判(实际可存根化,却判定为 required)可以接受。

分析算法

  1. 提取 Import:使用 ast.parse() 分析各文件中的 import 语句(区分模块级、函数级和 try/except 保护)
  2. 构建 Import 图:从入口点开始,通过 BFS 递归解析依赖关系(自动分类 stdlib / third_party / local)
  3. 使用情况分析:确定网关函数(在依赖库中调用包的函数),并追踪项目代码是否调用这些函数。仅引用名称(isinstance、类型注解)时,视为可安全使用存根并排除
  4. 模块级检测:如果导入时调用了包的函数,则提升为 required
  5. 子模块间接排除 (v0.2):找出导入 C 扩展包的子模块;如果项目没有直接导入该子模块,也没有调用其重新导出的符号,则输出存根提示

安装

pip install mcp-pystub
依赖包 / Dependencies
  • mcp>=1.0.0 - Model Context Protocol SDK
  • 解析引擎仅使用 Python 标准库(ast、importlib、pathlib)

使用方法 / Usage

作为 MCP 服务启动 / Run as MCP server
mcp-pystub
Claude Desktop / Claude Code 配置
{
  "mcpServers": {
    "pystub": {
      "command": "mcp-pystub"
    }
  }
}
工具使用示例 / Tool Examples
analyze
入力 / 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
  }
generate
入力 / 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"]
    }
  }
generate_submodule (v0.2 new)
入力 / 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')\""]
    }
  }

性能 / Performance

项目规模解析时间节点数
轻量(click)335ms73
中等规模(flask)1,743ms230
大型(pandas)4,820ms491
超大型(sympy)6,919ms681

测试 / Testing

python -m pytest tests/ -v
测试结果
测试类型数量结果
单元测试(9 个模块)91全部通过
PyPI 库大规模测试(requests、flask、pandas 等)840 次崩溃
PyInstaller exe 构建 + 运行测试22全部 PASS
asammdf E2E(MDF 创建→读取→重采样)1exe 减少 40% + 运行正常
恢复测试(备份 → 恢复 → 验证)4全部成功

许可证 / License

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。