""" Model Context Protocol (MCP) for Paper2Agent This codebase provides comprehensive bioinformatics analysis tools for transcriptomics data using the decoupler package. It supports bulk RNA-seq, single-cell RNA-seq, spatial transcriptomics, and pseudotime analysis workflows. The tools enable enrichment analysis, transcription factor activity scoring, pathway analysis, and cross-species gene mapping for functional genomics research. DATASET DECISION TREE ═══════════════════════════════════════════════════════════════════════ STEP 0 (if data lives in GEO): → decoupler_load_geo_series_matrix(url_or_path, condition_column=...) This downloads, parses, and saves an h5ad. Then proceed to STEP 1. STEP 1 — Always start with: decoupler_inspect_data(adata_path) Check: is_integer, has_negatives, likely_raw_counts, n_obs, orientation_warning STEP 2 — If orientation_warning is set: The matrix is transposed (genes as rows). Fix it before proceeding. STEP 3 — Choose path based on inspect results: PATH A — Raw counts (likely_raw_counts=True) decoupler_load_and_filter_data → decoupler_preprocess_data → decoupler_differential_expression(method='deseq2') → enrichment tools PATH B — Pre-normalized / log-transformed (data_type='log_expression' or 'log_ratio_microarray') Examples: GEO microarray, log-CPM, log-TPM, log-normalized scRNA-seq SKIP decoupler_preprocess_data entirely. Step 2a (microarray only — if features_look_like_probes=True): → decoupler_collapse_probes_to_genes # map probe IDs → gene symbols before DE Skip this step for RNA-seq (features are already gene symbols). Step 2b: → decoupler_differential_expression(method='ttest') # no R required → decoupler_differential_expression(method='limma') # preferred if R available → enrichment tools ⚠ Do NOT use method='deseq2' or decoupler_preprocess_data on pre-normalized data. PATH UNKNOWN — data_type='unknown' (heuristics inconclusive) Default to PATH B with method='ttest'. Ask the user to confirm data is not raw integer counts before proceeding. If it is, switch to PATH A with method='deseq2'. ═══════════════════════════════════════════════════════════════════════ This MCP Server contains tools extracted from the following tutorial files: 1. example - decoupler_load_toy_data: Load toy dataset and visualize gene expression patterns - decoupler_run_individual_methods: Run individual enrichment methods (GSEA and ULM) - decoupler_run_multiple_methods: Run all enrichment methods and compute consensus scores - decoupler_access_prior_knowledge: Query OmniPath resources for prior knowledge networks 2. licenses - decoupler_collect_transcriptional_regulators: Collect transcriptional regulator data with specified license - decoupler_access_resource_database: Access specific OmniPath resources with license restrictions 3. orthologs - decoupler_show_supported_organisms: Display organisms supported for ortholog translation - decoupler_load_knowledge_base: Load human-centric knowledge database resource - decoupler_translate_gene_symbols: Convert gene symbols from human to target organism - decoupler_access_organism_database: Directly load database with organism-specific gene symbols 4. rna - decoupler_inspect_data: Inspect data structure, detect orientation and data type, recommend analysis path - decoupler_load_geo_series_matrix: Download and parse a GEO series matrix URL or file into h5ad - decoupler_annotate_probes_with_gpl: Add gene symbols to var from a GPL platform SOFT file (required before probe collapse) - decoupler_collapse_probes_to_genes: Collapse microarray probe IDs to gene symbols before enrichment - decoupler_load_and_filter_data: Load bulk RNA-seq data and apply expression filtering - decoupler_preprocess_data: Normalize, scale and perform PCA analysis on bulk RNA-seq data (raw counts only) - decoupler_differential_expression: Differential expression via DESeq2, limma, or t-test (method parameter) - decoupler_tf_enrichment_collectri: TF enrichment using CollecTRI; auto-selects top TFs for network plot - decoupler_pathway_enrichment_progeny: Perform pathway enrichment analysis using PROGENy - decoupler_hallmark_enrichment: Perform hallmark gene set enrichment analysis 5. rna_pstime - decoupler_load_and_explore_data: Load and explore single-cell data with initial visualizations - decoupler_infer_pseudotime: Infer pseudotime trajectories using diffusion maps and DPT - decoupler_analyze_tf_activity: Analyze transcription factor activity along pseudotime - decoupler_analyze_pathway_activity: Analyze pathway activity using PROGENy along pseudotime - decoupler_analyze_hallmark_pathways: Analyze Hallmark pathway activity along pseudotime 6. rna_sc - decoupler_load_and_visualize_data: Load single-cell data and create initial UMAP visualization - decoupler_score_cell_types: Score cells using marker genes from PanglaoDB - decoupler_score_transcription_factors: Score cells using transcription factor networks from CollecTRI - decoupler_score_progeny_pathways: Score cells using PROGENy pathway gene sets - decoupler_score_hallmark_pathways: Score cells using Hallmark gene sets 7. rna_visium - decoupler_load_and_preprocess_visium: Load and preprocess spatial transcriptomics data with normalization - decoupler_apply_spatial_weighting: Apply spatial connectivity weighting to gene expression data - decoupler_score_transcription_factors: Score transcription factor activity using CollecTRI network - decoupler_score_progeny_pathways: Score pathway activity using PROGENy pathway database - decoupler_score_hallmark_pathways: Score pathway activity using Hallmark gene sets """ import os import sys import warnings PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) # ── R dependency installation ──────────────────────────────────────────────── # Run once at startup so limma is available when decoupler_differential_expression # is called with method='limma'. Failures are non-fatal: the rna.py tool # handles a missing limma gracefully via fallback_to_ttest or RuntimeError. try: from src.mcp_server.dependencies.r_dependencies import ensure_r_dependencies ensure_r_dependencies() except FileNotFoundError as _e: warnings.warn(f"R install script not found, skipping R setup: {_e}", stacklevel=2) except Exception as _e: warnings.warn(f"R dependency installation failed, limma may be unavailable: {_e}", stacklevel=2) from fastmcp import FastMCP # Import statements (alphabetical order) from src.tools.bulk_dataset_tools import bulk_dataset_mcp from src.tools.bulk_rnaseq import bulk_rnaseq_mcp from src.tools.dataset_tools import dataset_mcp from src.tools.example import example_mcp from src.tools.integration_tools import integration_mcp from src.tools.licenses import licenses_mcp from src.tools.orthologs import orthologs_mcp from src.tools.rna import rna_mcp from src.tools.rna_pstime import rna_pstime_mcp from src.tools.rna_sc import rna_sc_mcp from src.tools.rna_visium import rna_visium_mcp # Server definition and mounting mcp = FastMCP(name="Paper2Agent") mcp.mount(bulk_dataset_mcp) mcp.mount(bulk_rnaseq_mcp) mcp.mount(dataset_mcp) mcp.mount(example_mcp) mcp.mount(integration_mcp) mcp.mount(licenses_mcp) mcp.mount(orthologs_mcp) mcp.mount(rna_mcp) mcp.mount(rna_pstime_mcp) mcp.mount(rna_sc_mcp) mcp.mount(rna_visium_mcp) import threading from src.cache import preload_datasets # Pre-populate the disk cache in a background thread (pure Python/numpy/scanpy, # no rpy2 — safe to run concurrently with tool calls). # R/limma installation is handled at module import above (already synchronous). threading.Thread(target=preload_datasets, daemon=True, name="cache-preloader").start() if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(add_help=False) parser.add_argument("--transport", default=None) parser.add_argument("--port", type=int, default=8765) args, _ = parser.parse_known_args() if args.transport: # HTTP mode: persistent server, accepts multiple connections mcp.run(transport=args.transport, host="0.0.0.0", port=args.port) else: # stdio mode: default for MCP clients that spawn a subprocess per call mcp.run()