# Douyin MCP

抖音 MCP (Model Context Protocol) 服务器，为 AI 助手提供访问抖音数据的能力。

## 项目简介

Douyin MCP 是一个基于 MCP 协议的服务器，允许 AI 助手（如 Claude）直接与抖音平台交互。通过本项目，AI 可以搜索视频、获取视频详情、读取评论、查看用户信息等。

### 核心特性

- **本地签名**：内置 JavaScript 签名算法，通过 V8 引擎（py_mini_racer）本地生成 `a_bogus` 签名，无需外部签名服务
- **完整功能**：提供 8 个工具覆盖抖音主要数据获取场景
- **简单配置**：仅需提供抖音 Cookies 即可使用
- **类型安全**：完整的 Python 类型注解和数据模型

## 功能列表

| 工具 | 功能描述 | 参数 |
|------|----------|------|
| `check_login_status` | 检查登录状态 | 无 |
| `search_videos` | 按关键词搜索视频 | keyword, offset, count, sort_type, publish_time |
| `get_video_detail` | 获取视频详情 | aweme_id |
| `get_video_comments` | 获取视频评论 | aweme_id, cursor, count |
| `get_sub_comments` | 获取评论回复 | comment_id, cursor, count |
| `get_user_info` | 获取用户信息 | sec_user_id |
| `get_user_posts` | 获取用户发布的视频 | sec_user_id, max_cursor, count |
| `get_homefeed` | 获取推荐视频流 | tag, count, refresh_index |

## 环境要求

- Python 3.14+
- uv 包管理器（推荐）
- 有效的抖音登录 Cookies

## 安装

```bash
# 克隆仓库
git clone https://github.com/yourusername/douyinmcp.git
cd douyinmcp

# 安装依赖
uv sync
```

## 配置

### Cookie 配置

本项目使用 `cookies.txt` 文件配置 Cookie，**不使用环境变量**（避免特殊字符导致的问题）。

**配置步骤：**

1. 在项目根目录创建 `cookies.txt` 文件
2. 将抖音 Cookie 字符串粘贴到文件中（单行，无需引号）

```bash
# 创建 cookies.txt 文件
touch cookies.txt

# 编辑文件，粘贴你的 Cookie
vim cookies.txt
```

### 获取 Cookies

1. 打开浏览器，访问 https://www.douyin.com
2. 登录你的抖音账号
3. 按 F12 打开开发者工具
4. 进入 **Application → Cookies → https://www.douyin.com**
5. 复制所有 Cookie（格式：`key1=value1; key2=value2; ...`）
6. 粘贴到 `cookies.txt` 文件中

或者使用浏览器插件（如 EditThisCookie）导出 Cookie 字符串。

**cookies.txt 文件示例：**
```
sessionid=abc123; ttwid=xxx; passport_csrf_token=yyy; ...
```

> **注意**：Cookie 必须是单行文本，不要包含换行符。

## 使用方法

### 直接运行

```bash
# 确保 cookies.txt 文件存在
uv run python main.py
```

### 配置 Claude Desktop

在 `claude_desktop_config.json` 中添加：

```json
{
  "mcpServers": {
    "douyin": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/douyinmcp", "python", "main.py"]
    }
  }
}
```

> **注意**：无需配置环境变量，Cookie 从项目根目录的 `cookies.txt` 文件读取。

### 配置 Claude Code

在 `.mcp.json` 中添加 MCP 服务器配置：

```json
{
  "mcpServers": {
    "douyin": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/douyinmcp", "python", "main.py"]
    }
  }
}
```

## 工具详细说明

### 1. check_login_status - 检查登录状态

检查当前 Cookie 是否有效登录。

```python
# 返回示例
{"logged_in": True}
```

### 2. search_videos - 搜索视频

按关键词搜索抖音视频。

| 参数 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| keyword | str | 搜索关键词 | 必填 |
| offset | int | 分页偏移 | 0 |
| count | int | 每页数量 | 10 |
| search_channel | str | 搜索类型：general/video/user/live | general |
| sort_type | int | 排序：0-综合, 1-最多点赞, 2-最新 | 0 |
| publish_time | int | 时间筛选：0-不限, 1-1天内, 7-1周内, 180-半年内 | 0 |

```python
# 搜索美食视频，按点赞数排序
search_videos(keyword="美食", sort_type=1, count=20)
```

### 3. get_video_detail - 获取视频详情

通过视频 ID 获取视频详细信息。

| 参数 | 类型 | 说明 |
|------|------|------|
| aweme_id | str | 视频 ID |

```python
# 获取指定视频详情
get_video_detail(aweme_id="7590719110745525567")

# 返回信息包括：
# - 标题、描述
# - 点赞数、评论数、分享数、收藏数
# - 作者信息
# - 视频封面、下载地址
```

### 4. get_video_comments - 获取视频评论

获取视频的评论列表。

| 参数 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| aweme_id | str | 视频 ID | 必填 |
| cursor | int | 分页游标 | 0 |
| count | int | 每页数量 | 20 |

```python
# 获取视频评论
get_video_comments(aweme_id="7590719110745525567", count=50)
```

### 5. get_sub_comments - 获取评论回复

获取某条评论的回复列表。

| 参数 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| comment_id | str | 评论 ID | 必填 |
| cursor | int | 分页游标 | 0 |
| count | int | 每页数量 | 20 |

```python
# 获取评论的回复
get_sub_comments(comment_id="7590992888545395462")
```

### 6. get_user_info - 获取用户信息

获取用户的个人资料。

| 参数 | 类型 | 说明 |
|------|------|------|
| sec_user_id | str | 用户安全 ID（以 MS4wLjABAAAA 开头）|

```python
# 获取用户信息
get_user_info(sec_user_id="MS4wLjABAAAAG35eRUkDUlhVctlBVKNxjbbqw4Bu...")

# 返回信息包括：
# - 昵称、签名、头像
# - 粉丝数、关注数
# - 获赞数、作品数
# - IP 属地
```

### 7. get_user_posts - 获取用户作品

获取用户发布的视频列表。

| 参数 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| sec_user_id | str | 用户安全 ID | 必填 |
| max_cursor | str | 分页游标 | "0" |
| count | int | 每页数量 | 18 |

```python
# 获取用户的视频作品
get_user_posts(sec_user_id="MS4wLjABAAAA...", count=30)
```

### 8. get_homefeed - 获取推荐视频

获取首页推荐视频流。

| 参数 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| tag | str | 内容分类 | "all" |
| count | int | 获取数量 | 20 |
| refresh_index | int | 刷新索引 | 0 |

支持的分类标签：
- `all` - 全部
- `knowledge` - 知识
- `sports` - 体育
- `auto` - 汽车
- `anime` - 二次元
- `game` - 游戏
- `movie` - 影视
- `life_vlog` - 生活
- `travel` - 旅行
- `mini_drama` - 短剧
- `food` - 美食
- `agriculture` - 三农
- `music` - 音乐
- `animal` - 萌宠
- `parenting` - 亲子
- `fashion` - 时尚

```python
# 获取游戏类推荐视频
get_homefeed(tag="game", count=20)
```

## 项目结构

```
douyinmcp/
├── src/
│   ├── __init__.py        # 包初始化
│   ├── models.py          # 数据模型定义
│   ├── token_manager.py   # Token 生成（msToken, webid, verifyFp）
│   ├── sign.py            # 本地签名模块（V8 引擎）
│   ├── douyin.js          # 签名算法（JavaScript）
│   ├── client.py          # API 客户端实现
│   └── server.py          # MCP 服务器及工具定义
├── tests/
│   ├── __init__.py
│   └── test_all.py        # 综合测试套件
├── doc/
│   └── API.md             # API 接口文档
├── main.py                # 程序入口
├── pyproject.toml         # 项目配置
├── cookies.txt            # Cookie 文件（需自行创建）
├── CHANGELOG              # 变更日志
└── README.md              # 本文档
```

## 测试

运行综合测试验证所有功能：

```bash
# 确保 cookies.txt 存在
uv run python tests/test_all.py
```

测试输出示例：

```
============================================================
Douyin MCP - Comprehensive Test Suite
============================================================

Testing check_login_status...
  ✓ check_login_status: logged_in=True

Testing search_videos...
  ✓ search_videos: Found 5 results

Testing get_video_detail...
  ✓ get_video_detail: Got video: 《给大家讲讲...》

Testing get_video_comments...
  ✓ get_video_comments: Got 10 comments

Testing get_sub_comments...
  ✓ get_sub_comments: Got 1 replies

Testing get_user_info...
  ✓ get_user_info: Got user: 大阳

Testing get_user_posts...
  ✓ get_user_posts: Got 10 posts

Testing get_homefeed...
  ✓ get_homefeed: Got 2 videos from feed

Results: 8/8 tests passed
============================================================
```

## 技术实现

### 签名机制

抖音 Web API 使用 `a_bogus` 参数进行请求签名验证。本项目通过以下方式实现本地签名：

1. 使用 `py_mini_racer` 库提供 V8 JavaScript 引擎
2. 加载 `douyin.js` 签名算法
3. 构建完整的浏览器环境 polyfills（document, navigator, window 等）
4. 调用 `get_abogus()` 函数生成签名

### Token 生成

- **msToken**: 128 字符的验证 Token，支持从字节跳动 API 获取或本地生成
- **webid**: 19 位数字 ID，支持从服务器获取或本地 UUID 算法生成
- **verifyFp / s_v_web_id**: 指纹验证参数，使用 Base36 时间戳 + UUID 格式

### 请求参数

每个请求包含 31 个通用参数，模拟真实浏览器环境：
- 设备信息（platform, cpu_core_num, device_memory）
- 浏览器信息（browser_name, browser_version, engine_name）
- 屏幕信息（screen_width, screen_height）
- 网络信息（downlink, effective_type, round_trip_time）

## 常见问题

### Q: Cookie 多久需要更新？

A: 抖音 Cookie 通常有效期较长，但如果遇到 `logged_in=False` 或请求失败，需要重新获取 Cookie 并更新 `cookies.txt` 文件。

### Q: 为什么不使用环境变量配置 Cookie？

A: 抖音 Cookie 包含大量特殊字符（如 `=`、`;`、`%` 等），在环境变量中配置容易出现解析问题。使用文件配置更可靠。

### Q: cookies.txt 文件放在哪里？

A: 放在项目根目录（与 `main.py` 同级目录）。

### Q: 为什么 get_homefeed 返回的视频数量较少？

A: 推荐接口返回的数量取决于抖音服务器，可能需要多次调用并增加 `refresh_index` 来获取更多内容。

### Q: 遇到签名错误怎么办？

A: 签名模块会自动重置 JavaScript 上下文。如果持续失败，请检查 `douyin.js` 文件是否完整。

### Q: 支持哪些 Python 版本？

A: 项目使用 Python 3.14+ 特性，建议使用最新版本。

## API 文档

详细的 API 接口文档请参阅 [doc/API.md](doc/API.md)。

## 依赖项

- `fastmcp` - MCP 服务器框架
- `httpx` - 异步 HTTP 客户端
- `py-mini-racer` - V8 JavaScript 引擎

## 许可证

MIT License

## 免责声明

本项目仅供学习和研究使用。使用本项目获取的数据应遵守抖音平台的服务条款和相关法律法规。请勿将本项目用于任何商业用途或违法行为。
