Metadata-Version: 2.5
Name: bili_stalker_mcp
Version: 3.5.0
Summary: Bilibili MCP server for analyzing specific Bilibili users, with profile, video, dynamic, article, subtitle, and following tools
Project-URL: Homepage, https://github.com/222wcnm/BiliStalkerMCP
Project-URL: Documentation, https://github.com/222wcnm/BiliStalkerMCP#readme
Project-URL: Repository, https://github.com/222wcnm/BiliStalkerMCP
Project-URL: Issues, https://github.com/222wcnm/BiliStalkerMCP/issues
Project-URL: Changelog, https://github.com/222wcnm/BiliStalkerMCP/releases
Author-email: 222wcnm <2328072813li@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: bilibili,creator-analysis,dynamics,fastmcp,mcp,mcp-server,model-context-protocol,subtitles,user-analysis,video
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Communications
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.12
Requires-Dist: async-lru>=2.0.4
Requires-Dist: bilibili-api-python==17.4.2
Requires-Dist: curl-cffi>=0.7.0
Requires-Dist: fastmcp>=3.0.0
Requires-Dist: filelock==3.29.7
Requires-Dist: httpx>=0.25.0
Requires-Dist: mcp>=1.26.0
Requires-Dist: pydantic>=2.7.0
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: flake8>=6.0.0; extra == 'dev'
Requires-Dist: isort>=5.12.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# BiliStalkerMCP

[![Python](https://img.shields.io/badge/Python-3.12+-blue?logo=python)](https://www.python.org/)
[![MCP](https://img.shields.io/badge/MCP-Compatible-orange)](https://github.com/jlowin/fastmcp)
[![PyPI version](https://badge.fury.io/py/bili-stalker-mcp.svg)](https://pypi.org/project/bili-stalker-mcp/)

## Bilibili MCP Server for Specific User Analysis

BiliStalkerMCP is a Bilibili MCP server built on [Model Context Protocol (MCP)](https://modelcontextprotocol.io), designed for AI agents that need to analyze a specific Bilibili user or creator.

It is optimized for workflows that start from a target uid or username, then retrieve that user's profile, videos, dynamics, articles, subtitles, and followings with structured tools.

If you are searching for a Bilibili MCP server, a Bilibili Model Context Protocol server, or an MCP server for tracking and analyzing a specific Bilibili user, this repository is designed for that use case.

**English | [中文说明](README_zh.md)**

### Installation

```bash
uvx bili-stalker-mcp
# or
pip install bili-stalker-mcp
```

### Configuration (Claude Desktop, Recommended)

```json
{
  "mcpServers": {
    "bilistalker": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/BiliStalkerMCP", "bili-stalker-mcp"],
      "env": {
        "SESSDATA": "required_sessdata",
        "BILI_JCT": "optional_jct",
        "BUVID3": "optional_buvid3"
      }
    }
  }
}
```

> Prefer `uv run --directory ...` for faster local updates when PyPI release propagation is delayed.
> You can still use `uvx bili-stalker-mcp` for quick one-off usage.

> **Auth**: Provide `SESSDATA` directly, or put it in `BILI_COOKIE_FILE`. Obtain it from Browser DevTools (F12) > Application > Cookies > `.bilibili.com`.

### Environment Variables

| Key | Req | Description |
|-----|:---:|-------------|
| `SESSDATA` | Conditional | Bilibili session token; required unless `BILI_COOKIE_FILE` provides it. |
| `BILI_JCT` | No | CSRF protection token. |
| `BUVID3` | No | Hardware fingerprint (reduces rate-limiting risk). |
| `BILI_COOKIE_FILE` | No | Path to a plain Cookie file. |
| `BILI_REFRESH_TOKEN_FILE` | No | Path to the separate refresh-token file; never set the token through an environment variable. |
| `BILI_ENABLE_COOKIE_REFRESH` | No | `true` enables safe automatic refresh; default: `false`. |
| `BILI_COOKIE_REFRESH_CHECK_INTERVAL_SECONDS` | No | Refresh-check interval; default: `21600`, minimum: `60`. |
| `BILI_PROXY` | No | Route all upstream requests (bilibili_api and the built-in HTTP clients) through this proxy. Recommended when the system proxy is not picked up automatically or DNS resolution for Bilibili hosts is unstable. If the proxy is unreachable at startup, the server falls back to direct connections and logs a warning. |
| `BILI_REQUEST_JITTER_MODE` | No | Upstream jitter behavior: `adaptive` (default; sleeps only without a configured login or after recent 412/429/403), `always`, `never`. |
| `BILI_REQUEST_JITTER_MIN_MS` / `BILI_REQUEST_JITTER_MAX_MS` | No | Jitter sleep range; default: `200`–`1200`. |
| `BILI_REQUEST_JITTER_BUDGET_MS` | No | Total jitter sleep allowed per tool call; default: `500`. |
| `BILI_RISK_PRESSURE_WINDOW_SECONDS` | No | How long a 412/429/403 keeps adaptive jitter engaged; default: `300`. |
| `BILI_LOG_LEVEL` | No | `DEBUG`, `INFO` (Default), `WARNING`. |
| `BILI_TIMEZONE` | No | Output time zone for formatted timestamps (default: `Asia/Shanghai`). |

### Optional Safe Cookie Refresh

Automatic refresh is disabled by default. Enable it only when the Cookie file and
refresh-token file are existing, readable, writable regular files. The Cookie file
may contain only ordinary Cookie values (`SESSDATA`, `bili_jct`, `buvid3`,
`buvid4`, and `DedeUserID`); the refresh token belongs only in its own file.

```json
{
  "BILI_COOKIE_FILE": "/secure/bilibili-cookie.txt",
  "BILI_REFRESH_TOKEN_FILE": "/secure/bilibili-refresh-token.txt",
  "BILI_ENABLE_COOKIE_REFRESH": "true",
  "BILI_COOKIE_REFRESH_CHECK_INTERVAL_SECONDS": "21600"
}
```

When refresh is enabled, do not set `SESSDATA`, `BILI_JCT`, or `DEDEUSERID` in
the environment: those rotating values must come from the Cookie file so a restart
cannot reload stale credentials. `BUVID3` and `BUVID4` may still be provided through
the environment. Refresh checks are rate-limited, and concurrent MCP calls or server
processes sharing these files use one refresh lock. Pending confirmation is recovered
before another refresh. The `.bili-cookie-refresh.lock` sidecar may remain on disk
between runs.

For a quicker initial setup, copy the complete Cookie header value from a Bilibili
browser request and `ac_time_value` from Local Storage, then run:

```powershell
uv run bili-stalker-cookie-setup --directory D:\BiliStalkerSecrets
```

For a PyPI-only invocation without cloning this repository:

```powershell
uvx --from bili-stalker-mcp bili-stalker-cookie-setup --directory D:\BiliStalkerSecrets
```

The script hides both pasted values, refuses directories inside the repository and
existing credential files, and prints only a non-secret MCP `env` block. Do not
paste an entire cURL command: paste only the value after its `cookie:` header.

### Local Verification

All verification commands use mocks and do not require Bilibili credentials:

```powershell
uv run pytest -q tests/test_credentials.py tests/test_cookie_refresh.py tests/test_tool_contract.py
uv run pytest -q
uv run black --check bili_stalker_mcp tests scripts
uv run isort --check-only bili_stalker_mcp tests scripts
uv run flake8 bili_stalker_mcp tests scripts
uv run mypy bili_stalker_mcp
```

## Available Tools

| Tool | Capability | Parameters |
|------|------------|------------|
| `search_users` | Lightweight user candidates with numeric UIDs | `keyword`, `limit` |
| `get_user_snapshot` | One-call overview: profile + recent videos/dynamics/articles fetched concurrently | `user_id_or_username`, `video_limit`, `dynamic_limit`, `article_limit` (0 skips a section) |
| `get_user_info` | Rich profile: level, official title, VIP, live room, ban status, following/follower, total video views/article views/likes (needs `bili_jct`) | `user_id_or_username` |
| `get_user_videos` | Lightweight video list | `user_id_or_username`, `page`, `limit` |
| `search_user_videos` | Keyword search in one user's video list | `user_id_or_username`, `keyword`, `page`, `limit` |
| `get_video_detail` | Full video detail + optional subtitles | `bvid`, `fetch_subtitles` (default: `false`), `subtitle_mode` (`smart`/`full`/`minimal`), `subtitle_lang` (default: `auto`), `subtitle_max_chars` |
| `get_user_dynamics` | Structured dynamics with image metadata and cursor pagination | `user_id_or_username`, `cursor`, `limit`, `dynamic_type` |
| `get_user_articles` | Lightweight article list | `user_id_or_username`, `page`, `limit` |
| `get_article_content` | Full article markdown content | `article_id` |
| `get_user_followings` | Subscription list analysis | `user_id_or_username`, `page`, `limit` |
| `get_content_comments` | Comments for a video, article, or dynamic (including images and note metadata) | `content_type`, `content_id`, `cursor`, `limit`, `sort` |
| `get_content_comment_replies` | Full sub-replies for a video, article, or dynamic comment | `content_type`, `content_id`, `root_rpid`, `page`, `limit` |

When starting from a username, call `search_users` once and reuse the returned numeric
UID for subsequent tools. Implicit username resolution accepts exact matches only; it
does not silently select the first similar search result.

Comment `pictures` contain the original image URLs. Regular long comments retain the
full text returned by Bilibili. Note-style comments may contain only a preview; use
the returned `note.cvid` with `get_article_content` to retrieve the full note.
For video comments, pass `content_type="video"` and a BVID, AV number, or video URL
as `content_id`. Use a top-level comment's `rpid` as `root_rpid` when fetching its
complete reply thread.

### Dynamic Filtering (`dynamic_type`)

- `ALL` (default): Text, Draw, Reposts, and Video dynamics.
- `ALL_RAW`: Unfiltered (additionally includes Articles and unknown types).
- `VIDEO`, `ARTICLE`, `DRAW`, `TEXT`: Specific category filtering.
- `REVIEW`: Recognized five-slot rating cards only. Each result exposes
  `review.rating` (filled stars, 0-5), `review.title`, `review.text`, cover and
  jump URLs, plus the source score description when available. This filter does
  not independently classify whether the rated title is an anime.

Each dynamic item includes an `images` list. Every image contains `url`, `width`,
and `height`; invalid URLs are omitted, and unavailable dimensions are `null`.
`image_count` always equals the number of returned images. Reposts expose the same
fields under `origin.images` and `origin.image_count`. Non-image dynamics return
an empty `images` list.

**Pagination**: Responses include `next_cursor`. Pass this to subsequent requests for seamless scrolling.

### Subtitle Modes (`get_video_detail`)

- `smart` (default when `fetch_subtitles=true`): fetch metadata for all pages, download only one best-matched subtitle track text.
- `full`: download text for all subtitle tracks (higher cost).
- `minimal`: skip subtitle metadata and subtitle text fetching.

`subtitle_lang` can force a language (for example `en-US`); `auto` uses built-in priority fallback.  
`subtitle_max_chars` caps returned subtitle text size to avoid token explosion.

Subtitle text is returned once via `full_text`; `tracks` carry metadata only
(`text` is always empty). In `full` mode with multiple tracks, each segment in
`full_text` is prefixed with a `[language · part]` label.

## Bundled Skill

The repository ships a ready-to-use AI agent skill in `skills/bili-content-analysis/`:

```
skills/bili-content-analysis/
├── SKILL.md                        # Workflow & output contract
└── references/
    └── analysis-style.md           # Detailed writing style rules
```

### What It Does

Guides compatible AI agents (Gemini, Claude, etc.) through a structured 6-step workflow for deep Bilibili content analysis:

1. **Clarify** target and scope (uid / bvid / keyword).
2. **Collect** evidence — lightweight lists first, heavy detail only for high-value items.
3. **Reconstruct** source structure before interpreting (timeline, chapters, speakers).
4. **Analyze** — facts, logic chain, assumptions, themes, and shifts.
5. **Retain anchors** — uid, bvid, article_id, timestamps, key source snippets.
6. **Handle failures** — state blockers explicitly, stop speculation.

### Usage

Copy the `bili-content-analysis` folder into your project's skill directory:

```
<project>/.agent/skills/bili-content-analysis/
```

The agent will automatically activate the skill when user requests involve Bilibili creator tracking, transcript interpretation, timeline reconstruction, or content analysis.

## Development

```bash
# Setup
git clone https://github.com/222wcnm/BiliStalkerMCP.git
cd BiliStalkerMCP
uv sync --dev

# Test
uv run pytest -q

# Integration & Performance (Requires Auth)
uv run python scripts/integration_suite.py -u <UID>
uv run python scripts/perf_baseline.py -u <UID> --tools dynamics -n 3
```

## Release (Maintainers)

> **Credentials**: The release script uses `UV_PUBLISH_TOKEN` when set; otherwise it reads the matching `[pypi]` or `[testpypi]` token from `$HOME\.pypirc`.
> Twine is invoked transiently through `uvx` only for package metadata validation and is not a project dependency.

```powershell
# Build + test + package metadata validation (no upload)
.\scripts\pypi_release.ps1

# Upload to TestPyPI
.\scripts\pypi_release.ps1 -TestPyPI -Upload

# Upload to PyPI
.\scripts\pypi_release.ps1 -Upload
```

## Docker

Runs via `stdio` transport. No ports exposed.

```bash
docker build -t bilistalker-mcp .
docker run -e SESSDATA=... bilistalker-mcp
```

## Troubleshooting

- **412 Precondition Failed**: Bilibili anti-crawling system triggered. Refresh `SESSDATA` or provide `BUVID3`.
- **Cloud IPs**: Highly susceptible to blocking; local execution is recommended.
- **Long ~20s stalls or DNS timeouts on upstream calls**: configure `BILI_PROXY`. `bilibili_api`'s curl_cffi client ignores system and environment proxies unless an explicit proxy is set.

## Upstream Dependency Note

`bilibili-api-python` is pinned to `==17.4.2`. Its upstream repository has been
permanently shut down following a legal notice from Bilibili, so no further
maintenance or fixes can be expected from that project. Additionally, the
package is licensed GPL-3.0-or-later, which means its source **cannot be
vendored or forked into this MIT-licensed repository**.

The mitigation path is incremental migration of the remaining SDK-backed
endpoints (user info, video list/details, dynamics, articles) onto this
project's own raw HTTP stack (`SharedRawHttpClient`), which already serves
comments, followings, and relation stats independently of the SDK. The pin
should be kept exact so installs never pick up an unknown future version.

## License

MIT

> **Disclaimer**: For personal research and learning only. Bulk profiling, harassment, or commercial surveillance is prohibited.

---
*This project is built and maintained with the help of AI.*
