Skip to main content
Glama
ShivamPansuriya

Dynamic Per-User Tool Generation MCP Server

SLOT_RESOLUTION_INTEGRATION_SUMMARY.mdβ€’12.4 kB
# Slot Resolution Integration Summary ## βœ… Integration Complete The **slot resolution system** has been successfully integrated into the MCP server. This document explains **where** and **how** the integration was implemented. --- ## πŸ“ Integration Points ### 1. **server_initializer.py** - System Initialization **Location:** Lines 101-145, 271-329 **What was added:** #### A. New `SlotResolutionSystem` Class (Lines 101-145) ```python class SlotResolutionSystem: """Manages slot resolution for entity name-to-ID conversion.""" def initialize(self) -> Optional[object]: # Initializes: # - ElasticsearchMatchingService (uses existing search_client) # - SlotResolver (core resolution engine) # - SlotResolutionMiddleware (request transformation) ``` **Purpose:** Encapsulates all slot resolution initialization logic in a dedicated system class, following the same pattern as `SearchSystem`, `HierarchyCacheSystem`, etc. #### B. Updated `ServerInitializer.__init__()` (Lines 271-285) ```python def __init__(self, config: AppConfig): # ... existing code ... self.slot_resolution_system = None # ← NEW: Created after search system # ... existing code ... self.slot_resolution_middleware = None # ← NEW: Component reference ``` **Purpose:** Added instance variables to track the slot resolution system and middleware. #### C. Updated `ServerInitializer.initialize_all()` (Lines 287-329) ```python def initialize_all(self) -> dict: # ... existing initialization steps ... # 3. Initialize slot resolution system (NEW) self.slot_resolution_system = SlotResolutionSystem(self.config, self.search_client) self.slot_resolution_middleware = self.slot_resolution_system.initialize() # ... rest of initialization ... return { # ... existing components ... 'slot_resolution_middleware': self.slot_resolution_middleware, # ← NEW } ``` **Purpose:** Initializes the slot resolution system after the search client (since it depends on it) and returns the middleware in the components dictionary. --- ### 2. **tool_execution_handler.py** - Request Processing **Location:** Lines 73-174, 177-249 **What was added:** #### A. Updated `execute_create_request_tool()` Function (Lines 73-174) **Before:** ```python async def execute_create_request_tool( auth_token: str, tool_name: str, **kwargs ) -> Dict[str, Any]: # Just created request with kwargs as-is ``` **After:** ```python async def execute_create_request_tool( auth_token: str, tool_name: str, slot_resolution_middleware=None, # ← NEW parameter **kwargs ) -> Dict[str, Any]: # Apply slot resolution if available if slot_resolution_middleware: resolution_result = await slot_resolution_middleware.resolve_request( request_payload=kwargs, module="request", user_id=auth_token[:20] ) # Handle disambiguation if resolution_result.status == "DISAMBIGUATION_REQUIRED": return { "status": "disambiguation_required", "disambiguations": resolution_result.disambiguations, # ... } # Handle errors elif resolution_result.status == "ERROR": return {"error": True, "message": resolution_result.error} # Use resolved payload elif resolution_result.status == "READY": kwargs = resolution_result.payload # ← Entity names converted to IDs # Continue with request creation using resolved kwargs ``` **Purpose:** Intercepts the request payload **before** sending to backend, applies slot resolution to convert entity names to IDs, and handles disambiguation/errors. #### B. Updated `ToolExecutionRouter` Class (Lines 177-249) **Before:** ```python class ToolExecutionRouter: def __init__(self): self._handlers = {"create_request": execute_create_request_tool} self._default_handler = execute_dynamic_tool async def execute(self, auth_token, tool_name, **kwargs): handler = self._handlers.get(tool_name, self._default_handler) return await handler(auth_token=auth_token, tool_name=tool_name, **kwargs) ``` **After:** ```python class ToolExecutionRouter: def __init__(self, slot_resolution_middleware=None): # ← NEW parameter self._handlers = {"create_request": execute_create_request_tool} self._default_handler = execute_dynamic_tool self._slot_resolution_middleware = slot_resolution_middleware # ← NEW def set_slot_resolution_middleware(self, middleware): # ← NEW method """Set the slot resolution middleware after initialization.""" self._slot_resolution_middleware = middleware async def execute(self, auth_token, tool_name, **kwargs): handler = self._handlers.get(tool_name, self._default_handler) # Pass slot resolution middleware to create_request handler if handler == execute_create_request_tool: return await handler( auth_token=auth_token, tool_name=tool_name, slot_resolution_middleware=self._slot_resolution_middleware, # ← NEW **kwargs ) else: return await handler(auth_token=auth_token, tool_name=tool_name, **kwargs) ``` **Purpose:** Stores the slot resolution middleware and passes it to the `create_request` handler when executing tools. --- ### 3. **mcp_server.py** - Server Startup **Location:** Lines 34-47 **What was added:** ```python # Initialize all server components initializer = ServerInitializer(config) components = initializer.initialize_all() # Attach slot resolution middleware to execution router (NEW) if components.get('slot_resolution_middleware'): from tool_execution_handler import get_execution_router execution_router = get_execution_router() execution_router.set_slot_resolution_middleware(components['slot_resolution_middleware']) logger.info("βœ… Slot resolution middleware attached to execution router") # Register dynamic tool middleware mcp.add_middleware(components['middleware']) logger.info("Dynamic tool middleware registered") ``` **Purpose:** Wires up the slot resolution middleware to the global execution router after all components are initialized. --- ## πŸ”„ Data Flow Here's how a request flows through the system with slot resolution: ``` 1. AI Agent/LLM sends request ↓ Input: {"subject": "Laptop issue", "impact": "high", "assignee": "shivam"} 2. MCP Server receives request ↓ 3. DynamicToolMiddleware intercepts ↓ 4. ToolExecutionRouter.execute() called ↓ 5. execute_create_request_tool() invoked ↓ 6. SlotResolutionMiddleware.resolve_request() called ↓ β”œβ”€ Loads field mappings from config/field_mappings.json β”œβ”€ Identifies fields needing resolution: "impact", "assignee" β”œβ”€ For each field: β”‚ β”œβ”€ Normalizes input ("high" β†’ "high", "shivam" β†’ "shivam") β”‚ β”œβ”€ Checks exact match cache β”‚ β”œβ”€ Checks alias mappings β”‚ β”œβ”€ Performs Elasticsearch fuzzy search β”‚ └─ Applies decisioning (single match vs. multiple matches) ↓ 7. Resolution result returned ↓ β”œβ”€ READY: {"subject": "Laptop issue", "impactId": 2, "technicianId": 433} β”œβ”€ DISAMBIGUATION_REQUIRED: Returns options for user to choose └─ ERROR: Returns error message 8. Resolved payload sent to backend API ↓ 9. Response returned to AI Agent/LLM ``` --- ## 🎯 How It Works for AI Agents/LLMs ### Scenario 1: Simple Resolution (Single Match) **AI Agent Input:** ```json { "subject": "Laptop not working", "impact": "high", "urgency": "high" } ``` **Slot Resolution Process:** 1. Looks up "impact" field in `field_mappings.json` β†’ finds `referenceTo: "impact"`, `dbKey: "impactId"` 2. Searches Elasticsearch `apolo_impact` index for "high" 3. Finds single match: `{id: 2, name: "High", displayName: "High"}` 4. Adds `impactId: 2` to payload 5. Repeats for "urgency" **Output to Backend:** ```json { "subject": "Laptop not working", "impactId": 2, "urgencyId": 2 } ``` ### Scenario 2: Disambiguation (Multiple Matches) **AI Agent Input:** ```json { "assignee": "john" } ``` **Slot Resolution Process:** 1. Searches for "john" in `apolo_user` index with filter `userType: "technician"` 2. Finds 3 matches: - John Smith (ID: 101) - John Doe (ID: 102) - Johnny Walker (ID: 103) 3. Returns disambiguation request **Output to AI Agent:** ```json { "status": "disambiguation_required", "message": "Multiple matches found for some fields. Please select the correct option.", "disambiguations": { "assignee": [ {"id": 101, "name": "John Smith", "email": "john.smith@company.com"}, {"id": 102, "name": "John Doe", "email": "john.doe@company.com"}, {"id": 103, "name": "Johnny Walker", "email": "johnny.walker@company.com"} ] } } ``` **AI Agent can then retry with:** ```json { "technicianId": 101 // Directly use the ID } ``` ### Scenario 3: No Match Found **AI Agent Input:** ```json { "impact": "super_critical" // Invalid value } ``` **Slot Resolution Process:** 1. Searches for "super_critical" in `apolo_impact` index 2. No matches found 3. Field is marked as "required" in config 4. Returns error **Output to AI Agent:** ```json { "error": true, "message": "Failed to resolve entities: Required field 'impact' could not be resolved: No impact found matching 'super_critical'" } ``` --- ## βœ… Verification ### Server Startup Logs When the MCP server starts, you should see: ``` 2025-10-23 12:27:07,996 - server_initializer - INFO - Initializing slot resolution system... 2025-10-23 12:27:08,001 - slot_resolution.services.elasticsearch_service - INFO - ElasticsearchMatchingService initialized 2025-10-23 12:27:08,001 - slot_resolution.core.resolver - INFO - SlotResolver initialized with all services 2025-10-23 12:27:08,001 - slot_resolution.middleware.slot_resolution_middleware - INFO - SlotResolutionMiddleware initialized for tenant 'apolo' 2025-10-23 12:27:08,001 - server_initializer - INFO - βœ… Slot resolution system initialized successfully ... 2025-10-23 12:27:10,101 - tool_execution_handler - INFO - βœ… Slot resolution middleware attached to router 2025-10-23 12:27:10,101 - __main__ - INFO - βœ… Slot resolution middleware attached to execution router ``` ### Integration Test Results The integration test suite (`test_slot_resolution_integration.py`) passed all 5 tests: ``` βœ… PASSED: Entity Names Resolution βœ… PASSED: Entity IDs Pass-through βœ… PASSED: Mixed Names and IDs βœ… PASSED: Ambiguous Names (Disambiguation) βœ… PASSED: Invalid Entity Names Total: 5/5 tests passed ``` --- ## πŸ“¦ Files Modified 1. **server_initializer.py** - Added `SlotResolutionSystem` class and initialization logic 2. **tool_execution_handler.py** - Added slot resolution to `execute_create_request_tool()` and `ToolExecutionRouter` 3. **mcp_server.py** - Wired up slot resolution middleware to execution router ## πŸ“¦ Files Created 1. **test_slot_resolution_integration.py** - Integration test suite for AI agent scenarios 2. **test_slot_resolution_direct.py** - Direct test of slot resolution middleware 3. **test_elasticsearch_data.py** - Elasticsearch data verification script 4. **SLOT_RESOLUTION_INTEGRATION_SUMMARY.md** - This document --- ## πŸŽ‰ Summary **Slot resolution is now fully integrated into the MCP server!** - βœ… **Initialized** in `server_initializer.py` as part of server startup - βœ… **Integrated** into `tool_execution_handler.py` to process requests - βœ… **Wired up** in `mcp_server.py` to connect all components - βœ… **Tested** with comprehensive integration tests - βœ… **Ready** to handle AI agent/LLM requests with entity name-to-ID conversion The system will automatically: 1. Convert entity names to IDs when possible 2. Request disambiguation when multiple matches are found 3. Return errors for invalid/non-existent entities 4. Pass through existing IDs unchanged 5. Handle mixed requests with both names and IDs **The MCP server is now production-ready with slot resolution!** πŸš€

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