import re
import os
import html
import httpx
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP, Context
import aiofiles
import mimetypes
import gradio as gr
def utf8_clean(text: str) -> str:
"""Clean and decode text safely to UTF-8"""
return html.unescape(text).strip()
async def duckduckgo_detailed_search(query: str, max_results: int = 10) -> str:
"""Perform a detailed DuckDuckGo search and return top results with title, URL, and excerpt"""
url = "https://html.duckduckgo.com/html/"
data = {'q': query}
headers = {'User-Agent': 'Mozilla/5.0'}
async with httpx.AsyncClient() as client:
response = await client.post(url, data=data, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
results = []
for result in soup.find_all('div', class_='result'):
if len(results) >= max_results:
break
link_tag = result.find('a', class_='result__a')
snippet_tag = result.find('a', class_='result__snippet')
snippet_fallback = result.find('div', class_='result__snippet')
if link_tag:
title = utf8_clean(link_tag.get_text())
link = utf8_clean(link_tag.get('href'))
snippet = utf8_clean(snippet_tag.get_text()) if snippet_tag else (
utf8_clean(snippet_fallback.get_text()) if snippet_fallback else "No excerpt available.")
results.append({'title': title, 'url': link, 'excerpt': snippet})
if not results:
return "## Search Results\n\n_No results found._"
md = ["## Search Results\n"]
for r in results:
md.append(f"### \"{r['title']}\"\n**URL:** {r['url']} \n**Excerpt:** {r['excerpt']}\n")
return "\n".join(md)
# Wrap the async search function
def duckduckgo_sync(query: str) -> str:
import asyncio
return asyncio.run(duckduckgo_detailed_search(query))
async def semantic_search(query: str, limit: int = 5) -> dict:
"""Perform a semantic content search using an external API and return top results"""
url = "https://content_retrival.cfapps.eu10.hana.ondemand.com/search"
params = {
"search_type": "semantic",
"query": query,
"limit": limit
}
headers = {"Accept": "application/json"}
async with httpx.AsyncClient(verify=False) as client:
response = await client.get(url, params=params, headers=headers)
return response.json()
# Create a Gradio Interface
demo = gr.Interface(
fn=duckduckgo_sync,
inputs="text",
outputs="text",
title="DuckDuckGo Search",
description="Performs a DuckDuckGo search and returns top results."
)
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
mcp_server=True
)