mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-25 19:15:18 +02:00
refactor(mcp): per-connector cache refresh on lifecycle events
Collapse the invalidate + warmup pair into a single refresh_mcp_tools_cache_for_connector(connector_id, search_space_id) helper and scope live discovery to the one connector that changed instead of the whole search space. - new mcp_tool.discover_single_mcp_connector: load one connector, refresh OAuth if needed, force live MCP discovery so its cached_tools row is rewritten; returned wrappers are discarded since the in-process LRU is rebuilt lazily on the next user query - mcp_tools_cache.refresh_mcp_tools_cache_for_connector: synchronously evicts the per-space LRU (LRU keys cannot scope finer) and schedules the per-connector prefetch via loop.create_task - routes (OAuth callback, MCP POST, MCP PUT) collapse their two back-to-back calls into a single refresh call; DELETE handlers keep using bare invalidate_mcp_tools_cache (nothing to prefetch) No new automated tests: the new functions are I/O glue (DB + network) where mocked unit tests would test implementation rather than behavior. The existing 9 unit tests for the cached_tools data shape are unchanged.
This commit is contained in:
parent
c0aa4261ac
commit
704d1bf18f
4 changed files with 161 additions and 11 deletions
|
|
@ -428,7 +428,7 @@ async def mcp_oauth_callback(
|
|||
await session.commit()
|
||||
await session.refresh(db_connector)
|
||||
|
||||
_invalidate_cache(space_id)
|
||||
_refresh_mcp_cache(db_connector.id, space_id)
|
||||
|
||||
logger.info(
|
||||
"Re-authenticated %s MCP connector %s for user %s",
|
||||
|
|
@ -481,7 +481,7 @@ async def mcp_oauth_callback(
|
|||
detail="A connector for this service already exists.",
|
||||
) from e
|
||||
|
||||
_invalidate_cache(space_id)
|
||||
_refresh_mcp_cache(new_connector.id, space_id)
|
||||
|
||||
logger.info(
|
||||
"Created %s MCP connector %s for user %s in space %s",
|
||||
|
|
@ -658,10 +658,17 @@ async def reauth_mcp_service(
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _invalidate_cache(space_id: int) -> None:
|
||||
try:
|
||||
from app.agents.new_chat.tools.mcp_tool import invalidate_mcp_tools_cache
|
||||
def _refresh_mcp_cache(connector_id: int, space_id: int) -> None:
|
||||
"""Evict the in-process MCP tool LRU and schedule background prefetch.
|
||||
|
||||
invalidate_mcp_tools_cache(space_id)
|
||||
Wraps :func:`refresh_mcp_tools_cache_for_connector` so any failure is
|
||||
isolated from the OAuth response flow.
|
||||
"""
|
||||
try:
|
||||
from app.agents.new_chat.tools.mcp_tools_cache import (
|
||||
refresh_mcp_tools_cache_for_connector,
|
||||
)
|
||||
|
||||
refresh_mcp_tools_cache_for_connector(connector_id, space_id)
|
||||
except Exception:
|
||||
logger.debug("MCP cache invalidation skipped", exc_info=True)
|
||||
logger.debug("MCP cache refresh skipped", exc_info=True)
|
||||
|
|
|
|||
|
|
@ -2650,9 +2650,11 @@ async def create_mcp_connector(
|
|||
f"for user {user.id} in search space {search_space_id}"
|
||||
)
|
||||
|
||||
from app.agents.new_chat.tools.mcp_tool import invalidate_mcp_tools_cache
|
||||
from app.agents.new_chat.tools.mcp_tools_cache import (
|
||||
refresh_mcp_tools_cache_for_connector,
|
||||
)
|
||||
|
||||
invalidate_mcp_tools_cache(search_space_id)
|
||||
refresh_mcp_tools_cache_for_connector(db_connector.id, search_space_id)
|
||||
|
||||
connector_read = SearchSourceConnectorRead.model_validate(db_connector)
|
||||
return MCPConnectorRead.from_connector(connector_read)
|
||||
|
|
@ -2828,9 +2830,11 @@ async def update_mcp_connector(
|
|||
|
||||
logger.info(f"Updated MCP connector {connector_id}")
|
||||
|
||||
from app.agents.new_chat.tools.mcp_tool import invalidate_mcp_tools_cache
|
||||
from app.agents.new_chat.tools.mcp_tools_cache import (
|
||||
refresh_mcp_tools_cache_for_connector,
|
||||
)
|
||||
|
||||
invalidate_mcp_tools_cache(connector.search_space_id)
|
||||
refresh_mcp_tools_cache_for_connector(connector.id, connector.search_space_id)
|
||||
|
||||
connector_read = SearchSourceConnectorRead.model_validate(connector)
|
||||
return MCPConnectorRead.from_connector(connector_read)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue