Skip to main content
Glama
tanamurayuuki

Gemini URL Context & Search MCP Server

GoogleGenAI.ts3.5 kB
import { GoogleGenerativeAI } from '@google/generative-ai'; import { IGenAI, GenerateUrlContextInput, GenerateUrlContextResponse } from './IGenAI.js'; import { UpstreamUnavailableError, SafetyBlockedError, RateLimitError } from '../domain/DomainError.js'; export class GoogleGenAI implements IGenAI { private readonly genAI: GoogleGenerativeAI; constructor(apiKey: string) { this.genAI = new GoogleGenerativeAI(apiKey); } async generateUrlContextJson(input: GenerateUrlContextInput): Promise<GenerateUrlContextResponse> { const startTime = Date.now(); try { const model = this.genAI.getGenerativeModel({ model: input.model, generationConfig: { responseMimeType: 'application/json' } }); const prompt = this.buildPrompt(input); const result = await model.generateContent(prompt); const response = result.response; const text = response.text(); const processingTimeMs = Date.now() - startTime; try { const parsedResponse = JSON.parse(text); // Update actual processing time if (parsedResponse.url_context_metadata) { parsedResponse.url_context_metadata.processingTimeMs = processingTimeMs; } return parsedResponse; } catch (parseError) { throw new Error(`Failed to parse JSON response: ${parseError}`); } } catch (error) { const processingTimeMs = Date.now() - startTime; // Map specific errors to domain errors this.mapAndThrowError(error as Error); // Return error response with metadata as fallback return { pages: [], answer: '', url_context_metadata: { status: 'failed', totalUrls: input.urls.length, successfulUrls: 0, failedUrls: input.urls, processingTimeMs } }; } } private buildPrompt(input: GenerateUrlContextInput): string { const urlsText = input.urls.join('\\n'); const queryText = input.query || 'Please extract and summarize the content'; return ` Please analyze the following URLs and extract their content. Return a JSON response with the exact schema specified. URLs to analyze: ${urlsText} Query: ${queryText} Instructions: 1. For each URL, extract the title, main text content (max ${input.maxCharsPerPage} characters), and all image URLs 2. Make image URLs absolute (convert relative URLs to absolute ones based on the page's domain) 3. Provide a summary answer to the query based on all the content 4. Include metadata about the processing status Return only valid JSON following the exact response schema. `; } private mapAndThrowError(error: Error): void { const errorMessage = error.message.toLowerCase(); if (errorMessage.includes('safety') || errorMessage.includes('blocked')) { throw new SafetyBlockedError(error.message); } if (errorMessage.includes('rate limit') || errorMessage.includes('quota')) { throw new RateLimitError(error.message); } if (errorMessage.includes('network') || errorMessage.includes('timeout') || errorMessage.includes('unavailable') || errorMessage.includes('connection')) { throw new UpstreamUnavailableError(error.message, error); } // For other errors, throw as upstream unavailable throw new UpstreamUnavailableError(`Gemini API error: ${error.message}`, error); } }

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/tanamurayuuki/MCP-URLcontext'

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