mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-25 19:15:18 +02:00
perf(mcp): persist list_tools discovery in connector.config.cached_tools
Skip the ~1-3s MCP initialize + list_tools handshake on every cache miss by reading tool definitions from the connector row we already load. Lazy populate on first miss, self-heal on corrupt cache, zero schema migration.
This commit is contained in:
parent
db8bffab38
commit
c0aa4261ac
3 changed files with 304 additions and 42 deletions
|
|
@ -0,0 +1,130 @@
|
|||
"""Unit tests for ``mcp_tools_cache``."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from app.agents.new_chat.tools.mcp_tools_cache import (
|
||||
CachedMCPToolDef,
|
||||
CachedMCPTools,
|
||||
read_cached_tools,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
|
||||
def _make_connector(config: dict | None) -> SimpleNamespace:
|
||||
return SimpleNamespace(id=42, config=config)
|
||||
|
||||
|
||||
def test_read_returns_none_when_config_is_none() -> None:
|
||||
assert read_cached_tools(_make_connector(None)) is None
|
||||
|
||||
|
||||
def test_read_returns_none_when_cached_tools_missing() -> None:
|
||||
assert read_cached_tools(_make_connector({"server_config": {}})) is None
|
||||
|
||||
|
||||
def test_read_returns_none_when_cached_tools_is_not_a_dict() -> None:
|
||||
assert read_cached_tools(_make_connector({"cached_tools": []})) is None
|
||||
assert read_cached_tools(_make_connector({"cached_tools": "stale"})) is None
|
||||
|
||||
|
||||
def test_read_parses_minimal_valid_payload() -> None:
|
||||
parsed = read_cached_tools(
|
||||
_make_connector(
|
||||
{
|
||||
"cached_tools": {
|
||||
"discovered_at": "2026-05-20T10:00:00+00:00",
|
||||
"tools": [
|
||||
{
|
||||
"name": "list_issues",
|
||||
"description": "List Linear issues",
|
||||
"input_schema": {"type": "object"},
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
assert parsed is not None
|
||||
assert parsed.server_version is None
|
||||
assert parsed.server_name is None
|
||||
assert parsed.transport is None
|
||||
assert len(parsed.tools) == 1
|
||||
assert parsed.tools[0].name == "list_issues"
|
||||
|
||||
|
||||
def test_read_parses_full_payload_with_serverinfo() -> None:
|
||||
parsed = read_cached_tools(
|
||||
_make_connector(
|
||||
{
|
||||
"cached_tools": {
|
||||
"discovered_at": "2026-05-20T10:00:00+00:00",
|
||||
"server_version": "1.2.3",
|
||||
"server_name": "atlassian-mcp",
|
||||
"transport": "streamable-http",
|
||||
"tools": [
|
||||
{"name": "create_issue", "input_schema": {}},
|
||||
{"name": "list_issues", "input_schema": {}},
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
assert parsed is not None
|
||||
assert parsed.server_version == "1.2.3"
|
||||
assert parsed.server_name == "atlassian-mcp"
|
||||
assert parsed.transport == "streamable-http"
|
||||
assert [t.name for t in parsed.tools] == ["create_issue", "list_issues"]
|
||||
|
||||
|
||||
def test_read_returns_none_for_corrupt_payload(caplog) -> None:
|
||||
parsed = read_cached_tools(
|
||||
_make_connector(
|
||||
{
|
||||
"cached_tools": {
|
||||
"discovered_at": "not-a-date",
|
||||
"tools": "should-be-a-list",
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
assert parsed is None
|
||||
assert any("corrupt cached_tools" in r.getMessage() for r in caplog.records)
|
||||
|
||||
|
||||
def test_read_returns_none_when_tools_missing() -> None:
|
||||
parsed = read_cached_tools(
|
||||
_make_connector(
|
||||
{"cached_tools": {"discovered_at": "2026-05-20T10:00:00+00:00"}}
|
||||
)
|
||||
)
|
||||
assert parsed is None
|
||||
|
||||
|
||||
def test_tool_def_defaults_description_and_schema() -> None:
|
||||
td = CachedMCPToolDef.model_validate({"name": "ping"})
|
||||
assert td.description == ""
|
||||
assert td.input_schema == {}
|
||||
|
||||
|
||||
def test_model_dump_json_mode_is_round_trippable() -> None:
|
||||
original = CachedMCPTools(
|
||||
discovered_at=datetime(2026, 5, 20, 10, 0, 0, tzinfo=UTC),
|
||||
server_version="1.2.3",
|
||||
server_name="atlassian-mcp",
|
||||
transport="streamable-http",
|
||||
tools=[CachedMCPToolDef(name="list_issues")],
|
||||
)
|
||||
payload = original.model_dump(mode="json")
|
||||
|
||||
assert payload["discovered_at"] == "2026-05-20T10:00:00Z"
|
||||
assert payload["tools"][0]["name"] == "list_issues"
|
||||
|
||||
reparsed = CachedMCPTools.model_validate(payload)
|
||||
assert reparsed.discovered_at == original.discovered_at
|
||||
assert reparsed.tools[0].name == "list_issues"
|
||||
Loading…
Add table
Add a link
Reference in a new issue