Skip to main content
Glama
sbl-sdsc

MCP GeneLab Server

by sbl-sdsc

MCP GeneLab Server

License: BSD-3-Clause Python 3.10+ Model Context Protocol PyPI version

A Model Context Protocol (MCP) server that converts natural language queries into Cypher queries and executes them against the configured Neo4j endpoints. Customized tools provide seamless access to the NASA GeneLab Knowledge Graph (spoke-genelab v0.3.1), enabling AI-assisted analysis of spaceflight experiments and their biological effects. This server allows researchers to query differential gene expression, DNA methylation, and differential organism abundance data from NASA's space biology experiments through natural language interactions with AI assistants like Claude.

The GeneLab Knowledge Graph integrates omics data from NASA's Open Science Data Repository (OSDR), with nodes that can be used as connectors to other knowledge graphs, such as the SPOKE (Scalable Precision Medicine Open Knowledge Engine) knowledge graph. This integration connects spaceflight experimental results with a comprehensive biological context, including genes, proteins, anatomical structures, pathways, and diseases.

This server is part of the NSF-funded Proto-OKN Project (Prototype Open Knowledge Network). It's an extension of the Neo4j Cypher MCP server.

Table of Contents

Related MCP server: SPARQL MCP Server

Building and Querying the SPOKE-GeneLab Knowledge Graph

Presentation

Knowledge Graph Schema (v0.3.1)

The SPOKE-GeneLab KG v0.3.1 contains the following node and relationship types:

The MCP-GeneLab server uses the SPOKE-GeneLab v0.3.1+20260311 release. Any new datasets or processed data added to OSDR after March 11, 2026 is not available through the MCP-GeneLab server.

Nodes: Study, Mission, Assay, MGene, Gene, MethylationRegion, Organism, Anatomy, CellType

Relationships:

  • (Mission)-[:CONDUCTED_MIcS]->(Study) — Mission conducted a study

  • (Study)-[:PERFORMED_SpAS]->(Assay) — Study performed an assay

  • (Assay)-[:MEASURED_DIFFERENTIAL_EXPRESSION_ASmMG]->(MGene) — Differential gene expression

  • (Assay)-[:MEASURED_DIFFERENTIAL_METHYLATION_ASmMR]->(MethylationRegion) — Differential methylation

  • (Assay)-[:MEASURED_DIFFERENTIAL_ABUNDANCE_ASmO]->(Organism) — Differential organism abundance

  • (Assay)-[:INVESTIGATED_ASiA]->(Anatomy) — Assay investigated an anatomical structure

  • (Assay)-[:INVESTIGATED_ASiCT]->(CellType) — Assay investigated a cell type

  • (MGene)-[:IS_ORTHOLOG_MGiG]->(Gene) — Model organism gene is ortholog of human gene

  • (MGene)-[:METHYLATED_IN_MGmMR]->(MethylationRegion) — Gene is methylated in a region

Features

Querying & Analysis

  • Natural Language Querying: Ask questions in plain English — no need to write complex graph queries

  • NASA GeneLab Queries: Ask questions about spaceflight experiments in the NASA GeneLab knowledge graph

  • Differential Gene Expression Analysis: Find genes that are upregulated or downregulated in spaceflight conditions compared to ground controls

  • DNA Methylation Data: Access epigenetic changes observed in spaceflight experiments, including promoter / exon / intron / distance-to-feature filtering

  • Differential Organism Abundance: Query amplicon/metagenomics data showing changes in microbial community composition during spaceflight (DESeq2 and ANCOM-BC method-aware significance filtering)

  • Cross-Assay Intersection Analyses: Find features differentially detected across multiple assays — common DEGs, common DMRs, common DA organisms — each direction (up/down, hyper/hypo, increased/decreased) kept separate so the LLM can reason about them independently

  • Expression-Methylation Coupling: Identify differentially expressed genes whose promoter (or other gene region) is also differentially methylated in matched assays; supports pooled DM evidence across multiple methylation assays

  • Multi-Organism Support: Query data across multiple model organisms including mice, rats, and other species used in space research

  • Anatomy & Cell Type Filtering: Filter results by specific anatomical structures (UBERON ontology) or cell types (Cell Ontology) used in experiments

  • Assay Selection: Browse and filter assays by study, organism, technology, or measurement type

  • Biomedical Context Integration: Connect spaceflight gene expression changes to pathways, diseases, and other biological knowledge from SPOKE

  • Federated Queries: Combine data from GeneLab with other Neo4j knowledge graphs for comprehensive biomedical analysis

Visualization

  • Volcano Plots: Generate volcano plots showing differentially expressed genes / methylated regions / abundant organisms with significance thresholds

  • Venn Diagrams: Create Venn diagrams comparing differentially expressed genes (or DMRs, or DA organisms) across 2 or 3 assays, including an expression_methylation 2×2 grid variant for paired transcriptomic-epigenomic comparisons

  • Plot Resource Layer: Every generated plot is exposed as an MCP resource under plot://<session_id>/<filename> and via a fetch_plot tool, so clients can retrieve PNG bytes through a separate request from the tool call that produced them. A failed fetch can be retried without re-running the analysis

  • Schema Visualization: Generate visual representations of the knowledge graph schema

  • Mermaid Class Diagrams: Create and clean Mermaid-format class diagrams of the KG schema

Infrastructure

  • Read-Only Enforcement: All Neo4j sessions use READ_ACCESS mode — write operations are rejected at the Bolt protocol level, protecting the knowledge graph from modification

  • Multiple Transport Modes: Supports STDIO (local), SSE, and Streamable HTTP (remote deployment)

  • Remote Deployment: Deploy as a web service behind a TLS reverse proxy (target: CloudFront + WAF → ALB → ECS Fargate), accessible via HTTPS URL from any MCP client. Ships GET /healthz / GET /readyz routes for load-balancer health checks and built-in usage metrics (JSON usage log, CloudWatch EMF, optional /metrics) — see docs/deployment.md

  • Session Scoping: The hosted server is one shared process serving many users, so per-user state (output directory, plot registry) is keyed on a session_id obtained from create_session and passed on every tool call — nothing a user does is visible to another session

  • Docker Support: Build and deploy as a Docker container for consistent, reproducible environments

  • Multiple Access Methods: Use through Claude Desktop / claude.ai, ChatGPT, VS Code with GitHub Copilot, Gemini, or any MCP-compatible client

  • Pre-configured Setup: Ready-to-use mcp-genelab configuration files for a local STDIO connection to the spoke-genelab-v0.3.1 KG, or connect to the public endpoint at https://visualization.osdr.nasa.gov/kg/mcp with no local install

Prerequisites

Before using mcp-genelab, ensure you have:

  • Client Application: One of the following:

    • Claude Desktop or claude.ai — connect via Settings → Connectors → Add Custom Connector

    • ChatGPT (web, Developer mode) — connect via Add custom MCP server

    • VS Code with GitHub Copilot — connect via MCP server settings

    • Gemini app (personal Google Account) or Gemini CLI — connect via Connected Apps or gemini mcp add

    • Any MCP client that supports the STDIO or Streamable HTTP transport

  • Connection to the spoke-genelab-v0.3.1 knowledge graph via one of the two paths below:

    • Remote public endpoint: Connect to the hosted mcp-genelab server at https://visualization.osdr.nasa.gov/kg/mcp over HTTPS — no local install required. See Option A.

    • Local install with STDIO: Run mcp-genelab on your own machine against a local Neo4j instance holding the spoke-genelab-v0.3.1 KG. See Option B.

For the local STDIO setup you also need:

  • Operating System: macOS, Linux, or Windows

  • Python 3.10+ and the uv package manager

  • Neo4j Desktop with the spoke-genelab-v0.3.1 KG imported (installation links are provided in Option B)

Quick Start

mcp-genelab can be reached two ways: by connecting to the remote public endpoint (https://visualization.osdr.nasa.gov/kg/mcp) or by running mcp-genelab locally with STDIO. Both serve the spoke-genelab-v0.3.1 knowledge graph.

Option A: Connect to the Remote mcp-genelab Server

The public mcp-genelab endpoint is:

https://visualization.osdr.nasa.gov/kg/mcp

It is a Streamable HTTP MCP server hosted by NASA OSDR with no authentication required, so you can connect without installing anything locally. Pick your client below. (If you would rather run against your own Neo4j instance, use Option B.)

Claude (Desktop or claude.ai)

  1. Open Claude Desktop (or claude.ai)

  2. Go to Settings → Connectors (or Manage Connectors)

  3. Click Add Custom Connector

  4. Enter:

    • Name: mcp-genelab

    • MCP Server URL: https://visualization.osdr.nasa.gov/kg/mcp

  5. Click Save

  6. In the chat prompt, click the + button and toggle the mcp-genelab connector on

Documentation: Getting started with custom connectors using remote MCP

ChatGPT

  1. In ChatGPT on the web, open Settings → Apps → Advanced settings and enable Developer mode (Pro; on Business/Enterprise/Edu an admin must enable it)

  2. Go to chatgpt.com/plugins, click +, then Add custom MCP server

  3. Enter:

    • Name: mcp-genelab

    • Server URL: https://visualization.osdr.nasa.gov/kg/mcp

    • Authentication: No authentication

  4. Accept the risk notice (I understand and want to continue), then click Create as a plugin and install it

  5. In the chat prompt, type @ and select mcp-genelab

Documentation: Add custom MCP server · Developer mode and MCP apps in ChatGPT

VS Code with GitHub Copilot

  1. Open the Command Palette (Cmd+Shift+P) and run MCP: Add Server

  2. Choose HTTP, enter https://visualization.osdr.nasa.gov/kg/mcp as the URL and mcp-genelab as the server ID, and pick where to save it (workspace or global)

  3. When prompted, confirm that you trust the server so it starts

Equivalently, add this to .vscode/mcp.json (or your user MCP configuration):

{
  "servers": {
    "mcp-genelab": {
      "type": "http",
      "url": "https://visualization.osdr.nasa.gov/kg/mcp"
    }
  }
}

In Copilot Chat, open the Configure Tools button in the chat input to confirm the mcp-genelab tools are enabled.

Documentation: Use MCP servers in VS Code

Gemini

Gemini app (web; personal Google Account):

  1. Go to gemini.google.com, click Settings → Connected Apps (if you don't see it, click Personal Intelligence first)

  2. Under Custom apps, click Add a custom app and enter https://visualization.osdr.nasa.gov/kg/mcp

  3. Click Next and follow the on-screen instructions

  4. In the chat prompt, type @ and select the custom app

Documentation: Connect & manage custom apps for Gemini Apps

Gemini CLI (any Google account):

gemini mcp add --transport http mcp-genelab https://visualization.osdr.nasa.gov/kg/mcp

or add to ~/.gemini/settings.json: {"mcpServers": {"mcp-genelab": {"httpUrl": "https://visualization.osdr.nasa.gov/kg/mcp"}}}, then run /mcp inside Gemini CLI to confirm it is connected.

Documentation: Gemini CLI — MCP servers

Then ask a question like: "What organisms are represented in the spoke-genelab-v0.3.1 knowledge graph?"

Option B: Run mcp-genelab Locally with STDIO

Running mcp-genelab locally has two parts: (1) stand up a local Neo4j instance holding the spoke-genelab-v0.3.1 KG, and (2) point mcp-genelab at it via STDIO.

Step 1 — Install Neo4j Desktop and import the spoke-genelab-v0.3.1 KG

  1. Install Neo4j Desktop and create a spoke-genelab instance (with the APOC plugin) by following the Neo4j Desktop installation instructions.

  2. Import the spoke-genelab-v0.3.1 KG into that instance by following the database import instructions. Name the database exactly spoke-genelab-v0.3.1 and start the instance once the import completes.

Note the Bolt URI (default bolt://localhost:7687), username, and password of your running instance — you will need them in Step 2.

Step 2 — Install uv and configure mcp-genelab

Install uv if you don't already have it:

# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

Then configure your MCP client to launch mcp-genelab over STDIO. For Claude Desktop, go to Claude → Settings → Developer → Edit Config and add the following mcp-genelab entry:

{
  "mcpServers": {
    "spoke-genelab-local": {
      "command": "uvx",
      "args": ["mcp-genelab"],
      "env": {
        "NEO4J_URI": "bolt://localhost:7687",
        "NEO4J_USERNAME": "neo4j",
        "NEO4J_PASSWORD": "neo4jdemo",
        "NEO4J_DATABASE": "spoke-genelab-v0.3.1",
        "INSTRUCTIONS": "Query the spoke-genelab-v0.3.1 KG to identify NASA spaceflight experiments containing omics datasets, specifically differential gene expression (transcriptomics), DNA methylation (epigenomics), and Amplicon (metagenomics) data."
      }
    }
  }
}

For VS Code with GitHub Copilot, add the same mcp-genelab entry to your .vscode/mcp.json (note the top-level key is servers, not mcpServers):

{
  "servers": {
    "spoke-genelab-local": {
      "command": "uvx",
      "args": ["mcp-genelab"],
      "env": {
        "NEO4J_URI": "bolt://localhost:7687",
        "NEO4J_USERNAME": "neo4j",
        "NEO4J_PASSWORD": "neo4jdemo",
        "NEO4J_DATABASE": "spoke-genelab-v0.3.1",
        "INSTRUCTIONS": "Query the spoke-genelab-v0.3.1 KG to identify NASA spaceflight experiments containing omics datasets, specifically differential gene expression (transcriptomics), DNA methylation (epigenomics), and Amplicon (metagenomics) data."
      }
    }
  }
}

Note: Set NEO4J_USERNAME, NEO4J_PASSWORD, and NEO4J_URI to match the Neo4j instance you started in Step 1. The uvx command automatically downloads and runs the latest published mcp-genelab from PyPI. Keep NEO4J_DATABASE set to spoke-genelab-v0.3.1 to match the database name you imported.

Docker Deployment

Build the MCP Server Image

cd mcp-genelab
docker build -t mcp-genelab:latest .

Run with Streamable HTTP Transport

docker run \
  --name mcp-server \
  --publish=127.0.0.1:8000:8000 \
  --env NEO4J_URI=bolt://host.docker.internal:7687 \
  --env NEO4J_USERNAME=neo4j \
  --env NEO4J_PASSWORD=yourpassword \
  --env NEO4J_DATABASE=spoke-genelab-v0.3.1 \
  --env MCP_TRANSPORT=streamable-http \
  --env MCP_HOST=0.0.0.0 \
  --env MCP_PORT=8000 \
  --detach \
  mcp-genelab:latest

The MCP server is then accessible at http://localhost:8000/mcp/, with GET http://localhost:8000/healthz (liveness) and GET http://localhost:8000/readyz (readiness — pings Neo4j) for load balancers (all under MCP_PATH_PREFIX if one is set, e.g. /kg/mcp). In any remote transport the server defaults to MCP_SESSION_POLICY=strict: clients must call create_session first and pass the returned session_id on every tool call (see docs/api.md).

Environment Variables

Variable

Default

Description

NEO4J_URI

bolt://localhost:7687 (stdio only)

Neo4j Bolt connection URI — required in remote transports (no default; the server refuses to start without it)

NEO4J_USERNAME

neo4j (stdio only)

Neo4j username — required in remote transports

NEO4J_PASSWORD

neo4jdemo (stdio only)

Neo4j password — required in remote transports; inject from a secret store

NEO4J_DATABASE

spoke-genelab-v0.3.1

Neo4j database name for the spoke-genelab-v0.3.1 KG

MCP_TRANSPORT

stdio

Transport mode: stdio, sse, streamable-http, or http

MCP_HOST

127.0.0.1

HTTP listener host (use 0.0.0.0 for Docker)

MCP_PORT

8000

HTTP listener port

MCP_PATH_PREFIX

(empty)

Public path prefix when a load balancer publishes the service under one, e.g. /kg → POST /kg/mcp, GET /kg/healthz, /kg/readyz, /kg/metrics

MCP_SESSION_POLICY

strict (remote) / implicit (stdio)

strict: every tool except create_session requires a valid session_id; lenient: only state-bearing tools do; implicit: fixed local session

MCP_SESSION_IDLE_TTL_SECONDS / MCP_SESSION_MAX_AGE_SECONDS

3600 / 28800

Session idle and absolute lifetimes

MCP_MAX_SESSIONS / MCP_MAX_PLOTS_PER_SESSION / MCP_MAX_TOTAL_PLOT_BYTES

10000 / 8 / 268435456

Session-store bounds

MCP_SESSION_EVICTION_MIN_IDLE_SECONDS

300

Minimum idle time before a session may be recycled to make room at the MCP_MAX_SESSIONS cap

MCP_MAX_REQUEST_BODY_BYTES

1048576

Maximum size of one POST /mcp body (1 MiB)

MCP_READYZ_TIMEOUT_SECONDS / MCP_READYZ_CACHE_SECONDS

4 / 2

Budget for the /readyz Neo4j ping; how long the last verdict is reused

MCP_QUERY_TIMEOUT_SECONDS / MCP_MAX_QUERY_ROWS

60 / 1000

Per-query timeout; row cap for the query tool

MCP_NEO4J_POOL_SIZE / MCP_NEO4J_ACQUISITION_TIMEOUT

20 / 30

Bolt pool per process; fail-fast on saturation

MCP_USAGE_LOG / MCP_METRICS_EMF / MCP_METRICS_ENDPOINT

1 / 0 / 0

Usage metrics: JSON usage log, CloudWatch EMF, GET /metrics

MCP_USAGE_FP_SALT

random per process

Salt for the client_fp usage-log field; set it (from a secret store) so fingerprints are comparable across restarts

MCP_METRICS_NAMESPACE / MCP_SERVICE_NAME

mcp-genelab / mcp-genelab

CloudWatch namespace for EMF metrics; service field on usage events

MCP_LOG_LEVEL

INFO

Application log level

INSTRUCTIONS

(see source)

System instructions for the LLM

Example Queries

Each link below points to a chat transcript that demonstrates how to use the mcp-genelab server to query and analyze GeneLab data hosted in the spoke-genelab-v0.3.1 Neo4j Knowledge Graph. To create a transcript of your own chat, use the prompt Create a chat transcript; the transcript can then be downloaded in .md or .pdf format.

Knowledge Graph Overview & Class Diagram

Overview of spoke-genelab v0.3.1

Node and Relationship Metadata Examples

List spoke-genelab-v0.3.1 assay node, properties, and relationships

Differential Expression Analysis with MCP tools

OSD-244 DE analysis

Differential Expression and Differential Methylation Analysis with MCP tools

OSD-48 DE and DM analysis

Differential Abundance Analysis with MCP tools

OSD-267 DA analysis

Cross-Graph Differential Expression and Associated Disease Analysis with MCP tools

OSD-161 DE and spoke-okn disease analysis

Note: To perform this example query, you will need to add the NSF OKN MCP server to your MCP client by following the instructions at https://okn.us/mcp.

Demos

Recorded demo sessions and transcripts


MCP Tools Reference

The server exposes 24 tools (22 analysis/utility tools plus create_session / end_session) and a plot://{session_id}/{filename} resource template. On the hosted endpoint every tool except create_session takes a session_id argument (see docs/api.md). Tools are listed below grouped by category. The specialist tools should be preferred over the generic query tool — server.py's DEFAULT_INSTRUCTIONS carries a TOOL SELECTION POLICY that routes natural-language requests to the right specialist.

Schema & metadata

Tool

Description

get_neo4j_schema

List all node types, their attributes, and relationships in the knowledge graph

get_node_metadata

Get descriptions of all node types from MetaNode entries

get_relationship_metadata

Get descriptions of all relationship types and their properties

visualize_schema

Generate a visual schema diagram of the knowledge graph

Study / assay browsing

Tool

Description

get_study_info

Get detailed information about a specific study and its assays (metadata + assay inventory)

select_assays

Browse and filter assays by study, organism, technology, or measurement; resolve a factor pair to one or more assay IDs

Single-assay analyses

Tool

Description

find_differentially_expressed_genes

Find up/downregulated genes for a given assay (DESeq2)

find_differentially_methylated_regions

Find hyper/hypomethylated regions for a given assay, with optional in_promoter / in_exon / in_intron / distance filters

find_differentially_abundant_organisms

Find organisms with differential abundance for a given assay (DESeq2 and/or ANCOM-BC)

Cross-assay analyses

Tool

Description

find_common_differentially_expressed_genes

Intersect DEGs across multiple assays (up and down directions kept separate)

find_common_differentially_methylated_regions

Intersect DMRs across multiple assays, with optional MethylationRegion filters

find_common_differentially_abundant_organisms

Intersect differentially abundant organisms across multiple assays

find_common_de_genes_overlapping_dm_regions

Identify DE genes whose promoter (or other region) is also differentially methylated — supports method-aware significance filtering and pooled-DM evidence across multiple methylation assays

Cypher fallback

Tool

Description

query

Execute a read-only Cypher query on the Neo4j database. Fallback for questions the specialists don't cover — the DEFAULT_INSTRUCTIONS policy directs the LLM to use specialist tools first

Plot generation, delivery, and saving

Tool / resource

Description

create_volcano_plot

Generate a volcano plot of differential expression / methylation / abundance results; PNG returned inline and registered for resource fetch

create_venn_diagram

Create a Venn diagram comparing DEGs / DMRs / DA organisms across 2 or 3 assays (also supports the expression_methylation 2×2 grid variant); PNG returned inline and registered for resource fetch

fetch_plot

Re-fetch the canonical PNG bytes of a plot previously generated in the same session from the in-memory registry (last 8 plots per session, FIFO eviction). Returns the bytes as an EmbeddedResource so clients can render them inline. Safe to call repeatedly — no Cypher, no matplotlib, no re-render

get_save_script

Return a markdown block with multiple save options for a previously generated plot: right-click save, ask-LLM-client-to-save, or fetch via the plot:// resource URI

plot://{session_id}/{filename} (resource)

MCP resource template — clients fetch PNG bytes via resources/read on plot://<session_id>/<suggested_filename>. Session-scoped so one user's plot is never addressable from another session; decoupled from the tool response that generated the plot, so a failed fetch can be retried without re-running the analysis

Sessions and output paths

Tool

Description

create_session

Start a session and obtain the session_id that every other tool requires on the hosted endpoint (call first; call again if a tool reports the session unknown/expired)

end_session

End a session immediately, discarding its output directory and plots

set_output_directory

Set the user-facing directory where plots and CSV files should be saved (per session)

get_output_directory

Return the currently configured output directory (per session)

Mermaid & transcript utilities

Tool

Description

clean_mermaid_diagram

Clean and validate a Mermaid class diagram of the KG schema

create_chat_transcript

Export the current chat as a formatted transcript

Security

All Neo4j sessions are opened with default_access_mode=READ_ACCESS, which is enforced at the Bolt protocol level by Neo4j. Any write operation is rejected with the error: "Write operations are not allowed for READ transactions." This works on both Community and Enterprise Edition.

As a second layer of defense, the query tool includes a regex-based write filter (_is_write_query()) that catches the Cypher write keywords MERGE, CREATE, SET, DELETE, REMOVE, ADD, and DROP (case-insensitive) before the query is sent to Neo4j. All queries also use session.execute_read() for transaction-level read enforcement. The two layers — server-side regex + Bolt-level READ_ACCESS — protect the knowledge graph from modification even if one layer is bypassed.

The query tool additionally rejects read-only-but-dangerous procedures that READ_ACCESS does not block (_is_forbidden_query()): LOAD CSV, apoc.load.*, apoc.export.*, apoc.trigger/periodic/refactor/create/merge/cypher/systemdb.*, dbms.*, and db.create* / db.drop* / full-text index creation. apoc.meta.* and apoc.help remain allowed for the schema tools. Every query runs with a server-side timeout (MCP_QUERY_TIMEOUT_SECONDS, 60 s) and the query tool caps results at MCP_MAX_QUERY_ROWS (1,000) rows; error messages never echo the submitted Cypher or raw driver exceptions. On the hosted endpoint, Neo4j credentials are injected at runtime (the image contains none, and remote transports refuse to start without them), per-user state is isolated by session (see MCP_SESSION_POLICY), and the usage log records only salted digests — never raw session ids or IP addresses. See docs/deployment.md for the full hardening checklist.


Development

Instructions for local development

Release history: CHANGELOG.md

Testing

The project ships a pytest suite (201 tests across 11 test files) that runs offline — no Neo4j connection, no network, no MCP transport. It guards against regressions in tool registration, annotation completeness, routing-policy language in tool docstrings, Cypher invariants (read-only enforcement, conditional LIMIT, lnfc null-safety, MethylationRegion filter propagation, pooled IN $assay_ids clause for cross-assay queries), the plot resource layer (plot:// URI registration, fetch_plot round-trips, save-instruction size guarantees), per-session isolation (two sessions can never see each other's output directory or plots; missing/unknown/expired session errors; TTL and memory bounds), the /healthz / /readyz load-balancer routes, and the usage-metrics pipeline.

pip install -r mcp-genelab-tests/requirements-test.txt
pytest

The suite runs in roughly 10 seconds and is safe to run on every commit. A GitHub Actions workflow at mcp-genelab-tests/.github/workflows/test.yml runs the suite on Python 3.10 through 3.13 for every push and pull request. See mcp-genelab-tests/tests/README.md for the per-file breakdown and instructions on adding tests for new tools.

Building and Publishing (maintainers only)

Instructions for building, testing, and publishing the mcp-genelab package on PyPI

API Reference

mcp-genelab server API

Troubleshooting

Common Issues

MCP server not appearing in Claude Desktop:

  • Ensure you've completely quit and restarted Claude Desktop (not just closed the window)

  • Check that your JSON configuration is valid (attach your config file to a chat and ask it to fix any errors)

  • Verify that uvx is installed and accessible in your PATH

Connection errors:

  • Verify the Neo4j endpoint URL is correct and accessible

  • For a local Neo4j Desktop instance, ensure the spoke-genelab instance is started and the spoke-genelab-v0.3.1 database has finished loading

  • Check that NEO4J_DATABASE is set to spoke-genelab-v0.3.1 and matches the database name you imported

Query rejected ("This query was rejected. Only read-only graph queries are permitted…"):

  • This is expected behavior. The query tool refuses write operations (CREATE, MERGE, SET, DELETE, REMOVE, ADD, DROP) and procedures that perform network I/O, bulk export, or database administration (LOAD CSV, apoc.load.*, apoc.export.*, dbms.*, …) before they reach Neo4j; anything that slips past is still blocked at the Bolt protocol level because every session uses READ_ACCESS mode.

"Error (missing session)" / "Error (unknown session)" / "Error (expired session)":

  • On the hosted endpoint every tool except create_session requires a valid session_id. Ask the assistant to call create_session and retry; sessions expire after 60 minutes idle or 8 hours total, and are lost when the server restarts.

Performance issues:

  • Complex Cypher queries may take time to execute

  • Consider breaking down complex queries into smaller parts

  • Check the endpoint's documentation for query best practices

License

This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.

Citation

If you use MCP GeneLab in your research, please cite the following works:

@software{rose2026mcp-genelab,
  title={MCP GeneLab Server},
  author={Rose, P.W. and Saravia-Butler, A.M. and Nelson, C.A. and Shi, Y. and Baranzini, S.E.},
  year={2026},
  url={https://github.com/sbl-sdsc/mcp-genelab}
}

@software{rose2026spoke-genelab,
  title={NASA SPOKE-GeneLab Knowledge Graph},
  author={Rose, P.W. and Nelson, C.A. and Saravia-Butler, A.M. and Gebre, S.G. and Soman, K. and Grigorev, K.A. and Sanders, L.M. and Costes, S.V. and Baranzini, S.E.},
  year={2026},
  url={https://github.com/BaranziniLab/spoke_genelab}
}
  • Nelson, C.A., Rose, P.W., Soman, K., Sanders, L.M., Gebre, S.G., Costes, S.V., Baranzini, S.E. (2025). "Nasa Genelab-Knowledge Graph Fabric Enables Deep Biomedical Analysis of Multi-Omics Datasets." NASA Technical Reports, 20250000723. Link

  • Sanders, L., Costes, S., Soman, K., Rose, P., Nelson, C., Sawyer, A., Gebre, S., Baranzini, S. (2024). "Biomedical Knowledge Graph Capability for Space Biology Knowledge Gain." 45th COSPAR Scientific Assembly, July 13-21, 2024. Link

Acknowledgments

Funding

This work is supported in part by:

  • National Science Foundation Award #2333819: "Proto-OKN Theme 1: Connecting Biomedical information on Earth and in Space via the SPOKE knowledge graph"


For questions, issues, or contributions, please visit our GitHub repository.

Available Tools

24 tools
clean_mermaid_diagramA
Read-onlyIdempotent

Clean a Mermaid class diagram by removing unwanted elements.

    This tool removes:
    - All note statements that would render as unreadable yellow boxes
    - Empty curly braces from class definitions (handles both single-line and multi-line)
    - Strings after newline characters (e.g., truncates "ClassName

extra" to "ClassName")

    Args:
        mermaid_content: The raw Mermaid class diagram content
        
    Returns:
        Cleaned Mermaid content with note statements, empty braces, and post-newline strings removed
    
NameRequiredDescriptionDefault
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.
mermaid_contentYes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=false, so safety and repeatability are covered. The description adds useful transformation detail beyond annotations, including removal of note statements, empty braces, and post-newline strings, plus the exact returned state.

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

Conciseness4/5

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

The description is front-loaded with the core purpose and uses a scannable bullet list for removals. The Args and Returns sections add slight redundancy, but every part remains useful and the total length is reasonable for the transformation behavior it documents.

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

Completeness4/5

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

For a simple read-only utility with no output schema, the description explains the input content, transformations, and returned content well enough for an agent to invoke it correctly. It does not explain session handling, but that is covered in the schema for session_id.

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 description coverage is 50%. The undocumented required parameter, mermaid_content, is described in the description as 'the raw Mermaid class diagram content,' which adds meaning beyond the schema's bare string type. The optional session_id has a detailed schema description and does not need repetition here.

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?

States a specific verb and resource: 'Clean a Mermaid class diagram by removing unwanted elements.' The bullet list then names exactly which elements are removed, so an agent can distinguish this utility from unrelated sibling tools like plotting or querying tools.

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

Usage Guidelines3/5

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

The description implies usage by listing the unwanted elements it removes, but it does not explicitly say when to call this tool, when not to call it, or name an alternative. In the absence of similar sibling tools, the implied scenario is adequate but not rich.

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

create_chat_transcriptC
Read-onlyIdempotent

Prompt for creating a chat transcript in markdown format with user prompts and Claude responses.

NameRequiredDescriptionDefault
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.

TDQS

C2.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and the annotation title calls it 'prompt only'. The description contributes the output format (markdown, user prompts and Claude responses), but it does not confirm the 'prompt only' nature or explain that no transcript file is created — a meaningful ambiguity that annotations partly, but not fully, resolve.

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

Conciseness4/5

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

A single efficient sentence with no filler. It is front-loaded, though very short relative to the ambiguity it leaves unresolved.

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

Completeness3/5

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

For a single-parameter, no-output-schema tool, the description covers the minimum, but the read-only 'prompt only' nature — the most important thing an agent needs to know to avoid expecting a persisted transcript — is conveyed only indirectly. It is adequate but incomplete.

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

Parameters3/5

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

Schema description coverage is 100% and there is only one optional parameter, so the schema fully documents session_id, including its privacy role and reuse instructions. The description adds nothing about parameters, so baseline 3 applies.

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

Purpose3/5

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

The description names a verb-adjacent action and resource ('creating a chat transcript in markdown format') and clarifies the content shape (user prompts + Claude responses). However, the odd phrasing 'Prompt for creating' leaves it ambiguous whether the tool generates a prompt, returns a transcript, or writes a file, and it draws no distinction from the 25 sibling tools.

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

Usage Guidelines2/5

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

There is no statement of when to use this tool versus alternatives such as create_session or end_session, nor any precondition, trigger, or exclusion. The agent must infer usage entirely from the name.

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

create_sessionA

Start a session and obtain the session_id that EVERY other tool on this server requires.

WHEN TO USE THIS TOOL: Call this ONCE at the beginning of a conversation, before any other mcp-genelab tool. Also call it again whenever a tool replies that the session is unknown or expired.

WHY: This server runs as a single shared process serving many users at once. The session id is the only thing that keeps YOUR output directory and YOUR generated plots (retrievable via fetch_plot, get_save_script and the plot://{session_id}/{filename} resource) separate from everyone else's. It is an opaque bearer token — treat it as private to this conversation and never guess one.

LIFETIME: A session expires after a period of inactivity (default 60 min) or an absolute maximum age (default 8 h), whichever comes first. Expired sessions drop their plots; regenerate them under a new session.

RETURNS: A short message containing session_id: <token>. Extract the token and pass it as the session_id argument on every subsequent call.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only declare readOnlyHint=false, idempotentHint=false and openWorldHint=false; the description adds material context beyond that: inactivity (60 min) and absolute (8 h) lifetimes, the fact that expired sessions DROP their plots, and that the session id is an opaque bearer token to be kept private and never guessed. This directly discloses what is lost and the security posture.

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

Conciseness5/5

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

Front-loaded with the core action, then organized into clearly labeled WHEN TO USE / WHY / LIFETIME / RETURNS blocks. The extra length is justified because the tool is a universal prerequisite, and no sentence is filler.

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?

There is no output schema, so the description carries the return contract and does so ('a short message containing session_id: <token>'). Combined with lifetime and re-creation guidance, nothing an agent needs to call this correctly is 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?

The tool takes zero parameters, so the baseline is 4; the description still explains what the calling convention is (extract the token from the return message and pass it as session_id on every subsequent call), which is useful even though there is no argument to document.

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?

States a specific verb+resource ('Start a session and obtain the session_id') and immediately distinguishes itself from siblings by declaring that every other tool on the server requires the returned token. An agent can tell it apart from end_session and the plotting/query tools 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?

Explicit when-to-use: call ONCE at the start of a conversation before any other mcp-genelab tool, and again whenever a tool reports the session is unknown or expired. This is exactly the kind of ordering prerequisite an agent needs, with no reliance on inference.

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

create_venn_diagramA

Create Venn diagrams comparing differential data between 2 or 3 assays.

Supports multiple data types:

  • 'expression': Compares differentially expressed genes (upregulated/downregulated by log2fc)

  • 'methylation': Compares differentially methylated genes (hypermethylated/hypomethylated by methylation_diff)

  • 'abundance': Compares differentially abundant organisms (increased/decreased by log2fc; works for both DESeq2 and ANCOM-BC)

  • 'expression_methylation': Cross-comparison showing directional overlaps between differentially expressed genes from one assay and differentially methylated genes from another assay (2-way only)

Creates side-by-side Venn diagrams showing:

  • Left: Positive direction (upregulated / hypermethylated / increased abundance)

  • Right: Negative direction (downregulated / hypomethylated / decreased abundance)

For 'expression_methylation' mode, this tool computes FOUR directional overlaps so the user can see which kind of expression–methylation coupling is happening. By default (direction_pair='all') it renders all four as a 2x2 grid:

  • Hypermethylated + Downregulated (classical epigenetic silencing — promoter methylation reducing expression)

  • Hypomethylated + Upregulated (loss of methylation enabling expression)

  • Hypermethylated + Upregulated (less canonical; e.g. gene-body methylation activating expression)

  • Hypomethylated + Downregulated (less canonical; non-classical) If the user names a specific pairing (e.g. "create a Venn of hypermethylated and downregulated genes"), pass direction_pair='hyper_down' to render just that one. The summary always reports the size of all four overlaps, regardless of which subset is rendered.

Methylation region location filters (for data_type='methylation' and the methylation side of 'expression_methylation'):

  • in_promoter, in_exon, in_intron: each accepts True (include only regions where this flag is true), False (exclude regions where this flag is true), or None (no filter). Multiple filters combine with AND. For example, in_promoter=True alone restricts to promoter-overlapping regions; in_promoter=True with in_intron=False restricts to promoter regions that are NOT intronic.

  • dist_to_feature_max: when set, include only regions whose distance to the nearest gene feature is <= this value (in bp). Useful for narrowing to regions tightly associated with gene bodies. dist_to_feature on the MethylationRegion node is the bp distance from the region to the nearest annotated feature. These filters apply during the Cypher query — they reduce the set of methylation regions BEFORE the overlap computation, so each gene set is the genes that have at least one methylation region passing all the filters and the magnitude/significance criteria.

Significance filtering:

  • 'expression' and 'expression_methylation' (expression side): adj_p_value <= adj_p_threshold (default 0.05).

  • 'methylation' and 'expression_methylation' (methylation side): q_value <= q_value_threshold (default 0.05).

  • 'abundance' is method-aware: DESeq2 rows are filtered by adj_p_threshold, ANCOM-BC rows by q_value_threshold.

Magnitude filtering for 'abundance':

  • log2fc_threshold applies to every row (log2fc is populated for both methods).

  • lnfc_threshold (optional) adds an ANCOM-BC-specific |lnfc| filter; DESeq2 rows (lnfc IS NULL) pass through.

Returns a link to the plot and summary statistics.

NameRequiredDescriptionDefault
in_exonNoMethylationRegion location filter (data_type='methylation' or 'expression_methylation' only). When True, only include methylation regions overlapping an exon. When False, exclude exon-overlapping regions. None (default) imposes no exon filter. Maps directly to the in_exon property on MethylationRegion nodes.
data_typeNoType of data to compare. Options: 'expression' (differentially expressed genes), 'methylation' (differentially methylated genes), 'abundance' (differentially abundant organisms), 'expression_methylation' (overlap between DE genes and DM genes across assays)expression
in_intronNoMethylationRegion location filter (data_type='methylation' or 'expression_methylation' only). When True, only include methylation regions overlapping an intron. When False, exclude intron-overlapping regions. None (default) imposes no intron filter. Maps directly to the in_intron property on MethylationRegion nodes.
assay_id_1YesFirst assay identifier
assay_id_2YesSecond assay identifier
assay_id_3NoThird assay identifier (optional, for 3-way Venn diagram)
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.
in_promoterNoMethylationRegion location filter (data_type='methylation' or 'expression_methylation' only). When True, only include methylation regions overlapping a gene promoter. When False, exclude promoter-overlapping regions. None (default) imposes no promoter filter. Maps directly to the in_promoter property on MethylationRegion nodes.
figsize_widthNoFigure width in inches
direction_pairNoFor data_type='expression_methylation' only: which directional overlap(s) to render. 'all' (default) renders a 2x2 grid of all four biologically meaningful combinations: hypermethylated+downregulated (classical epigenetic silencing), hypomethylated+upregulated (loss of methylation enabling expression), hypermethylated+upregulated, and hypomethylated+downregulated. Specify one of 'hyper_down', 'hypo_up', 'hyper_up', 'hypo_down' to render only that single overlap. Ignored for non-expression_methylation data types.all
figsize_heightNoFigure height in inches
lnfc_thresholdNoOptional minimum |lnfc| magnitude for the 'abundance' data type. Only applied to rows with lnfc populated (ANCOM-BC). DESeq2 rows are not filtered by this parameter. Ignored for non-abundance data types. Leave unset (None) to skip lnfc filtering.
adj_p_thresholdNoAdjusted p-value threshold (default: 0.05). Applied to expression assays and to DESeq2 abundance rows.
log2fc_thresholdNoLog2 fold change threshold for filtering genes (used for expression and abundance data types)
q_value_thresholdNoq-value threshold (default: 0.05). Applied to methylation assays and to ANCOM-BC abundance rows.
dist_to_feature_maxNoMethylationRegion distance filter (data_type='methylation' or 'expression_methylation' only). When set, only include methylation regions whose dist_to_feature (distance in bp to the nearest gene feature) is <= this value. Useful for restricting to regions close to gene bodies. None (default) imposes no distance filter.
methylation_diff_thresholdNoMethylation difference threshold for filtering regions (used for methylation data type, default 0.0 means any change)

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already state it is a non-read-only, non-idempotent, closed-world operation, so the bar is lower. The description still adds real behavioral detail: filters execute in the Cypher query BEFORE overlap computation, and the summary always reports all four overlaps regardless of which subset is rendered. It stops short of describing the returned link's lifetime or how plots are fetched post-creation.

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?

The purpose and mode table are well front-loaded, but the block restating in_promoter/in_exon/in_intron/dist_to_feature_max semantics duplicates schema descriptions verbatim and inflates a 17-param tool's prose substantially. Every sentence earns its place less often than it should because of that redundancy.

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?

For a 17-parameter, four-mode tool with no output schema, the description covers the mode selection, filter interaction, significance/magnitude semantics per data type, and the return ('a link to the plot and summary statistics'). Nothing an agent needs in order to call it correctly is 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 would be 3, but the description adds semantics the schema omits: multiple location filters combine with AND, with a worked example (in_promoter=True with in_intron=False), and it clarifies that abundance significance filtering is method-aware (DESeq2 vs ANCOM-BC) and that lnfc_threshold only touches ANCOM-BC rows. Some of the threshold text merely echoes the schema, but the AND-combination and ordering semantics are genuine additions.

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?

The opening sentence states a specific verb and resource ('Create Venn diagrams comparing differential data between 2 or 3 assays') and the data_type enumeration distinguishes it from sibling plotting/finding tools. An agent can tell what it produces and over what inputs without opening the schema.

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

Usage Guidelines4/5

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

It maps each data_type to a concrete scenario (expression/methylation/abundance/expression_methylation) and gives a conditional rule for direction_pair ('If the user names a specific pairing... pass direction_pair=hyper_down'). It never names or excludes a sibling tool (e.g. find_common_differentially_expressed_genes), so usage context is clear but alternatives are left implicit.

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

create_volcano_plotA

Create a volcano plot for differential data from the given assay.

Works for three differential measurement types:

  • 'expression': -[MEASURED_DIFFERENTIAL_EXPRESSION_ASmMG]-> MGene x = log2fc, y = -log10(adj_p_value), labels = gene symbol Magnitude filter: log2fc_threshold (default 1.0 = 2-fold)

  • 'methylation': -[MEASURED_DIFFERENTIAL_METHYLATION_ASmMR]-> MethylationRegion x = methylation_diff, y = -log10(q_value), labels = gene symbol (joined via METHYLATED_IN_MGmMR back to MGene for labeling) Magnitude filter: methylation_diff_threshold (default 10.0 = 10%)

  • 'abundance': -[MEASURED_DIFFERENTIAL_ABUNDANCE_ASmO]-> Organism x = log2fc, y = -log10(significance), labels = organism name Magnitude filter: log2fc_threshold (default 1.0 = 2-fold) Significance is method-aware: DESeq2 rows use adj_p_value, ANCOM-BC rows use q_value.

Points are colored by significance:

  • Red: positive direction (upregulated / hypermethylated / increased)

  • Blue: negative direction (downregulated / hypomethylated / decreased)

  • Gray: not significant

Returns a markdown summary, an inline PNG image (if small enough), and the saved file path. Designed to handle assays with thousands of features without timing out.

NameRequiredDescriptionDefault
top_nNoHow many significant points to label in the plot (selected by smallest p/q-value).
assay_idYesAssay identifier (e.g., 'OSD-253-6c5f9f37b9cb2ebeb2743875af4bdc86')
data_typeNoWhich kind of differential data to plot. Options: 'expression' (differentially expressed genes), 'methylation' (differentially methylated regions), 'abundance' (differentially abundant organisms; works for both DESeq2 and ANCOM-BC). Default: 'expression'.expression
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.
figsize_widthNoFigure width in inches
figsize_heightNoFigure height in inches
adj_p_thresholdNoAdjusted p-value (DESeq2) / q-value (ANCOM-BC, methylation) threshold for significance. For abundance, both fields are checked in a method-aware way.
log2fc_thresholdNoLog2 fold change threshold (default 1.0 = 2-fold). Applies to data_type='expression' and data_type='abundance'. Ignored for data_type='methylation' (use methylation_diff_threshold instead).
label_avoid_overlapNoIf True, use adjustText to reposition labels to avoid overlap. Disable on very large assays for faster rendering.
methylation_diff_thresholdNoMethylation difference threshold in percentage points (default 10.0 = |diff| > 10%). Applies only to data_type='methylation'. Ignored for other data types.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=false, idempotentHint=false and openWorldHint=false, so the write/non-idempotent nature is covered. The description adds genuine context beyond that: the return payload (markdown summary, inline PNG, saved path), the color encoding scheme, method-aware significance handling, and a performance note about large assays not timing out.

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

Conciseness4/5

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

The content is long but front-loaded with the purpose and organized as scannable bullets per data type, with axis and color conventions grouped logically. Some of the per-type detail restates schema content, but nothing is wasteful enough to impede comprehension and the structure aids fast scanning.

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

Completeness4/5

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

With no output schema, the description correctly steps in to describe return values (markdown, PNG, file path) and rendering behavior. For a 10-parameter plotting tool it covers data types, thresholds, coloring and performance adequately; the only gap is the absence of prerequisite/session orchestration guidance, which the schema's session_id description partly carries.

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 baseline is 3, and the description meaningfully reinforces it by explaining that thresholds are magnitude filters with real units (default 1.0 = 2-fold, methylation diff in percentage points) and that the abundance significance field is method-aware. This adds interpretive value beyond the schema's field-level text, though it does overlap with several schema descriptions.

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: 'Create a volcano plot for differential data from the given assay.' It then enumerates exactly which measurement types it supports and how each maps to axes, clearly distinguishing it from sibling finders (find_differentially_*) and create_venn_diagram. An agent knows precisely what this tool produces without opening the schema.

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

Usage Guidelines3/5

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

The per-data-type breakdown tells the agent which data_type to choose and which threshold applies, which is useful internal guidance. However, it never states when to prefer this over adjacent tools (e.g., the differential finders that would precede plotting) or any preconditions such as which assay types are plottable. Usage is implied through the data-type taxonomy rather than explicitly framed as when/when-not.

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

end_sessionA
Idempotent

End a session immediately, discarding its output-directory setting and all plots it holds. Optional — sessions also expire on their own. Call it when the user is done, to free server memory promptly. After this, a new create_session() is needed before further tool calls.

NameRequiredDescriptionDefault
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.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only declare readOnlyHint=false, openWorldHint=false and idempotentHint=true. The description adds the key behavioral facts the annotations omit: what is destroyed (output-directory setting and held plots), that termination is optional because sessions self-expire, and the follow-up requirement to re-create a session.

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

Conciseness5/5

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

Three short sentences, the destructive effect front-loaded, then optionality, then the follow-up requirement. No filler or redundant restatement of the tool name.

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?

A simple one-parameter lifecycle tool with no output schema and adequate annotations; the description covers the effect, destructiveness, optionality, and postcondition, leaving nothing an agent needs before calling it.

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

Parameters3/5

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

Schema description coverage is 100% and the session_id parameter is thoroughly documented in the schema itself (identity semantics, privacy, reuse across calls, re-creation on expiry). The description adds no parameter-level detail, so the baseline 3 is appropriate.

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?

Specific verb+resource ("End a session") plus the exact consequences of the action (discards the output-directory setting and all plots it holds). An agent can distinguish this from sibling create_session without opening either 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?

Explicitly states when to call it ("when the user is done, to free server memory promptly") and when it is unnecessary ("Optional — sessions also expire on their own"), plus the postcondition that a new create_session() is required for further calls. The alternative to calling it is named.

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

fetch_plotA
Read-onlyIdempotent

Re-fetch the PNG bytes of a plot previously generated IN THIS SESSION.

WHEN TO USE THIS TOOL: Call this when you need the canonical PNG bytes for a plot that's already been generated. Common cases:

  • The inline image in the original plot tool response was corrupted or didn't render in the client.

  • You need the bytes for a downstream step (e.g. embedding in a transcript, saving to a side file, base64-encoding for an external API).

  • The user asked to see the plot again without re-running the analysis.

WHAT THIS TOOL DOES NOT DO: It does NOT re-render the plot. It returns the same bytes that were registered when the plot was originally generated. If the underlying data has changed, re-run the plot tool itself (create_volcano_plot, create_venn_diagram); don't expect fetch_plot to pick up new data.

EQUIVALENT RESOURCE URI: This tool returns the same bytes that resources/read would return for plot://<session_id>/<filename>. Use whichever path your client supports better — resources for clients that render them well, this tool for clients that don't.

REGISTRY BOUNDS: Each session holds its last 8 plots (FIFO eviction). Older plots, and plots from other or expired sessions, return a clear "not in registry" error and need to be regenerated by re-running the source plot tool under the current session.

NameRequiredDescriptionDefault
filenameYesSuggested filename of a previously generated plot (e.g. 'venn_expression_2way_OSD-244.png'). Look at the most recent create_volcano_plot or create_venn_diagram response — the filename appears in the 'Save' block. Each session keeps its last 8 plots in memory.
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.

TDQS

A4.6/5.0
Behavior5/5

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

Beyond the readOnly/idempotent/openWorld annotations, the description discloses registry bounds (last 8 plots, FIFO eviction), the error behavior for expired or foreign sessions, and equivalence to the resources/read URI. These are material operational facts the annotations cannot convey.

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

Conciseness4/5

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

Front-loaded with a single-sentence summary, then clearly labeled sections that make scanning fast. Slightly verbose in places (registry bounds restated in both description and schema), but every section carries actionable information.

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?

For a no-output-schema lookup tool, the description covers return semantics (same bytes as resources/read), failure modes (not-in-registry, expired session), and the recovery path (re-run the source plot tool). Nothing needed to call it correctly is missing.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents filename provenance and session_id semantics thoroughly. The description reinforces registry scope but adds little parameter-level meaning beyond what the schema states, so the baseline 3 applies.

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?

States a specific operation (re-fetch PNG bytes) and resource (a plot previously generated in this session), and explicitly distinguishes itself from the sibling generators create_volcano_plot and create_venn_diagram by declaring it does NOT re-render. An agent can identify the tool's role 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 explicit 'WHEN TO USE' section with three concrete cases (corrupted inline image, downstream byte consumption, re-display without re-running analysis) and a 'WHAT THIS TOOL DOES NOT DO' section naming the alternatives to use when data has changed. When-to-use, when-not-to-use, and alternatives are all covered.

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

find_common_de_genes_overlapping_dm_regionsA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "expression-methylation coupling", "classical epigenetic silencing", "DE genes that are also DM", "downregulated genes with promoter hypermethylation", or any cross-type intersection between differential expression and differential methylation. Falling back to query for this category reproduces the four-quadrant intersection logic this tool already does correctly (parallel DE+DM fetches across DIFFERENT assays, pooled-methylation aggregation when multiple methylation assays are passed as a list, MethylationRegion location filtering on the DM side, up_hyper/up_hypo/down_hyper/down_hypo direction categorization) and loses the four-quadrant markdown summary and the inline combined CSV.

Find differentially expressed genes that overlap with differentially methylated regions.

This cross-analysis tool:

  1. Gets DE genes from the expression assay (filtered by log2fc and adj_p thresholds)

  2. Gets genes associated with DM regions from the methylation assay(s) (filtered by methylation_diff, q_value, and any MethylationRegion location filters: in_promoter, in_exon, in_intron, dist_to_feature_max). If methylation_assay_id is a list, the methylation evidence is POOLED across the listed assays before the intersection — a gene is treated as hypermethylated if it passes the threshold in ANY of the pooled assays.

  3. Finds the intersection (genes that are BOTH differentially expressed AND differentially methylated)

  4. Reports the overlap categorized by direction (up+hyper, up+hypo, down+hyper, down+hypo)

For the classical epigenetic-silencing question — promoter hypermethylation reducing expression — pass in_promoter=True. When a study has replicate methylation assays (e.g. OSD-48 has two methylKit assays for the same Space Flight vs. Ground Control comparison), pass them as a list to capture the combined methylation evidence on the methylation side of the intersection.

NameRequiredDescriptionDefault
in_exonNoMethylationRegion location filter (True / False / None). See in_promoter.
in_intronNoMethylationRegion location filter (True / False / None). See in_promoter.
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.
in_promoterNoMethylationRegion location filter applied to the DM side of the overlap. When True, only DM regions overlapping a promoter contribute to the methylated-gene set. Use this for classical epigenetic-silencing questions: 'which downregulated genes have hypermethylation in their promoter?' → pass in_promoter=True.
adj_p_thresholdNoAdjusted p-value threshold for DE genes (default: 0.05)
log2fc_thresholdNoLog2 fold change threshold for DE genes (default: 1.0)
q_value_thresholdNoq-value threshold for DM regions (default: 0.05)
dist_to_feature_maxNoMethylationRegion distance filter. When set, only DM regions with dist_to_feature <= this value (bp) contribute to the methylated-gene set. None (default) imposes no distance filter.
expression_assay_idYesAssay identifier for differential expression data
methylation_assay_idYesAssay identifier for differential methylation data, or a list of identifiers to pool. Pass a single string to use one methylation assay (most common). Pass a list (e.g. ['OSD-48-968c...', 'OSD-48-4dc1...']) to pool methylation evidence across replicate methylation assays of the same comparison — a gene is treated as 'hypermethylated' if ANY of the pooled assays passes the threshold for it. This matches the natural reading of 'find DE genes that have hypermethylated promoter evidence in this study's methylation assays', where the methylation side is a union across assays before being intersected with the DE side.
methylation_diff_thresholdNoMethylation diff threshold for DM regions (default: 0.0)

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnlyHint=true, idempotentHint=true, openWorldHint=false), and the description adds real net-new behavior: pooled-methylation union semantics across a list of assays ('hypermethylated if it passes the threshold in ANY of the pooled assays') and the return artifacts (four-quadrant markdown summary and inline combined CSV). It does not cover failure behavior, empty-overlap handling, or result size, but the added disclosure goes meaningfully beyond the annotations.

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

Conciseness4/5

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

The routing instruction is front-loaded, which is the right priority. However, the opening parenthetical (pooling, MethylationRegion filtering, direction categorization, lost outputs) substantially duplicates the numbered step list that follows, so some sentences do not fully earn their place.

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?

For an 11-parameter cross-analysis tool with no output schema, the description covers inputs (DE/DM thresholds, location filters, pooling), the algorithm, edge cases (replicate assays, promoter silencing), and the return artifacts. An agent has everything needed to call it correctly and interpret results.

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 description coverage is 100%, so 3 is the baseline, but the description adds semantics the schema does not: it explains the union-across-assays semantics for a list-valued methylation_assay_id and gives a worked rationale for in_promoter=True. Thresholds and distance filters are left to the schema, which is reasonable.

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?

The description states a precise verb+resource: 'Find differentially expressed genes that overlap with differentially methylated regions', and then enumerates the four internal steps (DE fetch, DM fetch, intersection, direction categorization). This distinguishes it cleanly from sibling probes like find_differentially_expressed_genes and find_differentially_methylated_regions, which only handle one data type.

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?

Explicitly routes the agent: 'USE THIS TOOL (not the `query` tool) for any expression-methylation coupling...' and names the alternative and what is lost by falling back (four-quadrant intersection logic, markdown summary, combined CSV). It also gives a concrete condition for the special case: pass in_promoter=True for the classical silencing question, and pass a list when a study has replicate methylation assays.

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

find_common_differentially_abundant_organismsA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "common differentially abundant organisms across assays", "organisms increased in BOTH assays", "shared abundance signals across methods" (e.g. DESeq2 vs ANCOM-BC concordance), or any cross-assay abundance intersection question. Falling back to query for this category reproduces the per-assay fetch + inner-join logic this tool already does correctly (parallel fetches, method-aware significance filtering, lnfc handling that doesn't drop DESeq2 rows, separate increased vs. decreased intersections) and loses the formatted markdown + inline CSV side-channel and the assay-reference legend.

Find common differentially abundant organisms across multiple assays.

Useful for comparing results from different analysis methods (e.g., DESeq2 vs ANCOM-BC 1 vs ANCOM-BC 2) to identify organisms consistently detected as differentially abundant.

Direction (increase vs. decrease) and ranking use log2fc, which is populated for BOTH DESeq2 and ANCOM-BC edges in the GeneLab KG. log2fc is therefore the universal magnitude filter (log2fc_threshold); lnfc is ANCOM-BC-only and would null-filter every DESeq2 row if used for direction.

Significance filtering is method-aware:

  • DESeq2 edges populate adj_p_value (not q_value); the adj_p_threshold applies.

  • ANCOM-BC edges populate q_value (not adj_p_value); the q_value_threshold applies. Each row is kept if its populated significance field meets the matching threshold.

Magnitude filtering:

  • log2fc_threshold (default 0.0) applies to every row, since log2fc is populated for both methods.

  • lnfc_threshold (default None = no filter) is method-aware: when set, it requires |lnfc| >= lnfc_threshold on rows where lnfc is populated. Rows where lnfc is null (i.e., DESeq2 rows) are not affected by this filter.

This function:

  1. Takes a list of assay IDs as input (2 or more)

  2. Gets ALL organisms passing the magnitude and method-aware significance filters for each assay

  3. Inner joins among increased and among decreased abundance organisms

  4. Returns markdown tables showing common organisms and their log2fc values

NameRequiredDescriptionDefault
assay_idsYesList of assay identifiers for abundance comparisons (e.g., different methods like DESeq2, ANCOM-BC)
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.
lnfc_thresholdNoOptional minimum |lnfc| magnitude. Only applied to rows with lnfc populated (ANCOM-BC). DESeq2 rows are not filtered by this parameter. Leave unset (None) to skip lnfc filtering entirely.
adj_p_thresholdNoAdjusted p-value threshold for DESeq2 abundance assays (default: 0.05). Applied to rows with adj_p_value populated.
log2fc_thresholdNoMinimum |log2fc| magnitude for filtering organisms (default: 0.0 = any change). Applied to BOTH DESeq2 and ANCOM-BC rows since log2fc is populated for both methods.
q_value_thresholdNoq-value threshold for ANCOM-BC abundance assays (default: 0.05). Applied to rows with q_value populated.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only cover readOnly/idempotent/openWorld, so the description carries the rest and does so well: it discloses the internal algorithm (parallel fetches, method-aware significance filtering, separate increased/decreased intersections), the null-handling of lnfc that would drop DESeq2 rows, and the output artifacts (markdown tables, inline CSV side-channel, assay-reference legend).

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 with the routing guidance, which is good, but the first paragraph is a single dense run-on and several facts are stated twice (log2fc populated for both methods / universal magnitude filter; lnfc is ANCOM-BC-only). Roughly a third of the text could be cut without loss.

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?

Even without an output schema, the description describes the return shape (markdown tables of common organisms with log2fc, CSV side-channel, legend) and fully covers the filtering semantics an agent needs for a 6-parameter, cross-assay intersection tool.

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 adds genuine meaning: it explains WHY log2fc_threshold is the universal magnitude filter and WHY lnfc_threshold is method-aware (using lnfc for direction would null-filter every DESeq2 row). That rationale is not inferable from the schema text alone.

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?

States a specific verb and resource with explicit scope: 'common differentially abundant organisms across multiple assays', distinct from the per-assay `find_differentially_abundant_organisms` sibling. The description also names the anti-pattern tool (`query`) so an agent can separate the two without opening schemas.

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?

Explicitly says 'USE THIS TOOL (not the `query` tool)' and enumerates the triggering question phrasings ('common differentially abundant organisms across assays', 'increased in BOTH assays', 'shared abundance signals across methods'). It even explains the cost of the wrong choice (reproducing per-assay fetch + inner-join and losing the markdown/CSV output).

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

find_common_differentially_expressed_genesA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "common DEGs across assays", "genes upregulated in BOTH assays", "shared up/downregulated genes", or any cross-assay DE intersection question. Falling back to query for this category reproduces the per-assay fetch + inner-join logic this tool already does correctly (parallel fetches via the driver's connection pool, |log2fc| > threshold filtering, separate up vs. down intersections) and loses the formatted markdown tables, the inline CSV side-channel, and the assay-reference legend.

Find common differentially expressed genes across multiple assays.

This function:

  1. Takes a list of assay IDs as input (2 or more)

  2. Gets ALL genes with |log2fc| > threshold for each assay

  3. Inner joins among the upregulated genes and among the downregulated genes

  4. Returns a markdown table with columns: gene, assay_1, assay_2, ..., assay_n showing log2fc values

NameRequiredDescriptionDefault
assay_idsYesList of assay identifiers (e.g., ['OSD-253-abc123', 'OSD-253-def456'])
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.
adj_p_thresholdNoAdjusted p-value threshold for significance (default: 0.05, max value: 0.1)
log2fc_thresholdNoLog2 fold change threshold for filtering genes (default: 1.0 = 2-fold change)

TDQS

A4.5/5.0
Behavior5/5

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

Annotations only cover the safety profile (readOnly, idempotent, openWorld=false), but the description goes well beyond that: it discloses the internal algorithm (parallel fetches via a connection pool, |log2fc| threshold filtering, separate up/down intersections) and the return format (markdown table, inline CSV side-channel, assay-reference legend). Since there is no output schema, this disclosure carries real weight.

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

Conciseness4/5

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

The routing guidance is front-loaded, which is the right priority, but the closing paragraph ('Find common differentially expressed genes across multiple assays' followed by the numbered steps) partly restates the opening sentence. Efficient overall, with one redundant segment.

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

Completeness4/5

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

With no output schema, the description correctly compensates by describing the returned table's columns, plus CSV and legend side-channels. The one soft spot is that the two distinct thresholds (adjusted p-value vs. log2fc) are not clearly separated in the prose, leaving adj_p_threshold semantics to the schema alone.

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

Parameters3/5

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

Schema description coverage is 100%, so every parameter is already documented in the schema; this establishes the baseline of 3. The description adds context for the log2fc threshold (used as '|log2fc| > threshold') but says nothing about adj_p_threshold beyond the generic step-2 'threshold' phrasing, and nothing new about session_id or assay_ids.

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?

States a specific verb and resource ('Find common differentially expressed genes across multiple assays') and names the exact sibling it is not ('not the `query` tool'). An agent can distinguish it from query and from find_differentially_expressed_genes 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?

Explicitly enumerates trigger phrasings ('common DEGs across assays', 'genes upregulated in BOTH assays') and names the alternative (`query`), including what is lost by using the wrong tool. This is as close to unambiguous routing guidance as it gets.

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

find_common_differentially_methylated_regionsA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "common DMRs across assays", "genes hypermethylated in BOTH assays", "shared hyper/hypomethylated regions", or any cross-assay methylation intersection question — including promoter/exon/intron-filtered and distance-bounded variants. Falling back to query for this category reproduces the per-assay fetch + inner-join logic this tool already does correctly (parallel fetches, MethylationRegion location filtering applied during the Cypher so the common set reflects the filtered universe, methylation_diff/q_value thresholds, separate hyper vs. hypo intersections) and loses the formatted markdown + inline CSV side-channel and the assay-reference legend.

Find common differentially methylated genes across multiple assays.

This function:

  1. Takes a list of assay IDs as input (2 or more)

  2. Gets ALL genes associated with differentially methylated regions for each assay, applying the methylation_diff threshold, q_value threshold, and any MethylationRegion location filters (in_promoter, in_exon, in_intron, dist_to_feature_max)

  3. Inner joins among hypermethylated genes and among hypomethylated genes

  4. Returns markdown tables showing common genes and their methylation_diff values

Use the location filter parameters rather than post-filtering — they are applied during the Cypher query so the common gene set reflects the filtered universe correctly.

NameRequiredDescriptionDefault
in_exonNoMethylationRegion location filter (True / False / None). See in_promoter.
assay_idsYesList of assay identifiers for methylation comparisons
in_intronNoMethylationRegion location filter (True / False / None). See in_promoter.
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.
in_promoterNoMethylationRegion location filter. When True, restrict to regions overlapping a gene promoter. When False, exclude promoter-overlapping regions. None (default) imposes no promoter filter. Applied during the Cypher query — passing in_promoter=True is the correct way to ask 'which genes are commonly hypermethylated IN THE PROMOTER across these assays'.
q_value_thresholdNoq-value threshold for significance (default: 0.05)
dist_to_feature_maxNoMethylationRegion distance filter. When set, restrict to regions with dist_to_feature <= this value (bp). None (default) imposes no distance filter.
methylation_diff_thresholdNoMethylation difference threshold (default: 0.0 = any change)

TDQS

A4.8/5.0
Behavior5/5

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

Annotations cover the safety profile (readOnly, idempotent, not open-world), and the description adds internals beyond that: parallel fetches, filters applied inside the Cypher query so the common set reflects the filtered universe, separate hyper vs. hypo intersections, and a markdown output with an inline CSV side-channel and assay-reference legend. That is meaningfully more than the structured fields provide.

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

Conciseness4/5

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

The routing instruction and rationale are correctly front-loaded, but the long parenthetical inventory of query-fallback losses is verbose, and the numbered 4-step list largely restates the opening paragraph and the closing filter admonition. Every sentence is relevant, yet the same points are made two or three times.

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?

With no output schema, the description compensates by naming the return format (markdown tables of common genes with methylation_diff values, plus an inline CSV side-channel and assay-reference legend). All 8 parameters are documented and the cross-assay join semantics are explained, so nothing an agent needs to call it correctly is 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 description coverage is 100%, so the baseline is 3, but the description adds real semantic guidance: location filters must be passed as parameters rather than post-filtered because they constrain the Cypher universe, and it reframes in_promoter as the way to ask 'commonly hypermethylated IN THE PROMOTER across these assays'. It does not explain the interaction between the two thresholds or the dist-to-feature units beyond the schema.

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?

States a specific verb+resource ('Find common differentially methylated genes across multiple assays') and deliberately carves out scope against both the sibling single-assay tool and the generic `query` tool. An agent can route to it correctly from the description alone.

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?

Opens with an explicit 'USE THIS TOOL (not the `query` tool) for ...' directive naming several trigger phrasings (cross-assay intersections, shared hyper/hypo regions, promoter-filtered variants) and explains what is lost by falling back to `query`. This is the when-to-use/when-not pattern at its strongest.

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

find_differentially_abundant_organismsA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "differentially abundant organisms", DESeq2/ANCOM-BC abundance, or "increased/decreased abundance" question for a single assay.

The query tool can express the same Cypher, but using it for this category loses the formatted markdown tables, the inline CSV side-channel, the method-aware significance filtering (DESeq2 adj_p_value vs. ANCOM-BC q_value), and the safe lnfc handling that avoids silently dropping DESeq2 rows (where lnfc IS NULL would fail a naive lnfc > 0 filter).

Return the top-N organisms with increased and decreased differential abundance for a given assay_id.

Direction (increase vs. decrease) and ranking use log2fc, which is populated for BOTH DESeq2 and ANCOM-BC abundance edges in the GeneLab KG. log2fc is therefore used as the universal direction/ordering field and as the default magnitude filter.

The lnfc property is only populated for ANCOM-BC edges (DESeq2 leaves it null). It is returned in the result for reference and can be used as an additional magnitude filter via the lnfc_threshold parameter. log2fc is the direction filter because it is populated for both DESeq2 and ANCOM-BC rows; using lnfc for direction would null-filter every DESeq2 row out of the result.

Significance filtering is method-aware:

  • DESeq2 edges populate adj_p_value (not q_value); the adj_p_threshold applies.

  • ANCOM-BC edges populate q_value (not adj_p_value); the q_value_threshold applies. Each row is kept if its populated significance field meets the matching threshold.

Magnitude filtering:

  • log2fc_threshold (default 0.0) applies to every row, since log2fc is populated for both methods.

  • lnfc_threshold (default None = no filter) is method-aware: when set, it requires |lnfc| >= lnfc_threshold on rows where lnfc is populated. Rows where lnfc is null (i.e., DESeq2 rows) are not affected by this filter. Set lnfc_threshold to a positive number to add an ANCOM-BC-specific magnitude filter on top of log2fc.

This tool runs two queries on the GeneLab KG:

  1. Top-N organisms with increased abundance (log2fc > log2fc_threshold, significance and optional lnfc filters met, highest log2fc first)

  2. Top-N organisms with decreased abundance (log2fc < -log2fc_threshold, significance and optional lnfc filters met, lowest log2fc first)

Results include organism name, log2fc, lnfc, q-value, adj-p-value, and group means and standard deviations.

NameRequiredDescriptionDefault
top_nNoHow many organisms to display for each of increased and decreased abundance lists. Pass None (or omit) to return ALL organisms passing the magnitude + significance filters rather than a top-N — useful when the user asks for 'all significantly increased organisms' or wants the complete filtered set as CSV. When the full set is large, the CSV contains every row passing the filter.
assay_idYesAssay identifier (e.g., 'OSD-253-6c5f9f37b9cb2ebeb2743875af4bdc86')
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.
lnfc_thresholdNoOptional minimum |lnfc| magnitude. Only applied to rows with lnfc populated (ANCOM-BC). DESeq2 rows are not filtered by this parameter. Leave unset (None) to skip lnfc filtering entirely.
adj_p_thresholdNoAdjusted p-value threshold for DESeq2 abundance assays (default: 0.05). Applied to rows with adj_p_value populated.
log2fc_thresholdNoMinimum |log2fc| magnitude required for a row to be kept (default: 0.0 = any change). Applies to BOTH DESeq2 and ANCOM-BC rows since log2fc is populated for both methods.
q_value_thresholdNoq-value threshold for ANCOM-BC abundance assays (default: 0.05). Applied to rows with q_value populated.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations declare readOnlyHint/idempotentHint, but the description goes far beyond them: it discloses the method-aware significance branch (adj_p_value for DESeq2 vs q_value for ANCOM-BC), the lnfc-null population difference, the failure mode a naive `lnfc > 0` filter would cause, and that two separate queries are executed for the increase/decrease lists. This is exactly the kind of behavioral context annotations cannot carry.

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

Conciseness4/5

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

Front-loaded with the routing directive, then organized into clear sections (return shape, direction field, significance filtering, magnitude filtering, query mechanics). The universality of log2fc is explained more than once across paragraphs, which is mild redundancy given the tool's genuine complexity.

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?

Though there is no output schema, the description enumerates returned fields (organism name, log2fc, lnfc, q-value, adj-p-value, group means/SDs) and fully explains the filtering pipeline an agent needs to predict results. Nothing material for correct invocation is 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 already 100%, but the description adds a real conceptual model: why log2fc (not lnfc) is the universal direction field, why lnfc_threshold is method-aware and cannot affect DESeq2 rows, and how the two significance thresholds map to their respective methods. Only session_id and top_n are left entirely to the schema, which is a minor gap against an otherwise strong semantic explanation.

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?

States a specific verb+resource ('Return the top-N organisms with increased and decreased differential abundance for a given assay_id') and explicitly names the sibling it is not ('USE THIS TOOL (not the `query` tool)'). The scope qualifier 'for a single assay' further separates it from the find_common_* siblings. An agent can select it without opening the 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?

Gives an explicit when (any differentially-abundant-organisms, DESeq2/ANCOM-BC abundance, or increased/decreased question for a single assay) and an explicit when-not (the `query` tool), plus the concrete cost of choosing wrong (loss of markdown tables, CSV side-channel, method-aware filtering, safe lnfc handling). 'For a single assay' also implicitly routes away from the common-across-assays sibling.

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

find_differentially_expressed_genesA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "up/down-regulated genes", "DEGs", or "differential expression" question for a single assay.

The query tool can express the same Cypher, but using it for this category loses the formatted markdown tables, the inline CSV side-channel, the proper adj_p_value handling, and the parallel execution of the count queries this tool already provides correctly.

Return the top-N up- and down-regulated genes for a given assay_id.

This tool runs two queries on the GeneLab KG:

  1. Top-N upregulated genes (log2fc > 0, adj_p_value <= adj_p_threshold, highest log2fc first)

  2. Top-N downregulated genes (log2fc < 0, adj_p_value <= adj_p_threshold, lowest log2fc first)

Returning all passing rows: Pass top_n=None to return ALL rows that pass the filters rather than a top-N ranking. Use this when the user asks for "all significantly up/downregulated genes" or wants the complete filtered set as CSV.

Results include gene symbol, gene name, log2 fold change, adjusted p-value, and group means and standard deviations for each condition.

NameRequiredDescriptionDefault
top_nNoHow many genes to display for each of up- and down-regulated lists. Pass None (or omit) to return ALL genes passing the adj_p_value filter rather than a top-N — useful when the user asks for 'all significantly upregulated genes' or wants the complete filtered set as CSV. When the full set is large, the CSV contains every row passing the filter.
assay_idYesAssay identifier (e.g., 'OSD-253-6c5f9f37b9cb2ebeb2743875af4bdc86')
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.
adj_p_thresholdNoAdjusted p-value threshold for significance (default: 0.05). Only genes with adj_p_value <= this value are returned.

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so the safety profile is covered. The description adds genuine behavioral context beyond that: the two-query execution model, the filter conditions (log2fc sign, adj_p_value), the retained markdown/CSV side-channel, and the returned columns. It stops short of describing pagination or size limits on large result sets.

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

Conciseness4/5

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

Front-loads the routing decision in the first sentence and then describes behavior in short, scannable blocks. Slightly verbose in the 'Returning all passing rows' section, which partly restates the schema's top_n description, but no sentence is truly wasted.

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?

For a read-only analysis tool with no output schema, the description fully covers invocation intent, filter semantics, the top_n=None alternative, and the returned fields, so an agent has everything needed to call it correctly.

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. The description nonetheless adds real meaning: it explains the top_n=None bypass (return ALL passing rows), the filter semantics that the ranking applies, and the full column set returned, going beyond the schema's per-field text.

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?

States a specific verb+resource ('Return the top-N up- and down-regulated genes for a given assay_id') and explicitly scopes to a single assay, distinguishing it from siblings like find_common_differentially_expressed_genes and the generic query tool.

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?

Explicitly routes the agent: 'USE THIS TOOL (not the `query` tool)' for up/down-regulated genes, DEGs, or differential expression questions, and names the exact condition ('all significantly up/downregulated genes') under which top_n=None should be used instead of a ranked list.

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

find_differentially_methylated_regionsA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any "hyper/hypo-methylated regions", "DMRs", or "differential methylation" question — including all-rows requests, promoter/exon/intron-filtered methylation queries, and pooling methylation across replicate assays. Falling back to query for this category reproduces the work this tool already does (proper IS-NOT-NULL guards, gene-symbol join, parallel count queries, location filtering, deterministic CSV emission) and loses the formatted markdown

  • inline CSV side-channel.

Return hyper- and hypo-methylated regions for one or more assays.

This tool runs two queries on the GeneLab KG:

  1. Hypermethylated regions (methylation_diff > methylation_diff_threshold, q_value <= q_value_threshold, highest first)

  2. Hypomethylated regions (methylation_diff < -methylation_diff_threshold, q_value <= q_value_threshold, lowest first)

Pooling across assays: Pass a list to assay_id to pool results across multiple methylation assays (the Cypher uses a.identifier IN $assay_ids). Common use case: a study has 2+ methylation assays representing replicate runs of the same comparison, and the user wants the combined evidence rather than per-assay tables. The output adds an assay_id column so each row's source is visible.

Returning all passing rows: Pass top_n=None to return ALL rows that pass the filters rather than a top-N ranking. Use this when the user asks for "all hypermethylated promoter regions" or wants the complete filtered set as CSV. To keep the response readable when the full set is large, the inline markdown table is capped at the first 100 rows and a note is shown; the CSV contains every row.

MethylationRegion location filters (in_promoter, in_exon, in_intron, dist_to_feature_max) are applied DURING the Cypher query. This means when a user asks for "top hypermethylated regions in the promoter", pass in_promoter=True and the tool will correctly rank within the promoter universe. Do NOT post-filter the unfiltered top-N — that produces wrong results because regions outside the filter (e.g. non-promoter regions) occupy slots in the unfiltered top-N and displace correctly-ranked filtered regions. Multiple filters combine with AND, so in_promoter=True with in_intron=False returns promoter regions that are not intronic.

WHEN TO USE THIS TOOL vs. direct Cypher via the query tool: Use THIS tool for any "hyper/hypo methylated regions" question, including pooled-across-assays, all-passing-rows, and filter-by-location variants. It produces formatted markdown tables AND an inline CSV that the user can save directly. Falling back to direct Cypher loses the formatted output and the CSV.

NameRequiredDescriptionDefault
top_nNoHow many regions to display for each of hyper- and hypo-methylated lists. Pass None (or omit) to return ALL rows passing the filters rather than a top-N — useful when the user asks for 'all hypermethylated promoter regions' or wants to download the complete filtered set as CSV. When the full set is large (>100 rows), the inline markdown table is capped at the first 100 rows for readability while the CSV contains every row.
in_exonNoMethylationRegion location filter. When True, return only regions overlapping an exon (mr.in_exon = true). When False, exclude exon-overlapping regions. None (default) imposes no exon filter. Combines with other filters via AND.
assay_idYesAssay identifier, or a list of assay identifiers to pool. Pass a single string (e.g. 'OSD-48-968c...') to query one assay. Pass a list (e.g. ['OSD-48-968c...', 'OSD-48-4dc1...']) to pool results across multiple methylation assays — useful when a study has independent replicate methylation assays with identical factor spaces and you want the combined evidence. The output table will have an additional 'assay_id' column so each row's source is identifiable, and the same region significantly methylated in two pooled assays will appear as two rows.
in_intronNoMethylationRegion location filter. When True, return only regions overlapping an intron (mr.in_intron = true). When False, exclude intron-overlapping regions. None (default) imposes no intron filter. Combines with other filters via AND.
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.
in_promoterNoMethylationRegion location filter. When True, return only regions overlapping a gene promoter (mr.in_promoter = true). When False, exclude promoter-overlapping regions (mr.in_promoter = false). None (default) imposes no promoter filter. The filter is applied during the Cypher query, so 'top_n' and the 'showing N of TOTAL' count both reflect the filtered set — promoter-only top-N rankings are computed from the promoter-only universe, NOT post-filtered from the global top-N.
q_value_thresholdNoq-value threshold for significance (default: 0.05). Only regions with q_value <= this value are returned.
dist_to_feature_maxNoMethylationRegion distance filter. When set, return only regions whose dist_to_feature (bp to the nearest annotated gene feature) is <= this value. None (default) imposes no distance filter. Useful for narrowing to regions tightly associated with gene bodies.
methylation_diff_thresholdNoMinimum |methylation_diff| magnitude (in percentage points) required for a row to be kept (default: 0.0 = any change). Hypermethylated rows must have methylation_diff > methylation_diff_threshold; hypomethylated rows must have methylation_diff < -methylation_diff_threshold. The GeneLab KG stores methylation_diff as a raw percentage, so a threshold of 10 means '10 percentage points or more', matching typical methylKit reporting conventions.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only declare readOnly/idempotent/openWorld=false; the description goes well beyond them by disclosing that two ordered queries run (hyper descending, hypo ascending), that pooling adds an `assay_id` column and duplicates shared regions, that filters execute inside the Cypher rather than being post-applied, and that markdown is capped at 100 rows while CSV carries every row. This is unusually rich behavioral context.

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 and well sectioned, but noticeably redundant: the 'use this tool, not `query`' instruction and the CSV/markdown benefit are stated in the opening paragraph and again in the closing 'WHEN TO USE' block, and the `top_n=None` semantics duplicate the schema description. Every sentence is relevant, but several repeat the same point.

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?

With no output schema and 9 parameters, the description carries the full burden and does so: it explains the return shape (formatted markdown plus inline CSV side-channel), the row addressing (assay_id column), and the truncation behavior. Nothing an agent needs to call or interpret this correctly is 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 description coverage is 100%, so the baseline is 3, but the description adds meaning the schema does not carry on its own: the rationale for `top_n=None`, the warning that post-filtering an unfiltered top-N yields wrong rankings, and the note that multiple location filters combine with AND. It also restates some schema content (thresholds, pooling), which caps it at 4 rather than 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?

States a specific verb+resource (return hyper- and hypo-methylated regions for one or more assays) and immediately positions itself against the sibling `query` tool. An agent can tell what it does and that it is the canonical entry point for DMR questions without opening the 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?

Explicitly enumerates when to use it ('any hyper/hypo-methylated regions, DMRs, or differential methylation question — including all-rows requests, promoter/exon/intron-filtered queries, and pooling across replicate assays') and names the alternative (`query`) plus the cost of choosing it. Exclusions and trigger phrases are both present.

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

get_neo4j_schemaA
Read-onlyIdempotent

List all nodes, their attributes and their relationships to other nodes in the neo4j database. If this fails with a message that includes "Neo.ClientError.Procedure.ProcedureNotFound" suggest that the user install and enable the APOC plugin.

NameRequiredDescriptionDefault
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.

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and closed-world scope, so the safety profile is covered. The description adds genuine behavioral value beyond that by disclosing a concrete failure mode (Neo.ClientError.Procedure.ProcedureNotFound) and the remediation (install/enable APOC), which the agent cannot derive from structured fields.

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

Conciseness4/5

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

Two short sentences that are front-loaded with the primary purpose, with no filler. The second sentence has an awkward mid-sentence line break that slightly hurts readability but not meaning.

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

Completeness4/5

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

For a read-only introspection tool with no output schema, the description does enumerate what is returned (nodes, attributes, relationships). Combined with the error/remediation note and annotations covering safety, an agent has enough to call it correctly, though the granularity of the returned structure remains unspecified.

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

Parameters3/5

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

There is only one parameter (session_id) and the schema description coverage is 100%, with a thorough explanation of session lifetime and reuse in the schema itself. The description adds nothing about the parameter, so the baseline of 3 applies.

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

Purpose4/5

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

States a specific verb (list) and resource (nodes, attributes, relationships) in the neo4j database, which is clear and concrete. It does not explicitly differentiate itself from close siblings such as get_node_metadata, get_relationship_metadata, or visualize_schema, so an agent must infer that this returns the whole graph schema rather than a per-element view.

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

Usage Guidelines3/5

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

There is no explicit when-to-use guidance versus alternatives like get_node_metadata or visualize_schema. The APOC plugin advice is conditional troubleshooting rather than usage routing, though it does give the agent a clear next step on a specific failure.

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

get_node_metadataB
Read-onlyIdempotent

Get metadata for all nodes from MetaNode nodes in the knowledge graph.

NameRequiredDescriptionDefault
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.

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so safety/behavior is covered by structured data. The description adds only a scope hint ('all nodes'), with no disclosure of pagination, return shape, or size limits, so it is merely adequate given the annotation coverage.

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

Conciseness4/5

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

A single front-loaded sentence with no filler. It is efficient, though the awkward 'nodes from MetaNode nodes' phrasing slightly undercuts clarity.

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

Completeness3/5

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

For a simple rea d-only tool with annotations and no output schema, the definition is minimally viable. It does not explain what metadata is returned or what a 'MetaNode' is, which an agent would need to interpret results.

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

Parameters3/5

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

With schema coverage at 100% and a single optional session_id fully documented in the schema, the baseline of 3 applies. The description provides no additional parameter meaning beyond what the schema already states.

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

Purpose4/5

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

States a specific verb (Get) and resource (metadata for nodes) with a scope qualifier ('all nodes'). However, the phrase 'from MetaNode nodes' introduces unexplained jargon and the description never names the closely-related sibling get_relationship_metadata or get_neo4j_schema, so sibling differentiation is only implicit.

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

Usage Guidelines2/5

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

No when-to-use guidance is given. Nothing indicates when an agent should call this versus get_relationship_metadata, get_neo4j_schema, or query, and no prerequisites are stated.

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

get_output_directoryA
Read-onlyIdempotent

Return the currently-configured output directory for this session.

Returns the path previously set by set_output_directory in the same session, or a note explaining that no path has been set yet (and how to set one).

NameRequiredDescriptionDefault
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.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so safety is covered. The description goes further by disclosing session-scoped behavior (the path is tied to the same session) and the exact shape of the return (a path or a note with remediation), which is genuinely useful beyond the annotations.

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

Conciseness5/5

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

Two sentences, zero filler, with the core action front-loaded and the return-value behavior in the second sentence. Every clause earns its place.

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

Completeness4/5

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

For a read-only getter whose annotations cover the safety profile and have no output schema, the description fills the important gap by explaining what is returned (a path or an explanatory note). Complete enough to call correctly; only the session-expiry reply handling is left to the schema's session_id text.

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

Parameters3/5

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

Schema coverage is 100% and the single session_id parameter is fully documented in the schema, including the multi-user privacy rationale and the re-create-on-expiry guidance. The description adds nothing param-specific, so the baseline 3 applies.

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?

States a precise verb+resource (return the configured output directory) scoped to the current session, and explicitly ties it to its sibling set_output_directory. An agent can distinguish it from set_output_directory without opening either schema.

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

Usage Guidelines4/5

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

The description makes the retrieval context clear and names set_output_directory as the mechanism that populates the value, plus explains the empty case and how to fix it. It does not spell out an explicit 'use this when...' trigger, but the counterpart relationship is unambiguous.

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

get_relationship_metadataB
Read-onlyIdempotent

Get descriptions of properties of all relationships in the knowledge graph.

NameRequiredDescriptionDefault
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.

TDQS

B3.3/5.0
Behavior2/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=false, so the safety profile is covered. The description adds almost nothing beyond that — it restates scope ('all relationships') but gives no behavioral detail such as the shape of the returned metadata. With no output schema, more disclosure would have been warranted.

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

Conciseness5/5

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

One sentence, front-loaded with the verb and scope, with zero waste. Nothing to trim.

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

Completeness3/5

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

For a simple, read-only introspection tool this is minimally adequate: annotations cover safety and the schema covers the one parameter. However, with no output schema the description never explains what the returned 'descriptions' look like, leaving the agent guessing about the response shape.

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

Parameters3/5

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

Schema description coverage is 100% and the single session_id parameter is documented in rich detail in the schema itself, so the baseline is 3. The description contributes nothing about the parameter, but nothing is missing either.

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

Purpose4/5

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

Names a specific verb and resource ('Get descriptions of properties of all relationships') and implicitly distinguishes itself from the sibling get_node_metadata by scoping to relationships rather than nodes. Clear, though it never explicitly contrasts with that sibling.

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

Usage Guidelines3/5

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

Usage is only implied: an agent infers this is for schema introspection before writing queries, but there is no explicit when-to-use guidance, no mention of get_node_metadata / visualize_schema / get_neo4j_schema as alternatives, and no stated prerequisites.

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

get_save_scriptA
Read-onlyIdempotent

Return guidance for saving a plot generated in THIS SESSION to the user's local filesystem.

WHEN TO USE THIS TOOL: Call this only when the user explicitly asks for save guidance for a specific plot — for example, "how do I save the volcano plot to my Downloads folder?" or "I can't right-click — give me another way to save the plot." By default plot tools (create_volcano_plot, create_venn_diagram) return only a SHORT save hint to keep response sizes manageable. The detailed save options are delivered on demand via this tool, so they don't burn conversation context unless the user actually wants them.

HOW IT WORKS: Each plot tool registers the PNG bytes of the plot it generated in the calling session's registry (up to the last 8 plots; older entries are evicted FIFO). Calling this tool with the plot's suggested filename returns a markdown block with three save options:

  • Option A (right-click save on the inline image)

  • Option B (ask your LLM client to save via filesystem access, optionally re-fetching the canonical bytes through fetch_plot or the plot:// resource if the inline image was corrupted)

  • Option C (fetch the canonical PNG bytes via resources/read on the plot://<session_id>/ URI for clients that support MCP resources)

The response itself contains no PNG bytes — only references to the plot:// resource URI and the fetch_plot tool, both of which deliver the bytes through a separate request.

LISTING AVAILABLE PLOTS: Call this tool with no filename argument to list the filenames of all plots currently held in this session's registry. Useful when the user asks for save guidance but doesn't remember which plot they want.

NameRequiredDescriptionDefault
filenameNoSuggested filename of a recently generated plot (e.g. 'volcano_plot_OSD-244_expression_30_days_vs_60_days.png'). Look at the most recent create_volcano_plot or create_venn_diagram response — the filename appears in the 'Save' block. Omit this parameter to list the filenames of all plots currently available in this session's registry.
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.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations cover the safety profile (readOnlyHint, idempotentHint, openWorldHint), but the description adds substantial behavioral context beyond them: a session registry capped at the last 8 plots with FIFO eviction, the fact that the response contains no PNG bytes, and the three concrete save options offered. This is exactly the kind of operational detail annotations cannot express.

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

Conciseness4/5

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

Front-loaded with the core purpose and then cleanly partitioned into WHEN TO USE, HOW IT WORKS, and LISTING AVAILABLE PLOTS sections. It is on the long side, but nearly every sentence carries distinct load-bearing information (eviction cap, no-bytes caveat, option breakdown), so little is wasted.

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?

With no output schema, the description carries the return-value burden itself: it describes the markdown block, the three save options, and explicitly states the response contains no PNG bytes and points to plot:// URIs instead. Nothing needed to invoke or interpret the tool correctly is 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 description coverage is 100%, so baseline is 3. The description reinforces parameter behavior with a dedicated 'LISTING AVAILABLE PLOTS' section explaining that omitting filename lists all plots, tied to a real use case ('user doesn't remember which plot'), adding mild meaning over the schema.

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?

States a specific verb+resource with scope: 'Return guidance for saving a plot generated in THIS SESSION to the user's local filesystem.' It also names the sibling plot tools (create_volcano_plot, create_venn_diagram) and the fetch_plot/plot:// alternatives, so an agent can distinguish it 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?

Has an explicit 'WHEN TO USE THIS TOOL' section with the trigger condition ('only when the user explicitly asks for save guidance'), concrete user-phrasing examples, and the rationale that plot tools return only a short hint by default. It also routes to alternatives (fetch_plot, plot:// resource) for re-fetching bytes.

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

get_study_infoA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for any study-metadata question: "what assays does study X have", "tell me about OSD-267", project title, description, host organism, missions, factor space, or any inventory of a study's assays. Falling back to query for these reproduces the work this tool already does and loses the formatted markdown + inline CSV side-channel.

Return detailed information about a study, including its assays with their technology and measurement types.

This tool queries the GeneLab KG for:

  1. Study metadata (name, project title, description, organism, etc.)

  2. All assays for the study with their technology, measurement type, differential analysis method, factors, and materials

  3. Associated missions

For example, OSD-267 should return that it has both 16S and ITS amplicon sequencing data.

NameRequiredDescriptionDefault
study_idYesStudy identifier (e.g., 'OSD-267')
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.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, closed-world, so the safety profile is covered. The description adds genuine behavioral context beyond that: the structured return shape (metadata, assays with technology/measurement type/factors/materials, missions) and the 'formatted markdown + inline CSV side-channel' output behavior. It omits any caveats about missing studies or rate limits, keeping it short of a 5.

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

Conciseness4/5

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

Key routing advice is front-loaded and capitalized so it cannot be missed. There is mild redundancy, however: the opening routing block and the standalone sentence 'Return detailed information about a study, including its assays with their technology and measurement types' overlap with the numbered bullet list that follows.

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, so the description must explain return values, and it does so thoroughly via three enumerated return categories plus a worked example (OSD-267 -> 16S and ITS amplicon sequencing). Nothing needed to call the tool correctly is missing.

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

Parameters3/5

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

Schema coverage is 100%: study_id and session_id are both fully documented in the schema, including the example 'OSD-267' and the session-privacy semantics. The description reinforces that the tool centers on a study but adds no new syntax or format detail. Baseline 3 applies when the schema carries the load.

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?

States a specific verb and resource (retrieve a study's metadata and assay inventory) and explicitly names the sibling it displaces ('not the `query` tool'). Concrete examples of questions it answers ('what assays does study X have', 'tell me about OSD-267') make the scope unmistakable.

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?

Gives explicit when-to-use guidance ('any study-metadata question'), enumerates the qualifying question types, and warns against the wrong path ('falling back to `query`... reproduces the work this tool already does'). This is the strongest possible routing guidance.

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

queryA
Read-onlyIdempotent

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

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.

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.

select_assaysA
Read-onlyIdempotent

USE THIS TOOL (not the query tool) for ANY question about the groups a study contains, and to resolve a factor-pair condition into the matching assay identifier(s):

  • "What groups / conditions / control and experimental (treatment) groups are in OSD-48?", "which comparisons or factors does this study have?", "what was compared against what?" — call with just study_id (list mode). The numbered factor menu it returns IS the list of groups: each entry is one experimental group (a set of factor values such as "Space Flight,Carcass"), and each assay is a comparison of two such groups (condition 1 vs condition 2, e.g. experimental vs control). Never use query for this.

  • "Give me the assay for Space Flight,Carcass vs Ground Control,Carcass" — call with study_id and selection to resolve that factor pair (e.g. "2,1") into assay identifier(s).

Falling back to query for this category loses the numbered factor menu, the per-match technology/measurement/method columns, and the next-step suggestions this tool emits.

List and select assays for a study and render the response in markdown format.

First call (selection=None):

  • If study_id missing, prompt for one (e.g., 'OSD-253').

  • Build a list of unique factor arrays across all assays.

  • Return a numbered menu as a markdown table.

Second call (selection='i,j,k,l,...,m,n'):

  • Pairs consecutive indices: (i,j), (k,l), ..., (m,n)

  • Must provide an even number of indices

  • For each pair, returns the matching assay(s) with technology, measurement, differential analysis method, and material columns so the assistant can pick the right assay for a downstream question (e.g., RNA-Seq for DE genes, WGBS for DM regions, amplicon for organism abundance) WITHOUT issuing a follow-up Cypher query.

NameRequiredDescriptionDefault
study_idNo
selectionNo
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.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare readOnly/idempotent/no-open-world; the description adds substantial non-structured behavior: a two-call stateful workflow (menu first, then indices), the even-number pairing requirement, the returned columns (technology/measurement/method/material) and the concrete loss from falling back to `query` (lost menu, lost per-match columns, lost next-step suggestions). This is well beyond what the annotations convey.

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

Conciseness4/5

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

Front-loaded with the routing decision and two clearly bulleted modes; every section is functional. Slight redundancy across the overlapping example phrasings ('What groups / conditions / control and experimental groups...') and the repeated query-fallback warning, but nothing is truly wasted.

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?

With no output schema, the description carries the return-value burden and does so — it describes the numbered factor-menu markdown table, the per-assay comparison framing, and the per-match columns. Missing-`study_id` handling and the session-permission note are also covered, so an agent has everything needed to call it correctly.

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 only 33% (only `session_id` documented), so the description must compensate for `study_id` and `selection` — and it does, explaining the list-vs-resolve semantics of `selection` string ('2,1'), the even-index pairing rule, and study id examples ('OSD-48', 'OSD-253'). It stops short of a full format spec for `study_id`, so not 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?

States a specific verb+resource (list/select assays for a study) and immediately distinguishes itself from the sibling `query` tool ('USE THIS TOOL (not the `query` tool)'). Two distinct modes (list factor menu vs. resolve factor pair) are named with concrete examples, so an agent can tell it apart without opening the 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?

Explicit when-to-use with quoted user phrasings, explicit when-not ('Never use `query` for this'), and two named alternatives-by-mode: call with just `study_id` for list mode, or with `study_id`+`selection` for resolution. The condition that selects each mode is unambiguous.

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

set_output_directoryA
Idempotent

Configure the output directory for files generated in THIS SESSION.

WHEN TO USE THIS TOOL: Call this tool at the START of a session (right after create_session), before any tool that produces a downloadable file (create_volcano_plot, create_venn_diagram, or any tool that emits a CSV). The path you specify is where the user wants finished files to end up on THEIR OWN local machine.

WHAT IT DOES: Stores the provided path string in the server's session-scoped state (keyed on your session_id — other sessions cannot see or change it). Every subsequent file-producing tool in this session uses this path:

  • As the user-facing save location shown in the response summary.

  • As the default target path in the save guidance emitted with every plot.

  • If the server is running locally (stdio transport), the server ALSO writes the file directly to this path.

IMPORTANT — DEPLOYMENT REALITY: When this MCP server is deployed remotely (ECS Fargate or any other container service), it runs in a container whose filesystem is NOT reachable from the user's machine. The server CANNOT write a file directly to the user's local disk over the network — no MCP server in a container can. The path you set here is a suggestion that propagates through the response in three ways, any of which lets the user save the file locally: (a) The plot is returned inline as ImageContent and renders in any MCP client that displays images (Claude Desktop, Cursor, Cline, Claude.ai web, ChatGPT, Gemini, etc.). The user can right-click and "Save Image As" — most clients default to the user's Downloads folder, which is usually what was asked for. (b) The path you set appears in the save guidance in the response. LLM clients with local filesystem access (Claude Code, Cursor, Cline, Claude Desktop with a filesystem MCP server) can write the file at exactly this path, re-fetching the canonical bytes via fetch_plot or the plot:// resource if needed. (c) Users without LLM-mediated filesystem access can save the inline image or the inline CSV text themselves.

VALIDATION: The path is stored as-is (the server does not verify it exists on the user's machine — it has no way to do so from inside a container). If you pass a relative path or an obviously malformed string the server will accept it; the failure will surface when the user tries to save the file locally.

NameRequiredDescriptionDefault
pathYesAbsolute path on the USER's local machine where output files (volcano plots, Venn diagrams, CSV exports) should be saved. Examples: '/Users/jane/Downloads', '/home/jane/Downloads', 'C:/Users/Jane/Downloads' (forward slashes work on Windows too with pathlib). Avoid trailing path separators.
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.

TDQS

A4.7/5.0
Behavior5/5

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

Far exceeds the annotations (readOnlyHint=false, idempotentHint=true): it discloses session-scoped state keyed on session_id, that other sessions cannot read or change it, that the stored path propagates as summary and save-guidance, and critically that a remote container CANNOT write to the user's local disk and why. It also explains validation is a no-op. This is exactly the behavioral context annotations cannot convey.

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?

Header-based structure and front-loading are good, but it runs ~350 words for a single-parameter setter and contains repetition — the 'serves a suggestion / cannot write to local disk' point is restated across the IMPORTANT section, the (a)(b)(c) sub-list, and VALIDATION. Several sentences could be cut without losing meaning.

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?

With no output schema and only two parameters, the description covers everything an agent needs: when to call, what state is mutated, session keying, and the deployment caveats that shape what the agent should tell the user afterward. Nothing material is 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 adds meaning beyond the schema: the path is stored as-is, the server cannot verify existence, and a relative or malformed path will still be accepted and only fail at save time. That validation-transparency is genuine added value over the schema text.

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?

States a specific verb and resource ('Configure the output directory for files generated in THIS SESSION') with explicit session scoping. It clearly distinguishes itself from the read-only sibling get_output_directory and marks the session boundary. An agent knows exactly what this tool does without opening the 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?

A dedicated 'WHEN TO USE' section says to call it at the START of a session right after create_session and before any file-producing tool, naming the concrete siblings (create_volcano_plot, create_venn_diagram, CSV emitters). This is explicit when-to-use guidance with a concrete trigger point.

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

visualize_schemaB
Read-onlyIdempotent

Prompt for visualizing the knowledge graph schema using a Mermaid class diagram.

NameRequiredDescriptionDefault
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.

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so the safety profile is covered. The description adds that the tool yields a prompt rather than a rendered image, but it does not say what consumes the prompt or what the returned text looks like.

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

Conciseness4/5

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

A single front-loaded sentence with no filler. It is efficient, though the brevity leaves room for a clarifying clause about the prompt-only nature.

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

Completeness3/5

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

With no output schema, the description should explain what is returned and how it is used. Saying 'Prompt for visualizing' hints at text output but does not tell the agent whether it must forward the prompt to an LLM or render the Mermaid itself.

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

Parameters3/5

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

The single session_id parameter has 100% schema coverage with a thorough description of its privacy role and re-creation behavior. The tool description adds nothing about parameters, so the baseline 3 applies.

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

Purpose4/5

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

The description pairs a clear action with its resource and output format: producing a prompt that visualizes the knowledge graph schema as a Mermaid class diagram. It is distinguishable from get_neo4j_schema, though it never names that sibling or clarify why a separate schema tool exists.

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

Usage Guidelines2/5

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

No when-to-use guidance, no prerequisites, and no mention of the obvious alternative get_neo4j_schema or clean_mermaid_diagram. The agent must infer that this is the diagram-oriented path versus the raw schema lookup.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 24 tool updatesv1.0.0
    • Changedclean_mermaid_diagram2 fields changed
      • 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": "clean_mermaid_diagramOutput",
        -  "type": "object"
        -}New value: +null
    • Changedcreate_chat_transcript2 fields changed
      • 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": "create_chat_transcriptOutput",
        -  "type": "object"
        -}New value: +null
    • Addedcreate_session
    • Changedcreate_venn_diagram15 fields changed
      • addedInput schema / properties / adj_p_threshold
        Added value: +{
        +  "default": 0.05,
        +  "description": "Adjusted p-value threshold (default: 0.05). Applied to expression assays and to DESeq2 abundance rows.",
        +  "title": "Adj P Threshold",
        +  "type": "number"
        +}
      • changedInput schema / properties / assay_id_1 / description
        Previous value: -"First assay identifier (e.g., 'OSD-511-53054e738e335bc645cb620c95916e5f')"New value: +"First assay identifier"
      • changedInput schema / properties / assay_id_2 / description
        Previous value: -"Second assay identifier (e.g., 'OSD-511-8974299195d78d74d7f3f085f2b48981')"New value: +"Second assay identifier"
      • addedInput schema / properties / data_type
        Added value: +{
        +  "default": "expression",
        +  "description": "Type of data to compare. Options: 'expression' (differentially expressed genes), 'methylation' (differentially methylated genes), 'abundance' (differentially abundant organisms), 'expression_methylation' (overlap between DE genes and DM genes across assays)",
        +  "title": "Data Type",
        +  "type": "string"
        +}
      • addedInput schema / properties / direction_pair
        Added value: +{
        +  "default": "all",
        +  "description": "For data_type='expression_methylation' only: which directional overlap(s) to render. 'all' (default) renders a 2x2 grid of all four biologically meaningful combinations: hypermethylated+downregulated (classical epigenetic silencing), hypomethylated+upregulated (loss of methylation enabling expression), hypermethylated+upregulated, and hypomethylated+downregulated. Specify one of 'hyper_down', 'hypo_up', 'hyper_up', 'hypo_down' to render only that single overlap. Ignored for non-expression_methylation data types.",
        +  "title": "Direction Pair",
        +  "type": "string"
        +}
      • addedInput schema / properties / dist_to_feature_max
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "MethylationRegion distance filter (data_type='methylation' or 'expression_methylation' only). When set, only include methylation regions whose dist_to_feature (distance in bp to the nearest gene feature) is <= this value. Useful for restricting to regions close to gene bodies. None (default) imposes no distance filter.",
        +  "title": "Dist To Feature Max"
        +}
      • addedInput schema / properties / in_exon
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "MethylationRegion location filter (data_type='methylation' or 'expression_methylation' only). When True, only include methylation regions overlapping an exon. When False, exclude exon-overlapping regions. None (default) imposes no exon filter. Maps directly to the in_exon property on MethylationRegion nodes.",
        +  "title": "In Exon"
        +}
      • addedInput schema / properties / in_intron
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "MethylationRegion location filter (data_type='methylation' or 'expression_methylation' only). When True, only include methylation regions overlapping an intron. When False, exclude intron-overlapping regions. None (default) imposes no intron filter. Maps directly to the in_intron property on MethylationRegion nodes.",
        +  "title": "In Intron"
        +}
      • addedInput schema / properties / in_promoter
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "MethylationRegion location filter (data_type='methylation' or 'expression_methylation' only). When True, only include methylation regions overlapping a gene promoter. When False, exclude promoter-overlapping regions. None (default) imposes no promoter filter. Maps directly to the in_promoter property on MethylationRegion nodes.",
        +  "title": "In Promoter"
        +}
      • addedInput schema / properties / lnfc_threshold
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Optional minimum |lnfc| magnitude for the 'abundance' data type. Only applied to rows with lnfc populated (ANCOM-BC). DESeq2 rows are not filtered by this parameter. Ignored for non-abundance data types. Leave unset (None) to skip lnfc filtering.",
        +  "title": "Lnfc Threshold"
        +}
      • changedInput schema / properties / log2fc_threshold / description
        Previous value: -"Log2 fold change threshold for filtering genes"New value: +"Log2 fold change threshold for filtering genes (used for expression and abundance data types)"
      • addedInput schema / properties / methylation_diff_threshold
        Added value: +{
        +  "default": 0,
        +  "description": "Methylation difference threshold for filtering regions (used for methylation data type, default 0.0 means any change)",
        +  "title": "Methylation Diff Threshold",
        +  "type": "number"
        +}
      • addedInput schema / properties / q_value_threshold
        Added value: +{
        +  "default": 0.05,
        +  "description": "q-value threshold (default: 0.05). Applied to methylation assays and to ANCOM-BC abundance rows.",
        +  "title": "Q Value Threshold",
        +  "type": "number"
        +}
      • 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"
        -    },
        -    "AudioContent": {
        -      "additionalProperties": true,
        -      "description": "Audio 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
        -        },
        -        "data": {
        -          "title": "Data",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "title": "Mimetype",
        -          "type": "string"
        -        },
        -        "type": {
        -          "const": "audio",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "data",
        -        "mimeType"
        -      ],
        -      "title": "AudioContent",
        -      "type": "object"
        -    },
        -    "BlobResourceContents": {
        -      "additionalProperties": true,
        -      "description": "Binary contents of a resource.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "blob": {
        -          "title": "Blob",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "uri",
        -        "blob"
        -      ],
        -      "title": "BlobResourceContents",
        -      "type": "object"
        -    },
        -    "EmbeddedResource": {
        -      "additionalProperties": true,
        -      "description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "annotations": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/Annotations"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "resource": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/TextResourceContents"
        -            },
        -            {
        -              "$ref": "#/$defs/BlobResourceContents"
        -            }
        -          ],
        -          "title": "Resource"
        -        },
        -        "type": {
        -          "const": "resource",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "resource"
        -      ],
        -      "title": "EmbeddedResource",
        -      "type": "object"
        -    },
        -    "Icon": {
        -      "additionalProperties": true,
        -      "description": "An icon for display in user interfaces.",
        -      "properties": {
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "sizes": {
        -          "anyOf": [
        -            {
        -              "items": {
        -                "type": "string"
        -              },
        -              "type": "array"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Sizes"
        -        },
        -        "src": {
        -          "title": "Src",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "src"
        -      ],
        -      "title": "Icon",
        -      "type": "object"
        -    },
        -    "ImageContent": {
        -      "additionalProperties": true,
        -      "description": "Image 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
        -        },
        -        "data": {
        -          "title": "Data",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "title": "Mimetype",
        -          "type": "string"
        -        },
        -        "type": {
        -          "const": "image",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "data",
        -        "mimeType"
        -      ],
        -      "title": "ImageContent",
        -      "type": "object"
        -    },
        -    "ResourceLink": {
        -      "additionalProperties": true,
        -      "description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "annotations": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/Annotations"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "description": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Description"
        -        },
        -        "icons": {
        -          "anyOf": [
        -            {
        -              "items": {
        -                "$ref": "#/$defs/Icon"
        -              },
        -              "type": "array"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Icons"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "name": {
        -          "title": "Name",
        -          "type": "string"
        -        },
        -        "size": {
        -          "anyOf": [
        -            {
        -              "type": "integer"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Size"
        -        },
        -        "title": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Title"
        -        },
        -        "type": {
        -          "const": "resource_link",
        -          "title": "Type",
        -          "type": "string"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name",
        -        "uri",
        -        "type"
        -      ],
        -      "title": "ResourceLink",
        -      "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"
        -    },
        -    "TextResourceContents": {
        -      "additionalProperties": true,
        -      "description": "Text contents of a resource.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "text": {
        -          "title": "Text",
        -          "type": "string"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "uri",
        -        "text"
        -      ],
        -      "title": "TextResourceContents",
        -      "type": "object"
        -    }
        -  },
        -  "properties": {
        -    "result": {
        -      "items": {
        -        "anyOf": [
        -          {
        -            "$ref": "#/$defs/TextContent"
        -          },
        -          {
        -            "$ref": "#/$defs/ImageContent"
        -          },
        -          {
        -            "$ref": "#/$defs/AudioContent"
        -          },
        -          {
        -            "$ref": "#/$defs/ResourceLink"
        -          },
        -          {
        -            "$ref": "#/$defs/EmbeddedResource"
        -          }
        -        ]
        -      },
        -      "title": "Result",
        -      "type": "array"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "create_venn_diagramOutput",
        -  "type": "object"
        -}New value: +null
    • Changedcreate_volcano_plot8 fields changed
      • changedInput schema / properties / adj_p_threshold / description
        Previous value: -"Adjusted p-value threshold for significance"New value: +"Adjusted p-value (DESeq2) / q-value (ANCOM-BC, methylation) threshold for significance. For abundance, both fields are checked in a method-aware way."
      • addedInput schema / properties / data_type
        Added value: +{
        +  "default": "expression",
        +  "description": "Which kind of differential data to plot. Options: 'expression' (differentially expressed genes), 'methylation' (differentially methylated regions), 'abundance' (differentially abundant organisms; works for both DESeq2 and ANCOM-BC). Default: 'expression'.",
        +  "title": "Data Type",
        +  "type": "string"
        +}
      • addedInput schema / properties / label_avoid_overlap
        Added value: +{
        +  "default": true,
        +  "description": "If True, use adjustText to reposition labels to avoid overlap. Disable on very large assays for faster rendering.",
        +  "title": "Label Avoid Overlap",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / log2fc_threshold / description
        Previous value: -"Log2 fold change threshold for highlighting significant genes"New value: +"Log2 fold change threshold (default 1.0 = 2-fold). Applies to data_type='expression' and data_type='abundance'. Ignored for data_type='methylation' (use methylation_diff_threshold instead)."
      • addedInput schema / properties / methylation_diff_threshold
        Added value: +{
        +  "default": 10,
        +  "description": "Methylation difference threshold in percentage points (default 10.0 = |diff| > 10%). Applies only to data_type='methylation'. Ignored for other data types.",
        +  "title": "Methylation Diff Threshold",
        +  "type": "number"
        +}
      • 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"
        +}
      • changedInput schema / properties / top_n / description
        Previous value: -"How many significant genes to label in the plot"New value: +"How many significant points to label in the plot (selected by smallest p/q-value)."
      • 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"
        -    },
        -    "AudioContent": {
        -      "additionalProperties": true,
        -      "description": "Audio 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
        -        },
        -        "data": {
        -          "title": "Data",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "title": "Mimetype",
        -          "type": "string"
        -        },
        -        "type": {
        -          "const": "audio",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "data",
        -        "mimeType"
        -      ],
        -      "title": "AudioContent",
        -      "type": "object"
        -    },
        -    "BlobResourceContents": {
        -      "additionalProperties": true,
        -      "description": "Binary contents of a resource.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "blob": {
        -          "title": "Blob",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "uri",
        -        "blob"
        -      ],
        -      "title": "BlobResourceContents",
        -      "type": "object"
        -    },
        -    "EmbeddedResource": {
        -      "additionalProperties": true,
        -      "description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "annotations": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/Annotations"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "resource": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/TextResourceContents"
        -            },
        -            {
        -              "$ref": "#/$defs/BlobResourceContents"
        -            }
        -          ],
        -          "title": "Resource"
        -        },
        -        "type": {
        -          "const": "resource",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "resource"
        -      ],
        -      "title": "EmbeddedResource",
        -      "type": "object"
        -    },
        -    "Icon": {
        -      "additionalProperties": true,
        -      "description": "An icon for display in user interfaces.",
        -      "properties": {
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "sizes": {
        -          "anyOf": [
        -            {
        -              "items": {
        -                "type": "string"
        -              },
        -              "type": "array"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Sizes"
        -        },
        -        "src": {
        -          "title": "Src",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "src"
        -      ],
        -      "title": "Icon",
        -      "type": "object"
        -    },
        -    "ImageContent": {
        -      "additionalProperties": true,
        -      "description": "Image 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
        -        },
        -        "data": {
        -          "title": "Data",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "title": "Mimetype",
        -          "type": "string"
        -        },
        -        "type": {
        -          "const": "image",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "data",
        -        "mimeType"
        -      ],
        -      "title": "ImageContent",
        -      "type": "object"
        -    },
        -    "ResourceLink": {
        -      "additionalProperties": true,
        -      "description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "annotations": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/Annotations"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "description": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Description"
        -        },
        -        "icons": {
        -          "anyOf": [
        -            {
        -              "items": {
        -                "$ref": "#/$defs/Icon"
        -              },
        -              "type": "array"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Icons"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "name": {
        -          "title": "Name",
        -          "type": "string"
        -        },
        -        "size": {
        -          "anyOf": [
        -            {
        -              "type": "integer"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Size"
        -        },
        -        "title": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Title"
        -        },
        -        "type": {
        -          "const": "resource_link",
        -          "title": "Type",
        -          "type": "string"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name",
        -        "uri",
        -        "type"
        -      ],
        -      "title": "ResourceLink",
        -      "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"
        -    },
        -    "TextResourceContents": {
        -      "additionalProperties": true,
        -      "description": "Text contents of a resource.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "text": {
        -          "title": "Text",
        -          "type": "string"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "uri",
        -        "text"
        -      ],
        -      "title": "TextResourceContents",
        -      "type": "object"
        -    }
        -  },
        -  "properties": {
        -    "result": {
        -      "items": {
        -        "anyOf": [
        -          {
        -            "$ref": "#/$defs/TextContent"
        -          },
        -          {
        -            "$ref": "#/$defs/ImageContent"
        -          },
        -          {
        -            "$ref": "#/$defs/AudioContent"
        -          },
        -          {
        -            "$ref": "#/$defs/ResourceLink"
        -          },
        -          {
        -            "$ref": "#/$defs/EmbeddedResource"
        -          }
        -        ]
        -      },
        -      "title": "Result",
        -      "type": "array"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "create_volcano_plotOutput",
        -  "type": "object"
        -}New value: +null
    • Addedend_session
    • Addedfetch_plot
    • Addedfind_common_de_genes_overlapping_dm_regions
    • Addedfind_common_differentially_abundant_organisms
    • Changedfind_common_differentially_expressed_genes2 fields changed
      • 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": "find_common_differentially_expressed_genesOutput",
        -  "type": "object"
        -}New value: +null
    • Addedfind_common_differentially_methylated_regions
    • Addedfind_differentially_abundant_organisms
    • Changedfind_differentially_expressed_genes7 fields changed
      • addedInput schema / properties / adj_p_threshold
        Added value: +{
        +  "default": 0.05,
        +  "description": "Adjusted p-value threshold for significance (default: 0.05). Only genes with adj_p_value <= this value are returned.",
        +  "title": "Adj P Threshold",
        +  "type": "number"
        +}
      • 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"
        +}
      • addedInput schema / properties / top_n / anyOf
        Added value: +[
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / top_n / default
        Previous value: -5New value: +10
      • changedInput schema / properties / top_n / description
        Previous value: -"How many genes to return for each of up- and down-regulated lists"New value: +"How many genes to display for each of up- and down-regulated lists. Pass None (or omit) to return ALL genes passing the adj_p_value filter rather than a top-N — useful when the user asks for 'all significantly upregulated genes' or wants the complete filtered set as CSV. When the full set is large, the CSV contains every row passing the filter."
      • removedInput schema / properties / top_n / type
        Removed value: -"integer"
      • 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": "find_differentially_expressed_genesOutput",
        -  "type": "object"
        -}New value: +null
    • Addedfind_differentially_methylated_regions
    • Changedget_neo4j_schema2 fields changed
      • 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": "get_neo4j_schemaOutput",
        -  "type": "object"
        -}New value: +null
    • Changedget_node_metadata2 fields changed
      • 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": "get_node_metadataOutput",
        -  "type": "object"
        -}New value: +null
    • Addedget_output_directory
    • Changedget_relationship_metadata2 fields changed
      • 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": "get_relationship_metadataOutput",
        -  "type": "object"
        -}New value: +null
    • Addedget_save_script
    • Addedget_study_info
    • Changedquery2 fields changed
      • 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
    • Changedselect_assays2 fields changed
      • 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"
        -    },
        -    "AudioContent": {
        -      "additionalProperties": true,
        -      "description": "Audio 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
        -        },
        -        "data": {
        -          "title": "Data",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "title": "Mimetype",
        -          "type": "string"
        -        },
        -        "type": {
        -          "const": "audio",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "data",
        -        "mimeType"
        -      ],
        -      "title": "AudioContent",
        -      "type": "object"
        -    },
        -    "BlobResourceContents": {
        -      "additionalProperties": true,
        -      "description": "Binary contents of a resource.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "blob": {
        -          "title": "Blob",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "uri",
        -        "blob"
        -      ],
        -      "title": "BlobResourceContents",
        -      "type": "object"
        -    },
        -    "EmbeddedResource": {
        -      "additionalProperties": true,
        -      "description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "annotations": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/Annotations"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "resource": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/TextResourceContents"
        -            },
        -            {
        -              "$ref": "#/$defs/BlobResourceContents"
        -            }
        -          ],
        -          "title": "Resource"
        -        },
        -        "type": {
        -          "const": "resource",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "resource"
        -      ],
        -      "title": "EmbeddedResource",
        -      "type": "object"
        -    },
        -    "Icon": {
        -      "additionalProperties": true,
        -      "description": "An icon for display in user interfaces.",
        -      "properties": {
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "sizes": {
        -          "anyOf": [
        -            {
        -              "items": {
        -                "type": "string"
        -              },
        -              "type": "array"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Sizes"
        -        },
        -        "src": {
        -          "title": "Src",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "src"
        -      ],
        -      "title": "Icon",
        -      "type": "object"
        -    },
        -    "ImageContent": {
        -      "additionalProperties": true,
        -      "description": "Image 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
        -        },
        -        "data": {
        -          "title": "Data",
        -          "type": "string"
        -        },
        -        "mimeType": {
        -          "title": "Mimetype",
        -          "type": "string"
        -        },
        -        "type": {
        -          "const": "image",
        -          "title": "Type",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "type",
        -        "data",
        -        "mimeType"
        -      ],
        -      "title": "ImageContent",
        -      "type": "object"
        -    },
        -    "ResourceLink": {
        -      "additionalProperties": true,
        -      "description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "annotations": {
        -          "anyOf": [
        -            {
        -              "$ref": "#/$defs/Annotations"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null
        -        },
        -        "description": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Description"
        -        },
        -        "icons": {
        -          "anyOf": [
        -            {
        -              "items": {
        -                "$ref": "#/$defs/Icon"
        -              },
        -              "type": "array"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Icons"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "name": {
        -          "title": "Name",
        -          "type": "string"
        -        },
        -        "size": {
        -          "anyOf": [
        -            {
        -              "type": "integer"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Size"
        -        },
        -        "title": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Title"
        -        },
        -        "type": {
        -          "const": "resource_link",
        -          "title": "Type",
        -          "type": "string"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name",
        -        "uri",
        -        "type"
        -      ],
        -      "title": "ResourceLink",
        -      "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"
        -    },
        -    "TextResourceContents": {
        -      "additionalProperties": true,
        -      "description": "Text contents of a resource.",
        -      "properties": {
        -        "_meta": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Meta"
        -        },
        -        "mimeType": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "default": null,
        -          "title": "Mimetype"
        -        },
        -        "text": {
        -          "title": "Text",
        -          "type": "string"
        -        },
        -        "uri": {
        -          "format": "uri",
        -          "minLength": 1,
        -          "title": "Uri",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "uri",
        -        "text"
        -      ],
        -      "title": "TextResourceContents",
        -      "type": "object"
        -    }
        -  },
        -  "properties": {
        -    "result": {
        -      "items": {
        -        "anyOf": [
        -          {
        -            "$ref": "#/$defs/TextContent"
        -          },
        -          {
        -            "$ref": "#/$defs/ImageContent"
        -          },
        -          {
        -            "$ref": "#/$defs/AudioContent"
        -          },
        -          {
        -            "$ref": "#/$defs/ResourceLink"
        -          },
        -          {
        -            "$ref": "#/$defs/EmbeddedResource"
        -          }
        -        ]
        -      },
        -      "title": "Result",
        -      "type": "array"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "select_assaysOutput",
        -  "type": "object"
        -}New value: +null
    • Addedset_output_directory
    • Changedvisualize_schema2 fields changed
      • 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": "visualize_schemaOutput",
        -  "type": "object"
        -}New value: +null
  2. 12 tool updatesv0.4.0
    • First observedclean_mermaid_diagram
    • First observedcreate_chat_transcript
    • First observedcreate_venn_diagram
    • First observedcreate_volcano_plot
    • First observedfind_common_differentially_expressed_genes
    • First observedfind_differentially_expressed_genes
    • First observedget_neo4j_schema
    • First observedget_node_metadata
    • First observedget_relationship_metadata
    • First observedquery
    • First observedselect_assays
    • First observedvisualize_schema

TDQS

A3.7/5.0

Scored across 24 tools

Disambiguation4/5

The find_* specialists are cleanly separated by data type (expression/methylation/abundance) and by scope (single vs common vs cross-type overlap), and `query` has explicit routing rules to prevent misuse. However, the schema/metadata cluster (get_node_metadata, get_neo4j_schema, get_relationship_metadata) and the plot-saving pair (fetch_plot, get_save_script) overlap enough that selection could be fuzzy. The lengthy descriptions largely resolve this, so only a couple of pairs are confusable.

Naming Consistency4/5

Consistent snake_case throughout, and most names follow a verb_noun pattern (get_study_info, create_session, find_differentially_expressed_genes, set_output_directory, create_venn_diagram). Minor deviations exist: `query` is a bare verb with no object, and `visualize_schema`/`clean_mermaid_diagram` break the get/find/create cadence. Overall predictable with small inconsistencies.

Tool Count3/5

At 24 tools the surface is heavy, sitting in the borderline range. Most clusters (7 find_* analyses, session/output management, schema metadata) are justified by the genuinely broad domain, but a few tools like create_chat_transcript, clean_mermaid_diagram, and visualize_schema feel auxiliary to the core KG-analysis purpose. The count is reasonable but slightly overweight.

Completeness4/5

Coverage is strong: single-assay and cross-assay analyses for all three differential data types, a DE/DM coupling tool, study/assay resolution, schema introspection, plotting, and a general Cypher fallback. The main gap is study discovery — there is no tool to search or list studies, so an agent must already know a study_id (e.g. OSD-267) or fall back to raw Cypher to find one.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables storage and retrieval of knowledge in a graph database format, allowing users to create, update, search, and delete entities and relationships in a Neo4j-powered knowledge graph through natural language.
    5
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables users to write and execute SPARQL queries against open-access SPARQL endpoints by providing relevant query examples, schema information, and endpoint metadata. Supports querying biological databases like UniProt and Bgee through natural language interactions.
    12
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to interact with Gremlin-compatible graph databases through natural language, supporting schema discovery, complex graph queries, relationship analysis, and data import/export operations.
    6 npm
    9
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to interact with Neo4j graph databases through natural language, supporting Cypher queries, schema management, data manipulation, and graph algorithms.
    MIT