hljy-lark-doc-helper


Namehljy-lark-doc-helper JSON
Version 0.1.9 PyPI version JSON
download
home_pageNone
SummaryMCP server for uploading markdown files to Lark documents with automatic image processing
upload_time2025-07-18 09:00:36
maintainerNone
docs_urlNone
authorNone
requires_python>=3.12
licenseMIT
keywords document feishu lark markdown mcp upload
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 飞书文档助手 (Lark Doc Helper)

一个 MCP (Model Context Protocol) 服务器,用于将本地 Markdown 文件上传到飞书文档,并自动处理本地图片引用。

## 功能特性

- 📄 上传 Markdown 文件到飞书文档
- 🖼️ 自动检测并上传本地图片引用
- 🔗 自动替换图片链接为公共访问URL
- ⚙️ 可配置的API endpoints和认证信息
- 📊 支持多种图片格式 (jpg, jpeg, png, gif, bmp, webp, svg)

## 安装

确保您的系统已安装 Python 3.12+,然后运行:

```bash
# 使用 uv 安装依赖
uv sync

# 或者使用 pip
pip install -e .
```

## 配置

### 环境变量配置

创建一个 `.env` 文件或设置以下环境变量:

```bash
# API Endpoints配置
UPLOAD_CREDENTIALS_ENDPOINT=http://0.0.0.0:19106/api/v1/obs/post-signature/md-image-upload
OBS_UPLOAD_ENDPOINT=https://hljydc-common.obs.cn-east-3.myhuaweicloud.com
LARK_DOC_UPLOAD_ENDPOINT=http://0.0.0.0:19106/api/v1/lark-doc/helper/markdown-to-docx

# 认证配置
API_KEY=your-api-key
API_SECRET=your-api-secret

# 飞书应用配置
LARK_APP_ID=your-lark-app-id
LARK_APP_SECRET=your-lark-app-secret
LARK_TENANT_TOKEN=your-lark-tenant-token

# 默认挂载密钥(可选,也可以在调用时传入)
DEFAULT_MOUNT_KEY=

# 其他配置
MAX_FILE_SIZE=10485760  # 10MB
REQUEST_TIMEOUT=30      # 30秒
```

### 必需的API接口

您需要提供以下三个API接口:

1. **获取上传凭证接口**
   - 端点:`UPLOAD_CREDENTIALS_ENDPOINT`
   - 方法:POST
   - 请求体:`{"filename": "image.jpg"}`
   - 返回:包含OBS访问凭证的JSON

2. **OBS图片上传接口**
   - 端点:`OBS_UPLOAD_ENDPOINT`
   - 方法:POST
   - 请求:表单数据(multipart/form-data)
   - 返回:204状态码表示成功

3. **飞书文档上传接口**
   - 端点:`LARK_DOC_UPLOAD_ENDPOINT`
   - 方法:POST
   - 请求体:`{"markdown": "...", "doc_name": "...", "mount_key": "..."}`
   - 返回:包含文档URL的JSON

## 使用方法

### 作为 MCP 服务器运行

```bash
python main.py
```

### 在 Cursor 中使用

详细的Cursor配置指南请参考 [cursor-mcp-config.md](cursor-mcp-config.md)

简要配置:
1. 在Cursor设置中添加MCP服务器配置
2. 配置命令:`python /path/to/main.py`
3. 设置环境变量(API endpoints等)
4. 在聊天中直接使用工具

### 在其他 MCP 客户端中使用

服务器提供一个工具:`upload_markdown_to_lark_doc`

参数:
- `markdown_file_path`: 要上传的 Markdown 文件的绝对路径
- `doc_title`: 飞书文档的标题
- `mount_key`: 飞书文档的挂载密钥

示例:
```json
{
  "tool": "upload_markdown_to_lark_doc",
  "arguments": {
    "markdown_file_path": "/path/to/your/document.md",
    "doc_title": "我的文档标题",
    "mount_key": "change-this"
  }
}
```

## 工作流程

1. **读取 Markdown 文件**:从指定路径读取 Markdown 内容
2. **检测本地图片**:使用正则表达式找到所有本地图片引用
3. **上传图片**:
   - 调用接口1获取上传凭证
   - 调用接口2上传每张图片到OBS
   - 获取图片的公共访问URL
4. **替换图片链接**:将 Markdown 中的本地图片路径替换为公共URL
5. **上传文档**:调用接口3将最终的 Markdown 内容上传到飞书文档

## 支持的图片格式

- `.jpg`, `.jpeg`
- `.png`
- `.gif`
- `.bmp`
- `.webp`
- `.svg`

## 错误处理

- 文件不存在时会返回错误
- 图片文件大小超过限制时会返回错误
- API调用失败时会返回详细的错误信息
- 配置验证失败时会返回配置错误信息

## 日志

服务器会记录以下信息:
- 发现的本地图片数量
- 图片上传进度和结果
- API调用错误和异常

## 开发

### 项目结构

```
lark-doc-helper/
├── main.py           # 主程序文件
├── config.py         # 配置管理
├── pyproject.toml    # 项目配置
├── README.md         # 说明文档
└── uv.lock          # 依赖锁定文件
```

### 自定义API接口

您需要实现以下接口格式:

1. **上传凭证接口响应**:
```json
{
  "status": "success",
  "code": 200,
  "message": null,
  "data": {
    "policy": "base64-encoded-policy",
    "signature": "signature-string",
    "accessKeyId": "access-key-id",
    "key": "temp/md-image/20250717/uuid/filename.jpg",
    "originPolicy": "original-policy-json"
  }
}
```

2. **OBS上传接口响应**:
- 状态码:200 或 204 表示成功
- 上传成功后,图片可通过 `{obs_endpoint}/{key}` 访问

3. **飞书文档上传接口响应**:
```json
{
  "status": "success",
  "code": 200,
  "message": null,
  "data": {
    "url": "https://hailiang.feishu.cn/docx/XgWDdPwRCoK7QkxcaztcOMjFnCd"
  }
}
```

## 许可证

本项目使用 MIT 许可证。

## 贡献

欢迎提交 Issue 和 Pull Request!

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "hljy-lark-doc-helper",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "document, feishu, lark, markdown, mcp, upload",
    "author": null,
    "author_email": "HLJY <your-email@example.com>",
    "download_url": "https://files.pythonhosted.org/packages/28/08/da39a7b463ab193b1f9e6dc4a6ba53a28829189b194bc46c478a2564fdb1/hljy_lark_doc_helper-0.1.9.tar.gz",
    "platform": null,
    "description": "# \u98de\u4e66\u6587\u6863\u52a9\u624b (Lark Doc Helper)\n\n\u4e00\u4e2a MCP (Model Context Protocol) \u670d\u52a1\u5668\uff0c\u7528\u4e8e\u5c06\u672c\u5730 Markdown \u6587\u4ef6\u4e0a\u4f20\u5230\u98de\u4e66\u6587\u6863\uff0c\u5e76\u81ea\u52a8\u5904\u7406\u672c\u5730\u56fe\u7247\u5f15\u7528\u3002\n\n## \u529f\u80fd\u7279\u6027\n\n- \ud83d\udcc4 \u4e0a\u4f20 Markdown \u6587\u4ef6\u5230\u98de\u4e66\u6587\u6863\n- \ud83d\uddbc\ufe0f \u81ea\u52a8\u68c0\u6d4b\u5e76\u4e0a\u4f20\u672c\u5730\u56fe\u7247\u5f15\u7528\n- \ud83d\udd17 \u81ea\u52a8\u66ff\u6362\u56fe\u7247\u94fe\u63a5\u4e3a\u516c\u5171\u8bbf\u95eeURL\n- \u2699\ufe0f \u53ef\u914d\u7f6e\u7684API endpoints\u548c\u8ba4\u8bc1\u4fe1\u606f\n- \ud83d\udcca \u652f\u6301\u591a\u79cd\u56fe\u7247\u683c\u5f0f (jpg, jpeg, png, gif, bmp, webp, svg)\n\n## \u5b89\u88c5\n\n\u786e\u4fdd\u60a8\u7684\u7cfb\u7edf\u5df2\u5b89\u88c5 Python 3.12+\uff0c\u7136\u540e\u8fd0\u884c\uff1a\n\n```bash\n# \u4f7f\u7528 uv \u5b89\u88c5\u4f9d\u8d56\nuv sync\n\n# \u6216\u8005\u4f7f\u7528 pip\npip install -e .\n```\n\n## \u914d\u7f6e\n\n### \u73af\u5883\u53d8\u91cf\u914d\u7f6e\n\n\u521b\u5efa\u4e00\u4e2a `.env` \u6587\u4ef6\u6216\u8bbe\u7f6e\u4ee5\u4e0b\u73af\u5883\u53d8\u91cf\uff1a\n\n```bash\n# API Endpoints\u914d\u7f6e\nUPLOAD_CREDENTIALS_ENDPOINT=http://0.0.0.0:19106/api/v1/obs/post-signature/md-image-upload\nOBS_UPLOAD_ENDPOINT=https://hljydc-common.obs.cn-east-3.myhuaweicloud.com\nLARK_DOC_UPLOAD_ENDPOINT=http://0.0.0.0:19106/api/v1/lark-doc/helper/markdown-to-docx\n\n# \u8ba4\u8bc1\u914d\u7f6e\nAPI_KEY=your-api-key\nAPI_SECRET=your-api-secret\n\n# \u98de\u4e66\u5e94\u7528\u914d\u7f6e\nLARK_APP_ID=your-lark-app-id\nLARK_APP_SECRET=your-lark-app-secret\nLARK_TENANT_TOKEN=your-lark-tenant-token\n\n# \u9ed8\u8ba4\u6302\u8f7d\u5bc6\u94a5\uff08\u53ef\u9009\uff0c\u4e5f\u53ef\u4ee5\u5728\u8c03\u7528\u65f6\u4f20\u5165\uff09\nDEFAULT_MOUNT_KEY=\n\n# \u5176\u4ed6\u914d\u7f6e\nMAX_FILE_SIZE=10485760  # 10MB\nREQUEST_TIMEOUT=30      # 30\u79d2\n```\n\n### \u5fc5\u9700\u7684API\u63a5\u53e3\n\n\u60a8\u9700\u8981\u63d0\u4f9b\u4ee5\u4e0b\u4e09\u4e2aAPI\u63a5\u53e3\uff1a\n\n1. **\u83b7\u53d6\u4e0a\u4f20\u51ed\u8bc1\u63a5\u53e3**\n   - \u7aef\u70b9\uff1a`UPLOAD_CREDENTIALS_ENDPOINT`\n   - \u65b9\u6cd5\uff1aPOST\n   - \u8bf7\u6c42\u4f53\uff1a`{\"filename\": \"image.jpg\"}`\n   - \u8fd4\u56de\uff1a\u5305\u542bOBS\u8bbf\u95ee\u51ed\u8bc1\u7684JSON\n\n2. **OBS\u56fe\u7247\u4e0a\u4f20\u63a5\u53e3**\n   - \u7aef\u70b9\uff1a`OBS_UPLOAD_ENDPOINT`\n   - \u65b9\u6cd5\uff1aPOST\n   - \u8bf7\u6c42\uff1a\u8868\u5355\u6570\u636e\uff08multipart/form-data\uff09\n   - \u8fd4\u56de\uff1a204\u72b6\u6001\u7801\u8868\u793a\u6210\u529f\n\n3. **\u98de\u4e66\u6587\u6863\u4e0a\u4f20\u63a5\u53e3**\n   - \u7aef\u70b9\uff1a`LARK_DOC_UPLOAD_ENDPOINT`\n   - \u65b9\u6cd5\uff1aPOST\n   - \u8bf7\u6c42\u4f53\uff1a`{\"markdown\": \"...\", \"doc_name\": \"...\", \"mount_key\": \"...\"}`\n   - \u8fd4\u56de\uff1a\u5305\u542b\u6587\u6863URL\u7684JSON\n\n## \u4f7f\u7528\u65b9\u6cd5\n\n### \u4f5c\u4e3a MCP \u670d\u52a1\u5668\u8fd0\u884c\n\n```bash\npython main.py\n```\n\n### \u5728 Cursor \u4e2d\u4f7f\u7528\n\n\u8be6\u7ec6\u7684Cursor\u914d\u7f6e\u6307\u5357\u8bf7\u53c2\u8003 [cursor-mcp-config.md](cursor-mcp-config.md)\n\n\u7b80\u8981\u914d\u7f6e\uff1a\n1. \u5728Cursor\u8bbe\u7f6e\u4e2d\u6dfb\u52a0MCP\u670d\u52a1\u5668\u914d\u7f6e\n2. \u914d\u7f6e\u547d\u4ee4\uff1a`python /path/to/main.py`\n3. \u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\uff08API endpoints\u7b49\uff09\n4. \u5728\u804a\u5929\u4e2d\u76f4\u63a5\u4f7f\u7528\u5de5\u5177\n\n### \u5728\u5176\u4ed6 MCP \u5ba2\u6237\u7aef\u4e2d\u4f7f\u7528\n\n\u670d\u52a1\u5668\u63d0\u4f9b\u4e00\u4e2a\u5de5\u5177\uff1a`upload_markdown_to_lark_doc`\n\n\u53c2\u6570\uff1a\n- `markdown_file_path`: \u8981\u4e0a\u4f20\u7684 Markdown \u6587\u4ef6\u7684\u7edd\u5bf9\u8def\u5f84\n- `doc_title`: \u98de\u4e66\u6587\u6863\u7684\u6807\u9898\n- `mount_key`: \u98de\u4e66\u6587\u6863\u7684\u6302\u8f7d\u5bc6\u94a5\n\n\u793a\u4f8b\uff1a\n```json\n{\n  \"tool\": \"upload_markdown_to_lark_doc\",\n  \"arguments\": {\n    \"markdown_file_path\": \"/path/to/your/document.md\",\n    \"doc_title\": \"\u6211\u7684\u6587\u6863\u6807\u9898\",\n    \"mount_key\": \"change-this\"\n  }\n}\n```\n\n## \u5de5\u4f5c\u6d41\u7a0b\n\n1. **\u8bfb\u53d6 Markdown \u6587\u4ef6**\uff1a\u4ece\u6307\u5b9a\u8def\u5f84\u8bfb\u53d6 Markdown \u5185\u5bb9\n2. **\u68c0\u6d4b\u672c\u5730\u56fe\u7247**\uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u627e\u5230\u6240\u6709\u672c\u5730\u56fe\u7247\u5f15\u7528\n3. **\u4e0a\u4f20\u56fe\u7247**\uff1a\n   - \u8c03\u7528\u63a5\u53e31\u83b7\u53d6\u4e0a\u4f20\u51ed\u8bc1\n   - \u8c03\u7528\u63a5\u53e32\u4e0a\u4f20\u6bcf\u5f20\u56fe\u7247\u5230OBS\n   - \u83b7\u53d6\u56fe\u7247\u7684\u516c\u5171\u8bbf\u95eeURL\n4. **\u66ff\u6362\u56fe\u7247\u94fe\u63a5**\uff1a\u5c06 Markdown \u4e2d\u7684\u672c\u5730\u56fe\u7247\u8def\u5f84\u66ff\u6362\u4e3a\u516c\u5171URL\n5. **\u4e0a\u4f20\u6587\u6863**\uff1a\u8c03\u7528\u63a5\u53e33\u5c06\u6700\u7ec8\u7684 Markdown \u5185\u5bb9\u4e0a\u4f20\u5230\u98de\u4e66\u6587\u6863\n\n## \u652f\u6301\u7684\u56fe\u7247\u683c\u5f0f\n\n- `.jpg`, `.jpeg`\n- `.png`\n- `.gif`\n- `.bmp`\n- `.webp`\n- `.svg`\n\n## \u9519\u8bef\u5904\u7406\n\n- \u6587\u4ef6\u4e0d\u5b58\u5728\u65f6\u4f1a\u8fd4\u56de\u9519\u8bef\n- \u56fe\u7247\u6587\u4ef6\u5927\u5c0f\u8d85\u8fc7\u9650\u5236\u65f6\u4f1a\u8fd4\u56de\u9519\u8bef\n- API\u8c03\u7528\u5931\u8d25\u65f6\u4f1a\u8fd4\u56de\u8be6\u7ec6\u7684\u9519\u8bef\u4fe1\u606f\n- \u914d\u7f6e\u9a8c\u8bc1\u5931\u8d25\u65f6\u4f1a\u8fd4\u56de\u914d\u7f6e\u9519\u8bef\u4fe1\u606f\n\n## \u65e5\u5fd7\n\n\u670d\u52a1\u5668\u4f1a\u8bb0\u5f55\u4ee5\u4e0b\u4fe1\u606f\uff1a\n- \u53d1\u73b0\u7684\u672c\u5730\u56fe\u7247\u6570\u91cf\n- \u56fe\u7247\u4e0a\u4f20\u8fdb\u5ea6\u548c\u7ed3\u679c\n- API\u8c03\u7528\u9519\u8bef\u548c\u5f02\u5e38\n\n## \u5f00\u53d1\n\n### \u9879\u76ee\u7ed3\u6784\n\n```\nlark-doc-helper/\n\u251c\u2500\u2500 main.py           # \u4e3b\u7a0b\u5e8f\u6587\u4ef6\n\u251c\u2500\u2500 config.py         # \u914d\u7f6e\u7ba1\u7406\n\u251c\u2500\u2500 pyproject.toml    # \u9879\u76ee\u914d\u7f6e\n\u251c\u2500\u2500 README.md         # \u8bf4\u660e\u6587\u6863\n\u2514\u2500\u2500 uv.lock          # \u4f9d\u8d56\u9501\u5b9a\u6587\u4ef6\n```\n\n### \u81ea\u5b9a\u4e49API\u63a5\u53e3\n\n\u60a8\u9700\u8981\u5b9e\u73b0\u4ee5\u4e0b\u63a5\u53e3\u683c\u5f0f\uff1a\n\n1. **\u4e0a\u4f20\u51ed\u8bc1\u63a5\u53e3\u54cd\u5e94**:\n```json\n{\n  \"status\": \"success\",\n  \"code\": 200,\n  \"message\": null,\n  \"data\": {\n    \"policy\": \"base64-encoded-policy\",\n    \"signature\": \"signature-string\",\n    \"accessKeyId\": \"access-key-id\",\n    \"key\": \"temp/md-image/20250717/uuid/filename.jpg\",\n    \"originPolicy\": \"original-policy-json\"\n  }\n}\n```\n\n2. **OBS\u4e0a\u4f20\u63a5\u53e3\u54cd\u5e94**:\n- \u72b6\u6001\u7801\uff1a200 \u6216 204 \u8868\u793a\u6210\u529f\n- \u4e0a\u4f20\u6210\u529f\u540e\uff0c\u56fe\u7247\u53ef\u901a\u8fc7 `{obs_endpoint}/{key}` \u8bbf\u95ee\n\n3. **\u98de\u4e66\u6587\u6863\u4e0a\u4f20\u63a5\u53e3\u54cd\u5e94**:\n```json\n{\n  \"status\": \"success\",\n  \"code\": 200,\n  \"message\": null,\n  \"data\": {\n    \"url\": \"https://hailiang.feishu.cn/docx/XgWDdPwRCoK7QkxcaztcOMjFnCd\"\n  }\n}\n```\n\n## \u8bb8\u53ef\u8bc1\n\n\u672c\u9879\u76ee\u4f7f\u7528 MIT \u8bb8\u53ef\u8bc1\u3002\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4 Issue \u548c Pull Request\uff01\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "MCP server for uploading markdown files to Lark documents with automatic image processing",
    "version": "0.1.9",
    "project_urls": {
        "Homepage": "https://github.com/your-username/hljy-lark-doc-helper",
        "Issues": "https://github.com/your-username/hljy-lark-doc-helper/issues",
        "Repository": "https://github.com/your-username/hljy-lark-doc-helper"
    },
    "split_keywords": [
        "document",
        " feishu",
        " lark",
        " markdown",
        " mcp",
        " upload"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e44cd229cd3146af030666068c6356d93c5313734e83fd6d6b2fcb9ff23d816c",
                "md5": "0c4d384166b22e52e0ae71cd7d5a9164",
                "sha256": "7c3f3924db4d8635631cf7d2f63fa32c48452f37c7ae85905b7eea116eef887f"
            },
            "downloads": -1,
            "filename": "hljy_lark_doc_helper-0.1.9-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0c4d384166b22e52e0ae71cd7d5a9164",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 13926,
            "upload_time": "2025-07-18T09:00:34",
            "upload_time_iso_8601": "2025-07-18T09:00:34.756159Z",
            "url": "https://files.pythonhosted.org/packages/e4/4c/d229cd3146af030666068c6356d93c5313734e83fd6d6b2fcb9ff23d816c/hljy_lark_doc_helper-0.1.9-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2808da39a7b463ab193b1f9e6dc4a6ba53a28829189b194bc46c478a2564fdb1",
                "md5": "0cf2c316a9b0660e29323fd366737f61",
                "sha256": "4e466a15db64aa88c16ab680e5baa7775f28c877b2750079078f82b4cc4dacec"
            },
            "downloads": -1,
            "filename": "hljy_lark_doc_helper-0.1.9.tar.gz",
            "has_sig": false,
            "md5_digest": "0cf2c316a9b0660e29323fd366737f61",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 11424,
            "upload_time": "2025-07-18T09:00:36",
            "upload_time_iso_8601": "2025-07-18T09:00:36.479203Z",
            "url": "https://files.pythonhosted.org/packages/28/08/da39a7b463ab193b1f9e6dc4a6ba53a28829189b194bc46c478a2564fdb1/hljy_lark_doc_helper-0.1.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-18 09:00:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "your-username",
    "github_project": "hljy-lark-doc-helper",
    "github_not_found": true,
    "lcname": "hljy-lark-doc-helper"
}
        
Elapsed time: 0.81687s