Skip to main content
Glama
index.ts5.2 kB
import { ToolDefinition, ToolResponse } from '../types.js'; import { Config } from '../../config/config.js'; import axios from 'axios'; import { HttpsProxyAgent } from 'https-proxy-agent'; interface BraveSearchResult { title: string; url: string; description: string; } interface BraveSearchResponse { web: { results: BraveSearchResult[]; total: number; }; } // 搜索管理器类 class SearchManager { private readonly baseUrl = 'https://api.search.brave.com/res/v1/web/search'; private lastRequestTime: number = 0; private readonly minRequestInterval: number = 1000; constructor(private readonly config: Config) {} private validateApiKey(): void { if (!this.config.brave.apiKey) { throw new Error('请先在配置文件中设置 Brave Search API 密钥'); } } private getRequestOptions() { const options: any = { headers: { 'X-Subscription-Token': this.config.brave.apiKey, 'Accept': 'application/json', } }; // 如果配置了代理,使用代理 if (this.config.network.proxy) { options.httpsAgent = new HttpsProxyAgent(this.config.network.proxy); } return options; } private async enforceRateLimit(): Promise<void> { const now = Date.now(); if (now - this.lastRequestTime < this.minRequestInterval) { await new Promise(resolve => setTimeout(resolve, this.minRequestInterval)); } this.lastRequestTime = now; } // Brave 搜索处理器 async search(args: { query: string; count?: number; type?: 'web' | 'news'; country?: string; search_lang?: string; }): Promise<ToolResponse> { try { if (!args.query?.trim()) { return { content: [{ type: 'text', text: '搜索关键词不能为空' }], isError: true }; } this.validateApiKey(); await this.enforceRateLimit(); const response = await axios.get(this.baseUrl, { ...this.getRequestOptions(), params: { q: args.query, count: args.count || 10, type: args.type || 'web', country: args.country, search_lang: args.search_lang } }); if (response.status === 401) { return { content: [{ type: 'text', text: 'API密钥无效或已过期,请检查配置文件中的 brave.apiKey' }], isError: true }; } if (!response.status) { throw new Error(`HTTP error! status: ${response.status}`); } const data = response.data as BraveSearchResponse; if (!data.web?.results?.length) { return { content: [{ type: 'text', text: '未找到任何结果' }] }; } // 格式化搜索结果为文本 const resultText = data.web.results.map((result, index) => { return `${index + 1}. ${result.title}\n ${result.url}\n ${result.description}\n`; }).join('\n'); return { content: [{ type: 'text', text: `找到 ${data.web.total} 个结果:\n\n${resultText}` }] }; } catch (error: unknown) { if (error instanceof Error) { if (error.message.includes('429')) { return { content: [{ type: 'text', text: '已超过API调用限制,请等待一段时间后重试' }], isError: true }; } return { content: [{ type: 'text', text: `搜索请求失败: ${error.message}` }], isError: true }; } return { content: [{ type: 'text', text: '搜索过程中发生未知错误' }], isError: true }; } } } // 创建搜索工具 export function createSearchTools(config: Config): ToolDefinition[] { const manager = new SearchManager(config); return [ { name: 'brave_search', description: '使用Brave搜索引擎搜索网页。当需要搜索网页内容时优先使用此工具,而不是使用浏览器。支持高级搜索语法,结果更准确且无广告。', inputSchema: { type: 'object', properties: { query: { type: 'string', description: '搜索关键词。支持高级搜索语法,如: "site:github.com typescript"' }, count: { type: 'number', description: '返回结果数量,默认10,最大20' }, type: { type: 'string', description: '搜索类型: web(网页搜索) 或 news(新闻搜索)', enum: ['web', 'news'], default: 'web' }, country: { type: 'string', description: '国家代码,如: us, cn等。默认为全球' }, search_lang: { type: 'string', description: '搜索语言,如: en, zh等。默认为所有语言' } }, required: ['query'] }, handler: args => manager.search(args) } ]; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zxfgds/mcp-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server