mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-24 23:05:21 +02:00
Updated Brave
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
# DuckDuckGo MCP Server
|
||||
|
||||
MCP server providing search functionality via DuckDuckGo's HTML interface.
|
||||
|
||||
## Components
|
||||
|
||||
### Resources
|
||||
Single resource endpoint for search interface:
|
||||
```duckduckgo://search```
|
||||
|
||||
### Tools
|
||||
- **duckduckgo_search**
|
||||
- Performs a search using DuckDuckGo and returns the top search results
|
||||
- Inputs:
|
||||
- `query` (string, required): The search query to look up
|
||||
- `numResults` (number, optional): Number of results to return (default: 10)
|
||||
- Returns titles, snippets, and URLs of the search results
|
||||
|
||||
## Usage Example
|
||||
```javascript
|
||||
// Example tool call
|
||||
{
|
||||
"name": "duckduckgo_search",
|
||||
"arguments": {
|
||||
"query": "your search query",
|
||||
"numResults": 10
|
||||
}
|
||||
}
|
||||
|
||||
// Example response format:
|
||||
{
|
||||
"content": [{
|
||||
"type": "text",
|
||||
"text": "Title: Result Title\nSnippet: Result description...\nURL: https://example.com\n\nTitle: Another Result\n..."
|
||||
}]
|
||||
}
|
||||
```
|
||||
@@ -1,176 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListResourcesRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
Tool,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import fetch from "node-fetch";
|
||||
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. " +
|
||||
"Use this tool to search for current information on the internet.",
|
||||
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(
|
||||
{
|
||||
name: "example-servers/duckduckgo",
|
||||
version: "0.1.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
resources: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
||||
resources: [
|
||||
{
|
||||
uri: "duckduckgo://search",
|
||||
mimeType: "text/plain",
|
||||
name: "DuckDuckGo Search Results",
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
||||
if (request.params.uri.toString() === "duckduckgo://search") {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: "duckduckgo://search",
|
||||
mimeType: "text/plain",
|
||||
text: "DuckDuckGo search interface",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
throw new Error("Resource not found");
|
||||
});
|
||||
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools: [SEARCH_TOOL],
|
||||
}));
|
||||
|
||||
async function performSearch(query: string, numResults: number = 10) {
|
||||
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
||||
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") || "",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
if (request.params.name === "duckduckgo_search") {
|
||||
try {
|
||||
const { query, numResults = 10 } = request.params.arguments as {
|
||||
query: string;
|
||||
numResults?: number;
|
||||
};
|
||||
|
||||
const results = await performSearch(query, numResults);
|
||||
|
||||
const formattedResults = results
|
||||
.map(
|
||||
(result) =>
|
||||
`Title: ${result.title}\nSnippet: ${result.snippet}\nURL: ${result.url}\n`,
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: formattedResults || "No results found.",
|
||||
},
|
||||
],
|
||||
isError: false,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Error performing search: ${error instanceof Error ? error.message : String(error)}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Unknown tool: ${request.params.name}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
});
|
||||
|
||||
async function runServer() {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error("DuckDuckGo MCP Server running on stdio");
|
||||
}
|
||||
|
||||
runServer().catch((error) => {
|
||||
console.error("Fatal error running server:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "@modelcontextprotocol/server-duckduckgo",
|
||||
"version": "0.1.0",
|
||||
"description": "MCP server for DuckDuckGo search",
|
||||
"license": "MIT",
|
||||
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||
"homepage": "https://modelcontextprotocol.io",
|
||||
"bugs": "https://github.com/modelcontextprotocol/servers/issues",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"mcp-server-duckduckgo": "dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc && shx chmod +x dist/*.js",
|
||||
"prepare": "npm run build",
|
||||
"watch": "tsc --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "0.5.0",
|
||||
"jsdom": "^24.1.3",
|
||||
"node-fetch": "^3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/node": "^20.10.0",
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": [
|
||||
"./**/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user