xiaohongshu-mcp-integration

v2026.09.25

MCP server for Xiaohongshu (Little Red Book) - search, publish posts, manage interactions, and automate content operations

GitHub
Install command
npx skhub add reason-machines/xiaohongshu-mcp-integration
Markdown
SKILL.md

xiaohongshu-mcp-integration

Skill by ara.so — MCP Skills collection.

This skill enables AI coding agents to integrate with Xiaohongshu (Little Red Book / 小红书) through an MCP server. It provides capabilities for login management, content publishing (text/image/video), searching, retrieving recommendations, managing interactions (like, favorite, comment), and accessing user profiles.

What It Does

The xiaohongshu-mcp project is a Model Context Protocol (MCP) server that provides programmatic access to Xiaohongshu's platform. It uses browser automation to interact with the platform and exposes tools through the MCP interface.

Core capabilities:

  • Login and session management
  • Publish image posts (up to 20 characters title, 1000 characters content)
  • Publish video posts (local files only)
  • Search content by keywords
  • Get recommendation feed
  • Retrieve post details (including engagement metrics and comments)
  • Post comments and reply to comments
  • Like/unlike posts
  • Favorite/unfavorite posts
  • Get user profile information

Important constraints:

  • Titles must be ≤20 characters
  • Content must be ≤1000 characters
  • Daily posting limit is ~50 posts per account
  • Cannot log in on multiple web sessions simultaneously (mobile app is OK)
  • Requires login before using most features

Installation

Method 1: Pre-compiled Binaries (Recommended)

Download from GitHub Releases:

Main MCP Server:

  • macOS Apple Silicon: xiaohongshu-mcp-darwin-arm64
  • macOS Intel: xiaohongshu-mcp-darwin-amd64
  • Windows x64: xiaohongshu-mcp-windows-amd64.exe
  • Linux x64: xiaohongshu-mcp-linux-amd64

Login Tool:

  • macOS Apple Silicon: xiaohongshu-login-darwin-arm64
  • macOS Intel: xiaohongshu-login-darwin-amd64
  • Windows x64: xiaohongshu-login-windows-amd64.exe
  • Linux x64: xiaohongshu-login-linux-amd64
# 1. First run the login tool
chmod +x xiaohongshu-login-darwin-arm64
./xiaohongshu-login-darwin-arm64

# 2. Start the MCP server
chmod +x xiaohongshu-mcp-darwin-arm64
./xiaohongshu-mcp-darwin-arm64

Note: First run downloads a headless browser (~150MB).

Method 2: Docker

# Pull the image
docker pull xpzouying/xiaohongshu-mcp:latest

# Run the container
docker run -d \
  --name xiaohongshu-mcp \
  -p 8080:8080 \
  -v $(pwd)/data:/app/data \
  xpzouying/xiaohongshu-mcp:latest

Method 3: Build from Source

# Clone the repository
git clone https://github.com/xpzouying/xiaohongshu-mcp.git
cd xiaohongshu-mcp

# Build
go build -o xiaohongshu-mcp ./cmd/mcp
go build -o xiaohongshu-login ./cmd/login

# Run
./xiaohongshu-login  # First time setup
./xiaohongshu-mcp    # Start server

Configuration

The MCP server can be configured for Claude Desktop or other MCP clients:

Claude Desktop Configuration (claude_desktop_config.json):

{
  "mcpServers": {
    "xiaohongshu": {
      "command": "/path/to/xiaohongshu-mcp",
      "args": [],
      "env": {}
    }
  }
}

Environment Variables:

  • XHS_DATA_DIR: Directory for storing session data (default: ./data)
  • XHS_PORT: HTTP server port (default: 8080)
  • XHS_DEBUG: Enable debug logging (default: false)

MCP Tools

1. Login Management

xhs_login: Open login page for manual authentication

{
  "name": "xhs_login",
  "arguments": {}
}

xhs_check_login_status: Check if currently logged in

{
  "name": "xhs_check_login_status",
  "arguments": {}
}

2. Content Publishing

xhs_create_image_note: Publish image post

{
  "name": "xhs_create_image_note",
  "arguments": {
    "title": "美食分享",
    "desc": "今天做的菜真好吃!\n#美食 #家常菜",
    "images": [
      "/Users/username/Pictures/food1.jpg",
      "/Users/username/Pictures/food2.jpg"
    ],
    "post_time": "",
    "privacy": "public",
    "tags": ["美食", "家常菜"]
  }
}

Image sources supported:

  • Local absolute paths (recommended): /path/to/image.jpg
  • HTTP/HTTPS URLs: https://example.com/image.jpg

xhs_create_video_note: Publish video post

{
  "name": "xhs_create_video_note",
  "arguments": {
    "title": "旅行Vlog",
    "desc": "记录美好时光\n#旅行 #Vlog",
    "video": "/Users/username/Videos/trip.mp4",
    "cover": "/Users/username/Videos/cover.jpg",
    "post_time": "",
    "privacy": "public",
    "tags": ["旅行", "Vlog"]
  }
}

Note: Only local video files are supported (no HTTP URLs).

3. Content Discovery

xhs_search: Search for content

{
  "name": "xhs_search",
  "arguments": {
    "keyword": "美食",
    "page": 1,
    "page_size": 20,
    "sort": "general"
  }
}

xhs_get_recommend_feeds: Get recommendation feed

{
  "name": "xhs_get_recommend_feeds",
  "arguments": {
    "page_size": 10
  }
}

xhs_get_note_detail: Get post details with engagement data

{
  "name": "xhs_get_note_detail",
  "arguments": {
    "feed_id": "64f1a2b3c4d5e6f7a8b9c0d1",
    "xsec_token": "ABCdef123456..."
  }
}

Note: feed_id and xsec_token are obtained from search results or feed lists.

4. Interactions

xhs_comment_note: Post a comment

{
  "name": "xhs_comment_note",
  "arguments": {
    "feed_id": "64f1a2b3c4d5e6f7a8b9c0d1",
    "xsec_token": "ABCdef123456...",
    "content": "写得真好!"
  }
}

xhs_reply_comment: Reply to a comment

{
  "name": "xhs_reply_comment",
  "arguments": {
    "feed_id": "64f1a2b3c4d5e6f7a8b9c0d1",
    "xsec_token": "ABCdef123456...",
    "comment_id": "comment_123",
    "content": "谢谢你的支持!"
  }
}

xhs_like_note: Like a post

{
  "name": "xhs_like_note",
  "arguments": {
    "feed_id": "64f1a2b3c4d5e6f7a8b9c0d1",
    "xsec_token": "ABCdef123456...",
    "unlike": false
  }
}

xhs_favorite_note: Favorite a post

{
  "name": "xhs_favorite_note",
  "arguments": {
    "feed_id": "64f1a2b3c4d5e6f7a8b9c0d1",
    "xsec_token": "ABCdef123456...",
    "unfavorite": false
  }
}

5. User Profiles

xhs_get_user_profile: Get user profile and posts

{
  "name": "xhs_get_user_profile",
  "arguments": {
    "user_id": "5f9e8d7c6b5a4e3d2c1b0a9",
    "xsec_token": "ABCdef123456..."
  }
}

Code Examples

Go: Programmatic Usage

package main

import (
    "context"
    "fmt"
    "log"
    
    "github.com/xpzouying/xiaohongshu-mcp/pkg/xhs"
)

func main() {
    // Initialize client
    client, err := xhs.NewClient(xhs.Config{
        DataDir: "./data",
        Debug:   false,
    })
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
    
    ctx := context.Background()
    
    // Check login status
    loggedIn, err := client.CheckLoginStatus(ctx)
    if err != nil {
        log.Fatal(err)
    }
    
    if !loggedIn {
        // Trigger login flow
        if err := client.Login(ctx); err != nil {
            log.Fatal(err)
        }
    }
    
    // Search for content
    results, err := client.Search(ctx, xhs.SearchParams{
        Keyword:  "美食",
        Page:     1,
        PageSize: 10,
    })
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Found %d results\n", len(results.Items))
    
    // Publish an image post
    note, err := client.CreateImageNote(ctx, xhs.ImageNoteParams{
        Title: "美食分享",
        Desc:  "今天做的菜真好吃!\n#美食 #家常菜",
        Images: []string{
            "/path/to/image1.jpg",
            "/path/to/image2.jpg",
        },
        Tags: []string{"美食", "家常菜"},
    })
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Published note: %s\n", note.ID)
    
    // Like a post
    if len(results.Items) > 0 {
        item := results.Items[0]
        err = client.LikeNote(ctx, xhs.LikeParams{
            FeedID:    item.FeedID,
            XsecToken: item.XsecToken,
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Liked post successfully")
    }
}

Go: HTTP API Usage

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    baseURL := "http://localhost:8080"
    
    // Check login status
    resp, err := http.Get(baseURL + "/api/check_login_status")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    var loginStatus struct {
        LoggedIn bool `json:"logged_in"`
    }
    json.NewDecoder(resp.Body).Decode(&loginStatus)
    fmt.Printf("Logged in: %v\n", loginStatus.LoggedIn)
    
    // Search
    searchReq := map[string]interface{}{
        "keyword":   "美食",
        "page":      1,
        "page_size": 10,
    }
    body, _ := json.Marshal(searchReq)
    resp, err = http.Post(
        baseURL+"/api/search",
        "application/json",
        bytes.NewBuffer(body),
    )
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    var searchResult map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&searchResult)
    fmt.Printf("Search results: %+v\n", searchResult)
    
    // Publish image post
    publishReq := map[string]interface{}{
        "title": "美食分享",
        "desc":  "今天做的菜真好吃!\n#美食 #家常菜",
        "images": []string{
            "/path/to/image1.jpg",
            "/path/to/image2.jpg",
        },
        "tags": []string{"美食", "家常菜"},
    }
    body, _ = json.Marshal(publishReq)
    resp, err = http.Post(
        baseURL+"/api/create_image_note",
        "application/json",
        bytes.NewBuffer(body),
    )
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    result, _ := io.ReadAll(resp.Body)
    fmt.Printf("Published: %s\n", result)
}

Python: MCP Client Integration

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    server_params = StdioServerParameters(
        command="/path/to/xiaohongshu-mcp",
        args=[],
        env={}
    )
    
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            
            # Check login status
            result = await session.call_tool(
                "xhs_check_login_status",
                arguments={}
            )
            print(f"Login status: {result}")
            
            # Search
            result = await session.call_tool(
                "xhs_search",
                arguments={
                    "keyword": "美食",
                    "page": 1,
                    "page_size": 10
                }
            )
            print(f"Search results: {result}")
            
            # Publish post
            result = await session.call_tool(
                "xhs_create_image_note",
                arguments={
                    "title": "美食分享",
                    "desc": "今天做的菜真好吃!\n#美食 #家常菜",
                    "images": [
                        "/path/to/image1.jpg",
                        "/path/to/image2.jpg"
                    ],
                    "tags": ["美食", "家常菜"]
                }
            )
            print(f"Published: {result}")

if __name__ == "__main__":
    asyncio.run(main())

Common Patterns

Pattern 1: Content Automation Workflow

// 1. Check login
loggedIn, _ := client.CheckLoginStatus(ctx)
if !loggedIn {
    client.Login(ctx)
}

// 2. Search for trending topics
results, _ := client.Search(ctx, xhs.SearchParams{
    Keyword:  "trending_topic",
    Page:     1,
    PageSize: 20,
})

// 3. Analyze top posts
for _, item := range results.Items[:5] {
    detail, _ := client.GetNoteDetail(ctx, xhs.NoteDetailParams{
        FeedID:    item.FeedID,
        XsecToken: item.XsecToken,
    })
    // Analyze engagement metrics
    fmt.Printf("Likes: %d, Comments: %d\n", 
        detail.LikeCount, detail.CommentCount)
}

// 4. Publish optimized content
client.CreateImageNote(ctx, xhs.ImageNoteParams{
    Title:  "Title ≤20 chars",
    Desc:   "Optimized content based on analysis\n#trending",
    Images: []string{"/path/to/image.jpg"},
    Tags:   []string{"trending", "topic"},
})

Pattern 2: Engagement Automation

// Get recommendations
feeds, _ := client.GetRecommendFeeds(ctx, xhs.FeedParams{
    PageSize: 20,
})

// Engage with relevant content
for _, feed := range feeds.Items {
    // Like posts in your niche
    if isRelevant(feed.Title, feed.Desc) {
        client.LikeNote(ctx, xhs.LikeParams{
            FeedID:    feed.FeedID,
            XsecToken: feed.XsecToken,
        })
        
        // Add thoughtful comment
        client.CommentNote(ctx, xhs.CommentParams{
            FeedID:    feed.FeedID,
            XsecToken: feed.XsecToken,
            Content:   generateComment(feed),
        })
    }
}

Pattern 3: Scheduled Publishing

// Prepare content queue
posts := []xhs.ImageNoteParams{
    {
        Title:  "Morning Post",
        Desc:   "Content 1\n#tag1",
        Images: []string{"/images/1.jpg"},
    },
    {
        Title:  "Evening Post",
        Desc:   "Content 2\n#tag2",
        Images: []string{"/images/2.jpg"},
    },
}

// Schedule publishing (respect 50 posts/day limit)
for i, post := range posts {
    if i >= 50 {
        break // Daily limit
    }
    
    client.CreateImageNote(ctx, post)
    
    // Wait between posts (avoid rate limiting)
    time.Sleep(5 * time.Minute)
}

Troubleshooting

Issue: Login Session Expired

Symptom: API calls return "not logged in" errors

Solution:

// Re-authenticate
err := client.Login(ctx)
if err != nil {
    log.Fatal("Login failed:", err)
}

Issue: Title/Content Length Violations

Symptom: Post creation fails with validation error

Solution:

func validatePost(title, content string) error {
    if len([]rune(title)) > 20 {
        return fmt.Errorf("title too long: %d characters (max 20)", 
            len([]rune(title)))
    }
    if len([]rune(content)) > 1000 {
        return fmt.Errorf("content too long: %d characters (max 1000)", 
            len([]rune(content)))
    }
    return nil
}

Issue: Multiple Web Sessions

Symptom: Account gets logged out unexpectedly

Solution: Ensure only one web session is active. Use mobile app for manual checks while MCP is running.

Issue: Image Upload Fails

Symptom: Image post creation returns error

Solution: Use local absolute paths instead of URLs:

// ❌ Avoid
images := []string{"https://example.com/image.jpg"}

// ✅ Prefer
images := []string{"/Users/username/Pictures/image.jpg"}

Issue: Rate Limiting

Symptom: Actions fail with rate limit errors

Solution: Add delays between operations:

const (
    postDelay    = 5 * time.Minute  // Between posts
    likeDelay    = 2 * time.Second  // Between likes
    commentDelay = 10 * time.Second // Between comments
)

time.Sleep(postDelay)

Issue: Browser Download Fails

Symptom: First run hangs or fails downloading browser

Solution:

  • Ensure stable internet connection
  • Check firewall/proxy settings
  • Manually download browser and set PLAYWRIGHT_BROWSERS_PATH env var

Issue: Account Verification Required

Symptom: Platform requests identity verification

Solution: This is normal for new/unverified accounts. Complete identity verification through the mobile app, then retry.

Best Practices

  1. Respect platform limits: Max 50 posts/day per account
  2. Avoid spam behavior: Add delays between automated actions
  3. Use quality content: Platform penalizes low-quality/duplicate content
  4. Monitor account health: Watch for verification requests or restrictions
  5. Use local files: More reliable than URL-based image/video uploads
  6. Validate content: Check title/content length before posting
  7. Handle errors gracefully: Implement retry logic with exponential backoff
  8. Keep sessions alive: Re-authenticate when sessions expire
  9. Single web session: Don't log in on multiple web browsers simultaneously
  10. Avoid prohibited content: Use content screening tools to check for violations
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.25

Published

Sep 25, 2026

Category

Uncategorized

License

NOASSERTION

Source path

skills/xiaohongshu-mcp-integration

Default branch

main

Latest commit

329e67c

Tree SHA

01fd22f