Imported from ggg123124/vrchat-assistant (
skills/vrc-monitor-agent/SKILL.md). Install upstream withnpx skills add ggg123124/vrchat-assistant --skill vrc-monitor-agent. Copyright stays with the author.
vrc-monitor Agent Skill — 好友监控系统使用指南
本 skill 面向任何 AI Agent:当用户询问 VRChat 好友相关问题(谁在线、谁和谁一起玩、某人的活动时间线、上线规律)时,通过 vrc-monitor 的 MCP 接口查询。安装配置见项目根 AGENTS.md / README.md。
⚠️ Agent 义务:使用中发现本软件代码存在漏洞 / bug(功能异常、数据损坏风险、安全隐患等),应主动提交 issue + PR 修复让所有使用者受益,详见项目根
AGENTS.md「发现漏洞 / 缺陷时」小节与DEVELOPMENT.md§1。
- MCP 端点:
http://127.0.0.1:8799/mcp - 服务启动:项目目录下
node start-monitor.js(首次需配置credentials.json,见 AGENTS.md) - 数据库:本地 SQLite(WebSocket 实时采集事件,含历史上线/位置/同屏记录)
MCP 工具
| 工具 | 说明 |
|---|---|
get_online_friends |
当前在线好友列表(含昵称 nickname + 房型解析 locationParsed:worldId/instanceId/type/ownerId/region + 世界名 worldName(未缓存自动 API 补查)+ 房间停留时长 durationMinutes/enteredAt + 在线时长 onlineMinutes/onlineSince;durationMinutes 进入时间 = max(会话起点, 最新位置事件)防跨会话污染;onlineMinutes = 最近 friend-offline 之后最早 friend-online 起算,重复推送被 MIN 跳过) |
get_friend_info |
好友详细信息 |
search_users |
按名字搜索用户(API 优先;API 无匹配时自动回退本地好友库模糊搜索 display_name/备注,结果带 source: local_friends 标记) |
search_groups |
按名字搜索群组(API 用 query 参数,不是 search) |
search_worlds |
按名字搜索世界(英文/日文走 API;中文自动加本地缓存兜底) |
search_planet_worlds |
PlanetVRC 地图检索(planetvrchat.net 日文世界目录):关键词搜索 → 世界名/wrld_id/平台/分类/收藏数;适合 VRChat API 搜不到的日文/小众图。limit 最大 8(每个结果抓详情页补 wrld_id,约 1-2s/个) |
recommend_planet_worlds |
PlanetVRC 推荐排行:sort=popular(访问者数最多)/ new(最新发布)/ updated(最新更新)→ 世界+wrld_id+最大人数+访问量+收藏数+公开日 |
search_booth_items |
BOOTH 素材检索(2026-08-13 新增):booth.pm 关键词搜索 VRChat 素材 → 名称/价格/收藏数(wishlistCount=热度)/卖家/标签。detail=false 快速列表;默认补详情(~0.5s/个,max 10)。下载量/销量 Booth 不公开(匿名恒 0),收藏数作热度信号 |
get_booth_item |
BOOTH 单品详情:按 itemId 查商品 → 名称/价格/描述/标签/图片/卖家/发布时间/收藏数/变体。本地缓存:cached:true 命中快照,forceRefresh 强制实时 |
get_booth_history |
BOOTH 查询历史:本地缓存商品快照,按收藏数/更新时间排序 + minWishlist 趋势过滤 |
get_booth_searches |
BOOTH 搜索历史:最近搜索词 + 结果 + 时间 |
get_my_favorite_worlds |
我的收藏世界(2026-08-14 新增):拉取全部收藏世界(含 VRC+ 专属收藏夹),按标签分类(🎮游戏/👻恐怖/🎵音乐体验/🌄风景观光/🧍Avatar模型/🍻社交聚会/😴休闲睡觉/📷拍照/其他),返回世界名/作者/收藏/浏览/简介/分类。数据经 GET /worlds/favorites 分页一次拉全(含实时 occupants),秒级返回,无需逐个查详情。sortBy 支持 favorites/visits/name/added(added=按收藏时间倒序,最新添加在前,基于 /favorites 返回顺序,与客户端 "Date Added" 一致);group 参数可按收藏夹过滤(tag 或 displayName,如 vrcPlusWorlds1);配套 favorites-pdf.py 一键生成中文 PDF |
get_my_favorite_groups |
我的收藏分组:世界收藏分组(world + vrcPlusWorld 两种类型,含 VRC+ 专属收藏夹),返回 tag/显示名/类型/可见性/容量 capacity(来自 /auth/user/favoritelimits)/已用数/分组 id;type 参数可按类型过滤 |
backup_database |
立即备份数据库(WAL 在线备份,保留最近 2 份到 data/backups/);服务启动 + 每 24h 自动备份 |
get_dynamic_status |
动态状态引擎配置查询(按在线好友数量自动更新自己的自定义状态 statusDescription):enabled(开关,默认关闭)、template(文本模板,{online} 占位符替换为当前在线好友数)、onlineNow、lastSent/lastAt(最近一次实际提交) |
set_dynamic_status |
设置动态状态:enabled 开关(默认关闭)、template 模板({online} 占位符,最长 64 字符)、syncNow 保存后立即强制同步(默认 true)。引擎内置 65s 冷却 + 文本不变不提交(PUT /users/{userId} 只改 statusDescription,status 种类不变);事件驱动(friend-online/offline)+ 5 分钟定时核对兜底 |
get_presence_status |
按在场自动状态配置查询(presence-status 插件:按自己是否在游戏内切换自定义状态文字,采用"捕获+恢复"模型):config(enabled / idleTemplate / pollSeconds)、presence(核心自我在场三态 in_game 游戏内 / not_in_game 不在游戏 / unknown 无法判定,含 location/at/ageMs)、savedText(出游戏时捕获的"上次下线状态",回游戏时恢复用)、lastState/lastText/lastAppliedAt/lastError、serviceAvailable、minApplyIntervalMs |
set_presence_status |
设置按在场自动状态(presence-status 插件):enabled 开关(默认关闭)、idleTemplate 不在游戏时写入的文案(≤64 字符,只改 statusDescription、status 种类原样保留)、savedText 回游戏时恢复用的文字(省略=保留捕获值;空串=清空)、pollSeconds 轮询间隔秒(默认 60,下限 20,上限 3600)、syncNow 保存后立即同步(默认 true)。判定源 = 核心服务 dashboard.selfPresence(user-location 事件三态);只在进/出游戏的转换点动作(出游戏先捕获当前文案再写挂机文案;回游戏写回捕获值);unknown 不翻转现状;两次 PUT 最小间隔 65s、目标文案已在位不提交 |
get_friend_events |
某好友的事件历史(本地库) |
get_recent_events |
事件流查询:无 typeFilter 时返回最新事件窗口;带 typeFilter 为 SQL 层按类型检索(返回该类型最近事件,可查任意历史类型,如 typeFilter="friend-delete") |
get_friend_removals |
[friend-removals 插件] 谁把我删了:列出历史上解除好友的人(friend-delete 事件)。userId 省略=全部;days=最近 N 天;返回 userId/displayName(回填最后使用名)/nickname/createdAt |
get_companions |
同屏交叉查询(指定时间窗口内同实例的好友;可查自己或任意好友)。默认不返回 userTimeline(位置事件多时输出会过大被截断),仅返回 companions 汇总;需逐条位置明细时传 includeTimeline=true |
get_recent_cooplay |
最近一起玩(最近 N 天与自己同屏过的全部好友,按同屏次数降序):companions[{userId, displayName, matchCount, daysCount, lastDay}];days(1-90 默认 7)、limit(默认 30)。与 get_friend_pair_screen(两人版带逐条 matches)互补——面向自己的全好友批量版 |
get_friend_world_stats |
好友地图统计(好友群体最近 N 天去过的世界按热度聚合,发现好友圈热门图):stats[{worldId, worldName, imageUrl, authorName, visitors(去过的不同好友数,主排序), visits(总进入次数), lastSeen, friends(好友名样本 ≤5)}];days(1-365 默认 30)、limit(1-100 默认 20)。纯本地统计无 API 调用 |
get_ops_log |
运维日志(认证/WS/运维生命周期事件,保留最近 500 条):返回 items[{id, kind, level, message, createdAt}];limit(1-1000 默认 200)、kind(可选 'auth'|'ws'|'ops') |
get_friend_pair_meeting |
好友对单次见面分析(查任意两个用户(含自己)之间的「每次见面」时段与时长;self-pair 时 userIdA/B 可填自己的 userId,服务端同样扫描 user-location 与 friend-location 两类事件(与 get_friend_pair_screen 共用匹配引擎);按实例切分,同一实例内同屏匹配合并为一次见面(含实例内中途断开空档,合并为一次),返回每次 start/end/durationMinutes/世界/实例 + meetingCount + totalDurationSeconds;口径:同实例且时间差 ≤ windowMinutes(默认30),排除 private/offline/traveling;startTime/endTime 与 days 二选一) |
get_friend_pair_screen |
好友对同屏次数与时长(查任意两个用户(含自己)之间的共玩/同房统计;self-pair 时 userIdA/B 可填自己的 userId(与 get_recent_cooplay 的 meId 一致),服务端会同时扫描 user-location 与 friend-location 两类事件;精确口径:B 的每条可识别实例事件匹配 A 同一实例且时间差 ≤ windowMinutes(默认30)→ 计同屏;排除 private/offline/traveling,不同时间去过同一房不计;返回 matchCount(次数)、totalMinutes/totalSeconds(总时长,段首到段尾累加,含实例内中途断开空档)、worldDuration(按世界拆分时长)、worlds(共现世界)、matches(默认全量,可加 limit 限制条数);startTime/endTime 与 days 二选一) |
get_online_pattern |
上线规律分析(上线/下线/活跃时段分布 + 活跃天数/频率 + 峰值建议) |
get_world_name |
世界信息查询(懒刷新:缓存命中直接返回,forceRefresh 才走 API;含作者ID/作者名/容量/简介/标签/用户备注 note) |
get_worlds_by_author |
按作者列出全部世界:authorId 或 authorName(内部经 /users 解析)→ GET /worlds?userId= 分页拉全该作者发布的全部图(worldId/名称/收藏/浏览/容量/标签/发布时间),顺带写 world_cache(含 author_id)。配合 get_world_name 返回的 authorId 使用(如「当前所在图作者的全部图加权重」) |
set_world_note |
世界用户备注写入/更新(本地存储,API 刷新不覆盖;空串清除) |
get_world_history |
世界信息变更历史(name/description/author/image_url/release_status/capacity/tags 字段级记录) |
get_weekly_report |
一周游戏周报(活跃天数/时长/世界 Top/同屏伙伴带昵称/自己的上线规律/群组活动/圈内活动日历;days 默认 7)。渲染含两个固化板块:①每日足迹(每天去了哪些房间+和谁一起,daily 每项带当天 companions[{nickname,matchCount}])②本周总结(末尾一段连贯叙事评述)。模板见 vrchat-social-queries §9 |
scan_new_worlds |
扫描最近 N 天新世界(1-30,默认 7),过滤测试/垃圾图后写入 world_kb 表(原 new_worlds),按热度推荐 TOP10;dryRun 只看不写 |
get_new_worlds |
只读查询已跟踪新世界:onlyUnvisited 只看未逛过、sortBy(favorites/occupants/popularity/created_at)、excludeTheme 排除主题(按 author_tag_* 逗号分隔,SQL 层排除)、limit(默认 10 最大 50) |
rate_world |
用户反馈:给世界打好评/烂图标记(rating: 1=好图加权 / -1=烂图降权 / 0=清除),写入 world_kb.user_rating,影响 worldScore 推荐排序 |
mark_world_visited |
显式确认逛过某世界(事件驱动 visited 会漏记,开图闭环手动确认用) |
set_world_sleep |
手动标记睡觉图(worldId 必填,isSleep 默认 true,false=取消),写入 world_kb.sleep_ok=1,recommend_join / recommend_worlds(sleep 主题)的强信号。本地数据,不动云端 |
add_to_backlog |
加入待逛列表(本地待办,不动云端收藏):worldId 必填,reason/priority(0-2,默认 0)可选。幂等:重复加入更新备注/优先级,加入时间保持首次。状态存 world_kb.backlog(合表方案)。世界不在 world_kb 时插兜底行并回填 world_name/author/created_at(缓存优先,缺失走 API;mark_world_visited/rate_world/set_world_sleep 同路径) |
get_backlog |
查看待逛列表:status(pending 默认=未逛 / visited=逛完历史 / all)、sortBy(added_at 默认 / priority / favorites)、limit(1-50)。逛完自动从待逛列表移除(location 事件 / mark_world_visited / 扫描在首次置 visited=1 时同步清 backlog=0),pending 只显示仍待逛的世界 |
remove_from_backlog |
移出待逛列表:worldId 必填。只清 backlog 标记(保留行/世界知识),幂等 |
recommend_worlds |
多源融合世界推荐:local 新世界池 × PlanetVRC × 官方主题搜索 × 用户反馈,评分(热度+新鲜度+主题+作者画像 30 天窗口熟客)+ 可解释 reasons;theme/excludeTheme/sources/excludeVisited 参数 |
favorite_world |
云端收藏:加入 VRChat 收藏夹分组(tag 为 worldsN / vrcPlusWorldsN 动态发现,含 VRC+ 专属收藏夹,默认 worlds0,支持传 displayName),写操作需确认,成功后本地 favorited=1 供推荐加权 |
unfavorite_world |
移除世界收藏:DELETE /favorites/{记录id}(先查记录 id 再删,可逆)。worldId 必填;tag 可选(省略=从全部所在分组移除,含 VRC+ 专属收藏夹)。写操作,confirm: true 才执行 |
move_world_group |
移动世界收藏分组(2026-08-26 新增):删旧建新,与 move_friend_group 同模式(官方客户端 2026.1.1 同款能力)。worldId + toGroup(tag 或 displayName,含 VRC+ 收藏夹)。写操作,destructive(删旧建新非原子),confirm: true 才执行 |
update_favorite_group |
重命名/改可见性(2026-08-26 新增):PUT /favorite/group/{type}/{name}/{userId}。group(tag 或 displayName)必填;displayName(新名)/ visibility(friends/private/public)至少一个。⚠️ 设为 public 分组对他人可见,隐私敏感,须显式 confirm |
clear_favorite_group |
清空收藏分组(2026-08-26 新增):DELETE /favorite/group/{type}/{name}/{userId},清空组内全部收藏(分组本身保留,重新收藏可加回)。group 必填;批量删除,destructive,confirm: true 才执行 |
get_nicknames / set_nickname |
好友昵称映射(查询/写入,本地库) |
get_mutual_friends |
共同好友列表:你与目标用户(userId 或 displayName 精确匹配)的共同好友,自动带本地昵称 |
get_mutual_groups |
共同群组列表:你与目标用户(userId 或 displayName 精确匹配)都加入的群组,含成员数——社交破冰/找共同话题用 |
get_watchlist / add_to_watchlist / remove_from_watchlist |
关注名单 |
send_boop |
戳一戳好友(Boop),对方收到戳戳通知(参数:userId 必填、emojiId 可选) |
get_boop_emojis |
列出内置 boop 表情(65 个)及 emojiId 格式(default_<name>) |
set_emoji_note |
[manage] 给 emojiId(内置 default_xxx 或自定义 fileId)设备注/别名,存本地;note 与 aliases 都为空时软删除该条 |
get_emoji_notes |
[query] 列出 emoji 备注(可按 emojiId / kind 过滤,默认只返回有效项) |
resolve_emoji |
[query] 把口语化/可能带 STT 噪声的中文表情描述解析成 emojiId,支持别名/拼音同音/分词重叠/编辑距离;歧义时返回候选不瞎猜 |
upload_emoji |
上传自定义 boop 表情(需 VRChat Plus;imagePath 必填,animated/animationStyle 可选) |
upload_print |
上传照片到 VRChat 相册 Prints(需 VRC+;imagePath 必填,note 可选备注) |
upload_gallery_image |
上传图片到 VRC+ 图库 Gallery(需 VRC+;imagePath 必填) |
get_prints |
相册照片列表(含 downloadUrl 直链) |
get_gallery_images |
图库图片列表(含 downloadUrl 直链) |
download_print |
从相册下载照片到本地(printId 必填;返回路径可 MEDIA: 发送) |
download_gallery_image |
从图库下载图片到本地(fileId 必填;返回路径可 MEDIA: 发送) |
remove_print |
删除相册照片(不可逆!必须 confirm: true) |
remove_gallery_image |
删除图库图片(不可逆!必须 confirm: true) |
send_invite |
邀请好友加入你当前所在房间(拉人进房;userId/worldId/instanceId 必填、message 可选) |
request_invite |
请求好友邀请你加入 TA 的房间(userId 必填、message 可选,默认 "Can I join you?") |
create_instance |
创建新实例(房间):worldId 必填、type(默认 hidden)/region(默认 jp)可选;⚠️ 非 public 必须带 ownerId=当前用户(否则 400 "Invalid owner ID",2026-08-09 实测,官方文档没写);返回 location 可直接给 invite_myself |
invite_myself |
打开指定实例(与 open_world 同一引擎):管道直发优先(Windows 游戏内静默弹菜单),失败静默回退 API 自我邀请(通知接受后传送);location(worldId:instanceId)或 worldId+instanceId;forceApi 强制走 API |
open_world |
一键打开世界/实例:worldId(自动建实例)或 location(完整实例串直接开);core/vrchat-launch.js openInstance 统一入口——命名管道直发(游戏内静默弹加入菜单,Windows 1 步直达)失败静默回退 API 自我邀请;forceApi 强制走 API |
send_friend_request |
发送好友请求(添加好友;userId 直接加 或 displayName 精确匹配不区分大小写,二选一) |
remove_friend |
删除好友(不可逆!userId 或 displayName 精确匹配,必须传 confirm: true 才执行,否则只预览目标) |
get_server_status |
服务/认证状态 |
get_inventory_global |
全局物品栏:账号级物品列表(名称/描述/装备槽/获取方式),self-only |
get_inventory_drops |
待领取掉落:账号当前可领的物品掉落(空=无),self-only |
get_database_stats |
数据库统计 |
get_user_groups |
用户加入的群组列表(userId 可选,省略 = 当前账号;withDetails: true 批量带简介;GET /users/{userId}/groups) |
get_group_info |
群组详情(名称/成员数/shortCode/描述/认证状态/joinState(open/request/invite);includeAnnouncement: true 附带公告,非成员为 null) |
get_group_invites |
收到的群组邀请:账号待处理的群组邀请列表(含群名/成员数/描述)。self-only——查他人 403 |
get_group_instances |
群组当前开的房(group rooms):instanceId/location/memberCount + 世界信息;空 = 没开房。适合"XX 群今晚有没有活动房"类问题 |
get_group_announcement |
群组公告(title/text/作者/时间;无公告或非成员返回 null 不报错) |
get_group_heat |
群组热度:群组房活动热度榜(活动次数/活跃好友/世界数/成员数/趋势)+ 前 topK 群(星期×小时)热力图;grp_/gmem_ 兼容 |
join_group |
加入群组(open 群直接加入;已是成员返回 alreadyMember:true;groupId 必填) |
leave_group |
退出群组(POST /groups/{id}/leave;必须 confirm: true;非成员返回 notMember) |
peek_group_announcement |
窥探群公告:一键「加入→读公告→退出」,仅对 open 群生效,需 confirm: true |
get_favorite_friends_locations |
好友收藏夹位置:列出收藏分组内好友当前位置(支持 searchName 按名直查),按推荐度排序,private 自动排除 |
recommend_join |
推荐加入:全部在线好友综合评分推荐(熟悉度 + 收藏夹权重 + 圿间场景 + 实例人数/类型) |
set_join_preference |
设置推荐偏好(自然语言,如「我不喜欢人太多」→ 爆满重罚) |
get_join_preference |
查询当前推荐偏好 |
record_join_choice |
记录一次推荐选择(自动补全上下文,≥5 次后自动学习权重) |
get_join_learning |
查看选择学习状态与生效的权重调整 |
x_world_digest |
X 博主世界推荐聚合:聚合指定 X 博主近 1/3/7/15/30 天推荐的世界,按收藏数排序;收藏/浏览比 ≥ 1/5 标 ⭐重点。refresh=true 先抓最新推文再查询 |
x_scan_creators |
X 推荐抓取:立即抓取所有已配置博主的最新推文,提取推荐世界并查询收藏/浏览数据入库。双数据源降级:Nitter RSS 失败自动回退 X SearchTimeline GraphQL(完整推文流,可解决 Nitter 404 的博主);两者都挂时返回可读错误提示。内置 t.co 短链解包(推文里的世界链接常被 X 压缩成 https://t.co/XXXX 短链,如探跡家もっけい/fox_yata9 等博主的世界推荐全在短链里,不解包会整批漏抓;VRC_MONITOR_X_RESOLVE_TCO=0 可关闭) |
x_creators |
列出当前配置的 X 博主清单 |
x_add_creator |
添加要追踪的 X 博主(VRChat 世界推荐博主;screen_name 不带 @) |
x_remove_creator |
移除追踪的 X 博主 |
x_worlds |
查看已收录的推荐世界列表(调试用) |
fetch_community_events |
[events] VRChat 社区活动聚合(官方 events 插件):采集(VRC Search/RLVRC/VRCEve/VRCEvent-KR) → 群组深度挖掘(短码/活动名/世界名反查,补群组热度回填,经 groups.resolve 缓存优先) → 音乐∪虚拟主播筛选 → 结构化 JSON + 落库 plg_events_store。参数:window(week/month/tonight)、focus(all/music/vtuber)、sources(vrcsearch,rlvrc,vrceve,vrckr)、languages、minMembers、maxMine(默认 30,可覆盖)、peekGroups(窥探已挖掘群组公告补充活动,有副作用)、startDate/endDate、limit。返回事件自带规范图标URL/双列时区(start_local/start_bj/tz_label)/中文参加方式(join_info_zh)。用于"最近/今晚有什么活动、哪些可参加、群组热度"。未配置 Google Key 时返回 configStatus 的创建网址指引。PDF 渲染另走管道 |
get_community_events_config |
[events·配置] 查看社区活动抓取配置:Google Calendar API Key 是否已配置(值存数据库不回显);未配置时返回创建 key 的指引网址 |
set_community_events_google_key |
[events·配置] 录入/清除使用者的 Google Cloud API Key(存数据库 plg_events_config,仅本插件读)。createKeyUrl=https://console.cloud.google.com/apis/credentials。需要 confirm:true |
submit_totp |
提交 TOTP 验证码(手动兜底):在 credentials.json 配置 totp_secret 后,服务自动生成验证码登录,无需调用本工具;仅在自动登录失败(验证码被拒/secret 有误)或未配置 secret 时,账号处于 needsTotp 状态(/health 的 auth.needsTotp: true)才需调用本工具提交当前 6 位验证码(code 必填;登录后 WS 自动重连) |
get_friend_favorite_groups |
好友收藏分组列表(2026-08-19 新增):GET /favorite/groups?type=friend + /favorites?type=friend → 分组名/显示名/成员数。与 get_favorite_friends_locations 互补(后者看组内好友实时位置) |
favorite_friend |
添加好友到收藏分组(2026-08-19 新增):POST /favorites type=friend。userId/displayName 二选一;groupName 必填(显示名或分组名);须已是好友(403 返回 not friends);重复收藏返回 already favorited(不抛错)。写操作,confirm: true 才执行 |
unfavorite_friend |
从收藏分组移除好友(2026-08-19 新增):DELETE /favorites/{记录id}(先查记录 id 再删,可逆)。groupName 可选(省略=从全部分组移除)。写操作,confirm: true 才执行 |
move_friend_group |
移动好友到另一分组(2026-08-19 新增):删旧建新(API 无原地更新 tags 端点,与 VRCX 行为一致)。toGroup 必填。写操作,destructive(删旧建新非原子),confirm: true 才执行 |
get_friend_profile_changes |
好友资料变更历史(2026-08-19 新增):Avatar/Bio/状态/头像图标/代词变更记录。事件管道实时采集 friend-update 的 user 对象 diff 落库,与 VRCX 迁移数据(feed_avatar/feed_status/feed_bio)同 type 打通。userId 可选(省略=全部好友);types 逗号分隔过滤(avatar/status/bio/user_icon/pronouns);limit(1-200)/offset 分页。每次变更返回 change 含当前值+旧值 |
get_notifications |
通知收件箱(2026-08-19 新增):读取当前账号未读通知(旧 v1 系统)。limit/offset 分页;types 过滤(friendRequest/invite/message/boop/requestInvite/votetokick/inviteResponse/requestInviteResponse);hidden=true 查已隐藏。返回字段:returned(本页返回条数)、shown(过滤后条数)、hasMore(本页取满 limit 时可能还有下一页)。注意:API 的 type 查询参数已废弃不生效(本地过滤);seen/receiverUserId 仅 WS 推送有,REST 不返回 |
see_notification / hide_notification |
通知已读/隐藏:标记已读 PUT .../see;隐藏清除 PUT .../hide(旧 v1 hide 即删除)。notificationId 必填 |
accept_friend_request |
接受好友请求(2026-08-19 新增):PUT /auth/user/notifications/{id}/accept,接受即直接加为好友,不可逆,必须 confirm: true 才执行,否则只预览 |
decline_friend_request |
拒绝好友请求(2026-08-19 新增):旧 v1 无独立拒绝端点,hide 即清除该通知(对方不会收到明确拒绝提示),必须 confirm: true 才执行,否则只预览 |
auth_get_status |
公网鉴权状态查询(2026-08-25 新增):查看当前服务的网络监听 IP/Port、Token 保护状态与公网安全就绪度评估 |
auth_generate_token |
生成安全访问 Token(2026-08-25 新增):生成 32 字节高强度密码学随机 Token 并提供 .env 配置片段 |
auth_verify_token |
校验访问 Token(2026-08-25 新增):校验给定 Token 是否与当前生效配置相匹配 |
调用方式(HTTP SSE JSON-RPC):
curl -s http://127.0.0.1:8799/mcp -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"<工具名>","arguments":{...}}}'
响应是 SSE 格式,取 data: 行,解析 result.content[0].text 为 JSON。
安全模式(VRC_MONITOR_SAFE_MODE,2026-08-22 新增)
在仓库根
.env或环境变量设置VRC_MONITOR_SAFE_MODE=true并重启服务后,全部破坏性工具会被自动移除(tools/list不再暴露 +tools/call直接拦截),防止 Agent 误执行删除/移除类操作。默认关闭。
被移除的破坏性工具(删除/移除/退出/清除类,完整清单见 core/safe-mode.js 的 DESTRUCTIVE_TOOLS):
remove_friend(删好友)、remove_print(删相册照片)、remove_gallery_image(删画廊图片)、unfavorite_friend(移除好友收藏)、leave_group(退群)、decline_friend_request(拒好友请求)、hide_notification(清除通知)、remove_from_backlog(移出待逛)、remove_from_watchlist(移出关注)、x_remove_creator(移除 X 博主)。
安全模式下这些工具在 tools/list 中根本不存在——Agent 不要尝试调用(会收到拦截报错)。查询/推荐/加好友/加收藏/开房等非破坏性写工具不受影响。关闭安全模式:.env 中改回 VRC_MONITOR_SAFE_MODE=false(或删掉该行)并重启服务。
核心查询工作流 → 已按对象域拆分
2026-08-16 起查询工作流按域拆分(本总纲保留工具表唯一权威 + 通用陷阱):
| 域 | 工作流 | 见 |
|---|---|---|
| 好友/社交 | 在线五要素/同房/同屏/时间线/上线规律/常玩/昵称/画像/关系 + 全部写操作(boop/上传/邀请/开房/好友管理) | vrchat-social-queries |
| 群组 | 群组查询/公告 403 分诊/join/leave/peek | vrchat-group-queries |
| 世界 | 挑新世界/backlog/推荐/PlanetVRC/情报挖掘/X 博主 + 地图展示格式 | vrchat-world-queries |
| BOOTH | 素体服装检索/热度榜/封面/汉化 | booth-query-display |
结果格式 → 社交展示格式(companion 表格)见 vrchat-social-queries;地图展示格式见 vrchat-world-queries §6
常见陷阱
时间戳
所有事件时间为 ISO 8601 UTC,展示转北京时间 +8。原始格式有两种(...Z 毫秒 / +00:00 微秒),解析时统一兼容。
展示时间必须带完整日期
事件按 created_at DESC 返回,可能混入数天前的旧事件。展示时间戳必须带年月日,只看时分秒会误读。
世界名可能为空 / 缓存陈旧
get_friend_events的 world_name 字段经常空,用get_world_name(worldId)单独查- VRChat 世界可以改名,world_cache 懒刷新(缓存命中直接返回,无 TTL);用户否认世界名时用
get_world_name带forceRefresh: true强制刷新
traveling 状态
friend-location 事件中 location: "traveling" 是转场,目的地看 travelingToLocation。
boop 通知在 notification-v2 里
boop 通知落库的顶层事件类型是 notification-v2(不是 boop),boop 在 content_json.type 里。get_recent_events(typeFilter="boop") 查不到,用 typeFilter="notification-v2"。
好友删除事件 friend-delete(谁把我删了)
- VRChat 对方解除好友时,你的 WS 会收到
friend-delete事件(本地已实时落库并自动把该好友移出 friends 表);自己主动删人走remove_friend,不产生此事件。 - 该事件 display_name 为空(解除后 VRChat 不再下发对方信息)——判断"是谁"需靠 userId,可用
get_friend_events(userId)回溯其历史事件中的显示名,或直接调用get_friend_removals(friend-removals 插件已封装名字回填)。 - 查询历史:
get_recent_events(typeFilter="friend-delete")(2026-09-06 起 typeFilter 为 SQL 层类型检索,可查全史);或get_friend_events(userId, types="friend-delete")。语义化入口推荐get_friend_removals()(插件)。
存储引擎:better-sqlite3(WAL 模式,2026-08-09 起)
服务用 better-sqlite3(原生绑定,WAL 日志模式):每次写操作即时落盘,崩溃安全,支持服务运行中的并发读。外部工具(sqlite3 CLI / Python)可直接读主库文件,看到的是最新数据(曾因 sql.js 内存库报 database disk image is malformed,换引擎后解决)。数据写入仍建议走 MCP 工具(SQL 封装层统一在 core/storage.js)。数据库文件是标准 SQLite format 3,可直接被任意 SQLite 工具打开。⚠️ WAL 模式下运行中会有 -wal/-shm 伴生文件(已 gitignore)。
OTP 登录
- 服务自动从邮箱 IMAP 抓取 OTP 验证码登录,无人值守
- QQ 邮箱有"自动分类"功能会把验证码邮件归档到分类文件夹(IMAP 名含
VRChat,modified UTF-7 编码)——scripts/fetch-otp.py 已带文件夹遍历兜底,若 OTP 一直失败先想到这个 - 认证失败有 120s 冷却,401 限流 5min 冷却,会自愈
登录状态主动通知(issue #69)
无人值守服务默认只写日志。可配置 notify-config.json(复制 notify-config.example.json)开启主动通知:在「需人工介入/异常」时(进入 needsTotp、邮箱 OTP 抓取失败、运行期 401 自动重认证失败、认证恢复)提醒宿主,正常自动登录不通知。channels 支持 desktop(Linux notify-send / macOS osascript / Windows PowerShell toast)与 webhook(POST JSON 到 webhook_url)。去抖:连续失败达 consecutive_fail_threshold(默认 3)且距上次通知超 min_interval_sec(默认 300)才发送。默认关闭,缺文件或 enabled:false 不影响服务。桌面通知需系统通知守护(Linux dunst/mako),无守护时静默降级不崩服务。
代理(国内网络)
WebSocket 直连失败 6s 后自动回退到本地代理(默认 127.0.0.1:7892,可在代码/环境变量中修改)。若 HTTP 请求报 502 且本机开了系统代理,设 NO_PROXY=127.0.0.1,localhost 环境变量。
服务健康检查
curl -s http://127.0.0.1:8799/health
正常:auth.authenticated=true、ws.status=connected。服务没起时:项目目录下 node start-monitor.js 后台启动(10-15s 完成登录+WS 连接)。改代码后必须重启才生效(进程常驻,不热加载)。
- 日志:服务日志统一走
core/logger.js,默认写 stdout +<VRC_MONITOR_LOGGER_DIR>/monitor.log(默认<VRC_MONITOR_DIR>/logs)。排障优先看该文件;agent 用VRC_MONITOR_LOGGER_FORMAT=json启动后jq解析结构化行(键 ts/level/name/msg/pid)。级别用VRC_MONITOR_LOGGER_LEVEL控制(默认 info,调 debug 可看 MCP 协议往返)。MCP ping/keepalive 噪音可用VRC_MONITOR_LOGGER_SUPPRESS=ping,keepalive或VRC_MONITOR_LOGGER_LEVEL=warn过滤。 - 若想定位「哪个组件打的日志」:JSONL 的
name字段(如mcp/ws/api/storage);text 格式形如[ws]。