Skip to main content
Glama
bdc-assist

Redis Graph MCP Server

by bdc-assist

DUG MCP Server

A Model Context Protocol (MCP) server for querying a biomedical knowledge graph stored in Redis (RedisGraph). Supports both stdio (Claude Desktop) and SSE (HTTP) transports.

Overview

This server exposes a biomedical knowledge graph as MCP tools and prompts, enabling LLMs and AI agents to:

  • Search for diseases, phenotypes, and other biomedical concepts by name

  • Enrich searches with synonyms using Name Resolution SRI and SAP-BERT

  • Discover study variables connected to a concept via semantic biolink relationships — not keyword matching

  • Identify studies feasible for multi-condition cohort analysis

  • Traverse concept relationships and find paths between entities

  • Execute TRAPI and raw Cypher queries for advanced use cases

Related MCP server: OMOPHub MCP Server

How Variable Discovery Works

The key design principle: the Knowledge Graph decides which variables are relevant.

Natural language query: "asthma"
            │
            ▼
  Step 1 — Synonym Enrichment
    Name Resolution SRI + SAP-BERT
    "asthma" → MONDO:0004979, MONDO:0004784,
               HP:0002099, UMLS:C0004096 ...
            │
            ▼
  Step 2 — KG Semantic Query
    MATCH (concept)-[biolink:related_to]-(variable:StudyVariable)
    WHERE concept.id IN [enriched CURIEs]
    → Only variables with a proven biolink relationship
      are returned. No keyword noise.
            │
            ▼
  Step 3 — Study Resolution
    Variable IDs → Study nodes via KG edges
    → Returns study names, IDs, and matched concepts

A variable only appears in results if the Knowledge Graph has established a semantic relationship between the concept and that variable via a biolink edge.

Architecture

User / Claude Desktop / API Client
            │
            ▼
    redis-graph-agent  (port 8080)
      - REST API for natural language queries
      - LLM reasoning via vLLM (tool-calling mode)
            │
            ▼
    redis-mcp-server  (port 8000)
      - MCP tools and prompts over SSE
      - Synonym enrichment: Name Resolution SRI + SAP-BERT
      - KG semantic variable and study discovery
            │
            ▼
      Redis (RedisGraph)
      Knowledge Graph (FalkorDB)

Using with Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "redis-graph": {
      "url": "http://localhost:8000/sse"
    }
  }
}

Restart Claude Desktop after updating the config.


Using the Agent API

Via Swagger UI

Navigate to /docs on the running agent service.

Via curl

curl -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -d '{"query": "find study variables related to asthma"}'

Request body

Field

Type

Default

Description

query

string

required

Natural language question

max_results

int

20

Max results per tool call

system_prompt

string

built-in

Override the system prompt

Response

{
  "answer": "Found 20 study variables related to asthma...",
  "tools_used": ["search_concepts"],
  "tool_results": [...]
}

Available Tools

All tools return JSON. Below is each tool, what it does, and a concrete example.


search_concepts

Search for biomedical concepts by name, or find study variables related to a concept with automatic synonym enrichment.

When find_variables=true, the term is expanded via Name Resolution SRI and SAP-BERT (up to 10 results each). The combined CURIEs and labels are used to search the graph for connected StudyVariable nodes. Results are deduplicated by variable — each variable appears once with a matched_concepts array showing which concepts matched and via which predicate. The limit applies to unique variables, not raw rows. If either enrichment service is unavailable, a warnings field is included in the response so partial results are never silent.

Find concepts by name:

{ "search_term": "asthma" }

Filter by node type:

{ "search_term": "asthma", "node_type": "Disease" }

Find variables with synonym enrichment:

{ "search_term": "asthma", "find_variables": true, "limit": 20 }

Example response shape for find_variables=true:

{
  "search_term": "asthma",
  "enrichment": { "curies": ["MONDO:0004979", "..."], "labels": ["asthma", "..."] },
  "total_results": 20,
  "variables": [
    {
      "variable_id": "phv00425822.v1.p1",
      "variable_name": "p_asth",
      "variable_description": "lung, asthma/wheezing/reactive airway",
      "matched_concepts": [
        { "concept_id": "MONDO:0004979", "concept_name": "asthma", "concept_type": "biolink:Disease", "predicate": "biolink:related_to" },
        { "concept_id": "MONDO:0004784", "concept_name": "allergic asthma", "concept_type": "biolink:Disease", "predicate": "biolink:related_to" }
      ]
    }
  ]
}

get_concept_graph

Get the subgraph around a concept. Also works when the starting node is a variable (phv… or phs…_…) — in that case the query is flipped to return the concepts and study the variable belongs to.

  • Depth 1 — returns all directly connected nodes of any type

  • Depth 2 — traverses concept → StudyVariable → Study, with a count of how many other concepts each variable links to

  • Variable as input — returns concepts linked to the variable and its parent study

Direct neighbors:

{ "concept_id": "MONDO:0004979", "expand_depth": 1 }

Variables and studies:

{ "concept_id": "MONDO:0004979", "expand_depth": 2, "limit": 50 }

Starting from a variable:

{ "concept_id": "phv00425822.v1.p1", "expand_depth": 2 }

get_concept_connections

List every entity directly connected to a node — relationship direction (in/out), relationship type (in biolink: notation), node type, name, and ID. Also returns the concept name and a type-count summary. Works with both concept CURIEs and variable IDs. Optionally filter by node type.

All connections:

{ "concept_id": "MONDO:0004979" }

Only connected studies:

{ "concept_id": "MONDO:0004979", "node_type_filter": "Study" }

Only connected variables:

{ "concept_id": "MONDO:0004979", "node_type_filter": "StudyVariable" }

Inspect a variable's connections:

{ "concept_id": "phv00430345.v1.p1" }

search_variables_by_name

Search for StudyVariable nodes by name fragment or by partial ID. Unlike search_concepts, this targets only variables and supports ID prefix matching.

By name fragment:

{ "search_term": "bmi" }

By partial phv ID:

{ "search_term": "phv00430" }

find_highly_connected_variables

Find StudyVariable nodes with the most connections to biomedical concepts — useful for discovering the most broadly relevant variables across disease areas.

{ "min_connections": 5, "limit": 20 }

expand_concept

Traverse the concept graph N hops from a starting node, returning related concepts with hop distance and path relationship types. Optionally filter by relationship type.

All related concepts within 2 hops:

{ "concept_id": "MONDO:0004979", "max_hops": 2 }

Filter by relationship type:

{ "concept_id": "MONDO:0004979", "max_hops": 2, "relationship_types": ["related_to"] }

find_concept_paths

Find the shortest path(s) between two biomedical concepts. The path is tried in both directions (forward then reverse) since FalkorDB only supports directed shortestPath.

{
  "source_id": "MONDO:0004979",
  "target_id": "CHEBI:28534",
  "max_path_length": 3
}

Returns node_ids, node_names, node_types, and relationship_types for each hop along the path. Example result:

{
  "total_paths": 1,
  "paths": [
    {
      "path_length": 2,
      "node_ids":   ["MONDO:0004979", "NCBIGene:2944", "CHEBI:28534"],
      "node_names": ["asthma", "HSP90AA1", "homogentisic acid"],
      "node_types": ["biolink.NamedThing", "biolink.NamedThing", "biolink.NamedThing"],
      "relationship_types": ["biolink.related_to", "biolink.related_to"]
    }
  ]
}

---

### `list_graph_schema`

List all node types in the graph with counts. Recommended as a first step for any LLM to understand what data is available.

```json
{ "show_counts": true }

trapi_query

Query the knowledge graph using a standard TRAPI (Translator Reasoner API) query graph. Automatically handles the biolink predicate hierarchy — querying a parent predicate like biolink:related_to also matches all child predicates. Returns clean JSON with category, id, and name fields for each node.

Disease → StudyVariable (by CURIE):

{
  "qgraph": {
    "nodes": {
      "disease": {"ids": ["MONDO:0004979"], "categories": ["biolink:Disease"]},
      "variable": {"categories": ["biolink:StudyVariable"]}
    },
    "edges": {
      "e0": {"subject": "disease", "object": "variable"}
    }
  },
  "limit": 10
}

PhenotypicFeature → StudyVariable:

{
  "qgraph": {
    "nodes": {
      "phenotype": {"categories": ["biolink:PhenotypicFeature"]},
      "variable": {"categories": ["biolink:StudyVariable"]}
    },
    "edges": {
      "e0": {"subject": "phenotype", "object": "variable"}
    }
  }
}

The cypher_used field in the response shows the generated Cypher for transparency and debugging.


find_variables

Find study variables semantically linked to a biomedical concept using the knowledge graph. Automatically enriches the keyword with synonyms and related CURIEs via Name Resolution SRI + SAP-BERT, then queries the KG to return only variables with a proven biolink relationship to the concept.

Use this when you have a keyword and want to discover which study variables relate to it. Unlike search_variables_by_name (which matches on variable name text), this tool understands medical synonyms — searching "heart attack" also finds variables linked to "myocardial infarction", "MI", "STEMI", etc.

By keyword (semantic enrichment, default):

{ "keyword": "asthma", "semantic": true, "limit": 20 }

By phv IDs (look up specific variables in the KG):

{ "phv_ids": ["phv00425822", "phv00347788"], "limit": 20 }

By keyword, literal match only:

{ "keyword": "asthma", "semantic": false, "limit": 10 }

Recommended chain for single-concept variable discovery:

find_variables(keyword) → review variables → use variable IDs with get_concept_connections or find_cohort_variables

find_cohort_variables

Find study variables for multiple biomedical concepts simultaneously and identify which studies contain variables for all of them — the core tool for multi-condition cohort feasibility analysis.

For each concept, synonym enrichment finds matching variables in the KG. Variables are then resolved to studies directly via the Knowledge Graph (no PIC-SURE dependency). Studies are grouped by which concepts they cover: feasible_studies have variables for all concepts; partial_studies are missing at least one.

Each variable's matched_concepts entry carries both the concept name and the top enriched CURIEs used to find it.

Asthma AND obesity cohort:

{ "concepts": ["asthma", "obesity"], "limit": 10 }

Three-condition query:

{ "concepts": ["asthma", "obesity", "hypertension"], "variables_per_concept": 30 }

Example response shape:

{
  "concepts_searched": ["asthma", "COPD"],
  "enrichment_summary": [
    { "concept": "asthma", "curies_found": 12, "variables_in_kg": 20 },
    { "concept": "COPD",   "curies_found": 8,  "variables_in_kg": 15 }
  ],
  "feasible_studies_count": 2,
  "feasible_studies": [
    {
      "study_id":        "phs000007.v31.p12",
      "study_name":      "Framingham Cohort",
      "concepts_found":  ["asthma", "COPD"],
      "concepts_missing": [],
      "variables": [
        {
          "variable_id":   "phv00009088.v9.p15",
          "variable_name": "D360",
          "study_id":      "phs000007.v31.p12",
          "matched_concepts": [
            {
              "concept": "asthma",
              "curies":  ["MONDO:0004979", "MONDO:0004784", "MONDO:0001491"]
            }
          ]
        }
      ]
    }
  ],
  "partial_studies": [...],
  "_sources": [
    { "title": "Framingham Cohort", "link": "https://www.ncbi.nlm.nih.gov/projects/gap/cgi-bin/study.cgi?study_id=phs000007", "type": "dbgap-study" }
  ]
}

Recommended chain for multi-condition cohort building:

find_cohort_variables(concepts) → review feasible_studies → use variable IDs with get_concept_connections or find_variables

cypher_query

Execute a raw Cypher query directly against RedisGraph. Use backticks for biolink labels containing dots.

Count all diseases:

MATCH (n:`biolink.Disease`) RETURN COUNT(n)

Find concepts connected to a variable:

MATCH (v:`biolink.StudyVariable` {id: "phv00430345.v1.p1"})--(c)
RETURN labels(c)[0] AS type, c.name AS name, c.id AS id
LIMIT 20

Provenance — _sources

Every tool that touches study data appends a _sources array to its response. Each entry is a dbGaP study link:

"_sources": [
  {
    "title": "Framingham Cohort",
    "link":  "https://www.ncbi.nlm.nih.gov/projects/gap/cgi-bin/study.cgi?study_id=phs000007",
    "type":  "dbgap-study"
  }
]

This makes provenance machine-readable and uniform across all tools — downstream agents or UIs can aggregate _sources from multiple tool calls to show a consolidated list of studies that contributed to an answer, without needing to parse each tool's specific response structure.

Tools that emit _sources: search_concepts, get_concept_graph, find_cohort_variables.


Available Prompts

When connected via Claude Desktop or another MCP client, these prompts appear as guided workflows:

Prompt

Arguments

Description

find_variables_for_concept

concept

Synonym-enriched search for study variables

explore_concept

concept_id

Full exploration: connections, studies, subgraph

find_studies_for_disease

disease_name

End-to-end: disease name → matching studies

explain_variable

variable_id

Plain-language explanation of what a variable measures

find_path_between_concepts

concept_a_id, concept_b_id

Relationship path between two concepts


Local Development

Prerequisites

  • Python 3.12+

  • Redis with RedisGraph module running locally

Installation

pip install -r requirements.txt

Run MCP server (stdio mode)

REDIS_HOST=localhost \
REDIS_PORT=6379 \
REDIS_PASSWORD=<password> \
REDIS_GRAPH_NAME=<graph_name> \
  python3 redismcp_server.py

Run MCP server (SSE mode)

REDIS_HOST=localhost \
REDIS_PORT=6379 \
REDIS_PASSWORD=<password> \
REDIS_GRAPH_NAME=<graph_name> \
  python3 redismcp_server.py --transport sse --port 8000

Run agent

MCP_SERVER_URL=http://localhost:8000/sse \
VLLM_URL=<your_vllm_endpoint>/v1 \
MODEL=<model_name> \
  uvicorn agent_api:app --host 0.0.0.0 --port 8080

Kubernetes Deployment

# Deploy all services
kubectl apply -f k8s/mcp-server.yaml
kubectl apply -f k8s/agent.yaml
kubectl apply -f k8s/ingress.yaml

# Restart pods to pull a new image
kubectl rollout restart deployment/redis-mcp-server deployment/redis-graph-agent -n <namespace>

# Check pod status
kubectl get pods -n <namespace> -l 'app in (redis-mcp-server,redis-graph-agent)'

Configuration

MCP Server

Variable

Description

REDIS_HOST

Redis hostname

REDIS_PORT

Redis port

REDIS_PASSWORD

Redis auth password

REDIS_GRAPH_NAME

RedisGraph graph name

Agent

Variable

Description

MCP_SERVER_URL

SSE endpoint of the MCP server (e.g. http://redis-mcp-server:8000/sse)

VLLM_URL

vLLM OpenAI-compatible endpoint

MODEL

LLM model name served by vLLM

MAX_TOOL_TURNS

Max tool call iterations per query (default: 5)

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Provides AI agents with instant access to 10M+ OMOP medical vocabulary concepts for searching, mapping, and navigating clinical codes across SNOMED, ICD-10, RxNorm, LOINC, and more.
    11
    35 npm
    6
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables LLMs and AI agents to query a biomedical knowledge graph stored in RedisGraph, with tools for concept search, synonym enrichment, and study variable discovery through semantic relationships.
    -
  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables semantic search and exploration of a business glossary knowledge graph, allowing users to query terms, expand related concepts, trace dependencies, and resolve physical table mappings.
    -