recommend_for_project
Recommend top MCP servers for your project by analyzing its description and explaining why each fits.
Instructions
Given a project description, recommend the top MCP servers to install and explain why each one fits. Example: "Python FastAPI backend with PostgreSQL and JWT auth"
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| description | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/mcpilot/server.py:60-72 (handler)The 'recommend_for_project' tool handler function. It is a FastMCP tool registered with @mcp.tool(), accepts a project description string, ensures the index is built, calls find_similar() to get top 5 matching servers, formats results with rationales, and returns the recommendation.
@mcp.tool() def recommend_for_project(description: str) -> str: """ Given a project description, recommend the top MCP servers to install and explain why each one fits. Example: "Python FastAPI backend with PostgreSQL and JWT auth" """ try: _ensure_index() results = find_similar(description, top_k=5) header = f"## Recommended MCP servers for: {description}\n\n" return header + _format_results(results, description) except Exception as e: return _error_response("generating recommendations", e) - src/mcpilot/server.py:60-60 (registration)The @mcp.tool() decorator registers 'recommend_for_project' as an MCP tool on the FastMCP server instance.
@mcp.tool() - src/mcpilot/search.py:28-86 (helper)find_similar() - helper function called by recommend_for_project. Performs semantic search over the embedded server index using cosine similarity, with adaptive fallback threshold.
def find_similar( query: str, top_k: int = 10, exclude: list[str] | None = None, min_score: float = DEFAULT_MIN_SCORE, ) -> list[dict]: """ Return top_k servers most semantically similar to query. Each result: {name, url, description, category, score} """ model = _get_model() query_emb = model.encode([query])[0].tolist() excluded_lower = {n.lower() for n in (exclude or [])} fetch_limit = top_k + max(len(excluded_lower) * 3, 10) con = get_connection() rows = con.execute( """ SELECT name, description, url, category, score FROM ( SELECT name, description, url, category, array_cosine_similarity(embedding, ?::FLOAT[384]) AS score FROM servers ) WHERE score >= ? ORDER BY score DESC LIMIT ? """, [query_emb, min_score, fetch_limit], ).fetchall() con.close() results = [] for name, desc, url, cat, score in rows: name_lower = name.lower() short_name = name_lower.split("/")[-1] if any( e == name_lower or e == short_name or e in name_lower for e in excluded_lower ): continue results.append( { "name": name, "url": url, "description": desc, "category": cat, "score": float(score), } ) if len(results) >= top_k: break # Adaptive fallback: if nothing cleared the threshold, return the closest # matches below it so callers never silently get zero results. if not results and min_score > 0: return find_similar(query, top_k=top_k, exclude=exclude, min_score=0.0) return results - src/mcpilot/search.py:89-115 (helper)generate_rationale() - helper function used to produce the textual rationale explaining why each server was recommended. Called from _format_results() within recommend_for_project.
def generate_rationale(server: dict, project_description: str) -> str: """ Template-based rationale: why this server fits this project. No LLM call — grounded, fast, offline. """ name = server["name"] desc = server["description"] category = server["category"] score = server.get("score", 0) # Extract key nouns from project description (simple word overlap) proj_words = set(re.findall(r"[a-z0-9]+", project_description.lower())) desc_words = set(re.findall(r"[a-z0-9]+", desc.lower())) overlap = (proj_words & desc_words) - STOPWORDS if overlap: match_hint = f"It shares focus on: {', '.join(sorted(overlap)[:5])}." else: match_hint = f"It falls under the '{category}' category, which aligns with your project's needs." confidence = "strong" if score > 0.55 else "moderate" if score > 0.40 else "potential" return ( f"{name} — {desc} " f"[{confidence} match | category: {category}] " f"{match_hint}" ) - src/mcpilot/server.py:45-57 (helper)_format_results() - helper that formats the list of result dicts into a markdown string, called directly by recommend_for_project.
def _format_results(results: list[dict], project_description: str) -> str: if not results: return "No matching MCP servers found. Try a more descriptive project description." lines = [] for i, r in enumerate(results, 1): rationale = generate_rationale(r, project_description) lines.append( f"{i}. **{r['name']}**\n" f" {r['url']}\n" f" {rationale}\n" ) return "\n".join(lines)