Skip to content

fix(serve): bound multi-project graph contexts - #2269

Open
Kkartik14 wants to merge 1 commit into
Graphify-Labs:v8from
Kkartik14:fix/2268-bound-mcp-context-cache
Open

fix(serve): bound multi-project graph contexts#2269
Kkartik14 wants to merge 1 commit into
Graphify-Labs:v8from
Kkartik14:fix/2268-bound-mcp-context-cache

Conversation

@Kkartik14

@Kkartik14 Kkartik14 commented Jul 28, 2026

Copy link
Copy Markdown

Closes #2268

Summary

  • Bound non-default MCP project graph contexts with a locked LRU cache (default: 8).
  • Pin and warm the configured default graph outside the project limit.
  • Preserve client graph failures as tool errors rather than process exits.
  • Resolve paths consistently for cache, sidecars, and reports.
  • Document GRAPHIFY_MAX_CONTEXTS and add cache/LRU/corrupt-graph regression coverage.

Testing

  • /private/tmp/graphify-memory-audit/bin/pytest -q tests/test_serve_http.py — 27 passed
  • python -m compileall -q graphify/serve.py
  • git diff --check

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds a bounded LRU cache for graph contexts in the MCP server (graphify/serve.py). It introduces a _GraphContextCache class and a _max_server_contexts() helper driven by a new GRAPHIFY_MAX_CONTEXTS environment variable (default 8, minimum 1), replacing the previous unbounded per-graph context dict while keeping the server's configured default graph pinned separately from the project-graph LRU. Supporting changes include moving os/threading imports to module scope, resolving graph paths consistently via Path.resolve(), a new README table entry documenting the env var, and test additions in tests/test_serve_http.py covering env-var parsing and LRU/pinning behavior (including a parametrized helper to create multiple named projects). The surface area touches the server build/load path, the context caching mechanism, documentation, and HTTP serve tests.

No blocking issues surfaced. 7 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

graphify review

Impact — 415 function(s) in the blast radius of 162 changed node(s).

Health — regressions introduced by this change:

  • worsened (Ca·Ce 34→38): _build_http_app() (Ca=19 Ce=2) — 19 callers depend on it (afferent coupling)
  • worsened (Ca·Ce 28→32): _build_server() (Ca=2 Ce=16) — fans out to 16 callees (efferent coupling)
  • new offender: test_corrupt_project_graph_is_a_tool_error_without_killing_server() (Ca=0 Ce=7) — fans out to 7 callees (efferent coupling)
  • new offender: test_project_context_cache_is_lru_and_pins_default_graph() (Ca=0 Ce=7) — fans out to 7 callees (efferent coupling)

Verification — 415 function(s) need re-proving (callee-first):
graphify_serve_trigrams → tests_test_serve_test_trigrams_basic → graphify_serve_strip_diacritics → graphify_serve_search_tokens → graphify_serve_node_search_text → graphify_serve_get_trigram_index → tests_test_serve_test_trigram_index_cached_and_rebuilt_per_graph → graphify_serve_trigram_candidates → tests_test_serve_test_trigram_candidates_fast_path_fires_for_rare_term → tests_test_serve_test_trigram_candidates_falls_back_on_short_token …

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not enforced this run (re-run with --prove to verify the blast radius)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 285 function(s) in blast radius — re-run with --prove to formally verify them

· 2 grounded finding(s) anchored inline below; 2 more finding(s) on lines outside this diff (see the check run).

Comment thread tests/test_serve_http.py
assert serve_mod._max_server_contexts() == expected


def test_project_context_cache_is_lru_and_pins_default_graph(tmp_path, monkeypatch):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_project_context_cache_is_lru_and_pins_default_graph()

fans out to 7 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_serve_http.py
assert "Nodes: 2" in _call_tool(client, headers, "graph_stats", {}, rid=3)


def test_corrupt_project_graph_is_a_tool_error_without_killing_server(tmp_path):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_corrupt_project_graph_is_a_tool_error_without_killing_server()

fans out to 7 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix unbounded multi-project MCP graph-context cache

1 participant