Skip to main content
Glama
hingaibm

Data Intelligence MCP Server

by hingaibm
helpers.py8.3 kB
# Copyright [2025] [IBM] # Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) # See the LICENSE file in the project root for license information. # This file has been modified with the assistance of IBM Bob AI tool import json import re from difflib import get_close_matches from typing import Callable, List, Optional, Union from urllib.parse import urlparse, parse_qs from uuid import UUID from app.core.settings import settings from app.shared.exceptions.base import ServiceError def is_none(value: object) -> bool: """ This function takes a single value and checks if it is None or should be treated as None Args: value (object): A value to be tested Returns: bool: Information if value is or should be treated as None """ return value is None or value == "None" def is_uuid(id: str): """ This function takes a single string and checks if it is a valid UUID Args: id (str): A value to be tested Returns: None if valid UUID Raises: ServiceError: If the string is not a valid UUID """ try: UUID(id, version=4) except ValueError: raise ServiceError(f"'{id}' is not valid UUID") def is_uuid_bool(id: str) -> bool: """ Check if a string is a valid UUID. Args: id: String to check Returns: bool: True if valid UUID, False otherwise """ try: UUID(id, version=4) return True except (ValueError, AttributeError): return False async def confirm_uuid(uuid_or_str: str, find_function: Callable) -> str: try: is_uuid(uuid_or_str) return uuid_or_str except ServiceError: return await find_function(uuid_or_str) def _is_valid_lineage_id(lineage_id: str) -> bool: """ Check if a string is a valid lineage ID (64-character hexadecimal string). Args: lineage_id (str): The string to validate Returns: bool: True if the string is a valid lineage ID, False otherwise """ return isinstance(lineage_id, str) and bool( re.match(r"^[0-9a-f]{64}$", lineage_id.lower()) ) def _try_parse_json(json_str: str) -> Optional[List[str]]: """ Attempts to parse a string as JSON and validate it's a list. This function safely tries to convert a JSON string to a Python list. If parsing fails or the result is not a list, it returns None. Args: json_str (str): The JSON-formatted string to parse Returns: Optional[List[str]]: A list of strings if parsing succeeds and the result is a list, None if parsing fails or result is not a list Raises: No exceptions are raised as errors are caught internally """ try: parsed_value = json.loads(json_str) if isinstance(parsed_value, list): return parsed_value except json.JSONDecodeError: pass return None def _try_parse_with_normalization(json_str: str) -> Optional[List[str]]: """ Try to parse a string as JSON after normalizing quotes. Args: json_str: The string to parse Returns: List[str] if parsing succeeds and result is a list, None otherwise """ try: normalized_value = json_str.replace("'", '"') normalized_value = normalized_value.replace(r"\"", '"') return _try_parse_json(normalized_value) except json.JSONDecodeError: return None def _get_values_to_check(value) -> List[str]: """ Convert a value to a list of strings to check. Args: value: The value (string, list of strings, or JSON string representation of a list) Returns: List[str]: List of strings to check Raises: ServiceError: If the value is neither a string nor a list """ if isinstance(value, str): if value.strip().startswith("[") and value.strip().endswith("]"): parsed_list = _try_parse_json(value) if parsed_list: return parsed_list parsed_list = _try_parse_with_normalization(value) if parsed_list: return parsed_list return [value] elif isinstance(value, list): return value else: raise ServiceError( f"Argument '{value}' must be a string or list of strings, got {type(value).__name__}" ) def are_lineage_ids(values: Union[str, List[str]]): """ Check if all values are valid lineage IDs. Args: values: A list of values to check. Returns: bool: Information if all values are valid lineage IDs """ values_to_check = _get_values_to_check(values) # Check each lineage ID for lineage_id in values_to_check: if not isinstance(lineage_id, str): raise ServiceError( f"Lineage ID must be a string, got {type(lineage_id).__name__}" ) if not _is_valid_lineage_id(lineage_id): raise ServiceError( f"'{lineage_id}' is not a valid lineage ID. Expected a 64-character hexadecimal string." ) def get_closest_match(word_list_with_id: list, search_word: str) -> str | None: """ This function takes a list of objects, where each objects contains a 'name' and 'id' key, and a search word as input. It returns the 'id' of the objects in the list whose 'name' is the closest match to the search word, based on a fuzzy matching algorithm. Args: word_list_with_id (list): A list of objects, each containing 'name' and 'id' keys. search_word (str): The word to search for in the list of names. Returns: str | None: The 'id' of the dictionary in the list whose 'name' is the closest match to the search word, or None if no match is found. """ closest_name = get_close_matches( word=search_word.lower(), possibilities=[name["name"].lower() for name in word_list_with_id], n=1, cutoff=0.6, ) if closest_name: for words in word_list_with_id: if str(words.get("name")).lower() == closest_name[0].lower(): return str(words.get("id")) return None def get_project_or_space_type_based_on_context() -> str | None: """ Returns the project or space type based on the current context. Returns: str | None: The project/space type ('cpd' or 'wx') or None """ context = settings.di_context if context in ["cpdaas", "cpd"]: return "cpd" elif context == "df": return "wx" return None def append_context_to_url(url: str, context: str | None = None) -> str: """ Appends the context parameter to a URL if it doesn't already have one. Validates that the context is appropriate for the current environment mode. Args: url (str): The URL to append the context parameter to. context (str | None, optional): The context value to append. If None, uses settings.di_context. Defaults to None. Returns: str: The URL with the context parameter appended. Raises: ValueError: If the context is not valid for the environment mode. """ # Use provided context or fall back to settings.di_context context_value = context if context is not None else settings.di_context # Validate that the context is valid for the environment mode if context_value not in settings.valid_contexts: valid_contexts = ", ".join(settings.valid_contexts) raise ValueError( f"Invalid context '{context_value}' for environment mode '{settings.di_env_mode}'. " f"Valid contexts are: {valid_contexts}" ) # Parse the URL to check if it already has a context parameter parsed_url = urlparse(url) query_params = parse_qs(parsed_url.query) # If the URL already has a context parameter, return it as-is if "context" in query_params: return url # Determine the separator to use (? or &) separator = "&" if parsed_url.query else "?" # Append the context parameter with the appropriate separator return f"{url}{separator}context={context_value}"

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/hingaibm/data-intelligence-mcp-server'

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