search-source
Search for token-specific data across platforms like Dune, IQ Wiki, and news sources using token name and ticker symbol, enabling focused Web3 research directly from the MCP server.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source | Yes | Source to search (e.g., 'Dune', 'IQ Wiki', 'News') | |
| tokenName | Yes | Name of the token | |
| tokenTicker | Yes | Ticker symbol of the token |
Implementation Reference
- src/tools/researchTools.ts:400-485 (registration)Registers the "search-source" tool with the MCP server, providing input schema and inline handler function.server.tool( "search-source", { tokenName: z.string().describe("Name of the token"), tokenTicker: z.string().describe("Ticker symbol of the token"), source: z .string() .describe("Source to search (e.g., 'Dune', 'IQ Wiki', 'News')"), }, async ({ tokenName, tokenTicker, source, }: { tokenName: string; tokenTicker: string; source: string; }) => { storage.addLogEntry( `Searching ${source} for ${tokenName} (${tokenTicker})` ); try { const results = await searchSource(tokenName, tokenTicker, source); storage.addToSection("searchResults", { [source]: results, }); let responseText = `Search results for ${source} about ${tokenName} (${tokenTicker}):\n\n`; if (results.results && results.results.length > 0) { const topResults = results.results.slice(0, 5); responseText += JSON.stringify(topResults, null, 2); if (topResults[0] && topResults[0].url) { const url = topResults[0].url; responseText += `\n\nFetching content from top result: ${url}`; try { await sleep(3000); const content = await fetchContent(url, "text"); const resourceId = `${source.toLowerCase()}_${tokenName.toLowerCase()}_${new Date().getTime()}`; storage.addToSection("resources", { [resourceId]: { url, format: "text", content, source, fetchedAt: new Date().toISOString(), }, }); responseText += `\n\nContent has been saved as a resource. Use 'research://resource/${resourceId}' to access it.`; } catch (fetchError) { responseText += `\n\nCould not fetch content from URL: ${fetchError}`; } } } else { responseText += `No results found.`; } return { content: [ { type: "text", text: responseText, }, ], }; } catch (error) { storage.addLogEntry(`Error searching ${source}: ${error}`); return { isError: true, content: [ { type: "text", text: `Error searching ${source}: ${error}`, }, ], }; } } );
- src/tools/researchTools.ts:402-408 (schema)Zod schema defining inputs for the search-source tool: tokenName, tokenTicker, source.{ tokenName: z.string().describe("Name of the token"), tokenTicker: z.string().describe("Ticker symbol of the token"), source: z .string() .describe("Source to search (e.g., 'Dune', 'IQ Wiki', 'News')"), },
- src/tools/researchTools.ts:409-484 (handler)Handler function that executes the tool: logs action, calls searchSource helper, stores results, fetches and stores content from top result, returns formatted response.async ({ tokenName, tokenTicker, source, }: { tokenName: string; tokenTicker: string; source: string; }) => { storage.addLogEntry( `Searching ${source} for ${tokenName} (${tokenTicker})` ); try { const results = await searchSource(tokenName, tokenTicker, source); storage.addToSection("searchResults", { [source]: results, }); let responseText = `Search results for ${source} about ${tokenName} (${tokenTicker}):\n\n`; if (results.results && results.results.length > 0) { const topResults = results.results.slice(0, 5); responseText += JSON.stringify(topResults, null, 2); if (topResults[0] && topResults[0].url) { const url = topResults[0].url; responseText += `\n\nFetching content from top result: ${url}`; try { await sleep(3000); const content = await fetchContent(url, "text"); const resourceId = `${source.toLowerCase()}_${tokenName.toLowerCase()}_${new Date().getTime()}`; storage.addToSection("resources", { [resourceId]: { url, format: "text", content, source, fetchedAt: new Date().toISOString(), }, }); responseText += `\n\nContent has been saved as a resource. Use 'research://resource/${resourceId}' to access it.`; } catch (fetchError) { responseText += `\n\nCould not fetch content from URL: ${fetchError}`; } } } else { responseText += `No results found.`; } return { content: [ { type: "text", text: responseText, }, ], }; } catch (error) { storage.addLogEntry(`Error searching ${source}: ${error}`); return { isError: true, content: [ { type: "text", text: `Error searching ${source}: ${error}`, }, ], }; } }
- src/utils/searchUtils.ts:145-186 (helper)Helper function implementing source-specific search query construction and delegation to performSearch (DuckDuckGo scraper).export async function searchSource( tokenName: string, tokenTicker: string, source: string ): Promise<any> { const extraTerms = ["crypto", "token"]; switch (source.toLowerCase()) { case "coinmarketcap": extraTerms.push("price", "market", "chart"); break; case "docs": extraTerms.push("documentation", "whitepaper", "github"); break; case "vesting": extraTerms.push("tokenomics", "schedule", "unlock"); break; case "raise": extraTerms.push("funding", "investment", "ico", "seed"); break; case "news": extraTerms.push("latest", "announcement", "update"); break; case "crypto token": case "dashboard": case "iq wiki": case "dune": extraTerms.push("dashboard", "crypto", "stats"); break; case "airdrop": break; default: } const query = `${tokenName} ${tokenTicker} ${source} ${extraTerms.join(" ")}`; if (source.toLowerCase() === "news") { return performSearch(query, "news"); } return performSearch(query, "web"); }