@@ -57,103 +57,12 @@ async def dispatch(self, request: Request, call_next):
5757 return await call_next (request )
5858
5959
60- def format_answer_box (answer_box : dict [str , Any ]) -> str :
61- """Format answer_box results for weather, finance, and other structured data."""
62- if answer_box .get ("type" ) == "weather_result" :
63- result = f"Temperature: { answer_box .get ('temperature' , 'N/A' )} \n "
64- result += f"Unit: { answer_box .get ('unit' , 'N/A' )} \n "
65- result += f"Precipitation: { answer_box .get ('precipitation' , 'N/A' )} \n "
66- result += f"Humidity: { answer_box .get ('humidity' , 'N/A' )} \n "
67- result += f"Wind: { answer_box .get ('wind' , 'N/A' )} \n "
68- result += f"Location: { answer_box .get ('location' , 'N/A' )} \n "
69- result += f"Date: { answer_box .get ('date' , 'N/A' )} \n "
70- result += f"Weather: { answer_box .get ('weather' , 'N/A' )} "
71-
72- # Add forecast if available
73- if "forecast" in answer_box :
74- result += "\n \n Daily Forecast:\n "
75- for day in answer_box ["forecast" ]:
76- result += f"{ day .get ('day' , 'N/A' )} : { day .get ('weather' , 'N/A' )} "
77- if "temperature" in day :
78- high = day ["temperature" ].get ("high" , "N/A" )
79- low = day ["temperature" ].get ("low" , "N/A" )
80- result += f"(High: { high } , Low: { low } )"
81- result += "\n "
82-
83- return result
84-
85- elif answer_box .get ("type" ) == "finance_results" :
86- result = f"Title: { answer_box .get ('title' , 'N/A' )} \n "
87- result += f"Exchange: { answer_box .get ('exchange' , 'N/A' )} \n "
88- result += f"Stock: { answer_box .get ('stock' , 'N/A' )} \n "
89- result += f"Currency: { answer_box .get ('currency' , 'N/A' )} \n "
90- result += f"Price: { answer_box .get ('price' , 'N/A' )} \n "
91- result += f"Previous Close: { answer_box .get ('previous_close' , 'N/A' )} \n "
92-
93- if "price_movement" in answer_box :
94- pm = answer_box ["price_movement" ]
95- result += f"Price Movement: { pm .get ('price' , 'N/A' )} ({ pm .get ('percentage' , 'N/A' )} %) { pm .get ('movement' , 'N/A' )} \n "
96-
97- if "table" in answer_box :
98- result += "\n Financial Metrics:\n "
99- for row in answer_box ["table" ]:
100- result += f"{ row .get ('name' , 'N/A' )} : { row .get ('value' , 'N/A' )} \n "
101-
102- return result
103- else :
104- # Generic answer box formatting
105- result = ""
106- for key , value in answer_box .items ():
107- if key != "type" :
108- result += f"{ key .replace ('_' , ' ' ).title ()} : { value } \n "
109- return result
110-
111-
112- def format_organic_results (organic_results : list [Any ]) -> str :
113- """Format organic search results."""
114- formatted_results = []
115- for result in organic_results :
116- title = result .get ("title" , "No title" )
117- link = result .get ("link" , "No link" )
118- snippet = result .get ("snippet" , "No snippet" )
119- formatted_results .append (f"Title: { title } \n Link: { link } \n Snippet: { snippet } \n " )
120- return "\n " .join (formatted_results ) if formatted_results else ""
121-
122-
123- def format_news_results (news_results : list [Any ]) -> str :
124- """Format news search results."""
125- formatted_results = []
126- for result in news_results :
127- title = result .get ("title" , "No title" )
128- link = result .get ("link" , "No link" )
129- snippet = result .get ("snippet" , "No snippet" )
130- date = result .get ("date" , "No date" )
131- source = result .get ("source" , "No source" )
132- formatted_results .append (
133- f"Title: { title } \n Source: { source } \n Date: { date } \n Link: { link } \n Snippet: { snippet } \n "
134- )
135- return "\n " .join (formatted_results ) if formatted_results else ""
136-
137-
138- def format_images_results (images_results : list [Any ]) -> str :
139- """Format image search results."""
140- formatted_results = []
141- for result in images_results :
142- title = result .get ("title" , "No title" )
143- link = result .get ("link" , "No link" )
144- thumbnail = result .get ("thumbnail" , "No thumbnail" )
145- formatted_results .append (
146- f"Title: { title } \n Image: { link } \n Thumbnail: { thumbnail } \n "
147- )
148- return "\n " .join (formatted_results ) if formatted_results else ""
149-
150-
15160@mcp .tool ()
152- async def search (params : dict [str , Any ] = {}, raw : bool = False ) -> str :
61+ async def search (params : dict [str , Any ] = {}, mode : str = "complete" ) -> str :
15362 """Universal search tool supporting all SerpApi engines and result types.
15463
15564 This tool consolidates weather, stock, and general search functionality into a single interface.
156- It dynamically processes multiple result types and provides structured output.
65+ It processes multiple result types and returns structured JSON output.
15766
15867 Args:
15968 params: Dictionary of engine-specific parameters. Common parameters include:
@@ -162,17 +71,24 @@ async def search(params: dict[str, Any] = {}, raw: bool = False) -> str:
16271 - location: Geographic location filter
16372 - num: Number of results to return
16473
165- raw: If True, returns the raw JSON response from SerpApi (default: False)
74+ mode: Response mode (default: "complete")
75+ - "complete": Returns full JSON response with all fields
76+ - "compact": Returns JSON response with metadata fields removed
16677
16778 Returns:
168- A formatted string of search results or raw JSON data, or an error message.
79+ A JSON string containing search results or an error message.
16980
17081 Examples:
17182 Weather: {"q": "weather in London", "engine": "google"}
17283 Stock: {"q": "AAPL stock", "engine": "google"}
17384 General: {"q": "coffee shops", "engine": "google_light", "location": "Austin, TX"}
85+ Compact: {"q": "news", "mode": "compact"}
17486 """
17587
88+ # Validate mode parameter
89+ if mode not in ["complete" , "compact" ]:
90+ return "Error: Invalid mode. Must be 'complete' or 'compact'"
91+
17692 request = get_http_request ()
17793 if hasattr (request , "state" ) and request .state .api_key :
17894 api_key = request .state .api_key
@@ -188,56 +104,21 @@ async def search(params: dict[str, Any] = {}, raw: bool = False) -> str:
188104 try :
189105 data = serpapi .search (search_params ).as_dict ()
190106
191- # Return raw JSON if requested
192- if raw :
193- return json .dumps (data , indent = 2 , ensure_ascii = False )
194-
195- # Process results in priority order
196- formatted_output = ""
197-
198- # 1. Answer box (weather, finance, knowledge graph, etc.) - highest priority
199- if "answer_box" in data :
200- formatted_output += "=== Answer Box ===\n "
201- formatted_output += format_answer_box (data ["answer_box" ])
202- formatted_output += "\n \n "
203-
204- # 2. News results
205- if "news_results" in data and data ["news_results" ]:
206- formatted_output += "=== News Results ===\n "
207- formatted_output += format_news_results (data ["news_results" ])
208- formatted_output += "\n \n "
209-
210- # 3. Organic results
211- if "organic_results" in data and data ["organic_results" ]:
212- formatted_output += "=== Search Results ===\n "
213- formatted_output += format_organic_results (data ["organic_results" ])
214- formatted_output += "\n \n "
215-
216- # 4. Image results
217- if "images_results" in data and data ["images_results" ]:
218- formatted_output += "=== Image Results ===\n "
219- formatted_output += format_images_results (data ["images_results" ])
220- formatted_output += "\n \n "
221-
222- # 5. Shopping results
223- if "shopping_results" in data and data ["shopping_results" ]:
224- formatted_output += "=== Shopping Results ===\n "
225- shopping_results = []
226- for result in data ["shopping_results" ]:
227- title = result .get ("title" , "No title" )
228- price = result .get ("price" , "No price" )
229- link = result .get ("link" , "No link" )
230- source = result .get ("source" , "No source" )
231- shopping_results .append (
232- f"Title: { title } \n Price: { price } \n Source: { source } \n Link: { link } \n "
233- )
234- formatted_output += "\n " .join (shopping_results ) + "\n \n "
235-
236- # Return formatted output or fallback message
237- if formatted_output .strip ():
238- return formatted_output .strip ()
239- else :
240- return "No results found for the given query. Try adjusting your search parameters or engine."
107+ # Apply mode-specific filtering
108+ if mode == "compact" :
109+ # Remove specified fields for compact mode
110+ fields_to_remove = [
111+ "search_metadata" ,
112+ "search_parameters" ,
113+ "search_information" ,
114+ "pagination" ,
115+ "serpapi_pagination" ,
116+ ]
117+ for field in fields_to_remove :
118+ data .pop (field , None )
119+
120+ # Return JSON response for both modes
121+ return json .dumps (data , indent = 2 , ensure_ascii = False )
241122
242123 except serpapi .exceptions .HTTPError as e :
243124 if "429" in str (e ):
0 commit comments