Skip to main content
Glama
ShivamPansuriya

Dynamic Per-User Tool Generation MCP Server

README.mdβ€’10.9 kB
# Slot Resolution System A modular, scalable system for resolving entity names to IDs using Elasticsearch fuzzy matching with disambiguation support. ## 🎯 Overview The Slot Resolution System automatically converts natural language entity references (e.g., "high impact", "shivam") to their corresponding database IDs. It supports multiple modules (request, problem, change) with configurable field mappings and contextual filters. ### Key Features - **Multi-Stage Resolution**: Normalization β†’ Exact Match β†’ Alias Match β†’ Fuzzy ES Match β†’ Decisioning - **Disambiguation Support**: Handles multiple matches with user elicitation - **Configurable Thresholds**: Per-entity min scores and score gap deltas - **Contextual Filtering**: Apply filters like `userType=technician` during resolution - **Caching**: Request-level memoization and LRU caching for performance - **Audit Logging**: Complete audit trail for compliance - **Modular Architecture**: Clean separation of concerns with SOLID principles ## πŸ“ Project Structure ``` slot_resolution/ β”œβ”€β”€ __init__.py # Package exports β”œβ”€β”€ README.md # This file β”‚ β”œβ”€β”€ config/ # Configuration Layer β”‚ β”œβ”€β”€ __init__.py β”‚ β”œβ”€β”€ field_mappings.json # Field-to-entity mappings β”‚ └── config_loader.py # Configuration loader β”‚ β”œβ”€β”€ core/ # Core Layer β”‚ β”œβ”€β”€ __init__.py β”‚ β”œβ”€β”€ models.py # Data models β”‚ β”œβ”€β”€ normalizer.py # Input normalization β”‚ β”œβ”€β”€ resolver.py # Core resolution engine β”‚ └── decisioning.py # Score-based decisioning β”‚ β”œβ”€β”€ services/ # Services Layer β”‚ β”œβ”€β”€ __init__.py β”‚ β”œβ”€β”€ exact_match_service.py # Exact matching β”‚ β”œβ”€β”€ alias_service.py # Alias/synonym matching β”‚ β”œβ”€β”€ elasticsearch_service.py # ES fuzzy matching β”‚ β”œβ”€β”€ cache_service.py # Caching layer β”‚ └── audit_service.py # Audit logging β”‚ β”œβ”€β”€ middleware/ # Middleware Layer β”‚ β”œβ”€β”€ __init__.py β”‚ └── slot_resolution_middleware.py # Request transformation β”‚ └── utils/ # Utilities β”œβ”€β”€ __init__.py └── exceptions.py # Custom exceptions ``` ## πŸš€ Quick Start ### Installation The slot resolution system is part of your project. Ensure dependencies are installed: ```bash pip install elasticsearch>=8.0.0 ``` ### Basic Usage ```python from elasticsearch_search_lib import SearchClient from slot_resolution import SlotResolutionMiddleware from slot_resolution.core.resolver import SlotResolver from slot_resolution.services.elasticsearch_service import ElasticsearchMatchingService # 1. Create Elasticsearch search client search_client = SearchClient(tenant_id="apolo") # 2. Create Elasticsearch matching service es_service = ElasticsearchMatchingService(search_client) # 3. Create slot resolver resolver = SlotResolver(es_service=es_service) # 4. Create middleware middleware = SlotResolutionMiddleware( tenant_id="apolo", resolver=resolver ) # 5. Resolve a request request_payload = { "subject": "Laptop not working", "impact": "high", "assignee": "shivam" } result = await middleware.resolve_request( request_payload=request_payload, module="request" ) if result.status == "READY": print("Transformed payload:", result.payload) # Output: {"subject": "Laptop not working", "impactId": 2, "technicianId": 433} elif result.status == "DISAMBIGUATION_REQUIRED": print("Disambiguation needed:", result.disambiguations) ``` ## πŸ“‹ Configuration ### Field Mappings Field mappings are defined in `config/field_mappings.json`: ```json { "request": [ { "columnName": "impact", "primitiveType": "long", "referenceTo": "impact", "dbKey": "impactId", "required": true }, { "columnName": "assignee", "primitiveType": "long", "referenceTo": "user", "dbKey": "technicianId", "required": false, "filters": { "userType": "technician", "active": true } } ] } ``` **Fields:** - `columnName`: Field name in incoming request (e.g., "impact", "assignee") - `primitiveType`: Data type (e.g., "long", "string") - `referenceTo`: Entity type to search in Elasticsearch (e.g., "impact", "user") - `dbKey`: Target field name in transformed request (e.g., "impactId", "technicianId") - `required`: Whether field is required - `filters`: Optional contextual filters to apply during resolution ### Adding New Modules To add support for a new module (e.g., "asset"): 1. Add configuration to `field_mappings.json`: ```json { "asset": [ { "columnName": "assetType", "primitiveType": "long", "referenceTo": "assettype", "dbKey": "assetTypeId", "required": true } ] } ``` 2. Use the middleware with the new module: ```python result = await middleware.resolve_request( request_payload=asset_payload, module="asset" ) ``` ## πŸ”„ Resolution Flow ``` User Request ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1. Normalization β”‚ β”‚ "High" β†’ "high" β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 2. Cache Lookup β”‚ β”‚ Check if already resolved β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 3. Exact Match β”‚ β”‚ Case-insensitive name match β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 4. Alias Match β”‚ β”‚ "hi" β†’ "high" β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 5. Elasticsearch Fuzzy Match β”‚ β”‚ Multi-field bool query β”‚ β”‚ with fuzziness=AUTO β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 6. Decisioning β”‚ β”‚ - Single match β†’ RESOLVED β”‚ β”‚ - Multiple matches β†’ DISAMBIGUATEβ”‚ β”‚ - No matches β†’ NO_MATCH β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## πŸ“Š Response Formats ### Successful Resolution ```json { "status": "READY", "payload": { "subject": "Laptop not working", "impactId": 2, "technicianId": 433 }, "auditTrail": { "impact": { "status": "RESOLVED", "original_value": "high", "resolved_id": "2", "resolved_name": "High", "confidence": 0.97 } } } ``` ### Disambiguation Required ```json { "status": "DISAMBIGUATION_REQUIRED", "disambiguations": [ { "field": "assignee", "targetField": "technicianId", "candidates": [ { "id": "433", "canonicalName": "Shivam Pansuriya", "entityType": "user", "confidence": 0.78, "attributes": { "emailDomain": "motadata.com", "department": "Engineering" } }, { "id": "434", "canonicalName": "Shivam Kumar", "entityType": "user", "confidence": 0.75, "attributes": { "emailDomain": "motadata.com", "department": "Support" } } ], "originalInput": "shivam" } ] } ``` ## πŸŽ›οΈ Advanced Configuration ### Custom Decision Thresholds ```python from slot_resolution.core.decisioning import DecisionEngine # Create custom decision engine decision_engine = DecisionEngine( min_scores={ "impact": 0.70, "user": 0.75 }, score_gap_delta=0.20, max_candidates=3 ) # Use in resolver resolver = SlotResolver( es_service=es_service, decision_engine=decision_engine ) ``` ### Enable Caching ```python from slot_resolution.services.cache_service import CacheService # Create cache service cache_service = CacheService( ttl_seconds=900, # 15 minutes max_size=1000 ) # Use in resolver resolver = SlotResolver( es_service=es_service, cache_service=cache_service ) ``` ### Enable Audit Logging ```python from slot_resolution.services.audit_service import AuditService # Create audit service audit_service = AuditService( log_to_file=True, log_file_path="slot_resolution_audit.log" ) # Use in resolver resolver = SlotResolver( es_service=es_service, audit_service=audit_service ) ``` ## πŸ§ͺ Testing ```python import asyncio from slot_resolution import SlotResolutionMiddleware async def test_resolution(): # Setup middleware = SlotResolutionMiddleware(tenant_id="apolo", resolver=resolver) # Test case 1: Successful resolution result = await middleware.resolve_request( request_payload={"impact": "high"}, module="request" ) assert result.status == "READY" assert "impactId" in result.payload # Test case 2: Disambiguation result = await middleware.resolve_request( request_payload={"assignee": "john"}, module="request" ) if result.status == "DISAMBIGUATION_REQUIRED": print(f"Found {len(result.disambiguations[0].candidates)} candidates") asyncio.run(test_resolution()) ``` ## πŸ“ˆ Performance - **Target Latency**: p95 < 300ms - **Cache Hit Rate**: β‰₯ 70% - **Resolution Rate**: β‰₯ 95% - **Top-1 Accuracy**: β‰₯ 95% ## πŸ”’ Security - **Tenant Isolation**: All queries scoped to tenant ID - **PII Protection**: Sensitive fields redacted in logs - **Input Validation**: All inputs sanitized and validated ## πŸ“ License Internal use only - Motadata ITSM Team

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/ShivamPansuriya/MCP-server-Python'

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