mcp.md•12.9 kB
# Brave Search MCP Server Documentation
## Overview
This guide walks you through setting up and running a Model Context Protocol (MCP) server that provides Brave Search functionality via Streamable HTTP transport. The server offers two search tools: web search and local business search.
## Prerequisites
### Required Software
- **Bun** (JavaScript runtime) - Install from [bun.sh](https://bun.sh)
- **Brave Search API Key** - Obtain from [Brave Search API](https://api.search.brave.com/)
- **Basic terminal/command line knowledge**
### System Requirements
- Node.js 18+ compatible environment
- Internet connection for API calls
- Available port (default: 8000)
## Installation & Setup
### 1. Project Setup
```bash
# Clone or download the brave-search MCP server files
# Ensure you have these files:
# - index.ts (main server file)
# - package.json (dependencies)
# - tsconfig.json (TypeScript config)
```
### 2. Install Dependencies
```bash
# Navigate to the brave-search directory
cd /path/to/brave-search
# Install all required packages
bun install
```
**What this does:** Downloads the MCP SDK and other dependencies needed to run the server.
### 3. API Key Configuration
```bash
# Option 1: Environment variable (recommended for production)
export BRAVE_API_KEY="your-brave-api-key-here"
# Option 2: The server has a fallback hardcoded key for testing
# (already configured in the current implementation)
```
**Security Note:** Never commit API keys to version control. Use environment variables in production.
## Running the Server
### Starting the Server
```bash
# Start the server on port 8000 with Streamable HTTP transport
bun run index.ts --port 8000
```
**Expected Output:**
```
Listening on http://localhost:8000
Put this in your client config:
{
"mcpServers": {
"brave-search": {
"url": "http://localhost:8000/sse"
}
}
}
If your client supports streamable HTTP, you can use the /mcp endpoint instead.
```
### Understanding the Endpoints
The server provides two endpoints:
1. **`/sse`** - Server-Sent Events transport (for backward compatibility)
2. **`/mcp`** - Streamable HTTP transport (recommended for new implementations)
## Testing the Server
### 1. Initialize MCP Session
```bash
curl -v -X POST http://localhost:8000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"clientInfo": {
"name": "TestClient",
"version": "1.0.0"
}
}
}'
```
**What to look for:**
- Status: `200 OK`
- Header: `mcp-session-id: [uuid]` (save this for next steps)
- Response: JSON with server capabilities
### 2. Send Initialized Notification
```bash
curl -X POST http://localhost:8000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID_FROM_STEP_1" \
-d '{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}'
```
**Critical:** Replace `YOUR_SESSION_ID_FROM_STEP_1` with the actual session ID from step 1.
### 3. List Available Tools
```bash
curl -X POST http://localhost:8000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}'
```
**Expected Response:** List of two tools:
- `brave_web_search` - General web search
- `brave_local_search` - Local business search
### 4. Perform Web Search
```bash
curl -X POST http://localhost:8000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "brave_web_search",
"arguments": {
"query": "latest AI news",
"count": 3
}
}
}'
```
### 5. Perform Local Search
```bash
curl -X POST http://localhost:8000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "brave_local_search",
"arguments": {
"query": "pizza near Times Square NYC",
"count": 2
}
}
}'
```
## Implementation Details: From Stdio to Streamable HTTP
### What We Changed
The original brave-search MCP server only supported stdio transport (standard input/output). We modified it to support Streamable HTTP transport for AWS Lambda compatibility and better web integration.
### Key Code Changes
#### 1. Added HTTP Transport Imports
```typescript
// Added these imports
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { createServer } from "http";
import { randomUUID } from "crypto";
```
#### 2. Command Line Argument Parsing
```typescript
// Added argument parsing for --port flag
function parseArgs() {
const args = process.argv.slice(2);
const options: { port?: number; headless?: boolean } = {};
for (let i = 0; i < args.length; i++) {
if (args[i] === '--port' && i + 1 < args.length) {
options.port = parseInt(args[i + 1], 10);
i++;
}
}
return options;
}
```
#### 3. HTTP Server Setup
```typescript
// Added HTTP server with dual transport support
function startHttpServer(port: number) {
const httpServer = createServer();
httpServer.on('request', async (req, res) => {
const url = new URL(req.url!, `http://${req.headers.host}`);
if (url.pathname === '/sse') {
await handleSSE(req, res);
} else if (url.pathname === '/mcp') {
await handleStreamable(req, res);
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
}
```
#### 4. Session Management
```typescript
// Added session storage for concurrent connections
const streamableSessions = new Map<string, {transport: any, server: any}>();
// Each session gets its own server instance
function createServerInstance() {
const serverInstance = new Server({...});
// Set up tool handlers...
return serverInstance;
}
```
#### 5. Transport Handlers
```typescript
// Streamable HTTP transport handler
async function handleStreamable(req: any, res: any) {
const sessionId = req.headers['mcp-session-id'] as string | undefined;
if (sessionId) {
// Use existing session
const session = streamableSessions.get(sessionId);
return await session.transport.handleRequest(req, res);
}
// Create new session for initialization
const serverInstance = createServerInstance();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sessionId) => {
streamableSessions.set(sessionId, { transport, server: serverInstance });
}
});
await serverInstance.connect(transport);
await transport.handleRequest(req, res);
}
```
### Why These Changes Were Necessary
1. **Lambda Compatibility**: AWS Lambda doesn't support stdio, requiring HTTP-based communication
2. **Web Integration**: HTTP transport enables direct browser and web service integration
3. **Concurrent Sessions**: Multiple clients can connect simultaneously with session isolation
4. **Modern Protocol**: Streamable HTTP is the modern MCP transport standard
### Transport Comparison
| Feature | Stdio Transport | Streamable HTTP Transport |
|---------|----------------|---------------------------|
| Use Case | CLI applications | Web services, Lambda |
| Concurrency | Single client | Multiple concurrent clients |
| State Management | Process-based | Session-based |
| AWS Lambda | ❌ Not supported | ✅ Fully supported |
| Web Browser | ❌ Not possible | ✅ Direct integration |
| Debugging | Simple | Requires HTTP tools |
## Understanding MCP Concepts
### Session Management
- Each client connection gets a unique session ID
- Sessions maintain state between requests
- Sessions are automatically cleaned up when connections close
- **Important:** Always include the `Mcp-Session-Id` header after initialization
### Transport Types
1. **Streamable HTTP** (`/mcp`): Modern, efficient, supports streaming responses
2. **SSE** (`/sse`): Backward compatibility, uses Server-Sent Events
### Message Flow
1. **Initialize** - Establish capabilities and protocol version
2. **Initialized** - Confirm initialization complete
3. **Tools/List** - Discover available tools
4. **Tools/Call** - Execute tool functions
## Common Issues & Troubleshooting
### "Server not initialized" Error
**Cause:** Missing or incorrect session ID
**Solution:** Ensure you're using the session ID from the initialization response
### "Session not found" Error
**Cause:** Session expired or invalid session ID
**Solution:** Re-initialize with a new session
### Port Already in Use
**Cause:** Another process is using port 8000
**Solution:**
```bash
# Kill process on port 8000
lsof -ti:8000 | xargs kill -9
# Or use a different port
bun run index.ts --port 8001
```
### API Rate Limiting
**Cause:** Exceeded Brave Search API limits
**Solution:** The server has built-in rate limiting (1 request/second, 15000/month)
### Connection Timeout
**Cause:** Network issues or server overload
**Solution:** Check network connectivity and server resources
## Concurrent Connection Management
### How It Works
- Each client gets its own server instance and transport
- Sessions are isolated - no shared state between clients
- Automatic cleanup when clients disconnect
- Memory-efficient session storage using Maps
### Scaling Considerations
```typescript
// Current session storage (in-memory)
const streamableSessions = new Map<string, {transport: any, server: any}>();
```
**For production:**
- Consider Redis for session storage across multiple instances
- Implement session cleanup timeouts
- Monitor memory usage for session maps
- Use load balancers for horizontal scaling
### Connection Limits
- Default: No explicit connection limit
- Memory-bound by available system resources
- Each session uses ~1-5MB of memory
## Production Deployment
### Environment Variables
```bash
export BRAVE_API_KEY="your-production-api-key"
export PORT="8000"
export NODE_ENV="production"
```
### Process Management
```bash
# Using PM2 for process management
npm install -g pm2
pm2 start "bun run index.ts --port 8000" --name brave-search-mcp
```
### Docker Deployment
```dockerfile
FROM oven/bun:latest
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install
COPY . .
EXPOSE 8000
CMD ["bun", "run", "index.ts", "--port", "8000"]
```
### AWS Lambda Deployment
The server supports Streamable HTTP, making it suitable for serverless deployment:
- Configure API Gateway to proxy requests to `/mcp`
- Set appropriate timeout values (30s+)
- Handle cold starts gracefully
## Security Best Practices
### API Key Security
- Use environment variables, never hardcode keys
- Rotate API keys regularly
- Monitor API usage and set alerts
### Network Security
- Bind to localhost (`127.0.0.1`) for local development
- Use HTTPS in production
- Implement proper authentication for public deployments
### Input Validation
- The server validates JSON-RPC message format
- Search queries are limited to 400 characters
- Count parameters are bounded (1-20 results)
## Monitoring & Logging
### Built-in Logging
The server logs:
- Session creation/destruction
- API errors and rate limiting
- Connection events
### Health Checks
```bash
# Simple health check
curl -f http://localhost:8000/mcp || echo "Server down"
```
### Metrics to Monitor
- Active session count
- API call frequency
- Response times
- Error rates
- Memory usage
## Advanced Configuration
### Custom Rate Limiting
```typescript
const RATE_LIMIT = {
perSecond: 1, // Requests per second
perMonth: 15000 // Monthly request limit
};
```
### Timeout Configuration
```typescript
// Adjust in createServerInstance() if needed
const serverInstance = new Server({
name: "brave-search",
version: "1.0.0"
}, {
capabilities: { tools: {} },
// Add timeout configs here
});
```
## Support & Further Reading
- [MCP Specification](https://modelcontextprotocol.io/specification/draft/)
- [Brave Search API Documentation](https://api.search.brave.com/app/documentation)
- [Bun Documentation](https://bun.sh/docs)
This server is now ready for production use and can handle multiple concurrent connections efficiently while providing reliable Brave Search functionality through the MCP protocol.