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
DatabaseInterfaceabstraction.
Installation & Setup¶
Prerequisites¶
- Python ≥3.12
- Neo4j or Memgraph database with a knowledge graph
.envfile with database credentials:
DATABASE_TYPE=neo4j # or "memgraph" or "falkordb"
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_password
Install¶
CLI Usage¶
Invocation¶
Global Flags¶
| Flag | Description |
|---|---|
--database |
Neo4j database name (default: from .env) |
--human |
Pretty-print tables instead of JSON |
Global flags go before the subcommand:
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:
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¶
- Single source of truth: One function, one registration, three interfaces. No drift.
- Testability: Plain functions with explicit
dbparameter — no framework coupling. - Zero overhead: MCP wrapper adds <0.001ms (closure is essentially free). CLI adds ~0.01ms from argparse.
- 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