WORLDBOOK

Worldbooks | WebMCP | Search | Submit WebMCP

bilibili WebMCP

Browser tool configuration for bilibili

URL Pattern: ^https?://(www\.)?bilibili\.com/.*$
Allowed Extra Domains: api.bilibili.com, bilibili.com, example.com, member.bilibili.com, search.bilibili.com, space.bilibili.com

Tools (8)

open_article_editor()

Navigate to Bilibili article writing page

Parameters

No parameters

JavaScript Handler

() => {
  window.location.href = 'https://member.bilibili.com/article-text/home';
  return { success: true, message: 'Opening Bilibili article editor...' };
}

insert_article()

Insert content into Bilibili article editor (must be on member.bilibili.com/article-text/home)

Parameters

title string - Article title
content string required - Article content (HTML)

JavaScript Handler

(params) => {
  // Set title
  if (params.title) {
    const titleInput = document.querySelector('.article-title input') || document.querySelector('input[placeholder*="标题"]');
    if (titleInput) {
      titleInput.value = params.title;
      titleInput.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }
  // Find editor
  const editor = document.querySelector('.ql-editor') || document.querySelector('[contenteditable="true"]');
  if (!editor) {
    return { success: false, message: 'Editor not found. Open member.bilibili.com/article-text/home first' };
  }
  editor.innerHTML = params.content;
  editor.dispatchEvent(new Event('input', { bubbles: true }));
  return { success: true, message: 'Content inserted into Bilibili editor' };
}

bilibili_search()

Search Bilibili videos by keyword

Parameters

keyword string required - Search keyword
page string - Page number (default: 1)
count string - Results per page (default: 20, max: 50)
order string - Sort order: totalrank (default), click (views), pubdate (newest), dm (danmaku), stow (favorites)

JavaScript Handler

bilibili_video()

Get Bilibili video details by bvid

Parameters

bvid string required - Video BV ID (e.g. BV1xx411c7mD)

JavaScript Handler

(params) => {
  const run = async function(args) {

      const bvid = args.bvid || args._positional?.[0];
      if (!bvid) return {error: 'Missing argument: bvid'};
      const resp = await fetch('https://api.bilibili.com/x/web-interface/view?bvid=' + encodeURIComponent(bvid), {credentials: 'include'});
      if (!resp.ok) return {error: 'HTTP ' + resp.status, hint: 'Not logged in?'};
      const d = await resp.json();
      if (d.code !== 0) return {error: d.message || 'API error ' + d.code, hint: d.code === -404 ? 'Video not found' : 'Not logged in?'};
      const v = d.data;
      const result = {
        bvid: v.bvid,
        aid: v.aid,
        title: v.title,
        description: v.desc,
        cover: v.pic,
        duration: v.duration,
        duration_text: Math.floor(v.duration / 60) + ':' + String(v.duration % 60).padStart(2, '0'),
        author: v.owner?.name,
        author_mid: v.owner?.mid,
        author_face: v.owner?.face,
        category: v.tname,
        tags: v.tag || null,
        pub_date: v.pubdate ? new Date(v.pubdate * 1000).toISOString() : null,
        stat: {
          view: v.stat?.view,
          like: v.stat?.like,
          dislike: v.stat?.dislike,
          coin: v.stat?.coin,
          favorite: v.stat?.favorite,
          share: v.stat?.share,
          reply: v.stat?.reply,
          danmaku: v.stat?.danmaku
        },
        pages: (v.pages || []).map(p => ({
          page: p.page,
          cid: p.cid,
          title: p.part,
          duration: p.duration
        })),
        url: 'https://www.bilibili.com/video/' + v.bvid
      };

      // Also fetch related videos
      try {
        const resp2 = await fetch('https://api.bilibili.com/x/web-interface/archive/related?bvid=' + encodeURIComponent(bvid), {credentials: 'include'});
        const d2 = await resp2.json();
        if (d2.code === 0 && d2.data) {
          result.related = d2.data.slice(0, 5).map(r => ({
            bvid: r.bvid,
            title: r.title,
            author: r.owner?.name,
            view: r.stat?.view,
            duration: r.duration,
            url: 'https://www.bilibili.com/video/' + r.bvid
          }));
        }
      } catch(e) {}

      return result;
  };
  return run(params || {});
}

bilibili_comments()

Get comments for a Bilibili video

Parameters

bvid string required - Video BV ID
page string - Page number (default: 1)
count string - Comments per page (default: 20, max: 30)
sort string - Sort: 0=by_time, 2=by_likes (default: 2)

JavaScript Handler

(params) => {
  const run = async function(args) {

      const bvid = args.bvid || args._positional?.[0];
      if (!bvid) return {error: 'Missing argument: bvid'};
      const pn = parseInt(args.page) || 1;
      const ps = Math.min(parseInt(args.count) || 20, 30);
      const sort = args.sort !== undefined ? parseInt(args.sort) : 2;

      // First get aid from bvid
      const viewResp = await fetch('https://api.bilibili.com/x/web-interface/view?bvid=' + encodeURIComponent(bvid), {credentials: 'include'});
      if (!viewResp.ok) return {error: 'HTTP ' + viewResp.status, hint: 'Not logged in?'};
      const viewData = await viewResp.json();
      if (viewData.code !== 0) return {error: viewData.message || 'Failed to get video info', hint: viewData.code === -404 ? 'Video not found' : 'Not logged in?'};
      const aid = viewData.data?.aid;

      // Fetch comments using aid
      const resp = await fetch('https://api.bilibili.com/x/v2/reply?type=1&oid=' + aid + '&pn=' + pn + '&ps=' + ps + '&sort=' + sort, {credentials: 'include'});
      if (!resp.ok) return {error: 'HTTP ' + resp.status, hint: 'Not logged in?'};
      const d = await resp.json();
      if (d.code !== 0) return {error: d.message || 'API error ' + d.code, hint: 'Not logged in?'};

      const formatReply = r => ({
        rpid: r.rpid_str,
        user: r.member?.uname,
        user_mid: r.mid,
        user_level: r.member?.level_info?.current_level,
        content: r.content?.message,
        like: r.like,
        reply_count: r.rcount,
        time: r.ctime ? new Date(r.ctime * 1000).toISOString() : null,
        sub_replies: (r.replies || []).slice(0, 3).map(sr => ({
          user: sr.member?.uname,
          content: sr.content?.message,
          like: sr.like,
          time: sr.ctime ? new Date(sr.ctime * 1000).toISOString() : null
        }))
      });

      const comments = (d.data?.replies || []).map(formatReply);

      // Include top/pinned comments on first page
      let top = null;
      if (pn === 1 && d.data?.top_replies?.length) {
        top = d.data.top_replies.map(formatReply);
      }

      return {
        bvid,
        aid,
        title: viewData.data?.title,
        page: pn,
        total: d.data?.page?.count || 0,
        count: comments.length,
        sort: sort === 0 ? 'by_time' : 'by_likes',
        top_comments: top,
        comments
      };
  };
  return run(params || {});
}

bilibili_feed()

Get Bilibili dynamic feed (timeline from followed users)

Parameters

type string - Filter type: all (default), video, article, draw
count string - Max items to return (default: 20)

JavaScript Handler

(params) => {
  const run = async function(args) {

      const typeMap = {all: 'all', video: 'video', article: 'article', draw: 'draw'};
      const type = typeMap[args.type] || 'all';
      const maxCount = parseInt(args.count) || 20;
      const resp = await fetch('https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?type=' + type + '&page=1', {credentials: 'include'});
      if (!resp.ok) return {error: 'HTTP ' + resp.status, hint: 'Not logged in?'};
      const d = await resp.json();
      if (d.code !== 0) return {error: d.message || 'API error ' + d.code, hint: 'Not logged in?'};
      if (!d.data?.items?.length) return {error: 'No feed items', hint: 'Not logged in or not following anyone?'};

      const items = (d.data.items || []).slice(0, maxCount).map(item => {
        const author = item.modules?.module_author;
        const dynamic = item.modules?.module_dynamic;
        const stat = item.modules?.module_stat;
        const base = {
          id: item.id_str,
          type: item.type,
          url: 'https://www.bilibili.com/opus/' + item.id_str,
          author: author?.name,
          author_mid: author?.mid,
          author_face: author?.face,
          pub_time: author?.pub_ts ? new Date(author.pub_ts * 1000).toISOString() : null,
          pub_action: author?.pub_action,
          text: dynamic?.desc?.text || null,
          comment_count: stat?.comment?.count,
          forward_count: stat?.forward?.count,
          like_count: stat?.like?.count
        };

        // Video type
        if (item.type === 'DYNAMIC_TYPE_AV' && dynamic?.major?.archive) {
          const arc = dynamic.major.archive;
          base.video = {
            bvid: arc.bvid,
            title: arc.title,
            cover: arc.cover,
            duration_text: arc.duration_text,
            play: arc.stat?.play,
            danmaku: arc.stat?.danmaku,
            url: 'https://www.bilibili.com/video/' + arc.bvid
          };
        }

        // Draw/image type
        if (item.type === 'DYNAMIC_TYPE_DRAW' && dynamic?.major?.draw) {
          base.images = (dynamic.major.draw.items || []).map(img => img.src);
        }

        // Article type
        if (item.type === 'DYNAMIC_TYPE_ARTICLE' && dynamic?.major?.article) {
          const art = dynamic.major.article;
          base.article = {
            id: art.id,
            title: art.title,
            covers: art.covers,
            url: 'https://www.bilibili.com/read/cv' + art.id
          };
        }

        return base;
      });

      return {type, count: items.length, has_more: !!d.data.has_more, items};
  };
  return run(params || {});
}

bilibili_history()

Get Bilibili watch history

Parameters

count string - Number of items (default: 20, max: 50)

JavaScript Handler

(params) => {
  const run = async function(args) {

      const ps = Math.min(parseInt(args.count) || 20, 50);
      const resp = await fetch('https://api.bilibili.com/x/web-interface/history/cursor?ps=' + ps + '&type=archive', {credentials: 'include'});
      if (!resp.ok) return {error: 'HTTP ' + resp.status, hint: 'Not logged in?'};
      const d = await resp.json();
      if (d.code !== 0) return {error: d.message || 'API error ' + d.code, hint: 'Not logged in?'};
      if (!d.data?.list) return {error: 'No history data', hint: 'Not logged in?'};

      const items = (d.data.list || []).map(h => {
        const progress = h.progress === -1 ? 'completed' : h.progress > 0 ? Math.floor(h.progress / 60) + ':' + String(h.progress % 60).padStart(2, '0') : 'not_started';
        const duration_text = h.duration > 0 ? Math.floor(h.duration / 60) + ':' + String(h.duration % 60).padStart(2, '0') : null;
        return {
          bvid: h.history?.bvid,
          title: h.title,
          author: h.author_name,
          author_mid: h.author_mid,
          cover: h.cover,
          duration: h.duration,
          duration_text,
          progress,
          progress_seconds: h.progress,
          view_at: h.view_at ? new Date(h.view_at * 1000).toISOString() : null,
          tag_name: h.tag_name,
          url: h.history?.bvid ? 'https://www.bilibili.com/video/' + h.history.bvid : null
        };
      });

      return {count: items.length, items};
  };
  return run(params || {});
}

bilibili_me()

Get current Bilibili logged-in user info

Parameters

No parameters

JavaScript Handler

(params) => {
  const run = async function(args) {

      const resp = await fetch('https://api.bilibili.com/x/web-interface/nav', {credentials: 'include'});
      if (!resp.ok) return {error: 'HTTP ' + resp.status, hint: 'Not logged in?'};
      const d = await resp.json();
      if (d.code !== 0) return {error: d.message || 'API error ' + d.code, hint: 'Not logged in?'};
      if (!d.data?.isLogin) return {error: 'Not logged in', hint: 'Please log in to bilibili.com first'};
      const u = d.data;
      const result = {
        mid: u.mid,
        username: u.uname,
        url: 'https://space.bilibili.com/' + u.mid,
        face: u.face,
        level: u.level_info?.current_level,
        coins: u.money,
        vip: u.vipType > 0,
        vip_type: u.vipType === 1 ? 'monthly' : u.vipType === 2 ? 'annual' : 'none',
        vip_label: u.vip_label?.text || null,
        moral: u.moral,
        email_verified: u.email_verified === 1,
        tel_verified: u.mobile_verified === 1,
        follower: null,
        following: null
      };
      try {
        const statResp = await fetch('https://api.bilibili.com/x/web-interface/nav/stat', {credentials: 'include'});
        const statData = await statResp.json();
        if (statData.code === 0 && statData.data) {
          result.follower = statData.data.follower;
          result.following = statData.data.following;
        }
      } catch(e) {}
      return result;
  };
  return run(params || {});
}

🔌 Chrome MCP Server Extension

Use these tools with Claude, ChatGPT, and other AI assistants.

Get Extension →

How to Use WebMCP

WebMCP tools are designed for browser extensions or automation frameworks. The browser extension matches the current URL against the pattern and executes the JavaScript handler when the tool is invoked.

API Endpoint:

GET /api/webmcp/match?url=https://www.bilibili.com/...