Skip to main content
Glama
sbl-sdsc

MCP GeneLab Server

by sbl-sdsc

query

Read-onlyIdempotent

Run custom Cypher against the NASA GeneLab Knowledge Graph for schema exploration, multi-hop traversals, exotic aggregations, or one-off counts that specialist tools don't expose.

Instructions

FALLBACK Cypher executor. Use this ONLY when no specialist tool covers the question.

DO NOT call this tool when the question matches one of these patterns — call the named tool instead, EVEN IF you think Cypher would be more flexible:

  • "up/down-regulated genes", "DEGs", "differential expression", "log2fc rankings", "top N up/downregulated genes for assay X" → find_differentially_expressed_genes(assay_id=...)

  • "hyper/hypo-methylated regions", "DMRs", "methylation_diff", "hypermethylated promoter regions", "all DMRs passing q<0.05", pooling methylation across replicate assays → find_differentially_methylated_regions(assay_id=...)

  • "differentially abundant organisms", DESeq2/ANCOM-BC abundance, "increased/decreased abundance for assay X" → find_differentially_abundant_organisms(assay_id=...)

  • study metadata, what assays a study has, study factors/materials, project title, description, host organism/strain → get_study_info(study_id=...)

  • factor-pair → assay-id resolution (e.g. "give me the assay for Space Flight,Carcass vs Ground Control,Carcass in OSD-48") → select_assays(study_id=..., selection=...)

  • "what groups / conditions / control and experimental (treatment) groups are in study X", "what comparisons does OSD-48 have", "which factors were compared" — any question about the groups a study contains, even with no factor pair named → select_assays(study_id=...) (list mode; omit selection)

  • common DEGs/DMRs/DA organisms across multiple assays, intersections → find_common_differentially_expressed_genes(assay_ids=[...]) → find_common_differentially_methylated_regions(assay_ids=[...]) → find_common_differentially_abundant_organisms(assay_ids=[...])

  • DE genes overlapping DM regions, expression-methylation coupling, classical epigenetic silencing analysis → find_common_de_genes_overlapping_dm_regions(...)

  • listing nodes / properties / relationships in the KG → get_neo4j_schema(), get_node_metadata(), get_relationship_metadata()

If you only have a study identifier and need assay IDs, call select_assays or get_study_info FIRST; do not write Cypher to discover assay IDs.

The specialist tools return formatted markdown tables AND an inline CSV side-channel that this query tool does not produce. Falling back to query for the categories above also loses the parallel multi-query execution, the method-aware significance filtering (DESeq2 adj_p_value vs. ANCOM-BC q_value), the region-vs-gene aggregation, and the MethylationRegion location filter plumbing the specialists already implement correctly.

Only call this tool for ad-hoc Cypher that the specialist tools cannot express: schema exploration, custom multi-hop traversals, exotic aggregations, or one-off counts the specialists don't expose.

OUTPUT FORMAT - CRITICAL: The response begins with a total_rows: N header followed by rows: and then the JSON array of records. When reporting counts to the user (e.g. "how many hypermethylated regions are there"), ALWAYS use total_rows, NEVER count rows visible in the JSON array. Large results may be truncated by the MCP transport and stored to a side-file, leaving only a partial preview of the array — but the total_rows count is computed server-side from the materialized result before any truncation and is always accurate. For aggregate queries (RETURN count(*)) total_rows will be 1 and the count itself lives in the row's count(*) field.

EDGE PROPERTIES - CRITICAL: Many relationships in this knowledge graph have properties stored as edge attributes (data ON the relationship itself).

MEASURED_DIFFERENTIAL_EXPRESSION_ASmMG: log2fc, adj_p_value, group_mean_1, group_stdev_1, group_mean_2, group_stdev_2 MEASURED_DIFFERENTIAL_METHYLATION_ASmMR: methylation_diff, q_value, group_mean_1, group_stdev_1, group_mean_2, group_stdev_2 MEASURED_DIFFERENTIAL_ABUNDANCE_ASmO: log2fc, lnfc, q_value, adj_p_value, group_mean_1, group_stdev_1, group_mean_2, group_stdev_2

ABUNDANCE EDGE - METHOD-AWARE FIELDS (CRITICAL for correct queries): The MEASURED_DIFFERENTIAL_ABUNDANCE_ASmO edge stores different fields depending on which differential analysis method produced the row. Use log2fc (not lnfc) for direction and ranking, since it is populated for BOTH methods:

  • DESeq2 edges: log2fc populated, lnfc = null, adj_p_value populated, q_value = null

  • ANCOM-BC edges: log2fc populated, lnfc populated, adj_p_value = null, q_value populated

To filter by significance in a method-agnostic way, OR both fields together: WHERE r.log2fc > 0 AND ( (r.adj_p_value IS NOT NULL AND r.adj_p_value <= 0.05) OR (r.q_value IS NOT NULL AND r.q_value <= 0.05) )

Filtering on r.lnfc > 0 will silently drop every DESeq2 row because Cypher's null > 0 evaluates to null and fails the WHERE clause. If you want to use lnfc as an ANCOM-BC-specific magnitude filter alongside log2fc-based direction, write the clause defensively: AND (r.lnfc IS NULL OR abs(r.lnfc) >= 0.5) This applies the lnfc threshold only to rows where lnfc is populated (ANCOM-BC) and leaves DESeq2 rows untouched.

RELATIONSHIP DIRECTIONS (always use directed arrows in queries): (Assay)-[:MEASURED_DIFFERENTIAL_EXPRESSION_ASmMG]->(MGene) (Assay)-[:MEASURED_DIFFERENTIAL_METHYLATION_ASmMR]->(MethylationRegion) (Assay)-[:MEASURED_DIFFERENTIAL_ABUNDANCE_ASmO]->(Organism) (MGene)-[:METHYLATED_IN_MGmMR]->(MethylationRegion) (Study)-[:PERFORMED_SpAS]->(Assay) (Mission)-[:CONDUCTED_MIcS]->(Study)

NODE PROPERTIES - CRITICAL (use EXACTLY these property names, no others exist): MGene: identifier, symbol, name, organism, taxonomy MethylationRegion: identifier, name, chromosome, start, end, in_promoter, in_exon, in_intron, dist_to_feature Assay: identifier, name, technology, measurement, differential_analysis_method, factors_1, factors_2, material_1, material_2, material_id_1, material_id_2, material_name_1, material_name_2, factor_space_1, factor_space_2 Study: identifier, name, project_title, project_type, description, organism, taxonomy, host_organism, host_strain Mission: identifier, name, flight_program, space_program, start_date, end_date Organism: identifier, name

COMMON PROPERTY NAME MISTAKES - NEVER USE THESE: WRONG: mg.gene_symbol RIGHT: mg.symbol WRONG: mg.gene_name RIGHT: mg.name WRONG: g.gene_symbol RIGHT: g.symbol WRONG: g.gene_name RIGHT: g.name

Input Schema

NameRequiredDescriptionDefault
queryYesThe Cypher query to execute.
paramsNoThe parameters to pass to the Cypher query.
session_idNoSession id returned by `create_session()`. This server serves many users from one process; the session id is what keeps your output directory and generated plots private to you. Pass the SAME value on every tool call. If the server replies that the session is unknown or expired, call `create_session()` again and use the new id.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changedv1.0.0
    • addedInput schema / properties / session_id
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Session id returned by `create_session()`. This server serves many users from one process; the session id is what keeps your output directory and generated plots private to you. Pass the SAME value on every tool call. If the server replies that the session is unknown or expired, call `create_session()` again and use the new id.",
      +  "title": "Session Id"
      +}
    • changedOutput schema / (root)
      Previous value: -{
      -  "$defs": {
      -    "Annotations": {
      -      "additionalProperties": true,
      -      "properties": {
      -        "audience": {
      -          "anyOf": [
      -            {
      -              "items": {
      -                "enum": [
      -                  "user",
      -                  "assistant"
      -                ],
      -                "type": "string"
      -              },
      -              "type": "array"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "default": null,
      -          "title": "Audience"
      -        },
      -        "priority": {
      -          "anyOf": [
      -            {
      -              "maximum": 1,
      -              "minimum": 0,
      -              "type": "number"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "default": null,
      -          "title": "Priority"
      -        }
      -      },
      -      "title": "Annotations",
      -      "type": "object"
      -    },
      -    "TextContent": {
      -      "additionalProperties": true,
      -      "description": "Text content for a message.",
      -      "properties": {
      -        "_meta": {
      -          "anyOf": [
      -            {
      -              "additionalProperties": true,
      -              "type": "object"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "default": null,
      -          "title": "Meta"
      -        },
      -        "annotations": {
      -          "anyOf": [
      -            {
      -              "$ref": "#/$defs/Annotations"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "default": null
      -        },
      -        "text": {
      -          "title": "Text",
      -          "type": "string"
      -        },
      -        "type": {
      -          "const": "text",
      -          "title": "Type",
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "type",
      -        "text"
      -      ],
      -      "title": "TextContent",
      -      "type": "object"
      -    }
      -  },
      -  "properties": {
      -    "result": {
      -      "items": {
      -        "$ref": "#/$defs/TextContent"
      -      },
      -      "title": "Result",
      -      "type": "array"
      -    }
      -  },
      -  "required": [
      -    "result"
      -  ],
      -  "title": "queryOutput",
      -  "type": "object"
      -}New value: +null
  2. First observedv0.4.0

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld=false, and the description layers substantial additional behavior on top: the `total_rows` header semantics, server-side counting before truncation, side-file storage of large results, method-aware null handling on abundance edges, and required directed-arrow traversal. This is genuinely load-bearing context an agent could not infer from annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded correctly — the fallback-only rule and the routing table come before the schema minutiae. However the definition is very long, and a large block (node properties, relationship directions, edge field lists) duplicates information that arguably belongs in get_neo4j_schema/get_node_metadata rather than being restated in every call context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates fully: it specifies the `total_rows`/`rows`/JSON-array response shape, truncation behavior, and how counts surface in aggregate queries. For a complex, open-ended Cypher surface with three params, nothing an agent needs to call it correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes beyond by documenting the semantics of the graph the `query` string must target — exact node/relationship property names, edge-attribute fields, and the anti-patterns (e.g. mg.gene_symbol) that the schema cannot express. It doesn't add much on `params` or `session_id` beyond the schema, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource framing ('FALLBACK Cypher executor') and immediately nails its scope relative to siblings by naming exactly which questions it is not for. An agent can distinguish this from get_neo4j_schema, select_assays, and the find_* specialists without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an unusually explicit when/when-not routing table that maps user question patterns to named alternative tools (find_differentially_expressed_genes, select_assays, etc.), including the instruction to resolve study→assay IDs first rather than writing Cypher. The exclusion criteria ('DO NOT call this tool when...') and the fallback conditions are stated directly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.