MediaCrawler MCP Server
Integrates with Bilibili to search public posts/videos, retrieve specific posts by ID, and fetch creator posts, with optional comment collection and normalized results.
Integrates with Kuaishou to search public content, retrieve specific posts by ID, and fetch creator posts, with optional comment collection and normalized results.
Integrates with Xiaohongshu via Apify to search notes, retrieve note details by ID, URL, or xhslink link, and fetch creator posts, with optional comment collection and normalized results.
Integrates with Zhihu to search public content, retrieve specific posts by ID, and fetch creator posts, with optional comment collection and normalized results.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MediaCrawler MCP ServerSearch Xiaohongshu for recent posts about 露营 and include the comments"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MediaCrawler MCP Server
An MCP (Model Context Protocol) server that wraps the open-source MediaCrawler project so that Claude Code / Codex / Cursor and any other MCP-compatible agent can collect public data from Chinese social platforms through simple tool calls:
小红书 (Xiaohongshu) · 微博 (Weibo) · 抖音 (Douyin) · B站 (Bilibili) · 快手 (Kuaishou) · 贴吧 (Tieba) · 知乎 (Zhihu)
Xiaohongshu uses Apify. Other platforms use MediaCrawler as a black-box CLI: it
patches config just-in-time, runs the crawler, reads the data/ output, and
returns normalised JSON. Anti-ban guardrails are built in (rate limiting, a
machine-wide crawl queue, and optional integration with a shared
risk guard). It works with an unmodified
upstream MediaCrawler checkout.
⚠️ For personal, low-frequency, research use only. MediaCrawler is released under a non-commercial learning license and explicitly forbids commercial use and large-scale scraping. Respect each platform's Terms of Service and robots.txt, keep request rates low, use a secondary account, and never collect private personal data.
Architecture
agent (Claude Code / Codex)
│ MCP tool call
▼
mediacrawler_mcp.server ← this package (guardrails + parsing)
│ patch config/base_config.py + subprocess
▼
MediaCrawler CLI (uv run main.py --platform ... --type ...)
│ writes
▼
<MEDIACRAWLER_HOME>/data/*.json → parsed → normalised JSON back to agentRelated MCP server: content-collect-workbench
Xiaohongshu via Apify
The three content tools route platform="xhs" to memo23/xiaohongshu-all-in-one-scraper.
Set APIFY_TOKEN in the MCP environment or save the token alone in
~/.config/mediacrawler/apify-token.txt (mode 0600). The file is read on each call.
login_status().xhs reports whether a token is present. This backend runs without CDP.
The default per-run charge limit is USD 2, configurable via MEDIACRAWLER_APIFY_MAX_USD.
With comments enabled it requests up to 10 root comments per note and 5 replies per root.
Read replies_incomplete on root comments for identified gaps. Search returns the text from
the search row. Detail opens the note. Raw dataset rows are saved under data/xhs/apify/<run_id>/.
Exposed MCP tools
Tool | Purpose | Key args |
| Keyword search on a platform |
|
| Fetch specific posts by id (for xhs: note IDs, URLs or xhslink.com links) |
|
| Fetch a creator's posts |
|
| Check config + cached login session (+ xhs risk guard) | – |
| Request budget used and whether crawling is paused after a captcha |
|
| Capability matrix | – |
|
| – |
All content tools return:
{
"ok": true,
"platform": "xhs",
"count": 12,
"items": [
{
"id": "...", "author": "...", "author_id": "...",
"content": "...", "like_count": 42, "comment_count": 3,
"publish_time": "...", "url": "...",
"comments": [ { "...": "raw comment record" } ],
"raw": { "...": "original MediaCrawler record" }
}
],
"raw_files": ["/path/to/data/xhs/....json"],
"warnings": []
}How to read ok after a crawl:
Result | Meaning |
| The crawl exited with an error or timed out and saved nothing. The reason is in |
| The crawl stopped the same way but saved some results, for example when the risk guard ended it midway. The items are returned and the reason is in |
| The crawl finished without finding anything. Check |
diagnostics returns ok: false and error: "startup_failed" when
main.py --help fails. login_status only checks configuration, so its ok
does not show whether MediaCrawler can start.
Prerequisites
Clone MediaCrawler and install its dependencies (it requires Python 3.11,
uv, and Node.js ≥ 16 for some platforms):git clone https://github.com/NanmiCoder/MediaCrawler cd MediaCrawler uv sync # optional (only for standard Playwright mode): uv run playwright installThis server needs the official
mcpSDK:pip install --user "mcp>=1.2.0,<2" # or, from this folder: pip install --user -e .
CDP mode (strongly recommended — lowers ban risk)
MediaCrawler's default CDP mode connects to your own already-logged-in Chrome, reusing its cookies and session, which greatly reduces risk-control detection:
Install the latest Chrome (≥ 144).
Visit
chrome://inspect/#remote-debuggingand enable "Allow remote debugging for this browser instance" (should reportServer running at: 127.0.0.1:9222).Keep
MEDIACRAWLER_ENABLE_CDP=true(default).On first crawl, Chrome shows a confirmation dialog — click "accept" within 60s.
If you prefer standard mode, set MEDIACRAWLER_ENABLE_CDP=false; you will then
log in via QR code on first run.
Configuration
All settings come from environment variables (see .env.example).
The only required one is MEDIACRAWLER_HOME.
Var | Default | Meaning |
|
| Path to the cloned repo (must contain |
|
|
|
|
|
|
|
| Output format (json recommended) |
|
| Items per call when unspecified |
|
| Absolute cap; larger requests clamped |
|
| Random delay window (s) |
|
| Max tool calls per window |
|
| Rate-limit window (s) |
|
| Collect comments by default (each note's comments cost logged-in requests) |
|
| Reuse your logged-in Chrome |
|
| Enable MediaCrawler's proxy pool |
|
| Per-run subprocess timeout (s); the risk guard paces requests 10–30 s apart |
|
| How long a crawl may wait for the ones ahead of it (s) |
|
| Where the optional risk guard keeps its shared state |
Register with an MCP client
Claude Code (CLI)
claude mcp add mediacrawler \
--env MEDIACRAWLER_HOME=/path/to/MediaCrawler \
--env PYTHONPATH=/path/to/mediacrawler-mcp \
-- python -m mediacrawler_mcp.serverClaude Desktop / Cursor (JSON)
See examples/claude_desktop_config.snippet.json
and paste it into your client's MCP config, fixing the two absolute paths.
Quick test
# 1. unit tests (no network, no CLI)
pip install --user pytest
PYTHONPATH=. pytest -q
# 2. end-to-end (actually runs MediaCrawler — log in first!)
export MEDIACRAWLER_HOME=/path/to/MediaCrawler
python examples/quickstart.pyAsk your agent, e.g.:
"用 mediacrawler 搜索小红书上关于『城市露营』的 10 条笔记并带上评论"
How it passes parameters (important)
MediaCrawler reads keywords / specified post-ids / creator-ids from
config/base_config.py, not reliably from CLI flags. So before each run this
server temporarily patches base_config.py (setting KEYWORDS,
*_SPECIFIED_ID_LIST, *_CREATOR_ID_LIST, CRAWLER_MAX_NOTES_COUNT,
ENABLE_GET_COMMENTS, ENABLE_CDP_MODE, …) and restores the original file
afterwards, byte for byte. This keeps the server working across MediaCrawler
versions without forking it.
If MediaCrawler changes its argument names, run the diagnostics tool to see the
current main.py --help, then adjust mediacrawler_mcp/runner.py.
One crawl at a time
Every MCP server process on this machine shares one MediaCrawler checkout: one
config/base_config.py, one debug Chrome, and one result file per platform, type
and day, which MediaCrawler rewrites whole for each item. So crawls queue on a
machine-wide lock, <MEDIACRAWLER_GUARD_DIR>/crawl.lock, and a tool call simply
takes longer while it waits. queue_wait_seconds in the result says how long.
Scope: the lock covers
search_posts,get_post_detailandget_creator_posts.uv run main.pyby hand and other tools that drive the same Chrome do not take it.Breaker: the risk guard is checked again once a crawl reaches the front, since the crawl ahead may have tripped it.
Server killed mid-crawl: the crawler inherits the lock, so the queue waits for it to finish. The original config stays in
<MEDIACRAWLER_GUARD_DIR>/base_config.py.runningfor the length of a run, and the next crawl restores from it if the server never got to.Timeout: the whole process group is stopped, because
uv runkeeps Python as a child and killinguvalone would leave the crawl running.Results:
itemsholds only what this call crawled. The record counts of the per-day files are taken before the crawl and compared after it, inside the lock.raw_fileslists those per-day files, which also hold every earlier crawl of the day.Logs: the crawler's output goes to temporary files. Playwright's Node driver makes the stderr it inherits non-blocking, which on a pipe cuts long log lines mid-character and drops later ones. Any invalid UTF-8 left in the output is shown as U+FFFD.
Code changes reach a server only when that process restarts, and a server still on code from before this lock neither queues nor respects it.
Troubleshooting
Symptom | Likely cause / fix |
|
|
|
|
| Login session expired → run |
| You hit the local guard; wait, or raise |
| Other crawls held the queue past |
warning "could not attach to the debug Chrome" | MediaCrawler fell back to its own browser profile, without the debug Chrome's login. The warning quotes the reason; check that Chrome is running with |
| The platform answered with a captcha / risk code; every project is paused until |
warning "stopped early because of its risk guard" | The budget ran out ( |
warning "login session was not accepted" (xhs) | The platform rejected the browser session. Check that Chrome is logged in, or use the Apify backend for xhs |
Optional risk guard integration
This server can cooperate with a cross-process risk guard running inside
MediaCrawler, i.e. a component that paces every request, counts them against
shared hourly/daily budgets, and opens a circuit breaker when the platform
answers with a captcha or risk-control code. No such guard ships with
upstream MediaCrawler or with this repository; if you add one, have it write
its state to <MEDIACRAWLER_GUARD_DIR>/<platform>.json:
{ "tripped_until": 1767225600, "trip_reason": "captcha HTTP 461",
"requests": { "account": [1767220000.0], "anon": [], "media": [] },
"history": [] }When that file exists, the server:
checks the breaker before launching MediaCrawler and returns
risk_guard_trippedwithretry_after_secondsinstead of crawling;reports the request budget used in
risk_status/login_status;recognises the guard's log markers (
RiskControlTripped,BudgetExhausted,LoginRequired,[RiskGuard]) and returns partial results with a warning.
Without the file, these checks are no-ops and everything else works as usual.
Safety & compliance
Personal, low-frequency, non-commercial research only.
Use a secondary account; prefer CDP mode + proxies; keep counts small.
Do not collect private personal data or anything behind auth you don't own.
You are responsible for complying with platform ToS and applicable law. See MediaCrawler's disclaimer and 记录爬虫违法违规案例.
License
The code in this repository is released under the MIT License. It does not include any MediaCrawler code; it runs MediaCrawler as an external program. MediaCrawler itself is distributed under its own NON-COMMERCIAL LEARNING LICENSE 1.1, which you must accept and comply with when you install and run it.
Available Tools
7 toolsdiagnostics
Return MediaCrawler --help output and effective settings for debugging.
ok is false, with error "startup_failed", when MediaCrawler cannot start.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
get_creator_posts
Fetch posts from one or more creators' home pages.
Args: platform: one of xhs, dy, ks, bili, wb, tieba, zhihu. creator_ids: list of creator ids (or profile URLs for tieba/zhihu). max_count: max posts per creator (default from config, hard-capped).
Browser platforms queue behind other local browser crawls. XHS uses Apify.
| Name | Required | Description | Default |
|---|---|---|---|
| platform | Yes | ||
| max_count | No | ||
| creator_ids | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
get_post_detail
Fetch specific posts by their platform id(s), with optional comments.
Args: platform: one of xhs, dy, ks, bili, wb, tieba, zhihu. post_ids: platform-native IDs. XHS accepts note IDs, ordinary note URLs and xhslink.com links. with_comments: include comments (default from config).
Browser platforms queue behind other local browser crawls. XHS uses Apify.
| Name | Required | Description | Default |
|---|---|---|---|
| platform | Yes | ||
| post_ids | Yes | ||
| with_comments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
list_platforms
List supported platforms and the capability matrix.
Returns platform codes, human-readable names, and which crawl types each supports. All platforms support search / detail / creator per MediaCrawler.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
login_status
Report configuration health and login guidance.
MediaCrawler caches login sessions in a browser context. This tool cannot silently re-login; instead it validates configuration and tells you when a manual QR-code scan is likely required.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
risk_status
Show MediaCrawler's risk guard for a platform: request budget used and whether crawling is paused after a captcha / risk-control signal. Check this before planning a large crawl; the guard is shared by every process using the same MediaCrawler checkout.
| Name | Required | Description | Default |
|---|---|---|---|
| platform | No | xhs |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
search_posts
Keyword-search a platform and return matching public posts (+comments).
Args: platform: one of xhs, dy, ks, bili, wb, tieba, zhihu. keywords: search query. Multiple keywords may be comma-separated. max_count: max posts to fetch (default from config, hard-capped). with_comments: include comments (default from config). sort: optional sort hint (platform-dependent; may be ignored).
Returns a dict: {ok, platform, count, items:[{id, author, content, like_count, comment_count, publish_time, url, comments?}], raw_files, warnings}. items holds only what this call crawled; raw_files are MediaCrawler's per-day files, which also hold every earlier crawl of that day.
Browser crawls run one at a time across every project on this machine, so this call first waits for any crawl ahead of it (queue_wait_seconds says how long). If that wait outlasts MEDIACRAWLER_QUEUE_TIMEOUT, ok is false and error is "queue_timeout".
If the crawl fails and saves nothing, ok is false, error is "crawl_failed" and details gives the reason. If it stops after saving some results, ok stays true with partial: true and the reason in warnings. ok: true with count 0 means the crawl finished without finding anything; check warnings.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | ||
| keywords | Yes | ||
| platform | Yes | ||
| max_count | No | ||
| with_comments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.1.0- First observed
diagnostics - First observed
get_creator_posts - First observed
get_post_detail - First observed
list_platforms - First observed
login_status - First observed
risk_status - First observed
search_posts
Related MCP Connectors
Public data from 20+ platforms, including Douyin, Xiaohongshu, Weibo and TikTok, as structured JSON
Scrape X, Reddit, LinkedIn, GitHub, Instagram and TikTok data as tools for AI agents.
Unified social scraper MCP — profiles, posts, videos across ~40 platforms via Streamable HTTP.
Schedule and publish social posts across 9 platforms (Instagram, LinkedIn, X, TikTok, Facebook, Threads, Pinterest, Bluesky, Mastodon) straight from Claude, ChatGPT, Cursor, or any MCP client. Create, edit, and reschedule posts, upload media, and pull account and post analytics, follower demographics, and best-time windows. 20 tools, free on every plan.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to crawl and extract data from Chinese social media platforms like Bilibili, Xiaohongshu, and Douyin. Provides search, content detail retrieval, and creator information tools with persistent browser sessions and QR code login support.79-
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to collect and localize content from WeChat, Douyin, Kuaishou, Xiaohongshu, and Bilibili, with 47 MCP tools for fetching articles, parsing media, and managing a unified local content library.1-
- AlicenseAqualityBmaintenanceEnables agents to search and read posts, images, and limited comments across Xiaohongshu, Weibo, Zhihu, and WeChat Official Accounts, with local OCR and traceable sources.73MIT

ProLevelMax MCPofficial
AlicenseNot gradedqualityCmaintenanceEnables AI agents and developers to discover, inspect, run, and schedule live public social media data collection from 157 platforms, including Reddit, TikTok, Instagram, X, YouTube, Xiaohongshu, and Douyin. It supports previews, cost quotes, async runs, and download links via remote MCP, an Agent Skill, or REST API.MIT