@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.
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/assets/logo.svg +39 -0
- package/dist/bin/cli.js +4 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/package.json +109 -0
- package/dist/src/auth/cookieStore.js +136 -0
- package/dist/src/auth/cookieStore.js.map +1 -0
- package/dist/src/auth/index.js +398 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/config/defaults.json +58 -0
- package/dist/src/config/index.js +405 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/core/client.js +262 -0
- package/dist/src/core/client.js.map +1 -0
- package/dist/src/core/generatedToolOverrides.js +104 -0
- package/dist/src/core/generatedToolOverrides.js.map +1 -0
- package/dist/src/core/generatedToolSkips.js +28 -0
- package/dist/src/core/generatedToolSkips.js.map +1 -0
- package/dist/src/core/operationSchemas.js +102 -0
- package/dist/src/core/operationSchemas.js.map +1 -0
- package/dist/src/core/readToolRegistry.js +93 -0
- package/dist/src/core/readToolRegistry.js.map +1 -0
- package/dist/src/core/readTools.js +197 -0
- package/dist/src/core/readTools.js.map +1 -0
- package/dist/src/core/spec.js +137 -0
- package/dist/src/core/spec.js.map +1 -0
- package/dist/src/core/writeToolRegistry.js +113 -0
- package/dist/src/core/writeToolRegistry.js.map +1 -0
- package/dist/src/generated/vrchat-schemas.js +3326 -0
- package/dist/src/generated/vrchat-schemas.js.map +1 -0
- package/dist/src/index.js +31 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/infra/logger.js +26 -0
- package/dist/src/infra/logger.js.map +1 -0
- package/dist/src/models/avatars.js +22 -0
- package/dist/src/models/avatars.js.map +1 -0
- package/dist/src/models/events.js +115 -0
- package/dist/src/models/events.js.map +1 -0
- package/dist/src/models/friends.js +148 -0
- package/dist/src/models/friends.js.map +1 -0
- package/dist/src/models/groups.js +228 -0
- package/dist/src/models/groups.js.map +1 -0
- package/dist/src/models/instances.js +56 -0
- package/dist/src/models/instances.js.map +1 -0
- package/dist/src/models/invites.js +34 -0
- package/dist/src/models/invites.js.map +1 -0
- package/dist/src/models/notifications.js +62 -0
- package/dist/src/models/notifications.js.map +1 -0
- package/dist/src/models/status.js +50 -0
- package/dist/src/models/status.js.map +1 -0
- package/dist/src/models/statusPage.js +84 -0
- package/dist/src/models/statusPage.js.map +1 -0
- package/dist/src/models/users.js +113 -0
- package/dist/src/models/users.js.map +1 -0
- package/dist/src/models/vrcx.js +144 -0
- package/dist/src/models/vrcx.js.map +1 -0
- package/dist/src/models/worlds.js +150 -0
- package/dist/src/models/worlds.js.map +1 -0
- package/dist/src/resources/friendsChanges.js +44 -0
- package/dist/src/resources/friendsChanges.js.map +1 -0
- package/dist/src/resources/friendsSnapshot.js +69 -0
- package/dist/src/resources/friendsSnapshot.js.map +1 -0
- package/dist/src/resources/index.js +9 -0
- package/dist/src/resources/index.js.map +1 -0
- package/dist/src/resources/subscriptions.js +39 -0
- package/dist/src/resources/subscriptions.js.map +1 -0
- package/dist/src/schemas/auth.js +3 -0
- package/dist/src/schemas/auth.js.map +1 -0
- package/dist/src/schemas/call.js +13 -0
- package/dist/src/schemas/call.js.map +1 -0
- package/dist/src/schemas/read.js +58 -0
- package/dist/src/schemas/read.js.map +1 -0
- package/dist/src/schemas/write.js +18 -0
- package/dist/src/schemas/write.js.map +1 -0
- package/dist/src/services/api/client.js +66 -0
- package/dist/src/services/api/client.js.map +1 -0
- package/dist/src/services/api/index.js +2 -0
- package/dist/src/services/api/index.js.map +1 -0
- package/dist/src/services/avatars/index.js +24 -0
- package/dist/src/services/avatars/index.js.map +1 -0
- package/dist/src/services/cache.js +158 -0
- package/dist/src/services/cache.js.map +1 -0
- package/dist/src/services/events/curated.js +229 -0
- package/dist/src/services/events/curated.js.map +1 -0
- package/dist/src/services/events/index.js +3 -0
- package/dist/src/services/events/index.js.map +1 -0
- package/dist/src/services/events/utils.js +75 -0
- package/dist/src/services/events/utils.js.map +1 -0
- package/dist/src/services/friends/changes.js +246 -0
- package/dist/src/services/friends/changes.js.map +1 -0
- package/dist/src/services/friends/curated.js +497 -0
- package/dist/src/services/friends/curated.js.map +1 -0
- package/dist/src/services/friends/fetch.js +69 -0
- package/dist/src/services/friends/fetch.js.map +1 -0
- package/dist/src/services/friends/index.js +5 -0
- package/dist/src/services/friends/index.js.map +1 -0
- package/dist/src/services/friends/match.js +98 -0
- package/dist/src/services/friends/match.js.map +1 -0
- package/dist/src/services/groups/allowlist.js +19 -0
- package/dist/src/services/groups/allowlist.js.map +1 -0
- package/dist/src/services/groups/curated.js +343 -0
- package/dist/src/services/groups/curated.js.map +1 -0
- package/dist/src/services/groups/index.js +3 -0
- package/dist/src/services/groups/index.js.map +1 -0
- package/dist/src/services/instances/curated.js +80 -0
- package/dist/src/services/instances/curated.js.map +1 -0
- package/dist/src/services/instances/index.js +3 -0
- package/dist/src/services/instances/index.js.map +1 -0
- package/dist/src/services/instances/read.js +14 -0
- package/dist/src/services/instances/read.js.map +1 -0
- package/dist/src/services/invites/curated.js +90 -0
- package/dist/src/services/invites/curated.js.map +1 -0
- package/dist/src/services/invites/index.js +2 -0
- package/dist/src/services/invites/index.js.map +1 -0
- package/dist/src/services/notifications/curated.js +54 -0
- package/dist/src/services/notifications/curated.js.map +1 -0
- package/dist/src/services/notifications/index.js +2 -0
- package/dist/src/services/notifications/index.js.map +1 -0
- package/dist/src/services/pipeline/events.js +40 -0
- package/dist/src/services/pipeline/events.js.map +1 -0
- package/dist/src/services/pipeline/handlers.js +21 -0
- package/dist/src/services/pipeline/handlers.js.map +1 -0
- package/dist/src/services/pipeline/index.js +4 -0
- package/dist/src/services/pipeline/index.js.map +1 -0
- package/dist/src/services/pipeline/manager.js +143 -0
- package/dist/src/services/pipeline/manager.js.map +1 -0
- package/dist/src/services/status/curated.js +53 -0
- package/dist/src/services/status/curated.js.map +1 -0
- package/dist/src/services/status/index.js +2 -0
- package/dist/src/services/status/index.js.map +1 -0
- package/dist/src/services/statusPage/curated.js +397 -0
- package/dist/src/services/statusPage/curated.js.map +1 -0
- package/dist/src/services/statusPage/index.js +2 -0
- package/dist/src/services/statusPage/index.js.map +1 -0
- package/dist/src/services/users/curated.js +124 -0
- package/dist/src/services/users/curated.js.map +1 -0
- package/dist/src/services/users/groups.js +54 -0
- package/dist/src/services/users/groups.js.map +1 -0
- package/dist/src/services/users/index.js +3 -0
- package/dist/src/services/users/index.js.map +1 -0
- package/dist/src/services/vrcx/db.js +13 -0
- package/dist/src/services/vrcx/db.js.map +1 -0
- package/dist/src/services/vrcx/gamelog.js +125 -0
- package/dist/src/services/vrcx/gamelog.js.map +1 -0
- package/dist/src/services/vrcx/index.js +5 -0
- package/dist/src/services/vrcx/index.js.map +1 -0
- package/dist/src/services/vrcx/memos.js +51 -0
- package/dist/src/services/vrcx/memos.js.map +1 -0
- package/dist/src/services/vrcx/paths.js +133 -0
- package/dist/src/services/vrcx/paths.js.map +1 -0
- package/dist/src/services/vrcx/relationships.js +138 -0
- package/dist/src/services/vrcx/relationships.js.map +1 -0
- package/dist/src/services/vrcx/shared.js +173 -0
- package/dist/src/services/vrcx/shared.js.map +1 -0
- package/dist/src/services/vrcx/status.js +54 -0
- package/dist/src/services/vrcx/status.js.map +1 -0
- package/dist/src/services/worlds/index.js +256 -0
- package/dist/src/services/worlds/index.js.map +1 -0
- package/dist/src/tools/auth.js +44 -0
- package/dist/src/tools/auth.js.map +1 -0
- package/dist/src/tools/cache.js +61 -0
- package/dist/src/tools/cache.js.map +1 -0
- package/dist/src/tools/curated/avatars.js +57 -0
- package/dist/src/tools/curated/avatars.js.map +1 -0
- package/dist/src/tools/curated/events.js +212 -0
- package/dist/src/tools/curated/events.js.map +1 -0
- package/dist/src/tools/curated/friends.js +168 -0
- package/dist/src/tools/curated/friends.js.map +1 -0
- package/dist/src/tools/curated/groups.js +368 -0
- package/dist/src/tools/curated/groups.js.map +1 -0
- package/dist/src/tools/curated/instances.js +35 -0
- package/dist/src/tools/curated/instances.js.map +1 -0
- package/dist/src/tools/curated/invites.js +78 -0
- package/dist/src/tools/curated/invites.js.map +1 -0
- package/dist/src/tools/curated/notifications.js +35 -0
- package/dist/src/tools/curated/notifications.js.map +1 -0
- package/dist/src/tools/curated/status.js +44 -0
- package/dist/src/tools/curated/status.js.map +1 -0
- package/dist/src/tools/curated/statusPage.js +27 -0
- package/dist/src/tools/curated/statusPage.js.map +1 -0
- package/dist/src/tools/curated/users.js +201 -0
- package/dist/src/tools/curated/users.js.map +1 -0
- package/dist/src/tools/curated/vrcx/gamelog.js +80 -0
- package/dist/src/tools/curated/vrcx/gamelog.js.map +1 -0
- package/dist/src/tools/curated/vrcx/index.js +11 -0
- package/dist/src/tools/curated/vrcx/index.js.map +1 -0
- package/dist/src/tools/curated/vrcx/memos.js +105 -0
- package/dist/src/tools/curated/vrcx/memos.js.map +1 -0
- package/dist/src/tools/curated/vrcx/relationships.js +86 -0
- package/dist/src/tools/curated/vrcx/relationships.js.map +1 -0
- package/dist/src/tools/curated/vrcx/status.js +43 -0
- package/dist/src/tools/curated/vrcx/status.js.map +1 -0
- package/dist/src/tools/curated/worlds.js +162 -0
- package/dist/src/tools/curated/worlds.js.map +1 -0
- package/dist/src/tools/generated.js +19 -0
- package/dist/src/tools/generated.js.map +1 -0
- package/dist/src/tools/raw.js +49 -0
- package/dist/src/tools/raw.js.map +1 -0
- package/dist/src/tools/read/common.js +58 -0
- package/dist/src/tools/read/common.js.map +1 -0
- package/dist/src/tools/read/system.js +19 -0
- package/dist/src/tools/read/system.js.map +1 -0
- package/dist/src/tools/registerAllTools.js +41 -0
- package/dist/src/tools/registerAllTools.js.map +1 -0
- package/dist/src/tools/write/common.js +10 -0
- package/dist/src/tools/write/common.js.map +1 -0
- package/dist/src/utils/json.js +53 -0
- package/dist/src/utils/json.js.map +1 -0
- package/dist/src/utils/schema.js +14 -0
- package/dist/src/utils/schema.js.map +1 -0
- package/dist/src/utils/stableStringify.js +36 -0
- package/dist/src/utils/stableStringify.js.map +1 -0
- package/dist/src/utils/strings.js +7 -0
- package/dist/src/utils/strings.js.map +1 -0
- package/dist/src/utils/toolAnnotations.js +17 -0
- package/dist/src/utils/toolAnnotations.js.map +1 -0
- package/dist/src/utils/toolNames.js +13 -0
- package/dist/src/utils/toolNames.js.map +1 -0
- package/dist/src/utils/toolResponses.js +12 -0
- package/dist/src/utils/toolResponses.js.map +1 -0
- package/docs/architecture.md +46 -0
- package/docs/curated-tools.md +132 -0
- package/docs/design-notes.md +48 -0
- package/docs/evals.md +129 -0
- package/docs/tools-guide.md +27 -0
- package/docs/tools.md +13849 -0
- package/docs/vrcx.md +69 -0
- 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('<', '<')
|
|
29
|
+
.replaceAll('>', '>')
|
|
30
|
+
.replaceAll('"', '"')
|
|
31
|
+
.replaceAll("'", ''');
|
|
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":"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"}
|
|
@@ -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
|
+
}
|