@tgebrowser/mcp 1.0.6

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 (2) hide show
  1. package/build/server.js +1010 -0
  2. package/package.json +30 -0
@@ -0,0 +1,1010 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/server.ts
27
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
28
+ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
29
+
30
+ // ../core/src/client.ts
31
+ var import_axios = __toESM(require("axios"));
32
+ function parseArgs() {
33
+ const args = process.argv;
34
+ let port;
35
+ let apiKey;
36
+ for (let i = 0; i < args.length; i++) {
37
+ if (args[i] === "--port" && i + 1 < args.length) {
38
+ port = args[i + 1];
39
+ }
40
+ if (args[i] === "--api-key" && i + 1 < args.length) {
41
+ apiKey = args[i + 1];
42
+ }
43
+ }
44
+ return {
45
+ port: port || process.env.PORT || "50326",
46
+ apiKey: apiKey || process.env.API_KEY
47
+ };
48
+ }
49
+ var config = parseArgs();
50
+ var PORT = config.port;
51
+ var API_KEY = config.apiKey;
52
+ var BASE_URL = `http://127.0.0.1:${PORT}`;
53
+ var ENDPOINTS = {
54
+ STATUS: "/api/status",
55
+ START_BROWSER: "/api/browser/start",
56
+ CLOSE_BROWSER: "/api/browser/stop",
57
+ CREATE_BROWSER: "/api/browser/create",
58
+ UPDATE_BROWSER: "/api/browser/update",
59
+ DELETE_BROWSER: "/api/browser/delete",
60
+ GET_BROWSER_LIST: "/api/browser/list",
61
+ GET_BROWSER_DETAIL: "/api/browser/detail",
62
+ CLOSE_ALL_PROFILES: "/api/browser/stop-all",
63
+ DELETE_CACHE_V2: "/api/browser/cache/delete",
64
+ GET_OPENED_BROWSER: "/api/browser/open/list",
65
+ GET_GROUP_LIST: "/api/groups/list",
66
+ GET_PROXY_LIST: "/api/proxies/list"
67
+ };
68
+ var apiClient = import_axios.default.create({
69
+ baseURL: BASE_URL,
70
+ timeout: 1e4,
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ ...API_KEY ? { "Authorization": `Bearer ${API_KEY}` } : {}
74
+ }
75
+ });
76
+
77
+ // ../core/src/profile/actions.ts
78
+ function assertSuccess(data, action) {
79
+ if (data && data.success) return;
80
+ const message = data && typeof data.message === "string" ? data.message : "Unknown error";
81
+ throw new Error(`Failed to ${action}: ${message}`);
82
+ }
83
+ function buildBody(params) {
84
+ const body = {};
85
+ for (const [key, value] of Object.entries(params)) {
86
+ if (value === void 0) continue;
87
+ if (Array.isArray(value)) {
88
+ const mapped = value.map((item) => item && typeof item === "object" ? buildBody(item) : item).filter((v) => v !== void 0);
89
+ if (mapped.length > 0) body[key] = mapped;
90
+ } else if (value && typeof value === "object") {
91
+ body[key] = buildBody(value);
92
+ } else {
93
+ body[key] = value;
94
+ }
95
+ }
96
+ return body;
97
+ }
98
+ var profileActions = {
99
+ async open({ envId, userIndex, args, port }) {
100
+ const body = {};
101
+ if (envId !== void 0) body.envId = envId;
102
+ if (userIndex !== void 0) body.userIndex = userIndex;
103
+ if (args && args.length > 0) body.args = args;
104
+ if (port !== void 0) body.port = port;
105
+ const response = await apiClient.post(ENDPOINTS.START_BROWSER, body);
106
+ assertSuccess(response.data, "open browser");
107
+ const info = response.data.data || {};
108
+ const wsUrl = typeof info.ws === "object" ? info.ws?.puppeteer ?? info.ws?.selenium ?? JSON.stringify(info.ws) : info.ws;
109
+ return `Browser started: envId=${info.envId}, userIndex=${info.userIndex}, ws=${wsUrl}, http=${info.http}, port=${info.port}
110
+
111
+ To automate this browser, use connect-browser-with-ws with wsUrl="${wsUrl}"`;
112
+ },
113
+ async close({ envId, userIndex }) {
114
+ const body = {};
115
+ if (envId !== void 0) body.envId = envId;
116
+ if (userIndex !== void 0) body.userIndex = userIndex;
117
+ const response = await apiClient.post(ENDPOINTS.CLOSE_BROWSER, body);
118
+ assertSuccess(response.data, "close browser");
119
+ return "Browser closed successfully";
120
+ },
121
+ async create(params) {
122
+ const response = await apiClient.post(ENDPOINTS.CREATE_BROWSER, buildBody(params));
123
+ assertSuccess(response.data, "create browser");
124
+ const info = response.data.data || {};
125
+ return `Browser created: envId=${info.envId}, userIndex=${info.userIndex}`;
126
+ },
127
+ async update(params) {
128
+ const response = await apiClient.post(ENDPOINTS.UPDATE_BROWSER, buildBody(params));
129
+ assertSuccess(response.data, "update browser");
130
+ const info = response.data.data || {};
131
+ return `Browser updated: envId=${info.envId ?? params.envId}`;
132
+ },
133
+ async delete({ envId, userIndex }) {
134
+ const body = {};
135
+ if (envId !== void 0) body.envId = envId;
136
+ if (userIndex !== void 0) body.userIndex = userIndex;
137
+ const response = await apiClient.post(ENDPOINTS.DELETE_BROWSER, body);
138
+ assertSuccess(response.data, "delete browser");
139
+ return `Browser deleted: envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
140
+ },
141
+ async list(params) {
142
+ const searchParams = {};
143
+ if (params.current !== void 0) searchParams.current = params.current.toString();
144
+ if (params.pageSize !== void 0) searchParams.pageSize = params.pageSize.toString();
145
+ if (params.keyword) searchParams.keyword = params.keyword;
146
+ if (params.groupId !== void 0) searchParams.groupId = params.groupId.toString();
147
+ const response = await apiClient.get(ENDPOINTS.GET_BROWSER_LIST, { params: searchParams });
148
+ assertSuccess(response.data, "get browser list");
149
+ const raw = response.data.data || {};
150
+ const summary = {
151
+ total: raw.total,
152
+ current: raw.current,
153
+ pageSize: raw.pageSize,
154
+ list: (raw.list || []).map((item) => ({
155
+ envId: item.envId,
156
+ userIndex: item.userIndex,
157
+ browserName: item.browserName,
158
+ groupId: item.groupId,
159
+ remark: item.remark,
160
+ lastOpenedTime: item.lastOpenedTime
161
+ }))
162
+ };
163
+ return `Browser list: ${JSON.stringify(summary, null, 2)}`;
164
+ },
165
+ async openedList() {
166
+ const response = await apiClient.get(ENDPOINTS.GET_OPENED_BROWSER);
167
+ assertSuccess(response.data, "get opened browsers");
168
+ return `Opened browser list: ${JSON.stringify(response.data.data, null, 2)}`;
169
+ },
170
+ async getCookies({ envId, userIndex }) {
171
+ const body = {};
172
+ if (envId !== void 0) body.envId = envId;
173
+ if (userIndex !== void 0) body.userIndex = userIndex;
174
+ const response = await apiClient.post(ENDPOINTS.GET_BROWSER_DETAIL, body);
175
+ assertSuccess(response.data, "get profile cookies");
176
+ return `Profile cookies: ${JSON.stringify(response.data.data?.cookie, null, 2)}`;
177
+ },
178
+ async getUa({ envId, userIndex }) {
179
+ const body = {};
180
+ if (envId !== void 0) body.envId = envId;
181
+ if (userIndex !== void 0) body.userIndex = userIndex;
182
+ const response = await apiClient.post(ENDPOINTS.GET_BROWSER_DETAIL, body);
183
+ assertSuccess(response.data, "get profile User-Agent");
184
+ const ua = response.data.data?.fingerprint?.userAgent;
185
+ return `Profile User-Agent: ${ua ?? ""}`;
186
+ },
187
+ async closeAll() {
188
+ const response = await apiClient.post(ENDPOINTS.CLOSE_ALL_PROFILES, {});
189
+ assertSuccess(response.data, "close all browsers");
190
+ return "All browsers stopped successfully";
191
+ },
192
+ async newFingerprint({ envId, userIndex }) {
193
+ const body = {};
194
+ if (envId !== void 0) body.envId = envId;
195
+ if (userIndex !== void 0) body.userIndex = userIndex;
196
+ body.fingerprint = { randomFingerprint: true };
197
+ const response = await apiClient.post(ENDPOINTS.UPDATE_BROWSER, body);
198
+ assertSuccess(response.data, "refresh fingerprint");
199
+ return `Fingerprint updated for envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
200
+ },
201
+ async deleteCache({ envId, userIndex }) {
202
+ const body = {};
203
+ if (envId !== void 0) body.envId = envId;
204
+ if (userIndex !== void 0) body.userIndex = userIndex;
205
+ const response = await apiClient.post(ENDPOINTS.DELETE_CACHE_V2, body);
206
+ assertSuccess(response.data, "delete cache");
207
+ return `Cache deleted for envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
208
+ },
209
+ async getActive(_params) {
210
+ const response = await apiClient.get(ENDPOINTS.GET_OPENED_BROWSER);
211
+ assertSuccess(response.data, "get active browsers");
212
+ return `Active browsers: ${JSON.stringify(response.data.data, null, 2)}`;
213
+ }
214
+ };
215
+
216
+ // ../core/src/profile/schema.ts
217
+ var import_zod = require("zod");
218
+ var CHROME_VERSIONS = [
219
+ "133",
220
+ "135",
221
+ "137",
222
+ "139",
223
+ "141",
224
+ "143",
225
+ "ua_auto"
226
+ ];
227
+ var TLS_CIPHER_SUITES = {
228
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "0xC02C",
229
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "0xC030",
230
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "0xC02B",
231
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "0xC02F",
232
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: "0xCCA9",
233
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: "0xCCA8",
234
+ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: "0x009F",
235
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: "0x009E",
236
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: "0xC024",
237
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: "0xC028",
238
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "0xC00A",
239
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "0xC014",
240
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: "0x006B",
241
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA: "0x0039",
242
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "0xC023",
243
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "0xC027",
244
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "0xC009",
245
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "0xC013",
246
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: "0x0067",
247
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA: "0x0033",
248
+ TLS_RSA_WITH_AES_256_GCM_SHA384: "0x009D",
249
+ TLS_RSA_WITH_AES_128_GCM_SHA256: "0x009C",
250
+ TLS_RSA_WITH_AES_256_CBC_SHA256: "0x003D",
251
+ TLS_RSA_WITH_AES_128_CBC_SHA256: "0x003C",
252
+ TLS_RSA_WITH_AES_256_CBC_SHA: "0x0035",
253
+ TLS_RSA_WITH_AES_128_CBC_SHA: "0x002F",
254
+ TLS_AES_128_CCM_8_SHA256: "0x1305",
255
+ TLS_AES_128_CCM_SHA256: "0x1304"
256
+ };
257
+ var TLS_HEX_CODES = Object.values(TLS_CIPHER_SUITES);
258
+ var browserKernelConfigSchema = import_zod.z.object({
259
+ version: import_zod.z.union(
260
+ CHROME_VERSIONS.map((v) => import_zod.z.literal(v))
261
+ ).optional().describe("The version of the browser, supported: 133, 135, 137, 139, 141, 143, ua_auto"),
262
+ type: import_zod.z.literal("chrome").optional().describe("The type of the browser, only chrome is supported")
263
+ }).optional().superRefine((data, ctx) => {
264
+ if (!data) return;
265
+ const version = data.version;
266
+ if (version === void 0) return;
267
+ if (!CHROME_VERSIONS.includes(version)) {
268
+ ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: `Unsupported version "${version}". Supported: ${CHROME_VERSIONS.join(", ")}` });
269
+ }
270
+ });
271
+ var randomUaConfigSchema = import_zod.z.object({
272
+ ua_version: import_zod.z.array(import_zod.z.string()).optional(),
273
+ ua_system_version: import_zod.z.array(
274
+ import_zod.z.enum([
275
+ "Android 9",
276
+ "Android 10",
277
+ "Android 11",
278
+ "Android 12",
279
+ "Android 13",
280
+ "Android 14",
281
+ "Android 15",
282
+ "iOS 14",
283
+ "iOS 15",
284
+ "iOS 16",
285
+ "iOS 17",
286
+ "iOS 18",
287
+ "Windows 7",
288
+ "Windows 8",
289
+ "Windows 10",
290
+ "Windows 11",
291
+ "Mac OS X 10",
292
+ "Mac OS X 11",
293
+ "Mac OS X 12",
294
+ "Mac OS X 13",
295
+ "Mac OS X 14",
296
+ "Mac OS X 15",
297
+ "Mac OS X",
298
+ "Windows",
299
+ "iOS",
300
+ "Android",
301
+ "Linux"
302
+ ])
303
+ ).optional()
304
+ }).optional();
305
+ var webglConfigSchema = import_zod.z.object({
306
+ unmasked_vendor: import_zod.z.string().describe("WebGL vendor string. Required when webgl=2."),
307
+ unmasked_renderer: import_zod.z.string().describe("WebGL renderer string. Required when webgl=2."),
308
+ webgpu: import_zod.z.object({
309
+ webgpu_switch: import_zod.z.enum(["0", "1", "2"])
310
+ }).optional()
311
+ });
312
+ var macAddressConfigSchema = import_zod.z.object({
313
+ model: import_zod.z.enum(["0", "1", "2"]),
314
+ address: import_zod.z.string().optional()
315
+ });
316
+ var mediaDevicesNumSchema = import_zod.z.object({
317
+ audioinput_num: import_zod.z.string().regex(/^[1-9]$/),
318
+ videoinput_num: import_zod.z.string().regex(/^[1-9]$/),
319
+ audiooutput_num: import_zod.z.string().regex(/^[1-9]$/)
320
+ });
321
+ var sharedFingerprintFields = {
322
+ mobileDeviceId: import_zod.z.number().optional(),
323
+ platformVersion: import_zod.z.number().optional(),
324
+ kernel: import_zod.z.string().optional(),
325
+ userAgent: import_zod.z.string().optional(),
326
+ webrtc: import_zod.z.string().optional(),
327
+ resolution: import_zod.z.string().optional(),
328
+ windowWidth: import_zod.z.number().optional(),
329
+ windowHeight: import_zod.z.number().optional(),
330
+ language: import_zod.z.string().optional(),
331
+ languageBaseIp: import_zod.z.boolean().optional(),
332
+ uiLanguage: import_zod.z.string().optional(),
333
+ uiLanguageBaseIp: import_zod.z.boolean().optional(),
334
+ timezone: import_zod.z.string().optional(),
335
+ timezoneBaseIp: import_zod.z.boolean().optional(),
336
+ geolocationBaseIp: import_zod.z.boolean().optional(),
337
+ lng: import_zod.z.string().optional(),
338
+ lat: import_zod.z.string().optional(),
339
+ canvas: import_zod.z.boolean().optional(),
340
+ audioContext: import_zod.z.boolean().optional(),
341
+ speechVoices: import_zod.z.boolean().optional(),
342
+ clientRects: import_zod.z.boolean().optional(),
343
+ fonts: import_zod.z.array(import_zod.z.string()).optional(),
344
+ disableTLS: import_zod.z.array(import_zod.z.string()).optional(),
345
+ ram: import_zod.z.number().optional(),
346
+ cpu: import_zod.z.number().optional(),
347
+ hardwareAcceleration: import_zod.z.boolean().optional(),
348
+ disableSandbox: import_zod.z.boolean().optional(),
349
+ startupParams: import_zod.z.string().optional(),
350
+ deviceName: import_zod.z.string().optional(),
351
+ deviceMedia: import_zod.z.boolean().optional(),
352
+ portScanProtection: import_zod.z.string().optional(),
353
+ randomFingerprint: import_zod.z.boolean().optional(),
354
+ blockLargeImages: import_zod.z.boolean().optional(),
355
+ maxImageKB: import_zod.z.number().optional(),
356
+ syncCookies: import_zod.z.boolean().optional(),
357
+ clearCacheOnStart: import_zod.z.boolean().optional(),
358
+ clearCachePreserveExtensionsOnStart: import_zod.z.boolean().optional(),
359
+ clearCookiesOnStart: import_zod.z.boolean().optional(),
360
+ clearHistoryOnStart: import_zod.z.boolean().optional(),
361
+ disableMediaAutoplay: import_zod.z.boolean().optional(),
362
+ muteAllMedia: import_zod.z.boolean().optional(),
363
+ disableGoogleTranslate: import_zod.z.boolean().optional(),
364
+ disableSavePasswordPrompt: import_zod.z.boolean().optional(),
365
+ disableNotifications: import_zod.z.boolean().optional(),
366
+ blockClipboardRead: import_zod.z.boolean().optional(),
367
+ stopOnNetworkIssue: import_zod.z.boolean().optional(),
368
+ stopOnIPChange: import_zod.z.boolean().optional(),
369
+ stopOnCountryChange: import_zod.z.boolean().optional()
370
+ };
371
+ var sharedProxyFields = {
372
+ host: import_zod.z.string().optional(),
373
+ port: import_zod.z.number().optional(),
374
+ username: import_zod.z.string().optional(),
375
+ password: import_zod.z.string().optional(),
376
+ timezone: import_zod.z.string().optional(),
377
+ proxyId: import_zod.z.number().optional()
378
+ };
379
+ var startInfoSchema = import_zod.z.object({
380
+ startPage: import_zod.z.object({
381
+ mode: import_zod.z.string().optional(),
382
+ value: import_zod.z.array(import_zod.z.string()).optional()
383
+ }).optional(),
384
+ otherConfig: import_zod.z.object({
385
+ openConfigPage: import_zod.z.boolean().optional(),
386
+ checkPage: import_zod.z.boolean().optional(),
387
+ extensionTab: import_zod.z.boolean().optional()
388
+ }).optional()
389
+ }).optional();
390
+ var profileSchemas = {
391
+ create: import_zod.z.object({
392
+ browserName: import_zod.z.string().describe("Environment name"),
393
+ groupId: import_zod.z.number().optional().describe("Group id of the environment"),
394
+ remark: import_zod.z.string().optional().describe("Remark for the environment"),
395
+ proxy: import_zod.z.object({
396
+ protocol: import_zod.z.string().describe("Proxy protocol, e.g. http, socks5, direct"),
397
+ ...sharedProxyFields
398
+ }).optional(),
399
+ fingerprint: import_zod.z.object({
400
+ os: import_zod.z.string().describe("Operating system, e.g. Windows, macOS, Android, iOS"),
401
+ ...sharedFingerprintFields
402
+ }).optional(),
403
+ startInfo: startInfoSchema,
404
+ Cookie: import_zod.z.any().optional()
405
+ }),
406
+ update: import_zod.z.object({
407
+ envId: import_zod.z.number().optional().describe("Environment id to update"),
408
+ browserName: import_zod.z.string().optional().describe("Environment name"),
409
+ groupId: import_zod.z.number().optional().describe("Group id"),
410
+ remark: import_zod.z.string().optional().describe("Remark"),
411
+ proxy: import_zod.z.object({
412
+ protocol: import_zod.z.string().optional(),
413
+ ipChecker: import_zod.z.string().optional(),
414
+ ...sharedProxyFields
415
+ }).optional(),
416
+ fingerprint: import_zod.z.object({
417
+ os: import_zod.z.string().optional(),
418
+ ...sharedFingerprintFields
419
+ }).optional(),
420
+ Cookie: import_zod.z.any().optional(),
421
+ startInfo: startInfoSchema
422
+ }),
423
+ open: import_zod.z.object({
424
+ envId: import_zod.z.number().optional().describe("Environment id to start"),
425
+ userIndex: import_zod.z.number().optional().describe("Environment index to start"),
426
+ args: import_zod.z.array(import_zod.z.string()).optional().describe("Extra browser args"),
427
+ port: import_zod.z.number().optional().describe("Custom remote debugging port")
428
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
429
+ message: "Either envId or userIndex must be provided"
430
+ }),
431
+ close: import_zod.z.object({
432
+ envId: import_zod.z.number().optional().describe("Environment id to stop"),
433
+ userIndex: import_zod.z.number().optional().describe("Environment index to stop")
434
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
435
+ message: "Either envId or userIndex must be provided"
436
+ }),
437
+ delete: import_zod.z.object({
438
+ envId: import_zod.z.number().optional().describe("Environment id to delete"),
439
+ userIndex: import_zod.z.number().optional().describe("Environment index to delete")
440
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
441
+ message: "Either envId or userIndex must be provided"
442
+ }),
443
+ list: import_zod.z.object({
444
+ current: import_zod.z.number().optional().describe("Current page"),
445
+ pageSize: import_zod.z.number().optional().describe("Page size"),
446
+ keyword: import_zod.z.string().optional().describe("Search keyword"),
447
+ groupId: import_zod.z.number().optional().describe("Group id")
448
+ }).strict(),
449
+ cookies: import_zod.z.object({
450
+ envId: import_zod.z.number().optional().describe("Environment id"),
451
+ userIndex: import_zod.z.number().optional().describe("Environment index")
452
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
453
+ message: "Either envId or userIndex must be provided"
454
+ }),
455
+ ua: import_zod.z.object({
456
+ envId: import_zod.z.number().optional().describe("Environment id"),
457
+ userIndex: import_zod.z.number().optional().describe("Environment index")
458
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
459
+ message: "Either envId or userIndex must be provided"
460
+ }),
461
+ closeAll: import_zod.z.object({}).strict(),
462
+ newFingerprint: import_zod.z.object({
463
+ envId: import_zod.z.number().optional().describe("Environment id"),
464
+ userIndex: import_zod.z.number().optional().describe("Environment index")
465
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
466
+ message: "Either envId or userIndex must be provided"
467
+ }),
468
+ deleteCache: import_zod.z.object({
469
+ envId: import_zod.z.number().optional().describe("Environment id"),
470
+ userIndex: import_zod.z.number().optional().describe("Environment index")
471
+ }).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
472
+ message: "Either envId or userIndex must be provided"
473
+ }),
474
+ active: import_zod.z.object({
475
+ profileId: import_zod.z.string().optional().describe("The profile id"),
476
+ profileNo: import_zod.z.string().optional().describe("The profile number")
477
+ }).refine((data) => data.profileId || data.profileNo, {
478
+ message: "Either profileId or profileNo must be provided"
479
+ }),
480
+ openedList: import_zod.z.object({}).strict()
481
+ };
482
+
483
+ // ../core/src/automation/actions.ts
484
+ var import_path = __toESM(require("path"));
485
+ var import_os = __toESM(require("os"));
486
+
487
+ // ../core/src/automation/session.ts
488
+ var import_playwright = require("playwright");
489
+ var BrowserSession = class {
490
+ browser;
491
+ page;
492
+ screenshots;
493
+ constructor() {
494
+ this.browser = null;
495
+ this.page = null;
496
+ this.screenshots = /* @__PURE__ */ new Map();
497
+ }
498
+ get browserInstance() {
499
+ return this.browser;
500
+ }
501
+ get pageInstance() {
502
+ return this.page;
503
+ }
504
+ set pageInstance(page) {
505
+ this.page = page;
506
+ }
507
+ get screenshotsInstance() {
508
+ return this.screenshots;
509
+ }
510
+ checkConnected() {
511
+ const error = new Error("Browser not connected, please connect browser first");
512
+ if (!this.browser) throw error;
513
+ if (!this.browser.isConnected()) throw error;
514
+ if (!this.page) throw error;
515
+ }
516
+ async connectWithWs(wsUrl) {
517
+ this.browser = await import_playwright.chromium.connectOverCDP(wsUrl);
518
+ const defaultContext = this.browser.contexts()[0];
519
+ this.page = defaultContext.pages()[0];
520
+ await this.page.bringToFront().catch((error) => {
521
+ console.error("Failed to bring page to front", error);
522
+ });
523
+ }
524
+ async reset() {
525
+ this.browser = null;
526
+ this.page = null;
527
+ }
528
+ };
529
+ var session_default = new BrowserSession();
530
+
531
+ // ../core/src/automation/actions.ts
532
+ var defaultDownloadsPath = import_path.default.join(import_os.default.homedir(), "Downloads");
533
+ var automationActions = {
534
+ async connect({ wsUrl }) {
535
+ try {
536
+ await session_default.connectWithWs(wsUrl);
537
+ return `Browser connected successfully with: ${wsUrl}`;
538
+ } catch (error) {
539
+ return `Failed to connect browser with: ${error?.toString()}`;
540
+ }
541
+ },
542
+ async openNewPage() {
543
+ session_default.checkConnected();
544
+ const newPage = await session_default.pageInstance.context().newPage();
545
+ session_default.pageInstance = newPage;
546
+ return "New page opened successfully";
547
+ },
548
+ async navigate({ url }) {
549
+ session_default.checkConnected();
550
+ await session_default.pageInstance.goto(url);
551
+ return `Navigated to ${url} successfully`;
552
+ },
553
+ async screenshot({ savePath, isFullPage }) {
554
+ session_default.checkConnected();
555
+ const filename = `screenshot-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`;
556
+ const outputPath = import_path.default.join(savePath || defaultDownloadsPath, filename);
557
+ const screenshot = await session_default.pageInstance.screenshot({ path: outputPath, fullPage: isFullPage });
558
+ const screenshotBase64 = screenshot.toString("base64");
559
+ session_default.screenshotsInstance.set(filename, screenshotBase64);
560
+ return [{
561
+ type: "image",
562
+ data: screenshotBase64,
563
+ mimeType: "image/png"
564
+ }];
565
+ },
566
+ async getPageVisibleText() {
567
+ session_default.checkConnected();
568
+ try {
569
+ const visibleText = await session_default.pageInstance.evaluate(() => {
570
+ const walker = document.createTreeWalker(
571
+ document.body,
572
+ NodeFilter.SHOW_TEXT,
573
+ {
574
+ acceptNode: (node2) => {
575
+ const style = window.getComputedStyle(node2.parentElement);
576
+ return style.display !== "none" && style.visibility !== "hidden" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
577
+ }
578
+ }
579
+ );
580
+ let text = "";
581
+ let node;
582
+ while (node = walker.nextNode()) {
583
+ const trimmedText = node.textContent?.trim();
584
+ if (trimmedText) text += trimmedText + "\n";
585
+ }
586
+ return text.trim();
587
+ });
588
+ return `Visible text content:
589
+ ${visibleText}`;
590
+ } catch (error) {
591
+ return `Failed to get visible text content: ${error.message}`;
592
+ }
593
+ },
594
+ async getPageHtml() {
595
+ session_default.checkConnected();
596
+ return session_default.pageInstance.content();
597
+ },
598
+ async clickElement({ selector }) {
599
+ session_default.checkConnected();
600
+ await session_default.pageInstance.click(selector);
601
+ return `Clicked element with selector: ${selector} successfully`;
602
+ },
603
+ async iframeClickElement({ selector, iframeSelector }) {
604
+ session_default.checkConnected();
605
+ await session_default.pageInstance.waitForSelector(iframeSelector);
606
+ const frame = session_default.pageInstance.frameLocator(iframeSelector);
607
+ await frame.locator(selector).click();
608
+ return `Clicked element ${selector} inside iframe ${iframeSelector} successfully`;
609
+ },
610
+ async fillInput({ selector, text }) {
611
+ session_default.checkConnected();
612
+ await session_default.pageInstance.waitForSelector(selector);
613
+ await session_default.pageInstance.fill(selector, text);
614
+ return `Filled input with selector: ${selector} with text: ${text} successfully`;
615
+ },
616
+ async selectOption({ selector, value }) {
617
+ session_default.checkConnected();
618
+ await session_default.pageInstance.waitForSelector(selector);
619
+ await session_default.pageInstance.selectOption(selector, value);
620
+ return `Selected option with selector: ${selector} with value: ${value} successfully`;
621
+ },
622
+ async hoverElement({ selector }) {
623
+ session_default.checkConnected();
624
+ await session_default.pageInstance.waitForSelector(selector);
625
+ await session_default.pageInstance.hover(selector);
626
+ return `Hovered element with selector: ${selector} successfully`;
627
+ },
628
+ async scrollElement({ selector }) {
629
+ session_default.checkConnected();
630
+ await session_default.pageInstance.waitForSelector(selector);
631
+ await session_default.pageInstance.evaluate((sel) => {
632
+ document.querySelector(sel)?.scrollIntoView({ behavior: "smooth" });
633
+ }, selector);
634
+ return `Scrolled element with selector: ${selector} successfully`;
635
+ },
636
+ async pressKey({ key, selector }) {
637
+ session_default.checkConnected();
638
+ if (selector) {
639
+ await session_default.pageInstance.waitForSelector(selector);
640
+ await session_default.pageInstance.focus(selector);
641
+ }
642
+ await session_default.pageInstance.keyboard.press(key);
643
+ return `Pressed key: ${key} successfully`;
644
+ },
645
+ async evaluateScript({ script }) {
646
+ session_default.checkConnected();
647
+ return session_default.pageInstance.evaluate(script);
648
+ },
649
+ async dragElement({ selector, targetSelector }) {
650
+ session_default.checkConnected();
651
+ const sourceElement = await session_default.pageInstance.waitForSelector(selector);
652
+ const targetElement = await session_default.pageInstance.waitForSelector(targetSelector);
653
+ const sourceBound = await sourceElement.boundingBox();
654
+ const targetBound = await targetElement.boundingBox();
655
+ if (!sourceBound || !targetBound) {
656
+ return "Could not get element positions for drag operation";
657
+ }
658
+ await session_default.pageInstance.mouse.move(
659
+ sourceBound.x + sourceBound.width / 2,
660
+ sourceBound.y + sourceBound.height / 2
661
+ );
662
+ await session_default.pageInstance.mouse.down();
663
+ await session_default.pageInstance.mouse.move(
664
+ targetBound.x + targetBound.width / 2,
665
+ targetBound.y + targetBound.height / 2
666
+ );
667
+ await session_default.pageInstance.mouse.up();
668
+ return `Dragged element with selector: ${selector} to ${targetSelector} successfully`;
669
+ }
670
+ };
671
+
672
+ // ../core/src/automation/schema.ts
673
+ var import_zod2 = require("zod");
674
+ var automationSchemas = {
675
+ connect: import_zod2.z.object({
676
+ userId: import_zod2.z.string().optional().describe("The browser id of the browser to connect"),
677
+ serialNumber: import_zod2.z.string().optional().describe("The serial number of the browser to connect"),
678
+ wsUrl: import_zod2.z.string().describe("The ws url of the browser, get from the open-browser tool content `ws.puppeteer`")
679
+ }).strict(),
680
+ navigate: import_zod2.z.object({ url: import_zod2.z.string().describe("The url to navigate to") }).strict(),
681
+ screenshot: import_zod2.z.object({
682
+ savePath: import_zod2.z.string().optional().describe("The path to save the screenshot"),
683
+ isFullPage: import_zod2.z.boolean().optional().describe("The is full page of the screenshot")
684
+ }).strict(),
685
+ clickElement: import_zod2.z.object({ selector: import_zod2.z.string().describe("The selector of the element to click, find from the page source code") }).strict(),
686
+ fillInput: import_zod2.z.object({
687
+ selector: import_zod2.z.string().describe("The selector of the input to fill, find from the page source code"),
688
+ text: import_zod2.z.string().describe("The text to fill in the input")
689
+ }).strict(),
690
+ selectOption: import_zod2.z.object({
691
+ selector: import_zod2.z.string().describe("The selector of the option to select, find from the page source code"),
692
+ value: import_zod2.z.string().describe("The value of the option to select")
693
+ }).strict(),
694
+ hoverElement: import_zod2.z.object({ selector: import_zod2.z.string().describe("The selector of the element to hover, find from the page source code") }).strict(),
695
+ scrollElement: import_zod2.z.object({ selector: import_zod2.z.string().describe("The selector of the element to scroll, find from the page source code") }).strict(),
696
+ pressKey: import_zod2.z.object({
697
+ key: import_zod2.z.string().describe('The key to press, eg: "Enter"'),
698
+ selector: import_zod2.z.string().optional().describe("The selector of the element to press the key, find from the page source code")
699
+ }).strict(),
700
+ evaluateScript: import_zod2.z.object({ script: import_zod2.z.string().describe("The script to evaluate") }).strict(),
701
+ dragElement: import_zod2.z.object({
702
+ selector: import_zod2.z.string().describe("The selector of the element to drag, find from the page source code"),
703
+ targetSelector: import_zod2.z.string().describe("The selector of the element to drag to, find from the page source code")
704
+ }).strict(),
705
+ iframeClickElement: import_zod2.z.object({
706
+ selector: import_zod2.z.string().describe("The selector of the element to click, find from the page source code"),
707
+ iframeSelector: import_zod2.z.string().describe("The selector of the iframe to click, find from the page source code")
708
+ }).strict(),
709
+ empty: import_zod2.z.object({}).strict()
710
+ };
711
+
712
+ // ../core/src/group/actions.ts
713
+ function assertSuccess2(data, action) {
714
+ if (data && data.success) return;
715
+ const message = data && typeof data.message === "string" ? data.message : "Unknown error";
716
+ throw new Error(`Failed to ${action}: ${message}`);
717
+ }
718
+ var groupActions = {
719
+ async list({ current, pageSize }) {
720
+ const params = {};
721
+ if (current !== void 0) params.current = current.toString();
722
+ if (pageSize !== void 0) params.pageSize = pageSize.toString();
723
+ const response = await apiClient.get(ENDPOINTS.GET_GROUP_LIST, { params });
724
+ assertSuccess2(response.data, "get group list");
725
+ return `Group list: ${JSON.stringify(response.data.data, null, 2)}`;
726
+ }
727
+ };
728
+
729
+ // ../core/src/group/schema.ts
730
+ var import_zod3 = require("zod");
731
+ var groupSchemas = {
732
+ list: import_zod3.z.object({
733
+ current: import_zod3.z.number().optional().describe("Current page"),
734
+ pageSize: import_zod3.z.number().optional().describe("Page size")
735
+ }).strict()
736
+ };
737
+
738
+ // ../core/src/proxy/actions.ts
739
+ function assertSuccess3(data, action) {
740
+ if (data && data.success) return;
741
+ const message = data && typeof data.message === "string" ? data.message : "Unknown error";
742
+ throw new Error(`Failed to ${action}: ${message}`);
743
+ }
744
+ var proxyActions = {
745
+ async list({ current, pageSize }) {
746
+ const params = {};
747
+ if (current !== void 0) params.current = current.toString();
748
+ if (pageSize !== void 0) params.pageSize = pageSize.toString();
749
+ const response = await apiClient.get(ENDPOINTS.GET_PROXY_LIST, { params });
750
+ assertSuccess3(response.data, "get proxy list");
751
+ return `Proxy list: ${JSON.stringify(response.data.data, null, 2)}`;
752
+ }
753
+ };
754
+
755
+ // ../core/src/proxy/schema.ts
756
+ var import_zod4 = require("zod");
757
+ var proxySchemas = {
758
+ list: import_zod4.z.object({
759
+ current: import_zod4.z.number().optional().describe("Current page"),
760
+ pageSize: import_zod4.z.number().optional().describe("Page size")
761
+ }).strict()
762
+ };
763
+
764
+ // ../core/src/system/actions.ts
765
+ var systemActions = {
766
+ async checkStatus() {
767
+ const response = await apiClient.get(ENDPOINTS.STATUS);
768
+ return `Connection status: ${JSON.stringify(response.data, null, 2)}`;
769
+ }
770
+ };
771
+
772
+ // src/wrap.ts
773
+ function wrapHandler(handler) {
774
+ return async (params) => {
775
+ try {
776
+ const content = await handler(params);
777
+ if (typeof content === "string") {
778
+ return { content: [{ type: "text", text: content }] };
779
+ }
780
+ return { content };
781
+ } catch (error) {
782
+ let errorMessage = error instanceof Error ? error.message : String(error);
783
+ if (errorMessage.includes("Target page, context or browser has been closed") || errorMessage.includes("Target closed") || errorMessage.includes("Browser has been disconnected") || errorMessage.includes("Protocol error") || errorMessage.includes("Connection closed")) {
784
+ await session_default.reset();
785
+ errorMessage = `Browser connection error: ${errorMessage}. Connection has been reset - please retry the operation.`;
786
+ }
787
+ return { content: [{ type: "text", text: errorMessage }] };
788
+ }
789
+ };
790
+ }
791
+
792
+ // src/registry.ts
793
+ function schemaShape(schema) {
794
+ if ("shape" in schema && typeof schema.shape === "object" && schema.shape !== null) {
795
+ return schema.shape;
796
+ }
797
+ if ("_def" in schema) {
798
+ const def = schema._def;
799
+ if (def && "schema" in def) return schemaShape(def.schema);
800
+ }
801
+ throw new Error(`Cannot extract shape from schema: ${schema._def?.typeName || "unknown"}`);
802
+ }
803
+ function registerTools(server2) {
804
+ server2.tool(
805
+ "open-browser",
806
+ "Open the browser (environment/profile). Requires envId OR userIndex. Use get-browser-list first to find envId/userIndex. After opening, call connect-browser-with-ws with the returned ws URL to enable automation tools (navigate, screenshot, click, etc.)",
807
+ schemaShape(profileSchemas.open),
808
+ wrapHandler(profileActions.open)
809
+ );
810
+ server2.tool(
811
+ "close-browser",
812
+ "Close the browser",
813
+ schemaShape(profileSchemas.close),
814
+ wrapHandler(profileActions.close)
815
+ );
816
+ server2.tool(
817
+ "create-browser",
818
+ "Create a browser",
819
+ profileSchemas.create.shape,
820
+ wrapHandler(profileActions.create)
821
+ );
822
+ server2.tool(
823
+ "update-browser",
824
+ "Update the browser",
825
+ profileSchemas.update.shape,
826
+ wrapHandler(profileActions.update)
827
+ );
828
+ server2.tool(
829
+ "delete-browser",
830
+ "Delete the browser",
831
+ schemaShape(profileSchemas.delete),
832
+ wrapHandler(profileActions.delete)
833
+ );
834
+ server2.tool(
835
+ "get-browser-list",
836
+ "Get a summary list of browsers (envId, userIndex, browserName, groupId, remark, lastOpenedTime). Use pageSize to limit results. Use envId or userIndex from results to open a browser.",
837
+ profileSchemas.list.shape,
838
+ wrapHandler(profileActions.list)
839
+ );
840
+ server2.tool(
841
+ "get-opened-browser",
842
+ "Get the list of opened browsers",
843
+ automationSchemas.empty.shape,
844
+ wrapHandler(profileActions.openedList)
845
+ );
846
+ server2.tool(
847
+ "get-profile-cookies",
848
+ "Query and return cookies of the specified profile. Only one profile can be queried per request.",
849
+ schemaShape(profileSchemas.cookies),
850
+ wrapHandler(profileActions.getCookies)
851
+ );
852
+ server2.tool(
853
+ "get-profile-ua",
854
+ "Query and return the User-Agent of specified profiles. Up to 10 profiles can be queried per request.",
855
+ schemaShape(profileSchemas.ua),
856
+ wrapHandler(profileActions.getUa)
857
+ );
858
+ server2.tool(
859
+ "close-all-profiles",
860
+ "Close all opened profiles on the current device",
861
+ profileSchemas.closeAll.shape,
862
+ wrapHandler(profileActions.closeAll)
863
+ );
864
+ server2.tool(
865
+ "new-fingerprint",
866
+ "Generate a new fingerprint for specified profiles. Up to 10 profiles are supported per request.",
867
+ schemaShape(profileSchemas.newFingerprint),
868
+ wrapHandler(profileActions.newFingerprint)
869
+ );
870
+ server2.tool(
871
+ "delete-cache-v2",
872
+ "Clear local cache of specific profiles. For account security, please ensure that there are no open browsers on the device when using this interface.",
873
+ schemaShape(profileSchemas.deleteCache),
874
+ wrapHandler(profileActions.deleteCache)
875
+ );
876
+ server2.tool(
877
+ "get-browser-active",
878
+ "Get active browser profile information",
879
+ schemaShape(profileSchemas.active),
880
+ wrapHandler(profileActions.getActive)
881
+ );
882
+ server2.tool(
883
+ "get-group-list",
884
+ "Get the list of groups",
885
+ groupSchemas.list.shape,
886
+ wrapHandler(groupActions.list)
887
+ );
888
+ server2.tool(
889
+ "get-proxy-list",
890
+ "Get the list of proxies",
891
+ proxySchemas.list.shape,
892
+ wrapHandler(proxyActions.list)
893
+ );
894
+ server2.tool(
895
+ "check-status",
896
+ "Check the availability of the current device API interface (Connection Status)",
897
+ automationSchemas.empty.shape,
898
+ wrapHandler(systemActions.checkStatus)
899
+ );
900
+ server2.tool(
901
+ "connect-browser-with-ws",
902
+ "Connect to an opened browser via WebSocket CDP URL (obtained from open-browser result). Must be called before using any automation tools (navigate, screenshot, click, fill-input, etc.)",
903
+ automationSchemas.connect.shape,
904
+ wrapHandler(automationActions.connect)
905
+ );
906
+ server2.tool(
907
+ "open-new-page",
908
+ "Open a new page",
909
+ automationSchemas.empty.shape,
910
+ wrapHandler(automationActions.openNewPage)
911
+ );
912
+ server2.tool(
913
+ "navigate",
914
+ "Navigate to the url",
915
+ automationSchemas.navigate.shape,
916
+ wrapHandler(automationActions.navigate)
917
+ );
918
+ server2.tool(
919
+ "screenshot",
920
+ "Take a screenshot of the current page. savePath is the directory to save to (default: ~/Downloads). Returns the screenshot image.",
921
+ automationSchemas.screenshot.shape,
922
+ wrapHandler(automationActions.screenshot)
923
+ );
924
+ server2.tool(
925
+ "get-page-visible-text",
926
+ "Get the visible text content of the page",
927
+ automationSchemas.empty.shape,
928
+ wrapHandler(automationActions.getPageVisibleText)
929
+ );
930
+ server2.tool(
931
+ "get-page-html",
932
+ "Get the html content of the page",
933
+ automationSchemas.empty.shape,
934
+ wrapHandler(automationActions.getPageHtml)
935
+ );
936
+ server2.tool(
937
+ "click-element",
938
+ "Click the element",
939
+ automationSchemas.clickElement.shape,
940
+ wrapHandler(automationActions.clickElement)
941
+ );
942
+ server2.tool(
943
+ "fill-input",
944
+ "Fill the input",
945
+ automationSchemas.fillInput.shape,
946
+ wrapHandler(automationActions.fillInput)
947
+ );
948
+ server2.tool(
949
+ "select-option",
950
+ "Select the option",
951
+ automationSchemas.selectOption.shape,
952
+ wrapHandler(automationActions.selectOption)
953
+ );
954
+ server2.tool(
955
+ "hover-element",
956
+ "Hover the element",
957
+ automationSchemas.hoverElement.shape,
958
+ wrapHandler(automationActions.hoverElement)
959
+ );
960
+ server2.tool(
961
+ "scroll-element",
962
+ "Scroll the element",
963
+ automationSchemas.scrollElement.shape,
964
+ wrapHandler(automationActions.scrollElement)
965
+ );
966
+ server2.tool(
967
+ "press-key",
968
+ "Press the key",
969
+ automationSchemas.pressKey.shape,
970
+ wrapHandler(automationActions.pressKey)
971
+ );
972
+ server2.tool(
973
+ "evaluate-script",
974
+ "Evaluate the script",
975
+ automationSchemas.evaluateScript.shape,
976
+ wrapHandler(automationActions.evaluateScript)
977
+ );
978
+ server2.tool(
979
+ "drag-element",
980
+ "Drag the element",
981
+ automationSchemas.dragElement.shape,
982
+ wrapHandler(automationActions.dragElement)
983
+ );
984
+ server2.tool(
985
+ "iframe-click-element",
986
+ "Click the element in the iframe",
987
+ automationSchemas.iframeClickElement.shape,
988
+ wrapHandler(automationActions.iframeClickElement)
989
+ );
990
+ }
991
+
992
+ // src/server.ts
993
+ var server = new import_mcp.McpServer({
994
+ name: "tgebrowser-mcp-server",
995
+ version: "1.0.0",
996
+ capabilities: {
997
+ resources: {},
998
+ tools: {}
999
+ }
1000
+ });
1001
+ registerTools(server);
1002
+ async function main() {
1003
+ const transport = new import_stdio.StdioServerTransport();
1004
+ await server.connect(transport);
1005
+ console.error("TgeBrowser Local Api MCP Server running on stdio");
1006
+ }
1007
+ main().catch((error) => {
1008
+ console.error("Fatal error in main():", error);
1009
+ process.exit(1);
1010
+ });
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@tgebrowser/mcp",
3
+ "version": "1.0.6",
4
+ "main": "build/server.js",
5
+ "type": "commonjs",
6
+ "bin": {
7
+ "tgebrowser-local-api-mcp": "./build/server.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsup"
11
+ },
12
+ "dependencies": {
13
+ "@modelcontextprotocol/sdk": "^1.7.0",
14
+ "axios": "^1.8.4",
15
+ "playwright": "^1.51.1",
16
+ "zod": "^3.24.2"
17
+ },
18
+ "devDependencies": {
19
+ "@tgebrowser/core": "workspace:*",
20
+ "@types/node": "^22.13.13",
21
+ "typescript": "^5.8.2",
22
+ "tsup": "^8.5.1"
23
+ },
24
+ "engines": {
25
+ "node": ">=18.0.0"
26
+ },
27
+ "files": [
28
+ "build"
29
+ ]
30
+ }