one-search-mcp
Version:
One Search MCP Server, Web Search & Crawl & Scraper & Extract, support agent-browser, SearXNG, Tavily, DuckDuckGo, Bing, etc.
39 lines (28 loc) • 27 kB
JavaScript
;var Re=Object.create;var G=Object.defineProperty;var Ie=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames;var Te=Object.getPrototypeOf,Le=Object.prototype.hasOwnProperty;var K=(o,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ve(e))!Le.call(o,s)&&s!==r&&G(o,s,{get:()=>e[s],enumerable:!(t=Ie(e,s))||t.enumerable});return o};var S=(o,e,r)=>(r=o!=null?Re(Te(o)):{},K(e||!o||!o.__esModule?G(r,"default",{value:o,enumerable:!0}):r,o)),_e=o=>K(G({},"__esModule",{value:!0}),o);var Xe={};module.exports=_e(Xe);var fe=require("@modelcontextprotocol/sdk/server/mcp.js"),we=require("@modelcontextprotocol/sdk/server/stdio.js");var W=S(require("pino"),1),R=class{logger;constructor(e){this.logger=(0,W.default)({name:e||"one-search-mcp",level:process.env.LOG_LEVEL||"info",transport:process.env.NODE_ENV==="development"?{target:"pino-pretty",options:{colorize:!0,translateTime:"SYS:standard",ignore:"pid,hostname"}}:void 0},process.stderr)}logWithLevel(e,r,...t){t.length>0?this.logger[e]({data:t},r):this.logger[e](r)}info(e,...r){this.logWithLevel("info",e,...r)}error(e,...r){this.logWithLevel("error",e,...r)}success(e,...r){r.length>0?this.logger.info({level:"success",data:r},e):this.logger.info({level:"success"},e)}warn(e,...r){this.logWithLevel("warn",e,...r)}log(e,...r){this.logWithLevel("info",e,...r)}},$=new R;var d=new R("search");var Oe=2e4;async function z(o){let{query:e,limit:r=10,safeSearch:t=0,page:s=1,apiUrl:a="https://api.bing.microsoft.com/v7.0/search",apiKey:c,language:u}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!c)throw new Error("Bing API key is required");let i=["Off","Moderate","Strict"],l={q:e,count:r,offset:(s-1)*r,mkt:u,safeSearch:i[t]},p=new AbortController,g=setTimeout(()=>p.abort(),Oe);try{let h=new URLSearchParams;Object.entries(l).forEach(([w,T])=>{T!==void 0&&h.set(w,T.toString())});let m=await fetch(`${a}?${h}`,{method:"GET",headers:{"Content-Type":"application/json","Ocp-Apim-Subscription-Key":c},signal:p.signal});if(clearTimeout(g),!m.ok)throw new Error(`Bing search error: ${m.status} ${m.statusText}`);return{results:(await m.json()).webPages?.value?.map(w=>({title:w.name,snippet:w.snippet,url:w.url,source:w.siteName,thumbnailUrl:w.thumbnailUrl,language:w.language,image:null,video:null,engine:"bing"}))??[],success:!0}}catch(h){clearTimeout(g);let m=h instanceof Error?h.message:"Bing search error.";throw d.error(m),h}}var U=S(require("duck-duck-scrape"),1),Z=S(require("async-retry"),1);async function V(o){let{query:e,timeout:r=1e4,safeSearch:t=U.SafeSearchType.OFF,retry:s={retries:3},...a}=o;if(!e?.trim())throw new Error("Query cannot be empty");try{let c=await(0,Z.default)(()=>U.search(e,{...a,safeSearch:t},{response_timeout:r}),s);return{results:(c?{noResults:c.noResults,vqd:c.vqd,results:c.results}:{noResults:!0,vqd:"",results:[]}).results.map(i=>({title:i.title,snippet:i.description,url:i.url,source:i.hostname,image:null,video:null,engine:"duckduckgo"})),success:!0}}catch(c){let u=c instanceof Error?c.message:"DuckDuckGo search error.";throw d.error(u),c}}var Q=S(require("url"),1);async function J(o){let{query:e,page:r=1,limit:t=10,categories:s="general",engines:a="all",safeSearch:c=0,format:u="json",language:i="auto",timeRange:l="",timeout:p=1e4,apiKey:g,apiUrl:h}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!h)throw new Error("SearxNG API URL is required");let m=new AbortController,F=setTimeout(()=>m.abort(),Number(p));try{let I={q:e,pageno:r,categories:s,format:u,safesearch:c,language:i,engines:a,time_range:l},k=`${h}/search`,w=Q.default.format({query:I}),T={"Content-Type":"application/json"};g&&(T.Authorization=`Bearer ${g}`);let be=await fetch(`${k}${w}`,{method:"POST",headers:T,signal:m.signal});clearTimeout(F);let N=await be.json();return N.results?{results:N.results.slice(0,t).map(f=>{let xe=f.img_src?{thumbnail:f.thumbnail_src,src:f.img_src}:null,Ee=f.iframe_src?{thumbnail:f.thumbnail_src,src:f.iframe_src}:null;return{title:f.title,snippet:f.content,url:f.url,source:f.source,image:xe,video:Ee,engine:f.engine}}),success:!0}:{results:[],success:!1}}catch(I){clearTimeout(F);let k=I instanceof Error?I.message:"Searxng search error.";throw d.error(k),I}}var Y=require("@tavily/core");var Ae=2e4;async function X(o){let{query:e,limit:r=10,categories:t="general",timeRange:s,apiKey:a}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!a)throw new Error("Tavily API key is required");let c;try{let u=(0,Y.tavily)({apiKey:a}),i={topic:t,timeRange:s,maxResults:r},l=await Promise.race([u.search(e,i),new Promise((g,h)=>{c=setTimeout(()=>h(new Error("Tavily search timeout")),Ae)})]);return clearTimeout(c),{results:l.results.map(g=>({title:g.title,url:g.url,snippet:g.content,engine:"tavily"})),success:!0}}catch(u){clearTimeout(c);let i=u instanceof Error?u.message:"Tavily search error.";throw d.error(i),u}}var re=require("agent-browser/dist/browser.js"),te=S(require("turndown"),1),se=require("turndown-plugin-gfm"),_=S(require("cheerio"),1);var L=S(require("fs"),1),H=S(require("path"),1),ee=S(require("os"),1);var M=class{logger;constructor(e){this.logger=e??$}get browsers(){let e=ee.homedir(),r=process.env.LOCALAPPDATA;return[{name:"Chromium",executable:{win32:"C:\\Program Files\\Chromium\\Application\\chrome.exe",darwin:"/Applications/Chromium.app/Contents/MacOS/Chromium",linux:"/usr/bin/chromium"},userDataDir:{win32:`${r}\\Chromium\\User Data`,darwin:`${e}/Library/Application Support/Chromium`,linux:`${e}/.config/chromium`}},{name:"Google Chrome",executable:{win32:"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",darwin:"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",linux:"/usr/bin/google-chrome"},userDataDir:{win32:`${r}\\Google\\Chrome\\User Data`,darwin:`${e}/Library/Application Support/Google/Chrome`,linux:`${e}/.config/google-chrome`}},{name:"Google Chrome Canary",executable:{win32:"C:\\Program Files\\Google\\Chrome Canary\\Application\\chrome.exe",darwin:"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",linux:"/usr/bin/google-chrome-canary"},userDataDir:{win32:`${r}\\Google\\Chrome Canary\\User Data`,darwin:`${e}/Library/Application Support/Google/Chrome Canary`,linux:`${e}/.config/google-chrome-canary`}},{name:"Microsoft Edge",executable:{win32:"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",darwin:"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",linux:"/usr/bin/microsoft-edge"},userDataDir:{win32:`${r}\\Microsoft\\Edge\\User Data`,darwin:`${e}/Library/Application Support/Microsoft Edge`,linux:`${e}/.config/microsoft-edge`}}]}findBrowser(e){let r=process.platform;if(this.logger.info("Finding browser on platform:",r),r!=="darwin"&&r!=="win32"&&r!=="linux"){let a=new Error(`Unsupported platform: ${r}`);throw this.logger.error(a.message),a}let t=e?this.browsers.find(a=>a.name===e&&L.existsSync(a.executable[r])):this.browsers.find(a=>L.existsSync(a.executable[r]));if(this.logger.log("browser",t),!t){let a=e?new Error(`Cannot find browser: ${e}`):new Error("Cannot find a supported browser on your system. Please install Chrome, Chromium, Edge, or Brave.");throw this.logger.error(a.message),a}let s={executable:t.executable[r],userDataDir:t.userDataDir[r]};return this.logger.success(`Found browser: ${t.name}`),this.logger.info("Browser details:",s),s}getBrowserProfiles(e){let r=this.findBrowser(e);try{let s=JSON.parse(L.readFileSync(H.join(r.userDataDir,"Local State"),"utf8")).profile.info_cache;return Object.entries(s).map(([a,c])=>({displayName:c.name,path:H.join(r.userDataDir,a)}))}catch{return[]}}findChrome(){try{let{executable:e}=this.findBrowser("Google Chrome");return e}catch{return null}}};var D={DEFAULT_WAIT_MS:2e3,SEARCH_WAIT_MS:3e3,DEFAULT_TIMEOUT:3e4,DEFAULT_HEADLESS:!0},j=["bing","google","baidu","sogou"];var E=class{constructor(e={}){this.options=e;this.browser=new re.BrowserManager;try{let r=new M,{executable:t}=r.findBrowser();this.browserPath=t}catch{this.browserPath=void 0}this.turndown=new te.default({headingStyle:"atx",codeBlockStyle:"fenced"}),this.turndown.use(se.gfm)}browser;turndown;browserPath;async ensureLaunched(){if(!this.browser.isLaunched())try{await this.browser.launch({id:`session-${Date.now()}`,action:"launch",headless:this.options.headless??!0,executablePath:this.browserPath})}catch(e){let r=e instanceof Error?e.message:String(e);throw r.includes("Executable")||r.includes("browser")?new Error(`Browser not found. Please install one of the following:
- Google Chrome: https://www.google.com/chrome/
- Microsoft Edge: https://www.microsoft.com/edge
- Chromium: https://www.chromium.org/getting-involved/download-chromium/
Or install via Playwright:
npx playwright install chromium
Original error: ${r}`):e}}async getPage(){return await this.ensureLaunched(),this.browser.getPage()}async navigate(e){await(await this.getPage()).goto(e,{waitUntil:"domcontentloaded",timeout:this.options.timeout})}async getHtml(){return await(await this.getPage()).content()}async getText(){return await(await this.getPage()).evaluate(()=>document.body.innerText)}async screenshot(){return`data:image/png;base64,${(await(await this.getPage()).screenshot({type:"png",fullPage:!1})).toString("base64")}`}async wait(e){await new Promise(r=>setTimeout(r,e))}async close(){this.browser.isLaunched()&&await this.browser.close()}async scrapeUrl(e,r={}){try{await this.navigate(e),r.waitFor?await this.wait(r.waitFor):await this.wait(D.DEFAULT_WAIT_MS);let t={success:!0},s=r.formats||["markdown"],a=await this.getHtml();return s.includes("markdown")&&(t.markdown=this.turndown.turndown(a)),(s.includes("html")||s.includes("rawHtml"))&&(t.html=a,t.rawHtml=a),s.includes("links")&&(t.links=this.extractLinks(a,e)),(s.includes("screenshot")||s.includes("screenshot@fullPage"))&&(t.screenshot=await this.screenshot()),t}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async mapUrl(e,r={}){try{await this.navigate(e),await this.wait(D.DEFAULT_WAIT_MS);let t=await this.getHtml(),s=this.extractLinks(t,e);if(r.search&&(s=s.filter(a=>a.toLowerCase().includes(r.search.toLowerCase()))),!r.includeSubdomains){let a=new URL(e).hostname;s=s.filter(c=>{try{return new URL(c).hostname===a}catch{return!1}})}return r.limit&&(s=s.slice(0,r.limit)),{success:!0,links:s}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async search(e){let{query:r,engine:t,limit:s=10}=e,a=this.getSearchUrl(t,r);await this.navigate(a),await this.wait(D.SEARCH_WAIT_MS);let c=await this.getHtml();return this.extractSearchResults(t,c).slice(0,s)}getSearchUrl(e,r){let t=encodeURIComponent(r);switch(e){case"google":return`https://www.google.com/search?q=${t}`;case"bing":return`https://www.bing.com/search?q=${t}`;case"baidu":return`https://www.baidu.com/s?wd=${t}`;case"sogou":return`https://www.sogou.com/web?query=${t}`;default:throw new Error(`Unsupported search engine: ${e}`)}}extractSearchResults(e,r){try{switch(e){case"google":return this.extractGoogleResults(r);case"bing":return this.extractBingResults(r);case"baidu":return this.extractBaiduResults(r);case"sogou":return this.extractSogouResults(r);default:return[]}}catch(t){let s=t instanceof Error?t.message:String(t);return $.warn(`Failed to extract ${e} search results: ${s}`),[]}}extractGoogleResults(e){let r=_.load(e),t=[];return r("div.g").each((s,a)=>{let c=r(a),u=c.find("a[href]").first(),i=c.find("h3").first(),l=c.find("div.VwiC3b, div[data-sncf]").first(),p=u.attr("href"),g=i.text().trim(),h=l.text().trim();p&&g&&!p.startsWith("/search")&&t.push({title:g,url:p,snippet:h})}),t}extractBingResults(e){let r=_.load(e),t=[];return r("li.b_algo").each((s,a)=>{let c=r(a),u=c.find("h2 a").first(),i=c.find("p, div.b_caption p").first(),l=u.attr("href"),p=u.text().trim(),g=i.text().trim();l&&p&&t.push({title:p,url:l,snippet:g})}),t}extractBaiduResults(e){let r=_.load(e),t=[];return r("div.result").each((s,a)=>{let c=r(a),u=c.find("h3 a").first(),i=c.find('div.c-abstract, div[class*="abstract"]').first(),l=u.attr("href"),p=u.text().trim(),g=i.text().trim();l&&p&&t.push({title:p,url:l,snippet:g})}),t}extractSogouResults(e){let r=_.load(e),t=[];return r("div.vrwrap").each((s,a)=>{let c=r(a),u=c.find("h3 a").first(),i=c.find('p.str-text, p[class*="text"]').first(),l=u.attr("href"),p=u.text().trim(),g=i.text().trim();l&&p&&t.push({title:p,url:l,snippet:g})}),t}extractLinks(e,r){let t=/<a[^>]+href=["']([^"']+)["']/gi,s=[],a;for(;(a=t.exec(e))!==null;)try{let c=new URL(a[1],r).href;s.includes(c)||s.push(c)}catch{}return s}};var v=new R("[LocalSearch]");function oe(o){return j.includes(o)}function Pe(o,e){return{title:o.title,snippet:o.snippet,url:o.url,markdown:o.content,engine:e}}async function ne(o){let{query:e,limit:r=10}=o,{engines:t="all"}=o;t==="all"&&(t="bing,google,baidu,sogou");let s=t.split(",").map(i=>i.trim()).filter(Boolean);if(s.length===0)throw new Error("engines is required");let a=s.filter(oe),c=s.filter(i=>!oe(i));if(c.length>0&&v.warn(`Invalid search engines ignored: ${c.join(", ")}`),a.length===0)throw new Error(`No valid search engines provided. Valid engines: ${j.join(", ")}`);let u=new E({headless:!0,timeout:3e4});try{let i=[];for(let l of a)try{v.info(`Searching with engine: ${l}`);let p=await u.search({query:e,engine:l,limit:r});if(p.length>0){let g=p.map(h=>Pe(h,l));i.push(...g),v.info(`Found ${p.length} results from ${l}`);break}}catch(p){v.error(`Failed to search with ${l}:`,p)}return v.info(`Total results found: ${i.length}`),{results:i,success:!0}}catch(i){let l=i instanceof Error?i.message:"Local search error.";throw v.error(l,i),i}finally{await u.close()}}var Ce="https://www.googleapis.com/customsearch/v1",ke=2e4;async function ae(o){let{query:e,apiKey:r,apiUrl:t,limit:s=10,language:a}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!r||!t)throw new Error("Google search requires SEARCH_API_KEY and SEARCH_API_URL (Search Engine ID)");let c=new URLSearchParams({key:r,cx:t,q:e,num:String(Math.min(s,10))});a&&a!=="auto"&&c.set("lr",`lang_${a}`);let u=new AbortController,i=setTimeout(()=>u.abort(),ke);try{let l=await fetch(`${Ce}?${c}`,{method:"GET",signal:u.signal});if(clearTimeout(i),!l.ok)throw new Error(`Google search failed: ${l.status} ${l.statusText}`);let p=await l.json();if(p.error)throw new Error(`Google API error: ${p.error.message}`);return{results:(p.items??[]).map(m=>({title:m.title,url:m.link,snippet:m.snippet||"",source:m.displayLink,thumbnailUrl:m.pagemap?.cse_thumbnail?.[0]?.src,engine:"google"})),success:!0}}catch(l){clearTimeout(i);let p=l instanceof Error?l.message:"Google search error.";throw d.error(p),l}}var $e="https://open.bigmodel.cn/api/paas/v4/web_search",Ue=2e4;async function ie(o){let{query:e,apiKey:r,limit:t=10,engines:s}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!r)throw new Error("Zhipu search requires SEARCH_API_KEY");let c=["search_std","search_pro","search_pro_sogou","search_pro_quark","search_pro_jina","search_pro_bing"].includes(s)?s:"search_std",u=new AbortController,i=setTimeout(()=>u.abort(),Ue);try{let l=await fetch($e,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({search_engine:c,search_query:e,search_intent:!1,count:t}),signal:u.signal});if(clearTimeout(i),!l.ok)throw new Error(`Zhipu search failed: ${l.status} ${l.statusText}`);return{results:((await l.json()).search_result??[]).map(m=>({title:m.title,url:m.link,snippet:m.content,source:m.media,engine:"zhipu"})),success:!0}}catch(l){clearTimeout(i);let p=l instanceof Error?l.message:"Zhipu search error.";throw d.error(p),l}}var ce=require("exa-js");var Me=2e4;async function le(o){let{query:e,apiKey:r,limit:t=10}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!r)throw new Error("Exa search requires SEARCH_API_KEY");let s;try{let a=new ce.Exa(r),c=await Promise.race([a.search(e,{numResults:t,contents:{text:!0}}),new Promise((i,l)=>{s=setTimeout(()=>l(new Error("Exa search timeout")),Me)})]);return clearTimeout(s),{results:c.results.map(i=>({title:i.title||"",url:i.url,snippet:i.text||"",engine:"exa"})),success:!0}}catch(a){clearTimeout(s);let c=a instanceof Error?a.message:"Exa search error.";throw d.error(c),a}}var De="https://api.bocha.cn/v1/web-search",qe=2e4;async function ue(o){let{query:e,apiKey:r,limit:t=10,timeRange:s}=o;if(!e?.trim())throw new Error("Query cannot be empty");if(!r)throw new Error("Bocha search requires SEARCH_API_KEY");let a="noLimit";s&&(a={day:"oneDay",week:"oneWeek",month:"oneMonth",year:"oneYear"}[s]||"noLimit");let c=new AbortController,u=setTimeout(()=>c.abort(),qe);try{let i=await fetch(De,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({query:e,count:t,summary:!0,freshness:a}),signal:c.signal});if(clearTimeout(u),!i.ok)throw new Error(`Bocha search failed: ${i.status} ${i.statusText}`);let l=await i.json();return{results:(l?.data?.webPages?.value||l?.webPages?.value||l?.results||[]).map(h=>({title:h.name||h.title||"",url:h.url||h.link||"",snippet:h.snippet||h.summary||h.content||"",source:h.siteName||h.site_name,thumbnailUrl:h.urlToImage||h.icon,engine:"bocha"})),success:!0}}catch(i){clearTimeout(u);let l=i instanceof Error?i.message:"Bocha search error.";throw d.error(l),i}}var n=require("zod/v3"),pe=n.z.object({query:n.z.string().describe("Search query string"),limit:n.z.number().optional().describe("Maximum number of results to return (default: 10)"),language:n.z.string().optional().describe("Language code for search results (default: auto)"),categories:n.z.enum(["general","news","images","videos","it","science","map","music","files","social_media"]).optional().describe("Categories to search for (default: general)"),timeRange:n.z.enum(["all","day","week","month","year"]).optional().describe("Time range for search results (default: all)")}),he=n.z.object({url:n.z.string().describe("Starting URL for URL discovery"),search:n.z.string().optional().describe("Optional search term to filter URLs"),ignoreSitemap:n.z.boolean().optional().describe("Skip sitemap.xml discovery and only use HTML links"),sitemapOnly:n.z.boolean().optional().describe("Only use sitemap.xml for discovery, ignore HTML links"),includeSubdomains:n.z.boolean().optional().describe("Include URLs from subdomains in results"),limit:n.z.number().optional().describe("Maximum number of URLs to return")}),Be=n.z.discriminatedUnion("type",[n.z.object({type:n.z.literal("wait"),milliseconds:n.z.number().describe("Time to wait in milliseconds")}),n.z.object({type:n.z.literal("click"),selector:n.z.string().describe("CSS selector for the target element")}),n.z.object({type:n.z.literal("screenshot"),fullPage:n.z.boolean().optional().describe("Take full page screenshot")}),n.z.object({type:n.z.literal("write"),selector:n.z.string().describe("CSS selector for the target element"),text:n.z.string().describe("Text to write")}),n.z.object({type:n.z.literal("press"),key:n.z.string().describe("Key to press")}),n.z.object({type:n.z.literal("scroll"),direction:n.z.enum(["up","down"]).describe("Scroll direction")}),n.z.object({type:n.z.literal("scrape")}),n.z.object({type:n.z.literal("executeJavascript"),script:n.z.string().describe("JavaScript code to execute")})]),ge=n.z.object({url:n.z.string().describe("The URL to scrape"),formats:n.z.array(n.z.enum(["markdown","html","rawHtml","screenshot","links","screenshot@fullPage","extract"])).optional().describe("Content formats to extract (default: ['markdown'])"),onlyMainContent:n.z.boolean().optional().describe("Extract only the main content, filtering out navigation, footers, etc."),includeTags:n.z.array(n.z.string()).optional().describe("HTML tags to specifically include in extraction"),excludeTags:n.z.array(n.z.string()).optional().describe("HTML tags to exclude from extraction"),waitFor:n.z.number().optional().describe("Time in milliseconds to wait for dynamic content to load"),timeout:n.z.number().optional().describe("Maximum time in milliseconds to wait for the page to load"),actions:n.z.array(Be).optional().describe("List of actions to perform before scraping"),extract:n.z.object({schema:n.z.record(n.z.any()).optional().describe("Schema for structured data extraction"),systemPrompt:n.z.string().optional().describe("System prompt for LLM extraction"),prompt:n.z.string().optional().describe("User prompt for LLM extraction")}).optional().describe("Configuration for structured data extraction"),mobile:n.z.boolean().optional().describe("Use mobile viewport"),skipTlsVerification:n.z.boolean().optional().describe("Skip TLS certificate verification"),removeBase64Images:n.z.boolean().optional().describe("Remove base64 encoded images from output"),location:n.z.object({country:n.z.string().optional().describe("Country code for geolocation"),languages:n.z.array(n.z.string()).optional().describe("Language codes for content")}).optional().describe("Location settings for scraping")}),me=n.z.object({urls:n.z.array(n.z.string()).describe("List of URLs to extract information from"),prompt:n.z.string().optional().describe("Prompt for the LLM extraction"),systemPrompt:n.z.string().optional().describe("System prompt for LLM extraction"),schema:n.z.record(n.z.any()).optional().describe("JSON schema for structured data extraction"),allowExternalLinks:n.z.boolean().optional().describe("Allow extraction from external links"),enableWebSearch:n.z.boolean().optional().describe("Enable web search for additional context"),includeSubdomains:n.z.boolean().optional().describe("Include subdomains in extraction")});var O={name:"one_search",description:"Search and retrieve content from web pages. Returns SERP results by default (url, title, description).",schema:pe},A={name:"one_map",description:"Discover URLs from a starting point. Can use both sitemap.xml and HTML link discovery.",schema:he},P={name:"one_scrape",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.",schema:ge},C={name:"one_extract",description:"Extract structured information from web pages using LLM. Supports both cloud AI and self-hosted LLM extraction.",schema:me};var Se=S(require("@dotenvx/dotenvx"),1),q=require("duck-duck-scrape");Se.default.config({quiet:!0});var ye=process.env.SEARCH_API_URL,b=process.env.SEARCH_API_KEY,de=process.env.SEARCH_PROVIDER??"local",Fe=process.env.SAFE_SEARCH??0,Ge=process.env.LIMIT??10,He=process.env.CATEGORIES??"general",je=process.env.ENGINES??"all",Ne=process.env.FORMAT??"json",Ke=process.env.LANGUAGE??"auto",We=process.env.TIME_RANGE??"",ze=process.env.TIMEOUT??1e4,x=new fe.McpServer({name:"one-search-mcp",version:"1.1.2"},{capabilities:{tools:{},logging:{}}}),y={limit:Number(Ge),categories:He,format:Ne,safesearch:Fe,language:Ke,engines:je,time_range:We,timeout:ze};function B(o,e){return async r=>{let t=Date.now();try{await x.sendLoggingMessage({level:"info",data:`[${new Date().toISOString()}] Request started for tool: [${o}]`});let s=await e(r);return await x.sendLoggingMessage({level:"info",data:`[${new Date().toISOString()}] Request completed in ${Date.now()-t}ms`}),s}catch(s){return await x.sendLoggingMessage({level:"error",data:`[${new Date().toISOString()}] Error in ${o}: ${s}`}),{content:[{type:"text",text:s instanceof Error?s.message:String(s)}],isError:!0}}}}x.registerTool(O.name,{description:O.description,inputSchema:O.schema},B(O.name,async o=>{let{results:e,success:r}=await Ze({...o,apiKey:b??"",apiUrl:ye});if(!r)throw new Error("Failed to search");return{content:[{type:"text",text:e.map(s=>`Title: ${s.title}
URL: ${s.url}
Description: ${s.snippet}
${s.markdown?`Content: ${s.markdown}`:""}`).join(`
`)}]}}));x.registerTool(P.name,{description:P.description,inputSchema:P.schema},B(P.name,async o=>{let{url:e,...r}=o,{content:t}=await Ve(e,r);return{content:t}}));x.registerTool(A.name,{description:A.description,inputSchema:A.schema},B(A.name,async o=>{let{content:e}=await Qe(o.url,o);return{content:e}}));x.registerTool(C.name,{description:C.description,inputSchema:C.schema},B(C.name,async o=>{let{content:e}=await Je(o);return{content:e}}));async function Ze(o){switch(de){case"searxng":{let e={...y,...o,apiKey:b},{categories:r,language:t}=y;return r&&(e.categories=r),t&&(e.language=t),await J(e)}case"tavily":return await X({...y,...o,apiKey:b});case"bing":return await z({...y,...o,apiKey:b});case"duckduckgo":{let e=o.safeSearch??0,r=[q.SafeSearchType.STRICT,q.SafeSearchType.MODERATE,q.SafeSearchType.OFF];return await V({...y,...o,apiKey:b,safeSearch:r[e]})}case"local":return await ne({...y,...o});case"google":return await ae({...y,...o,apiKey:b,apiUrl:ye});case"zhipu":return await ie({...y,...o,apiKey:b});case"exa":return await le({...y,...o,apiKey:b});case"bocha":return await ue({...y,...o,apiKey:b});default:throw new Error(`Unsupported search provider: ${de}`)}}async function Ve(o,e){let r=new E({headless:!0,timeout:3e4});try{let t=await r.scrapeUrl(o,e);if(!t.success)throw new Error(`Failed to scrape: ${t.error}`);let s=[];return t.markdown&&s.push(t.markdown),t.rawHtml&&s.push(t.rawHtml),t.links&&s.push(t.links.join(`
`)),t.screenshot&&s.push(t.screenshot),t.html&&s.push(t.html),{content:[{type:"text",text:s.join(`
`)||"No content found"}],result:t,success:!0}}finally{await r.close()}}async function Qe(o,e){let r=new E({headless:!0,timeout:3e4});try{let t=await r.mapUrl(o,e);if(!t.success)throw new Error(`Failed to map: ${t.error}`);if(!t.links)throw new Error(`No links found from: ${o}`);return{content:[{type:"text",text:t.links.join(`
`).trim()}],result:t.links,success:!0}}finally{await r.close()}}async function Je(o){let{urls:e,prompt:r,systemPrompt:t,schema:s}=o,a=new E({headless:!0,timeout:3e4});try{let c=[];for(let i of e)try{let l=await a.scrapeUrl(i,{formats:["markdown"],onlyMainContent:!0});l.success&&l.markdown?c.push(`## Content from ${i}
${l.markdown}`):c.push(`## Failed to extract from ${i}
Error: ${l.error||"Unknown error"}`)}catch(l){let p=l instanceof Error?l.message:String(l);c.push(`## Failed to extract from ${i}
Error: ${p}`)}let u=c.join(`
---
`);if(r||t||s){let i=[];t&&i.push(`System Instructions: ${t}`),r&&i.push(`Extraction Task: ${r}`),s&&i.push(`Expected Schema:
${JSON.stringify(s,null,2)}`),u=`${i.join(`
`)}
---
Extracted Content:
${u}`}return{content:[{type:"text",text:u}]}}finally{await a.close()}}async function Ye(){try{let o=new we.StdioServerTransport;await x.connect(o),await x.sendLoggingMessage({level:"info",data:"OneSearch MCP server started"})}catch(o){let e=o instanceof Error?o.message:String(o);process.stderr.write(`Error starting server: ${e}
`),process.exit(1)}}Ye().catch(o=>{let e=o instanceof Error?o.message:String(o);process.stderr.write(`Error running server: ${e}
`),process.exit(1)});
//# sourceMappingURL=index.cjs.map