scrapeless-mcp-server 0.3.0 → 0.4.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/README.md +97 -14
- package/build/cf.js +27 -0
- package/build/config.js +7 -12
- package/build/context.js +120 -0
- package/build/index.js +10 -13
- package/build/server.js +55 -97
- package/build/session-manager.js +55 -0
- package/build/tools/browser/browser.js +444 -0
- package/build/tools/deepserp/googleFlights.js +188 -0
- package/build/tools/deepserp/googleScholar.js +74 -0
- package/build/tools/deepserp/googleSearch.js +269 -0
- package/build/tools/deepserp/googleTrends.js +208 -0
- package/build/tools/index.js +7 -0
- package/build/tools/universal/scrapeHtml.js +22 -0
- package/build/tools/universal/scrapeMarkdown.js +22 -0
- package/build/tools/universal/scrapeScreenshot.js +48 -0
- package/build/tools/utils.js +86 -0
- package/build/transport.js +120 -0
- package/package.json +11 -2
- package/build/client.js +0 -40
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineTool, wrapMcpBrowserResponse, snapshot } from "../utils.js";
|
|
3
|
+
export const browserCreate = defineTool({
|
|
4
|
+
name: "browser_create",
|
|
5
|
+
description: "Create or reuse a cloud browser session using Scrapeless. Updates the active session.",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
sessionId: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, a new session is created."),
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
export const browserClose = defineTool({
|
|
14
|
+
name: "browser_close",
|
|
15
|
+
description: "Closes the current session by disconnecting the cloud browser. This will terminate the recording for the session.",
|
|
16
|
+
inputSchema: {
|
|
17
|
+
sessionId: z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("The session ID to identify target browser. If not provided or invalid, you cannot close the session."),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
export const browserGoto = defineTool({
|
|
23
|
+
name: "browser_goto",
|
|
24
|
+
description: `Navigate browser to a specified URL.
|
|
25
|
+
Restrictions: Only for direct URL navigation, not for searches.
|
|
26
|
+
Valid: Go to https://google.com.
|
|
27
|
+
Invalid: Search for "cats" on Google (use google_search).`,
|
|
28
|
+
inputSchema: {
|
|
29
|
+
url: z
|
|
30
|
+
.string()
|
|
31
|
+
.url()
|
|
32
|
+
.describe("The URL to navigate to in the browser session."),
|
|
33
|
+
sessionId: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
37
|
+
},
|
|
38
|
+
handle: async (context, params) => {
|
|
39
|
+
const session = context.getSession(params.sessionId);
|
|
40
|
+
if (!session?.page) {
|
|
41
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
42
|
+
}
|
|
43
|
+
await session.page.goto(params.url);
|
|
44
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: `Navigated to ${params.url}`,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: accessibilitySnapshot
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
export const browserGoBack = defineTool({
|
|
60
|
+
name: "browser_go_back",
|
|
61
|
+
description: `Go back one step in browser history.
|
|
62
|
+
Restrictions: Only works if a previous page exists in the session history.
|
|
63
|
+
Valid: After navigating from page A to B, go back to A.
|
|
64
|
+
Invalid: Attempting to go back on the first page of a session.`,
|
|
65
|
+
inputSchema: {
|
|
66
|
+
sessionId: z
|
|
67
|
+
.string()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
70
|
+
},
|
|
71
|
+
handle: async (context, params) => {
|
|
72
|
+
const session = context.getSession(params.sessionId);
|
|
73
|
+
if (!session?.page) {
|
|
74
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
75
|
+
}
|
|
76
|
+
await session.page.goBack();
|
|
77
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: "Navigated back.",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
type: "text",
|
|
86
|
+
text: accessibilitySnapshot,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
export const browserGoForward = defineTool({
|
|
93
|
+
name: "browser_go_forward",
|
|
94
|
+
description: `Go forward one step in browser history.
|
|
95
|
+
Restrictions: Only works after a "go_back" action has been performed.
|
|
96
|
+
Valid: After going back from page B to A, go forward to B.
|
|
97
|
+
Invalid: Attempting to go forward without a preceding "go_back" action.`,
|
|
98
|
+
inputSchema: {
|
|
99
|
+
sessionId: z
|
|
100
|
+
.string()
|
|
101
|
+
.optional()
|
|
102
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
103
|
+
},
|
|
104
|
+
handle: async (context, params) => {
|
|
105
|
+
const session = context.getSession(params.sessionId);
|
|
106
|
+
if (!session?.page) {
|
|
107
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
108
|
+
}
|
|
109
|
+
await session.page.goForward();
|
|
110
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
111
|
+
return {
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: "Navigated forward.",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
type: "text",
|
|
119
|
+
text: accessibilitySnapshot,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
export const browserClick = defineTool({
|
|
126
|
+
name: "browser_click",
|
|
127
|
+
description: `Click a specific element on the page.
|
|
128
|
+
Restrictions: Requires a valid CSS selector for the target element.
|
|
129
|
+
Valid: Click the button with selector "#submit-button".
|
|
130
|
+
Invalid: Click "the login button" without providing a selector.`,
|
|
131
|
+
inputSchema: {
|
|
132
|
+
selector: z.string().describe("The CSS selector of the element to click."),
|
|
133
|
+
sessionId: z
|
|
134
|
+
.string()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
137
|
+
},
|
|
138
|
+
handle: async (context, params) => {
|
|
139
|
+
const session = context.getSession(params.sessionId);
|
|
140
|
+
if (!session?.page) {
|
|
141
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
await session.page.click(params.selector);
|
|
145
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{
|
|
149
|
+
type: "text",
|
|
150
|
+
text: `Clicked on element with selector ${params.selector}`
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
type: "text",
|
|
154
|
+
text: accessibilitySnapshot
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
return wrapMcpBrowserResponse(`Failed to click on element: ${error.message}`);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
export const browserType = defineTool({
|
|
165
|
+
name: "browser_type",
|
|
166
|
+
description: `Type text into a specified input field.
|
|
167
|
+
Restrictions: Requires a CSS selector for an input/textarea and the text to type.
|
|
168
|
+
Valid: Type "hello world" into input "[name='q']".
|
|
169
|
+
Invalid: Type "hello world" without specifying a target field.`,
|
|
170
|
+
inputSchema: {
|
|
171
|
+
selector: z.string().describe("CSS selector for the element to type into."),
|
|
172
|
+
text: z.string().describe("Text to type."),
|
|
173
|
+
sessionId: z
|
|
174
|
+
.string()
|
|
175
|
+
.optional()
|
|
176
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
177
|
+
},
|
|
178
|
+
handle: async (context, params) => {
|
|
179
|
+
const session = context.getSession(params.sessionId);
|
|
180
|
+
if (!session?.page) {
|
|
181
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
await session.page.type(params.selector, params.text);
|
|
185
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
186
|
+
return {
|
|
187
|
+
content: [
|
|
188
|
+
{
|
|
189
|
+
type: "text",
|
|
190
|
+
text: `Typed ${params.text} into element with selector ${params.selector}`
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
type: "text",
|
|
194
|
+
text: accessibilitySnapshot
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
return wrapMcpBrowserResponse(`Failed to type into element: ${error.message}`);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
export const browserWaitFor = defineTool({
|
|
205
|
+
name: "browser_wait_for",
|
|
206
|
+
description: `Wait for a specific page element to appear.
|
|
207
|
+
Restrictions: Requires a valid CSS selector for the element to wait for.
|
|
208
|
+
Valid: Wait for the element "#results" to become visible.
|
|
209
|
+
Invalid: Wait for "the results to load" without a selector.`,
|
|
210
|
+
inputSchema: {
|
|
211
|
+
selector: z.string().describe("CSS selector of the element to wait for."),
|
|
212
|
+
timeout: z
|
|
213
|
+
.number()
|
|
214
|
+
.optional()
|
|
215
|
+
.describe("Maximum time to wait in milliseconds (default: 30000)."),
|
|
216
|
+
sessionId: z
|
|
217
|
+
.string()
|
|
218
|
+
.optional()
|
|
219
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
220
|
+
},
|
|
221
|
+
handle: async (context, params) => {
|
|
222
|
+
const session = context.getSession(params.sessionId);
|
|
223
|
+
if (!session?.page) {
|
|
224
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
await session.page.waitForSelector(params.selector, {
|
|
228
|
+
timeout: params.timeout ?? 30000,
|
|
229
|
+
});
|
|
230
|
+
return wrapMcpBrowserResponse(`Successfully waited for element ${params.selector}`);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
return wrapMcpBrowserResponse(`Failed to wait for condition: ${error.message}`);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
export const browserWait = defineTool({
|
|
238
|
+
name: "browser_wait",
|
|
239
|
+
description: `Pause execution for a fixed duration.
|
|
240
|
+
Restrictions: Requires a duration in milliseconds. Should be used sparingly.
|
|
241
|
+
Valid: Wait for 2000 milliseconds.
|
|
242
|
+
Invalid: Wait for a page to finish loading (use "browser_wait_for")`,
|
|
243
|
+
inputSchema: {
|
|
244
|
+
time: z
|
|
245
|
+
.number()
|
|
246
|
+
.int()
|
|
247
|
+
.positive()
|
|
248
|
+
.describe("Time to wait in milliseconds (default: 30000)."),
|
|
249
|
+
sessionId: z
|
|
250
|
+
.string()
|
|
251
|
+
.optional()
|
|
252
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
253
|
+
},
|
|
254
|
+
handle: async (context, params) => {
|
|
255
|
+
await new Promise((resolve) => setTimeout(resolve, params.time ?? 30000));
|
|
256
|
+
return wrapMcpBrowserResponse(`Waited for ${params.time ?? 30000} milliseconds`);
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
export const browserScreenshot = defineTool({
|
|
260
|
+
name: "browser_screenshot",
|
|
261
|
+
description: `Capture a screenshot of the current page.
|
|
262
|
+
Restrictions: Can capture either the full page or the visible viewport.
|
|
263
|
+
Valid: Take a screenshot of the current browser view.
|
|
264
|
+
Invalid: Capture a screenshot of a specific element (not supported).`,
|
|
265
|
+
inputSchema: {
|
|
266
|
+
fullPage: z
|
|
267
|
+
.boolean()
|
|
268
|
+
.optional()
|
|
269
|
+
.describe([
|
|
270
|
+
"Whether to screenshot the full page (default: false)",
|
|
271
|
+
"You should avoid fullscreen if it's not important, since the " +
|
|
272
|
+
"images can be quite large",
|
|
273
|
+
].join("\n")),
|
|
274
|
+
sessionId: z
|
|
275
|
+
.string()
|
|
276
|
+
.optional()
|
|
277
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
278
|
+
},
|
|
279
|
+
handle: async (context, params) => {
|
|
280
|
+
const session = context.getSession(params.sessionId);
|
|
281
|
+
if (!session?.page) {
|
|
282
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const screenshot = await session.page.screenshot({
|
|
286
|
+
fullPage: params.fullPage ?? false,
|
|
287
|
+
});
|
|
288
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
289
|
+
return {
|
|
290
|
+
content: [
|
|
291
|
+
{
|
|
292
|
+
type: "image",
|
|
293
|
+
// @ts-ignore
|
|
294
|
+
data: screenshot.toString("base64"),
|
|
295
|
+
mimeType: "image/png",
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
type: "text",
|
|
299
|
+
text: accessibilitySnapshot,
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
return {
|
|
306
|
+
content: [],
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
export const browserGetHtml = defineTool({
|
|
312
|
+
name: "browser_get_html",
|
|
313
|
+
description: `Get the full HTML of the current page.
|
|
314
|
+
Restrictions: Returns the entire raw HTML source code.
|
|
315
|
+
Valid: Get the HTML of the current page to parse its structure.
|
|
316
|
+
Invalid: Get only the visible text (use "browser_get_text")`,
|
|
317
|
+
inputSchema: {
|
|
318
|
+
sessionId: z
|
|
319
|
+
.string()
|
|
320
|
+
.optional()
|
|
321
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
322
|
+
},
|
|
323
|
+
handle: async (context, params) => {
|
|
324
|
+
const session = context.getSession(params.sessionId);
|
|
325
|
+
if (!session?.page) {
|
|
326
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
327
|
+
}
|
|
328
|
+
try {
|
|
329
|
+
const html = await session.page.content();
|
|
330
|
+
return wrapMcpBrowserResponse(html);
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
return wrapMcpBrowserResponse(`Failed to retrieve HTML content: ${error.message}`);
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
export const browserGetText = defineTool({
|
|
338
|
+
name: "browser_get_text",
|
|
339
|
+
description: `Get all visible text from the current page.
|
|
340
|
+
Restrictions: Extracts only text content, ignoring HTML tags.
|
|
341
|
+
Valid: Get the text content of the current page for summarization.
|
|
342
|
+
Invalid: Get the page's HTML structure (use "browser_get_html")`,
|
|
343
|
+
inputSchema: {
|
|
344
|
+
sessionId: z
|
|
345
|
+
.string()
|
|
346
|
+
.optional()
|
|
347
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
348
|
+
},
|
|
349
|
+
handle: async (context, params) => {
|
|
350
|
+
const session = context.getSession(params.sessionId);
|
|
351
|
+
if (!session?.page) {
|
|
352
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
const text = await session.page.evaluate(() => document.body.innerText);
|
|
356
|
+
return wrapMcpBrowserResponse(text);
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
return wrapMcpBrowserResponse(`Failed to retrieve text content: ${error.message}`);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
export const browserScroll = defineTool({
|
|
364
|
+
name: "browser_scroll",
|
|
365
|
+
description: `Scroll the current page to a specific position.
|
|
366
|
+
Restrictions: Requires pixel coordinates for scrolling.
|
|
367
|
+
Valid: Scroll to the bottom of the page (e.g., { x: 0, y: 10000 }).
|
|
368
|
+
Invalid: Scroll to "the top" without specifying coordinates.`,
|
|
369
|
+
inputSchema: {
|
|
370
|
+
sessionId: z
|
|
371
|
+
.string()
|
|
372
|
+
.optional()
|
|
373
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
374
|
+
},
|
|
375
|
+
handle: async (context, params) => {
|
|
376
|
+
const session = context.getSession(params.sessionId);
|
|
377
|
+
if (!session?.page) {
|
|
378
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
379
|
+
}
|
|
380
|
+
try {
|
|
381
|
+
await session.page.evaluate(() => {
|
|
382
|
+
window.scrollTo(0, document.body.scrollHeight);
|
|
383
|
+
});
|
|
384
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
385
|
+
return {
|
|
386
|
+
content: [
|
|
387
|
+
{
|
|
388
|
+
type: "text",
|
|
389
|
+
text: `Scrolled to the bottom of the page.`,
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
type: "text",
|
|
393
|
+
text: accessibilitySnapshot,
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
return wrapMcpBrowserResponse(`Failed to scroll page: ${error.message}`);
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
export const browserScrollTo = defineTool({
|
|
404
|
+
name: "browser_scroll_to",
|
|
405
|
+
description: `Scroll a specific element into view.
|
|
406
|
+
Restrictions: Requires a valid CSS selector for the target element.
|
|
407
|
+
Valid: Scroll to the element "#footer".
|
|
408
|
+
Invalid: Scroll to the bottom of the page (use "browser_scroll").`,
|
|
409
|
+
inputSchema: {
|
|
410
|
+
x: z.number().describe("X coordinate to scroll to."),
|
|
411
|
+
y: z.number().describe("Y coordinate to scroll to."),
|
|
412
|
+
sessionId: z
|
|
413
|
+
.string()
|
|
414
|
+
.optional()
|
|
415
|
+
.describe("Optional session ID to use/reuse. If not provided or invalid, the active session is used."),
|
|
416
|
+
},
|
|
417
|
+
handle: async (context, params) => {
|
|
418
|
+
const session = context.getSession(params.sessionId);
|
|
419
|
+
if (!session?.page) {
|
|
420
|
+
return wrapMcpBrowserResponse("No active browser session found. Please create a browser session first.");
|
|
421
|
+
}
|
|
422
|
+
try {
|
|
423
|
+
await session.page.evaluate((x, y) => {
|
|
424
|
+
window.scrollTo(x, y);
|
|
425
|
+
}, params.x, params.y);
|
|
426
|
+
const accessibilitySnapshot = await snapshot(session.page);
|
|
427
|
+
return {
|
|
428
|
+
content: [
|
|
429
|
+
{
|
|
430
|
+
type: "text",
|
|
431
|
+
text: `Scrolled to position (${params.x}, ${params.y})`,
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
type: "text",
|
|
435
|
+
text: accessibilitySnapshot,
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
return wrapMcpBrowserResponse(`Failed to scroll page: ${error.message}`);
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { defineTool, wrapMcpResponse } from "../utils.js";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
export const googleFlights = defineTool({
|
|
4
|
+
name: 'google_flights',
|
|
5
|
+
description: `Exclusive Flight Information Query Tool.
|
|
6
|
+
Activated only when requests include departure city, arrival city, and specific date/date range.
|
|
7
|
+
Valid:Check flights from Beijing to Shanghai on July 15.
|
|
8
|
+
Invalid:Compare airline service quality (use google-search instead)`,
|
|
9
|
+
inputSchema: {
|
|
10
|
+
gl: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe("Parameter defines the country to use for the Google search. It's a two-letter country code. (e.g., us for the United States, uk for United Kingdom, or fr for France).")
|
|
13
|
+
.default('us'),
|
|
14
|
+
hl: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("Parameter defines the language to use for the Google search. It's a two-letter language code. (e.g., en for English, es for Spanish, or fr for French).")
|
|
17
|
+
.default('en'),
|
|
18
|
+
currency: z
|
|
19
|
+
.union([
|
|
20
|
+
z.literal('ALL'),
|
|
21
|
+
z.literal('DZD'),
|
|
22
|
+
z.literal('ARS'),
|
|
23
|
+
z.literal('AMD'),
|
|
24
|
+
z.literal('AWG'),
|
|
25
|
+
z.literal('AUD'),
|
|
26
|
+
z.literal('AZN'),
|
|
27
|
+
z.literal('BSD'),
|
|
28
|
+
z.literal('BHD'),
|
|
29
|
+
z.literal('BYN'),
|
|
30
|
+
z.literal('BMD'),
|
|
31
|
+
z.literal('BAM'),
|
|
32
|
+
z.literal('BRL'),
|
|
33
|
+
z.literal('GBP'),
|
|
34
|
+
z.literal('BGN'),
|
|
35
|
+
z.literal('XPF'),
|
|
36
|
+
z.literal('CAD'),
|
|
37
|
+
z.literal('CLP'),
|
|
38
|
+
z.literal('CNY'),
|
|
39
|
+
z.literal('COP'),
|
|
40
|
+
z.literal('CRC'),
|
|
41
|
+
z.literal('CUP'),
|
|
42
|
+
z.literal('CZK'),
|
|
43
|
+
z.literal('DKK'),
|
|
44
|
+
z.literal('DOP'),
|
|
45
|
+
z.literal('EGP'),
|
|
46
|
+
z.literal('EUR'),
|
|
47
|
+
z.literal('GEL'),
|
|
48
|
+
z.literal('HKD'),
|
|
49
|
+
z.literal('HUF'),
|
|
50
|
+
z.literal('ISK'),
|
|
51
|
+
z.literal('INR'),
|
|
52
|
+
z.literal('IDR'),
|
|
53
|
+
z.literal('IRR'),
|
|
54
|
+
z.literal('ILS'),
|
|
55
|
+
z.literal('JMD'),
|
|
56
|
+
z.literal('JPY'),
|
|
57
|
+
z.literal('JOD'),
|
|
58
|
+
z.literal('KZT'),
|
|
59
|
+
z.literal('KWD'),
|
|
60
|
+
z.literal('LBP'),
|
|
61
|
+
z.literal('MKD'),
|
|
62
|
+
z.literal('MYR'),
|
|
63
|
+
z.literal('MXN'),
|
|
64
|
+
z.literal('MDL'),
|
|
65
|
+
z.literal('MAD'),
|
|
66
|
+
z.literal('TWD'),
|
|
67
|
+
z.literal('NZD'),
|
|
68
|
+
z.literal('NOK'),
|
|
69
|
+
z.literal('OMR'),
|
|
70
|
+
z.literal('PKR'),
|
|
71
|
+
z.literal('PAB'),
|
|
72
|
+
z.literal('PEN'),
|
|
73
|
+
z.literal('PHP'),
|
|
74
|
+
z.literal('PLN'),
|
|
75
|
+
z.literal('QAR'),
|
|
76
|
+
z.literal('RON'),
|
|
77
|
+
z.literal('RUB'),
|
|
78
|
+
z.literal('SAR'),
|
|
79
|
+
z.literal('RSD'),
|
|
80
|
+
z.literal('SGD'),
|
|
81
|
+
z.literal('ZAR'),
|
|
82
|
+
z.literal('KRW'),
|
|
83
|
+
z.literal('SEK'),
|
|
84
|
+
z.literal('CHF'),
|
|
85
|
+
z.literal('THB'),
|
|
86
|
+
z.literal('TRY'),
|
|
87
|
+
z.literal('USD'),
|
|
88
|
+
z.literal('UAH'),
|
|
89
|
+
z.literal('AED'),
|
|
90
|
+
z.literal('VND')
|
|
91
|
+
])
|
|
92
|
+
.describe('Parameter defines the currency of the returned prices. Default to USD.')
|
|
93
|
+
.optional(),
|
|
94
|
+
departure_id: z
|
|
95
|
+
.string()
|
|
96
|
+
.describe('Departure airport code or location kgmid. An airport code is an uppercase 3-letter code. You can search for it on Google Flights or IATA. For example, CDG is Paris Charles de Gaulle Airport, /m/0vzm is the location kgmid for Austin.You can specify multiple departure airports by separating them with a comma. For example, CDG,ORY,/m/04jpl.')
|
|
97
|
+
.default('ORY'),
|
|
98
|
+
arrival_id: z
|
|
99
|
+
.string()
|
|
100
|
+
.describe('An airport code is an uppercase 3-letter code. You can search for it on Google Flights or IATA.')
|
|
101
|
+
.default('BCN'),
|
|
102
|
+
data_type: z
|
|
103
|
+
.number()
|
|
104
|
+
.describe('Parameter defines the type of the flights.\nAvailable options:\n1 - Round trip (default)\n2 - One way\n3 - Multi-city\n\nWhen this parameter is set to 3, use multi_city_json to set the flight information.\n\nTo obtain the returning flight information for Round Trip (1), you need to make another request using a departure_token.')
|
|
105
|
+
.default(1),
|
|
106
|
+
travel_class: z
|
|
107
|
+
.union([
|
|
108
|
+
z.literal(1).describe('Economy(default) - 1'),
|
|
109
|
+
z.literal(2).describe('Premium economy - 2'),
|
|
110
|
+
z.literal(3).describe('Business - 3'),
|
|
111
|
+
z.literal(4).describe('First - 4')
|
|
112
|
+
])
|
|
113
|
+
.describe('Parameter defines the travel class.\nAvailable options:\n1 - Economy (default)\n2 - Premium economy\n3 - Business\n4 - First')
|
|
114
|
+
.default(1),
|
|
115
|
+
multi_city_json: z
|
|
116
|
+
.any()
|
|
117
|
+
.describe("Parameter defines the flight information for multi-city flights. It's a JSON string containing multiple flight information objects. Each object should contain the following fields: departure_id, arrival_id, date, times (optional). See schema for details.")
|
|
118
|
+
.optional(),
|
|
119
|
+
adults: z.number().describe('Parameter defines the number of adults. Default to 1.').default(1),
|
|
120
|
+
children: z.number().describe('Parameter defines the number of children. Default to 0.').default(0),
|
|
121
|
+
infants_in_seat: z.number().describe('Parameter defines the number of infants in seat. Default to 0.').default(0),
|
|
122
|
+
infants_on_lap: z.number().describe('Parameter defines the number of infants on lap. Default to 0.').default(0),
|
|
123
|
+
outbound_date: z
|
|
124
|
+
.string()
|
|
125
|
+
.describe('Parameter defines the outbound date. The format is YYYY-MM-DD. e.g. 2025-03-09')
|
|
126
|
+
.default('next_1d'),
|
|
127
|
+
return_date: z
|
|
128
|
+
.string()
|
|
129
|
+
.describe('Parameter defines the return date. The format is YYYY-MM-DD. e.g. 2025-03-15\n\nParameter is required if type parameter is set to: 1 (Round trip)')
|
|
130
|
+
.default('next_1w'),
|
|
131
|
+
stops: z
|
|
132
|
+
.union([
|
|
133
|
+
z.literal(0).describe('Any number of stops (default) - 0'),
|
|
134
|
+
z.literal(1).describe('Nonstop only - 1'),
|
|
135
|
+
z.literal(2).describe('1 stop or fewer - 2'),
|
|
136
|
+
z.literal(3).describe('2 stops or fewer - 3')
|
|
137
|
+
])
|
|
138
|
+
.describe('Parameter defines the number of stops during the flight.\nAvailable options:\n0 - Any number of stops (default)\n1 - Nonstop only\n2 - 1 stop or fewer\n3 - 2 stops or fewer')
|
|
139
|
+
.default(0),
|
|
140
|
+
include_airlines: z
|
|
141
|
+
.string()
|
|
142
|
+
.describe("Parameter defines the airline codes to be included. Split multiple airlines with comma. It can't be used together with exclude_airlines. Each airline code should be a 2-character IATA code consisting of either two uppercase letters or one uppercase letter and one digit. Alliances can also be included. See schema for details.")
|
|
143
|
+
.optional()
|
|
144
|
+
.optional(),
|
|
145
|
+
bags: z.number().describe('Parameter defines the number of carry-on bags. Default to 0.').default(0),
|
|
146
|
+
max_price: z.number().describe('Parameter defines the maximum ticket price. Default to unlimited.').default(0),
|
|
147
|
+
outbound_times: z
|
|
148
|
+
.string()
|
|
149
|
+
.describe('Parameter defines the outbound times range. See schema for details.')
|
|
150
|
+
.optional()
|
|
151
|
+
.optional(),
|
|
152
|
+
return_times: z
|
|
153
|
+
.string()
|
|
154
|
+
.describe('Parameter defines the return times range. See schema for details.')
|
|
155
|
+
.optional()
|
|
156
|
+
.optional(),
|
|
157
|
+
emissions: z
|
|
158
|
+
.union([z.literal(0).describe('reset'), z.literal(1).describe('Less emissions only - ·')])
|
|
159
|
+
.describe('Parameter defines the emission level of the flight.\nAvailable options:\n1 - Less emissions only')
|
|
160
|
+
.default(0),
|
|
161
|
+
layover_duration: z
|
|
162
|
+
.string()
|
|
163
|
+
.describe("Parameter defines the layover duration, in minutes. It's a string containing two comma-separated numbers. See schema for details.")
|
|
164
|
+
.optional()
|
|
165
|
+
.optional(),
|
|
166
|
+
exclude_conns: z
|
|
167
|
+
.string()
|
|
168
|
+
.describe('Parameter defines the connecting airport codes to be excluded. See schema for details.')
|
|
169
|
+
.optional()
|
|
170
|
+
.optional(),
|
|
171
|
+
max_duration: z
|
|
172
|
+
.number()
|
|
173
|
+
.describe('Parameter defines the maximum flight duration, in minutes. For example, specify 1500 for 25 hours.')
|
|
174
|
+
.default(0)
|
|
175
|
+
.optional(),
|
|
176
|
+
departure_token: z
|
|
177
|
+
.string()
|
|
178
|
+
.describe('Parameter is used to select the flight and get returning flights (for Round trip) or flights for the next leg of itinerary (for Multi-city). Find this token in the departure flight results.')
|
|
179
|
+
.optional()
|
|
180
|
+
.optional()
|
|
181
|
+
},
|
|
182
|
+
handle: async (params, client) => {
|
|
183
|
+
return wrapMcpResponse(() => client.deepserp.scrape({
|
|
184
|
+
actor: 'scraper.google.flights',
|
|
185
|
+
input: params
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
});
|