Skip to main content
Glama

explain_why

Evaluates your project description and a given server name to explain why that MCP server is a good fit for your specific needs.

Instructions

Explain why a specific MCP server is a good fit for a given project. Example: server_name="github", project_description="open source Python library with CI/CD"

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
server_nameYes
project_descriptionYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The main handler for the 'explain_why' tool. Decorated with @mcp.tool(), it looks up a server by name using lookup_by_name(), generates a rationale via generate_rationale(), and returns a formatted markdown explanation.
    @mcp.tool()
    def explain_why(server_name: str, project_description: str) -> str:
        """
        Explain why a specific MCP server is a good fit for a given project.
        Example: server_name="github", project_description="open source Python library with CI/CD"
        """
        try:
            _ensure_index()
            server = lookup_by_name(server_name)
            if server is None:
                return (
                    f"Could not find '{server_name}' in the index. "
                    f"Try a partial name or check spelling."
                )
    
            rationale = generate_rationale(server, project_description)
            return (
                f"## Why {server['name']} fits your project\n\n"
                f"**Server:** {server['name']}\n"
                f"**URL:** {server['url']}\n"
                f"**Category:** {server['category']}\n"
                f"**Description:** {server['description']}\n\n"
                f"**Rationale:** {rationale}"
            )
        except Exception as e:
            return _error_response(f"explaining fit for '{server_name}'", e)
  • The tool is registered as an MCP tool via the @mcp.tool() decorator on line 97.
    @mcp.tool()
  • generate_rationale() generates a template-based rationale string explaining why a server fits a project. No LLM call — grounded, fast, offline.
    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}"
        )
  • lookup_by_name() finds a server by name in the index with ranked matching: exact → short-name exact → prefix → substring.
    def lookup_by_name(server_name: str) -> dict | None:
        """Find a server by name, ranked: exact → short-name exact → prefix → substring."""
        if not server_name or not server_name.strip():
            return None
        q = server_name.strip().lower()
        con = get_connection()
        rows = con.execute(
            "SELECT name, description, url, category FROM servers WHERE lower(name) LIKE ?",
            [f"%{q}%"],
        ).fetchall()
        con.close()
        if not rows:
            return None
    
        def _rank(row):
            n = row[0].lower()
            parts = n.split("/", 1)
            owner = parts[0] if len(parts) == 2 else ""
            short = parts[-1]
            if n == q or short == q:
                return (0, 0)
            # owner exact match is a stronger prefix signal
            if owner == q:
                return (1, 0)
            if n.startswith(q) or short.startswith(q):
                return (1, 1)
            return (2, 0)
    
        name, desc, url, cat = min(rows, key=_rank)
        return {"name": name, "description": desc, "url": url, "category": cat}
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden. It explains that the tool returns an explanation, but does not disclose any side effects, permissions, or limitations beyond the basic read-only nature.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise: two sentences plus an example. It is front-loaded with the main purpose and includes no unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple tool with 2 parameters and an output schema, the description covers the basic purpose but lacks context on prerequisites, error conditions, or what the output contains. It is adequate but not complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, and the description only provides an example without explaining parameter semantics (e.g., valid values for server_name, format for project_description). The example helps but is insufficient for full understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Explain why' and the resource 'a specific MCP server is a good fit for a given project', distinguishing it from siblings like 'recommend_for_project' and 'recommend_next'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides an example but does not explicitly state when to use this tool versus alternatives or when not to use it. Usage is implied from context but not clearly guided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/yahiaklk/mcpilot'

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