Skip to content

[CHORE]: GatewayService creates uninitialized service instances (ToolService, PromptService, ResourceService) #2256

@crivetimihai

Description

@crivetimihai

Summary

GatewayService creates private instances of ToolService, PromptService, and ResourceService without calling their initialize() methods. This means events emitted by these services (e.g., _notify_tool_activated, _notify_prompt_deactivated) won't propagate to Redis or any subscribers.

Current Behavior

# mcpgateway/services/gateway_service.py:383-385
self.tool_service = ToolService()
self.prompt_service = PromptService()
self.resource_service = ResourceService()

These services have an initialize() method that sets up the EventService Redis client:

# Example from prompt_service.py:204-207
async def initialize(self) -> None:
    """Initialize the service."""
    logger.info("Initializing prompt service")
    await self._event_service.initialize()

Without initialize(), the _redis_client remains None and events are only pushed to local _event_subscribers queues. If no local subscribers exist, events are silently dropped.

Why This Currently Works

  1. Database state changes are committed - The actual enabled field updates happen regardless
  2. Cache invalidation is explicit - cache.invalidate_prompts() / cache.invalidate_resources() is called after batch operations
  3. Global singletons exist - main.py creates and properly initializes global instances that handle event propagation for the app

Impact

  • Events emitted during gateway state changes (activate/deactivate) don't reach Redis subscribers
  • Cross-worker event propagation for these specific operations may not work
  • UI updates relying on these events won't trigger (though cache invalidation handles most cases)

Proposed Solution

Option 1: Reuse Global Singletons (Preferred)

Refactor to use the initialized global instances from main.py:

# This requires careful handling of circular imports
from mcpgateway.services.tool_service import tool_service  # singleton
from mcpgateway.services.prompt_service import prompt_service  # singleton
from mcpgateway.services.resource_service import resource_service  # singleton

class GatewayService:
    def __init__(self):
        self.tool_service = tool_service
        self.prompt_service = prompt_service
        self.resource_service = resource_service

Option 2: Initialize in GatewayService.initialize()

async def initialize(self) -> None:
    # ... existing initialization ...
    await self.tool_service.initialize()
    await self.prompt_service.initialize()
    await self.resource_service.initialize()

Option 3: Lazy Initialization

Initialize on first use if not already initialized.

Files Affected

  • mcpgateway/services/gateway_service.py - Creates uninitialized instances
  • mcpgateway/main.py - Has properly initialized global singletons
  • mcpgateway/services/tool_service.py
  • mcpgateway/services/prompt_service.py
  • mcpgateway/services/resource_service.py

Related

Labels

  • tech-debt
  • refactor

Metadata

Metadata

Labels

SHOULDP2: Important but not vital; high-value items that are not crucial for the immediate releasechoreLinting, formatting, dependency hygiene, or project maintenance chorespythonPython / backend development (FastAPI)

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions