Skip to main content
Glama
cli.py6.51 kB
""" Command-line interface for running the Yellhorn MCP server. This module provides a simple command to run the Yellhorn MCP server as a standalone application, making it easier to integrate with other programs or launch directly. """ import argparse import asyncio import logging import os import sys from pathlib import Path import uvicorn from yellhorn_mcp.llm.model_families import ( ModelFamily, detect_model_family, supports_reasoning_effort, ) from yellhorn_mcp.server import AsyncXAI, is_git_repository, mcp logging.basicConfig( stream=sys.stderr, level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s" ) def main(): """ Run the Yellhorn MCP server as a standalone command. This function parses command-line arguments, validates environment variables, and launches the MCP server. """ parser = argparse.ArgumentParser(description="Yellhorn MCP Server") parser.add_argument( "--repo-path", dest="repo_path", default=os.getenv("REPO_PATH", os.getcwd()), help="Path to the Git repository (default: current directory or REPO_PATH env var)", ) parser.add_argument( "--model", dest="model", default=os.getenv("YELLHORN_MCP_MODEL", "gemini-2.5-pro"), help="Model to use (e.g., gemini-2.5-pro, gemini-2.5-flash, " "gpt-4o, gpt-4o-mini, gpt-5, gpt-5-mini, gpt-5-nano, " "grok-4, grok-4-fast, o4-mini, o3, o3-deep-research, o4-mini-deep-research). " "Default: gemini-2.5-pro or YELLHORN_MCP_MODEL env var.", ) parser.add_argument( "--codebase-reasoning", dest="codebase_reasoning", default=os.getenv("YELLHORN_MCP_REASONING", "full"), choices=["full", "lsp", "none"], help="Control codebase context for AI processing: " "'full' (all code), 'lsp' (function signatures only), 'none' (no code). " "Default: full or YELLHORN_MCP_REASONING env var.", ) parser.add_argument( "--no-search-grounding", dest="no_search_grounding", action="store_true", help="Disable Google Search Grounding for Gemini models. " "By default, search grounding is enabled for all Gemini models. " "This flag maps to YELLHORN_MCP_SEARCH=off environment variable.", ) parser.add_argument( "--reasoning-effort", dest="reasoning_effort", choices=["low", "medium", "high"], default=None, help="Set reasoning effort level for GPT-5 models (gpt-5, gpt-5-mini). " "Options: low, medium, high. This provides enhanced reasoning capabilities " "at higher cost. Has no effect on models that don't support reasoning.", ) parser.add_argument( "--host", dest="host", default="127.0.0.1", help="Host to bind the server to (default: 127.0.0.1)", ) parser.add_argument( "--port", dest="port", type=int, default=8000, help="Port to bind the server to (default: 8000)", ) args = parser.parse_args() # Validate API keys based on model model = args.model try: model_family: ModelFamily = detect_model_family(model) except ValueError as exc: logging.error(str(exc)) sys.exit(1) if args.reasoning_effort and not supports_reasoning_effort(model): logging.info( "Model %s does not support reasoning effort overrides; ignoring --reasoning-effort.", model, ) args.reasoning_effort = None # For Gemini models if model_family == "gemini": api_key = os.getenv("GEMINI_API_KEY") if not api_key: logging.error("GEMINI_API_KEY environment variable is not set") logging.error( "Please set the GEMINI_API_KEY environment variable with your Gemini API key" ) sys.exit(1) elif model_family == "xai": api_key = os.getenv("XAI_API_KEY") if not api_key: logging.error("XAI_API_KEY environment variable is not set") logging.error("Please set the XAI_API_KEY environment variable with your xAI API key") sys.exit(1) if AsyncXAI is None: logging.error("xai-sdk is required for Grok models but is not installed") logging.error( "Install the xai-sdk package (e.g., 'uv pip install xai-sdk' or rerun 'uv sync') to use Grok models" ) sys.exit(1) else: # OpenAI api_key = os.getenv("OPENAI_API_KEY") if not api_key: logging.error("OPENAI_API_KEY environment variable is not set") logging.error( "Please set the OPENAI_API_KEY environment variable with your OpenAI API key" ) sys.exit(1) # Set environment variables for the server os.environ["REPO_PATH"] = args.repo_path os.environ["YELLHORN_MCP_MODEL"] = args.model os.environ["YELLHORN_MCP_REASONING"] = args.codebase_reasoning # Handle search grounding flag if args.no_search_grounding: os.environ["YELLHORN_MCP_SEARCH"] = "off" # Handle reasoning effort flag if args.reasoning_effort: os.environ["YELLHORN_MCP_REASONING_EFFORT"] = args.reasoning_effort # Validate repository path repo_path = Path(args.repo_path).resolve() if not repo_path.exists(): logging.error(f"Repository path {repo_path} does not exist") sys.exit(1) # Check if the path is a Git repository (either standard or worktree) if not is_git_repository(repo_path): logging.error(f"{repo_path} is not a Git repository") sys.exit(1) logging.info(f"Starting Yellhorn MCP server at http://{args.host}:{args.port}") logging.info(f"Repository path: {repo_path}") logging.info(f"Using model: {args.model}") # Show search grounding status if using Gemini model if model_family == "gemini": search_status = "disabled" if args.no_search_grounding else "enabled" logging.info(f"Google Search Grounding: {search_status}") # Show reasoning effort status for GPT-5 models if args.model.startswith("gpt-5") and args.model != "gpt-5-nano": if args.reasoning_effort: logging.info(f"Reasoning effort: {args.reasoning_effort}") else: logging.info("Reasoning effort: disabled") mcp.run(transport="stdio") if __name__ == "__main__": main()

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/msnidal/yellhorn-mcp'

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