From 8df8e33534acddcbcc687a501f41b5742c4837b7 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 23:30:29 +0000 Subject: [PATCH 1/2] Cache Sharesight MCP results for 10 minutes cache_ttl 600 on the sharesight server in mcp_servers.json (Yahoo stays at 30 seconds). Identical calls within the window share one result, including the daily holding-news check. Errors are never cached, and the cache lives in memory so a restart clears it. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_014k4kywyN5dAo39izUPvxbw --- README.md | 3 ++- mcp_servers.json | 3 ++- tests/test_mcp.py | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c10eb4..ae4a58c 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,8 @@ Each answer's log line shows the cached percentage. points, Sharesight holdings flattened into tables, markdown tables (Yahoo) squeezed (padding and rule rows dropped, `1.20067e+11` shown as `120.067B`, NaN as `-`), results capped at 12,000 characters; an identical call within one request gets a short "same as earlier" note instead of a second copy; - `cache_ttl` shares results between concurrent users. + `cache_ttl` shares results between users: 30 seconds for Yahoo, 10 minutes for Sharesight (so a portfolio + answer can be up to 10 minutes old). - **Compact history:** stored HTML is shown to the model as plain text (ticker links become the symbol, tags and Yahoo URLs dropped), lines cut to 240 characters and the bot's own to 160. - **Smaller prompts:** the system prompt is about half its previous size, the repeated instruction diff --git a/mcp_servers.json b/mcp_servers.json index 07a64ca..dcd52db 100644 --- a/mcp_servers.json +++ b/mcp_servers.json @@ -39,7 +39,8 @@ ], "slim": "sharesight", "gate": "portfolio", - "max_concurrent": 1 + "max_concurrent": 1, + "cache_ttl": 600 } } } diff --git a/tests/test_mcp.py b/tests/test_mcp.py index 5dc30d1..5d60673 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -1,5 +1,6 @@ import asyncio import json +from pathlib import Path from types import SimpleNamespace as N from lib.mcp.results import diet, slim_result, squeeze_tables, table_records, tidy_sharesight @@ -112,6 +113,21 @@ async def test_call_slims_and_caches_identical_concurrent_calls(): assert len(s.session.calls) == 2 +async def test_sharesight_results_are_cached_for_ten_minutes(monkeypatch): + cfg = json.loads((Path(__file__).parent.parent / "mcp_servers.json").read_text())["mcpServers"]["sharesight"] + assert cfg["cache_ttl"] == 600 + clock = [1000.0] + monkeypatch.setattr("lib.mcp.server.time", N(monotonic=lambda: clock[0])) + s = make_server(cache_ttl=cfg["cache_ttl"]) + await s.call("get_a", {"portfolio_id": 1}) + clock[0] += 599 + await s.call("get_a", {"portfolio_id": 1}) + assert len(s.session.calls) == 1 # still inside the 10 minutes + clock[0] += 2 + await s.call("get_a", {"portfolio_id": 1}) + assert len(s.session.calls) == 2 # expired, fetched again + + async def test_no_cache_by_default_and_not_connected_message(): s = make_server() await s.call("get_a", {}) From 27d764e529ad027e0faf40c2c71295fea41a7d46 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 23:30:54 +0000 Subject: [PATCH 2/2] Sharesight cache: 30 minutes Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_014k4kywyN5dAo39izUPvxbw --- README.md | 4 ++-- mcp_servers.json | 2 +- tests/test_mcp.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ae4a58c..7837e31 100644 --- a/README.md +++ b/README.md @@ -187,8 +187,8 @@ Each answer's log line shows the cached percentage. points, Sharesight holdings flattened into tables, markdown tables (Yahoo) squeezed (padding and rule rows dropped, `1.20067e+11` shown as `120.067B`, NaN as `-`), results capped at 12,000 characters; an identical call within one request gets a short "same as earlier" note instead of a second copy; - `cache_ttl` shares results between users: 30 seconds for Yahoo, 10 minutes for Sharesight (so a portfolio - answer can be up to 10 minutes old). + `cache_ttl` shares results between users: 30 seconds for Yahoo, 30 minutes for Sharesight (so a portfolio + answer can be up to 30 minutes old). - **Compact history:** stored HTML is shown to the model as plain text (ticker links become the symbol, tags and Yahoo URLs dropped), lines cut to 240 characters and the bot's own to 160. - **Smaller prompts:** the system prompt is about half its previous size, the repeated instruction diff --git a/mcp_servers.json b/mcp_servers.json index dcd52db..6e5ddad 100644 --- a/mcp_servers.json +++ b/mcp_servers.json @@ -40,7 +40,7 @@ "slim": "sharesight", "gate": "portfolio", "max_concurrent": 1, - "cache_ttl": 600 + "cache_ttl": 1800 } } } diff --git a/tests/test_mcp.py b/tests/test_mcp.py index 5d60673..a2894b7 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -113,16 +113,16 @@ async def test_call_slims_and_caches_identical_concurrent_calls(): assert len(s.session.calls) == 2 -async def test_sharesight_results_are_cached_for_ten_minutes(monkeypatch): +async def test_sharesight_results_are_cached_for_thirty_minutes(monkeypatch): cfg = json.loads((Path(__file__).parent.parent / "mcp_servers.json").read_text())["mcpServers"]["sharesight"] - assert cfg["cache_ttl"] == 600 + assert cfg["cache_ttl"] == 1800 clock = [1000.0] monkeypatch.setattr("lib.mcp.server.time", N(monotonic=lambda: clock[0])) s = make_server(cache_ttl=cfg["cache_ttl"]) await s.call("get_a", {"portfolio_id": 1}) - clock[0] += 599 + clock[0] += 1799 await s.call("get_a", {"portfolio_id": 1}) - assert len(s.session.calls) == 1 # still inside the 10 minutes + assert len(s.session.calls) == 1 # still inside the 30 minutes clock[0] += 2 await s.call("get_a", {"portfolio_id": 1}) assert len(s.session.calls) == 2 # expired, fetched again