@@ -36,109 +36,115 @@ interface McpSearchResponse {
3636 }
3737}
3838
39- export const WebSearchTool = Tool . define ( "websearch" , {
40- description : DESCRIPTION ,
41- parameters : z . object ( {
42- query : z . string ( ) . describe ( "Websearch query" ) ,
43- numResults : z . number ( ) . optional ( ) . describe ( "Number of search results to return (default: 8)" ) ,
44- livecrawl : z
45- . enum ( [ "fallback" , "preferred" ] )
46- . optional ( )
47- . describe (
48- "Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')" ,
49- ) ,
50- type : z
51- . enum ( [ "auto" , "fast" , "deep" ] )
52- . optional ( )
53- . describe ( "Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search" ) ,
54- contextMaxCharacters : z
55- . number ( )
56- . optional ( )
57- . describe ( "Maximum characters for context string optimized for LLMs (default: 10000)" ) ,
58- } ) ,
59- async execute ( params , ctx ) {
60- await ctx . ask ( {
61- permission : "websearch" ,
62- patterns : [ params . query ] ,
63- always : [ "*" ] ,
64- metadata : {
65- query : params . query ,
66- numResults : params . numResults ,
67- livecrawl : params . livecrawl ,
68- type : params . type ,
69- contextMaxCharacters : params . contextMaxCharacters ,
70- } ,
71- } )
72-
73- const searchRequest : McpSearchRequest = {
74- jsonrpc : "2.0" ,
75- id : 1 ,
76- method : "tools/call" ,
77- params : {
78- name : "web_search_exa" ,
79- arguments : {
39+ export const WebSearchTool = Tool . define ( "websearch" , async ( ) => {
40+ return {
41+ get description ( ) {
42+ return DESCRIPTION . replace ( "{{date}}" , new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) )
43+ } ,
44+ parameters : z . object ( {
45+ query : z . string ( ) . describe ( "Websearch query" ) ,
46+ numResults : z . number ( ) . optional ( ) . describe ( "Number of search results to return (default: 8)" ) ,
47+ livecrawl : z
48+ . enum ( [ "fallback" , "preferred" ] )
49+ . optional ( )
50+ . describe (
51+ "Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')" ,
52+ ) ,
53+ type : z
54+ . enum ( [ "auto" , "fast" , "deep" ] )
55+ . optional ( )
56+ . describe (
57+ "Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search" ,
58+ ) ,
59+ contextMaxCharacters : z
60+ . number ( )
61+ . optional ( )
62+ . describe ( "Maximum characters for context string optimized for LLMs (default: 10000)" ) ,
63+ } ) ,
64+ async execute ( params , ctx ) {
65+ await ctx . ask ( {
66+ permission : "websearch" ,
67+ patterns : [ params . query ] ,
68+ always : [ "*" ] ,
69+ metadata : {
8070 query : params . query ,
81- type : params . type || "auto" ,
82- numResults : params . numResults || API_CONFIG . DEFAULT_NUM_RESULTS ,
83- livecrawl : params . livecrawl || "fallback" ,
71+ numResults : params . numResults ,
72+ livecrawl : params . livecrawl ,
73+ type : params . type ,
8474 contextMaxCharacters : params . contextMaxCharacters ,
8575 } ,
86- } ,
87- }
88-
89- const controller = new AbortController ( )
90- const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 25000 )
76+ } )
9177
92- try {
93- const headers : Record < string , string > = {
94- accept : "application/json, text/event-stream" ,
95- "content-type" : "application/json" ,
78+ const searchRequest : McpSearchRequest = {
79+ jsonrpc : "2.0" ,
80+ id : 1 ,
81+ method : "tools/call" ,
82+ params : {
83+ name : "web_search_exa" ,
84+ arguments : {
85+ query : params . query ,
86+ type : params . type || "auto" ,
87+ numResults : params . numResults || API_CONFIG . DEFAULT_NUM_RESULTS ,
88+ livecrawl : params . livecrawl || "fallback" ,
89+ contextMaxCharacters : params . contextMaxCharacters ,
90+ } ,
91+ } ,
9692 }
9793
98- const response = await fetch ( `${ API_CONFIG . BASE_URL } ${ API_CONFIG . ENDPOINTS . SEARCH } ` , {
99- method : "POST" ,
100- headers,
101- body : JSON . stringify ( searchRequest ) ,
102- signal : AbortSignal . any ( [ controller . signal , ctx . abort ] ) ,
103- } )
94+ const controller = new AbortController ( )
95+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 25000 )
10496
105- clearTimeout ( timeoutId )
97+ try {
98+ const headers : Record < string , string > = {
99+ accept : "application/json, text/event-stream" ,
100+ "content-type" : "application/json" ,
101+ }
106102
107- if ( ! response . ok ) {
108- const errorText = await response . text ( )
109- throw new Error ( `Search error (${ response . status } ): ${ errorText } ` )
110- }
103+ const response = await fetch ( `${ API_CONFIG . BASE_URL } ${ API_CONFIG . ENDPOINTS . SEARCH } ` , {
104+ method : "POST" ,
105+ headers,
106+ body : JSON . stringify ( searchRequest ) ,
107+ signal : AbortSignal . any ( [ controller . signal , ctx . abort ] ) ,
108+ } )
109+
110+ clearTimeout ( timeoutId )
111+
112+ if ( ! response . ok ) {
113+ const errorText = await response . text ( )
114+ throw new Error ( `Search error (${ response . status } ): ${ errorText } ` )
115+ }
111116
112- const responseText = await response . text ( )
117+ const responseText = await response . text ( )
113118
114- // Parse SSE response
115- const lines = responseText . split ( "\n" )
116- for ( const line of lines ) {
117- if ( line . startsWith ( "data: " ) ) {
118- const data : McpSearchResponse = JSON . parse ( line . substring ( 6 ) )
119- if ( data . result && data . result . content && data . result . content . length > 0 ) {
120- return {
121- output : data . result . content [ 0 ] . text ,
122- title : `Web search: ${ params . query } ` ,
123- metadata : { } ,
119+ // Parse SSE response
120+ const lines = responseText . split ( "\n" )
121+ for ( const line of lines ) {
122+ if ( line . startsWith ( "data: " ) ) {
123+ const data : McpSearchResponse = JSON . parse ( line . substring ( 6 ) )
124+ if ( data . result && data . result . content && data . result . content . length > 0 ) {
125+ return {
126+ output : data . result . content [ 0 ] . text ,
127+ title : `Web search: ${ params . query } ` ,
128+ metadata : { } ,
129+ }
124130 }
125131 }
126132 }
127- }
128133
129- return {
130- output : "No search results found. Please try a different query." ,
131- title : `Web search: ${ params . query } ` ,
132- metadata : { } ,
133- }
134- } catch ( error ) {
135- clearTimeout ( timeoutId )
134+ return {
135+ output : "No search results found. Please try a different query." ,
136+ title : `Web search: ${ params . query } ` ,
137+ metadata : { } ,
138+ }
139+ } catch ( error ) {
140+ clearTimeout ( timeoutId )
136141
137- if ( error instanceof Error && error . name === "AbortError" ) {
138- throw new Error ( "Search request timed out" )
139- }
142+ if ( error instanceof Error && error . name === "AbortError" ) {
143+ throw new Error ( "Search request timed out" )
144+ }
140145
141- throw error
142- }
143- } ,
146+ throw error
147+ }
148+ } ,
149+ }
144150} )
0 commit comments