diff --git a/README.md b/README.md index e7e1f5f..007c891 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ # Social MCP -Multi-platform social media automation service that exposes browser-based actions as both MCP (Model Context Protocol) tools and a REST API. Currently supports **Xiaohongshu** (Little Red Book). +[中文文档](./README.zh-CN.md) + +Multi-platform social media automation service that exposes browser-based actions as both MCP (Model Context Protocol) tools and a REST API. Current platform support: **Xiaohongshu** (Little Red Book). ## Features -- **13 MCP tools** for Xiaohongshu: login management, content browsing, publishing, and interactions -- **REST API** with Bearer token authentication and rate limiting -- **Browser automation** via rebrowser-playwright with anti-detection patches -- **Cookie persistence** with file-based storage (0600 permissions, atomic writes) -- **Security**: DNS rebinding protection, Host header validation, error message sanitization, log redaction -- **Docker support** with hardened configuration (non-root user, read-only filesystem, resource limits) -- **Plugin architecture** for adding new platforms +- **17 MCP tools** for Xiaohongshu (login, browsing, publishing, interactions, notifications) +- **REST API** with Bearer token authentication and per-route rate limiting +- **Browser automation** via `rebrowser-playwright` with per-platform serial queueing +- **Cookie persistence** with file-based storage (`0600`, atomic writes) +- **Web dashboard** (React + Vite) for login, feed exploration, publishing, and API testing +- **Security controls**: timing-safe token comparison, bind-address safety gate, error sanitization, log redaction +- **Docker deployment** support with hardened runtime defaults +- **Plugin architecture** for adding additional social platforms ## Quick Start @@ -19,34 +22,48 @@ Multi-platform social media automation service that exposes browser-based action - Node.js >= 22.0.0 - pnpm -### Install and Run +### Install and Run (Backend) ```bash # Install dependencies pnpm install -# Install Playwright browsers (first time only) +# Install Playwright browser (first time only) npx playwright install chromium -# Build +# Build backend pnpm build -# Start the server +# Start server pnpm start ``` -The server starts on `http://127.0.0.1:3000` by default. A REST API Bearer token is printed to the console on first startup and saved to `~/.social-mcp/.api-token`. +The server listens on `http://127.0.0.1:9527` by default in local mode. +A REST API Bearer token is printed on startup and persisted at `~/.social-mcp/.api-token`. + +### Build With Web Dashboard + +```bash +# Build backend + web dashboard bundle +pnpm build:all + +# Start server (serves dashboard from /) +pnpm start +``` ### Development ```bash -# Watch mode (rebuilds on file changes) +# Backend watch build pnpm dev -# Type check without emitting +# Frontend dev server +pnpm dev:web + +# Type check pnpm lint -# Run tests +# Tests pnpm test ``` @@ -54,19 +71,19 @@ pnpm test ### Claude Desktop -Add the following to your Claude Desktop configuration file (`claude_desktop_config.json`): +Add this in `claude_desktop_config.json`: ```json { "mcpServers": { "social-mcp": { - "url": "http://127.0.0.1:3000/sse" + "url": "http://127.0.0.1:9527/sse" } } } ``` -### Available MCP Tools +### Available MCP Tools (Xiaohongshu) | Tool | Description | |------|-------------| @@ -75,60 +92,76 @@ Add the following to your Claude Desktop configuration file (`claude_desktop_con | `xhs_delete_cookies` | Delete cookies and reset login session | | `xhs_list_feeds` | Get explore page recommended feed list | | `xhs_search` | Search notes by keyword with filters | -| `xhs_get_feed_detail` | Get note detail with content, images, stats, comments | -| `xhs_get_user_profile` | Get user profile with bio, stats, recent notes | +| `xhs_get_feed_detail` | Get note detail (content/media/stats/comments) | +| `xhs_get_sub_comments` | Load all sub-comments for a parent comment | +| `xhs_get_user_profile` | Get user profile with recent notes | +| `xhs_list_my_notes` | List current account's published notes | | `xhs_publish_image` | Publish an image note | | `xhs_publish_video` | Publish a video note | | `xhs_post_comment` | Post a comment on a note | | `xhs_reply_comment` | Reply to a comment | -| `xhs_like` | Like or unlike a note | -| `xhs_favorite` | Favorite or unfavorite a note | +| `xhs_like` | Toggle like state on a note | +| `xhs_favorite` | Toggle favorite state on a note | +| `xhs_get_comment_notifications` | Get unread comment/@ notifications | +| `xhs_reply_notification` | Reply to a specific notification | ## REST API -All REST endpoints require a `Bearer` token in the `Authorization` header. The token is generated on first startup and printed to the console. +All `/api/*` endpoints require: + +- `Authorization: Bearer ` +- `Content-Type: application/json` (for POST bodies) + +Example: ```bash -# Example: check login status -curl -H "Authorization: Bearer " http://127.0.0.1:3000/api/xhs/login/status +# Login status +curl -H "Authorization: Bearer " \ + http://127.0.0.1:9527/api/xhs/login/status -# Example: search notes -curl -X POST -H "Authorization: Bearer " \ +# Search notes +curl -X POST \ + -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ - -d '{"keyword": "travel", "filters": {"sort": "popularity_descending"}}' \ - http://127.0.0.1:3000/api/xhs/search + -d '{"keyword":"travel","filters":{"sort":"popularity_descending"}}' \ + http://127.0.0.1:9527/api/xhs/search ``` -### Endpoints +### Endpoint List -| Method | Path | Description | Rate Limit | -|--------|------|-------------|------------| +Read endpoints are limited to **60/min** per IP. Write endpoints are limited to **10/min** per IP. + +| Method | Path | Description | Limit | +|--------|------|-------------|-------| | `GET` | `/api/xhs/login/status` | Check login status | 60/min | | `GET` | `/api/xhs/login/qrcode` | Get login QR code | 60/min | | `DELETE` | `/api/xhs/login/cookies` | Delete cookies | 10/min | +| `GET` | `/api/xhs/login/cookie-check` | Check whether cookie file exists | 60/min | | `GET` | `/api/xhs/feeds` | Get recommended feeds | 60/min | | `POST` | `/api/xhs/search` | Search notes | 60/min | | `POST` | `/api/xhs/feeds/detail` | Get note detail | 60/min | +| `POST` | `/api/xhs/feeds/sub-comments` | Load sub-comments for parent comment | 60/min | | `POST` | `/api/xhs/user/profile` | Get user profile | 60/min | +| `GET` | `/api/xhs/my-notes` | List my published notes | 60/min | | `POST` | `/api/xhs/publish/image` | Publish image note | 10/min | | `POST` | `/api/xhs/publish/video` | Publish video note | 10/min | | `POST` | `/api/xhs/comment` | Post a comment | 10/min | | `POST` | `/api/xhs/comment/reply` | Reply to a comment | 10/min | -| `POST` | `/api/xhs/like` | Like/unlike a note | 10/min | -| `POST` | `/api/xhs/favorite` | Favorite/unfavorite a note | 10/min | +| `POST` | `/api/xhs/like` | Toggle like | 10/min | +| `POST` | `/api/xhs/favorite` | Toggle favorite | 10/min | +| `GET` | `/api/xhs/notifications/comments` | Get comment notifications | 60/min | +| `POST` | `/api/xhs/notifications/reply` | Reply to notification | 10/min | ### Response Format -All REST responses follow a consistent JSON format: - ```json -// Success { "success": true, - "data": { ... } + "data": {} } +``` -// Error +```json { "success": false, "error": { @@ -138,17 +171,17 @@ All REST responses follow a consistent JSON format: } ``` -### Other Endpoints (no auth required) +### Public Endpoints (No Bearer Token) | Method | Path | Description | |--------|------|-------------| -| `GET` | `/health` | Health check (memory, uptime, plugin status) | +| `GET` | `/health` | Health check (uptime/memory/plugin status) | | `GET` | `/sse` | MCP SSE transport | -| `POST` | `/messages` | MCP JSON-RPC messages | +| `POST` | `/messages` | MCP JSON-RPC message endpoint | ## Docker Deployment -### Using Docker Compose (recommended) +### Using Compose (Recommended) ```bash cd deploy @@ -157,17 +190,15 @@ docker compose up -d # View logs docker compose logs -f -# The API token is printed in the logs on first start +# Find Bearer token in logs docker compose logs social-mcp | grep "Bearer Token" ``` -### Using Docker directly +### Docker Run ```bash -# Build the image docker build -t social-mcp . -# Run with required settings docker run -d \ --name social-mcp \ -p 127.0.0.1:3000:3000 \ @@ -182,64 +213,60 @@ docker run -d \ social-mcp ``` -**Important**: The `--shm-size=1gb` flag is required. Chromium uses `/dev/shm` for shared memory and the default 64MB causes crashes. +Note: Docker defaults expose port `3000` because container env sets `PORT=3000`. ## Environment Variables -| Variable | Default | Description | -|----------|---------|-------------| -| `PORT` | `3000` | HTTP server port | +| Variable | Default (local) | Description | +|----------|------------------|-------------| +| `PORT` | `9527` | HTTP server port | | `HOST` | `127.0.0.1` | Bind address (`0.0.0.0` requires `ALLOW_REMOTE`) | | `HEADLESS` | `true` | Run browser in headless mode | | `BROWSER_BIN` | (auto) | Custom Chromium executable path | | `LOG_LEVEL` | `info` | Pino log level (`debug`, `info`, `warn`, `error`) | -| `NODE_ENV` | `development` | Environment (`production` disables pretty logs) | -| `COOKIE_DIR` | `~/.social-mcp` | Directory for cookie and token storage | +| `NODE_ENV` | `development` | Runtime environment | +| `COOKIE_DIR` | `~/.social-mcp` | Cookie/token storage directory | | `MAX_QUEUE_DEPTH` | `10` | Max pending operations per platform queue | -| `ALLOW_REMOTE` | (unset) | Set to `yes-i-understand-the-risk` to allow `HOST=0.0.0.0` | +| `ALLOW_REMOTE` | (unset) | Must be `yes-i-understand-the-risk` to allow public bind | ## Project Structure -``` +```text social-mcp/ -├── package.json -├── tsconfig.json -├── tsup.config.ts -├── Dockerfile -├── deploy/ -│ └── docker-compose.yml ├── src/ -│ ├── index.ts # Entry point: bootstrap, plugin registration, graceful shutdown +│ ├── index.ts │ ├── server/ -│ │ ├── app.ts # AppServer: Express + MCP lifecycle -│ │ └── middleware.ts # DNS rebinding guard, bearer auth, rate limiter, error handler +│ │ ├── app.ts +│ │ └── middleware.ts │ ├── browser/ -│ │ └── manager.ts # BrowserManager: browser lifecycle, serial queues, backpressure +│ │ └── manager.ts │ ├── cookie/ -│ │ └── store.ts # CookieStore: per-platform cookie persistence (0600, atomic writes) +│ │ └── store.ts │ ├── config/ -│ │ └── index.ts # Environment-based configuration +│ │ └── index.ts │ ├── utils/ -│ │ ├── logger.ts # Pino logger with deep redaction -│ │ ├── errors.ts # Error classification, sanitization, MCP error wrapper -│ │ └── downloader.ts # Media file download and path validation +│ │ ├── logger.ts +│ │ ├── errors.ts +│ │ └── downloader.ts │ └── platforms/ │ └── xiaohongshu/ -│ ├── index.ts # PlatformPlugin: MCP tool + REST route registration -│ ├── routes.ts # REST API route handlers -│ ├── schemas.ts # Zod schemas for tool/API parameter validation -│ ├── types.ts # Domain types (Feed, Comment, UserProfile, etc.) -│ ├── selectors.ts # CSS selector constants -│ ├── login.ts # Login management (QR code, status check) -│ ├── feeds.ts # Explore page feed extraction -│ ├── search.ts # Search with filters -│ ├── feed-detail.ts # Note detail + comment loading -│ ├── user-profile.ts # User profile extraction -│ ├── publish.ts # Image note publishing -│ ├── publish-video.ts # Video note publishing -│ ├── comment.ts # Comment and reply posting -│ └── interaction.ts # Like and favorite toggling -└── tests/ +│ ├── index.ts +│ ├── routes.ts +│ ├── schemas.ts +│ ├── selectors.ts +│ ├── login.ts +│ ├── feeds.ts +│ ├── search.ts +│ ├── feed-detail.ts +│ ├── user-profile.ts +│ ├── my-notes.ts +│ ├── publish.ts +│ ├── publish-video.ts +│ ├── comment.ts +│ ├── interaction.ts +│ └── notification.ts +└── web/ + └── src/ ``` ## License diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..9f65e82 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,275 @@ +# Social MCP + +[English README](./README.md) + +一个面向社交媒体自动化的服务,既提供 MCP(Model Context Protocol)工具能力,也提供 REST API。当前支持平台:**小红书**。 + +## 功能特性 + +- 小红书 **17 个 MCP 工具**(登录、浏览、发布、互动、通知) +- 带 Bearer Token 鉴权与按路由限流的 REST API +- 基于 `rebrowser-playwright` 的浏览器自动化,按平台串行队列执行 +- 文件型 Cookie 持久化(`0600` 权限、原子写入) +- Web 控制台(React + Vite):登录、内容浏览、发布、接口测试 +- 安全控制:Token 常量时间比对、绑定地址安全门、错误信息脱敏、日志字段脱敏 +- 支持 Docker 部署 +- 插件化平台架构,便于扩展更多平台 + +## 快速开始 + +### 前置要求 + +- Node.js >= 22.0.0 +- pnpm + +### 安装与运行(后端) + +```bash +# 安装依赖 +pnpm install + +# 首次安装 Playwright Chromium +npx playwright install chromium + +# 构建后端 +pnpm build + +# 启动服务 +pnpm start +``` + +本地默认监听地址:`http://127.0.0.1:9527`。 +首次启动会在控制台打印 REST API Bearer Token,并保存到 `~/.social-mcp/.api-token`。 + +### 构建并启用 Web 控制台 + +```bash +# 构建后端 + 前端 +pnpm build:all + +# 启动服务(会同时托管 dashboard) +pnpm start +``` + +### 开发命令 + +```bash +# 后端 watch 构建 +pnpm dev + +# 前端开发服务器 +pnpm dev:web + +# 类型检查 +pnpm lint + +# 测试 +pnpm test +``` + +## MCP 集成 + +### Claude Desktop + +在 `claude_desktop_config.json` 中添加: + +```json +{ + "mcpServers": { + "social-mcp": { + "url": "http://127.0.0.1:9527/sse" + } + } +} +``` + +### MCP 工具列表(小红书) + +| 工具名 | 说明 | +|------|------| +| `xhs_check_login` | 检查登录状态 | +| `xhs_get_login_qrcode` | 获取扫码登录二维码 | +| `xhs_delete_cookies` | 删除 Cookie 并重置登录状态 | +| `xhs_list_feeds` | 获取推荐流 | +| `xhs_search` | 关键词搜索笔记(支持筛选) | +| `xhs_get_feed_detail` | 获取笔记详情(内容/媒体/统计/评论) | +| `xhs_get_sub_comments` | 拉取某条父评论的完整子评论 | +| `xhs_get_user_profile` | 获取用户主页及近期笔记 | +| `xhs_list_my_notes` | 获取当前账号已发布笔记列表 | +| `xhs_publish_image` | 发布图文笔记 | +| `xhs_publish_video` | 发布视频笔记 | +| `xhs_post_comment` | 发表评论 | +| `xhs_reply_comment` | 回复评论 | +| `xhs_like` | 切换点赞状态 | +| `xhs_favorite` | 切换收藏状态 | +| `xhs_get_comment_notifications` | 获取未读评论/@通知 | +| `xhs_reply_notification` | 对通知进行回复 | + +## REST API + +所有 `/api/*` 接口都需要: + +- `Authorization: Bearer ` +- `POST` 请求需设置 `Content-Type: application/json` + +示例: + +```bash +# 查询登录状态 +curl -H "Authorization: Bearer " \ + http://127.0.0.1:9527/api/xhs/login/status + +# 搜索笔记 +curl -X POST \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"keyword":"travel","filters":{"sort":"popularity_descending"}}' \ + http://127.0.0.1:9527/api/xhs/search +``` + +### 接口清单 + +读接口限流:**60/min**(按 IP) +写接口限流:**10/min**(按 IP) + +| 方法 | 路径 | 说明 | 限流 | +|------|------|------|------| +| `GET` | `/api/xhs/login/status` | 检查登录状态 | 60/min | +| `GET` | `/api/xhs/login/qrcode` | 获取二维码 | 60/min | +| `DELETE` | `/api/xhs/login/cookies` | 删除 Cookie | 10/min | +| `GET` | `/api/xhs/login/cookie-check` | 检查本地 Cookie 文件是否存在 | 60/min | +| `GET` | `/api/xhs/feeds` | 获取推荐流 | 60/min | +| `POST` | `/api/xhs/search` | 搜索笔记 | 60/min | +| `POST` | `/api/xhs/feeds/detail` | 获取笔记详情 | 60/min | +| `POST` | `/api/xhs/feeds/sub-comments` | 拉取子评论 | 60/min | +| `POST` | `/api/xhs/user/profile` | 获取用户主页 | 60/min | +| `GET` | `/api/xhs/my-notes` | 获取我的笔记 | 60/min | +| `POST` | `/api/xhs/publish/image` | 发布图文 | 10/min | +| `POST` | `/api/xhs/publish/video` | 发布视频 | 10/min | +| `POST` | `/api/xhs/comment` | 发表评论 | 10/min | +| `POST` | `/api/xhs/comment/reply` | 回复评论 | 10/min | +| `POST` | `/api/xhs/like` | 点赞切换 | 10/min | +| `POST` | `/api/xhs/favorite` | 收藏切换 | 10/min | +| `GET` | `/api/xhs/notifications/comments` | 获取评论通知 | 60/min | +| `POST` | `/api/xhs/notifications/reply` | 回复通知 | 10/min | + +### 返回格式 + +```json +{ + "success": true, + "data": {} +} +``` + +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "keyword: Required" + } +} +``` + +### 公开接口(无需鉴权) + +| 方法 | 路径 | 说明 | +|------|------|------| +| `GET` | `/health` | 健康检查(运行时长/内存/插件状态) | +| `GET` | `/sse` | MCP SSE 连接入口 | +| `POST` | `/messages` | MCP JSON-RPC 消息入口 | + +## Docker 部署 + +### 使用 Compose(推荐) + +```bash +cd deploy +docker compose up -d + +# 查看日志 +docker compose logs -f + +# 查找 Bearer Token +docker compose logs social-mcp | grep "Bearer Token" +``` + +### 直接运行 Docker + +```bash +docker build -t social-mcp . + +docker run -d \ + --name social-mcp \ + -p 127.0.0.1:3000:3000 \ + --shm-size=1gb \ + --memory=2g \ + --cpus=2.0 \ + --security-opt=no-new-privileges:true \ + --cap-drop=ALL \ + --read-only \ + --tmpfs /tmp:size=512m \ + -v social-mcp-data:/home/appuser/.social-mcp \ + social-mcp +``` + +说明:Docker 镜像默认使用 `PORT=3000`。 + +## 环境变量 + +| 变量 | 默认值(本地) | 说明 | +|------|----------------|------| +| `PORT` | `9527` | HTTP 监听端口 | +| `HOST` | `127.0.0.1` | 绑定地址(`0.0.0.0` 需设置 `ALLOW_REMOTE`) | +| `HEADLESS` | `true` | 是否无头运行浏览器 | +| `BROWSER_BIN` | 自动探测 | 自定义 Chromium 路径 | +| `LOG_LEVEL` | `info` | 日志级别(`debug`/`info`/`warn`/`error`) | +| `NODE_ENV` | `development` | 运行环境 | +| `COOKIE_DIR` | `~/.social-mcp` | Cookie/Token 存储目录 | +| `MAX_QUEUE_DEPTH` | `10` | 单平台最大排队深度 | +| `ALLOW_REMOTE` | 空 | 仅当值为 `yes-i-understand-the-risk` 时允许公网绑定 | + +## 项目结构 + +```text +social-mcp/ +├── src/ +│ ├── index.ts +│ ├── server/ +│ │ ├── app.ts +│ │ └── middleware.ts +│ ├── browser/ +│ │ └── manager.ts +│ ├── cookie/ +│ │ └── store.ts +│ ├── config/ +│ │ └── index.ts +│ ├── utils/ +│ │ ├── logger.ts +│ │ ├── errors.ts +│ │ └── downloader.ts +│ └── platforms/ +│ └── xiaohongshu/ +│ ├── index.ts +│ ├── routes.ts +│ ├── schemas.ts +│ ├── selectors.ts +│ ├── login.ts +│ ├── feeds.ts +│ ├── search.ts +│ ├── feed-detail.ts +│ ├── user-profile.ts +│ ├── my-notes.ts +│ ├── publish.ts +│ ├── publish-video.ts +│ ├── comment.ts +│ ├── interaction.ts +│ └── notification.ts +└── web/ + └── src/ +``` + +## License + +ISC