Merge branch 'main' of https://github.com/xpzouying/xiaohongshu-mcp into feature/comment-feed-logic

This commit is contained in:
chekayo
2025-12-07 15:58:50 +08:00
17 changed files with 525 additions and 88 deletions

View File

@@ -156,6 +156,24 @@
"contributions": [
"code"
]
},
{
"login": "ctrlz526",
"name": "Ctrlz",
"avatar_url": "https://avatars.githubusercontent.com/u/143257420?v=4",
"profile": "https://github.com/ctrlz526",
"contributions": [
"code"
]
},
{
"login": "flippancy",
"name": "flippancy",
"avatar_url": "https://avatars.githubusercontent.com/u/6467703?v=4",
"profile": "https://github.com/flippancy",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -27,10 +27,11 @@ jobs:
username: xpzouying
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
- name: Build and push Docker image (AMD64)
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
platforms: linux/amd64
tags: |
@@ -38,3 +39,16 @@ jobs:
xpzouying/xiaohongshu-mcp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push Docker image (ARM64)
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.arm64
push: true
platforms: linux/arm64
tags: |
xpzouying/xiaohongshu-mcp:${{ github.event.inputs.version }}-arm64
xpzouying/xiaohongshu-mcp:latest-arm64
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -3,3 +3,5 @@
- 所有的feature变更,都需要使用分支进行开发.
- 在我未同意之前, 你不能推送到远程.
- 我需要: 1.本地 review; 2.远程 PR review.
- 不要过度设计, 保持代码的简洁和易读.
- 使用中文注释,一定要简洁明了.专业名词可以用英文.

94
DONATIONS.md Normal file
View File

@@ -0,0 +1,94 @@
# 赞赏与公益捐赠公开账本
本项目的所有赞赏,将全部用于公益捐赠。
> 本页按月公开记录:收到的赞赏(默认匿名或使用对方指定昵称)、对应捐出、以及捐赠凭证截图(已脱敏)。
> 如需更正/撤回署名,请开 Issue 或通过邮箱联系。
## 摘要
- 累计收到赞赏:¥ 469.78
- 累计捐赠:¥ 600
- 最近更新时间2025-12-04
---
## 维护说明
- **隐私**:默认匿名展示;仅在赞助者明确授权时展示昵称。请在截图中打码/涂抹交易号、手机号、邮箱、二维码关键元素等敏感信息。
- **更正机制**:如有遗漏或需要修改,请开 Issue所有更动保留在 Git 历史中。
---
## 月度明细
### 2025-12
**本月小结**
- 收到赞赏合计:¥ 39.90
- 捐出合计:暂未捐出,将于月底统一捐赠。
**收到的赞赏**
| 日期 | 昵称 | 金额 | 备注 |
|------------|-----:|-----:|------|
| 2025-12-03 | 源 | 39.90 | 微信红包 |
### 2025-11
**本月小结**
- 收到赞赏合计:¥ 249.96
- 捐出合计:¥ 400.00。守望相助,驰援香江:为香港大浦火灾同胞筹集善款!
<img width="594" height="848" alt="PixPin_2025-10-26_21-34-08" src="https://github.com/user-attachments/assets/2dc52a01-d14a-4eec-961f-406f1ef91889" />
**收到的赞赏**
| 日期 | 昵称 | 金额 | 备注 |
|------------|-----:|-----:|------|
| 2025-11-05 | 勇敢的心 | 9.99 | 赞赏码 |
| 2025-11-10 | Sijin Yang | 99.99 | 赞赏码 |
| 2025-11-17 | cym | 29.99 | 赞赏码 |
| 2025-11-26 | 一虎君 | 10.00 | 赞赏码 |
| 2025-11-26 | Sijin Yang | 99.99 | 赞赏码 |
### 2025-10
**本月小结**
- 收到赞赏合计:¥ 109.93
- 捐出合计:¥ 200.00。 9 月、10 月份一起汇总捐赠给「春蕾计划她们想上学」。
<img width="594" height="848" alt="PixPin_2025-10-26_21-34-08" src="https://github.com/user-attachments/assets/8329275c-a328-410e-8744-9bc267661c31" />
**收到的赞赏**
| 日期 | 昵称 | 金额 | 备注 |
|------------|-----:|-----:|------|
| 2025-10-11 | Sijin Yang | 29.99 | 赞赏码 |
| 2025-10-13 | Sijin Yang | 29.99 | 赞赏码 |
| 2025-10-16 | RESOLUTION | 9.99 | 赞赏码 |
| 2025-10-17 | Sijin Yang | 9.99 | 赞赏码 |
| 2025-10-19 | 无名大侠 | 9.99 | 赞赏码 |
| 2025-10-22 | Sijin Yang | 9.99 | 赞赏码 |
| 2025-10-22 | 无名大侠 | 9.99 | 赞赏码 |
### 2025-09
**本月小结**
- 收到赞赏合计:¥ 69.99
- 捐出合计9 月、10 月份一起汇总捐赠给「春蕾计划她们想上学」。
**收到的赞赏**
| 日期 | 昵称 | 金额 | 备注 |
|------------|-----:|-----:|------|
| 2025-09-23 | 米爸 | 50.00 | 微信红包 |
| 2025-09-27 | 麦子 | 19.99 | 赞赏码 |
---
## 变更记录
- 2025-10-26初始化赞赏记录。汇总 2025 年 9 月、10 月份的赞赏,捐赠给「春蕾计划她们想上学」。

88
Dockerfile.arm64 Normal file
View File

@@ -0,0 +1,88 @@
# Dockerfile for ARM64 architecture
# This Dockerfile uses Chromium (auto-downloaded by go-rod) instead of Google Chrome
# because Google Chrome does not provide official Linux ARM64 builds.
# ---- build stage ----
FROM golang:1.24 AS builder
WORKDIR /src
# 配置 Go 模块代理为国内源
ENV GOPROXY=https://goproxy.cn,direct
ENV GOSUMDB=sum.golang.google.cn
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# 移除 GOARCH 硬编码,让构建系统根据目标平台自动选择架构
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /out/app .
# ---- run stage ----
FROM ubuntu:22.04
# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
# 1. 先安装必要工具,然后配置阿里云镜像源
RUN apt-get update && apt-get install -y ca-certificates wget gnupg && \
sed -i 's|http://archive.ubuntu.com|https://mirrors.aliyun.com|g' /etc/apt/sources.list && \
sed -i 's|http://security.ubuntu.com|https://mirrors.aliyun.com|g' /etc/apt/sources.list
# 2. 安装 Chromium 运行所需的依赖库
# 注意:不安装 Google Chrome因为它不支持 ARM64
# go-rod 会在首次运行时自动从 Playwright CDN 下载 ARM64 版本的 Chromium
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
fonts-liberation \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgbm1 \
libgcc1 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libstdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
lsb-release \
wget \
xdg-utils \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /out/app .
# 3. 创建共享目录并设置权限
RUN mkdir -p /app/images && \
chmod 777 /app/images
# 4. 不设置 ROD_BROWSER_BIN 环境变量
# go-rod 会自动检测并下载适合 ARM64 架构的 Chromium 浏览器
# Chromium 下载源https://playwright.azureedge.net/builds/chromium/
EXPOSE 18060
CMD ["./app"]

View File

@@ -1,9 +1,13 @@
# xiaohongshu-mcp
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[![已捐赠](https://img.shields.io/badge/Donated-CNY%20600.00-brightgreen?style=flat-square)](./DONATIONS.md)
[![获得赞赏](https://img.shields.io/badge/Received-CNY%20469.78-blue?style=flat-square)](./DONATIONS.md)
[![Docker Pulls](https://img.shields.io/docker/pulls/xpzouying/xiaohongshu-mcp?style=flat-square&logo=docker)](https://hub.docker.com/r/xpzouying/xiaohongshu-mcp)
MCP for 小红书/xiaohongshu.com。
- 我的博客文章:[haha.ai/xiaohongshu-mcp](https://www.haha.ai/xiaohongshu-mcp)
@@ -16,6 +20,23 @@ MCP for 小红书/xiaohongshu.com。
[![Star History Chart](https://api.star-history.com/svg?repos=xpzouying/xiaohongshu-mcp&type=Timeline)](https://www.star-history.com/#xpzouying/xiaohongshu-mcp&Timeline)
## 赞赏支持
本项目所有的赞赏都会用于慈善捐赠。所有的慈善捐赠记录,请参考 [DONATIONS.md](./DONATIONS.md)。
**捐赠时,请备注 MCP 以及名字。**
如需更正/撤回署名,请开 Issue 或通过邮箱联系。
**支付宝(不展示二维码):**
通过支付宝向 **xpzouying@gmail.com** 赞赏。
**微信:**
<img src="donate/wechat@2x.png" alt="WeChat Pay QR" width="260" />
## 项目简介
**主要功能**
> 💡 **提示:** 点击下方功能标题可展开查看视频演示
@@ -327,6 +348,7 @@ docker build -t xpzouying/xiaohongshu-mcp .
**4. 配置说明**
Docker 版本会自动:
- 配置 Chrome 浏览器和中文字体
- 挂载 `./data` 用于存储 cookies
- 挂载 `./images` 用于存储发布的图片
@@ -717,6 +739,43 @@ Cline 是一个强大的 AI 编程助手,支持 MCP 协议集成。
<img src="./assets/publish_result.jpeg" alt="xiaohongshu-mcp 发布结果" width="300">
### 2.5. 💬 MCP 使用常见问题解答
---
**Q:** 为什么检查登录用户名显示 `xiaghgngshu-mcp`
**A:** 用户名是写死的。
---
**Q:** 显示发布成功后,但实际上没有显示?
**A:** 排查步骤如下:
1. 使用 **非无头模式** 重新发布一次。
2. 更换 **不同的内容** 重新发布。
3. 登录网页版小红书,查看账号是否被 **风控限制网页版发布**。
4. 检查 **图片大小** 是否过大。
5. 确认 **图片路径中没有中文字符**。
6. 若使用网络图片地址,请确认 **图片链接可正常访问**。
---
**Q:** 在设备上运行 MCP 程序出现闪退如何解决?
**A:**
1. 建议 **从源码安装**。
2. 或使用 **Docker 安装 xiaohongshu-mcp**,教程参考:
- [使用 Docker 安装 xiaohongshu-mcp](https://github.com/xpzouying/xiaohongshu-mcp#:~:text=%E6%96%B9%E5%BC%8F%E4%B8%89%EF%BC%9A%E4%BD%BF%E7%94%A8%20Docker%20%E5%AE%B9%E5%99%A8%EF%BC%88%E6%9C%80%E7%AE%80%E5%8D%95%EF%BC%89)
- [X-MCP 项目页面](https://github.com/xpzouying/x-mcp/)
---
**Q:** 使用 `http://localhost:18060/mcp` 进行 MCP 验证时提示无法连接?
**A:**
-**Docker 环境** 下,请使用
👉 [http://host.docker.internal:18060/mcp](http://host.docker.internal:18060/mcp)
-**非 Docker 环境** 下,请使用 **本机 IPv4 地址** 访问。
---
## 3. 🌟 实战案例展示 (Community Showcases)
> 💡 **强烈推荐查看**:这些都是社区贡献者的真实使用案例,包含详细的配置步骤和实战经验!
@@ -736,16 +795,11 @@ Cline 是一个强大的 AI 编程助手,支持 MCP 协议集成。
**重要:在群里问问题之前,请一定要先仔细看完 README 文档以及查看 Issues。**
<!-- 两列排布:飞书二群 | 微信群 -->
| 【飞书3群】:扫码进入 | 【微信群 9 群】:扫码进入 |
| 【飞书 3 群】:扫码进入 | 【微信群 11 群】:扫码进入 |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| <img src="https://github.com/user-attachments/assets/9a0ec41a-cb65-4f4e-a0f7-31658a49512d" alt="qrcode_2qun" width="300"> | <img src="https://github.com/user-attachments/assets/ffddf1f9-3f80-4eb7-9078-5fc357675414" alt="WechatIMG119" width="300"> |
| <img src="https://github.com/user-attachments/assets/9a0ec41a-cb65-4f4e-a0f7-31658a49512d" alt="qrcode_2qun" width="300"> | <img src="https://github.com/user-attachments/assets/29c28520-31a9-42cd-ab80-899c0e0c5742" alt="WechatIMG119" width="300"> |
## 🙏 致谢贡献者 ✨
@@ -778,6 +832,8 @@ Cline 是一个强大的 AI 编程助手,支持 MCP 协议集成。
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://carlo-blog.aiju.fun/"><img src="https://avatars.githubusercontent.com/u/18513362?v=4?s=100" width="100px;" alt="Carlo"/><br /><sub><b>Carlo</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=a67793581" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hrz394943230"><img src="https://avatars.githubusercontent.com/u/28583005?v=4?s=100" width="100px;" alt="hrz"/><br /><sub><b>hrz</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=hrz394943230" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ctrlz526"><img src="https://avatars.githubusercontent.com/u/143257420?v=4?s=100" width="100px;" alt="Ctrlz"/><br /><sub><b>Ctrlz</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=ctrlz526" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/flippancy"><img src="https://avatars.githubusercontent.com/u/6467703?v=4?s=100" width="100px;" alt="flippancy"/><br /><sub><b>flippancy</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=flippancy" title="Code">💻</a></td>
</tr>
</tbody>
</table>
@@ -794,15 +850,3 @@ Cline 是一个强大的 AI 编程助手,支持 MCP 协议集成。
| [<img src="https://avatars.githubusercontent.com/wanpengxie" width="100px;"><br>@wanpengxie](https://github.com/wanpengxie) |
本项目遵循 [all-contributors](https://github.com/all-contributors/all-contributors) 规范。欢迎任何形式的贡献!
## 赞赏支持
欢迎请作者喝杯咖啡~(随缘支持,感谢!)
**支付宝(不展示二维码):**
通过支付宝向 **xpzouying@gmail.com** 赞赏。
**微信:**
<img src="donate/wechat@2x.png" alt="WeChat Pay QR" width="260" />

View File

@@ -1,19 +1,42 @@
# xiaohongshu-mcp
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[![Donated](https://img.shields.io/badge/Donated-CNY%20600.00-brightgreen?style=flat-square)](./DONATIONS.md)
[![Received](https://img.shields.io/badge/Received-CNY%20469.78-blue?style=flat-square)](./DONATIONS.md)
[![Docker Pulls](https://img.shields.io/docker/pulls/xpzouying/xiaohongshu-mcp?style=flat-square&logo=docker)](https://hub.docker.com/r/xpzouying/xiaohongshu-mcp)
MCP for RedNote (Xiaohongshu) platform.
- My blog article: [haha.ai/xiaohongshu-mcp](https://www.haha.ai/xiaohongshu-mcp)
**If you encounter any issues, be sure to check [Common Issues and Solutions](https://github.com/xpzouying/xiaohongshu-mcp/issues/56) first.**
After checking the **Common Issues** list, if you still can't resolve your deployment problems, we strongly recommend using another tool I've created: [xpzouying/x-mcp](https://github.com/xpzouying/x-mcp). This tool doesn't require deployment - you only need a browser extension to drive your MCP, making it more user-friendly for non-technical users.
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=xpzouying/xiaohongshu-mcp&type=Timeline)](https://www.star-history.com/#xpzouying/xiaohongshu-mcp&Timeline)
## Appreciation and Support
All donations received for this project will be used for charitable giving. For all charitable donation records, please refer to [DONATIONS.md](./DONATIONS.md).
**When donating, please note "MCP" and your name.**
If you need to correct/withdraw your name attribution, please open an Issue or contact via email.
**Alipay (QR code not displayed):**
Donate via Alipay to **xpzouying@gmail.com**.
**WeChat:**
<img src="donate/wechat@2x.png" alt="WeChat Pay QR" width="260" />
## Project Overview
**Main Features**
> 💡 **Tip:** Click on the feature titles below to expand and view video demonstrations
@@ -190,9 +213,10 @@ Get RedNote user's personal profile information, including basic user informatio
**RedNote Basic Operation Knowledge**
- **Title: (Very Important) RedNote requires titles to not exceed 20 characters**
- Currently only supports image-text posting: From a recommendation perspective, image-text posts get better traffic than pure text.
- (Low priority) Video and pure text support can be considered. 1. I personally feel these two would greatly increase operation complexity; 2. These two types have low value in my use scenarios.
- Tags: Will be supported soon.
- **Content: (Very Important) Content cannot exceed 1000 characters**
- Currently supports both image-text and video posting: From a recommendation perspective, image-text posts get better traffic than video or pure text.
- (Low priority) Pure text support can be considered. 1. I personally feel pure text would greatly increase operation complexity; 2. Pure text has low value in my use scenarios.
- Tags: Now supported. Adding appropriate tags can bring more traffic.
- According to my practical experience, RedNote should allow **50 posts** per day.
- **(Very Important) RedNote does not allow the same account to login on multiple web platforms**. If you login to the current xiaohongshu-mcp, don't login to that account on other web platforms, otherwise it will "kick out" the current MCP account login. You can use the mobile app to check current account information.
@@ -718,6 +742,8 @@ Use xiaohongshu-mcp's video publishing feature.
1. **[n8n Complete Integration Tutorial](./examples/n8n/README.md)** - Workflow automation platform integration
2. **[Cherry Studio Complete Configuration Tutorial](./examples/cherrystudio/README.md)** - Perfect AI client integration
3. **[Claude Code + Kimi K2 Integration Tutorial](./examples/claude-code/claude-code-kimi-k2.md)** - If Claude Code's barrier is too high, then integrate with Kimi domestic LLM!
4. **[AnythingLLM Complete Guide](./examples/anythingLLM/readme.md)** - AnythingLLM is an all-in-one multimodal AI client that supports workflow definition, multiple LLMs, and plugin extensions.
> 🎯 **Tip**: Click the links above to view detailed step-by-step tutorials for quick setup of various integration solutions!
>
@@ -725,38 +751,13 @@ Use xiaohongshu-mcp's video publishing feature.
## 4. RedNote MCP Community Group
Since the project has just started, there will be many issues. Let's create a group to discuss problems together and contribute to the open source project. ~~Scan my WeChat QR code to join the technical discussion group~~.
**Important: Before asking questions in the group, please make sure to read the README documentation thoroughly and check Issues first.**
Due to too many people adding WeChat, WeChat banned my account for being "in an unsafe network environment." (Not sure if it's because of too many people, possibly triggering WeChat's telecom fraud safety detection. Tried: 1. Real-name verification; 2. Bank card binding; 3. Manual appeal; none worked.)
<!-- Two-column layout: Feishu Group 3 | WeChat Group 10 -->
Switched to Feishu group, scan QR code to join directly
<details>
<summary>【Feishu Group 1】Full</summary>
![1757903591605_副本](https://github.com/user-attachments/assets/63ad53b9-6e5d-4117-ba61-90a223494501)
</details>
<details>
<summary>【WeChat Group 1】Full </summary>
<img src="https://github.com/user-attachments/assets/34c51c3a-d5fd-4086-9d37-a5a5284264c9" alt="WechatIMG119" width="300">
</details>
<details>
<summary>【WeChat Group 2】Full </summary>
<img src="https://github.com/user-attachments/assets/d2c0340c-33e7-4d19-a9f5-cd581b63bd56" alt="WechatIMG119" width="300">
</details>
<!-- Two-column layout: Feishu Group 2 | WeChat Group 3 -->
| 【Feishu Group 2】: Scan to join | 【WeChat Group 3】: Scan to join |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| <img src="https://github.com/user-attachments/assets/ca1f5d6e-b1bf-4c15-9975-ff75f339ec9b" alt="qrcode_2qun" width="300"> | <img src="https://github.com/user-attachments/assets/7665056d-be56-4bf3-a9f3-77f967079929" alt="WechatIMG119" width="300"> |
| 【Feishu Group 3】: Scan to join | 【WeChat Group 10】: Scan to join |
| -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| <img src="https://github.com/user-attachments/assets/9a0ec41a-cb65-4f4e-a0f7-31658a49512d" alt="qrcode_2qun" width="300"> | <img src="https://github.com/user-attachments/assets/a5f8fc69-e37a-4404-a611-4a601ba0b42f" alt="WechatIMG119" width="300"> |
## 🙏 Thanks to Contributors ✨
@@ -774,6 +775,21 @@ Thanks to all friends who have contributed to this project! (In no particular or
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DTDucas"><img src="https://avatars.githubusercontent.com/u/105262836?v=4?s=100" width="100px;" alt="Duong Tran"/><br /><sub><b>Duong Tran</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=DTDucas" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Angiin"><img src="https://avatars.githubusercontent.com/u/17389304?v=4?s=100" width="100px;" alt="Angiin"/><br /><sub><b>Angiin</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=Angiin" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/muhenan"><img src="https://avatars.githubusercontent.com/u/43441941?v=4?s=100" width="100px;" alt="Henan Mu"/><br /><sub><b>Henan Mu</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=muhenan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chengazhen"><img src="https://avatars.githubusercontent.com/u/52627267?v=4?s=100" width="100px;" alt="Journey"/><br /><sub><b>Journey</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=chengazhen" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/eveyuyi"><img src="https://avatars.githubusercontent.com/u/69026872?v=4?s=100" width="100px;" alt="Eve Yu"/><br /><sub><b>Eve Yu</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=eveyuyi" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CooperGuo"><img src="https://avatars.githubusercontent.com/u/183056602?v=4?s=100" width="100px;" alt="CooperGuo"/><br /><sub><b>CooperGuo</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=CooperGuo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://biboyqg.github.io/"><img src="https://avatars.githubusercontent.com/u/125724218?v=4?s=100" width="100px;" alt="Banghao Chi"/><br /><sub><b>Banghao Chi</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=BiboyQG" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/varz1"><img src="https://avatars.githubusercontent.com/u/60377372?v=4?s=100" width="100px;" alt="varz1"/><br /><sub><b>varz1</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=varz1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://google.meloguan.site"><img src="https://avatars.githubusercontent.com/u/62586556?v=4?s=100" width="100px;" alt="Melo Y Guan"/><br /><sub><b>Melo Y Guan</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=Meloyg" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lmxdawn"><img src="https://avatars.githubusercontent.com/u/21293193?v=4?s=100" width="100px;" alt="lmxdawn"/><br /><sub><b>lmxdawn</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=lmxdawn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/haikow"><img src="https://avatars.githubusercontent.com/u/22428382?v=4?s=100" width="100px;" alt="haikow"/><br /><sub><b>haikow</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=haikow" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://carlo-blog.aiju.fun/"><img src="https://avatars.githubusercontent.com/u/18513362?v=4?s=100" width="100px;" alt="Carlo"/><br /><sub><b>Carlo</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=a67793581" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hrz394943230"><img src="https://avatars.githubusercontent.com/u/28583005?v=4?s=100" width="100px;" alt="hrz"/><br /><sub><b>hrz</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=hrz394943230" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ctrlz526"><img src="https://avatars.githubusercontent.com/u/143257420?v=4?s=100" width="100px;" alt="Ctrlz"/><br /><sub><b>Ctrlz</b></sub></a><br /><a href="https://github.com/xpzouying/xiaohongshu-mcp/commits?author=ctrlz526" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -10,6 +10,7 @@ import (
type Cookier interface {
LoadCookies() ([]byte, error)
SaveCookies(data []byte) error
DeleteCookies() error
}
type localCookie struct {
@@ -42,6 +43,15 @@ func (c *localCookie) SaveCookies(data []byte) error {
return os.WriteFile(c.path, data, 0644)
}
// DeleteCookies 删除 cookies 文件。
func (c *localCookie) DeleteCookies() error {
if _, err := os.Stat(c.path); os.IsNotExist(err) {
// 文件不存在,返回 nil认为已经删除
return nil
}
return os.Remove(c.path)
}
// GetCookiesFilePath 获取 cookies 文件路径。
// 为了向后兼容,如果旧路径 /tmp/cookies.json 存在,则继续使用;
// 否则使用当前目录下的 cookies.json

3
go.mod
View File

@@ -11,11 +11,12 @@ require (
github.com/modelcontextprotocol/go-sdk v0.7.0
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.1
github.com/xpzouying/headless_browser v0.2.0
)
require (
github.com/avast/retry-go/v4 v4.7.0 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect

6
go.sum
View File

@@ -1,5 +1,5 @@
github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio=
github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@@ -81,6 +81,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=

View File

@@ -3,6 +3,7 @@ package main
import (
"net/http"
"github.com/xpzouying/xiaohongshu-mcp/cookies"
"github.com/xpzouying/xiaohongshu-mcp/xiaohongshu"
"github.com/gin-gonic/gin"
@@ -63,6 +64,22 @@ func (s *AppServer) getLoginQrcodeHandler(c *gin.Context) {
respondSuccess(c, result, "获取登录二维码成功")
}
// deleteCookiesHandler 删除 cookies重置登录状态
func (s *AppServer) deleteCookiesHandler(c *gin.Context) {
err := s.xiaohongshuService.DeleteCookies(c.Request.Context())
if err != nil {
respondError(c, http.StatusInternalServerError, "DELETE_COOKIES_FAILED",
"删除 cookies 失败", err.Error())
return
}
cookiePath := cookies.GetCookiesFilePath()
respondSuccess(c, map[string]interface{}{
"cookie_path": cookiePath,
"message": "Cookies 已成功删除,登录状态已重置。下次操作时需要重新登录。",
}, "删除 cookies 成功")
}
// publishHandler 发布内容
func (s *AppServer) publishHandler(c *gin.Context) {
var req PublishRequest

View File

@@ -8,7 +8,12 @@ import (
"strings"
"time"
"strconv"
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/xpzouying/xiaohongshu-mcp/cookies"
"github.com/xpzouying/xiaohongshu-mcp/xiaohongshu"
)
@@ -29,7 +34,14 @@ func (s *AppServer) handleCheckLoginStatus(ctx context.Context) *MCPToolResult {
}
}
resultText := fmt.Sprintf("登录状态检查成功: %+v", status)
// 根据 IsLoggedIn 判断并返回友好的提示
var resultText string
if status.IsLoggedIn {
resultText = fmt.Sprintf("✅ 已登录\n用户名: %s\n\n你可以使用其他功能了。", status.Username)
} else {
resultText = fmt.Sprintf("❌ 未登录\n\n请使用 get_login_qrcode 工具获取二维码进行登录。")
}
return &MCPToolResult{
Content: []MCPContent{{
Type: "text",
@@ -78,6 +90,28 @@ func (s *AppServer) handleGetLoginQrcode(ctx context.Context) *MCPToolResult {
return &MCPToolResult{Content: contents}
}
// handleDeleteCookies 处理删除 cookies 请求,用于登录重置
func (s *AppServer) handleDeleteCookies(ctx context.Context) *MCPToolResult {
logrus.Info("MCP: 删除 cookies重置登录状态")
err := s.xiaohongshuService.DeleteCookies(ctx)
if err != nil {
return &MCPToolResult{
Content: []MCPContent{{Type: "text", Text: "删除 cookies 失败: " + err.Error()}},
IsError: true,
}
}
cookiePath := cookies.GetCookiesFilePath()
resultText := fmt.Sprintf("Cookies 已成功删除,登录状态已重置。\n\n删除的文件路径: %s\n\n下次操作时需要重新登录。", cookiePath)
return &MCPToolResult{
Content: []MCPContent{{
Type: "text",
Text: resultText,
}},
}
}
// handlePublishContent 处理发布内容
func (s *AppServer) handlePublishContent(ctx context.Context, args map[string]interface{}) *MCPToolResult {
logrus.Info("MCP: 发布内容")
@@ -367,7 +401,67 @@ func (s *AppServer) handleGetFeedDetail(ctx context.Context, args map[string]any
}
logrus.Infof("MCP: 获取Feed详情 - Feed ID: %s, loadAllComments=%v, config=%+v", feedID, loadAll, config)
loadAll := false
if raw, ok := args["load_all_comments"]; ok {
switch v := raw.(type) {
case bool:
loadAll = v
case string:
if parsed, err := strconv.ParseBool(v); err == nil {
loadAll = parsed
}
case float64:
loadAll = v != 0
}
}
// 解析评论配置参数,如果未提供则使用默认值
config := xiaohongshu.DefaultCommentLoadConfig()
if raw, ok := args["click_more_replies"]; ok {
switch v := raw.(type) {
case bool:
config.ClickMoreReplies = v
case string:
if parsed, err := strconv.ParseBool(v); err == nil {
config.ClickMoreReplies = parsed
}
}
}
if raw, ok := args["max_replies_threshold"]; ok {
switch v := raw.(type) {
case float64:
config.MaxRepliesThreshold = int(v)
case string:
if parsed, err := strconv.Atoi(v); err == nil {
config.MaxRepliesThreshold = parsed
}
case int:
config.MaxRepliesThreshold = v
}
}
if raw, ok := args["max_comment_items"]; ok {
switch v := raw.(type) {
case float64:
config.MaxCommentItems = int(v)
case string:
if parsed, err := strconv.Atoi(v); err == nil {
config.MaxCommentItems = parsed
}
case int:
config.MaxCommentItems = v
}
}
if raw, ok := args["scroll_speed"].(string); ok && raw != "" {
config.ScrollSpeed = raw
}
logrus.Infof("MCP: 获取Feed详情 - Feed ID: %s, loadAllComments=%v, config=%+v", feedID, loadAll, config)
result, err := s.xiaohongshuService.GetFeedDetailWithConfig(ctx, feedID, xsecToken, loadAll, config)
result, err := s.xiaohongshuService.GetFeedDetailWithConfig(ctx, feedID, xsecToken, loadAll, config)
if err != nil {
return &MCPToolResult{

View File

@@ -167,7 +167,19 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 3: 发布内容
// 工具 3: 删除 cookies登录重置
mcp.AddTool(server,
&mcp.Tool{
Name: "delete_cookies",
Description: "删除 cookies 文件,重置登录状态。删除后需要重新登录。",
},
withPanicRecovery("delete_cookies", func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
result := appServer.handleDeleteCookies(ctx)
return convertToMCPResult(result), nil, nil
}),
)
// 工具 4: 发布内容
mcp.AddTool(server,
&mcp.Tool{
Name: "publish_content",
@@ -186,7 +198,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 4: 获取Feed列表
// 工具 5: 获取Feed列表
mcp.AddTool(server,
&mcp.Tool{
Name: "list_feeds",
@@ -198,7 +210,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 5: 搜索内容
// 工具 6: 搜索内容
mcp.AddTool(server,
&mcp.Tool{
Name: "search_feeds",
@@ -210,7 +222,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 6: 获取Feed详情
// 工具 7: 获取Feed详情
mcp.AddTool(server,
&mcp.Tool{
Name: "get_feed_detail",
@@ -225,13 +237,20 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
"max_replies_threshold": args.MaxRepliesThreshold,
"max_comment_items": args.MaxCommentItems,
"scroll_speed": args.ScrollSpeed,
"feed_id": args.FeedID,
"xsec_token": args.XsecToken,
"load_all_comments": args.LoadAllComments,
"click_more_replies": args.ClickMoreReplies,
"max_replies_threshold": args.MaxRepliesThreshold,
"max_comment_items": args.MaxCommentItems,
"scroll_speed": args.ScrollSpeed,
}
result := appServer.handleGetFeedDetail(ctx, argsMap)
return convertToMCPResult(result), nil, nil
}),
)
// 工具 7: 获取用户主页
// 工具 8: 获取用户主页
mcp.AddTool(server,
&mcp.Tool{
Name: "user_profile",
@@ -247,7 +266,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 8: 发表评论
// 工具 9: 发表评论
mcp.AddTool(server,
&mcp.Tool{
Name: "post_comment_to_feed",
@@ -264,7 +283,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 9: 回复评论
// 工具 10: 回复评论
mcp.AddTool(server,
&mcp.Tool{
Name: "reply_comment_in_feed",
@@ -290,7 +309,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
},
)
// 工具 10: 发布视频(仅本地文件)
// 工具 11: 发布视频(仅本地文件)
mcp.AddTool(server,
&mcp.Tool{
Name: "publish_with_video",
@@ -308,7 +327,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 11: 点赞笔记
// 工具 12: 点赞笔记
mcp.AddTool(server,
&mcp.Tool{
Name: "like_feed",
@@ -325,7 +344,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
// 工具 12: 收藏笔记
// 工具 13: 收藏笔记
mcp.AddTool(server,
&mcp.Tool{
Name: "favorite_feed",
@@ -342,7 +361,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
logrus.Infof("Registered %d MCP tools", 11)
logrus.Infof("Registered %d MCP tools", 12)
}
// convertToMCPResult 将自定义的 MCPToolResult 转换为官方 SDK 的格式

View File

@@ -22,29 +22,25 @@ func NewImageProcessor() *ImageProcessor {
// 支持两种输入格式:
// 1. URL格式 (http/https开头) - 自动下载到本地
// 2. 本地文件路径 - 直接使用
// 保持原始图片顺序,如果下载失败直接返回错误
func (p *ImageProcessor) ProcessImages(images []string) ([]string, error) {
var localPaths []string
var urlsToDownload []string
localPaths := make([]string, 0, len(images))
// 分离URL和本地路径
// 按顺序处理每张图片
for _, image := range images {
if IsImageURL(image) {
urlsToDownload = append(urlsToDownload, image)
// URL图片立即下载失败直接返回错误
localPath, err := p.downloader.DownloadImage(image)
if err != nil {
return nil, fmt.Errorf("下载图片失败 %s: %w", image, err)
}
localPaths = append(localPaths, localPath)
} else {
// 本地路径直接添加
// 本地路径直接使用
localPaths = append(localPaths, image)
}
}
// 批量下载URL图片
if len(urlsToDownload) > 0 {
downloadedPaths, err := p.downloader.DownloadImages(urlsToDownload)
if err != nil {
return nil, fmt.Errorf("failed to download images: %w", err)
}
localPaths = append(localPaths, downloadedPaths...)
}
if len(localPaths) == 0 {
return nil, fmt.Errorf("no valid images found")
}

View File

@@ -40,6 +40,7 @@ func setupRoutes(appServer *AppServer) *gin.Engine {
{
api.GET("/login/status", appServer.checkLoginStatusHandler)
api.GET("/login/qrcode", appServer.getLoginQrcodeHandler)
api.DELETE("/login/cookies", appServer.deleteCookiesHandler)
api.POST("/publish", appServer.publishHandler)
api.POST("/publish_video", appServer.publishVideoHandler)
api.GET("/feeds/list", appServer.listFeedsHandler)

View File

@@ -86,6 +86,13 @@ type UserProfileResponse struct {
Feeds []xiaohongshu.Feed `json:"feeds"`
}
// DeleteCookies 删除 cookies 文件,用于登录重置
func (s *XiaohongshuService) DeleteCookies(ctx context.Context) error {
cookiePath := cookies.GetCookiesFilePath()
cookieLoader := cookies.NewLoadCookie(cookiePath)
return cookieLoader.DeleteCookies()
}
// CheckLoginStatus 检查登录状态
func (s *XiaohongshuService) CheckLoginStatus(ctx context.Context) (*LoginStatusResponse, error) {
b := newBrowser()

View File

@@ -46,12 +46,26 @@ type CommentLoadConfig struct {
ScrollSpeed string `json:"scroll_speed,omitempty"`
}
// CommentLoadConfig 评论加载配置
type CommentLoadConfig struct {
// 是否点击"更多回复"按钮
ClickMoreReplies bool `json:"click_more_replies,omitempty"`
// 回复数量阈值,超过这个数量的"更多"按钮将被跳过0表示不跳过任何
MaxRepliesThreshold int `json:"max_replies_threshold,omitempty"`
// 最大加载评论数comment-item数量0表示加载所有
MaxCommentItems int `json:"max_comment_items,omitempty"`
// 滚动速度等级: slow(慢速), normal(正常), fast(快速)
ScrollSpeed string `json:"scroll_speed,omitempty"`
}
// FeedDetailRequest Feed详情请求
type FeedDetailRequest struct {
FeedID string `json:"feed_id" binding:"required"`
XsecToken string `json:"xsec_token" binding:"required"`
LoadAllComments bool `json:"load_all_comments,omitempty"`
CommentConfig *CommentLoadConfig `json:"comment_config,omitempty"`
LoadAllComments bool `json:"load_all_comments,omitempty"`
CommentConfig *CommentLoadConfig `json:"comment_config,omitempty"`
}
type SearchFeedsRequest struct {