Skip to main content
Glama
lumishoang

OpenRouter MCP Server

by lumishoang

compare_models

Compare multiple AI models side by side to evaluate their pricing, context limits, and capabilities. Find the right model for your needs.

Instructions

Compare multiple models side by side.

Args: model_ids: Comma-separated model IDs

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
model_idsYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The @mcp.tool() decorated function that implements the 'compare_models' tool logic. It fetches models, matches given comma-separated model IDs (exact or fuzzy), and renders a side-by-side comparison table with Context, Input $/1M, Output $/1M, and Tools support columns.
    @mcp.tool()
    def compare_models(model_ids: str) -> str:
        """Compare multiple models side by side.
    
        Args:
            model_ids: Comma-separated model IDs
        """
        models = fetch_models()
        ids = [x.strip() for x in model_ids.split(",")]
        selected = []
        for mid in ids:
            for m in models:
                if m["id"] == mid or mid.lower() in m["id"].lower():
                    selected.append(m)
                    break
        if not selected:
            return "No matching models found."
    
        names = [m["id"] for m in selected]
        max_len = max(len(n) for n in names) if names else 10
    
        def row(label, fn):
            vals = " | ".join(str(fn(m)).rjust(max_len) for m in selected)
            return f"| {label} | {vals} |"
    
        lines = ["# Model Comparison\n"]
        lines.append("| Metric | " + " | ".join(n.rjust(max_len) for n in names) + " |")
        lines.append("|--------|" + "|".join("-" * (max_len + 2) for _ in names) + "|")
        lines.append(row("Context", lambda m: m.get("context_length", "?")))
        lines.append(row("Input $/1M", lambda m: _price_str(float(m.get("pricing",{}).get("prompt",0)))))
        lines.append(row("Output $/1M", lambda m: _price_str(float(m.get("pricing",{}).get("completion",0)))))
        lines.append(row("Tools", lambda m: "✅" if "tools" in m.get("supported_parameters",[]) else "❌"))
        return "\n".join(lines)
  • The @mcp.tool() decorator registers 'compare_models' as an MCP tool on the FastMCP server instance.
    @mcp.tool()
    def compare_models(model_ids: str) -> str:
  • Helper function _price_str converts per-token price to a human-readable string like '$2.50/1M tok' or 'free', used by compare_models when displaying pricing columns.
    def _price_str(per_token: float) -> str:
        if per_token <= 0:
            return "free"
        return f"${per_token * 1_000_000:.2f}/1M tok"
  • The fetch_models helper fetches the OpenRouter model list (with caching), called by compare_models to retrieve model data.
    def fetch_models(force=False) -> list[dict]:
        """Fetch model list from OpenRouter with caching."""
        now = time.time()
        if _cache["data"] is not None and (now - _cache["ts"]) < CACHE_TTL and not force:
            return _cache["data"]
    
        headers = {"Accept": "application/json"}
        if OR_API_KEY:
            headers["Authorization"] = f"Bearer {OR_API_KEY}"
    
        req = Request(OR_MODELS_URL, headers=headers)
        try:
            with urlopen(req, timeout=30) as resp:
                body = json.loads(resp.read())
                _cache["data"] = body.get("data", [])
                _cache["ts"] = now
                return _cache["data"]
        except URLError as e:
            raise RuntimeError(f"Failed to fetch OpenRouter models: {e}")
  • The compare_models function is exported from the package via the __init__.py __all__ list and direct import.
    from .server import main, fetch_models, list_models, get_model, search_models, compare_models, refresh_cache
    
    __all__ = ["main", "fetch_models", "list_models", "get_model", "search_models", "compare_models", "refresh_cache"]
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It does not disclose behavioral traits such as whether the operation is read-only, potential side effects, or output format. The minimal description lacks sufficient transparency.

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

Conciseness4/5

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

The description is very short with no wasted words. It lacks structure (e.g., sections) but remains efficient. A bit more detail could be added without compromising conciseness.

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

Completeness2/5

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

Given the tool's simplicity (1 param) and presence of output schema, the description is incomplete. It fails to describe what 'side by side' means in the output, whether it shows differences or full models, or how results are presented.

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

Parameters3/5

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

The description explains that model_ids is 'comma-separated model IDs,' adding format context beyond the schema (which only specifies type string). However, with 0% schema description coverage, more detail on parameter constraints would improve clarity.

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 'Compare multiple models side by side,' specifying the verb 'compare' and the resource 'multiple models.' It distinguishes itself from sibling tools like get_model (single) and list_models (list) by implying a comparative operation.

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 does not explicitly state when to use this tool versus alternatives. While the purpose implies it's for comparing multiple models, there is no guidance on exclusions or when-not-to-use.

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/lumishoang/openrouter-mcp'

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