@basicbit/vrchat-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +266 -0
  4. package/assets/logo.svg +39 -0
  5. package/dist/bin/cli.js +4 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/package.json +109 -0
  8. package/dist/src/auth/cookieStore.js +136 -0
  9. package/dist/src/auth/cookieStore.js.map +1 -0
  10. package/dist/src/auth/index.js +398 -0
  11. package/dist/src/auth/index.js.map +1 -0
  12. package/dist/src/config/defaults.json +58 -0
  13. package/dist/src/config/index.js +405 -0
  14. package/dist/src/config/index.js.map +1 -0
  15. package/dist/src/core/client.js +262 -0
  16. package/dist/src/core/client.js.map +1 -0
  17. package/dist/src/core/generatedToolOverrides.js +104 -0
  18. package/dist/src/core/generatedToolOverrides.js.map +1 -0
  19. package/dist/src/core/generatedToolSkips.js +28 -0
  20. package/dist/src/core/generatedToolSkips.js.map +1 -0
  21. package/dist/src/core/operationSchemas.js +102 -0
  22. package/dist/src/core/operationSchemas.js.map +1 -0
  23. package/dist/src/core/readToolRegistry.js +93 -0
  24. package/dist/src/core/readToolRegistry.js.map +1 -0
  25. package/dist/src/core/readTools.js +197 -0
  26. package/dist/src/core/readTools.js.map +1 -0
  27. package/dist/src/core/spec.js +137 -0
  28. package/dist/src/core/spec.js.map +1 -0
  29. package/dist/src/core/writeToolRegistry.js +113 -0
  30. package/dist/src/core/writeToolRegistry.js.map +1 -0
  31. package/dist/src/generated/vrchat-schemas.js +3326 -0
  32. package/dist/src/generated/vrchat-schemas.js.map +1 -0
  33. package/dist/src/index.js +31 -0
  34. package/dist/src/index.js.map +1 -0
  35. package/dist/src/infra/logger.js +26 -0
  36. package/dist/src/infra/logger.js.map +1 -0
  37. package/dist/src/models/avatars.js +22 -0
  38. package/dist/src/models/avatars.js.map +1 -0
  39. package/dist/src/models/events.js +115 -0
  40. package/dist/src/models/events.js.map +1 -0
  41. package/dist/src/models/friends.js +148 -0
  42. package/dist/src/models/friends.js.map +1 -0
  43. package/dist/src/models/groups.js +228 -0
  44. package/dist/src/models/groups.js.map +1 -0
  45. package/dist/src/models/instances.js +56 -0
  46. package/dist/src/models/instances.js.map +1 -0
  47. package/dist/src/models/invites.js +34 -0
  48. package/dist/src/models/invites.js.map +1 -0
  49. package/dist/src/models/notifications.js +62 -0
  50. package/dist/src/models/notifications.js.map +1 -0
  51. package/dist/src/models/status.js +50 -0
  52. package/dist/src/models/status.js.map +1 -0
  53. package/dist/src/models/statusPage.js +84 -0
  54. package/dist/src/models/statusPage.js.map +1 -0
  55. package/dist/src/models/users.js +113 -0
  56. package/dist/src/models/users.js.map +1 -0
  57. package/dist/src/models/vrcx.js +144 -0
  58. package/dist/src/models/vrcx.js.map +1 -0
  59. package/dist/src/models/worlds.js +150 -0
  60. package/dist/src/models/worlds.js.map +1 -0
  61. package/dist/src/resources/friendsChanges.js +44 -0
  62. package/dist/src/resources/friendsChanges.js.map +1 -0
  63. package/dist/src/resources/friendsSnapshot.js +69 -0
  64. package/dist/src/resources/friendsSnapshot.js.map +1 -0
  65. package/dist/src/resources/index.js +9 -0
  66. package/dist/src/resources/index.js.map +1 -0
  67. package/dist/src/resources/subscriptions.js +39 -0
  68. package/dist/src/resources/subscriptions.js.map +1 -0
  69. package/dist/src/schemas/auth.js +3 -0
  70. package/dist/src/schemas/auth.js.map +1 -0
  71. package/dist/src/schemas/call.js +13 -0
  72. package/dist/src/schemas/call.js.map +1 -0
  73. package/dist/src/schemas/read.js +58 -0
  74. package/dist/src/schemas/read.js.map +1 -0
  75. package/dist/src/schemas/write.js +18 -0
  76. package/dist/src/schemas/write.js.map +1 -0
  77. package/dist/src/services/api/client.js +66 -0
  78. package/dist/src/services/api/client.js.map +1 -0
  79. package/dist/src/services/api/index.js +2 -0
  80. package/dist/src/services/api/index.js.map +1 -0
  81. package/dist/src/services/avatars/index.js +24 -0
  82. package/dist/src/services/avatars/index.js.map +1 -0
  83. package/dist/src/services/cache.js +158 -0
  84. package/dist/src/services/cache.js.map +1 -0
  85. package/dist/src/services/events/curated.js +229 -0
  86. package/dist/src/services/events/curated.js.map +1 -0
  87. package/dist/src/services/events/index.js +3 -0
  88. package/dist/src/services/events/index.js.map +1 -0
  89. package/dist/src/services/events/utils.js +75 -0
  90. package/dist/src/services/events/utils.js.map +1 -0
  91. package/dist/src/services/friends/changes.js +246 -0
  92. package/dist/src/services/friends/changes.js.map +1 -0
  93. package/dist/src/services/friends/curated.js +497 -0
  94. package/dist/src/services/friends/curated.js.map +1 -0
  95. package/dist/src/services/friends/fetch.js +69 -0
  96. package/dist/src/services/friends/fetch.js.map +1 -0
  97. package/dist/src/services/friends/index.js +5 -0
  98. package/dist/src/services/friends/index.js.map +1 -0
  99. package/dist/src/services/friends/match.js +98 -0
  100. package/dist/src/services/friends/match.js.map +1 -0
  101. package/dist/src/services/groups/allowlist.js +19 -0
  102. package/dist/src/services/groups/allowlist.js.map +1 -0
  103. package/dist/src/services/groups/curated.js +343 -0
  104. package/dist/src/services/groups/curated.js.map +1 -0
  105. package/dist/src/services/groups/index.js +3 -0
  106. package/dist/src/services/groups/index.js.map +1 -0
  107. package/dist/src/services/instances/curated.js +80 -0
  108. package/dist/src/services/instances/curated.js.map +1 -0
  109. package/dist/src/services/instances/index.js +3 -0
  110. package/dist/src/services/instances/index.js.map +1 -0
  111. package/dist/src/services/instances/read.js +14 -0
  112. package/dist/src/services/instances/read.js.map +1 -0
  113. package/dist/src/services/invites/curated.js +90 -0
  114. package/dist/src/services/invites/curated.js.map +1 -0
  115. package/dist/src/services/invites/index.js +2 -0
  116. package/dist/src/services/invites/index.js.map +1 -0
  117. package/dist/src/services/notifications/curated.js +54 -0
  118. package/dist/src/services/notifications/curated.js.map +1 -0
  119. package/dist/src/services/notifications/index.js +2 -0
  120. package/dist/src/services/notifications/index.js.map +1 -0
  121. package/dist/src/services/pipeline/events.js +40 -0
  122. package/dist/src/services/pipeline/events.js.map +1 -0
  123. package/dist/src/services/pipeline/handlers.js +21 -0
  124. package/dist/src/services/pipeline/handlers.js.map +1 -0
  125. package/dist/src/services/pipeline/index.js +4 -0
  126. package/dist/src/services/pipeline/index.js.map +1 -0
  127. package/dist/src/services/pipeline/manager.js +143 -0
  128. package/dist/src/services/pipeline/manager.js.map +1 -0
  129. package/dist/src/services/status/curated.js +53 -0
  130. package/dist/src/services/status/curated.js.map +1 -0
  131. package/dist/src/services/status/index.js +2 -0
  132. package/dist/src/services/status/index.js.map +1 -0
  133. package/dist/src/services/statusPage/curated.js +397 -0
  134. package/dist/src/services/statusPage/curated.js.map +1 -0
  135. package/dist/src/services/statusPage/index.js +2 -0
  136. package/dist/src/services/statusPage/index.js.map +1 -0
  137. package/dist/src/services/users/curated.js +124 -0
  138. package/dist/src/services/users/curated.js.map +1 -0
  139. package/dist/src/services/users/groups.js +54 -0
  140. package/dist/src/services/users/groups.js.map +1 -0
  141. package/dist/src/services/users/index.js +3 -0
  142. package/dist/src/services/users/index.js.map +1 -0
  143. package/dist/src/services/vrcx/db.js +13 -0
  144. package/dist/src/services/vrcx/db.js.map +1 -0
  145. package/dist/src/services/vrcx/gamelog.js +125 -0
  146. package/dist/src/services/vrcx/gamelog.js.map +1 -0
  147. package/dist/src/services/vrcx/index.js +5 -0
  148. package/dist/src/services/vrcx/index.js.map +1 -0
  149. package/dist/src/services/vrcx/memos.js +51 -0
  150. package/dist/src/services/vrcx/memos.js.map +1 -0
  151. package/dist/src/services/vrcx/paths.js +133 -0
  152. package/dist/src/services/vrcx/paths.js.map +1 -0
  153. package/dist/src/services/vrcx/relationships.js +138 -0
  154. package/dist/src/services/vrcx/relationships.js.map +1 -0
  155. package/dist/src/services/vrcx/shared.js +173 -0
  156. package/dist/src/services/vrcx/shared.js.map +1 -0
  157. package/dist/src/services/vrcx/status.js +54 -0
  158. package/dist/src/services/vrcx/status.js.map +1 -0
  159. package/dist/src/services/worlds/index.js +256 -0
  160. package/dist/src/services/worlds/index.js.map +1 -0
  161. package/dist/src/tools/auth.js +44 -0
  162. package/dist/src/tools/auth.js.map +1 -0
  163. package/dist/src/tools/cache.js +61 -0
  164. package/dist/src/tools/cache.js.map +1 -0
  165. package/dist/src/tools/curated/avatars.js +57 -0
  166. package/dist/src/tools/curated/avatars.js.map +1 -0
  167. package/dist/src/tools/curated/events.js +212 -0
  168. package/dist/src/tools/curated/events.js.map +1 -0
  169. package/dist/src/tools/curated/friends.js +168 -0
  170. package/dist/src/tools/curated/friends.js.map +1 -0
  171. package/dist/src/tools/curated/groups.js +368 -0
  172. package/dist/src/tools/curated/groups.js.map +1 -0
  173. package/dist/src/tools/curated/instances.js +35 -0
  174. package/dist/src/tools/curated/instances.js.map +1 -0
  175. package/dist/src/tools/curated/invites.js +78 -0
  176. package/dist/src/tools/curated/invites.js.map +1 -0
  177. package/dist/src/tools/curated/notifications.js +35 -0
  178. package/dist/src/tools/curated/notifications.js.map +1 -0
  179. package/dist/src/tools/curated/status.js +44 -0
  180. package/dist/src/tools/curated/status.js.map +1 -0
  181. package/dist/src/tools/curated/statusPage.js +27 -0
  182. package/dist/src/tools/curated/statusPage.js.map +1 -0
  183. package/dist/src/tools/curated/users.js +201 -0
  184. package/dist/src/tools/curated/users.js.map +1 -0
  185. package/dist/src/tools/curated/vrcx/gamelog.js +80 -0
  186. package/dist/src/tools/curated/vrcx/gamelog.js.map +1 -0
  187. package/dist/src/tools/curated/vrcx/index.js +11 -0
  188. package/dist/src/tools/curated/vrcx/index.js.map +1 -0
  189. package/dist/src/tools/curated/vrcx/memos.js +105 -0
  190. package/dist/src/tools/curated/vrcx/memos.js.map +1 -0
  191. package/dist/src/tools/curated/vrcx/relationships.js +86 -0
  192. package/dist/src/tools/curated/vrcx/relationships.js.map +1 -0
  193. package/dist/src/tools/curated/vrcx/status.js +43 -0
  194. package/dist/src/tools/curated/vrcx/status.js.map +1 -0
  195. package/dist/src/tools/curated/worlds.js +162 -0
  196. package/dist/src/tools/curated/worlds.js.map +1 -0
  197. package/dist/src/tools/generated.js +19 -0
  198. package/dist/src/tools/generated.js.map +1 -0
  199. package/dist/src/tools/raw.js +49 -0
  200. package/dist/src/tools/raw.js.map +1 -0
  201. package/dist/src/tools/read/common.js +58 -0
  202. package/dist/src/tools/read/common.js.map +1 -0
  203. package/dist/src/tools/read/system.js +19 -0
  204. package/dist/src/tools/read/system.js.map +1 -0
  205. package/dist/src/tools/registerAllTools.js +41 -0
  206. package/dist/src/tools/registerAllTools.js.map +1 -0
  207. package/dist/src/tools/write/common.js +10 -0
  208. package/dist/src/tools/write/common.js.map +1 -0
  209. package/dist/src/utils/json.js +53 -0
  210. package/dist/src/utils/json.js.map +1 -0
  211. package/dist/src/utils/schema.js +14 -0
  212. package/dist/src/utils/schema.js.map +1 -0
  213. package/dist/src/utils/stableStringify.js +36 -0
  214. package/dist/src/utils/stableStringify.js.map +1 -0
  215. package/dist/src/utils/strings.js +7 -0
  216. package/dist/src/utils/strings.js.map +1 -0
  217. package/dist/src/utils/toolAnnotations.js +17 -0
  218. package/dist/src/utils/toolAnnotations.js.map +1 -0
  219. package/dist/src/utils/toolNames.js +13 -0
  220. package/dist/src/utils/toolNames.js.map +1 -0
  221. package/dist/src/utils/toolResponses.js +12 -0
  222. package/dist/src/utils/toolResponses.js.map +1 -0
  223. package/docs/architecture.md +46 -0
  224. package/docs/curated-tools.md +132 -0
  225. package/docs/design-notes.md +48 -0
  226. package/docs/evals.md +129 -0
  227. package/docs/tools-guide.md +27 -0
  228. package/docs/tools.md +13849 -0
  229. package/docs/vrcx.md +69 -0
  230. package/package.json +109 -0
@@ -0,0 +1,398 @@
1
+ import { CookieJar } from 'tough-cookie';
2
+ import { createServer } from 'node:http';
3
+ import { randomBytes } from 'node:crypto';
4
+ import { EventEmitter } from 'node:events';
5
+ import { URL } from 'node:url';
6
+ import { logger } from '../infra/logger.js';
7
+ import { getCookieStore } from './cookieStore.js';
8
+ const MAX_LOGIN_BODY_BYTES = 16 * 1024;
9
+ class AuthError extends Error {
10
+ kind;
11
+ isChallenge;
12
+ constructor(message, kind, options = {}) {
13
+ super(message);
14
+ this.name = 'AuthError';
15
+ this.kind = kind;
16
+ this.isChallenge = options.isChallenge === true;
17
+ }
18
+ }
19
+ class BodyTooLargeError extends Error {
20
+ constructor() {
21
+ super('Login request body is too large.');
22
+ this.name = 'BodyTooLargeError';
23
+ }
24
+ }
25
+ function escapeHtml(value) {
26
+ return value
27
+ .replaceAll('&', '&')
28
+ .replaceAll('<', '&lt;')
29
+ .replaceAll('>', '&gt;')
30
+ .replaceAll('"', '&quot;')
31
+ .replaceAll("'", '&#39;');
32
+ }
33
+ function cleanInput(value) {
34
+ const trimmed = value?.trim();
35
+ if (!trimmed)
36
+ return undefined;
37
+ return trimmed;
38
+ }
39
+ function parseLoginSubmission(params) {
40
+ const usernameInput = params.get('username') ?? '';
41
+ const passwordInput = params.get('password') ?? '';
42
+ const factorKind = params.get('factorKind') ?? '';
43
+ const code = cleanInput(params.get('code'));
44
+ const directTotp = cleanInput(params.get('totp'));
45
+ const directEmailOtp = cleanInput(params.get('emailOtp'));
46
+ return {
47
+ usernameInput,
48
+ passwordInput,
49
+ totp: directTotp ?? (factorKind === 'totp' ? code : undefined),
50
+ emailOtp: directEmailOtp ?? (factorKind === 'emailOtp' ? code : undefined),
51
+ };
52
+ }
53
+ class AuthManager {
54
+ jar = new CookieJar();
55
+ server = null;
56
+ serverToken = null;
57
+ port = null;
58
+ loggedIn = false;
59
+ pendingCreds = null;
60
+ store = getCookieStore();
61
+ events = new EventEmitter();
62
+ async init() {
63
+ const loaded = await this.store.load();
64
+ if (loaded) {
65
+ this.jar = loaded;
66
+ this.loggedIn = await this.hasAuthCookie();
67
+ }
68
+ this.emitStatus();
69
+ }
70
+ async hasAuthCookie() {
71
+ const cookies = await this.jar.getCookies('https://api.vrchat.cloud');
72
+ return cookies.some((c) => c.key === 'auth' || c.key === 'twoFactorAuth');
73
+ }
74
+ clearCookies() {
75
+ this.jar = new CookieJar();
76
+ }
77
+ getCookieHeader(url) {
78
+ return this.jar.getCookieString(url);
79
+ }
80
+ async getCookieValue(name, url = 'https://api.vrchat.cloud') {
81
+ const cookies = await this.jar.getCookies(url);
82
+ const match = cookies.find((cookie) => cookie.key === name);
83
+ return match?.value;
84
+ }
85
+ async setCookiesFromResponse(url, setCookieHeaders) {
86
+ for (const setCookie of setCookieHeaders) {
87
+ await this.jar.setCookie(setCookie, url);
88
+ }
89
+ await this.persist();
90
+ }
91
+ getStatus() {
92
+ return { loggedIn: this.loggedIn };
93
+ }
94
+ onStatusChange(listener) {
95
+ this.events.on('status', listener);
96
+ return () => this.events.off('status', listener);
97
+ }
98
+ emitStatus() {
99
+ this.events.emit('status', this.getStatus());
100
+ }
101
+ async logout() {
102
+ this.loggedIn = false;
103
+ this.clearCookies();
104
+ this.pendingCreds = null;
105
+ await this.store.clear();
106
+ if (this.server) {
107
+ this.server.close();
108
+ this.server = null;
109
+ this.port = null;
110
+ }
111
+ this.emitStatus();
112
+ }
113
+ async startLoginServer() {
114
+ if (this.server) {
115
+ return {
116
+ url: `http://127.0.0.1:${this.port}/?token=${encodeURIComponent(this.serverToken)}`,
117
+ token: this.serverToken,
118
+ };
119
+ }
120
+ const token = randomBytes(16).toString('hex');
121
+ this.serverToken = token;
122
+ this.server = createServer((req, res) => {
123
+ this.handleRequest(req, res).catch((err) => {
124
+ logger.error('auth server error', { message: err.message });
125
+ res.statusCode = 500;
126
+ res.end('Internal server error');
127
+ });
128
+ });
129
+ await new Promise((resolve) => {
130
+ this.server.listen(0, '127.0.0.1', () => resolve());
131
+ });
132
+ const address = this.server.address();
133
+ const port = typeof address === 'object' && address ? address.port : 0;
134
+ this.port = port;
135
+ return { url: `http://127.0.0.1:${port}/?token=${encodeURIComponent(token)}`, token };
136
+ }
137
+ async parseBody(req) {
138
+ const chunks = [];
139
+ let total = 0;
140
+ for await (const chunk of req) {
141
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
142
+ total += buf.length;
143
+ if (total > MAX_LOGIN_BODY_BYTES) {
144
+ req.resume();
145
+ throw new BodyTooLargeError();
146
+ }
147
+ chunks.push(buf);
148
+ }
149
+ const body = Buffer.concat(chunks).toString('utf8');
150
+ return new URLSearchParams(body);
151
+ }
152
+ renderForm(res, token, options = {}) {
153
+ const stage = options.stage ?? 'initial';
154
+ const showOtp = stage === 'totp' || stage === 'emailOtp';
155
+ const codeLabel = stage === 'emailOtp' ? 'Email verification code' : 'Authenticator code';
156
+ const codeHelp = stage === 'emailOtp'
157
+ ? 'Check your VRChat account email for the one-time code.'
158
+ : 'Open your authenticator app and enter the current six-digit code.';
159
+ const usernameHint = options.usernameHint ? escapeHtml(options.usernameHint) : '';
160
+ const error = options.error ? escapeHtml(options.error) : undefined;
161
+ const notice = options.notice ? escapeHtml(options.notice) : undefined;
162
+ const encodedToken = encodeURIComponent(token);
163
+ const actionsClass = showOtp ? 'actions two' : 'actions';
164
+ this.renderPage(res, `<div class="brand"><h1>VRChat MCP Login</h1></div>
165
+ ${error ? `<p class="error">${error}</p>` : ''}
166
+ ${notice ? `<p class="notice">${notice}</p>` : ''}
167
+ ${showOtp
168
+ ? `<p>2FA is required${usernameHint ? ` for <span class="account">${usernameHint}</span>` : ''}. ${codeHelp}</p>`
169
+ : '<p>Sign in to VRChat to let the MCP server make authenticated requests on your behalf.</p>'}
170
+ <form method="POST" action="/submit?token=${encodedToken}">
171
+ ${showOtp
172
+ ? `<input type="hidden" name="factorKind" value="${stage}" /><label>${codeLabel}<input name="code" inputmode="numeric" autocomplete="one-time-code" required autofocus /></label>`
173
+ : '<label>Username or email<input name="username" autocomplete="username" required autofocus /></label><label>Password<input name="password" type="password" autocomplete="current-password" required /></label>'}
174
+ <div class="${actionsClass}">
175
+ <button type="submit">${showOtp ? 'Verify' : 'Login'}</button>
176
+ ${showOtp ? `<a class="link-button" href="/reset?token=${encodedToken}">Use another account</a>` : ''}
177
+ </div>
178
+ </form>`);
179
+ }
180
+ renderSuccess(res) {
181
+ this.renderPage(res, `<div class="brand"><h1>Login successful</h1></div>
182
+ <p class="notice">You're logged in.</p>
183
+ <p>You can close this window and return to your MCP client.</p>`);
184
+ }
185
+ renderAuthError(res, token, err, username) {
186
+ if (!(err instanceof AuthError) || !err.kind || err.kind === 'unknown') {
187
+ return false;
188
+ }
189
+ const isChallenge = err.isChallenge;
190
+ const notice = err.kind === 'emailOtp' ? 'Email verification required' : 'Authenticator code required';
191
+ this.renderForm(res, token, {
192
+ error: isChallenge ? undefined : err.message,
193
+ notice: isChallenge ? notice : undefined,
194
+ stage: err.kind === 'totp' ? 'totp' : 'emailOtp',
195
+ usernameHint: username,
196
+ });
197
+ return true;
198
+ }
199
+ renderPage(res, body) {
200
+ res.setHeader('content-type', 'text/html; charset=utf-8');
201
+ res.end(`<!doctype html>
202
+ <html lang="en">
203
+ <head>
204
+ <meta charset="utf-8" />
205
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
206
+ <title>VRChat MCP Login</title>
207
+ <style>
208
+ :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
209
+ * { box-sizing: border-box; }
210
+ body { min-height: 100vh; margin: 0; display: grid; place-items: center; background: radial-gradient(circle at top left, #4f46e5 0, transparent 30%), linear-gradient(135deg, #0f172a, #111827 55%, #020617); color: #e5e7eb; }
211
+ main { width: min(440px, calc(100vw - 32px)); padding: 32px; border: 1px solid rgba(148, 163, 184, 0.24); border-radius: 24px; background: rgba(15, 23, 42, 0.86); box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45); backdrop-filter: blur(16px); }
212
+ .brand { margin-bottom: 24px; }
213
+ h1 { margin: 0; font-size: 1.45rem; line-height: 1.2; }
214
+ p { color: #aebbd0; line-height: 1.5; }
215
+ .error { padding: 12px 14px; border: 1px solid rgba(248, 113, 113, 0.45); border-radius: 14px; background: rgba(127, 29, 29, 0.35); color: #fecaca; }
216
+ .notice { padding: 12px 14px; border: 1px solid rgba(103, 232, 249, 0.36); border-radius: 14px; background: rgba(8, 47, 73, 0.35); color: #cffafe; }
217
+ label { display: grid; gap: 8px; margin: 16px 0; color: #dbeafe; font-weight: 650; }
218
+ input { width: 100%; border: 1px solid rgba(148, 163, 184, 0.36); border-radius: 14px; padding: 12px 14px; background: rgba(2, 6, 23, 0.74); color: #f8fafc; font-size: 1rem; }
219
+ input:focus { outline: 2px solid #22d3ee; outline-offset: 2px; }
220
+ .actions { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 22px; }
221
+ .actions.two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
222
+ button, .link-button { min-height: 52px; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 16px; padding: 0 18px; background: #67e8f9; color: #082f49; font-weight: 800; line-height: 1.15; text-align: center; cursor: pointer; text-decoration: none; }
223
+ .link-button { background: rgba(148, 163, 184, 0.18); color: #dbeafe; }
224
+ .hint { margin: 0; font-size: 0.92rem; }
225
+ .account { color: #f8fafc; font-weight: 800; }
226
+ @media (max-width: 520px) { main { padding: 24px; } .actions.two { grid-template-columns: 1fr; } }
227
+ </style>
228
+ </head>
229
+ <body>
230
+ <main>
231
+ ${body}
232
+ </main>
233
+ </body>
234
+ </html>`);
235
+ }
236
+ getValidatedRequestContext(req, res) {
237
+ if (!this.serverToken || !this.port) {
238
+ res.statusCode = 503;
239
+ res.end('Auth server not ready');
240
+ return null;
241
+ }
242
+ const urlObj = new URL(req.url ?? '/', `http://127.0.0.1:${this.port}`);
243
+ const token = urlObj.searchParams.get('token');
244
+ if (!token || token !== this.serverToken) {
245
+ res.statusCode = 403;
246
+ res.end('Invalid token');
247
+ return null;
248
+ }
249
+ return { urlObj, token };
250
+ }
251
+ async handleSubmit(req, res, token) {
252
+ const params = await this.parseBody(req);
253
+ const submission = parseLoginSubmission(params);
254
+ if (submission.usernameInput || submission.passwordInput) {
255
+ this.pendingCreds = {
256
+ username: submission.usernameInput,
257
+ password: submission.passwordInput,
258
+ };
259
+ }
260
+ const creds = this.pendingCreds ?? {
261
+ username: submission.usernameInput,
262
+ password: submission.passwordInput,
263
+ };
264
+ if (!creds.username || !creds.password) {
265
+ this.renderForm(res, token, { error: 'Username and password are required.' });
266
+ return;
267
+ }
268
+ try {
269
+ await this.performLogin(creds.username, creds.password, submission.totp, submission.emailOtp);
270
+ this.loggedIn = true;
271
+ this.pendingCreds = null;
272
+ await this.persist();
273
+ this.emitStatus();
274
+ res.statusCode = 200;
275
+ this.renderSuccess(res);
276
+ }
277
+ catch (err) {
278
+ this.loggedIn = false;
279
+ if (this.renderAuthError(res, token, err, creds.username)) {
280
+ return;
281
+ }
282
+ this.clearCookies();
283
+ this.pendingCreds = null;
284
+ const msg = err instanceof Error ? err.message : 'Login failed';
285
+ this.renderForm(res, token, { error: msg });
286
+ }
287
+ }
288
+ async handleRequest(req, res) {
289
+ const context = this.getValidatedRequestContext(req, res);
290
+ if (!context)
291
+ return;
292
+ const { urlObj, token } = context;
293
+ if (req.method === 'GET' && urlObj.pathname === '/') {
294
+ this.renderForm(res, token);
295
+ return;
296
+ }
297
+ if (req.method === 'GET' && urlObj.pathname === '/reset') {
298
+ this.loggedIn = false;
299
+ this.pendingCreds = null;
300
+ this.clearCookies();
301
+ await this.store.clear();
302
+ this.emitStatus();
303
+ this.renderForm(res, token);
304
+ return;
305
+ }
306
+ if (req.method === 'POST' && urlObj.pathname === '/submit') {
307
+ try {
308
+ await this.handleSubmit(req, res, token);
309
+ }
310
+ catch (err) {
311
+ if (err instanceof BodyTooLargeError) {
312
+ res.statusCode = 413;
313
+ res.setHeader('Connection', 'close');
314
+ res.end('Request body too large');
315
+ return;
316
+ }
317
+ throw err;
318
+ }
319
+ return;
320
+ }
321
+ res.statusCode = 404;
322
+ res.end('Not found');
323
+ }
324
+ async performLogin(username, password, totp, emailOtp) {
325
+ const basic = Buffer.from(`${username}:${password}`).toString('base64');
326
+ const res1 = await fetch('https://api.vrchat.cloud/api/1/auth/user', {
327
+ method: 'GET',
328
+ headers: {
329
+ authorization: `Basic ${basic}`,
330
+ 'user-agent': 'vrchat-mcp-login',
331
+ },
332
+ });
333
+ const setCookies1 = res1.headers.getSetCookie?.() ?? [];
334
+ await this.setCookiesFromResponse('https://api.vrchat.cloud', setCookies1);
335
+ const body1 = (await res1.json().catch(() => ({})));
336
+ const requires2fa = Array.isArray(body1?.requiresTwoFactorAuth)
337
+ ? body1.requiresTwoFactorAuth
338
+ : [];
339
+ if (requires2fa.length) {
340
+ const cookieHeader = await this.getCookieHeader('https://api.vrchat.cloud');
341
+ if (requires2fa.includes('totp')) {
342
+ if (!totp) {
343
+ throw new AuthError('2FA required (TOTP). Enter the code from your authenticator app.', 'totp', { isChallenge: true });
344
+ }
345
+ const res2 = await fetch('https://api.vrchat.cloud/api/1/auth/twofactorauth/totp/verify', {
346
+ method: 'POST',
347
+ headers: {
348
+ cookie: cookieHeader,
349
+ 'content-type': 'application/json',
350
+ 'user-agent': 'vrchat-mcp-login',
351
+ },
352
+ body: JSON.stringify({ code: totp }),
353
+ });
354
+ const setCookies2 = res2.headers.getSetCookie?.() ?? [];
355
+ await this.setCookiesFromResponse('https://api.vrchat.cloud', setCookies2);
356
+ if (res2.status !== 200) {
357
+ throw new AuthError(`TOTP verify failed: ${res2.status}`, 'totp');
358
+ }
359
+ return;
360
+ }
361
+ if (requires2fa.includes('emailOtp')) {
362
+ if (!emailOtp) {
363
+ throw new AuthError('2FA required (Email OTP). Check your email and enter the code.', 'emailOtp', { isChallenge: true });
364
+ }
365
+ const res2 = await fetch('https://api.vrchat.cloud/api/1/auth/twofactorauth/emailotp/verify', {
366
+ method: 'POST',
367
+ headers: {
368
+ cookie: cookieHeader,
369
+ 'content-type': 'application/json',
370
+ 'user-agent': 'vrchat-mcp-login',
371
+ },
372
+ body: JSON.stringify({ code: emailOtp }),
373
+ });
374
+ const setCookies2 = res2.headers.getSetCookie?.() ?? [];
375
+ await this.setCookiesFromResponse('https://api.vrchat.cloud', setCookies2);
376
+ if (res2.status !== 200) {
377
+ throw new AuthError(`Email OTP verify failed: ${res2.status}`, 'emailOtp');
378
+ }
379
+ return;
380
+ }
381
+ throw new AuthError(`2FA required (${requires2fa.join(', ')}).`, 'unknown');
382
+ }
383
+ if (res1.status === 200) {
384
+ return;
385
+ }
386
+ throw new Error(`Login failed: ${res1.status}`);
387
+ }
388
+ async persist() {
389
+ try {
390
+ await this.store.save(this.jar);
391
+ }
392
+ catch (err) {
393
+ logger.warn('Failed to persist cookies', { message: err.message });
394
+ }
395
+ }
396
+ }
397
+ export const authManager = new AuthManager();
398
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,oBAAoB,GAAG,EAAE,GAAG,IAAI,CAAC;AAMvC,MAAM,SAAU,SAAQ,KAAK;IAC3B,IAAI,CAAmC;IACvC,WAAW,CAAU;IACrB,YACE,OAAe,EACf,IAAsC,EACtC,UAAqC,EAAE;QAEvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,CAAC;IAClD,CAAC;CACF;AAED,MAAM,iBAAkB,SAAQ,KAAK;IACnC;QACE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AASD,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,UAAU,CAAC,KAAoB;IACtC,MAAM,OAAO,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAuB;IACnD,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACnD,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACnD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1D,OAAO;QACL,aAAa;QACb,aAAa;QACb,IAAI,EAAE,UAAU,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,QAAQ,EAAE,cAAc,IAAI,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;KAC3E,CAAC;AACJ,CAAC;AAED,MAAM,WAAW;IACP,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;IACtB,MAAM,GAA2C,IAAI,CAAC;IACtD,WAAW,GAAkB,IAAI,CAAC;IAClC,IAAI,GAAkB,IAAI,CAAC;IAC3B,QAAQ,GAAG,KAAK,CAAC;IACjB,YAAY,GAAkD,IAAI,CAAC;IACnE,KAAK,GAAG,cAAc,EAAE,CAAC;IACzB,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAEpC,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC;YAClB,IAAI,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,aAAa;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;QACtE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,KAAK,eAAe,CAAC,CAAC;IAC5E,CAAC;IAED,YAAY;QACV,IAAI,CAAC,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,eAAe,CAAC,GAAW;QACzB,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,IAAY,EACZ,GAAG,GAAG,0BAA0B;QAEhC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAC5D,OAAO,KAAK,EAAE,KAAK,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,GAAW,EAAE,gBAA0B;QAClE,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;YACzC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IAED,SAAS;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IACrC,CAAC;IAED,cAAc,CAAC,QAAsC;QACnD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACnC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,MAAM;QACV,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO;gBACL,GAAG,EAAE,oBAAoB,IAAI,CAAC,IAAI,WAAW,kBAAkB,CAAC,IAAI,CAAC,WAAY,CAAC,EAAE;gBACpF,KAAK,EAAE,IAAI,CAAC,WAAY;aACzB,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAEzB,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACtC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACzC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvE,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,IAAI,CAAC,MAAO,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,OAAO,EAAE,GAAG,EAAE,oBAAoB,IAAI,WAAW,kBAAkB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;IACxF,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,GAAoB;QAC1C,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChE,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC;YACpB,IAAI,KAAK,GAAG,oBAAoB,EAAE,CAAC;gBACjC,GAAG,CAAC,MAAM,EAAE,CAAC;gBACb,MAAM,IAAI,iBAAiB,EAAE,CAAC;YAChC,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpD,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAEO,UAAU,CAChB,GAAmB,EACnB,KAAa,EACb,UAKI,EAAE;QAEN,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC;QACzC,MAAM,OAAO,GAAG,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,UAAU,CAAC;QACzD,MAAM,SAAS,GAAG,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,oBAAoB,CAAC;QAC1F,MAAM,QAAQ,GACZ,KAAK,KAAK,UAAU;YAClB,CAAC,CAAC,wDAAwD;YAC1D,CAAC,CAAC,mEAAmE,CAAC;QAC1E,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,IAAI,CAAC,UAAU,CACb,GAAG,EACH;QACE,KAAK,CAAC,CAAC,CAAC,oBAAoB,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE;QAC5C,MAAM,CAAC,CAAC,CAAC,qBAAqB,MAAM,MAAM,CAAC,CAAC,CAAC,EAAE;QAE/C,OAAO;YACL,CAAC,CAAC,qBAAqB,YAAY,CAAC,CAAC,CAAC,8BAA8B,YAAY,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,MAAM;YACjH,CAAC,CAAC,4FACN;kDAC4C,YAAY;UAEpD,OAAO;YACL,CAAC,CAAC,iDAAiD,KAAK,cAAc,SAAS,mGAAmG;YAClL,CAAC,CAAC,+MACN;sBACc,YAAY;kCACA,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;YAClD,OAAO,CAAC,CAAC,CAAC,6CAA6C,YAAY,2BAA2B,CAAC,CAAC,CAAC,EAAE;;cAEjG,CACT,CAAC;IACJ,CAAC;IAEO,aAAa,CAAC,GAAmB;QACvC,IAAI,CAAC,UAAU,CACb,GAAG,EACH;;sEAEgE,CACjE,CAAC;IACJ,CAAC;IAEO,eAAe,CACrB,GAAmB,EACnB,KAAa,EACb,GAAY,EACZ,QAAgB;QAEhB,IAAI,CAAC,CAAC,GAAG,YAAY,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACvE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;QACpC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,6BAA6B,CAAC;QACvG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE;YAC1B,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO;YAC5C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YACxC,KAAK,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU;YAChD,YAAY,EAAE,QAAQ;SACvB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,UAAU,CAAC,GAAmB,EAAE,IAAY;QAClD,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;QAC1D,GAAG,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA8BJ,IAAI;;;QAGJ,CAAC,CAAC;IACR,CAAC;IAEO,0BAA0B,CAChC,GAAoB,EACpB,GAAmB;QAEnB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACpC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrB,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,oBAAoB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YACzC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrB,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,GAAoB,EAAE,GAAmB,EAAE,KAAa;QACjF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAEhD,IAAI,UAAU,CAAC,aAAa,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;YACzD,IAAI,CAAC,YAAY,GAAG;gBAClB,QAAQ,EAAE,UAAU,CAAC,aAAa;gBAClC,QAAQ,EAAE,UAAU,CAAC,aAAa;aACnC,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,IAAI;YACjC,QAAQ,EAAE,UAAU,CAAC,aAAa;YAClC,QAAQ,EAAE,UAAU,CAAC,aAAa;SACnC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC9F,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACrB,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1D,OAAO;YACT,CAAC;YACD,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;YAChE,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,GAAoB,EAAE,GAAmB;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,0BAA0B,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;QAElC,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;YACpD,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3D,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;oBACrC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;oBACrB,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;oBACrC,GAAG,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;oBAClC,OAAO;gBACT,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,OAAO;QACT,CAAC;QAED,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,QAAgB,EAAE,IAAa,EAAE,QAAiB;QAC7F,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,0CAA0C,EAAE;YACnE,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,aAAa,EAAE,SAAS,KAAK,EAAE;gBAC/B,YAAY,EAAE,kBAAkB;aACjC;SACF,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC;QACxD,MAAM,IAAI,CAAC,sBAAsB,CAAC,0BAA0B,EAAE,WAAW,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAQ,CAAC;QAC3D,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,qBAAqB,CAAC;YAC7D,CAAC,CAAE,KAAK,CAAC,qBAAkC;YAC3C,CAAC,CAAC,EAAE,CAAC;QAEP,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;YACvB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,0BAA0B,CAAC,CAAC;YAC5E,IAAI,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACjC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,MAAM,IAAI,SAAS,CACjB,kEAAkE,EAClE,MAAM,EACN,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CAAC;gBACJ,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,+DAA+D,EAAE;oBACxF,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACP,MAAM,EAAE,YAAY;wBACpB,cAAc,EAAE,kBAAkB;wBAClC,YAAY,EAAE,kBAAkB;qBACjC;oBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;iBACrC,CAAC,CAAC;gBACH,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC;gBACxD,MAAM,IAAI,CAAC,sBAAsB,CAAC,0BAA0B,EAAE,WAAW,CAAC,CAAC;gBAC3E,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACxB,MAAM,IAAI,SAAS,CAAC,uBAAuB,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;gBACpE,CAAC;gBACD,OAAO;YACT,CAAC;YAED,IAAI,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,IAAI,SAAS,CACjB,gEAAgE,EAChE,UAAU,EACV,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CAAC;gBACJ,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,KAAK,CACtB,mEAAmE,EACnE;oBACE,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACP,MAAM,EAAE,YAAY;wBACpB,cAAc,EAAE,kBAAkB;wBAClC,YAAY,EAAE,kBAAkB;qBACjC;oBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;iBACzC,CACF,CAAC;gBACF,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC;gBACxD,MAAM,IAAI,CAAC,sBAAsB,CAAC,0BAA0B,EAAE,WAAW,CAAC,CAAC;gBAC3E,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACxB,MAAM,IAAI,SAAS,CAAC,4BAA4B,IAAI,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,CAAC;gBAC7E,CAAC;gBACD,OAAO;YACT,CAAC;YAED,MAAM,IAAI,SAAS,CAAC,iBAAiB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC9E,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,OAAO;QACnB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC"}
@@ -0,0 +1,58 @@
1
+ {
2
+ "api": {
3
+ "baseUrl": "https://api.vrchat.cloud/api/1",
4
+ "userAgent": "vrchat-mcp/{version}"
5
+ },
6
+ "spec": {
7
+ "url": "https://vrchat.community/openapi.yaml"
8
+ },
9
+ "logging": {
10
+ "level": "info"
11
+ },
12
+ "auth": {
13
+ "cookieStore": "memory",
14
+ "cookieFile": "~/.vrchat-mcp-cookies.json"
15
+ },
16
+ "writes": {
17
+ "allow": false
18
+ },
19
+ "cache": {
20
+ "enabled": true,
21
+ "ttlSeconds": {
22
+ "friends": 120,
23
+ "userGroups": 300,
24
+ "groups": 300,
25
+ "notifications": 30
26
+ },
27
+ "staleTtlSeconds": {
28
+ "friends": 600,
29
+ "userGroups": 1800,
30
+ "groups": 1800,
31
+ "notifications": 300
32
+ }
33
+ },
34
+ "pipeline": {
35
+ "enabled": true,
36
+ "url": "wss://pipeline.vrchat.cloud/",
37
+ "reconnectMs": 5000,
38
+ "changeBuffer": 200,
39
+ "userAgent": ""
40
+ },
41
+ "groups": {
42
+ "allowlist": []
43
+ },
44
+ "rawTools": {
45
+ "enabled": false
46
+ },
47
+ "generatedReadTools": {
48
+ "disable": false
49
+ },
50
+ "generatedWriteTools": {
51
+ "disable": false
52
+ },
53
+ "vrcx": {
54
+ "enabled": true,
55
+ "databasePath": "",
56
+ "worldDbPath": ""
57
+ }
58
+ }