@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,405 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ import { z } from 'zod';
5
+ import pkg from '../../package.json' with { type: 'json' };
6
+ import defaultsJson from './defaults.json' with { type: 'json' };
7
+ const DISABLED_ALLOWLIST_VALUES = new Set(['', '0', 'false', 'no', 'off']);
8
+ const ConfigBaseSchema = z
9
+ .object({
10
+ api: z
11
+ .object({
12
+ baseUrl: z.string().min(1),
13
+ userAgent: z.string().min(1),
14
+ })
15
+ .strict(),
16
+ spec: z
17
+ .object({
18
+ url: z.string().min(1),
19
+ })
20
+ .strict(),
21
+ logging: z
22
+ .object({
23
+ level: z.string().min(1),
24
+ })
25
+ .strict(),
26
+ auth: z
27
+ .object({
28
+ cookieStore: z.enum(['memory', 'file', 'keychain']),
29
+ cookieFile: z.string().min(1),
30
+ })
31
+ .strict(),
32
+ writes: z
33
+ .object({
34
+ allow: z.boolean(),
35
+ })
36
+ .strict(),
37
+ cache: z
38
+ .object({
39
+ enabled: z.boolean(),
40
+ ttlSeconds: z
41
+ .object({
42
+ friends: z.number().int().positive(),
43
+ userGroups: z.number().int().positive(),
44
+ groups: z.number().int().positive(),
45
+ notifications: z.number().int().positive(),
46
+ })
47
+ .strict(),
48
+ staleTtlSeconds: z
49
+ .object({
50
+ friends: z.number().int().positive(),
51
+ userGroups: z.number().int().positive(),
52
+ groups: z.number().int().positive(),
53
+ notifications: z.number().int().positive(),
54
+ })
55
+ .strict(),
56
+ })
57
+ .strict(),
58
+ pipeline: z
59
+ .object({
60
+ enabled: z.boolean(),
61
+ url: z.string().min(1),
62
+ reconnectMs: z.number().int().positive(),
63
+ changeBuffer: z.number().int().positive(),
64
+ userAgent: z.string(),
65
+ })
66
+ .strict(),
67
+ groups: z
68
+ .object({
69
+ allowlist: z.array(z.string()),
70
+ })
71
+ .strict(),
72
+ rawTools: z
73
+ .object({
74
+ enabled: z.boolean(),
75
+ })
76
+ .strict(),
77
+ generatedReadTools: z
78
+ .object({
79
+ disable: z.boolean(),
80
+ })
81
+ .strict(),
82
+ generatedWriteTools: z
83
+ .object({
84
+ disable: z.boolean(),
85
+ })
86
+ .strict(),
87
+ vrcx: z
88
+ .object({
89
+ enabled: z.boolean(),
90
+ databasePath: z.string(),
91
+ worldDbPath: z.string(),
92
+ })
93
+ .strict(),
94
+ })
95
+ .strict();
96
+ const ConfigSchema = ConfigBaseSchema.transform((config) => {
97
+ const next = structuredClone(config);
98
+ next.api.userAgent = applyTemplate(next.api.userAgent);
99
+ next.pipeline.userAgent = next.pipeline.userAgent?.trim()
100
+ ? applyTemplate(next.pipeline.userAgent)
101
+ : next.api.userAgent;
102
+ next.auth.cookieFile = expandHome(next.auth.cookieFile);
103
+ next.vrcx.databasePath = expandHome(next.vrcx.databasePath);
104
+ next.vrcx.worldDbPath = expandHome(next.vrcx.worldDbPath);
105
+ return next;
106
+ });
107
+ const defaults = ConfigSchema.parse(defaultsJson);
108
+ const EnvString = z.preprocess((value) => {
109
+ if (value === undefined)
110
+ return undefined;
111
+ if (typeof value !== 'string')
112
+ return value;
113
+ return value.trim();
114
+ }, z.string().min(1).optional());
115
+ const EnvLowercase = (schema) => z.preprocess((value) => {
116
+ if (value === undefined)
117
+ return undefined;
118
+ if (typeof value !== 'string')
119
+ return value;
120
+ return value.trim().toLowerCase();
121
+ }, schema);
122
+ const EnvBoolean = z.preprocess((value) => {
123
+ if (value === undefined)
124
+ return undefined;
125
+ if (typeof value !== 'string')
126
+ return value;
127
+ const trimmed = value.trim().toLowerCase();
128
+ if (['1', 'true', 'yes', 'on'].includes(trimmed))
129
+ return true;
130
+ if (['0', 'false', 'no', 'off'].includes(trimmed))
131
+ return false;
132
+ return value;
133
+ }, z.boolean().optional());
134
+ const EnvPositiveInt = z.preprocess((value) => {
135
+ if (value === undefined)
136
+ return undefined;
137
+ if (typeof value !== 'string')
138
+ return value;
139
+ const trimmed = value.trim();
140
+ if (!trimmed)
141
+ return value;
142
+ return Number(trimmed);
143
+ }, z.number().int().positive().optional());
144
+ const EnvAllowlist = z.preprocess((value) => {
145
+ if (value === undefined)
146
+ return undefined;
147
+ if (typeof value !== 'string')
148
+ return value;
149
+ const trimmed = value.trim();
150
+ if (!trimmed)
151
+ return [];
152
+ if (DISABLED_ALLOWLIST_VALUES.has(trimmed.toLowerCase()))
153
+ return [];
154
+ return trimmed
155
+ .split(/[,\n]/)
156
+ .map((entry) => entry.trim())
157
+ .filter(Boolean);
158
+ }, z.array(z.string()).optional());
159
+ const EnvSchema = z
160
+ .object({
161
+ VRCHAT_MCP_API_BASE: EnvString,
162
+ VRCHAT_MCP_USER_AGENT: EnvString,
163
+ VRCHAT_MCP_SPEC_URL: EnvString,
164
+ VRCHAT_MCP_LOG_LEVEL: EnvLowercase(z.enum(['debug', 'info', 'warn', 'error']).optional()),
165
+ VRCHAT_MCP_COOKIE_STORE: EnvLowercase(z.enum(['memory', 'file', 'keychain']).optional()),
166
+ VRCHAT_MCP_COOKIE_FILE: EnvString,
167
+ VRCHAT_MCP_ALLOW_WRITES: EnvBoolean,
168
+ VRCHAT_MCP_CACHE_ENABLED: EnvBoolean,
169
+ VRCHAT_MCP_CACHE_TTL_FRIENDS: EnvPositiveInt,
170
+ VRCHAT_MCP_CACHE_STALE_TTL_FRIENDS: EnvPositiveInt,
171
+ VRCHAT_MCP_CACHE_TTL_USER_GROUPS: EnvPositiveInt,
172
+ VRCHAT_MCP_CACHE_STALE_TTL_USER_GROUPS: EnvPositiveInt,
173
+ VRCHAT_MCP_CACHE_TTL_GROUPS: EnvPositiveInt,
174
+ VRCHAT_MCP_CACHE_STALE_TTL_GROUPS: EnvPositiveInt,
175
+ VRCHAT_MCP_CACHE_TTL_NOTIFICATIONS: EnvPositiveInt,
176
+ VRCHAT_MCP_CACHE_STALE_TTL_NOTIFICATIONS: EnvPositiveInt,
177
+ VRCHAT_MCP_PIPELINE_ENABLED: EnvBoolean,
178
+ VRCHAT_MCP_PIPELINE_URL: EnvString,
179
+ VRCHAT_MCP_PIPELINE_RECONNECT_MS: EnvPositiveInt,
180
+ VRCHAT_MCP_PIPELINE_CHANGE_BUFFER: EnvPositiveInt,
181
+ VRCHAT_MCP_GROUP_ALLOWLIST: EnvAllowlist,
182
+ VRCHAT_MCP_ENABLE_RAW_CALL: EnvBoolean,
183
+ VRCHAT_MCP_DISABLE_GENERATED_READ_TOOLS: EnvBoolean,
184
+ VRCHAT_MCP_DISABLE_GENERATED_WRITE_TOOLS: EnvBoolean,
185
+ })
186
+ .strict();
187
+ const ENV_KEYS = Object.keys(EnvSchema.shape);
188
+ let cachedBase = null;
189
+ let cachedConfigPath = null;
190
+ function expandHome(value) {
191
+ if (!value)
192
+ return value;
193
+ if (value.startsWith('~/') || value === '~') {
194
+ const rest = value.length > 2 ? value.slice(2) : '';
195
+ return path.join(os.homedir(), rest);
196
+ }
197
+ return value;
198
+ }
199
+ function resolveConfigFilePath() {
200
+ const raw = process.env.VRCHAT_MCP_CONFIG_FILE;
201
+ if (!raw)
202
+ return null;
203
+ const trimmed = raw.trim();
204
+ if (!trimmed)
205
+ return null;
206
+ return path.isAbsolute(trimmed) ? trimmed : path.resolve(process.cwd(), trimmed);
207
+ }
208
+ function readConfigFile(filePath) {
209
+ if (!filePath)
210
+ return {};
211
+ try {
212
+ const content = readFileSync(filePath, 'utf8');
213
+ const parsed = JSON.parse(content);
214
+ if (!isPlainObject(parsed)) {
215
+ throw new Error('Config file must contain a JSON object.');
216
+ }
217
+ return parsed;
218
+ }
219
+ catch (err) {
220
+ if (err.code === 'ENOENT')
221
+ return {};
222
+ throw err;
223
+ }
224
+ }
225
+ function isPlainObject(value) {
226
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
227
+ }
228
+ function mergeConfig(base, override) {
229
+ if (!isPlainObject(base) || !isPlainObject(override)) {
230
+ return (override ?? base);
231
+ }
232
+ const result = { ...base };
233
+ for (const [key, value] of Object.entries(override)) {
234
+ if (value === undefined)
235
+ continue;
236
+ const existing = base[key];
237
+ if (Array.isArray(value)) {
238
+ result[key] = value.slice();
239
+ }
240
+ else if (isPlainObject(value) && isPlainObject(existing)) {
241
+ result[key] = mergeConfig(existing, value);
242
+ }
243
+ else {
244
+ result[key] = value;
245
+ }
246
+ }
247
+ return result;
248
+ }
249
+ function applyTemplate(value) {
250
+ return value.replace('{version}', pkg.version ?? '0.0.0');
251
+ }
252
+ function applyApiEnvOverrides(overrides, env) {
253
+ if (env.VRCHAT_MCP_API_BASE) {
254
+ overrides.api = { ...overrides.api, baseUrl: env.VRCHAT_MCP_API_BASE };
255
+ }
256
+ if (env.VRCHAT_MCP_USER_AGENT) {
257
+ overrides.api = { ...overrides.api, userAgent: env.VRCHAT_MCP_USER_AGENT };
258
+ }
259
+ }
260
+ function applySpecEnvOverrides(overrides, env) {
261
+ if (env.VRCHAT_MCP_SPEC_URL) {
262
+ overrides.spec = { ...overrides.spec, url: env.VRCHAT_MCP_SPEC_URL };
263
+ }
264
+ }
265
+ function applyLoggingEnvOverrides(overrides, env) {
266
+ if (env.VRCHAT_MCP_LOG_LEVEL) {
267
+ overrides.logging = { ...overrides.logging, level: env.VRCHAT_MCP_LOG_LEVEL };
268
+ }
269
+ }
270
+ function applyAuthEnvOverrides(overrides, env) {
271
+ if (env.VRCHAT_MCP_COOKIE_STORE) {
272
+ overrides.auth = { ...overrides.auth, cookieStore: env.VRCHAT_MCP_COOKIE_STORE };
273
+ }
274
+ if (env.VRCHAT_MCP_COOKIE_FILE) {
275
+ overrides.auth = { ...overrides.auth, cookieFile: env.VRCHAT_MCP_COOKIE_FILE };
276
+ }
277
+ }
278
+ function applyWriteEnvOverrides(overrides, env) {
279
+ if (env.VRCHAT_MCP_ALLOW_WRITES !== undefined) {
280
+ overrides.writes = { allow: env.VRCHAT_MCP_ALLOW_WRITES };
281
+ }
282
+ }
283
+ function applyCacheEnvOverrides(overrides, env) {
284
+ const cacheOverrides = {};
285
+ const ttlOverrides = {};
286
+ const staleOverrides = {};
287
+ if (env.VRCHAT_MCP_CACHE_ENABLED !== undefined) {
288
+ cacheOverrides.enabled = env.VRCHAT_MCP_CACHE_ENABLED;
289
+ }
290
+ if (env.VRCHAT_MCP_CACHE_TTL_FRIENDS !== undefined)
291
+ ttlOverrides.friends = env.VRCHAT_MCP_CACHE_TTL_FRIENDS;
292
+ if (env.VRCHAT_MCP_CACHE_TTL_USER_GROUPS !== undefined)
293
+ ttlOverrides.userGroups = env.VRCHAT_MCP_CACHE_TTL_USER_GROUPS;
294
+ if (env.VRCHAT_MCP_CACHE_TTL_GROUPS !== undefined)
295
+ ttlOverrides.groups = env.VRCHAT_MCP_CACHE_TTL_GROUPS;
296
+ if (env.VRCHAT_MCP_CACHE_TTL_NOTIFICATIONS !== undefined)
297
+ ttlOverrides.notifications = env.VRCHAT_MCP_CACHE_TTL_NOTIFICATIONS;
298
+ if (env.VRCHAT_MCP_CACHE_STALE_TTL_FRIENDS !== undefined)
299
+ staleOverrides.friends = env.VRCHAT_MCP_CACHE_STALE_TTL_FRIENDS;
300
+ if (env.VRCHAT_MCP_CACHE_STALE_TTL_USER_GROUPS !== undefined)
301
+ staleOverrides.userGroups = env.VRCHAT_MCP_CACHE_STALE_TTL_USER_GROUPS;
302
+ if (env.VRCHAT_MCP_CACHE_STALE_TTL_GROUPS !== undefined)
303
+ staleOverrides.groups = env.VRCHAT_MCP_CACHE_STALE_TTL_GROUPS;
304
+ if (env.VRCHAT_MCP_CACHE_STALE_TTL_NOTIFICATIONS !== undefined)
305
+ staleOverrides.notifications = env.VRCHAT_MCP_CACHE_STALE_TTL_NOTIFICATIONS;
306
+ if (Object.keys(ttlOverrides).length > 0) {
307
+ cacheOverrides.ttlSeconds = ttlOverrides;
308
+ }
309
+ if (Object.keys(staleOverrides).length > 0) {
310
+ cacheOverrides.staleTtlSeconds = staleOverrides;
311
+ }
312
+ if (Object.keys(cacheOverrides).length > 0) {
313
+ overrides.cache = cacheOverrides;
314
+ }
315
+ }
316
+ function applyPipelineEnvOverrides(overrides, env) {
317
+ const pipelineOverrides = {};
318
+ if (env.VRCHAT_MCP_PIPELINE_ENABLED !== undefined) {
319
+ pipelineOverrides.enabled = env.VRCHAT_MCP_PIPELINE_ENABLED;
320
+ }
321
+ if (env.VRCHAT_MCP_PIPELINE_URL) {
322
+ pipelineOverrides.url = env.VRCHAT_MCP_PIPELINE_URL;
323
+ }
324
+ if (env.VRCHAT_MCP_PIPELINE_RECONNECT_MS !== undefined) {
325
+ pipelineOverrides.reconnectMs = env.VRCHAT_MCP_PIPELINE_RECONNECT_MS;
326
+ }
327
+ if (env.VRCHAT_MCP_PIPELINE_CHANGE_BUFFER !== undefined) {
328
+ pipelineOverrides.changeBuffer = env.VRCHAT_MCP_PIPELINE_CHANGE_BUFFER;
329
+ }
330
+ if (Object.keys(pipelineOverrides).length > 0) {
331
+ overrides.pipeline = pipelineOverrides;
332
+ }
333
+ }
334
+ function applyGroupEnvOverrides(overrides, env) {
335
+ if (env.VRCHAT_MCP_GROUP_ALLOWLIST !== undefined) {
336
+ overrides.groups = { allowlist: env.VRCHAT_MCP_GROUP_ALLOWLIST };
337
+ }
338
+ }
339
+ function applyToolingEnvOverrides(overrides, env) {
340
+ if (env.VRCHAT_MCP_ENABLE_RAW_CALL !== undefined) {
341
+ overrides.rawTools = { enabled: env.VRCHAT_MCP_ENABLE_RAW_CALL };
342
+ }
343
+ if (env.VRCHAT_MCP_DISABLE_GENERATED_READ_TOOLS !== undefined) {
344
+ overrides.generatedReadTools = {
345
+ ...overrides.generatedReadTools,
346
+ disable: env.VRCHAT_MCP_DISABLE_GENERATED_READ_TOOLS,
347
+ };
348
+ }
349
+ if (env.VRCHAT_MCP_DISABLE_GENERATED_WRITE_TOOLS !== undefined) {
350
+ overrides.generatedWriteTools = {
351
+ ...overrides.generatedWriteTools,
352
+ disable: env.VRCHAT_MCP_DISABLE_GENERATED_WRITE_TOOLS,
353
+ };
354
+ }
355
+ }
356
+ function readEnvOverrides() {
357
+ const envInput = {};
358
+ for (const key of ENV_KEYS) {
359
+ envInput[key] = process.env[key];
360
+ }
361
+ let env;
362
+ try {
363
+ env = EnvSchema.parse(envInput);
364
+ }
365
+ catch (err) {
366
+ if (err instanceof z.ZodError) {
367
+ const issues = err.issues.map((issue) => issue.path.join('.') || 'env');
368
+ throw new Error(`Invalid environment variables: ${issues.join(', ')}`);
369
+ }
370
+ throw err;
371
+ }
372
+ const overrides = {};
373
+ applyApiEnvOverrides(overrides, env);
374
+ applySpecEnvOverrides(overrides, env);
375
+ applyLoggingEnvOverrides(overrides, env);
376
+ applyAuthEnvOverrides(overrides, env);
377
+ applyWriteEnvOverrides(overrides, env);
378
+ applyCacheEnvOverrides(overrides, env);
379
+ applyPipelineEnvOverrides(overrides, env);
380
+ applyGroupEnvOverrides(overrides, env);
381
+ applyToolingEnvOverrides(overrides, env);
382
+ return {
383
+ overrides,
384
+ };
385
+ }
386
+ function loadBaseConfig() {
387
+ const configPath = resolveConfigFilePath();
388
+ if (cachedBase && cachedConfigPath === configPath)
389
+ return cachedBase;
390
+ const fileConfig = readConfigFile(configPath);
391
+ cachedBase = mergeConfig(defaults, fileConfig);
392
+ cachedConfigPath = configPath;
393
+ return cachedBase;
394
+ }
395
+ export function getConfig() {
396
+ const base = loadBaseConfig();
397
+ const { overrides } = readEnvOverrides();
398
+ const merged = mergeConfig(base, overrides);
399
+ return ConfigSchema.parse(merged);
400
+ }
401
+ export function resetConfigCacheForTest() {
402
+ cachedBase = null;
403
+ cachedConfigPath = null;
404
+ }
405
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,262 @@
1
+ import { authManager } from '../auth/index.js';
2
+ import { fetch, Headers } from 'undici';
3
+ import { getSpecIndex } from './spec.js';
4
+ import { getConfig } from '../config/index.js';
5
+ import { logger } from '../infra/logger.js';
6
+ import { checkGroupAllowed } from '../services/groups/index.js';
7
+ const config = getConfig();
8
+ const DEFAULT_BASE_URL = config.api.baseUrl;
9
+ const DEFAULT_USER_AGENT = config.api.userAgent;
10
+ export class CallError extends Error {
11
+ status;
12
+ payload;
13
+ constructor(message, status, payload) {
14
+ super(message);
15
+ this.name = 'CallError';
16
+ this.status = status;
17
+ this.payload = payload;
18
+ }
19
+ }
20
+ const ALLOW_WRITES = config.writes.allow;
21
+ function stringifyParam(value) {
22
+ if (typeof value === 'string')
23
+ return value;
24
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
25
+ return `${value}`;
26
+ }
27
+ if (typeof value === 'symbol')
28
+ return value.toString();
29
+ const json = JSON.stringify(value);
30
+ return json ?? '';
31
+ }
32
+ function coerceId(value) {
33
+ if (typeof value === 'string')
34
+ return value;
35
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
36
+ return `${value}`;
37
+ }
38
+ return undefined;
39
+ }
40
+ function extractGroupId(params, body) {
41
+ const paramGroupId = coerceId(params.groupId);
42
+ if (paramGroupId)
43
+ return paramGroupId;
44
+ if (body && typeof body === 'object' && 'groupId' in body) {
45
+ const bodyGroupId = coerceId(body.groupId);
46
+ if (bodyGroupId)
47
+ return bodyGroupId;
48
+ }
49
+ return undefined;
50
+ }
51
+ function extractCreateInstanceGroupId(body) {
52
+ if (!isRecord(body))
53
+ return undefined;
54
+ if (body.type !== 'group')
55
+ return undefined;
56
+ return coerceId(body.groupId) ?? coerceId(body.ownerId);
57
+ }
58
+ function isGroupOperation(op) {
59
+ if (op.path.includes('{groupId}'))
60
+ return true;
61
+ return op.parameters.some((param) => param.name === 'groupId');
62
+ }
63
+ function buildUrl(op, params = {}) {
64
+ let path = op.path;
65
+ const pathParams = op.parameters.filter((p) => p.in === 'path');
66
+ for (const p of pathParams) {
67
+ const val = params[p.name];
68
+ if (val === undefined || val === null) {
69
+ if (p.required) {
70
+ throw new CallError(`Missing required path param: ${p.name}`);
71
+ }
72
+ continue;
73
+ }
74
+ path = path.replace(`{${p.name}}`, encodeURIComponent(stringifyParam(val)));
75
+ }
76
+ const base = new URL(DEFAULT_BASE_URL);
77
+ const basePath = base.pathname.replace(/\/+$/, '');
78
+ const opPath = path.replace(/^\/+/, '');
79
+ base.pathname = `${basePath}/${opPath}`.replace(/\/{2,}/g, '/');
80
+ const url = base;
81
+ const queryParams = op.parameters.filter((p) => p.in === 'query');
82
+ for (const p of queryParams) {
83
+ const val = params[p.name];
84
+ if (val === undefined || val === null)
85
+ continue;
86
+ if (Array.isArray(val)) {
87
+ val.forEach((v) => url.searchParams.append(p.name, stringifyParam(v)));
88
+ }
89
+ else {
90
+ url.searchParams.append(p.name, stringifyParam(val));
91
+ }
92
+ }
93
+ return url.toString();
94
+ }
95
+ function buildHeaders(op, params = {}) {
96
+ const headers = new Headers();
97
+ headers.set('user-agent', DEFAULT_USER_AGENT);
98
+ const headerParams = op.parameters.filter((p) => p.in === 'header');
99
+ for (const p of headerParams) {
100
+ const val = params[p.name];
101
+ if (val === undefined || val === null)
102
+ continue;
103
+ headers.set(p.name, stringifyParam(val));
104
+ }
105
+ return headers;
106
+ }
107
+ function isRecord(value) {
108
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
109
+ }
110
+ function extractErrorMessage(data) {
111
+ if (!isRecord(data))
112
+ return undefined;
113
+ const nestedError = data.error;
114
+ if (isRecord(nestedError)) {
115
+ const nestedMessage = nestedError.message;
116
+ if (typeof nestedMessage === 'string')
117
+ return nestedMessage;
118
+ }
119
+ else if (typeof nestedError === 'string') {
120
+ return nestedError;
121
+ }
122
+ const topMessage = data.message;
123
+ if (typeof topMessage === 'string')
124
+ return topMessage;
125
+ return undefined;
126
+ }
127
+ function buildErrorPayload(params) {
128
+ const payload = {
129
+ status: params.status,
130
+ url: params.url,
131
+ error: params.data,
132
+ };
133
+ if (params.message)
134
+ payload.message = params.message;
135
+ return payload;
136
+ }
137
+ function getOperationOrThrow(index, operationId) {
138
+ const op = index.operations.get(operationId);
139
+ if (!op) {
140
+ throw new CallError(`Unknown operationId: ${operationId}`);
141
+ }
142
+ return op;
143
+ }
144
+ function validateOperationParams(op, params) {
145
+ const allowed = new Set(op.parameters.map((param) => param.name));
146
+ const unknown = Object.entries(params)
147
+ .filter(([, value]) => value !== undefined && value !== null)
148
+ .map(([key]) => key)
149
+ .filter((key) => !allowed.has(key));
150
+ if (unknown.length === 0)
151
+ return;
152
+ throw new CallError(`Unknown parameter(s) for ${op.operationId}: ${unknown.join(', ')}`);
153
+ }
154
+ function enforceOperationPolicy(op, params, body) {
155
+ if (!ALLOW_WRITES && op.method !== 'GET') {
156
+ throw new CallError(`Write operations are disabled (blocked ${op.method}). Enable writes in config (writes.allow).`);
157
+ }
158
+ if (op.method === 'GET')
159
+ return;
160
+ const groupId = isGroupOperation(op)
161
+ ? extractGroupId(params, body)
162
+ : op.operationId === 'createInstance'
163
+ ? extractCreateInstanceGroupId(body)
164
+ : undefined;
165
+ if (!groupId)
166
+ return;
167
+ const allowed = checkGroupAllowed(groupId);
168
+ if (!allowed.ok) {
169
+ throw new CallError(allowed.reason);
170
+ }
171
+ }
172
+ async function buildRequestInit(op, url, params, body) {
173
+ const headers = buildHeaders(op, params);
174
+ const cookieHeader = await authManager.getCookieHeader(url);
175
+ if (cookieHeader)
176
+ headers.set('cookie', cookieHeader);
177
+ const init = {
178
+ method: op.method,
179
+ headers,
180
+ };
181
+ if (op.hasRequestBody || body !== undefined) {
182
+ init.body = body !== undefined ? JSON.stringify(body) : undefined;
183
+ headers.set('content-type', 'application/json');
184
+ }
185
+ return init;
186
+ }
187
+ function parseResponseText(text) {
188
+ try {
189
+ return text ? JSON.parse(text) : null;
190
+ }
191
+ catch {
192
+ return text;
193
+ }
194
+ }
195
+ function headersToRecord(headers) {
196
+ const headersRecord = {};
197
+ headers.forEach((value, key) => {
198
+ headersRecord[key] = value;
199
+ });
200
+ return headersRecord;
201
+ }
202
+ async function storeCookiesFromResponse(url, res) {
203
+ const setCookieHeaders = res.headers.getSetCookie?.() ?? [];
204
+ if (!setCookieHeaders.length)
205
+ return;
206
+ await authManager.setCookiesFromResponse(url, setCookieHeaders);
207
+ }
208
+ function buildNonOkCallError(params) {
209
+ const isClientError = params.status >= 400 && params.status < 500;
210
+ const errorMessage = isClientError ? extractErrorMessage(params.data) : undefined;
211
+ const message = errorMessage
212
+ ? `VRChat API returned ${params.status}: ${errorMessage}`
213
+ : `VRChat API returned ${params.status}`;
214
+ const payload = isClientError
215
+ ? buildErrorPayload({
216
+ status: params.status,
217
+ url: params.url,
218
+ data: params.data,
219
+ message: errorMessage,
220
+ })
221
+ : undefined;
222
+ return new CallError(message, params.status, payload);
223
+ }
224
+ async function executeRequestWithHandling(input) {
225
+ try {
226
+ const res = await fetch(input.url, input.init);
227
+ const text = await res.text();
228
+ const data = parseResponseText(text);
229
+ const headersRecord = headersToRecord(res.headers);
230
+ await storeCookiesFromResponse(input.url, res);
231
+ if (input.options?.rawResponse) {
232
+ return { url: input.url, status: res.status, headers: headersRecord, data };
233
+ }
234
+ if (!res.ok) {
235
+ throw buildNonOkCallError({ status: res.status, url: input.url, data });
236
+ }
237
+ return { url: input.url, data };
238
+ }
239
+ catch (err) {
240
+ logger.error('callOperation failed', {
241
+ operationId: input.operationId,
242
+ message: err.message,
243
+ });
244
+ if (err instanceof CallError)
245
+ throw err;
246
+ throw new CallError('Network or fetch error');
247
+ }
248
+ }
249
+ export async function callOperation(input) {
250
+ const { operationId, params = {}, body, options } = input;
251
+ const index = await getSpecIndex();
252
+ const op = getOperationOrThrow(index, operationId);
253
+ validateOperationParams(op, params);
254
+ enforceOperationPolicy(op, params, body);
255
+ const url = buildUrl(op, params);
256
+ if (options?.dryRun) {
257
+ return { url, dryRun: true };
258
+ }
259
+ const init = await buildRequestInit(op, url, params, body);
260
+ return executeRequestWithHandling({ operationId, url, init, options });
261
+ }
262
+ //# sourceMappingURL=client.js.map