How User Login Status Is Managed and Checked in Xiaohongshu-MCP

Xiaohongshu-MCP determines user login status by detecting a specific DOM element on the Xiaohongshu explore page while persisting session cookies to disk for automatic re-authentication across browser instances.

The xpzouying/xiaohongshu-mcp project automates interactions with Xiaohongshu (Little Red Book) through a Model Context Protocol implementation. Understanding how user login status is managed and checked is essential for maintaining persistent sessions across API calls without requiring repeated authentication.

Runtime Login Detection via DOM Inspection

The core mechanism for verifying authentication relies on browser automation using the Rod library to inspect the Xiaohongshu web interface.

When checking authentication state, the system navigates to https://www.xiaohongshu.com/explore and waits for the page to fully load. This URL serves as the entry point for detecting user-specific UI elements that only appear post-authentication.

The Login Indicator Selector

The actual detection occurs by querying for the CSS selector .main-container .user .link-wrapper .channel. This element represents the user avatar and name block in the Xiaohongshu interface, which is only rendered after a successful login.

In xiaohongshu/login.go, the CheckLoginStatus method implements this logic:

// xiaohongshu/login.go – CheckLoginStatus
func (a *LoginAction) CheckLoginStatus(ctx context.Context) (bool, error) {
    pp := a.page.Context(ctx)
    pp.MustNavigate("https://www.xiaohongshu.com/explore").MustWaitLoad()
    time.Sleep(1 * time.Second)

    exists, _, err := pp.Has(`.main-container .user .link-wrapper .channel`) // detection
    if err != nil {
        return false, errors.Wrap(err, "check login status failed")
    }
    if !exists {
        return false, errors.Wrap(err, "login status element not found")
    }
    return true, nil
}

Service Layer Abstraction

The service layer in service.go wraps the login action to provide a clean API response. It initializes a new browser instance (which automatically loads any persisted cookies), creates a page, and delegates to the login action:

// service.go – CheckLoginStatus
func (s *XiaohongshuService) CheckLoginStatus(ctx context.Context) (*LoginStatusResponse, error) {
    b := newBrowser()
    defer b.Close()
    page := b.NewPage()
    defer page.Close()

    loginAction := xiaohongshu.NewLogin(page)
    isLoggedIn, err := loginAction.CheckLoginStatus(ctx) // invokes the DOM check
    // ...
    response := &LoginStatusResponse{IsLoggedIn: isLoggedIn, Username: configs.Username}
    return response, nil
}

QR Code Authentication and Session Establishment

When CheckLoginStatus returns false, the system initiates a QR code login flow that bridges the gap between manual user authentication and automated session persistence.

Generating the Login QR Code

The FetchQrcodeImage method (invoked via GetLoginQrcode in the service layer) generates a QR code image for the user to scan with the Xiaohongshu mobile app.

Polling for Authentication

After presenting the QR code, the system enters a polling loop via WaitForLogin, which checks for the same DOM selector every 500 milliseconds:

// xiaohongshu/login.go – WaitForLogin (polls the same selector)
func (a *LoginAction) WaitForLogin(ctx context.Context) bool {
    pp := a.page.Context(ctx)
    ticker := time.NewTicker(500 * time.Millisecond)
    // ...
    for {
        select {
        case <-ticker.C:
            el, err := pp.Element(".main-container .user .link-wrapper .channel")
            if err == nil && el != nil {
                return true // login succeeded
            }
        }
    }
}

Background Login Monitoring

The service layer launches this polling mechanism in a background goroutine that waits for successful authentication and immediately persists the session:

// service.go – GetLoginQrcode
loginAction := xiaohongshu.NewLogin(page)
img, loggedIn, err := loginAction.FetchQrcodeImage(ctx)
// ...
if !loggedIn {
    go func() {
        ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
        defer cancel()
        if loginAction.WaitForLogin(ctxTimeout) {
            // Persist cookies for later sessions
            _ = saveCookies(page)
        }
    }()
}

Persistent Session Management

To avoid requiring QR code scanning on every request, xiaohongshu-mcp implements cookie-based session persistence that bridges browser instances.

Saving Cookies to Disk

When WaitForLogin detects a successful authentication, the saveCookies helper serializes the browser's cookies to JSON and writes them to a local file:

func saveCookies(page *rod.Page) error {
    cks, err := page.Browser().GetCookies()
    // ...
    data, err := json.Marshal(cks)
    // ...
    cookieLoader := cookies.NewLoadCookie(cookies.GetCookiesFilePath())
    return cookieLoader.SaveCookies(data)
}

Loading Cookies on Browser Startup

Future invocations automatically reuse these cookies because the newBrowser() constructor (implemented in the browser package) loads the persisted cookies from the cookies/ directory when initializing the Rod browser instance. This allows CheckLoginStatus to return true immediately if the cookies are still valid, bypassing the QR code flow.

Invalidating Sessions

A dedicated API endpoint (DELETE /login/cookies) exposes the DeleteCookies method, which removes the persisted cookie file and forces a fresh authentication on the next request:

func (s *XiaohongshuService) DeleteCookies(ctx context.Context) error {
    cookiePath := cookies.GetCookiesFilePath()
    cookieLoader := cookies.NewLoadCookie(cookiePath)
    return cookieLoader.DeleteCookies()
}

Summary

  • DOM-based detection: Login status is determined by checking for the .main-container .user .link-wrapper .channel selector on the Xiaohongshu explore page, which only appears after successful authentication.
  • QR code workflow: Unauthenticated sessions trigger a QR code generation flow with a background goroutine that polls every 500 milliseconds for the login indicator.
  • Cookie persistence: Successful authentications trigger saveCookies to serialize browser cookies to disk, while newBrowser() automatically loads these cookies to maintain sessions across API calls.
  • Session invalidation: The DeleteCookies endpoint removes the stored cookie file, forcing a fresh QR code login on the next status check.

Frequently Asked Questions

How does xiaohongshu-mcp check if a user is logged in?

The system navigates to https://www.xiaohongshu.com/explore and checks for the presence of the CSS selector .main-container .user .link-wrapper .channel using the Rod browser automation library. If this element exists, the CheckLoginStatus function returns true, indicating an active session.

Where are session cookies stored in xiaohongshu-mcp?

Session cookies are persisted to a local file within the cookies/ directory, with the specific path determined by cookies.GetCookiesFilePath(). The saveCookies function in service.go handles the JSON serialization and storage, while the browser package handles automatic loading on startup.

What triggers the background login monitoring process?

When GetLoginQrcode detects that the user is not already logged in (via the loggedIn boolean from FetchQrcodeImage), it launches a background goroutine that calls WaitForLogin. This function polls every 500 milliseconds for the login indicator element, and upon detection, triggers saveCookies to persist the session.

How can I force a new login in xiaohongshu-mcp?

To force re-authentication, call the DELETE /login/cookies endpoint or invoke the DeleteCookies method directly. This removes the persisted cookie file from disk, causing the next CheckLoginStatus call to return false and trigger a new QR code login flow.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →