How to Publish Content with xiaohongshu-mcp: A Complete Technical Guide
Publishing content with xiaohongshu-mcp involves validating API requests, processing media files, automating a headless Chrome browser with go-rod to interact with Xiaohongshu's creator platform, and submitting posts through either image-text or video workflows.
The xpzouying/xiaohongshu-mcp repository provides a Model Context Protocol (MCP) server and HTTP API that automates publishing to Xiaohongshu (Little Red Book) by orchestrating browser sessions. This guide details the exact steps, source file locations, and code implementations used to publish content programmatically.
API Entry Points and Request Structure
The publishing process begins at the HTTP layer defined in main/handlers_api.go. The system exposes two distinct endpoints for different content types.
Image-Text Publishing Endpoint
The POST /api/v1/publish endpoint handles image-text notes. The publishHandler function (lines 83-101) unmarshals the JSON body into a PublishRequest struct containing title, content, image URLs or paths, tags, and optional scheduling parameters.
Video Publishing Endpoint
The POST /api/v1/publish_video endpoint handles short videos. The publishVideoHandler function (lines 103-121) processes PublishVideoRequest structs, which replace the image array with a single video file path and include the same metadata fields as image posts.
Service Layer Validation and Preparation
Before browser automation begins, main/service.go performs critical validation and resource preparation.
Title Length Validation
The service enforces Xiaohongshu's 20-rune title limit using xhsutil.CalcTitleLength from pkg/xhsutil/title.go. This function counts Unicode runes rather than bytes to properly handle Chinese characters.
Image Processing and Downloading
The processImages function handles both local file paths and remote URLs. For remote resources, it invokes the downloader.ImageProcessor from pkg/downloader/images.go to cache files locally before upload. The system verifies file existence and size constraints before proceeding.
Scheduling Constraints
If the request includes ScheduleAt (ISO-8601 format), the service validates that the timestamp falls within the 1-hour to 14-day window required by Xiaohongshu. Invalid schedules return immediate errors before browser launch.
Browser Automation with go-rod
The core publishing mechanism relies on go-rod, a Go driver for Chrome DevTools Protocol.
Browser Initialization
The newBrowser() function in main/mcp_server.go creates a rod.Browser instance with a temporary user data directory. Each publishing operation receives a fresh browser context to ensure isolation.
b := newBrowser()
defer b.Close()
page := b.NewPage()
defer page.Close()
Navigation and Tab Selection
Both publishing workflows navigate to https://creator.xiaohongshu.com/publish/publish?source=official (defined as urlOfPublic constant). The automation then switches to the appropriate content tab—"上传图文" for images or the video tab for video content—using the mustClickPublishTab helper.
Publishing Workflows
Image-Text Note Publishing
The NewPublishImageAction constructor in xiaohongshu/publish.go (lines 38-67) initializes the image publishing workflow. The Publish method (lines 71-95) executes the following sequence:
- Upload images via uploadImages, which sequentially calls
SetFileson the file input element and waits for preview generation using waitForUploadComplete. - Trim tags to the maximum of 10 allowed by the platform.
- Submit the note via submitPublish (lines 74-124), which:
- Fills title and content fields
- Applies optional setSchedulePublish (toggles switch and sets datetime picker)
- Sets setVisibility via dropdown selection
- Toggles setOriginal and confirms via confirmOriginalDeclaration modal if requested
- Executes bindProducts to search and attach product links
- Clicks the final publish button (
.publish-page-publish-btn button.bg-red)
All DOM interactions include defensive checks such as isElementBlocked, removePopCover, and clickEmptyPosition to handle pop-ups and overlays.
Video Note Publishing
The NewPublishVideoAction constructor in xiaohongshu/publish_video.go (lines 27-53) handles video content. The workflow mirrors image publishing with these differences:
- Single file upload via uploadVideo with a 5-minute timeout
- Publish button polling via waitForPublishButtonClickable to detect when the platform enables the submit button after processing
- Shared submission logic reusing submitPublishVideo which calls the same helper functions for scheduling, visibility, and product binding
Response Handling and Error Management
After successful action.Publish or PublishVideo execution, the service constructs response structs:
// Image response
return &PublishResponse{
Title: req.Title,
Content: req.Content,
Images: len(imagePaths),
Status: "发布完成",
}, nil
// Video response
return &PublishVideoResponse{
Title: req.Title,
Content: req.Content,
Video: req.Video,
Status: "发布完成",
}, nil
Errors propagate using wrapped errors from github.com/pkg/errors. Structured logging via logrus and slog captures execution details. UI automation failures (element timeouts, blocked interactions) return 5xx status codes with machine-readable error identifiers such as PUBLISH_FAILED.
Code Examples
Publishing Images via cURL
curl -X POST http://localhost:8080/api/v1/publish \
-H "Content-Type: application/json" \
-d '{
"title":"我的春季穿搭",
"content":"今天的穿搭分享…",
"images":["https://example.com/img1.jpg","./local/img2.png"],
"tags":["春季","穿搭"],
"visibility":"公开可见",
"is_original":true,
"schedule_at":"2026-04-01T10:00:00Z",
"products":["连衣裙"]
}'
The server downloads remote images, launches a headless Chrome session, and returns:
{
"title":"我的春季穿搭",
"content":"今天的穿搭分享…",
"images":2,
"status":"发布完成"
}
Publishing Video via cURL
curl -X POST http://localhost:8080/api/v1/publish_video \
-H "Content-Type: application/json" \
-d '{
"title":"旅行Vlog",
"content":"在云南的七天行程",
"video":"/home/user/Videos/yn.mp4",
"tags":["旅行","云南"],
"visibility":"仅自己可见"
}'
Direct Go Integration
import (
"context"
"github.com/xpzouying/xiaohongshu-mcp/main/xiaohongshu"
"github.com/xpzouying/xiaohongshu-mcp/main/service"
)
func main() {
svc := service.NewXiaohongshuService() // uses default config
req := &service.PublishRequest{
Title: "手工咖啡教程",
Content: "一步步教你做手冲咖啡",
Images: []string{"./imgs/step1.jpg", "./imgs/step2.jpg"},
}
resp, err := svc.PublishContent(context.Background(), req)
if err != nil {
log.Fatalf("publish failed: %v", err)
}
fmt.Printf("Published, post id: %s\n", resp.Status)
}
Key Source Files Reference
| File | Purpose |
|---|---|
main/handlers_api.go |
HTTP endpoints (publishHandler, publishVideoHandler) and request validation |
main/service.go |
Business logic including validation, image processing, and workflow orchestration |
xiaohongshu/publish.go |
UI automation for image-text notes (NewPublishImageAction, uploadImages, submitPublish) |
xiaohongshu/publish_video.go |
UI automation for video notes (NewPublishVideoAction, uploadVideo) |
pkg/downloader/images.go |
Remote image downloading and local caching (ImageProcessor) |
pkg/xhsutil/title.go |
Unicode-aware title length calculation (CalcTitleLength) |
main/mcp_server.go |
Browser factory (newBrowser) and global configuration |
docs/API.md |
Complete API specification and request/response schemas |
Summary
Publishing content with xiaohongshu-mcp follows a structured pipeline:
- API Layer:
main/handlers_api.goexposes REST endpoints that accept JSON payloads for image-text or video content. - Validation:
main/service.goenforces title length limits (20 runes), downloads remote media viapkg/downloader/images.go, and validates scheduling windows (1 hour to 14 days). - Browser Automation: The system launches headless Chrome via
newBrowser()inmain/mcp_server.go, then usesxiaohongshu/publish.goorxiaohongshu/publish_video.goto navigate the creator platform, upload files, and submit posts. - Optional Features: Supports scheduled publishing, visibility controls (public/private), originality declarations, and product binding through dedicated UI automation helpers.
- Response: Returns structured JSON confirming publication status or detailed error codes for debugging.
Frequently Asked Questions
What authentication method does xiaohongshu-mcp use?
The system operates by automating a logged-in Chrome session rather than using API tokens. You must manually log into Xiaohongshu in the headless browser instance (or use a pre-configured user data directory) before the automation can access publishing features. The newBrowser() function in main/mcp_server.go initializes this browser context.
Can I schedule posts for a specific time in the future?
Yes. Include the schedule_at field in your API request with an ISO-8601 timestamp. The service layer in main/service.go validates that the time falls between 1 hour and 14 days from the current time. The setSchedulePublish function in xiaohongshu/publish.go then toggles the scheduling switch and sets the datetime picker in the browser automation.
How does the system handle remote images versus local files?
The processImages function in main/service.go detects whether image paths are URLs or local filesystem paths. For remote URLs, it invokes the ImageProcessor from pkg/downloader/images.go to download and cache files locally before upload. Local paths are validated for existence and size constraints. All images are then passed as absolute paths to the browser automation for sequential upload via uploadImages.
What happens if the Xiaohongshu UI changes and elements can't be found?
The automation includes defensive programming patterns such as isElementBlocked, removePopCover, and clickEmptyPosition to handle overlays and pop-ups. However, if Xiaohongshu significantly changes DOM selectors, the automation will fail with a PUBLISH_FAILED error code and detailed logs via logrus and slog. You would need to update the selector constants in xiaohongshu/publish.go or xiaohongshu/publish_video.go to match the new UI structure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →