Skip to content

KG Tools: Usage Guide & Tool Reference

Unified knowledge-graph query tools exposed through CLI, MCP, and LangChain agent interfaces — all backed by a single tool registry.

Backend support: All tools work with both Neo4j and Memgraph via the DatabaseInterface abstraction.


Installation & Setup

Prerequisites

  • Python ≥3.12
  • Neo4j or Memgraph database with a knowledge graph
  • .env file with database credentials:
DATABASE_TYPE=neo4j  # or "memgraph" or "falkordb"
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_password

Install

pip install uv
uv sync

CLI Usage

Invocation

uv run python -m src.kg_tools.cli <subcommand> [flags]

Global Flags

Flag Description
--database Neo4j database name (default: from .env)
--human Pretty-print tables instead of JSON

Global flags go before the subcommand:

uv run python -m src.kg_tools.cli --human --database olink1 get_top_biomarkers --disease cancer

Output

  • Default: JSON to stdout, errors to stderr.
  • --human: Aligned tables for scalar values and list-of-dict results.

Subcommands

Every registered tool is a subcommand. Run with --help for per-tool flags:

uv run python -m src.kg_tools.cli get_top_biomarkers --help

Examples

# Top biomarkers for a disease
uv run python -m src.kg_tools.cli get_top_biomarkers --disease "cardiovascular disease" --limit 5

# Fuzzy entity search
uv run python -m src.kg_tools.cli search_entities --query TP53 --entity_type protein

# Shared diseases between proteins
uv run python -m src.kg_tools.cli get_shared_diseases --proteins TP53 BRCA1

# Raw Cypher (read-only)
uv run python -m src.kg_tools.cli run_cypher_query --query "MATCH (p:Protein) RETURN p.name LIMIT 5"

# Human-readable output
uv run python -m src.kg_tools.cli --human get_protein_interactions --protein TP53

# Graph statistics (no flags needed)
uv run python -m src.kg_tools.cli get_graph_statistics

MCP Interface

The MCP adapter exposes the same tools to LLM clients via FastMCP.

from fastmcp import FastMCP
from src.kg_tools.registry import ToolRegistry
from src.kg_tools.tools import register_all
from src.kg_tools.mcp_adapter import register_tools

mcp = FastMCP("olink-kg")
registry = ToolRegistry()
register_all(registry)
register_tools(mcp, registry, db)  # db bound into every tool

Each tool's db parameter is hidden from MCP clients — JSON schemas are auto-derived from the remaining type annotations.


LangChain Agent Interface

Load tools as LangChain StructuredTool instances for use with create_react_agent or direct .invoke():

from src.kg_tools.registry import ToolRegistry
from src.kg_tools.tools import register_all
from src.kg_tools.agent_adapter import get_agent_tools

registry = ToolRegistry()
register_all(registry)

# All 16 tools
tools = get_agent_tools(registry, db)

# Filtered by group
tools = get_agent_tools(registry, db, groups=["biomarker", "evidence"])

# Explicit tool names
tools = get_agent_tools(registry, db, tool_names=["search_entities", "get_protein_details"])

Tool Groups

Group Tools
biomarker get_top_biomarkers, get_disease_proteins, get_evidence_for_association, search_entities
protein get_protein_details, get_protein_interactions, get_protein_pathways, get_shared_diseases, search_entities
disease get_disease_hierarchy, get_disease_proteins, get_shared_proteins, search_entities
pathway get_protein_pathways, get_pathway_members, search_entities
evidence get_evidence_for_association, get_relationship_evidence_depth, search_entities
exploration search_entities, get_entity_disambiguation, get_graph_statistics, get_community_summary, run_cypher_query

Groups are union-merged when multiple are specified. Combine with tool_names for fine-grained control.


Tool Reference

All tools return JSON-serializable dicts. On error, the dict includes an "error" key.


get_top_biomarkers

Get top protein biomarkers associated with a disease, ranked by confidence.

Parameter Type Default Description
disease str required Disease name (e.g., "cardiovascular disease")
limit int 10 Max biomarkers to return
min_confidence float 0.7 Minimum confidence score (0.0–1.0)

Output schema:

{
  "disease": "cardiovascular disease",
  "biomarkers": [
    {
      "protein": "CRP",
      "uniprot_id": "P02741",
      "confidence": 0.95,
      "evidence_count": 23,
      "pmids": ["12345678", "23456789"]
    }
  ],
  "total_found": 1
}


get_disease_proteins

Get all proteins associated with a disease, optionally filtered by relationship type.

Parameter Type Default Description
disease str required Disease name or MONDO ID
relationship_type str \| None None Filter by relationship (e.g., "ASSOCIATES_WITH")
limit int 20 Max proteins to return

Output schema:

{
  "disease": "diabetes mellitus",
  "mondo_id": "MONDO:0005015",
  "proteins": [
    {"name": "INS", "uniprot_id": "P01308", "relationship": "ASSOCIATES_WITH"}
  ],
  "total_found": 1
}


get_protein_pathways

Get biological pathways, GO terms, and subcellular locations for a protein. Optionally includes pathways from interacting proteins.

Parameter Type Default Description
protein str required Protein name, gene symbol, or UniProt ID
include_interactors bool False Include pathways from PPI partners
limit int 20 Max interactor pathways to return

Output schema:

{
  "protein": "TP53",
  "uniprot_id": "P04637",
  "pathways": ["p53 signaling pathway"],
  "go_terms": [{"id": "GO:0006915", "name": "apoptotic process", "category": "biological_process"}],
  "locations": ["Nucleus"],
  "interactor_pathways": [
    {"interactor": "MDM2", "uniprot_id": "Q00987", "pathways": ["p53 signaling pathway"]}
  ]
}

interactor_pathways is only present when include_interactors=True.


get_pathway_members

Get all proteins participating in a biological pathway.

Parameter Type Default Description
pathway str required Pathway name (substring match)
limit int 50 Max proteins to return

Output schema:

{
  "pathway": "p53 signaling pathway",
  "proteins": [
    {"name": "TP53", "uniprot_id": "P04637"}
  ],
  "total_found": 1
}


get_protein_interactions

Get protein-protein interactions for a given protein.

Parameter Type Default Description
protein str required Protein name, gene symbol, or UniProt ID
limit int 20 Max interactions to return

Output schema:

{
  "protein": "TP53",
  "uniprot_id": "P04637",
  "interactions": [
    {
      "interactor": "MDM2",
      "uniprot_id": "Q00987",
      "gene_symbol": "MDM2",
      "confidence": 0.95,
      "evidence_count": 12,
      "interaction_type": "INTERACTS_WITH"
    }
  ],
  "total_found": 1
}


get_protein_details

Get all node properties for a protein.

Parameter Type Default Description
protein str required Protein name, gene symbol, or UniProt ID

Output schema:

{
  "protein": "TP53",
  "found": true,
  "properties": {
    "name": "TP53",
    "uniprot_id": "P04637",
    "gene_symbol": "TP53",
    "synonyms": ["p53", "tumor protein p53"]
  }
}

Returns all properties stored on the node via Cypher properties(p).


search_entities

Fuzzy search across Protein, Disease, and Pathway nodes. Matches against name, synonyms, gene_symbol, uniprot_id, and mondo_id with ranked scoring.

Parameter Type Default Description
query str required Search string (case-insensitive)
entity_type str \| None None Filter: "protein", "disease", or "pathway"
limit int 20 Max results

Scoring tiers: exact name = 1.0, ID match = 0.95, prefix = 0.8, substring = 0.6, synonym-only = 0.4.

Output schema:

{
  "query": "TP53",
  "results": [
    {"name": "TP53", "type": "protein", "id": "P04637", "gene_symbol": "TP53", "score": 1.0}
  ],
  "total_found": 1
}


get_disease_hierarchy

Get parent and child diseases from the MONDO ontology IS_A hierarchy.

Parameter Type Default Description
disease str required Disease name, MONDO ID, or synonym

Output schema:

{
  "disease": "diabetes mellitus",
  "mondo_id": "MONDO:0005015",
  "found": true,
  "parents": [{"name": "endocrine system disease", "mondo_id": "MONDO:0005151"}],
  "children": [{"name": "type 1 diabetes", "mondo_id": "MONDO:0005147"}]
}


get_community_summary

Get the LLM-generated summary and key entities for a Louvain community cluster.

Parameter Type Default Description
community_id int required Community ID from Louvain detection

Output schema:

{
  "community_id": 5,
  "found": true,
  "summary": "This community centers on inflammatory cytokines...",
  "member_count": 42,
  "key_entities": [
    {"name": "IL6", "labels": ["Protein"]}
  ]
}

Returns up to 20 key entities.


get_evidence_for_association

Get PMIDs, confidence scores, and abstract excerpts for a protein-disease association.

Parameter Type Default Description
protein str required Protein name, gene symbol, or UniProt ID
disease str required Disease name or MONDO ID

Output schema:

{
  "protein": "CRP",
  "disease": "cardiovascular disease",
  "associations": [
    {
      "protein": "CRP", "uniprot_id": "P02741",
      "disease": "cardiovascular disease", "mondo_id": "MONDO:0004995",
      "relationship": "ASSOCIATES_WITH",
      "pmids": ["12345678"],
      "avg_confidence": 0.92, "min_confidence": 0.85, "max_confidence": 0.98,
      "confidence_scores": [0.85, 0.92, 0.98],
      "excerpts": ["CRP levels were significantly elevated..."],
      "evidence_count": 3
    }
  ],
  "total_found": 1
}


get_graph_statistics

Get node counts, relationship counts, and degree distribution. No parameters.

Output schema:

{
  "total_nodes": 15000,
  "total_relationships": 45000,
  "node_counts_by_label": {"Protein": 5000, "Disease": 3000, "Pathway": 200},
  "relationship_counts_by_type": {"ASSOCIATES_WITH": 30000, "INTERACTS_WITH": 10000},
  "degree_distribution": {"min": 1, "max": 342, "mean": 6.0, "median": 3}
}


get_shared_diseases

Find diseases shared between two or more proteins (comparative analysis).

Parameter Type Default Description
proteins list[str] required ≥2 protein identifiers (name, gene_symbol, or uniprot_id)
limit int 50 Max diseases to return

CLI usage: --proteins TP53 BRCA1 MDM2

Output schema:

{
  "proteins": ["TP53", "BRCA1"],
  "shared_diseases": [
    {"disease": "breast cancer", "mondo_id": "MONDO:0007254", "associated_proteins": ["TP53", "BRCA1"], "protein_count": 2}
  ],
  "total_found": 1
}


get_shared_proteins

Find proteins shared between two or more diseases.

Parameter Type Default Description
diseases list[str] required ≥2 disease identifiers (name or MONDO ID)
limit int 50 Max proteins to return

CLI usage: --diseases "breast cancer" "ovarian cancer"

Output schema:

{
  "diseases": ["breast cancer", "ovarian cancer"],
  "shared_proteins": [
    {"protein": "BRCA1", "uniprot_id": "P38398", "gene_symbol": "BRCA1", "associated_diseases": ["breast cancer", "ovarian cancer"], "disease_count": 2}
  ],
  "total_found": 1
}


get_entity_disambiguation

Return ranked candidate matches for an ambiguous entity name. Similar to search_entities but includes synonyms in output to explain why candidates matched.

Parameter Type Default Description
name str required Ambiguous entity name
limit int 10 Max candidates

Output schema:

{
  "query": "IL6",
  "candidates": [
    {"name": "IL6", "type": "protein", "id": "P05231", "gene_symbol": "IL6", "synonyms": ["interleukin-6", "BSF-2"], "match_score": 1.0}
  ],
  "total_candidates": 1
}


get_relationship_evidence_depth

Full evidence chain for a relationship: PMIDs, extraction methods, confidence scores, and temporal data. Lookup by protein+disease pair or by Neo4j relationship element ID.

Parameter Type Default Description
protein str "" Protein identifier (used with disease)
disease str "" Disease identifier (used with protein)
relationship_id str "" Neo4j element ID (alternative lookup)

Provide either relationship_id or both protein and disease.

Output schema:

{
  "relationships": [
    {
      "protein": "CRP", "uniprot_id": "P02741", "gene_symbol": "CRP",
      "disease": "cardiovascular disease", "mondo_id": "MONDO:0004995",
      "relationship": "ASSOCIATES_WITH", "relationship_id": "5:abc:123",
      "pmids": ["12345678"], "extraction_methods": ["llm_extraction"],
      "confidence_scores": [0.92], "avg_confidence": 0.92,
      "min_confidence": 0.92, "max_confidence": 0.92,
      "first_seen": "2024-01-15", "last_seen": "2025-03-01",
      "excerpts": ["..."], "evidence_count": 1
    }
  ],
  "total_found": 1
}


run_cypher_query

Execute an arbitrary read-only Cypher query. Write operations (CREATE, MERGE, DELETE, SET, REMOVE, DROP) and write-capable CALL procedures are rejected. Queries have a 30-second timeout.

Parameter Type Default Description
query str required Cypher query string (read-only)

Output schema:

{
  "query": "MATCH (p:Protein) RETURN p.name LIMIT 3",
  "results": [{"p.name": "TP53"}, {"p.name": "BRCA1"}, {"p.name": "CRP"}],
  "count": 3
}


Architecture

Registry Pattern

All 16 tools are plain Python functions with db as the first parameter. They are registered in a central ToolRegistry via ToolDefinition frozen dataclasses:

ToolDefinition(name, function, description, params)
    ToolRegistry
    ┌──────────┐
    │ register()     │
    │ get_tool()     │
    │ get_all_tools()│
    └──────┬───────┘
     ┌─────┼──────┐
     ▼     ▼      ▼
    CLI   MCP   Agent

The registry is the single source of truth. Adding a new tool means: 1. Write a plain function in src/kg_tools/tools/ 2. Register it in src/kg_tools/tools/__init__.py

Both interfaces pick it up automatically.

Dual-Interface Design

The same function is exposed through three interfaces with zero code duplication:

CLI (src/kg_tools/cli.py): - Reads ToolRegistry, creates an argparse subcommand per tool - Derives flags from tool.params and inspect.signature (defaults, types) - list[str] params get nargs="+" for multi-value input - _DbAdapter bridges the database's _execute_cypher to the execute_query interface tools expect - Output: JSON to stdout (default) or human-readable tables (--human)

MCP (src/kg_tools/mcp_adapter.py): - _make_wrapper(fn, db) creates a closure that pre-binds db and overrides __signature__ to hide it - FastMCP auto-derives JSON schemas from the remaining type annotations - functools.partial is deliberately avoided — it breaks pydantic schema introspection

LangChain Agent (src/kg_tools/agent_adapter.py): - Same closure + __signature__ override pattern as MCP - Wraps output as JSON string (matching GraphTools.get_tools() contract) - StructuredTool.from_function() derives pydantic args schema from the wrapper signature - Tool groups enable loading relevant subsets per conversation

Why This Design

  1. Single source of truth: One function, one registration, three interfaces. No drift.
  2. Testability: Plain functions with explicit db parameter — no framework coupling.
  3. Zero overhead: MCP wrapper adds <0.001ms (closure is essentially free). CLI adds ~0.01ms from argparse.
  4. Token efficiency: All 16 tool definitions fit in 713 tokens — no need for dynamic tool subsetting.

File Structure

src/kg_tools/
├── __init__.py
├── registry.py          # ToolDefinition + ToolRegistry
├── cli.py               # argparse CLI entrypoint
├── mcp_adapter.py       # FastMCP adapter
├── agent_adapter.py     # LangChain StructuredTool adapter
├── formatter.py         # Human-readable table output
└── tools/
    ├── __init__.py      # register_all() — central registration
    ├── biomarkers.py    # get_top_biomarkers, get_disease_proteins
    ├── pathways.py      # get_protein_pathways, get_pathway_members
    ├── search.py        # search_entities
    ├── interactions.py  # get_protein_interactions
    ├── proteins.py      # get_protein_details
    ├── diseases.py      # get_disease_hierarchy
    ├── communities.py   # get_community_summary
    ├── evidence.py      # get_evidence_for_association
    ├── evidence_depth.py # get_relationship_evidence_depth
    ├── statistics.py    # get_graph_statistics
    ├── shared.py        # get_shared_diseases, get_shared_proteins
    ├── disambiguation.py # get_entity_disambiguation
    └── cypher.py        # run_cypher_query