Skip to main content
Glama
util.py8.06 kB
import logging from typing import List, Dict, Any, Optional import enum from src.constants import RELEVANCE_SCORE_NOT_AVAILABLE # Configure logging logger = logging.getLogger("mcp.server.reltio") def simplify_reltio_attributes(attributes_dict, preserve_metadata=False): """ Simplifies a Reltio-style attributes dictionary by extracting 'value' fields, preserving the nested structure and handling multiple values. Args: attributes_dict: The attributes dictionary from Reltio API preserve_metadata: If True, preserve full attribute metadata including uri, type, ov, lookupCode, etc. If False, only extract value fields (default behavior for backward compatibility) """ if preserve_metadata: # Return full attribute details without simplification return attributes_dict # Original simplification logic result = {} for key, value_list in attributes_dict.items(): if isinstance(value_list, list) and value_list: simplified_list = [] for item in value_list: if isinstance(item, dict) and 'value' in item: if isinstance(item['value'], dict): simplified_list.append(simplify_reltio_attributes(item['value'], preserve_metadata)) else: simplified_list.append(item['value']) if not simplified_list: continue if len(simplified_list) == 1: result[key] = simplified_list[0] else: result[key] = simplified_list return result def slim_crosswalks(cws: List[Dict[str, Any]], preserve_details=False) -> List[Dict[str, Any]]: """ Process crosswalks data based on preserve_details flag. Args: cws: List of crosswalk dictionaries from Reltio API preserve_details: If True, preserve full crosswalk details including uri, attributes, singleAttributeUpdateDates, etc. If False, keep only id, type, value, createDate (default behavior for backward compatibility) """ if preserve_details: # Return full crosswalk details without simplification return [cw for cw in cws if isinstance(cw, dict)] # Original slim logic out: List[Dict[str, Any]] = [] for cw in cws: if not isinstance(cw, dict): continue # Extract ID from URI uri = cw.get("uri", "") if uri and "/" in uri: id_value = uri.rsplit("/", 1)[-1] else: id_value = cw.get("id") # Extract type (last part after /) type_value = cw.get("type", "") if type_value and "/" in type_value: type_value = type_value.rsplit("/", 1)[-1] # Extract createDate with fallbacks create_date = cw.get("createDate") or cw.get("createTime") or cw.get("createdTime") out.append({ "id": id_value, "type": type_value, "value": cw.get("value"), "createDate": create_date, }) return out def format_entity_matches(matches: List[Dict[str, Any]]) -> Dict[str, Any]: return {d["object"]["uri"]:{ "matchRules":d["matchRules"], "createdTime":d["createdTime"], "relevance":d.get("relevance",RELEVANCE_SCORE_NOT_AVAILABLE), "label":d.get("label",None)} for d in matches} def format_unified_entity_matches(matches: List[Dict[str, Any]], match_entities: Dict[str, Dict[str, Any]] = None) -> Dict[str, Any]: """ Format matches for the unified entity with matches tool. Args: matches: List of match objects from _transitiveMatches API match_entities: Optional dict of full entity data keyed by entity URI Returns: Dictionary with formatted match data including metadata and optional full entity attributes """ result = {} for match in matches: entity_uri = match["object"]["uri"] match_data = { "label": match.get("label"), "matchRules": match["matchRules"], "relevance": match.get("relevance",RELEVANCE_SCORE_NOT_AVAILABLE), "createdTime": match["createdTime"] } # Add full entity attributes if provided if match_entities and entity_uri in match_entities: entity_data = match_entities[entity_uri] match_data["attributes"] = simplify_reltio_attributes(entity_data.get("attributes", {})) if "crosswalks" in entity_data: match_data["crosswalks"] = slim_crosswalks(entity_data["crosswalks"]) result[entity_uri] = match_data return result def create_search_activity_description(filter: str = "", entity_type: str = "", options: str = "") -> dict: """ Create activity log description for search operations. Args: filter (str): The search filter used entity_type (str): The entity type being searched options (str): Search options used Returns: dict: Activity log description in the required format """ # Build the query string with filter and options query_parts = [] if filter: query_parts.append(f"filter={filter}") if options: query_parts.append(f"options={options}") query_string = "&".join(query_parts) # Create activity log description in the new format activity_description = { "activity": { "query": query_string, "uiState": { "view": { "searchResultsMode": "table", "entityTypeTab": f"configuration/entityTypes/{entity_type}" if entity_type else None, "tabs": None, "previewPanelMode": None }, "facets": { "type": { "fieldName": "type" } }, "currentTenant": None, "searchOptions": { "searchByOv": "searchByOv" in options if options else False, "ovOnly": "ovOnly" in options if options else False }, "keyword": { "value": filter if filter else "", "isRawFilter": True }, "map": None, "version": "2.0" } }, "version": "2.0" } return activity_description class ActivityLogLabel(enum.Enum): USER_SEARCH="USER_SEARCH" USER_PROFILE_VIEW="USER_PROFILE_VIEW" ENTITY_UPDATE="ENTITY_CHANGED" ENTITY_MERGED="ENTITIES_MERGED" ENTITY_UNMERGED="ENTITIES_UNMERGED" ENTITY_MATCH_HISTORY="ENTITY_MATCH_HISTORY" ENTITY_MATCH_SCORE="ENTITY_MATCH_SCORE" ENTITY_CONFIDENCE_LEVEL="ENTITY_CONFIDENCE_LEVEL" ENTITY_TOTAL_MATCHES="ENTITY_TOTAL_MATCHES" NOT_MATCHES_SET="NOT_MATCHES_SET" POTENTIAL_MATCHES_FOUND="POTENTIAL_MATCHES_FOUND" NOT_MATCHES_RESET="NOT_MATCHES_RESET" ENTITY_MERGE_TREE_EXPORT="ENTITY_MERGE_TREE_EXPORT" RELATIONSHIP_SEARCH="RELATIONSHIP_SEARCH" TENANT_METADATA="TENANT_METADATA" DATA_MODEL_DEFINITION="DATA_MODEL_DEFINITION" ENTITY_TYPE_DEFINITION="ENTITY_TYPE_DEFINITION" CHANGE_REQUEST_TYPE_DEFINITION="CHANGE_REQUEST_TYPE_DEFINITION" RELATION_TYPE_DEFINITION="RELATION_TYPE_DEFINITION" INTERACTION_TYPE_DEFINITION="INTERACTION_TYPE_DEFINITION" GRAPH_TYPE_DEFINITION="GRAPH_TYPE_DEFINITION" GROUPING_TYPE_DEFINITION="GROUPING_TYPE_DEFINITION" TENANT_PERMISSIONS_METADATA="TENANT_PERMISSIONS_METADATA" GET_MERGE_ACTIVITIES="GET_MERGE_ACTIVITIES" USER_SUMMARY="USER_SUMMARY" USER_DETAILS="USER_DETAILS" WORKFLOW_TASKS="WORKFLOW_TASKS" LOOKUP_LIST="LOOKUP_LIST" ENTITY_HOPS="ENTITY_HOPS" RELATIONSHIP_CREATE="RELATIONSHIP_CREATE" RELATIONSHIP_DELETE="RELATIONSHIP_DELETE" USER_INTERACTION="USER_INTERACTION"

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/reltio-ai/reltio-mcp-server'

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