Skip to main content
Glama
vialan-art

social-search-mcp

by vialan-art
README.md
# social-search-mcp

给 AI agent 用的**社交媒体搜索 MCP 工具集**:X/Twitter + Reddit 两路实时舆情与讨论数据,全部生产环境验证过(2026-07-31 取自运行中的服务)。

一句话:让 agent 能搜推文、搜 Reddit、读完整评论树,**拿回原始数据自己合成观点**——比让搜索引擎替你总结便宜 100 倍,且合成质量更高(能结合你自己的上下文)。

## 目录

- [包含什么](#包含什么)
- [设计哲学](#设计哲学)
- [组件一:x-search(X/Twitter)](#组件一x-searchxtwitter)
- [组件二:reddit-search(Reddit)](#组件二reddit-searchreddit)
- [快速开始](#快速开始)
- [完整部署教程(reddit-search 全链路)](#完整部署教程reddit-search-全链路)
- [MCP 客户端配置](#mcp-客户端配置)
- [成本核算](#成本核算)
- [实测数据](#实测数据)
- [已知坑总表](#已知坑总表)
- [FAQ](#faq)

## 包含什么

```
social-search-mcp/
├── x-search/
│   ├── twitterapi-io.js   # X/Twitter 搜索 MCP(149 行,4 个工具)
│   └── README.md          # 模块级文档
├── reddit-search/
│   ├── reddit.js          # Reddit MCP(87 行,2 个工具)
│   ├── redlib-api.js      # Redlib → JSON API 转换层(242 行,纯 node 零依赖)
│   ├── DEPLOY.md          # Redlib Docker 部署备忘(含全部坑)
│   └── README.md          # 模块级文档
└── package.json           # 唯一依赖:@modelcontextprotocol/sdk
```

| 组件 | 数据源 | 成本 | 需要部署什么 |
|---|---|---|---|
| x-search | [twitterapi.io](https://twitterapi.io)(付费 API) | $0.00015/次搜索 | 什么都不用,填 key 就跑 |
| reddit-search | 自建 [Redlib](https://github.com/redlib-org/redlib) 实例 | **$0** | 一台 VPS 跑 Docker + 一个 node 小服务 |

## 设计哲学

1. **返回原始数据,不替 agent 做总结**。Grok `x_search` 合成一次 $0.02;twitterapi.io 拉原始推文一次 $0.00015——差 100 倍。agent 用自己的模型合成,能结合对话上下文,质量反而更高。
2. **在工具层做质量重排**。搜索引擎的默认排序对 agent 不友好(转推噪音、跨版转载重复、spam)。两个组件都在返回前完成清洗+重排,agent 拿到的第一条就是最高信号。
3. **零依赖或少依赖**。reddit-search 的 API 层是纯 node `http` 模块,一个依赖都不装;MCP 层只依赖 MCP SDK。能跑 node 18+ 就能跑。
4. **每一个设计决策都有实测依据**(见[实测数据](#实测数据)),不是拍脑袋。

---

## 组件一:x-search(X/Twitter)

单文件 MCP stdio server,基于 twitterapi.io 的 REST API。

### 工具清单

| 工具 | 用途 | 关键参数 |
|---|---|---|
| `twitter_search` | 关键词高级搜索(主工具,自带重排清洗) | `query`(支持 operator)、`queryType`(Latest/Top)、`cursor`(翻页)、`raw`(跳过清洗拿原始 JSON) |
| `twitter_user_tweets` | 某用户的时间线 | `userName`、`cursor` |
| `twitter_user_info` | 用户资料(粉丝数/bio/认证状态) | `userName` |
| `twitter_tweet_detail` | 按 ID 批量取推文 | `ids: string[]` |

### query operator 速查

直接写在 `query` 字符串里:

| Operator | 作用 | 示例 |
|---|---|---|
| `min_faves:N` | 至少 N 赞(**中文 query 必加 `min_faves:5`**,否则撞 spam) | `opencode min_faves:5` |
| `lang:en` | 限定语言 | `AI agent lang:en` |
| `from:user` | 某人的推 | `from:karpathy` |
| `since:` / `until:` | 日期范围 | `since:2026-07-01` |
| `within_time:24h` | 最近 N 时间 | `within_time:24h` |
| `"phrase"` | 精确匹配 | `"context window"` |
| `-filter:retweets` | 排除转推(**工具自动加,无需手写**) | — |

### 内部处理管线(每次 `twitter_search` 做了什么)

```
query → 自动追加 -filter:retweets → twitterapi.io advanced_search
  → fmtTweet 字段规整(author/likes/retweets/views/createdAt)
  → engagement 重排:score = 赞 + 转推×2 + 回复 + 引用(降序)
  → cleanTweets 清洗:
      · 剥掉 t.co 短链后取 60 字符指纹去重(近似文本)
      · 丢掉纯链接推(零信息量)
  → 紧凑 markdown 输出(engagement 标注 + 原文链接)
```

为什么转推权重 ×2:转发是比点赞更强的"值得传播"信号。为什么默认排转推:转推没有新观点,是搜索结果里最大的噪音源。

### 适用场景(实测结论)

- **X 强**:实时事件、争议话题、科技圈、政治、产品发布反应
- **X 弱**:生活方式、口味、小众文化(实测"马黛茶"0 命中)→ 别硬调 operator,直接换 reddit-search
- **0 命中 fallback 顺序**:先去 `lang`/引号/`min_faves` 放宽一轮 → 仍 0 则判定 X 不覆盖该话题,换 Reddit

### 已知限制

- **GFW**:`api.twitterapi.io` 从 2026-07 起大陆直连被掐,境内部署需代理层(可用 `TWITTERAPI_IO_BASE` 环境变量指向自己的反代)
- 计费先扣 bonus credits(30 天过期),recharge 永不过期;余额查询 `GET /oapi/my/info`

---

## 组件二:reddit-search(Reddit)

### 为什么必须自建(2026 年 Reddit 生态实测)

| 方案 | 状态(2026-07 实测) |
|---|---|
| 匿名 `.json` API | 🔴 2026-05-30 起全面 403 |
| 官方 OAuth | 🔴 Responsible Builder Policy 后新 app 需人工审批,个人 script 基本不批 |
| GummySearch(第三方 SaaS) | 🔴 2026-12-01 完全关闭 |
| PullPush(pushshift 替代) | 🟡 在线但数据冻结于 2025-05-19 |
| RSS | 🟡 限流约 1 req/60s |
| exa 索引的 reddit | 🔴 实测多次 0 结果 |
| **Redlib(本方案)** | 🟢 **唯一活路** |

Redlib 的原理:模拟 Reddit **官方 Android 客户端**的匿名 OAuth token 访问数据——Reddit 封这个通道等于封掉自家官方 App,所以机制层面极稳定。不绑任何 Reddit 账号,零封号面,也不依赖 VPS 的 IP 信誉。

### 三层架构

```
agent (MCP stdio)
   │  reddit.js —— 薄 wrapper,调 HTTP、格式化 markdown
   ▼
redlib-api (:8091)
   │  redlib-api.js —— 抓 Redlib HTML → 解析成结构化 JSON
   │  附带:跨版去重 + engagement 重排 + 评论树清洗
   ▼
Redlib docker (:8090)
   │  官方匿名 client token 通道
   ▼
Reddit
```

### 工具清单

| 工具 | 用途 | 关键参数 |
|---|---|---|
| `reddit_search` | 全站/单版实时搜索 | `query`、`sub`(限定版块)、`sort`、`t`(时间窗)、`mode`(重排模式,见下)、`limit`(≤25) |
| `reddit_post` | 帖子全文 + 评论树深读 | `path`(reddit URL 或 `/r/...` 路径)、`max_comments`(≤50)、`max_depth`(≤8) |

### 搜索重排公式(redlib-api 的核心价值)

每条帖子的最终分数:

```
rank = W.eng × engagement + W.fresh × freshness + W.rel × relevance − W.div × 版内序号

engagement = ln(1+score) + 1.5 × ln(1+comments)   # 评论权重 1.5 倍:讨论密度比票数更代表信息价值
freshness  = 0.5 ^ (帖龄天数 / 半衰期)
relevance  = 标题命中 query 词数 / query 总词数
```

三种 mode 的权重表:

| mode | eng | fresh | rel | div | 半衰期 | 适用 |
|---|---|---|---|---|---|---|
| `discussion`(默认) | 0.45 | 0.25 | 0.20 | 0.10 | 7 天 | 常规调研,要讨论密度高的帖 |
| `fresh` | 0.25 | 0.45 | 0.20 | 0.10 | 2 天 | 突发事件、新闻 |
| `evergreen` | 0.55 | 0.05 | 0.30 | 0.10 | 365 天 | 经时间考验的 how-to、经验帖 |

另外两道清洗:
- **跨版转载去重**:同一帖子被转到多个版,按标题指纹(前 10 个词)只保留评论数最多的一份
- **版多样性惩罚**:同一版第 N 条结果扣 `0.10×N`,防止结果被一个大版刷屏

### 评论树清洗规则(`reddit_post` 做了什么)

Redlib 的 HTML 里评论树 = `<div class="comment">` + 嵌套 `<blockquote class="replies">`,API 层用 token 流解析出扁平数组 + depth。然后:

1. 过滤 `[deleted]` / `[removed]` / AutoModerator / 负分评论(帖内评论 ≥10 条时)
2. 在 `depth ≤ max_depth` 范围内按 score 选 top `max_comments` 条
3. **OP 的回复永远保留**(楼主追加的上下文价值最高,不受 top N 预算限制)
4. 每条评论正文截断 1500 字符
5. 按原帖顺序输出(不是按分数排),保留对话脉络

### redlib-api HTTP 端点(可脱离 MCP 直接用)

部署好后它就是一个普通 JSON API,curl/任何语言都能调:

```bash
GET /api/health                                    # {"ok":true}
GET /api/search?q=opencode&mode=discussion&limit=10
GET /api/search?q=claude&sub=ClaudeAI&t=week       # 限定版块+时间窗
GET /api/post?path=/r/opencode/comments/xxx/title/&max_comments=15&max_depth=3
```

### 与搜索引擎摘要层的差距(为什么值得)

实测同一话题:tavily 摘要层只能给到"官方说了什么",评论树里有模型用量明细、官方 FAQ 原文引述、用户推导的计费公式——**一手信息全部只在评论区**。这是摘要层结构性拿不到的。

顺带收益:Redlib 网页版本身就是一个无 JS、无广告、无登录墙的 Reddit 前端,手机刷 Reddit 体验极好。

---

## 快速开始

### x-search(2 分钟)

```bash
git clone https://github.com/vialan-art/social-search-mcp.git
cd social-search-mcp
npm install
TWITTERAPI_IO_KEY=你的key node x-search/twitterapi-io.js
```

key 在 [twitterapi.io](https://twitterapi.io) 注册即得,充 $10 够用一年($0.15/1k 推文)。

### reddit-search(只用 MCP,已有 Redlib 实例)

改环境变量指向任何 Redlib 实例(自有或公共):

```bash
npm install
REDLIB_API_BASE=https://你的redlib域名/api node reddit-search/reddit.js
```

注意:`/api` 这层是本仓库的 `redlib-api.js` 提供的,裸 Redlib 没有——所以要么按下面教程部署完整链路,要么把 `reddit.js` 改成直接解析(不推荐)。

---

## 完整部署教程(reddit-search 全链路)

需要:一台境外 VPS(1G 内存即可),一个域名(走 Cloudflare)。

### 第 1 步:部署 Redlib 容器

```bash
# ⚠️ 必须源码构建!quay.io 预构建镜像的匿名 OAuth 已坏(issue #551,2026-04 起)
git clone https://github.com/redlib-org/redlib.git /opt/redlib
cd /opt/redlib

# 1G 内存 VPS 必加这一行到 Dockerfile.ubuntu 构建阶段前,否则 cargo 编译 OOM:
# ENV CARGO_BUILD_JOBS=2
docker build -f Dockerfile.ubuntu -t redlib:local .

# 只绑 localhost,由 nginx 反代出公网
docker run -d --name redlib --restart unless-stopped -p 127.0.0.1:8090:8080 redlib:local
```

### 第 2 步:部署 redlib-api(JSON 转换层)

```bash
mkdir -p /opt/redlib-api
cp reddit-search/redlib-api.js /opt/redlib-api/index.js
```

systemd unit `/etc/systemd/system/redlib-api.service`:

```ini
[Unit]
Description=redlib-api
After=network.target docker.service

[Service]
ExecStart=/usr/bin/node /opt/redlib-api/index.js
Environment=PORT=8091
Environment=REDLIB_BASE=http://127.0.0.1:8090
Restart=always

[Install]
WantedBy=multi-user.target
```

```bash
systemctl enable --now redlib-api
```

### 第 3 步:nginx + 证书

- 域名 A 记录走 Cloudflare 橙云代理
- 证书推荐 **Cloudflare Origin 证书**(15 年有效,CF dashboard → SSL/TLS → Origin Server 生成),CF 端加密模式 Full (strict)。certbot 如果坏了别修 pip,直接换 Origin 证书
- nginx 站点:

```nginx
server {
    listen 443 ssl;
    server_name redlib.你的域名;
    ssl_certificate     /path/to/origin.pem;
    ssl_certificate_key /path/to/origin.key;

    location /api/ { proxy_pass http://127.0.0.1:8091; }
    location /     { proxy_pass http://127.0.0.1:8090; }
}
```

### 第 4 步:验证

```bash
curl https://redlib.你的域名/r/opencode                     # 25 帖列表 HTML
curl "https://redlib.你的域名/api/health"                   # {"ok":true}
curl "https://redlib.你的域名/api/search?q=opencode&limit=5" # 结构化 JSON
```

### 第 5 步:跑 MCP

```bash
REDLIB_API_BASE=https://redlib.你的域名/api node reddit-search/reddit.js
```

---

## MCP 客户端配置

### Claude Code / Claude Desktop(`claude_desktop_config.json` 或 `.mcp.json`)

```json
{
  "mcpServers": {
    "x-search": {
      "command": "node",
      "args": ["/绝对路径/social-search-mcp/x-search/twitterapi-io.js"],
      "env": { "TWITTERAPI_IO_KEY": "你的key" }
    },
    "reddit": {
      "command": "node",
      "args": ["/绝对路径/social-search-mcp/reddit-search/reddit.js"],
      "env": { "REDLIB_API_BASE": "https://redlib.你的域名/api" }
    }
  }
}
```

### opencode(`opencode.json`)

```json
{
  "mcp": {
    "x-search": {
      "type": "local",
      "command": ["node", "/绝对路径/social-search-mcp/x-search/twitterapi-io.js"],
      "environment": { "TWITTERAPI_IO_KEY": "你的key" }
    },
    "reddit": {
      "type": "local",
      "command": ["node", "/绝对路径/social-search-mcp/reddit-search/reddit.js"],
      "environment": { "REDLIB_API_BASE": "https://redlib.你的域名/api" }
    }
  }
}
```

---

## 成本核算

| 项 | 成本 |
|---|---|
| x-search 搜索一次(20 条推文) | $0.00015($0.15/1k 推文) |
| 对比:Grok x_search 合成一次 | $0.02(**贵 133 倍**) |
| twitterapi.io 充值 | $10 ≈ 66k 次搜索,个人用一年 |
| reddit-search 全链路 | **$0**(VPS 是既有的;Redlib 走官方 client 通道不要 key) |
| 对比:Reddit 官方 API | 免费额度 100 req/min 但新 app 审批基本不过 |

## 实测数据

| 测试 | 结果 | 日期 |
|---|---|---|
| x-search 重排 | 20 条返回 engagement 13→8→7→7→6 单调降序,零 RT@ | 2026-07-30 |
| x-search 中文 query 对比 | 中文轮 20 条全 0 互动 spam;英文轮正常讨论 → 中文必加 `min_faves:5` | 2026-07-30 |
| reddit 搜索解析 | 25 帖全部解析正确(标题/分数/评论数/时间) | 2026-07-31 |
| reddit 评论树 | 47 条评论 depth 0-3 嵌套全对,upvote/时间戳/permalink 全保留 | 2026-07-31 |
| reddit vs tavily 摘要 | 评论树含用量明细/FAQ 原文/计费公式推导,摘要层完全没有 | 2026-07-31 |
| X 覆盖弱场景 | "马黛茶" 0 命中(X 无小众生活方式讨论)→ 换 Reddit 正常 | 2026-07-30 |

## 已知坑总表

| 坑 | 解法 |
|---|---|
| twitterapi.io 大陆直连被掐(2026-07 起) | `TWITTERAPI_IO_BASE` 指向代理层 |
| 中文 X 搜索撞 spam | 英文关键词 + `min_faves:5` |
| quay.io Redlib 预构建镜像 OAuth 坏(issue #551) | **必须源码构建** `Dockerfile.ubuntu` |
| 1G 内存构建 Redlib OOM | `ENV CARGO_BUILD_JOBS=2` + 确保有 swap |
| tavily_extract 抓 Redlib 页截断+评论乱序 | 深读用 `reddit_post`,别用通用抓取器 |
| Redlib 上游改模板会导致解析失效 | Docker 锁版本,升级前先测 `/api/search` |
| VPS certbot 坏(pyOpenSSL 冲突) | 别修 pip,换 Cloudflare Origin 证书 |
| 搜 reddit 帖子别用搜索引擎 includeDomains | query 里写 `site:reddit.com` 操作符 |

## FAQ

**Q: 为什么 reddit-search 不用 Reddit 官方 API?**
A: 2025-11 Responsible Builder Policy 后新 app 需人工审批,个人用途基本不批。Redlib 走官方 Android 客户端匿名 token,机制上 Reddit 没法封(封了等于封自家 App),且不用绑账号。

**Q: Redlib 会不会哪天也挂?**
A: 机制风险低(见上)。真正的风险是上游改 HTML 模板导致解析失效——Docker 锁版本、升级前先验证即可。这是 2026 年实测所有方案里唯一稳定在线的。

**Q: 能不能用公共 Redlib 实例不自建?**
A: 可以,把 `REDLIB_API_BASE` 指过去——但公共实例没有 `/api` 这层(那是本仓库的代码),你只能拿到 HTML。要么自己 VPS 部署 `redlib-api.js` 包一层公共实例,要么全套自建。

**Q: 为什么不让工具直接返回 AI 总结?**
A: 见[设计哲学](#设计哲学):原始数据便宜 100 倍,且 agent 结合你的上下文合成质量更高。工具的职责是**取数+清洗+重排**,合成的职责在 agent。

**Q: x-search 和 Grok 的 x_search 怎么分工?**
A: 批量采集、结构化数据、监控场景 → x-search(便宜);要一句话观点合成的轻场景 → Grok。本工具的工具描述里也写了这条分工,agent 会自己选。

## 出处

全部代码取自生产环境(2026-07-31):x-search 来自 search-hub `mcp/twitterapi-io.js`;reddit MCP 来自 `mcp/reddit.js`;redlib-api 来自 VPS `/opt/redlib-api/index.js` 运行中服务。模块考古版见 [search-salvage](https://github.com/vialan-art/search-salvage) 仓库 modules/05 与 06。

Maintenance

ActivitySlowing
ResponsivenessNo issues