google_search
Perform Google searches directly from the Fetch Browser MCP server, retrieve results in text, JSON, HTML, or Markdown formats, and specify search types like web or news for tailored queries.
Instructions
Execute a Google search and return results in various formats
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| maxResults | No | Maximum number of results to return | |
| query | Yes | The search query to execute | |
| responseType | No | Expected response type | json |
| topic | No | Type of search to perform | web |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"maxResults": {
"default": 10,
"description": "Maximum number of results to return",
"maximum": 100,
"minimum": 1,
"type": "number"
},
"query": {
"description": "The search query to execute",
"minLength": 1,
"type": "string"
},
"responseType": {
"default": "json",
"description": "Expected response type",
"enum": [
"text",
"json",
"html",
"markdown"
],
"type": "string"
},
"topic": {
"default": "web",
"description": "Type of search to perform",
"enum": [
"web",
"news"
],
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
Implementation Reference
- src/google-search.ts:69-157 (handler)The asynchronous handler function that implements the core logic of the 'google_search' tool: builds search URL, fetches results, extracts URLs, fetches content from each, formats output based on responseType, and returns structured content with metadata.async (params) => { try { // First, get the search results const searchUrl = buildGoogleSearchUrl({ query: params.query, maxResults: params.maxResults, topic: params.topic }); // Get search results in JSON format to extract URLs const searchResults = await fetchUrl(searchUrl, 'json'); const urls = await extractSearchUrls(searchResults); // Now fetch the full content of each URL const fullResults = await Promise.all( urls.map(async (url) => { try { const content = await fetchUrl(url, params.responseType); return { url, content, error: null }; } catch (error) { return { url, content: null, error: error instanceof Error ? error.message : 'Unknown error' }; } }) ); // Format the results based on response type let formattedResults; switch (params.responseType) { case 'markdown': formattedResults = fullResults .map(r => r.error ? `## [Failed to fetch: ${r.url}]\nError: ${r.error}` : `## [${r.url}]\n\n${r.content}`) .join('\n\n---\n\n'); break; case 'html': formattedResults = fullResults .map(r => r.error ? `<div class="search-result error"><h2><a href="${r.url}">Failed to fetch</a></h2><p class="error">${r.error}</p></div>` : `<div class="search-result"><h2><a href="${r.url}">${r.url}</a></h2>${r.content}</div>`) .join('\n'); break; case 'text': formattedResults = fullResults .map(r => r.error ? `### ${r.url}\nError: ${r.error}` : `### ${r.url}\n\n${r.content}`) .join('\n\n==========\n\n'); break; case 'json': default: formattedResults = JSON.stringify(fullResults, null, 2); break; } return { content: [{ type: "text", text: formattedResults, mimeType: params.responseType === 'json' ? 'application/json' : params.responseType === 'markdown' ? 'text/markdown' : params.responseType === 'html' ? 'text/html' : 'text/plain' }], metadata: { query: params.query, topic: params.topic, maxResults: params.maxResults, responseType: params.responseType, resultsCount: fullResults.length, successCount: fullResults.filter(r => !r.error).length } }; } catch (error) { return { content: [{ type: "text", text: `Failed to execute Google search: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; }
- src/google-search.ts:6-21 (schema)Zod schema defining the input parameters and validation for the 'google_search' tool.const GoogleSearchSchema = z.object({ query: z.string() .min(1) .describe("The search query to execute"), responseType: z.enum(['text', 'json', 'html', 'markdown']) .default('json') .describe("Expected response type"), maxResults: z.number() .min(1) .max(100) .default(10) .describe("Maximum number of results to return"), topic: z.enum(['web', 'news']) .default('web') .describe("Type of search to perform") });
- src/google-search.ts:64-160 (registration)The registration function that calls server.tool() to register the 'google_search' tool with name, description, schema, and handler on the MCP server.export function registerGoogleSearchTool(server: McpServer) { server.tool( "google_search", "Execute a Google search and return results in various formats", GoogleSearchSchema.shape, async (params) => { try { // First, get the search results const searchUrl = buildGoogleSearchUrl({ query: params.query, maxResults: params.maxResults, topic: params.topic }); // Get search results in JSON format to extract URLs const searchResults = await fetchUrl(searchUrl, 'json'); const urls = await extractSearchUrls(searchResults); // Now fetch the full content of each URL const fullResults = await Promise.all( urls.map(async (url) => { try { const content = await fetchUrl(url, params.responseType); return { url, content, error: null }; } catch (error) { return { url, content: null, error: error instanceof Error ? error.message : 'Unknown error' }; } }) ); // Format the results based on response type let formattedResults; switch (params.responseType) { case 'markdown': formattedResults = fullResults .map(r => r.error ? `## [Failed to fetch: ${r.url}]\nError: ${r.error}` : `## [${r.url}]\n\n${r.content}`) .join('\n\n---\n\n'); break; case 'html': formattedResults = fullResults .map(r => r.error ? `<div class="search-result error"><h2><a href="${r.url}">Failed to fetch</a></h2><p class="error">${r.error}</p></div>` : `<div class="search-result"><h2><a href="${r.url}">${r.url}</a></h2>${r.content}</div>`) .join('\n'); break; case 'text': formattedResults = fullResults .map(r => r.error ? `### ${r.url}\nError: ${r.error}` : `### ${r.url}\n\n${r.content}`) .join('\n\n==========\n\n'); break; case 'json': default: formattedResults = JSON.stringify(fullResults, null, 2); break; } return { content: [{ type: "text", text: formattedResults, mimeType: params.responseType === 'json' ? 'application/json' : params.responseType === 'markdown' ? 'text/markdown' : params.responseType === 'html' ? 'text/html' : 'text/plain' }], metadata: { query: params.query, topic: params.topic, maxResults: params.maxResults, responseType: params.responseType, resultsCount: fullResults.length, successCount: fullResults.filter(r => !r.error).length } }; } catch (error) { return { content: [{ type: "text", text: `Failed to execute Google search: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); }
- src/index.ts:66-66 (registration)Invocation of the registerGoogleSearchTool function during MCP server initialization to enable the 'google_search' tool.registerGoogleSearchTool(server);
- src/google-search.ts:26-45 (helper)Helper function to construct the Google search URL with query parameters for results count and topic (web/news).function buildGoogleSearchUrl(options: { query: string; maxResults?: number; topic?: 'web' | 'news'; }): string { const searchParams = new URLSearchParams({ q: options.query, num: `${options.maxResults || 10}` }); if (options.topic === 'news') { // News tab searchParams.set("tbm", "nws"); } else { // Web tab searchParams.set("udm", "14"); } return `https://www.google.com/search?${searchParams.toString()}`; }