Skip to main content
Glama

search_news

Search for news articles across multiple APIs with automatic failover. Retrieve relevant results in over 20 languages without managing API quotas or limits.

Instructions

Search for news articles using multiple news APIs with automatic failover. The system intelligently switches between different news APIs when one reaches its limit or fails.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
languageNoLanguage code for news articles (e.g., 'en', 'zh', 'es')en
limitNoMaximum number of articles to return (1-10)
queryYesSearch query for news articles (keywords, topics, etc.)

Implementation Reference

  • The exported `newsSearch` tool object defining the `search_news` tool. Contains the name, description, input parameters schema, and the `run` handler function that implements the complete tool logic including input validation, multi-API quota management, automatic failover between APIs, HTTP requests, response formatting, and error handling.
    export const newsSearch = { name: "search_news", description: "Search for news articles using multiple news APIs with automatic failover. The system intelligently switches between different news APIs when one reaches its limit or fails.", parameters: { type: "object", properties: { query: { type: "string", description: "Search query for news articles (keywords, topics, etc.)" }, language: { type: "string", description: "Language code for news articles (e.g., 'en', 'zh', 'es')", default: "en" }, limit: { type: "number", description: "Maximum number of articles to return (1-10)", minimum: 1, maximum: 10, default: 5 } }, required: ["query"] }, async run(args: { query: string; language?: string; limit?: number }) { try { // Validate input if (!args.query || args.query.trim().length === 0) { throw new Error("Search query cannot be empty"); } const query = args.query.trim(); const language = args.language || 'en'; const limit = Math.min(Math.max(args.limit || 5, 1), 10); // Get available APIs const activeAPIs = getActiveAPIs(); if (activeAPIs.length === 0) { return { content: [{ type: "text", text: "❌ **No News APIs Configured**\n\nPlease configure at least one news API key in your .env file. Available options:\n\n" + "- **NewsAPI.org**: Get free key at https://newsapi.org/register\n" + "- **GNews API**: Get free key at https://gnews.io/\n" + "- **TheNewsAPI**: Get free key at https://www.thenewsapi.com/\n" + "- **NewsData.io**: Get free key at https://newsdata.io/\n" + "- **Twingly**: Get trial key at https://www.twingly.com/news-api/\n\n" + "Add your API keys to the .env file and restart the service." }], isError: true }; } let lastError = ''; let attemptedAPIs: string[] = []; // Try each API in priority order for (const apiConfig of activeAPIs) { // Skip APIs that have reached their daily limit if (!hasRemainingQuota(apiConfig)) { attemptedAPIs.push(`${apiConfig.name} (quota exceeded)`); continue; } attemptedAPIs.push(apiConfig.name); const result = await searchWithAPI(apiConfig, query, language, limit); if (result.success && result.data) { const formattedResponse = formatNewsResponse(result.data, result.apiUsed!); const quotaInfo = `\n\n---\n\n**API Used:** ${result.apiUsed}\n**Remaining Quota:** ${result.remainingQuota} requests\n**Attempted APIs:** ${attemptedAPIs.join(', ')}`; return { content: [{ type: "text", text: formattedResponse + quotaInfo }] }; } else { lastError = result.error || 'Unknown error'; console.warn(`API ${apiConfig.name} failed: ${lastError}`); } } // All APIs failed return { content: [{ type: "text", text: `❌ **All News APIs Failed**\n\n` + `**Query:** "${query}"\n` + `**Attempted APIs:** ${attemptedAPIs.join(', ')}\n` + `**Last Error:** ${lastError}\n\n` + `**Suggestions:**\n` + `- Check your API keys in the .env file\n` + `- Verify your internet connection\n` + `- Try a different search query\n` + `- Some APIs may have temporary outages` }], isError: true }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { content: [{ type: "text", text: `❌ **Search Failed:** ${errorMessage}` }], isError: true }; } } };
  • JSON schema defining the input parameters for the search_news tool: required 'query' string, optional 'language' and 'limit'.
    parameters: { type: "object", properties: { query: { type: "string", description: "Search query for news articles (keywords, topics, etc.)" }, language: { type: "string", description: "Language code for news articles (e.g., 'en', 'zh', 'es')", default: "en" }, limit: { type: "number", description: "Maximum number of articles to return (1-10)", minimum: 1, maximum: 10, default: 5 } }, required: ["query"] },
  • src/index.ts:19-29 (registration)
    MCP server registration for ListToolsRequestHandler, listing the search_news tool with its name, description, and input schema.
    server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: newsSearch.name, description: newsSearch.description, inputSchema: newsSearch.parameters } ] }; });
  • src/index.ts:32-39 (registration)
    MCP server registration for CallToolRequestHandler, with switch case dispatching calls to 'search_news' to the tool's run method.
    server.setRequestHandler(CallToolRequestSchema, async (request) => { switch (request.params.name) { case "search_news": return await newsSearch.run(request.params.arguments as { query: string; language?: string; limit?: number }); default: throw new Error(`Unknown tool: ${request.params.name}`); } });
  • Helper function that performs the actual HTTP search request to a specific news API, handling URL construction for 5 different APIs, error checking, quota incrementing.
    async function searchWithAPI(apiConfig: NewsAPIConfig, query: string, language: string = 'en', pageSize: number = 10): Promise<NewsAPIResponse> { try { let url = ''; let headers: any = {}; // Build API-specific request switch (apiConfig.name) { case 'NewsAPI.org': url = `${apiConfig.baseUrl}?q=${encodeURIComponent(query)}&language=${language}&pageSize=${pageSize}&apiKey=${apiConfig.apiKey}`; break; case 'GNews': url = `${apiConfig.baseUrl}?q=${encodeURIComponent(query)}&lang=${language}&max=${pageSize}&apikey=${apiConfig.apiKey}`; break; case 'TheNewsAPI': url = `${apiConfig.baseUrl}/all?api_token=${apiConfig.apiKey}&search=${encodeURIComponent(query)}&language=${language}&limit=${pageSize}`; break; case 'NewsData.io': url = `${apiConfig.baseUrl}?apikey=${apiConfig.apiKey}&q=${encodeURIComponent(query)}&language=${language}&size=${pageSize}`; break; case 'Twingly': url = `${apiConfig.baseUrl}?q=${encodeURIComponent(query)}&format=json&apikey=${apiConfig.apiKey}`; break; default: throw new Error(`Unsupported API: ${apiConfig.name}`); } const response = await fetch(url, { headers }); if (!response.ok) { const errorText = await response.text(); throw new Error(`HTTP ${response.status}: ${errorText}`); } const data = await response.json(); // Check for API-specific error responses if ((data as any).status === 'error' || (data as any).error) { throw new Error((data as any).message || (data as any).error || 'API returned an error'); } incrementUsage(apiConfig.name); return { success: true, data, apiUsed: apiConfig.name, remainingQuota: getRemainingQuota(apiConfig) }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { success: false, error: errorMessage, apiUsed: apiConfig.name }; } }

Other Tools

Related Tools

Latest Blog Posts

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/guangxiangdebizi/news-mcp'

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