mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2024-12-01 18:58:34 +03:00
Updated Brave
This commit is contained in:
61
package-lock.json
generated
61
package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"src/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/server-brave-search": "*",
|
||||
"@modelcontextprotocol/server-duckduckgo": "*",
|
||||
"@modelcontextprotocol/server-everything": "*",
|
||||
"@modelcontextprotocol/server-filesystem": "*",
|
||||
@@ -162,6 +163,10 @@
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/server-brave-search": {
|
||||
"resolved": "src/brave-search",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/server-duckduckgo": {
|
||||
"resolved": "src/duckduckgo",
|
||||
"link": true
|
||||
@@ -3607,6 +3612,62 @@
|
||||
"zod": "^3.23.3"
|
||||
}
|
||||
},
|
||||
"src/brave-search": {
|
||||
"name": "@modelcontextprotocol/server-brave-search",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "0.5.0",
|
||||
"jsdom": "^24.1.3",
|
||||
"node-fetch": "^3.3.2"
|
||||
},
|
||||
"bin": {
|
||||
"mcp-server-brave-search": "dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/node": "^20.10.0",
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
},
|
||||
"src/brave-search/node_modules/@types/node": {
|
||||
"version": "20.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz",
|
||||
"integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"src/brave-search/node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"src/brave-search/node_modules/node-fetch": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"src/duckduckgo": {
|
||||
"name": "@modelcontextprotocol/server-duckduckgo",
|
||||
"version": "0.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Brave Search MCP Server
|
||||
|
||||
An MCP server implementation that integrates the Brave Search API, providing both web and local search capabilities through the Model Context Protocol.
|
||||
An MCP server implementation that integrates the Brave Search API, providing both web and local search capabilities.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -9,86 +9,38 @@ An MCP server implementation that integrates the Brave Search API, providing bot
|
||||
- **Flexible Filtering**: Control result types, safety levels, and content freshness
|
||||
- **Smart Fallbacks**: Local search automatically falls back to web when no results are found
|
||||
|
||||
## Tools
|
||||
|
||||
- **brave_web_search**
|
||||
- Execute web searches with pagination and filtering
|
||||
- Inputs:
|
||||
- `query` (string): Search terms
|
||||
- `count` (number, optional): Results per page (max 20)
|
||||
- `offset` (number, optional): Pagination offset (max 9)
|
||||
|
||||
- **brave_local_search**
|
||||
- Search for local businesses and services
|
||||
- Inputs:
|
||||
- `query` (string): Local search terms
|
||||
- `count` (number, optional): Number of results (max 20)
|
||||
- Automatically falls back to web search if no local results found
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
### Client Configuration
|
||||
Add this to your MCP client config:
|
||||
### Getting an API Key
|
||||
1. Sign up for a [Brave Search API account](https://brave.com/search/api/)
|
||||
2. Choose a plan (Free tier available with 2,000 queries/month)
|
||||
3. Generate your API key [from the developer dashboard](https://api.search.brave.com/app/keys)
|
||||
|
||||
### Usage with Claude Desktop
|
||||
Add this to your `claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
"brave-search": {
|
||||
"mcp-server-brave-search": {
|
||||
"command": "mcp-server-brave-search",
|
||||
"env": {
|
||||
"BRAVE_API_KEY": "YOUR_API_KEY_HERE"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you can set the API key as an environment variable:
|
||||
|
||||
```bash
|
||||
export BRAVE_API_KEY='your_actual_api_key_here'
|
||||
```
|
||||
|
||||
### Getting an API Key
|
||||
1. Sign up for a Brave Search API account
|
||||
2. Choose a plan (Free tier available)
|
||||
3. Generate your API key from the developer dashboard
|
||||
|
||||
## Tools
|
||||
|
||||
### brave_web_search
|
||||
Performs general web searches:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"name": "brave_web_search",
|
||||
"arguments": {
|
||||
"query": "latest AI developments",
|
||||
"count": 10,
|
||||
"freshness": "pw", // Past week
|
||||
"safesearch": "moderate"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### brave_local_search
|
||||
Finds local businesses and services:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"name": "brave_local_search",
|
||||
"arguments": {
|
||||
"query": "pizza near Central Park",
|
||||
"count": 5,
|
||||
"units": "imperial"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
- Rate limiting to respect API quotas (1 request/second, 15000/month)
|
||||
- Parallel fetching of POI details and descriptions for local search
|
||||
- Type-safe argument validation
|
||||
- Comprehensive error handling and logging
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Build the server
|
||||
npm run build
|
||||
|
||||
# Run the server
|
||||
mcp-server-brave-search
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions welcome! Please check the issues tab or submit a PR.
|
||||
|
||||
## License
|
||||
|
||||
MIT - see [LICENSE](LICENSE) file for details.
|
||||
|
||||
@@ -4,26 +4,18 @@ 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";
|
||||
|
||||
// Define tool schemas
|
||||
const WEB_SEARCH_TOOL: Tool = {
|
||||
name: "brave_web_search",
|
||||
description:
|
||||
"Performs a web search using the Brave Search API, ideal for general queries, news, articles, and online content. " +
|
||||
"Use this for broad information gathering, recent events, or when you need diverse web sources. " +
|
||||
"Supports pagination, content filtering, and freshness controls. " +
|
||||
"Maximum 20 results per request, with offset for pagination. " +
|
||||
"Additional features:\n" +
|
||||
"- Safesearch: moderate (default), strict, or off\n" +
|
||||
"- Freshness: filter by recency (past day/week/month/year)\n" +
|
||||
"- Result types: web, news, videos, discussions\n" +
|
||||
"- Spell check and query alteration support",
|
||||
"Maximum 20 results per request, with offset for pagination. ",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
@@ -41,37 +33,6 @@ const WEB_SEARCH_TOOL: Tool = {
|
||||
description: "Pagination offset (max 9, default 0)",
|
||||
default: 0
|
||||
},
|
||||
freshness: {
|
||||
type: "string",
|
||||
description: "Filter by recency: pd (past day), pw (past week), pm (past month), or custom date range",
|
||||
enum: ["pd", "pw", "pm", "py"]
|
||||
},
|
||||
safesearch: {
|
||||
type: "string",
|
||||
description: "Content filtering level",
|
||||
enum: ["off", "moderate", "strict"],
|
||||
default: "moderate"
|
||||
},
|
||||
country: {
|
||||
type: "string",
|
||||
description: "2-letter country code for localized results",
|
||||
default: "US"
|
||||
},
|
||||
search_lang: {
|
||||
type: "string",
|
||||
description: "Search language (2+ char code)",
|
||||
default: "en"
|
||||
},
|
||||
ui_lang: {
|
||||
type: "string",
|
||||
description: "UI language preference",
|
||||
default: "en-US"
|
||||
},
|
||||
result_filter: {
|
||||
type: "string",
|
||||
description: "Comma-separated result types: web, news, videos, discussions, locations",
|
||||
default: null
|
||||
}
|
||||
},
|
||||
required: ["query"],
|
||||
},
|
||||
@@ -86,7 +47,6 @@ const LOCAL_SEARCH_TOOL: Tool = {
|
||||
"- Business names and addresses\n" +
|
||||
"- Ratings and review counts\n" +
|
||||
"- Phone numbers and opening hours\n" +
|
||||
"- AI-generated descriptions\n" +
|
||||
"Use this when the query implies 'near me' or mentions specific locations. " +
|
||||
"Automatically falls back to web search if no local results are found.",
|
||||
inputSchema: {
|
||||
@@ -101,26 +61,6 @@ const LOCAL_SEARCH_TOOL: Tool = {
|
||||
description: "Number of results (1-20, default 5)",
|
||||
default: 5
|
||||
},
|
||||
units: {
|
||||
type: "string",
|
||||
description: "Measurement system for distances",
|
||||
enum: ["metric", "imperial"]
|
||||
},
|
||||
country: {
|
||||
type: "string",
|
||||
description: "2-letter country code for localized results",
|
||||
default: "US"
|
||||
},
|
||||
search_lang: {
|
||||
type: "string",
|
||||
description: "Search language (2+ char code)",
|
||||
default: "en"
|
||||
},
|
||||
ui_lang: {
|
||||
type: "string",
|
||||
description: "UI language preference",
|
||||
default: "en-US"
|
||||
}
|
||||
},
|
||||
required: ["query"]
|
||||
}
|
||||
@@ -135,7 +75,6 @@ const server = new Server(
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
resources: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -221,7 +160,6 @@ interface BraveDescription {
|
||||
descriptions: {[id: string]: string};
|
||||
}
|
||||
|
||||
// Type guard functions for arguments
|
||||
function isBraveWebSearchArgs(args: unknown): args is { query: string; count?: number } {
|
||||
return (
|
||||
typeof args === "object" &&
|
||||
@@ -240,19 +178,12 @@ function isBraveLocalSearchArgs(args: unknown): args is { query: string; count?:
|
||||
);
|
||||
}
|
||||
|
||||
// API functions
|
||||
async function performWebSearch(query: string, count: number = 10, offset: number = 0) {
|
||||
checkRateLimit();
|
||||
const url = new URL('https://api.search.brave.com/res/v1/web/search');
|
||||
url.searchParams.set('q', query);
|
||||
url.searchParams.set('search_lang', 'en');
|
||||
url.searchParams.set('count', Math.min(count, 20).toString()); // API limit
|
||||
url.searchParams.set('offset', offset.toString());
|
||||
url.searchParams.set('result_filter', 'web');
|
||||
url.searchParams.set('text_decorations', '0');
|
||||
url.searchParams.set('spellcheck', '0');
|
||||
url.searchParams.set('safesearch', 'moderate');
|
||||
url.searchParams.set('freshness', 'pw'); // Past week results
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
@@ -377,32 +308,6 @@ Description: ${descData.descriptions[poi.id] || 'No description available'}
|
||||
}).join('\n---\n') || 'No local results found';
|
||||
}
|
||||
|
||||
// Resource handlers
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
||||
resources: [
|
||||
{
|
||||
uri: "brave://search",
|
||||
mimeType: "text/plain",
|
||||
name: "Brave Search Interface",
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
||||
if (request.params.uri.toString() === "brave://search") {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: "brave://search",
|
||||
mimeType: "text/plain",
|
||||
text: "Brave Search API interface",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
throw new Error("Resource not found");
|
||||
});
|
||||
|
||||
// Tool handlers
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools: [WEB_SEARCH_TOOL, LOCAL_SEARCH_TOOL],
|
||||
|
||||
Reference in New Issue
Block a user