Skip to content

Commit

Permalink
Updated Brave
Browse files Browse the repository at this point in the history
  • Loading branch information
maheshmurag committed Nov 21, 2024
1 parent 016f885 commit 7e89d83
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 169 deletions.
61 changes: 61 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 25 additions & 73 deletions src/brave-search/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

## Configuration
## Tools

### Client Configuration
Add this to your MCP client config:
- **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)

```json
"brave-search": {
"command": "mcp-server-brave-search",
"env": {
"BRAVE_API_KEY": "YOUR_API_KEY_HERE"
}
}
```
- **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

Alternatively, you can set the API key as an environment variable:

```bash
export BRAVE_API_KEY='your_actual_api_key_here'
```
## Configuration

### 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
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)

### 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"
}
}
```
### Usage with Claude Desktop
Add this to your `claude_desktop_config.json`:

### brave_local_search
Finds local businesses and services:

```javascript
{
"name": "brave_local_search",
"arguments": {
"query": "pizza near Central Park",
"count": 5,
"units": "imperial"
```json
"mcp-server-brave-search": {
"command": "mcp-server-brave-search",
"env": {
"BRAVE_API_KEY": "YOUR_API_KEY_HERE"
}
}
```

## 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.
97 changes: 1 addition & 96 deletions src/brave-search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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"],
},
Expand All @@ -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: {
Expand All @@ -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"]
}
Expand All @@ -135,7 +75,6 @@ const server = new Server(
{
capabilities: {
tools: {},
resources: {},
},
},
);
Expand Down Expand Up @@ -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" &&
Expand All @@ -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: {
Expand Down Expand Up @@ -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],
Expand Down

0 comments on commit 7e89d83

Please sign in to comment.