# PyPI 发布指南
本文档说明如何将 `yuppie-mcp-feishu` 发布到 PyPI。
## 前置准备
### 1. 安装发布工具
```bash
# 使用 uv(本项目推荐)
uv pip install build twine
# 或使用 pip
pip install build twine
```
### 2. 准备 PyPI 账号
- 注册 PyPI 账号:https://pypi.org/account/register/
- 启用双重认证(2FA)
- 创建 API token:https://pypi.org/manage/account/token/
- 保存 token,发布时需要使用
## 发布步骤
### 步骤 1: 检查版本号
**重要**: 本项目需要在两个地方同步版本号:
在 `pyproject.toml` 中确认版本号:
```toml
version = "0.5.0"
```
在 `src/yuppie_mcp_feishu/server.py` 中确认版本号:
```python
InitializationOptions(
server_name="yuppie-mcp-feishu",
server_version="0.5.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
)
```
**注意**: 每次发布都必须更新版本号,PyPI 不允许覆盖已存在的版本。
### 步骤 2: 构建发布包
```bash
# 清理旧的构建文件
rm -rf dist/ build/
# 构建源码包和 wheel
uv run python -m build
```
这将创建:
- `dist/yuppie_mcp_feishu-0.5.0.tar.gz` (源码包)
- `dist/yuppie_mcp_feishu-0.5.0-py3-none-any.whl` (wheel 包)
### 步骤 3: 检查构建结果
```bash
# 查看生成的文件
ls -lh dist/
# 检查包的元数据
uv run twine check dist/*
```
### 步骤 4: 上传到 TestPyPI(推荐先测试)
```bash
# 上传到 TestPyPI
uv run twine upload --repository testpypi dist/*
```
验证安装:
```bash
# 从 TestPyPI 安装测试
pip install --index-url https://test.pypi.org/simple/ yuppie-mcp-feishu
# 验证安装
yuppie-mcp-feishu --help
# 或使用 uvx
uvx yuppie-mcp-feishu --help
```
### 步骤 5: 上传到 PyPI(正式发布)
```bash
# 使用 API token 上传(推荐)
uv run twine upload dist/*
```
#### 配置 API Token
创建 `~/.pypirc` 文件:
```ini
[pypi]
username = __token__
password = <your-pypi-token>
```
或直接在上传时输入凭证(交互式)。
### 步骤 6: 验证发布
```bash
# 安装发布的包
pip install yuppie-mcp-feishu
# 或升级到最新版本
pip install --upgrade yuppie-mcp-feishu
# 或使用 uvx
uvx yuppie-mcp-feishu --help
```
访问 PyPI 页面确认:
https://pypi.org/project/yuppie-mcp-feishu/
## 版本发布建议
### 语义化版本号
- `0.5.0` - 破坏性变更
- `0.4.4` - Bug 修复
- `0.4.2` - 新增功能(向后兼容)
- `1.0.0` - 稳定版本
- `2.0.0` - 重大破坏性变更
### 破坏性变更版本号
当进行以下类型的变更时,应该升级次版本号(例如 `0.5.0` → `0.6.0`):
- 参数类型变更(如 v0.5.0 将对象/数组参数改为 JSON 字符串)
- 移除已有功能或参数
- 修改返回值结构
- 不兼容的 API 变更
**注意**: 破坏性变更需要在发布说明中提供迁移指南。
### 发布检查清单
发布前请确认:
- [ ] 版本号已更新(两处:`pyproject.toml` 和 `server.py`)
- [ ] `CHANGELOG.md` 已更新
- [ ] `README.md` 中工具参数文档已更新且与实现一致
- [ ] 所有测试通过:`PYTHONPATH=src uv run pytest tests/ -v`
- [ ] 构建成功:`uv run python -m build`
- [ ] 元数据检查通过:`uv run twine check dist/*`
- [ ] 已在 TestPyPI 测试过(可选但推荐)
- [ ] Git tag 已创建并推送:
```bash
git tag v0.5.0
git push origin main
git push origin v0.5.0
```
## CHANGELOG 管理
建议创建并维护 `CHANGELOG.md` 文件来记录版本变更。
### CHANGELOG 模板
```markdown
## [0.5.0] - 2025-01-04
### Breaking Changes
- 破坏性变更描述
- 提供迁移指南
### Added
- 新增功能
### Changed
- 变更内容
### Fixed
- 修复的问题
### Removed
- 移除的功能
```
### 参考资源
- [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
## v0.5.0 迁移指南
版本 0.5.0 引入了破坏性变更:所有对象和数组类型的参数改为 JSON 字符串格式。
### 变更原因
为了避免 MCP 协议中的序列化问题,确保参数能够正确传递。
### 迁移步骤
#### 1. 更新参数格式
**旧版本调用方式**:
```json
{
"app_token": "xxx",
"table_id": "xxx",
"fields": {
"name": "张三",
"age": 25
},
"filter": {
"conjunction": "and",
"conditions": [...]
}
}
```
**新版本调用方式**:
```json
{
"app_token": "xxx",
"table_id": "xxx",
"fields": "{\"name\":\"张三\",\"age\":25}",
"filter": "{\"conjunction\":\"and\",\"conditions\":[...]}"
}
```
#### 2. 批量操作参数
**旧版本**:
```json
{
"records": [
{"fields": {"name": "张三"}},
{"fields": {"name": "李四"}}
]
}
```
**新版本**:
```json
{
"records": "[{\"fields\":{\"name\":\"张三\"}},{\"fields\":{\"name\":\"李四\"}}]"
}
```
#### 3. 记录 ID 列表
**旧版本**:
```json
{
"record_ids": ["id1", "id2", "id3"]
}
```
**新版本**:
```json
{
"record_ids": "[\"id1\",\"id2\",\"id3\"]"
}
```
### 错误处理
新版本添加了 JSON 解析错误处理。如果提供的 JSON 格式不正确,将返回:
```json
{
"success": false,
"error": "Invalid JSON format: <具体错误信息>",
"error_type": "JSONDecodeError"
}
```
## 常见问题
### Q: 如何回退已发布的版本?
A: PyPI 不允许删除或覆盖已发布的版本。如果发现问题,需要:
1. 发布新的修复版本(如 0.5.1)
2. 在 PyPI 上将旧版本标记为 "yanked"
### Q: 上传失败怎么办?
A: 检查:
- 版本号是否已存在
- 包名是否已被占用
- 网络连接是否正常
- API token 是否有效
### Q: 如何预览包的 PyPI 页面?
A: 使用 TestPyPI 进行测试发布:
```bash
uv run twine upload --repository testpypi dist/*
```
然后访问:https://test.pypi.org/project/yuppie-mcp-feishu/
### Q: 如何处理破坏性变更?
A:
1. 升级次版本号(如 0.5.0 → 0.6.0)
2. 在 CHANGELOG 中提供详细的迁移指南
3. 在发布说明中突出显示破坏性变更
4. 考虑在发布后提供一段过渡期
### Q: 本项目为什么需要同步两处版本号?
A: `pyproject.toml` 中的版本号用于 PyPI 包版本管理,而 `server.py` 中的版本号用于 MCP 协议握手时报告给客户端。两处保持同步可以确保版本信息的一致性。
### Q: 如何避免忘记同步版本号?
A: 可以使用以下方法:
1. 在发布前使用 `grep` 检查两处版本号是否一致
2. 考虑添加 pre-commit hook 进行自动检查
3. 使用自动化工具(如 `setuptools_scm`)从 git tag 自动生成版本号
## 相关链接
- PyPI: https://pypi.org/
- TestPyPI: https://test.pypi.org/
- 打包指南: https://packaging.python.org/tutorials/packaging-projects/
- Twine 文档: https://twine.readthedocs.io/
- Keep a Changelog: https://keepachangelog.com/
- Semantic Versioning: https://semver.org/