search_sales_tools
Find sales APIs, tools, and MCP servers by searching with natural language queries like 'lead enrichment API' or 'free CRM with webhooks'. Filter results by category, free tier, or MCP support.
Instructions
Search the Salestools Club directory for sales APIs, tools, and MCP servers. Use natural language like 'lead enrichment API' or 'free CRM with webhooks'.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Natural language search query (e.g., 'enrichment API', 'cold email tools', 'CRM for startups') | |
| mcpReady | No | Only return tools with MCP server support | |
| hasFreeTier | No | Only return tools with a free tier | |
| category | No | Filter by category (e.g., 'Sales Intelligence', 'CRM & RevOps', 'Sales Engagement') | |
| limit | No | Max results to return (default: 20) |
Implementation Reference
- index.js:49-93 (handler)The handleSearch function executes the 'search_sales_tools' tool logic. It extracts keywords from the query, fetches results from the Salestools Club API for each keyword, aggregates and scores results, applies filters (mcpReady, hasFreeTier, category, limit), and returns formatted tool listings.
async function handleSearch(args) { const { query, mcpReady, hasFreeTier, category, limit = 20 } = args; const keywords = extractKeywords(query); if (keywords.length === 0) { return { content: [{ type: "text", text: "No meaningful search terms found. Try being more specific." }] }; } const toolMap = new Map(); for (const kw of keywords) { try { const data = await fetchJSON(`${BASE_URL}/api/tools?q=${encodeURIComponent(kw)}`); if (data.tools && Array.isArray(data.tools)) { for (const tool of data.tools) { if (!toolMap.has(tool.slug)) { toolMap.set(tool.slug, { ...tool, score: 0 }); } toolMap.get(tool.slug).score += 1; } } } catch { continue; } } let results = Array.from(toolMap.values()).sort((a, b) => b.score - a.score); if (mcpReady === true) results = results.filter(t => t.mcpReady === true); if (hasFreeTier === true) results = results.filter(t => t.hasFreeTier === true); if (category) results = results.filter(t => t.category?.toLowerCase().includes(category.toLowerCase())); results = results.slice(0, limit); if (results.length === 0) { return { content: [{ type: "text", text: `No tools found for "${query}". Try different keywords.` }] }; } let text = `Found ${results.length} tool${results.length !== 1 ? 's' : ''} for "${query}":\n\n`; for (const tool of results) { const badges = []; if (tool.mcpReady) badges.push('MCP Ready'); if (tool.hasFreeTier) badges.push('Free Tier'); text += `**${tool.name}** — ${tool.oneLiner || ''}\n`; text += ` Category: ${tool.category || 'N/A'}`; if (badges.length > 0) text += ` | ${badges.join(' | ')}`; text += `\n → https://salestools.club/apis/${tool.slug}\n\n`; } return { content: [{ type: "text", text: text.trim() }] }; } - index.js:247-261 (schema)Input schema (JSON Schema) for the 'search_sales_tools' tool, defining the 'query', 'mcpReady', 'hasFreeTier', 'category', and 'limit' properties, with 'query' as required.
{ name: "search_sales_tools", description: "Search the Salestools Club directory for sales APIs, tools, and MCP servers. Use natural language like 'lead enrichment API' or 'free CRM with webhooks'.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Natural language search query (e.g., 'enrichment API', 'cold email tools', 'CRM for startups')" }, mcpReady: { type: "boolean", description: "Only return tools with MCP server support" }, hasFreeTier: { type: "boolean", description: "Only return tools with a free tier" }, category: { type: "string", description: "Filter by category (e.g., 'Sales Intelligence', 'CRM & RevOps', 'Sales Engagement')" }, limit: { type: "number", description: "Max results to return (default: 20)" }, }, required: ["query"], }, }, - index.js:246-261 (registration)The tool named 'search_sales_tools' is registered in the ListToolsRequestSchema handler (server.setRequestHandler) which declares all available tools.
tools: [ { name: "search_sales_tools", description: "Search the Salestools Club directory for sales APIs, tools, and MCP servers. Use natural language like 'lead enrichment API' or 'free CRM with webhooks'.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Natural language search query (e.g., 'enrichment API', 'cold email tools', 'CRM for startups')" }, mcpReady: { type: "boolean", description: "Only return tools with MCP server support" }, hasFreeTier: { type: "boolean", description: "Only return tools with a free tier" }, category: { type: "string", description: "Filter by category (e.g., 'Sales Intelligence', 'CRM & RevOps', 'Sales Engagement')" }, limit: { type: "number", description: "Max results to return (default: 20)" }, }, required: ["query"], }, }, - index.js:308-308 (registration)The tool dispatch in CallToolRequestSchema routes the name 'search_sales_tools' to the handleSearch function.
case "search_sales_tools": return handleSearch(args); - index.js:33-39 (helper)The extractKeywords helper function preprocesses the search query by lowercasing, removing special characters, splitting on whitespace, and filtering out stop words and single-character terms. It is used by handleSearch.
function extractKeywords(query) { return query .toLowerCase() .replace(/[^\w\s-]/g, ' ') .split(/\s+/) .filter(word => word.length > 1 && !STOP_WORDS.has(word)); }