MCP DuckDuckGo Search Plugin
- tests
#!/usr/bin/env python
"""
Script to test real DuckDuckGo searches.
This script makes actual HTTP requests to DuckDuckGo.
"""
import asyncio
import logging
from pydantic import BaseModel
import httpx
from mcp_duckduckgo.search import duckduckgo_search
from mcp_duckduckgo.tools import duckduckgo_web_search, duckduckgo_get_details, duckduckgo_related_searches
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
class MockContext(BaseModel):
"""A simple mock context to use for testing."""
lifespan_context: dict = {}
async def progress(self, message):
"""Print progress messages."""
print(f"Progress: {message}")
async def info(self, message):
"""Print info messages."""
print(f"Info: {message}")
async def error(self, message):
"""Print error messages."""
print(f"Error: {message}")
async def test_real_search():
"""Test a real search against DuckDuckGo."""
# Create a mock context with a real HTTP client
ctx = MockContext()
ctx.lifespan_context = {'http_client': httpx.AsyncClient(
timeout=15.0,
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
},
follow_redirects=True
)}
try:
# Test basic search
query = "Python programming language"
print(f"\n1. Testing basic search for: '{query}'")
search_params = {"query": query, "count": 5}
search_results = await duckduckgo_search(search_params, ctx)
print(f"Found {len(search_results['results'])} results:")
for i, result in enumerate(search_results['results'], 1):
print(f"\nResult {i}:")
print(f"Title: {result['title']}")
print(f"URL: {result['url']}")
print(f"Description: {result['description'][:100]}..." if len(result['description']) > 100 else f"Description: {result['description']}")
# Test web search tool
print(f"\n2. Testing web search tool for: '{query}'")
web_search_results = await duckduckgo_web_search(query=query, count=5, page=1, site=None, time_period=None, ctx=ctx)
print(f"Found {len(web_search_results.results)} results:")
for i, result in enumerate(web_search_results.results, 1):
print(f"\nResult {i}:")
print(f"Title: {result.title}")
print(f"URL: {result.url}")
print(f"Description: {result.description[:100]}..." if len(result.description) > 100 else f"Description: {result.description}")
# Test web search with site filter
print("\n3. Testing web search with site filter: 'documentation' on python.org")
site_filtered_results = await duckduckgo_web_search(query="documentation", count=3, page=1, site="python.org", time_period=None, ctx=ctx)
print(f"Found {len(site_filtered_results.results)} results for site python.org:")
for i, result in enumerate(site_filtered_results.results, 1):
print(f"\nResult {i}:")
print(f"Title: {result.title}")
print(f"URL: {result.url}")
print(f"Description: {result.description[:100]}..." if len(result.description) > 100 else f"Description: {result.description}")
# Test web search with time filter
print("\n4. Testing web search with time filter: 'python release' from last year")
time_filtered_results = await duckduckgo_web_search(query="python release", count=3, page=1, site=None, time_period="year", ctx=ctx)
print(f"Found {len(time_filtered_results.results)} results from last year:")
for i, result in enumerate(time_filtered_results.results, 1):
print(f"\nResult {i}:")
print(f"Title: {result.title}")
print(f"URL: {result.url}")
print(f"Description: {result.description[:100]}..." if len(result.description) > 100 else f"Description: {result.description}")
# Test content extraction with different spider depths
print("\n5. Testing enhanced content extraction with spidering:")
# Test with an official documentation site
print("\n5.1. Testing enhanced extraction on Python.org (no spidering)")
python_org_details = await duckduckgo_get_details(url="https://www.python.org/", ctx=ctx)
print_detailed_result(python_org_details, include_linked_content=False)
# Test with a Wikipedia article with spidering depth 1
print("\n5.2. Testing enhanced extraction on Wikipedia with spidering (depth=1)")
wiki_details = await duckduckgo_get_details(
url="https://en.wikipedia.org/wiki/Python_(programming_language)",
spider_depth=1,
max_links_per_page=2,
same_domain_only=True,
ctx=ctx
)
print_detailed_result(wiki_details, include_linked_content=True)
# Test with a documentation page
print("\n5.3. Testing enhanced extraction on Python documentation")
docs_details = await duckduckgo_get_details(url="https://docs.python.org/3/tutorial/", ctx=ctx)
print_detailed_result(docs_details, include_linked_content=False)
# Test related searches
print(f"\n6. Testing related searches for: '{query}'")
related_queries = await duckduckgo_related_searches(query=query, count=5, ctx=ctx)
print(f"Found {len(related_queries)} related searches:")
for i, related_query in enumerate(related_queries, 1):
print(f"{i}. {related_query}")
except Exception as e:
print(f"Error: {e}")
finally:
# Close HTTP client
await ctx.lifespan_context['http_client'].aclose()
def print_detailed_result(result, include_linked_content=False):
"""Pretty print a DetailedResult."""
print(f"Title: {result.title}")
print(f"URL: {result.url}")
print(f"Domain: {result.domain}")
print(f"Official Source: {result.is_official}")
if result.author:
print(f"Author: {result.author}")
if result.published_date:
print(f"Published Date: {result.published_date}")
if result.keywords:
print(f"Keywords: {', '.join(result.keywords)}")
if result.main_image:
print(f"Main Image: {result.main_image}")
if result.social_links:
print("Social Links:")
for platform, url in result.social_links.items():
print(f" - {platform}: {url}")
if result.headings:
print("Content Structure:")
for i, heading in enumerate(result.headings[:5], 1):
print(f" {i}. {heading}")
if len(result.headings) > 5:
print(f" ... ({len(result.headings) - 5} more headings)")
print("Description:", end=" ")
if result.description:
if len(result.description) > 150:
print(f"{result.description[:150]}...")
else:
print(result.description)
else:
print("None")
print("Content Snippet:", end=" ")
if result.content_snippet:
if len(result.content_snippet) > 200:
print(f"{result.content_snippet[:200]}...")
else:
print(result.content_snippet)
else:
print("None")
if result.related_links:
print(f"Related Links: {len(result.related_links)} found")
for i, link in enumerate(result.related_links[:3], 1):
print(f" {i}. {link}")
if len(result.related_links) > 3:
print(f" ... ({len(result.related_links) - 3} more links)")
if include_linked_content and result.linked_content:
print(f"\nLinked Content: {len(result.linked_content)} pages")
for i, content in enumerate(result.linked_content[:2], 1):
print(f"\n Linked Page {i} ({content.relation}):")
print(f" Title: {content.title}")
print(f" URL: {content.url}")
if content.content_snippet:
if len(content.content_snippet) > 150:
print(f" Snippet: {content.content_snippet[:150]}...")
else:
print(f" Snippet: {content.content_snippet}")
if len(result.linked_content) > 2:
print(f" ... ({len(result.linked_content) - 2} more linked pages)")
# Run the test
if __name__ == "__main__":
asyncio.run(test_real_search())