Skip to main content
Glama
gianlucamazza

MCP DuckDuckGo Search Plugin

web_search

Search the web using DuckDuckGo to find relevant information, websites, and resources with detailed results including titles, URLs, and descriptions.

Instructions

Search the web using DuckDuckGo.

Returns a list of search results with titles, URLs, descriptions, and domains.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query
max_resultsNoMaximum number of results to return (1-20)

Implementation Reference

  • Main handler function for the 'web_search' tool. Includes input schema via Pydantic Field annotations and executes the search logic using DuckDuckGo via the search_web helper.
    async def web_search( query: str = Field(..., description="Search query", max_length=400), max_results: int = Field( 10, description="Maximum number of results to return (1-20)", ge=1, le=20 ), ctx: Context = Field(default_factory=Context), ) -> Dict[str, Any]: """ Search the web using DuckDuckGo. Returns a list of search results with titles, URLs, descriptions, and domains. """ logger.info("Searching for: '%s' (max %d results)", query, max_results) try: # Get HTTP client from context http_client = None close_client = False # Try to get HTTP client from lifespan context if ( hasattr(ctx, "lifespan_context") and ctx.lifespan_context and "http_client" in ctx.lifespan_context ): logger.info("Using HTTP client from lifespan context") http_client = ctx.lifespan_context["http_client"] else: # Create a new HTTP client logger.info("Creating new HTTP client") http_client = httpx.AsyncClient(timeout=10.0) close_client = True try: # Perform the search results = await search_web(query, http_client, max_results) # Convert to dict format search_results = [ { "title": result.title, "url": result.url, "description": result.description, "domain": result.domain, } for result in results ] return { "query": query, "results": search_results, "total_results": len(search_results), "status": "success", } finally: if close_client: await http_client.aclose() except (httpx.RequestError, httpx.HTTPError, ValueError) as e: logger.error("Search failed: %s", e) return { "query": query, "results": [], "total_results": 0, "status": "error", "error": str(e), }
  • Registers the search tools (including web_search) by calling register_search_tools on the FastMCP server instance during server creation.
    def create_mcp_server() -> FastMCP: """Create and return a FastMCP server instance with proper tool registration.""" server = FastMCP("DuckDuckGo Search", lifespan=app_lifespan) # Register tools directly with the server instance register_search_tools(server) return server
  • Core helper function that implements the DuckDuckGo web search logic, querying both the instant API and HTML search page, parsing results, and deduplicating them. Called by the web_search handler.
    async def search_web( query: str, http_client: httpx.AsyncClient, count: int = 10 ) -> List[SearchResult]: """ Main search function that tries multiple methods. Args: query: Search query string http_client: HTTP client to use for requests count: Maximum number of results to return Returns: List of unique SearchResult objects from both instant answers and HTML search """ logger.info("Searching for: '%s' (max %d results)", query, count) # Try instant answers first instant_results = await search_duckduckgo_instant(query, http_client) logger.info("Instant answers found %d results", len(instant_results)) # Always try HTML search for more comprehensive results html_results = await search_duckduckgo_html(query, http_client, count) logger.info("HTML search found %d results", len(html_results)) # Combine and deduplicate all_results = instant_results + html_results # Remove duplicates based on URL seen_urls = set() unique_results = [] for result in all_results: if result.url and result.url not in seen_urls and result.url.startswith("http"): seen_urls.add(result.url) unique_results.append(result) if len(unique_results) >= count: break logger.info("Returning %d unique valid results", len(unique_results)) return unique_results
  • Dataclass defining the structure of individual search results used in the output of web_search.
    @dataclass class SearchResult: title: str url: str description: str domain: str = ""
  • Utility function to extract the domain from a URL, used in search result processing.
    def extract_domain(url: str) -> str: """ Extract domain from URL. Args: url: URL string to extract domain from Returns: Lowercase domain name or empty string if parsing fails """ try: parsed = urllib.parse.urlparse(url) return parsed.netloc.lower() except Exception as e: logger.debug("Failed to extract domain from URL %s: %s", url, e) return ""

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gianlucamazza/mcp-duckduckgo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server