@brave/brave-search-mcp-server
Version:
Brave Search MCP Server: web results, images, videos, rich results, AI summaries, and more.
97 lines (96 loc) • 4.35 kB
JavaScript
import { LoggingLevelSchema } from '@modelcontextprotocol/sdk/types.js';
import { Command } from 'commander';
import dotenv from 'dotenv';
import tools from './tools/index.js';
dotenv.config({ debug: false, quiet: true });
function parseToolNameList(value) {
if (value == null)
return [];
if (Array.isArray(value))
return value.map((t) => t.trim()).filter((t) => t.length > 0);
return value
.trim()
.split(/\s+/)
.filter((t) => t.length > 0);
}
const state = {
transport: 'stdio',
port: 8080,
host: '0.0.0.0',
braveApiKey: process.env.BRAVE_API_KEY ?? '',
loggingLevel: 'info',
ready: false,
enabledTools: [],
disabledTools: [],
stateless: false,
};
export function isToolPermittedByUser(toolName) {
return state.enabledTools.length > 0
? state.enabledTools.includes(toolName)
: state.disabledTools.includes(toolName) === false;
}
export function getOptions() {
const program = new Command()
.option('--brave-api-key <string>', 'Brave API key', process.env.BRAVE_API_KEY ?? '')
.option('--logging-level <string>', 'Logging level', process.env.BRAVE_MCP_LOG_LEVEL ?? 'info')
.option('--transport <stdio|http>', 'transport type', process.env.BRAVE_MCP_TRANSPORT ?? 'stdio')
.option('--enabled-tools <names...>', 'tools to enable', process.env.BRAVE_MCP_ENABLED_TOOLS?.trim().split(' ') ?? [])
.option('--disabled-tools <names...>', 'tools to disable', process.env.BRAVE_MCP_DISABLED_TOOLS?.trim().split(' ') ?? [])
.option('--port <number>', 'desired port for HTTP transport', process.env.BRAVE_MCP_PORT ?? '8080')
.option('--host <string>', 'desired host for HTTP transport', process.env.BRAVE_MCP_HOST ?? '0.0.0.0')
.option('--stateless <boolean>', 'whether the server should be stateless', process.env.BRAVE_MCP_STATELESS === 'true' ? true : false)
.allowUnknownOption()
.parse(process.argv);
const options = program.opts();
const toolNames = Object.values(tools).map((tool) => tool.name);
// Validate tool inclusion configuration
const enabledTools = parseToolNameList(options.enabledTools);
const disabledTools = parseToolNameList(options.disabledTools);
if (enabledTools.length > 0 && disabledTools.length > 0) {
console.error('Error: --enabled-tools and --disabled-tools cannot be used together');
return false;
}
const invalidToolNames = [...enabledTools, ...disabledTools].filter((t) => !toolNames.includes(t));
if (invalidToolNames.length > 0) {
console.error(`Invalid tool name(s) used: ${invalidToolNames.join(', ')}`);
console.error(`Valid tool names are: ${toolNames.join(', ')}`);
return false;
}
// Validate all other options
if (!['stdio', 'http'].includes(options.transport)) {
console.error(`Invalid --transport value: '${options.transport}'. Must be one of: stdio, http.`);
return false;
}
if (!LoggingLevelSchema.options.includes(options.loggingLevel)) {
console.error(`Invalid --logging-level value: '${options.loggingLevel}'. Must be one of: ${LoggingLevelSchema.options.join(', ')}`);
return false;
}
if (!options.braveApiKey) {
console.error('Error: --brave-api-key is required. You can get one at https://brave.com/search/api/.');
return false;
}
if (options.transport === 'http') {
if (options.port < 1 || options.port > 65535) {
console.error(`Invalid --port value: '${options.port}'. Must be a valid port number between 1 and 65535.`);
return false;
}
if (!options.host) {
console.error('Error: --host is required');
return false;
}
}
// Normalize stateless to boolean (CLI passes it as string)
options.stateless = options.stateless === true || options.stateless === 'true';
// Update state
state.braveApiKey = options.braveApiKey;
state.transport = options.transport;
state.port = options.port;
state.host = options.host;
state.loggingLevel = options.loggingLevel;
state.enabledTools = enabledTools;
state.disabledTools = disabledTools;
state.stateless = options.stateless;
state.ready = true;
return options;
}
export default state;