one-search-mcp 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 zac_ma.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # 🚀 OneSearch MCP Server: Web Search & Crawl & Scraper & Extract
2
+
3
+ A Model Context Protocol (MCP) server implementation that integrates with Searxng/Firecrawl/Tavily for web search and scraping capabilities.
4
+
5
+ ## Features
6
+
7
+ - Web Search, scrape, crawl and extract content from websites.
8
+ - Support multiple search engines and web scrapers: SearXNG, Firecrawl, Tavily, etc.
9
+ - Support for self-hosted: SearXNG, Firecrawl, etc. (see [Deploy](./deploy/README.md))
10
+
11
+ ## Installation
12
+
13
+ ```shell
14
+ npm install -g one-search-mcp
15
+ ```
16
+
17
+ ```shell
18
+ # Running with npx
19
+ env SEARCH_API_KEY=YOUR_API_KEY SEARCH_API_URL=YOUR_API_URL npx -y one-search-mcp
20
+ ```
21
+
22
+ ## Self-host
23
+
24
+ Local deployment of Searxng and Firecrawl, please refer to [Deploy](./deploy/README.md)
25
+
26
+ ## License
27
+
28
+ MIT License - see [LICENSE](./LICENSE) file for details.
package/dist/index.cjs ADDED
@@ -0,0 +1,518 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // src/index.ts
27
+ var index_exports = {};
28
+ module.exports = __toCommonJS(index_exports);
29
+ var import_server = require("@modelcontextprotocol/sdk/server/index.js");
30
+ var import_types = require("@modelcontextprotocol/sdk/types.js");
31
+
32
+ // src/search.ts
33
+ var import_node_url = __toESM(require("url"), 1);
34
+ var import_core = require("@tavily/core");
35
+ async function searxngSearch(apiUrl, params) {
36
+ try {
37
+ const {
38
+ query,
39
+ limit = 10,
40
+ categories = "general",
41
+ engines = "all",
42
+ safeSearch = 0,
43
+ format = "json",
44
+ language = "auto",
45
+ timeRange = "",
46
+ timeout = 1e4,
47
+ apiKey = ""
48
+ } = params;
49
+ const controller = new AbortController();
50
+ const timeoutId = setTimeout(() => controller.abort(), Number(timeout));
51
+ const config2 = {
52
+ q: query,
53
+ pageno: limit,
54
+ categories,
55
+ format,
56
+ safesearch: safeSearch,
57
+ language,
58
+ engines,
59
+ time_range: timeRange
60
+ };
61
+ const endpoint = `${apiUrl}/search`;
62
+ const queryParams = import_node_url.default.format({ query: config2 });
63
+ const headers = {
64
+ "Content-Type": "application/json"
65
+ };
66
+ if (apiKey) {
67
+ headers["Authorization"] = `Bearer ${apiKey}`;
68
+ }
69
+ const res = await fetch(`${endpoint}${queryParams}`, {
70
+ method: "POST",
71
+ headers,
72
+ signal: controller.signal
73
+ });
74
+ clearTimeout(timeoutId);
75
+ const result = await res.json();
76
+ if (result.results) {
77
+ const results = result.results.map((item) => {
78
+ const image = item.img_src ? {
79
+ thumbnail: item.thumbnail_src,
80
+ src: item.img_src
81
+ } : null;
82
+ const video = item.iframe_src ? {
83
+ thumbnail: item.thumbnail_src,
84
+ src: item.iframe_src
85
+ } : null;
86
+ return {
87
+ title: item.title,
88
+ snippet: item.content,
89
+ url: item.url,
90
+ source: item.source,
91
+ image,
92
+ video,
93
+ engine: item.engine
94
+ };
95
+ });
96
+ return {
97
+ results,
98
+ success: true
99
+ };
100
+ }
101
+ return {
102
+ results: [],
103
+ success: false
104
+ };
105
+ } catch (err) {
106
+ process.stdout.write(err?.message ?? "Searxng search error.");
107
+ throw err;
108
+ }
109
+ }
110
+ var tvly = null;
111
+ async function tavilySearch(query, options) {
112
+ const {
113
+ limit = 10,
114
+ categories = "general",
115
+ timeRange,
116
+ apiKey
117
+ } = options;
118
+ if (!apiKey) {
119
+ throw new Error("Tavily API key is required");
120
+ }
121
+ if (!tvly) {
122
+ tvly = (0, import_core.tavily)({
123
+ apiKey
124
+ });
125
+ }
126
+ const params = {
127
+ topic: categories,
128
+ timeRange,
129
+ maxResults: limit
130
+ };
131
+ const res = await tvly.search(query, params);
132
+ const results = res.results.map((item) => ({
133
+ title: item.title,
134
+ url: item.url,
135
+ snippet: item.content
136
+ }));
137
+ return {
138
+ results,
139
+ success: true
140
+ };
141
+ }
142
+
143
+ // src/index.ts
144
+ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
145
+ var SEARCH_TOOL = {
146
+ name: "one_search",
147
+ description: "Search and retrieve content from web pages. Returns SERP results by default (url, title, description).",
148
+ inputSchema: {
149
+ type: "object",
150
+ properties: {
151
+ query: {
152
+ type: "string",
153
+ description: "Search query string"
154
+ },
155
+ limit: {
156
+ type: "number",
157
+ description: "Maximum number of results to return (default: 5)"
158
+ },
159
+ language: {
160
+ type: "string",
161
+ description: "Language code for search results (default: en)"
162
+ },
163
+ categories: {
164
+ type: "string",
165
+ description: "Categories to search for (default: general)"
166
+ },
167
+ timeRange: {
168
+ type: "string",
169
+ description: "Time range for search results (default: all)"
170
+ }
171
+ },
172
+ required: ["query"]
173
+ }
174
+ };
175
+ var SCRAPE_TOOL = {
176
+ name: "one_scrape",
177
+ description: "Scrape a single webpage with advanced options for content extraction. Supports various formats including markdown, HTML, and screenshots. Can execute custom actions like clicking or scrolling before scraping.",
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ url: {
182
+ type: "string",
183
+ description: "The URL to scrape"
184
+ },
185
+ formats: {
186
+ type: "array",
187
+ items: {
188
+ type: "string",
189
+ enum: [
190
+ "markdown",
191
+ "html",
192
+ "rawHtml",
193
+ "screenshot",
194
+ "links",
195
+ "screenshot@fullPage",
196
+ "extract"
197
+ ]
198
+ },
199
+ description: "Content formats to extract (default: ['markdown'])"
200
+ },
201
+ onlyMainContent: {
202
+ type: "boolean",
203
+ description: "Extract only the main content, filtering out navigation, footers, etc."
204
+ },
205
+ includeTags: {
206
+ type: "array",
207
+ items: { type: "string" },
208
+ description: "HTML tags to specifically include in extraction"
209
+ },
210
+ excludeTags: {
211
+ type: "array",
212
+ items: { type: "string" },
213
+ description: "HTML tags to exclude from extraction"
214
+ },
215
+ waitFor: {
216
+ type: "number",
217
+ description: "Time in milliseconds to wait for dynamic content to load"
218
+ },
219
+ timeout: {
220
+ type: "number",
221
+ description: "Maximum time in milliseconds to wait for the page to load"
222
+ },
223
+ actions: {
224
+ type: "array",
225
+ items: {
226
+ type: "object",
227
+ properties: {
228
+ type: {
229
+ type: "string",
230
+ enum: [
231
+ "wait",
232
+ "click",
233
+ "screenshot",
234
+ "write",
235
+ "press",
236
+ "scroll",
237
+ "scrape",
238
+ "executeJavascript"
239
+ ],
240
+ description: "Type of action to perform"
241
+ },
242
+ selector: {
243
+ type: "string",
244
+ description: "CSS selector for the target element"
245
+ },
246
+ milliseconds: {
247
+ type: "number",
248
+ description: "Time to wait in milliseconds (for wait action)"
249
+ },
250
+ text: {
251
+ type: "string",
252
+ description: "Text to write (for write action)"
253
+ },
254
+ key: {
255
+ type: "string",
256
+ description: "Key to press (for press action)"
257
+ },
258
+ direction: {
259
+ type: "string",
260
+ enum: ["up", "down"],
261
+ description: "Scroll direction"
262
+ },
263
+ script: {
264
+ type: "string",
265
+ description: "JavaScript code to execute"
266
+ },
267
+ fullPage: {
268
+ type: "boolean",
269
+ description: "Take full page screenshot"
270
+ }
271
+ },
272
+ required: ["type"]
273
+ },
274
+ description: "List of actions to perform before scraping"
275
+ },
276
+ extract: {
277
+ type: "object",
278
+ properties: {
279
+ schema: {
280
+ type: "object",
281
+ description: "Schema for structured data extraction"
282
+ },
283
+ systemPrompt: {
284
+ type: "string",
285
+ description: "System prompt for LLM extraction"
286
+ },
287
+ prompt: {
288
+ type: "string",
289
+ description: "User prompt for LLM extraction"
290
+ }
291
+ },
292
+ description: "Configuration for structured data extraction"
293
+ },
294
+ mobile: {
295
+ type: "boolean",
296
+ description: "Use mobile viewport"
297
+ },
298
+ skipTlsVerification: {
299
+ type: "boolean",
300
+ description: "Skip TLS certificate verification"
301
+ },
302
+ removeBase64Images: {
303
+ type: "boolean",
304
+ description: "Remove base64 encoded images from output"
305
+ },
306
+ location: {
307
+ type: "object",
308
+ properties: {
309
+ country: {
310
+ type: "string",
311
+ description: "Country code for geolocation"
312
+ },
313
+ languages: {
314
+ type: "array",
315
+ items: { type: "string" },
316
+ description: "Language codes for content"
317
+ }
318
+ },
319
+ description: "Location settings for scraping"
320
+ }
321
+ },
322
+ required: ["url"]
323
+ }
324
+ };
325
+ var EXTRACT_TOOL = {
326
+ name: "one_extract",
327
+ description: "Extract structured information from web pages using LLM. Supports both cloud AI and self-hosted LLM extraction.",
328
+ inputSchema: {
329
+ type: "object",
330
+ properties: {
331
+ urls: {
332
+ type: "array",
333
+ items: { type: "string" },
334
+ description: "List of URLs to extract information from"
335
+ },
336
+ prompt: {
337
+ type: "string",
338
+ description: "Prompt for the LLM extraction"
339
+ },
340
+ systemPrompt: {
341
+ type: "string",
342
+ description: "System prompt for LLM extraction"
343
+ },
344
+ schema: {
345
+ type: "object",
346
+ description: "JSON schema for structured data extraction"
347
+ },
348
+ allowExternalLinks: {
349
+ type: "boolean",
350
+ description: "Allow extraction from external links"
351
+ },
352
+ enableWebSearch: {
353
+ type: "boolean",
354
+ description: "Enable web search for additional context"
355
+ },
356
+ includeSubdomains: {
357
+ type: "boolean",
358
+ description: "Include subdomains in extraction"
359
+ }
360
+ },
361
+ required: ["urls"]
362
+ }
363
+ };
364
+ var server = new import_server.Server(
365
+ {
366
+ name: "one-search-mcp",
367
+ version: "0.0.1"
368
+ },
369
+ {
370
+ capabilities: {
371
+ tools: {},
372
+ logging: {}
373
+ }
374
+ }
375
+ );
376
+ var SEARCH_API_URL = process.env.SEARCH_API_URL;
377
+ var SEARCH_API_KEY = process.env.SEARCH_API_KEY;
378
+ var SEARCH_PROVIDER = process.env.SEARCH_PROVIDER ?? "searxng";
379
+ if (!SEARCH_API_URL) {
380
+ process.stderr.write("SEARCH_API_URL must be set");
381
+ process.exit(1);
382
+ }
383
+ var SAFE_SEARCH = process.env.SAFE_SEARCH ?? 0;
384
+ var LIMIT = process.env.LIMIT ?? 10;
385
+ var CATEGORIES = process.env.CATEGORIES ?? "general";
386
+ var ENGINES = process.env.ENGINES ?? "all";
387
+ var FORMAT = process.env.FORMAT ?? "json";
388
+ var LANGUAGE = process.env.LANGUAGE ?? "auto";
389
+ var TIME_RANGE = process.env.TIME_RANGE ?? "";
390
+ var DEFAULT_TIMEOUT = process.env.TIMEOUT ?? 1e4;
391
+ var config = {
392
+ pageno: LIMIT,
393
+ categories: CATEGORIES,
394
+ format: FORMAT,
395
+ safesearch: SAFE_SEARCH,
396
+ language: LANGUAGE,
397
+ engines: ENGINES,
398
+ time_range: TIME_RANGE,
399
+ timeout: DEFAULT_TIMEOUT
400
+ };
401
+ server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({
402
+ tools: [
403
+ SEARCH_TOOL,
404
+ EXTRACT_TOOL,
405
+ SCRAPE_TOOL
406
+ ]
407
+ }));
408
+ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
409
+ const startTime = Date.now();
410
+ try {
411
+ const { name, arguments: args } = request.params;
412
+ if (!args) {
413
+ throw new Error("No arguments provided");
414
+ }
415
+ server.sendLoggingMessage({
416
+ level: "info",
417
+ data: `[${(/* @__PURE__ */ new Date()).toISOString()}] Received request for tool: [${name}]`
418
+ });
419
+ switch (name) {
420
+ case "one_search": {
421
+ if (!checkSearchArgs(args)) {
422
+ throw new Error(`Invalid arguments for tool: [${name}]`);
423
+ }
424
+ try {
425
+ const { results, success } = await processSearch(SEARCH_API_URL, {
426
+ ...config,
427
+ ...args,
428
+ apiKey: SEARCH_API_KEY ?? ""
429
+ });
430
+ if (!success) {
431
+ throw new Error("Failed to search");
432
+ }
433
+ return {
434
+ results,
435
+ success
436
+ };
437
+ } catch (error) {
438
+ server.sendLoggingMessage({
439
+ level: "error",
440
+ data: `[${(/* @__PURE__ */ new Date()).toISOString()}] Error searching: ${error}`
441
+ });
442
+ const msg = error instanceof Error ? error.message : "Unknown error";
443
+ return {
444
+ success: false,
445
+ error: msg
446
+ };
447
+ }
448
+ }
449
+ default:
450
+ throw new Error(`Unknown tool: ${name}`);
451
+ }
452
+ } catch (error) {
453
+ const msg = error instanceof Error ? error.message : String(error);
454
+ server.sendLoggingMessage({
455
+ level: "error",
456
+ data: {
457
+ message: `[${(/* @__PURE__ */ new Date()).toISOString()}] Error processing request: ${msg}`,
458
+ tool: request.params.name,
459
+ arguments: request.params.arguments,
460
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
461
+ duration: Date.now() - startTime
462
+ }
463
+ });
464
+ return {
465
+ success: false,
466
+ error: error instanceof Error ? error.message : msg
467
+ };
468
+ } finally {
469
+ server.sendLoggingMessage({
470
+ level: "info",
471
+ data: `[${(/* @__PURE__ */ new Date()).toISOString()}] Request completed in ${Date.now() - startTime}ms`
472
+ });
473
+ }
474
+ });
475
+ async function processSearch(apiUrl, args) {
476
+ switch (SEARCH_PROVIDER) {
477
+ case "searxng":
478
+ return await searxngSearch(apiUrl, {
479
+ ...config,
480
+ ...args,
481
+ apiKey: SEARCH_API_KEY
482
+ });
483
+ case "tavily":
484
+ return await tavilySearch(apiUrl, {
485
+ ...config,
486
+ ...args,
487
+ apiKey: SEARCH_API_KEY
488
+ });
489
+ default:
490
+ throw new Error(`Unsupported search provider: ${SEARCH_PROVIDER}`);
491
+ }
492
+ }
493
+ function checkSearchArgs(args) {
494
+ return typeof args === "object" && args !== null && "query" in args && typeof args.query === "string";
495
+ }
496
+ async function runServer() {
497
+ try {
498
+ process.stdout.write("Starting OneSearch MCP server...\n");
499
+ const transport = new import_stdio.StdioServerTransport();
500
+ await server.connect(transport);
501
+ server.sendLoggingMessage({
502
+ level: "info",
503
+ data: "OneSearch MCP server started"
504
+ });
505
+ } catch (error) {
506
+ const msg = error instanceof Error ? error.message : String(error);
507
+ process.stderr.write(`Error starting server: ${msg}
508
+ `);
509
+ process.exit(1);
510
+ }
511
+ }
512
+ runServer().catch((error) => {
513
+ const msg = error instanceof Error ? error.message : String(error);
514
+ process.stderr.write(`Error running server: ${msg}
515
+ `);
516
+ process.exit(1);
517
+ });
518
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/search.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { ISearchRequestOptions, ISearchResponse, Provider } from './interface.js';\nimport { searxngSearch, tavilySearch } from './search.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\n// export interface\nexport * from './interface.js';\n\n// tools definition\nconst SEARCH_TOOL: Tool = {\n name: 'one_search',\n description:\n 'Search and retrieve content from web pages. ' +\n 'Returns SERP results by default (url, title, description).',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query string',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results to return (default: 5)',\n },\n language: {\n type: 'string',\n description: 'Language code for search results (default: en)',\n },\n categories: {\n type: 'string',\n description: 'Categories to search for (default: general)',\n },\n timeRange: {\n type: 'string',\n description: 'Time range for search results (default: all)',\n },\n },\n required: ['query'],\n },\n};\n\nconst SCRAPE_TOOL: Tool = {\n name: 'one_scrape',\n description:\n 'Scrape a single webpage with advanced options for content extraction. ' +\n 'Supports various formats including markdown, HTML, and screenshots. ' +\n 'Can execute custom actions like clicking or scrolling before scraping.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to scrape',\n },\n formats: {\n type: 'array',\n items: {\n type: 'string',\n enum: [\n 'markdown',\n 'html',\n 'rawHtml',\n 'screenshot',\n 'links',\n 'screenshot@fullPage',\n 'extract',\n ],\n },\n description: \"Content formats to extract (default: ['markdown'])\",\n },\n onlyMainContent: {\n type: 'boolean',\n description:\n 'Extract only the main content, filtering out navigation, footers, etc.',\n },\n includeTags: {\n type: 'array',\n items: { type: 'string' },\n description: 'HTML tags to specifically include in extraction',\n },\n excludeTags: {\n type: 'array',\n items: { type: 'string' },\n description: 'HTML tags to exclude from extraction',\n },\n waitFor: {\n type: 'number',\n description: 'Time in milliseconds to wait for dynamic content to load',\n },\n timeout: {\n type: 'number',\n description:\n 'Maximum time in milliseconds to wait for the page to load',\n },\n actions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: [\n 'wait',\n 'click',\n 'screenshot',\n 'write',\n 'press',\n 'scroll',\n 'scrape',\n 'executeJavascript',\n ],\n description: 'Type of action to perform',\n },\n selector: {\n type: 'string',\n description: 'CSS selector for the target element',\n },\n milliseconds: {\n type: 'number',\n description: 'Time to wait in milliseconds (for wait action)',\n },\n text: {\n type: 'string',\n description: 'Text to write (for write action)',\n },\n key: {\n type: 'string',\n description: 'Key to press (for press action)',\n },\n direction: {\n type: 'string',\n enum: ['up', 'down'],\n description: 'Scroll direction',\n },\n script: {\n type: 'string',\n description: 'JavaScript code to execute',\n },\n fullPage: {\n type: 'boolean',\n description: 'Take full page screenshot',\n },\n },\n required: ['type'],\n },\n description: 'List of actions to perform before scraping',\n },\n extract: {\n type: 'object',\n properties: {\n schema: {\n type: 'object',\n description: 'Schema for structured data extraction',\n },\n systemPrompt: {\n type: 'string',\n description: 'System prompt for LLM extraction',\n },\n prompt: {\n type: 'string',\n description: 'User prompt for LLM extraction',\n },\n },\n description: 'Configuration for structured data extraction',\n },\n mobile: {\n type: 'boolean',\n description: 'Use mobile viewport',\n },\n skipTlsVerification: {\n type: 'boolean',\n description: 'Skip TLS certificate verification',\n },\n removeBase64Images: {\n type: 'boolean',\n description: 'Remove base64 encoded images from output',\n },\n location: {\n type: 'object',\n properties: {\n country: {\n type: 'string',\n description: 'Country code for geolocation',\n },\n languages: {\n type: 'array',\n items: { type: 'string' },\n description: 'Language codes for content',\n },\n },\n description: 'Location settings for scraping',\n },\n },\n required: ['url'],\n },\n};\n\nconst EXTRACT_TOOL: Tool = {\n name: 'one_extract',\n description:\n 'Extract structured information from web pages using LLM. ' +\n 'Supports both cloud AI and self-hosted LLM extraction.',\n inputSchema: {\n type: 'object',\n properties: {\n urls: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of URLs to extract information from',\n },\n prompt: {\n type: 'string',\n description: 'Prompt for the LLM extraction',\n },\n systemPrompt: {\n type: 'string',\n description: 'System prompt for LLM extraction',\n },\n schema: {\n type: 'object',\n description: 'JSON schema for structured data extraction',\n },\n allowExternalLinks: {\n type: 'boolean',\n description: 'Allow extraction from external links',\n },\n enableWebSearch: {\n type: 'boolean',\n description: 'Enable web search for additional context',\n },\n includeSubdomains: {\n type: 'boolean',\n description: 'Include subdomains in extraction',\n },\n },\n required: ['urls'],\n },\n};\n\n// Server implementation\nconst server = new Server(\n {\n name: 'one-search-mcp',\n version: '0.0.1',\n },\n {\n capabilities: {\n tools: {},\n logging: {},\n },\n },\n);\n\n// searxng api\nconst SEARCH_API_URL = process.env.SEARCH_API_URL;\nconst SEARCH_API_KEY = process.env.SEARCH_API_KEY;\nconst SEARCH_PROVIDER: Provider = process.env.SEARCH_PROVIDER as Provider ?? 'searxng';\n\nif (!SEARCH_API_URL) {\n process.stderr.write('SEARCH_API_URL must be set');\n process.exit(1);\n}\n\n// query params\nconst SAFE_SEARCH = process.env.SAFE_SEARCH ?? 0;\nconst LIMIT = process.env.LIMIT ?? 10;\nconst CATEGORIES = process.env.CATEGORIES ?? 'general';\nconst ENGINES = process.env.ENGINES ?? 'all';\nconst FORMAT = process.env.FORMAT ?? 'json';\nconst LANGUAGE = process.env.LANGUAGE ?? 'auto';\nconst TIME_RANGE = process.env.TIME_RANGE ?? '';\nconst DEFAULT_TIMEOUT = process.env.TIMEOUT ?? 10000;\n\nconst config = {\n pageno: LIMIT,\n categories: CATEGORIES,\n format: FORMAT,\n safesearch: SAFE_SEARCH,\n language: LANGUAGE,\n engines: ENGINES,\n time_range: TIME_RANGE,\n timeout: DEFAULT_TIMEOUT,\n};\n\n// Tool handlers\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n SEARCH_TOOL,\n EXTRACT_TOOL,\n SCRAPE_TOOL,\n ],\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const startTime = Date.now();\n\n try {\n const { name, arguments: args } = request.params;\n\n if (!args) {\n throw new Error('No arguments provided');\n }\n \n server.sendLoggingMessage({\n level: 'info',\n data: `[${new Date().toISOString()}] Received request for tool: [${name}]`,\n });\n \n switch (name) {\n case 'one_search': {\n // check args.\n if (!checkSearchArgs(args)) {\n throw new Error(`Invalid arguments for tool: [${name}]`);\n }\n try {\n const { results, success } = await processSearch(SEARCH_API_URL, {\n ...config,\n ...args,\n apiKey: SEARCH_API_KEY ?? '',\n });\n if (!success) {\n throw new Error('Failed to search');\n }\n return {\n results,\n success,\n };\n } catch (error) {\n server.sendLoggingMessage({\n level: 'error',\n data: `[${new Date().toISOString()}] Error searching: ${error}`,\n });\n const msg = error instanceof Error ? error.message : 'Unknown error';\n return {\n success: false,\n error: msg,\n };\n }\n }\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch(error) {\n const msg = error instanceof Error ? error.message : String(error);\n server.sendLoggingMessage({\n level: 'error',\n data: {\n message: `[${new Date().toISOString()}] Error processing request: ${msg}`,\n tool: request.params.name,\n arguments: request.params.arguments,\n timestamp: new Date().toISOString(),\n duration: Date.now() - startTime,\n },\n });\n return {\n success: false,\n error: error instanceof Error ? error.message : msg,\n };\n } finally {\n server.sendLoggingMessage({\n level: 'info',\n data: `[${new Date().toISOString()}] Request completed in ${Date.now() - startTime}ms`,\n });\n }\n});\n\nasync function processSearch(apiUrl: string, args: ISearchRequestOptions): Promise<ISearchResponse> {\n switch (SEARCH_PROVIDER) {\n case 'searxng':\n return await searxngSearch(apiUrl, {\n ...config,\n ...args,\n apiKey: SEARCH_API_KEY,\n });\n case 'tavily':\n return await tavilySearch(apiUrl, {\n ...config,\n ...args,\n apiKey: SEARCH_API_KEY,\n });\n default:\n throw new Error(`Unsupported search provider: ${SEARCH_PROVIDER}`);\n }\n}\n\nfunction checkSearchArgs(args: unknown): args is ISearchRequestOptions {\n return (\n typeof args === 'object' &&\n args !== null &&\n 'query' in args &&\n typeof args.query === 'string'\n );\n}\n\nasync function runServer() {\n try {\n process.stdout.write('Starting OneSearch MCP server...\\n');\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n server.sendLoggingMessage({\n level: 'info',\n data: 'OneSearch MCP server started',\n });\n\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`Error starting server: ${msg}\\n`);\n process.exit(1);\n }\n}\n\n// run server\nrunServer().catch((error) => {\n const msg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`Error running server: ${msg}\\n`);\n process.exit(1);\n});\n","import url from 'node:url';\nimport { tavily, TavilyClient, TavilySearchOptions } from '@tavily/core';\nimport { ISearchRequestOptions, ISearchResponse, ISearchResponseResult } from './interface.js';\n\n/**\n * SearxNG Search API\n * - https://docs.searxng.org/dev/search_api.html\n */\nexport async function searxngSearch(apiUrl: string, params: ISearchRequestOptions): Promise<ISearchResponse> {\n try {\n const {\n query,\n limit = 10,\n categories = 'general',\n engines = 'all',\n safeSearch = 0,\n format = 'json',\n language = 'auto',\n timeRange = '',\n timeout = 10000,\n apiKey = '',\n } = params;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), Number(timeout));\n\n const config = {\n q: query,\n pageno: limit,\n categories,\n format,\n safesearch: safeSearch,\n language,\n engines,\n time_range: timeRange,\n };\n\n const endpoint = `${apiUrl}/search`;\n\n const queryParams = url.format({ query: config });\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n };\n\n if (apiKey) {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n const res = await fetch(`${endpoint}${queryParams}`, {\n method: 'POST',\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n const result = await res.json();\n if (result.results) {\n const results: ISearchResponseResult[] = result.results.map((item: Record<string, unknown>) => {\n const image = item.img_src ? {\n thumbnail: item.thumbnail_src,\n src: item.img_src,\n } : null;\n const video = item.iframe_src ? {\n thumbnail: item.thumbnail_src,\n src: item.iframe_src,\n } : null;\n return {\n title: item.title,\n snippet: item.content,\n url: item.url,\n source: item.source,\n image,\n video,\n engine: item.engine,\n };\n });\n return {\n results,\n success: true,\n };\n }\n return {\n results: [],\n success: false,\n };\n } catch (err: any) {\n process.stdout.write(err?.message ?? 'Searxng search error.');\n throw err;\n }\n}\n\n\nlet tvly: TavilyClient | null = null;\nexport async function tavilySearch(query: string, options: ISearchRequestOptions): Promise<ISearchResponse> {\n const {\n limit = 10,\n categories = 'general',\n timeRange,\n apiKey,\n } = options;\n\n if (!apiKey) {\n throw new Error('Tavily API key is required');\n }\n\n if (!tvly) {\n tvly = tavily({\n apiKey,\n });\n }\n\n const params: TavilySearchOptions = {\n topic: categories as TavilySearchOptions['topic'],\n timeRange: timeRange as TavilySearchOptions['timeRange'],\n maxResults: limit,\n };\n\n const res = await tvly.search(query, params);\n const results = res.results.map(item => ({\n title: item.title,\n url: item.url,\n snippet: item.content,\n }));\n\n return {\n results,\n success: true,\n };\n}\n"],"mappings":"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","names":["config","url"]}
@@ -0,0 +1,33 @@
1
+ interface IMediaItem {
2
+ thumbnail?: string;
3
+ src?: string;
4
+ }
5
+ interface ISearchRequestOptions {
6
+ query: string;
7
+ limit?: number;
8
+ categories?: string;
9
+ format?: string;
10
+ language?: string;
11
+ engines?: string;
12
+ safeSearch?: number;
13
+ timeRange?: string;
14
+ timeout?: number | string;
15
+ apiKey?: string;
16
+ }
17
+ interface ISearchResponseResult {
18
+ title: string;
19
+ snippet: string;
20
+ url: string;
21
+ source?: string;
22
+ engine?: string;
23
+ image?: IMediaItem | null;
24
+ video?: IMediaItem | null;
25
+ }
26
+ interface ISearchResponse {
27
+ results: ISearchResponseResult[];
28
+ success: boolean;
29
+ }
30
+ type Provider = 'searxng' | 'google' | 'bing' | 'tavily';
31
+ type SearchTimeRange = 'year' | 'month' | 'week' | 'day';
32
+
33
+ export type { IMediaItem, ISearchRequestOptions, ISearchResponse, ISearchResponseResult, Provider, SearchTimeRange };
@@ -0,0 +1,33 @@
1
+ interface IMediaItem {
2
+ thumbnail?: string;
3
+ src?: string;
4
+ }
5
+ interface ISearchRequestOptions {
6
+ query: string;
7
+ limit?: number;
8
+ categories?: string;
9
+ format?: string;
10
+ language?: string;
11
+ engines?: string;
12
+ safeSearch?: number;
13
+ timeRange?: string;
14
+ timeout?: number | string;
15
+ apiKey?: string;
16
+ }
17
+ interface ISearchResponseResult {
18
+ title: string;
19
+ snippet: string;
20
+ url: string;
21
+ source?: string;
22
+ engine?: string;
23
+ image?: IMediaItem | null;
24
+ video?: IMediaItem | null;
25
+ }
26
+ interface ISearchResponse {
27
+ results: ISearchResponseResult[];
28
+ success: boolean;
29
+ }
30
+ type Provider = 'searxng' | 'google' | 'bing' | 'tavily';
31
+ type SearchTimeRange = 'year' | 'month' | 'week' | 'day';
32
+
33
+ export type { IMediaItem, ISearchRequestOptions, ISearchResponse, ISearchResponseResult, Provider, SearchTimeRange };
package/dist/index.js ADDED
@@ -0,0 +1,491 @@
1
+ // src/index.ts
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
4
+
5
+ // src/search.ts
6
+ import url from "node:url";
7
+ import { tavily } from "@tavily/core";
8
+ async function searxngSearch(apiUrl, params) {
9
+ try {
10
+ const {
11
+ query,
12
+ limit = 10,
13
+ categories = "general",
14
+ engines = "all",
15
+ safeSearch = 0,
16
+ format = "json",
17
+ language = "auto",
18
+ timeRange = "",
19
+ timeout = 1e4,
20
+ apiKey = ""
21
+ } = params;
22
+ const controller = new AbortController();
23
+ const timeoutId = setTimeout(() => controller.abort(), Number(timeout));
24
+ const config2 = {
25
+ q: query,
26
+ pageno: limit,
27
+ categories,
28
+ format,
29
+ safesearch: safeSearch,
30
+ language,
31
+ engines,
32
+ time_range: timeRange
33
+ };
34
+ const endpoint = `${apiUrl}/search`;
35
+ const queryParams = url.format({ query: config2 });
36
+ const headers = {
37
+ "Content-Type": "application/json"
38
+ };
39
+ if (apiKey) {
40
+ headers["Authorization"] = `Bearer ${apiKey}`;
41
+ }
42
+ const res = await fetch(`${endpoint}${queryParams}`, {
43
+ method: "POST",
44
+ headers,
45
+ signal: controller.signal
46
+ });
47
+ clearTimeout(timeoutId);
48
+ const result = await res.json();
49
+ if (result.results) {
50
+ const results = result.results.map((item) => {
51
+ const image = item.img_src ? {
52
+ thumbnail: item.thumbnail_src,
53
+ src: item.img_src
54
+ } : null;
55
+ const video = item.iframe_src ? {
56
+ thumbnail: item.thumbnail_src,
57
+ src: item.iframe_src
58
+ } : null;
59
+ return {
60
+ title: item.title,
61
+ snippet: item.content,
62
+ url: item.url,
63
+ source: item.source,
64
+ image,
65
+ video,
66
+ engine: item.engine
67
+ };
68
+ });
69
+ return {
70
+ results,
71
+ success: true
72
+ };
73
+ }
74
+ return {
75
+ results: [],
76
+ success: false
77
+ };
78
+ } catch (err) {
79
+ process.stdout.write(err?.message ?? "Searxng search error.");
80
+ throw err;
81
+ }
82
+ }
83
+ var tvly = null;
84
+ async function tavilySearch(query, options) {
85
+ const {
86
+ limit = 10,
87
+ categories = "general",
88
+ timeRange,
89
+ apiKey
90
+ } = options;
91
+ if (!apiKey) {
92
+ throw new Error("Tavily API key is required");
93
+ }
94
+ if (!tvly) {
95
+ tvly = tavily({
96
+ apiKey
97
+ });
98
+ }
99
+ const params = {
100
+ topic: categories,
101
+ timeRange,
102
+ maxResults: limit
103
+ };
104
+ const res = await tvly.search(query, params);
105
+ const results = res.results.map((item) => ({
106
+ title: item.title,
107
+ url: item.url,
108
+ snippet: item.content
109
+ }));
110
+ return {
111
+ results,
112
+ success: true
113
+ };
114
+ }
115
+
116
+ // src/index.ts
117
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
118
+ var SEARCH_TOOL = {
119
+ name: "one_search",
120
+ description: "Search and retrieve content from web pages. Returns SERP results by default (url, title, description).",
121
+ inputSchema: {
122
+ type: "object",
123
+ properties: {
124
+ query: {
125
+ type: "string",
126
+ description: "Search query string"
127
+ },
128
+ limit: {
129
+ type: "number",
130
+ description: "Maximum number of results to return (default: 5)"
131
+ },
132
+ language: {
133
+ type: "string",
134
+ description: "Language code for search results (default: en)"
135
+ },
136
+ categories: {
137
+ type: "string",
138
+ description: "Categories to search for (default: general)"
139
+ },
140
+ timeRange: {
141
+ type: "string",
142
+ description: "Time range for search results (default: all)"
143
+ }
144
+ },
145
+ required: ["query"]
146
+ }
147
+ };
148
+ var SCRAPE_TOOL = {
149
+ name: "one_scrape",
150
+ description: "Scrape a single webpage with advanced options for content extraction. Supports various formats including markdown, HTML, and screenshots. Can execute custom actions like clicking or scrolling before scraping.",
151
+ inputSchema: {
152
+ type: "object",
153
+ properties: {
154
+ url: {
155
+ type: "string",
156
+ description: "The URL to scrape"
157
+ },
158
+ formats: {
159
+ type: "array",
160
+ items: {
161
+ type: "string",
162
+ enum: [
163
+ "markdown",
164
+ "html",
165
+ "rawHtml",
166
+ "screenshot",
167
+ "links",
168
+ "screenshot@fullPage",
169
+ "extract"
170
+ ]
171
+ },
172
+ description: "Content formats to extract (default: ['markdown'])"
173
+ },
174
+ onlyMainContent: {
175
+ type: "boolean",
176
+ description: "Extract only the main content, filtering out navigation, footers, etc."
177
+ },
178
+ includeTags: {
179
+ type: "array",
180
+ items: { type: "string" },
181
+ description: "HTML tags to specifically include in extraction"
182
+ },
183
+ excludeTags: {
184
+ type: "array",
185
+ items: { type: "string" },
186
+ description: "HTML tags to exclude from extraction"
187
+ },
188
+ waitFor: {
189
+ type: "number",
190
+ description: "Time in milliseconds to wait for dynamic content to load"
191
+ },
192
+ timeout: {
193
+ type: "number",
194
+ description: "Maximum time in milliseconds to wait for the page to load"
195
+ },
196
+ actions: {
197
+ type: "array",
198
+ items: {
199
+ type: "object",
200
+ properties: {
201
+ type: {
202
+ type: "string",
203
+ enum: [
204
+ "wait",
205
+ "click",
206
+ "screenshot",
207
+ "write",
208
+ "press",
209
+ "scroll",
210
+ "scrape",
211
+ "executeJavascript"
212
+ ],
213
+ description: "Type of action to perform"
214
+ },
215
+ selector: {
216
+ type: "string",
217
+ description: "CSS selector for the target element"
218
+ },
219
+ milliseconds: {
220
+ type: "number",
221
+ description: "Time to wait in milliseconds (for wait action)"
222
+ },
223
+ text: {
224
+ type: "string",
225
+ description: "Text to write (for write action)"
226
+ },
227
+ key: {
228
+ type: "string",
229
+ description: "Key to press (for press action)"
230
+ },
231
+ direction: {
232
+ type: "string",
233
+ enum: ["up", "down"],
234
+ description: "Scroll direction"
235
+ },
236
+ script: {
237
+ type: "string",
238
+ description: "JavaScript code to execute"
239
+ },
240
+ fullPage: {
241
+ type: "boolean",
242
+ description: "Take full page screenshot"
243
+ }
244
+ },
245
+ required: ["type"]
246
+ },
247
+ description: "List of actions to perform before scraping"
248
+ },
249
+ extract: {
250
+ type: "object",
251
+ properties: {
252
+ schema: {
253
+ type: "object",
254
+ description: "Schema for structured data extraction"
255
+ },
256
+ systemPrompt: {
257
+ type: "string",
258
+ description: "System prompt for LLM extraction"
259
+ },
260
+ prompt: {
261
+ type: "string",
262
+ description: "User prompt for LLM extraction"
263
+ }
264
+ },
265
+ description: "Configuration for structured data extraction"
266
+ },
267
+ mobile: {
268
+ type: "boolean",
269
+ description: "Use mobile viewport"
270
+ },
271
+ skipTlsVerification: {
272
+ type: "boolean",
273
+ description: "Skip TLS certificate verification"
274
+ },
275
+ removeBase64Images: {
276
+ type: "boolean",
277
+ description: "Remove base64 encoded images from output"
278
+ },
279
+ location: {
280
+ type: "object",
281
+ properties: {
282
+ country: {
283
+ type: "string",
284
+ description: "Country code for geolocation"
285
+ },
286
+ languages: {
287
+ type: "array",
288
+ items: { type: "string" },
289
+ description: "Language codes for content"
290
+ }
291
+ },
292
+ description: "Location settings for scraping"
293
+ }
294
+ },
295
+ required: ["url"]
296
+ }
297
+ };
298
+ var EXTRACT_TOOL = {
299
+ name: "one_extract",
300
+ description: "Extract structured information from web pages using LLM. Supports both cloud AI and self-hosted LLM extraction.",
301
+ inputSchema: {
302
+ type: "object",
303
+ properties: {
304
+ urls: {
305
+ type: "array",
306
+ items: { type: "string" },
307
+ description: "List of URLs to extract information from"
308
+ },
309
+ prompt: {
310
+ type: "string",
311
+ description: "Prompt for the LLM extraction"
312
+ },
313
+ systemPrompt: {
314
+ type: "string",
315
+ description: "System prompt for LLM extraction"
316
+ },
317
+ schema: {
318
+ type: "object",
319
+ description: "JSON schema for structured data extraction"
320
+ },
321
+ allowExternalLinks: {
322
+ type: "boolean",
323
+ description: "Allow extraction from external links"
324
+ },
325
+ enableWebSearch: {
326
+ type: "boolean",
327
+ description: "Enable web search for additional context"
328
+ },
329
+ includeSubdomains: {
330
+ type: "boolean",
331
+ description: "Include subdomains in extraction"
332
+ }
333
+ },
334
+ required: ["urls"]
335
+ }
336
+ };
337
+ var server = new Server(
338
+ {
339
+ name: "one-search-mcp",
340
+ version: "0.0.1"
341
+ },
342
+ {
343
+ capabilities: {
344
+ tools: {},
345
+ logging: {}
346
+ }
347
+ }
348
+ );
349
+ var SEARCH_API_URL = process.env.SEARCH_API_URL;
350
+ var SEARCH_API_KEY = process.env.SEARCH_API_KEY;
351
+ var SEARCH_PROVIDER = process.env.SEARCH_PROVIDER ?? "searxng";
352
+ if (!SEARCH_API_URL) {
353
+ process.stderr.write("SEARCH_API_URL must be set");
354
+ process.exit(1);
355
+ }
356
+ var SAFE_SEARCH = process.env.SAFE_SEARCH ?? 0;
357
+ var LIMIT = process.env.LIMIT ?? 10;
358
+ var CATEGORIES = process.env.CATEGORIES ?? "general";
359
+ var ENGINES = process.env.ENGINES ?? "all";
360
+ var FORMAT = process.env.FORMAT ?? "json";
361
+ var LANGUAGE = process.env.LANGUAGE ?? "auto";
362
+ var TIME_RANGE = process.env.TIME_RANGE ?? "";
363
+ var DEFAULT_TIMEOUT = process.env.TIMEOUT ?? 1e4;
364
+ var config = {
365
+ pageno: LIMIT,
366
+ categories: CATEGORIES,
367
+ format: FORMAT,
368
+ safesearch: SAFE_SEARCH,
369
+ language: LANGUAGE,
370
+ engines: ENGINES,
371
+ time_range: TIME_RANGE,
372
+ timeout: DEFAULT_TIMEOUT
373
+ };
374
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
375
+ tools: [
376
+ SEARCH_TOOL,
377
+ EXTRACT_TOOL,
378
+ SCRAPE_TOOL
379
+ ]
380
+ }));
381
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
382
+ const startTime = Date.now();
383
+ try {
384
+ const { name, arguments: args } = request.params;
385
+ if (!args) {
386
+ throw new Error("No arguments provided");
387
+ }
388
+ server.sendLoggingMessage({
389
+ level: "info",
390
+ data: `[${(/* @__PURE__ */ new Date()).toISOString()}] Received request for tool: [${name}]`
391
+ });
392
+ switch (name) {
393
+ case "one_search": {
394
+ if (!checkSearchArgs(args)) {
395
+ throw new Error(`Invalid arguments for tool: [${name}]`);
396
+ }
397
+ try {
398
+ const { results, success } = await processSearch(SEARCH_API_URL, {
399
+ ...config,
400
+ ...args,
401
+ apiKey: SEARCH_API_KEY ?? ""
402
+ });
403
+ if (!success) {
404
+ throw new Error("Failed to search");
405
+ }
406
+ return {
407
+ results,
408
+ success
409
+ };
410
+ } catch (error) {
411
+ server.sendLoggingMessage({
412
+ level: "error",
413
+ data: `[${(/* @__PURE__ */ new Date()).toISOString()}] Error searching: ${error}`
414
+ });
415
+ const msg = error instanceof Error ? error.message : "Unknown error";
416
+ return {
417
+ success: false,
418
+ error: msg
419
+ };
420
+ }
421
+ }
422
+ default:
423
+ throw new Error(`Unknown tool: ${name}`);
424
+ }
425
+ } catch (error) {
426
+ const msg = error instanceof Error ? error.message : String(error);
427
+ server.sendLoggingMessage({
428
+ level: "error",
429
+ data: {
430
+ message: `[${(/* @__PURE__ */ new Date()).toISOString()}] Error processing request: ${msg}`,
431
+ tool: request.params.name,
432
+ arguments: request.params.arguments,
433
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
434
+ duration: Date.now() - startTime
435
+ }
436
+ });
437
+ return {
438
+ success: false,
439
+ error: error instanceof Error ? error.message : msg
440
+ };
441
+ } finally {
442
+ server.sendLoggingMessage({
443
+ level: "info",
444
+ data: `[${(/* @__PURE__ */ new Date()).toISOString()}] Request completed in ${Date.now() - startTime}ms`
445
+ });
446
+ }
447
+ });
448
+ async function processSearch(apiUrl, args) {
449
+ switch (SEARCH_PROVIDER) {
450
+ case "searxng":
451
+ return await searxngSearch(apiUrl, {
452
+ ...config,
453
+ ...args,
454
+ apiKey: SEARCH_API_KEY
455
+ });
456
+ case "tavily":
457
+ return await tavilySearch(apiUrl, {
458
+ ...config,
459
+ ...args,
460
+ apiKey: SEARCH_API_KEY
461
+ });
462
+ default:
463
+ throw new Error(`Unsupported search provider: ${SEARCH_PROVIDER}`);
464
+ }
465
+ }
466
+ function checkSearchArgs(args) {
467
+ return typeof args === "object" && args !== null && "query" in args && typeof args.query === "string";
468
+ }
469
+ async function runServer() {
470
+ try {
471
+ process.stdout.write("Starting OneSearch MCP server...\n");
472
+ const transport = new StdioServerTransport();
473
+ await server.connect(transport);
474
+ server.sendLoggingMessage({
475
+ level: "info",
476
+ data: "OneSearch MCP server started"
477
+ });
478
+ } catch (error) {
479
+ const msg = error instanceof Error ? error.message : String(error);
480
+ process.stderr.write(`Error starting server: ${msg}
481
+ `);
482
+ process.exit(1);
483
+ }
484
+ }
485
+ runServer().catch((error) => {
486
+ const msg = error instanceof Error ? error.message : String(error);
487
+ process.stderr.write(`Error running server: ${msg}
488
+ `);
489
+ process.exit(1);
490
+ });
491
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/search.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { ISearchRequestOptions, ISearchResponse, Provider } from './interface.js';\nimport { searxngSearch, tavilySearch } from './search.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\n// export interface\nexport * from './interface.js';\n\n// tools definition\nconst SEARCH_TOOL: Tool = {\n name: 'one_search',\n description:\n 'Search and retrieve content from web pages. ' +\n 'Returns SERP results by default (url, title, description).',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query string',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results to return (default: 5)',\n },\n language: {\n type: 'string',\n description: 'Language code for search results (default: en)',\n },\n categories: {\n type: 'string',\n description: 'Categories to search for (default: general)',\n },\n timeRange: {\n type: 'string',\n description: 'Time range for search results (default: all)',\n },\n },\n required: ['query'],\n },\n};\n\nconst SCRAPE_TOOL: Tool = {\n name: 'one_scrape',\n description:\n 'Scrape a single webpage with advanced options for content extraction. ' +\n 'Supports various formats including markdown, HTML, and screenshots. ' +\n 'Can execute custom actions like clicking or scrolling before scraping.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to scrape',\n },\n formats: {\n type: 'array',\n items: {\n type: 'string',\n enum: [\n 'markdown',\n 'html',\n 'rawHtml',\n 'screenshot',\n 'links',\n 'screenshot@fullPage',\n 'extract',\n ],\n },\n description: \"Content formats to extract (default: ['markdown'])\",\n },\n onlyMainContent: {\n type: 'boolean',\n description:\n 'Extract only the main content, filtering out navigation, footers, etc.',\n },\n includeTags: {\n type: 'array',\n items: { type: 'string' },\n description: 'HTML tags to specifically include in extraction',\n },\n excludeTags: {\n type: 'array',\n items: { type: 'string' },\n description: 'HTML tags to exclude from extraction',\n },\n waitFor: {\n type: 'number',\n description: 'Time in milliseconds to wait for dynamic content to load',\n },\n timeout: {\n type: 'number',\n description:\n 'Maximum time in milliseconds to wait for the page to load',\n },\n actions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: [\n 'wait',\n 'click',\n 'screenshot',\n 'write',\n 'press',\n 'scroll',\n 'scrape',\n 'executeJavascript',\n ],\n description: 'Type of action to perform',\n },\n selector: {\n type: 'string',\n description: 'CSS selector for the target element',\n },\n milliseconds: {\n type: 'number',\n description: 'Time to wait in milliseconds (for wait action)',\n },\n text: {\n type: 'string',\n description: 'Text to write (for write action)',\n },\n key: {\n type: 'string',\n description: 'Key to press (for press action)',\n },\n direction: {\n type: 'string',\n enum: ['up', 'down'],\n description: 'Scroll direction',\n },\n script: {\n type: 'string',\n description: 'JavaScript code to execute',\n },\n fullPage: {\n type: 'boolean',\n description: 'Take full page screenshot',\n },\n },\n required: ['type'],\n },\n description: 'List of actions to perform before scraping',\n },\n extract: {\n type: 'object',\n properties: {\n schema: {\n type: 'object',\n description: 'Schema for structured data extraction',\n },\n systemPrompt: {\n type: 'string',\n description: 'System prompt for LLM extraction',\n },\n prompt: {\n type: 'string',\n description: 'User prompt for LLM extraction',\n },\n },\n description: 'Configuration for structured data extraction',\n },\n mobile: {\n type: 'boolean',\n description: 'Use mobile viewport',\n },\n skipTlsVerification: {\n type: 'boolean',\n description: 'Skip TLS certificate verification',\n },\n removeBase64Images: {\n type: 'boolean',\n description: 'Remove base64 encoded images from output',\n },\n location: {\n type: 'object',\n properties: {\n country: {\n type: 'string',\n description: 'Country code for geolocation',\n },\n languages: {\n type: 'array',\n items: { type: 'string' },\n description: 'Language codes for content',\n },\n },\n description: 'Location settings for scraping',\n },\n },\n required: ['url'],\n },\n};\n\nconst EXTRACT_TOOL: Tool = {\n name: 'one_extract',\n description:\n 'Extract structured information from web pages using LLM. ' +\n 'Supports both cloud AI and self-hosted LLM extraction.',\n inputSchema: {\n type: 'object',\n properties: {\n urls: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of URLs to extract information from',\n },\n prompt: {\n type: 'string',\n description: 'Prompt for the LLM extraction',\n },\n systemPrompt: {\n type: 'string',\n description: 'System prompt for LLM extraction',\n },\n schema: {\n type: 'object',\n description: 'JSON schema for structured data extraction',\n },\n allowExternalLinks: {\n type: 'boolean',\n description: 'Allow extraction from external links',\n },\n enableWebSearch: {\n type: 'boolean',\n description: 'Enable web search for additional context',\n },\n includeSubdomains: {\n type: 'boolean',\n description: 'Include subdomains in extraction',\n },\n },\n required: ['urls'],\n },\n};\n\n// Server implementation\nconst server = new Server(\n {\n name: 'one-search-mcp',\n version: '0.0.1',\n },\n {\n capabilities: {\n tools: {},\n logging: {},\n },\n },\n);\n\n// searxng api\nconst SEARCH_API_URL = process.env.SEARCH_API_URL;\nconst SEARCH_API_KEY = process.env.SEARCH_API_KEY;\nconst SEARCH_PROVIDER: Provider = process.env.SEARCH_PROVIDER as Provider ?? 'searxng';\n\nif (!SEARCH_API_URL) {\n process.stderr.write('SEARCH_API_URL must be set');\n process.exit(1);\n}\n\n// query params\nconst SAFE_SEARCH = process.env.SAFE_SEARCH ?? 0;\nconst LIMIT = process.env.LIMIT ?? 10;\nconst CATEGORIES = process.env.CATEGORIES ?? 'general';\nconst ENGINES = process.env.ENGINES ?? 'all';\nconst FORMAT = process.env.FORMAT ?? 'json';\nconst LANGUAGE = process.env.LANGUAGE ?? 'auto';\nconst TIME_RANGE = process.env.TIME_RANGE ?? '';\nconst DEFAULT_TIMEOUT = process.env.TIMEOUT ?? 10000;\n\nconst config = {\n pageno: LIMIT,\n categories: CATEGORIES,\n format: FORMAT,\n safesearch: SAFE_SEARCH,\n language: LANGUAGE,\n engines: ENGINES,\n time_range: TIME_RANGE,\n timeout: DEFAULT_TIMEOUT,\n};\n\n// Tool handlers\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n SEARCH_TOOL,\n EXTRACT_TOOL,\n SCRAPE_TOOL,\n ],\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const startTime = Date.now();\n\n try {\n const { name, arguments: args } = request.params;\n\n if (!args) {\n throw new Error('No arguments provided');\n }\n \n server.sendLoggingMessage({\n level: 'info',\n data: `[${new Date().toISOString()}] Received request for tool: [${name}]`,\n });\n \n switch (name) {\n case 'one_search': {\n // check args.\n if (!checkSearchArgs(args)) {\n throw new Error(`Invalid arguments for tool: [${name}]`);\n }\n try {\n const { results, success } = await processSearch(SEARCH_API_URL, {\n ...config,\n ...args,\n apiKey: SEARCH_API_KEY ?? '',\n });\n if (!success) {\n throw new Error('Failed to search');\n }\n return {\n results,\n success,\n };\n } catch (error) {\n server.sendLoggingMessage({\n level: 'error',\n data: `[${new Date().toISOString()}] Error searching: ${error}`,\n });\n const msg = error instanceof Error ? error.message : 'Unknown error';\n return {\n success: false,\n error: msg,\n };\n }\n }\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch(error) {\n const msg = error instanceof Error ? error.message : String(error);\n server.sendLoggingMessage({\n level: 'error',\n data: {\n message: `[${new Date().toISOString()}] Error processing request: ${msg}`,\n tool: request.params.name,\n arguments: request.params.arguments,\n timestamp: new Date().toISOString(),\n duration: Date.now() - startTime,\n },\n });\n return {\n success: false,\n error: error instanceof Error ? error.message : msg,\n };\n } finally {\n server.sendLoggingMessage({\n level: 'info',\n data: `[${new Date().toISOString()}] Request completed in ${Date.now() - startTime}ms`,\n });\n }\n});\n\nasync function processSearch(apiUrl: string, args: ISearchRequestOptions): Promise<ISearchResponse> {\n switch (SEARCH_PROVIDER) {\n case 'searxng':\n return await searxngSearch(apiUrl, {\n ...config,\n ...args,\n apiKey: SEARCH_API_KEY,\n });\n case 'tavily':\n return await tavilySearch(apiUrl, {\n ...config,\n ...args,\n apiKey: SEARCH_API_KEY,\n });\n default:\n throw new Error(`Unsupported search provider: ${SEARCH_PROVIDER}`);\n }\n}\n\nfunction checkSearchArgs(args: unknown): args is ISearchRequestOptions {\n return (\n typeof args === 'object' &&\n args !== null &&\n 'query' in args &&\n typeof args.query === 'string'\n );\n}\n\nasync function runServer() {\n try {\n process.stdout.write('Starting OneSearch MCP server...\\n');\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n server.sendLoggingMessage({\n level: 'info',\n data: 'OneSearch MCP server started',\n });\n\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`Error starting server: ${msg}\\n`);\n process.exit(1);\n }\n}\n\n// run server\nrunServer().catch((error) => {\n const msg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`Error running server: ${msg}\\n`);\n process.exit(1);\n});\n","import url from 'node:url';\nimport { tavily, TavilyClient, TavilySearchOptions } from '@tavily/core';\nimport { ISearchRequestOptions, ISearchResponse, ISearchResponseResult } from './interface.js';\n\n/**\n * SearxNG Search API\n * - https://docs.searxng.org/dev/search_api.html\n */\nexport async function searxngSearch(apiUrl: string, params: ISearchRequestOptions): Promise<ISearchResponse> {\n try {\n const {\n query,\n limit = 10,\n categories = 'general',\n engines = 'all',\n safeSearch = 0,\n format = 'json',\n language = 'auto',\n timeRange = '',\n timeout = 10000,\n apiKey = '',\n } = params;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), Number(timeout));\n\n const config = {\n q: query,\n pageno: limit,\n categories,\n format,\n safesearch: safeSearch,\n language,\n engines,\n time_range: timeRange,\n };\n\n const endpoint = `${apiUrl}/search`;\n\n const queryParams = url.format({ query: config });\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n };\n\n if (apiKey) {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n const res = await fetch(`${endpoint}${queryParams}`, {\n method: 'POST',\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n const result = await res.json();\n if (result.results) {\n const results: ISearchResponseResult[] = result.results.map((item: Record<string, unknown>) => {\n const image = item.img_src ? {\n thumbnail: item.thumbnail_src,\n src: item.img_src,\n } : null;\n const video = item.iframe_src ? {\n thumbnail: item.thumbnail_src,\n src: item.iframe_src,\n } : null;\n return {\n title: item.title,\n snippet: item.content,\n url: item.url,\n source: item.source,\n image,\n video,\n engine: item.engine,\n };\n });\n return {\n results,\n success: true,\n };\n }\n return {\n results: [],\n success: false,\n };\n } catch (err: any) {\n process.stdout.write(err?.message ?? 'Searxng search error.');\n throw err;\n }\n}\n\n\nlet tvly: TavilyClient | null = null;\nexport async function tavilySearch(query: string, options: ISearchRequestOptions): Promise<ISearchResponse> {\n const {\n limit = 10,\n categories = 'general',\n timeRange,\n apiKey,\n } = options;\n\n if (!apiKey) {\n throw new Error('Tavily API key is required');\n }\n\n if (!tvly) {\n tvly = tavily({\n apiKey,\n });\n }\n\n const params: TavilySearchOptions = {\n topic: categories as TavilySearchOptions['topic'],\n timeRange: timeRange as TavilySearchOptions['timeRange'],\n maxResults: limit,\n };\n\n const res = await tvly.search(query, params);\n const results = res.results.map(item => ({\n title: item.title,\n url: item.url,\n snippet: item.content,\n }));\n\n return {\n results,\n success: true,\n };\n}\n"],"mappings":"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","names":["config"]}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "one-search-mcp",
3
+ "version": "1.0.0",
4
+ "description": "One Search MCP Server, Web Search & Crawl & Scraper & Extract, support SearXNG, Firecrawl, Tavily, etc.",
5
+ "private": false,
6
+ "type": "module",
7
+ "keywords": [
8
+ "AI",
9
+ "LLM",
10
+ "MCP",
11
+ "ModelContextProtocol",
12
+ "SearXNG MCP Server",
13
+ "Firecrawl MCP Server",
14
+ "Search MCP Server",
15
+ "Web Search",
16
+ "LLM Tool",
17
+ "One Search"
18
+ ],
19
+ "author": "zac.ma",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/yokingma/one-search-mcp.git"
24
+ },
25
+ "main": "./dist/index.cjs",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "files": [
29
+ "dist/**"
30
+ ],
31
+ "engines": {
32
+ "node": ">=20.0.0"
33
+ },
34
+ "scripts": {
35
+ "dev": "dotenvx run --env-file=.env -- cross-env NODE_ENV=development tsx src/index.ts",
36
+ "build": "tsup",
37
+ "lint": "eslint src",
38
+ "lint:fix": "eslint src --fix"
39
+ },
40
+ "tsup": {
41
+ "entry": [
42
+ "src/index.ts"
43
+ ],
44
+ "outDir": "dist",
45
+ "format": [
46
+ "cjs",
47
+ "esm"
48
+ ],
49
+ "splitting": false,
50
+ "dts": true,
51
+ "clean": true,
52
+ "sourcemap": true
53
+ },
54
+ "exports": {
55
+ ".": {
56
+ "require": "./dist/index.cjs",
57
+ "import": "./dist/index.js"
58
+ }
59
+ },
60
+ "devDependencies": {
61
+ "@eslint/js": "^8.56.0",
62
+ "@types/node": "^22.13.10",
63
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
64
+ "@typescript-eslint/parser": "^7.0.0",
65
+ "cross-env": "^7.0.3",
66
+ "eslint": "^8.56.0",
67
+ "tsup": "^8.4.0",
68
+ "tsx": "^4.19.3",
69
+ "typescript": "^5.3.3",
70
+ "typescript-eslint": "^7.0.0"
71
+ },
72
+ "dependencies": {
73
+ "@dotenvx/dotenvx": "^1.38.5",
74
+ "@modelcontextprotocol/sdk": "^1.7.0",
75
+ "@tavily/core": "^0.3.1"
76
+ }
77
+ }