The basic development way to create a mcp server is using mcp/fastmcp you can refer to their documentation for detailed guide. Here we just introduce the API in scmcphub, which is designed to reuse existing tools and further reduce the difficulty of MCP development.

BaseMCPManager

The BaseMCPManager is the core class for creating MCP servers in scmcphub. It provides a standardized way to manage multiple MCP modules with built-in filtering capabilities. For a complete reference documentation, see BaseMCPManager Reference.

Key Features

  1. Module Management: Automatically handles module registration and organization
  2. Filtering: Built-in support for including/excluding modules and tools
  3. Backend Integration: Seamless integration with different backend managers
  4. Tag-based Filtering: Support for filtering tools based on tags
  5. Async Support: Proper async/await handling for server lifespan

Basic Usage

from scmcp_shared.mcp_base import BaseMCPManager
from scmcp_shared.backend import AdataManager

class MyMCPManager(BaseMCPManager):
    def init_mcp(self):
        self.available_modules = {
            "io": io_mcp,
            "pp": pp_mcp,
            "tl": tl_mcp,
        }

# Create and use
manager = MyMCPManager("my-mcp", backend=AdataManager)
mcp = manager.mcp
For detailed usage examples, best practices, and troubleshooting, see the complete BaseMCPManager reference.

Backend Access Functions

The get_ads and get_nbm functions are essential for accessing backend managers within MCP tools. These functions provide access to the appropriate backend based on the execution mode. For complete documentation, see Backend Functions Reference.

Quick Overview

get_ads() - Tool Mode Backend

  • Purpose: Access AdataManager for AnnData operations
  • Mode: Tool Mode (tool-mode)
  • Returns: AdataManager instance

get_nbm() - Code Mode Backend

  • Purpose: Access NotebookManager for Jupyter notebook operations
  • Mode: Code Mode (code-mode)
  • Returns: NotebookManager instance

Usage Examples

Tool Mode Example

from scmcp_shared.util import get_ads
from scmcp_shared.schema import AdataInfo

@mcp.tool()
def process_data(adinfo: AdataInfo):
    """Process AnnData using AdataManager."""
    ads = get_ads()  # Get AdataManager
    adata = ads.get_adata(adinfo=adinfo)
    
    # Process the data
    # ... processing logic ...
    
    return {"message": "Data processed successfully"}

Code Mode Example

from scmcp_shared.util import get_nbm

@mcp.tool(tags=["nb"])
def execute_code(code: str):
    """Execute code in Jupyter notebook."""
    nbm = get_nbm()  # Get NotebookManager
    jce = nbm.active_notebook
    result = jce.execute(code)
    
    return {
        "notebook_id": nbm.active_nbid,
        "result": result
    }

Backend Selection

The choice between get_ads and get_nbm depends on your server configuration:
  • AdataManager Backend: Use get_ads() for tool-mode
  • NotebookManager Backend: Use get_nbm() for code-mode

AdataManager

The AdataManager is the primary backend manager for handling AnnData objects in tool mode. It provides centralized management of multiple AnnData objects with different data types and sample IDs.

Key Features

  • Multi-type Support: Manages different types of AnnData (exp, activity, cnv, splicing)
  • Sample ID Management: Tracks and organizes data by sample identifiers
  • Active Sample Tracking: Maintains the currently active sample for operations
  • Data Consistency: Ensures proper data access and storage patterns

Basic Usage

from scmcp_shared.backend import AdataManager
from scmcp_shared.schema import AdataInfo
import scanpy as sc

# Initialize manager
ads = AdataManager()

# Set active sample
ads.active_id = "pbmc_sample"

# Load and store data
adata = sc.read_h5ad("pbmc3k.h5ad")
ads.set_adata(adata, sampleid="pbmc_sample", sdtype="exp")

# Retrieve data
retrieved_adata = ads.get_adata(adinfo=AdataInfo(sampleid="pbmc_sample"))

Data Types

The AdataManager supports these default data types:
  • exp: Expression data (default)
  • activity: Activity scores from pathway analysis
  • cnv: Copy number variation data
  • splicing: Alternative splicing data
You can also add custom data types during initialization:
# Add custom types
ads = AdataManager(add_adtypes=["pathway_scores", "regulatory_network"])
For detailed information about methods, data structures, best practices, and troubleshooting, see the complete AdataManager reference.

NotebookManager

The NotebookManager is the primary backend manager for handling Jupyter notebooks in code mode. It provides centralized management of multiple notebook instances with different kernels, making it essential for interactive analysis workflows. For complete documentation, see NotebookManager Reference.

Quick Overview

Key Features

  • Multiple Notebook Support: Manages multiple Jupyter notebook instances simultaneously
  • Kernel Management: Handles different Jupyter kernels (Python, R, etc.)
  • Active Notebook Tracking: Maintains the currently active notebook for operations
  • Code Execution: Provides a unified interface for code execution across notebooks
  • Notebook Lifecycle: Manages creation, deletion, and switching between notebooks

Basic Usage

from abcoder.backend import NotebookManager

# Initialize manager
nbm = NotebookManager()

# Create a notebook
nbm.create_notebook("analysis1", "/path/to/analysis1.ipynb", "python")

# Get the active notebook
jce = nbm.active_notebook

# Execute code
result = jce.execute("import pandas as pd\nprint('Pandas imported successfully')")

# Switch to a different notebook
nbm.create_notebook("r_analysis", "/path/to/r_analysis.ipynb", "ir")
jce_r = nbm.active_notebook
jce_r.execute("library(ggplot2)\nprint('R kernel working')")

Multi-Kernel Support

The NotebookManager supports various Jupyter kernels:
# Python kernel (default)
nbm.create_notebook("python_nb", "/path/to/python.ipynb", "python")

# R kernel
nbm.create_notebook("r_nb", "/path/to/r.ipynb", "ir")

# Julia kernel
nbm.create_notebook("julia_nb", "/path/to/julia.ipynb", "julia-1.8")

Integration with MCP Tools

from scmcp_shared.util import get_nbm

@mcp.tool(tags=["nb"])
def execute_code(code: str, backup_var: str = None):
    """Execute code in the active Jupyter notebook."""
    nbm = get_nbm()
    jce = nbm.active_notebook
    
    result = jce.execute(code, backup_var=backup_var)
    
    return {
        "notebook_id": nbm.active_nbid,
        "success": result["success"],
        "result": result["result"],
        "error": result.get("error", ""),
        "display_data": result.get("display_data", "")
    }
For detailed information about methods, JupyterClientExecutor integration, best practices, and troubleshooting, see the complete NotebookManager reference.