Answers
How do I run a Xiaohongshu MCP on a cloud server without a browser?
Short answer
Point the agent at a hosted MCP server instead of running Chrome in your container: okdata at https://api.okdata.online/mcp takes an API key in a header and returns Xiaohongshu results as JSON, so the server needs no browser, no display and no login. A search page costs $0.02 and a full note $0.02; failed calls are free.
Take the browser out of the picture. Self-hosted Xiaohongshu MCP servers run a full Chrome inside the container, logged into your account, and that is where cloud deployments go wrong: searches that hang until a 60-second deadline, containers that shut down when idle, a login that has to be redone by QR code, and a datacenter IP that Xiaohongshu treats with more suspicion than a home connection. The project's issue tracker has reports of exactly these. With a hosted server, your machine makes one HTTPS request and gets JSON back. That runs fine on a 1 GB VPS, a cron job in GitHub Actions or a serverless function.
Two ways to wire it
- Your agent speaks MCP. Add
https://api.okdata.online/mcpas a remote server with anAuthorization: Bearerheader. The agent getsfind,describeandcall, and can reach every platform, not only Xiaohongshu. Client configs are on the MCP page. - A scheduled job, no agent. Call the HTTP endpoints directly: Xiaohongshu note search and note detail. The script below is what you would put in cron.
import os, time, uuid, requests
API = "https://api.okdata.online"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
def search(query, sort="latest", tries=3):
key = str(uuid.uuid4()) # same key on every retry: never billed twice
for _ in range(tries):
r = requests.get(API + "/v1/xiaohongshu/notes/search",
headers={**H, "Idempotency-Key": key},
params={"query": query, "sort": sort,
"fields": "id,url,title,metrics.likes,published_at"},
timeout=90)
body = r.json()
if body["code"] == "ok":
return body["data"]["items"]
if body["retry"] in ("yes", "same_key"):
time.sleep(body.get("retry_after_seconds") or 5)
continue
raise RuntimeError(f"{body['code']}: {body['message']}")
raise RuntimeError("gave up")
for note in search("露营装备"):
print(note["metrics"]["likes"], note["title"], note["url"])
What it costs to run on a schedule
| Job | Calls | Cost |
|---|---|---|
| 20 keywords, first page, once a day | 20 a day | $0.40 a day |
| Same job for 30 days | 600 | $12.00 |
| Plus full text of 10 new notes a day for 30 days | 300 | $6.00 |
There is nothing to pay for the server beyond what you already run, since it only waits on HTTP.
Gotchas
- Set your HTTP timeout to 60 seconds or more. Most calls are quicker, but a slow platform response should not be cut off on your side.
- A timeout from us comes back as
timeoutwithcharged: null. Resend with the sameIdempotency-Keyand you will get the stored result or a fresh run, never a second charge. The errors page lists every code. - Watch
X-RateLimit-Remainingif you run many keywords in parallel; arate_limitedreply says how many seconds to wait. - Xiaohongshu hides view counts, so
metrics.viewsis always null.
When to keep the self-hosted MCP
If your agent has to publish notes or reply to comments as your account, the browser-based server is still the tool, and a machine on a home connection tends to behave better than a datacenter VM. Keep it for writing and move reading to an API key. For one-off research by hand, the Xiaohongshu app is still the cheapest way to look.
Updated