Skip to content

feat: add Anthropic LLM binding for API server + MCP server adapter#3028

Open
tonygil wants to merge 7 commits intoHKUDS:mainfrom
tonygil:pr/anthropic-binding-mcp-server
Open

feat: add Anthropic LLM binding for API server + MCP server adapter#3028
tonygil wants to merge 7 commits intoHKUDS:mainfrom
tonygil:pr/anthropic-binding-mcp-server

Conversation

@tonygil
Copy link
Copy Markdown

@tonygil tonygil commented May 7, 2026

Summary

This PR adds two features and a suite of architectural improvements developed
during a grilling session on the MCP server design.

New features

  • Anthropic as API server binding: Adds anthropic as a selectable
    LLM_BINDING option in the API server, wiring it through config.py and
    lightrag_server.py to the existing lightrag/llm/anthropic.py.
  • MCP server adapter (lightrag/mcp_server.py): A Model Context Protocol
    adapter exposing two tools to MCP-compatible clients (Claude Desktop, Cursor,
    etc.):
    • query — LLM-synthesised answer from the Knowledge Graph
    • retrieve — raw entities, relations, and chunks for diagnostic use
  • Atomic JSON writes for Windows (lightrag/utils.py): Fixes a Windows
    Defender file-locking issue on large JSON writes via temp file + atomic rename.

Architectural improvements

  • ConfigResolver (lightrag/query_config.py): QueryParam is now a pure
    value object with no os.getenv() calls at class definition time. All env-var
    reading is centralised in ConfigResolver; tests inject config via
    ConfigResolver(env={...}).query_param() without mutating os.environ.
  • resolve_workspace (lightrag/kg/shared_storage.py): The repeated
    workspace path resolution block (working_dir + makedirs) is extracted into
    one helper used by all 5 file-based storage backends (JsonKVStorage,
    JsonDocStatusStorage, NanoVectorDBStorage, NetworkXStorage,
    FaissVectorDBStorage).
  • QueryParam/QueryRequest parity test (tests/test_query_param_parity.py):
    CI fails with a clear message if a field is added to QueryParam but not to
    QueryRequest. Uses ast to read field names without triggering the API auth
    chain.
  • MCP server hardening: Mode/top_k hidden behind env vars; retrieve tool
    renamed from search; McpError raised on 5xx/transport failures; references
    formatted as [title](url).
  • Startup warm-up: GET /health on MCP server startup surfaces
    misconfiguration immediately rather than on the first user query.
  • ADR-0001: Records that the MCP server is intentionally a thin adapter and
    that query caching (if ever needed) belongs in the REST API layer, not here.
  • CONTEXT.md: Domain glossary with canonical terms (Knowledge Graph, Query,
    Retrieve, MCP Server, Retrieval Mode, QueryParam, ConfigResolver).

Test plan

  • Set LLM_BINDING=anthropic + LLM_MODEL=claude-sonnet-4-6 in .env,
    start server, confirm model responds
  • Run lightrag-mcp — confirm warm-up logs reachability of LightRAG server
  • Connect via Claude Desktop MCP config, confirm query and retrieve tools
    appear and return results
  • On Windows: insert a large document, confirm no file-locking errors
  • pytest tests/test_query_param_parity.py passes offline

🤖 Generated with Claude Code

Tony Gilpin and others added 7 commits May 7, 2026 07:47
- Add 'anthropic' as a supported LLM_BINDING option in config.py and lightrag_server.py
- Implement anthropic_model_complete wrapper using anthropic_complete_if_cache
- Fix write_json to use temp file + atomic rename to avoid Windows Defender locking large JSON files mid-write

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds lightrag-mcp entry point — a thin MCP adapter that wraps the
existing REST API as two tools (query, search) for use with Claude
Desktop, Cursor, and any MCP-compatible client.

Also changes the default query mode from 'mix' to 'local' for faster
response times when callers don't specify a mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hide mode/top_k behind LIGHTRAG_QUERY_MODE / LIGHTRAG_TOP_K env vars;
  retrieval tuning is an ops concern, not a caller concern
- Make HTTP timeout configurable via LIGHTRAG_MCP_TIMEOUT (default 120s)
- Rename `search` tool to `retrieve` to signal diagnostic intent
- Raise McpError on 5xx and transport failures; return string on 4xx
- Format references as [title](url), falling back to reference_id

Also adds CONTEXT.md with domain glossary (Knowledge Graph, Query,
Retrieve, MCP Server, Retrieval Mode).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
QueryParam is now a pure value object — field defaults are compile-time
constants, not os.getenv() calls. All env-based defaulting is centralised
in ConfigResolver (lightrag/query_config.py).

- lightrag/query_config.py: new module with QueryParam, ConfigResolver,
  default_query_param()
- lightrag/base.py: re-exports QueryParam for backwards compatibility;
  removes env-reading field defaults and unused imports
- CONTEXT.md: adds QueryParam and ConfigResolver glossary entries

Tests can now inject Query config via ConfigResolver(env={...}).query_param()
without mutating os.environ.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… backends

Extracts the repeated workspace-path block from 5 file-based storage
__post_init__ methods into resolve_workspace() in shared_storage.py.

Before (repeated identically in each backend):
  working_dir = self.global_config["working_dir"]
  if self.workspace:
      workspace_dir = os.path.join(working_dir, self.workspace)
  else:
      workspace_dir = working_dir
      self.workspace = ""
  os.makedirs(workspace_dir, exist_ok=True)

After (one call per backend):
  workspace_dir, self.workspace = resolve_workspace(
      self.global_config, self.workspace
  )

Backends updated: JsonKVStorage, JsonDocStatusStorage,
NanoVectorDBStorage, NetworkXStorage, FaissVectorDBStorage.
Remote backends (Mongo, Postgres, Redis, etc.) are unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…elds

Adding a field to QueryParam without adding it to QueryRequest is the
common failure mode when the two models drift. This test catches it at
CI time with a clear error message and documented exclusion list.

Uses ast to parse QueryRequest field names without importing the module,
avoiding the API auth chain that calls parse_args() in test context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ision

Warm-up (_warmup): on startup, GET /health to verify the LightRAG server
is reachable before accepting MCP connections. Emits a warning (not a
crash) so transient connectivity issues during rolling restarts don't
block startup. Surfaces LIGHTRAG_API_URL misconfiguration immediately
rather than on the first user query.

ADR-0001: records that the MCP Server is intentionally a thin adapter
and that query caching was considered and deferred (belongs in the REST
API where cache invalidation can be wired to ingestion events, not in
the MCP layer which has no visibility into Knowledge Graph changes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant