Minor updates to duckduckgo

This commit is contained in:
Mahesh Murag 2024-11-20 01:09:52 -05:00
commit 124ff86101
No known key found for this signature in database

View file

@ -7,10 +7,33 @@ import {
ListResourcesRequestSchema, ListResourcesRequestSchema,
ListToolsRequestSchema, ListToolsRequestSchema,
ReadResourceRequestSchema, ReadResourceRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js"; } from "@modelcontextprotocol/sdk/types.js";
import fetch from "node-fetch"; import fetch from "node-fetch";
import { JSDOM } from "jsdom"; import { JSDOM } from "jsdom";
const SEARCH_TOOL: Tool = {
name: "duckduckgo_search",
description:
"Performs a search using DuckDuckGo and returns the top search results. " +
"Returns titles, snippets, and URLs of the search results. ",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "The search query to look up",
},
numResults: {
type: "number",
description: "Number of results to return (default: 10)",
default: 10,
},
},
required: ["query"],
},
};
const server = new Server( const server = new Server(
{ {
name: "example-servers/duckduckgo", name: "example-servers/duckduckgo",
@ -19,25 +42,21 @@ const server = new Server(
{ {
capabilities: { capabilities: {
tools: {}, tools: {},
resources: {}, // Required since we're using ListResourcesRequestSchema resources: {},
}, },
}, },
); );
// Add Resources List Handler - Important for showing up in the tools list server.setRequestHandler(ListResourcesRequestSchema, async () => ({
server.setRequestHandler(ListResourcesRequestSchema, async () => { resources: [
return { {
resources: [ uri: "duckduckgo://search",
{ mimeType: "text/plain",
uri: "duckduckgo://search", name: "DuckDuckGo Search Results",
mimeType: "text/plain", },
name: "DuckDuckGo Search Results", ],
}, }));
],
};
});
// Add Read Resource Handler
server.setRequestHandler(ReadResourceRequestSchema, async (request) => { server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
if (request.params.uri.toString() === "duckduckgo://search") { if (request.params.uri.toString() === "duckduckgo://search") {
return { return {
@ -53,75 +72,56 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
throw new Error("Resource not found"); throw new Error("Resource not found");
}); });
server.setRequestHandler(ListToolsRequestSchema, async () => { server.setRequestHandler(ListToolsRequestSchema, async () => ({
return { tools: [SEARCH_TOOL],
tools: [ }));
{
name: "search", async function performSearch(query: string, numResults: number = 10) {
description: const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
"Performs a search using DuckDuckGo and returns the top search results. " + const headers = {
"Returns titles, snippets, and URLs of the search results. " + "User-Agent":
"Use this tool when you need to search for current information on the internet.", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "The search query to look up",
},
numResults: {
type: "number",
description: "Number of results to return (default: 5)",
default: 5,
},
},
required: ["query"],
},
},
],
}; };
});
const response = await fetch(url, { headers });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const html = await response.text();
const dom = new JSDOM(html);
const document = dom.window.document;
const results = [];
const resultElements = document.querySelectorAll(".result");
for (let i = 0; i < Math.min(numResults, resultElements.length); i++) {
const result = resultElements[i];
const titleElem = result.querySelector(".result__title");
const snippetElem = result.querySelector(".result__snippet");
const urlElem = result.querySelector(".result__url");
if (titleElem && snippetElem) {
results.push({
title: titleElem.textContent?.trim() || "",
snippet: snippetElem.textContent?.trim() || "",
url: urlElem?.getAttribute("href") || "",
});
}
}
return results;
}
server.setRequestHandler(CallToolRequestSchema, async (request) => { server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "search") { if (request.params.name === "duckduckgo_search") {
try { try {
const { query, numResults = 5 } = request.params.arguments as { const { query, numResults = 10 } = request.params.arguments as {
query: string; query: string;
numResults?: number; numResults?: number;
}; };
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`; const results = await performSearch(query, numResults);
const 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",
};
const response = await fetch(url, { headers });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const html = await response.text();
const dom = new JSDOM(html);
const document = dom.window.document;
const results = [];
const resultElements = document.querySelectorAll(".result");
for (let i = 0; i < Math.min(numResults, resultElements.length); i++) {
const result = resultElements[i];
const titleElem = result.querySelector(".result__title");
const snippetElem = result.querySelector(".result__snippet");
const urlElem = result.querySelector(".result__url");
if (titleElem && snippetElem) {
results.push({
title: titleElem.textContent?.trim() || "",
snippet: snippetElem.textContent?.trim() || "",
url: urlElem?.getAttribute("href") || "",
});
}
}
const formattedResults = results const formattedResults = results
.map( .map(
@ -137,6 +137,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
text: formattedResults || "No results found.", text: formattedResults || "No results found.",
}, },
], ],
isError: false,
}; };
} catch (error) { } catch (error) {
return { return {
@ -151,7 +152,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
} }
} }
throw new Error(`Unknown tool: ${request.params.name}`); return {
content: [
{
type: "text",
text: `Unknown tool: ${request.params.name}`,
},
],
isError: true,
};
}); });
async function runServer() { async function runServer() {