Skip to main content
Glama

Gemini MCP Server

client_info.pyโ€ข9.01 kB
""" Client Information Utility for MCP Server This module provides utilities to extract and format client information from the MCP protocol's clientInfo sent during initialization. It also provides friendly name mapping and caching for consistent client identification across the application. """ import logging from typing import Any, Optional logger = logging.getLogger(__name__) # Global cache for client information _client_info_cache: Optional[dict[str, Any]] = None # Mapping of known client names to friendly names # This is case-insensitive and checks if the key is contained in the client name CLIENT_NAME_MAPPINGS = { # Claude variants "claude-ai": "Claude", "claude": "Claude", "claude-desktop": "Claude", "claude-code": "Claude", "anthropic": "Claude", # Gemini variants "gemini-cli-mcp-client": "Gemini", "gemini-cli": "Gemini", "gemini": "Gemini", "google": "Gemini", # Other known clients "cursor": "Cursor", "vscode": "VS Code", "codeium": "Codeium", "copilot": "GitHub Copilot", # Generic MCP clients "mcp-client": "MCP Client", "test-client": "Test Client", } # Default friendly name when no match is found DEFAULT_FRIENDLY_NAME = "Claude" def get_friendly_name(client_name: str) -> str: """ Map a client name to a friendly name. Args: client_name: The raw client name from clientInfo Returns: A friendly name for display (e.g., "Claude", "Gemini") """ if not client_name: return DEFAULT_FRIENDLY_NAME # Convert to lowercase for case-insensitive matching client_name_lower = client_name.lower() # Check each mapping - using 'in' to handle partial matches for key, friendly_name in CLIENT_NAME_MAPPINGS.items(): if key.lower() in client_name_lower: return friendly_name # If no match found, return the default return DEFAULT_FRIENDLY_NAME def get_cached_client_info() -> Optional[dict[str, Any]]: """ Get cached client information if available. Returns: Cached client info dictionary or None """ global _client_info_cache return _client_info_cache def get_client_info_from_context(server: Any) -> Optional[dict[str, Any]]: """ Extract client information from the MCP server's request context. The MCP protocol sends clientInfo during initialization containing: - name: The client application name (e.g., "Claude Code", "Claude Desktop") - version: The client version string This function also adds a friendly_name field and caches the result. Args: server: The MCP server instance Returns: Dictionary with client info or None if not available: { "name": "claude-ai", "version": "1.0.0", "friendly_name": "Claude" } """ global _client_info_cache # Return cached info if available if _client_info_cache is not None: return _client_info_cache try: # Try to access the request context and session if not server: return None # Check if server has request_context property request_context = None try: request_context = server.request_context except AttributeError: logger.debug("Server does not have request_context property") return None if not request_context: logger.debug("Request context is None") return None # Try to access session from request context session = None try: session = request_context.session except AttributeError: logger.debug("Request context does not have session property") return None if not session: logger.debug("Session is None") return None # Try to access client params from session client_params = None try: # The clientInfo is stored in _client_params.clientInfo client_params = session._client_params except AttributeError: logger.debug("Session does not have _client_params property") return None if not client_params: logger.debug("Client params is None") return None # Try to extract clientInfo client_info = None try: client_info = client_params.clientInfo except AttributeError: logger.debug("Client params does not have clientInfo property") return None if not client_info: logger.debug("Client info is None") return None # Extract name and version result = {} try: result["name"] = client_info.name except AttributeError: logger.debug("Client info does not have name property") try: result["version"] = client_info.version except AttributeError: logger.debug("Client info does not have version property") if not result: return None # Add friendly name raw_name = result.get("name", "") result["friendly_name"] = get_friendly_name(raw_name) # Cache the result _client_info_cache = result logger.debug(f"Cached client info: {result}") return result except Exception as e: logger.debug(f"Error extracting client info: {e}") return None def format_client_info(client_info: Optional[dict[str, Any]], use_friendly_name: bool = True) -> str: """ Format client information for display. Args: client_info: Dictionary with client info or None use_friendly_name: If True, use the friendly name instead of raw name Returns: Formatted string like "Claude v1.0.0" or "Claude" """ if not client_info: return DEFAULT_FRIENDLY_NAME if use_friendly_name: name = client_info.get("friendly_name", client_info.get("name", DEFAULT_FRIENDLY_NAME)) else: name = client_info.get("name", "Unknown") version = client_info.get("version", "") if version and not use_friendly_name: return f"{name} v{version}" else: # For friendly names, we just return the name without version return name def get_client_friendly_name() -> str: """ Get the cached client's friendly name. This is a convenience function that returns just the friendly name from the cached client info, defaulting to "Claude" if not available. Returns: The friendly name (e.g., "Claude", "Gemini") """ cached_info = get_cached_client_info() if cached_info: return cached_info.get("friendly_name", DEFAULT_FRIENDLY_NAME) return DEFAULT_FRIENDLY_NAME def log_client_info(server: Any, logger_instance: Optional[logging.Logger] = None) -> None: """ Log client information extracted from the server. Args: server: The MCP server instance logger_instance: Optional logger to use (defaults to module logger) """ log = logger_instance or logger client_info = get_client_info_from_context(server) if client_info: # Log with both raw and friendly names for debugging raw_name = client_info.get("name", "Unknown") friendly_name = client_info.get("friendly_name", DEFAULT_FRIENDLY_NAME) version = client_info.get("version", "") if raw_name != friendly_name: log.info(f"MCP Client Connected: {friendly_name} (raw: {raw_name} v{version})") else: log.info(f"MCP Client Connected: {friendly_name} v{version}") # Log to activity logger as well try: activity_logger = logging.getLogger("mcp_activity") activity_logger.info(f"CLIENT_IDENTIFIED: {friendly_name} (name={raw_name}, version={version})") except Exception: pass else: log.debug("Could not extract client info from MCP protocol") # Example usage in tools: # # from utils.client_info import get_client_friendly_name, get_cached_client_info # # # In a tool's execute method: # def execute(self, arguments: dict[str, Any]) -> list[TextContent]: # # Get the friendly name of the connected client # client_name = get_client_friendly_name() # Returns "Claude" or "Gemini" etc. # # # Or get full cached info if needed # client_info = get_cached_client_info() # if client_info: # raw_name = client_info['name'] # e.g., "claude-ai" # version = client_info['version'] # e.g., "1.0.0" # friendly = client_info['friendly_name'] # e.g., "Claude" # # # Customize response based on client # if client_name == "Claude": # response = f"Hello from Zen MCP Server to {client_name}!" # elif client_name == "Gemini": # response = f"Greetings {client_name}, welcome to Zen MCP Server!" # else: # response = f"Welcome {client_name}!"

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/BeehiveInnovations/gemini-mcp-server'

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