From 925c5db70fa010b88fbf57bf10376ddb39548026 Mon Sep 17 00:00:00 2001
From: KQDtianxiaK <1720573356@qq.com>
Date: Wed, 25 Feb 2026 01:24:11 +0800
Subject: [PATCH 01/13] initialize files, commit to branch Test
---
README.md | 528 ++++++---
SKILL.md | 245 ++++
__pycache__/server.cpython-312.pyc | Bin 0 -> 31226 bytes
__pycache__/server.cpython-313.pyc | Bin 0 -> 36166 bytes
config.json | 17 +
geomcp_sra/__init__.py | 10 +
.../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 467 bytes
geomcp_sra/__pycache__/config.cpython-312.pyc | Bin 0 -> 5719 bytes
geomcp_sra/__pycache__/config.cpython-313.pyc | Bin 0 -> 5846 bytes
.../__pycache__/geo_download.cpython-312.pyc | Bin 0 -> 20369 bytes
.../__pycache__/geo_download.cpython-313.pyc | Bin 0 -> 20411 bytes
.../__pycache__/geo_search.cpython-312.pyc | Bin 0 -> 15626 bytes
.../__pycache__/geo_search.cpython-313.pyc | Bin 0 -> 15327 bytes
.../__pycache__/sra_handler.cpython-312.pyc | Bin 0 -> 23239 bytes
.../__pycache__/sra_handler.cpython-313.pyc | Bin 0 -> 39122 bytes
geomcp_sra/config.py | 159 +++
geomcp_sra/geo_download.py | 463 ++++++++
geomcp_sra/geo_search.py | 384 ++++++
geomcp_sra/sra_handler.py | 1040 +++++++++++++++++
pyproject.toml | 37 +-
requirements.txt | 4 +
server.py | 1031 ++++++++++++++++
22 files changed, 3715 insertions(+), 203 deletions(-)
create mode 100644 SKILL.md
create mode 100644 __pycache__/server.cpython-312.pyc
create mode 100644 __pycache__/server.cpython-313.pyc
create mode 100644 config.json
create mode 100644 geomcp_sra/__init__.py
create mode 100644 geomcp_sra/__pycache__/__init__.cpython-313.pyc
create mode 100644 geomcp_sra/__pycache__/config.cpython-312.pyc
create mode 100644 geomcp_sra/__pycache__/config.cpython-313.pyc
create mode 100644 geomcp_sra/__pycache__/geo_download.cpython-312.pyc
create mode 100644 geomcp_sra/__pycache__/geo_download.cpython-313.pyc
create mode 100644 geomcp_sra/__pycache__/geo_search.cpython-312.pyc
create mode 100644 geomcp_sra/__pycache__/geo_search.cpython-313.pyc
create mode 100644 geomcp_sra/__pycache__/sra_handler.cpython-312.pyc
create mode 100644 geomcp_sra/__pycache__/sra_handler.cpython-313.pyc
create mode 100644 geomcp_sra/config.py
create mode 100644 geomcp_sra/geo_download.py
create mode 100644 geomcp_sra/geo_search.py
create mode 100644 geomcp_sra/sra_handler.py
create mode 100644 requirements.txt
create mode 100644 server.py
diff --git a/README.md b/README.md
index 81f946e..647a67a 100644
--- a/README.md
+++ b/README.md
@@ -1,247 +1,411 @@
-# Gene Expression Omnibus (GEO) MCP
-
-
-

-
-
Gene Expression Omnibus (GEO) - A public functional genomics data repository
-
-
-[](https://pypi.org/project/geo-mcp/)
-[](https://www.python.org/downloads/)
-[](LICENSE)
-[](https://modelcontextprotocol.io/)
-[](https://www.ncbi.nlm.nih.gov/geo/)
-
-> ⚠️ **Development Warning** ⚠️
->
-> **This project is currently in active development and is not yet production-ready.**
->
-> - The MCP stdio server is functional but may have bugs or incomplete features
-> - API endpoints and functionality may change without notice
-> - Use at your own risk and report any issues you encounter
->
-> We recommend testing thoroughly in a development environment before using in production.
-
-A Model Context Protocol (MCP) server for accessing [GEO (Gene Expression Omnibus)](https://www.ncbi.nlm.nih.gov/geo/) data through NCBI E-Utils API.
-The tool will enable you to search for GEO datasets, series, samples, platforms, and profiles for your LLM.
-Tested with Claude Desktop, chatGPT has no out of the box support for this tool yet.
-Claude will automatically use the tools if it fits the context.
-
-## Quick Install (pip)
-
-install from pip
-```bash
-pip install geo-mcp
-```
-install from source
+# GEO MCP Server with SRA Support
+
+An enhanced [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for accessing **GEO (Gene Expression Omnibus)** data through NCBI E-Utils API, with comprehensive support for **SRA (Sequence Read Archive)** raw sequencing data downloads and conversion.
+
+## Features
+
+### GEO Data Access
+- 🔍 **Search GEO databases**: Series (GSE), Samples (GSM), Platforms (GPL), Datasets (GDS), and Profiles
+- 📥 **Download metadata**: SOFT format, Series Matrix, MINiML XML
+- 📦 **Download supplementary files**: Processed data tables, raw array data
+
+### SRA Raw Sequencing Data (NEW)
+- 🔗 **Query SRA from GEO**: Map GEO Samples (GSM) to SRA Runs (SRR)
+- 📊 **Size estimation**: Dry-run mode to check file sizes before downloading
+- 💾 **Download & convert**: Integrated prefetch + fastq-dump workflow
+- 🛡️ **Safety constraints**: Size warnings and confirmation requirements
+- ✅ **Check sra-toolkit**: Verify installation and get setup instructions
+
+## Safety Features
+
+Following [maintainer recommendations](https://github.com/MCPmed/GEOmcp/issues/1), this server implements safety constraints for large file downloads:
+
+| Constraint | Implementation |
+|------------|----------------|
+| **Safe by Default** | `dry_run=True` by default - only estimates sizes |
+| **Dry-Run Mode** | `sra_estimate_size()` tool for size checking |
+| **Explicit Output** | Required `output_dir` for files >1GB |
+| **Confirmation** | `confirm_large=True` required for files >5GB |
+
+## Installation
+
+### Prerequisites
+- Python 3.10 or higher
+- (Optional) [SRA Toolkit](https://github.com/ncbi/sra-tools) for downloading raw FASTQ files
+
+### Install from Source
```bash
-# Clone the repo (if not already)
-git clone https://github.com/MCPmed/GEOmcp
-cd GEO_MCP
+# Clone the repository
+git clone https://github.com/yourusername/geo-mcp-server.git
+cd geo-mcp-server
+
+# Install dependencies
pip install -e .
```
-## Configuration
+### Configuration
-Run init to create a config file
+1. **Initialize configuration:**
```bash
-geo-mcp --init
+python server.py --init
```
-This will create a config file at `~/.geo-mcp/config.json` (auto-created on first run if missing).
-This file will contain the following:
+2. **Edit the config file** at `~/.geo-mcp/config.json`:
```json
{
- "base_url": "https://eutils.ncbi.nlm.nih.gov/entrez/eutils",
"email": "your_email@example.com",
- "api_key": "YOUR_API_KEY"
+ "api_key": "YOUR_NCBI_API_KEY (optional)",
+ "download_dir": "~/geo_downloads",
+ "sra_toolkit_path": "/path/to/sra-toolkit/bin (optional)"
+}
+```
+
+> **Note:** NCBI requires an email address for E-Utils access. An API key is optional but recommended for higher rate limits (10 req/s vs 3 req/s). Get one at [NCBI](https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/).
+
+## Usage
+
+### Running the Server
+
+**MCP stdio mode** (for Claude Desktop):
+```bash
+python server.py
+```
+
+**HTTP mode**:
+```bash
+python server.py --http --port 8000
+```
+
+### Claude Desktop Integration
+
+Add to your Claude Desktop configuration (`~/.config/claude-desktop/config.json`):
+
+```json
+{
+ "mcpServers": {
+ "geo_mcp": {
+ "command": "python",
+ "args": ["/path/to/geo_mcp_server/server.py"],
+ "env": {
+ "CONFIG_PATH": "/home/yourusername/.geo-mcp/config.json"
+ }
+ }
+ }
}
```
-It will also print out a configuration template for your claude desktop configuration file.
+## Available Tools (18 Total)
-- `email` is required by NCBI.
-- `api_key` is optional but recommended for higher rate limits ([get one here](https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/)).
+### GEO Search Tools
-## Running the Server
+| Tool | Description |
+|------|-------------|
+| `geo_search` | Search all GEO record types with natural language (e.g., "Human RNA-seq") |
+| `geo_search_series` | Search GEO Series (GSE) - complete experiments |
+| `geo_search_samples` | Search GEO Samples (GSM) - individual samples |
+| `geo_search_platforms` | Search GEO Platforms (GPL) - array/sequencing platforms |
+| `geo_search_datasets` | Search GEO Datasets (GDS) - curated gene expression |
+| `geo_search_profiles` | Search GEO Profiles - gene expression profiles |
-- **MCP stdio mode:**
- ```bash
- geo-mcp
- ```
-- **HTTP mode:**
- ```bash
- geo-mcp --http --port 8001
- ```
+### GEO Download Tools
-## Claude Desktop Integration
+| Tool | Description |
+|------|-------------|
+| `geo_download_series` | Download GSE data files (SOFT, matrix, supplementary) |
+| `geo_download_sample` | Download GSM supplementary files |
+| `geo_get_download_status` | Check if a GEO dataset has been downloaded |
+| `geo_list_downloads` | List all downloaded datasets |
+| `geo_cleanup_downloads` | Clean up downloaded files |
-### Common Issue: `spawn geo-mcp ENOENT`
+### SRA Tools
-This error means Claude Desktop cannot find the `geo-mcp` command. This is usually a PATH issue.
+| Tool | Description |
+|------|-------------|
+| `sra_query_from_geo` | Query SRA Run information from a GEO Series |
+| `sra_get_metadata` | Get SRA run metadata |
+| `sra_estimate_size` | **NEW** Estimate download sizes before downloading (dry-run) |
+| `sra_generate_download_commands` | Generate download commands for various methods |
+| `sra_check_toolkit` | Check sra-toolkit installation |
+| `sra_download` | Download SRA directly via HTTP (small files only) |
+| `sra_download_and_convert` | **NEW** Download with prefetch and convert to FASTQ |
-### Solution
-1. **Find the full path to the executable:**
- ```bash
- which geo-mcp
- ```
- Example output: `/Users/youruser/miniforge3/bin/geo-mcp`
+## Example Workflows
-2. **Update your Claude config:**
- Instead of just `"geo-bio-mcp"`, use the full path:
- ```json
- {
- "mcpServers": {
- "geo-mcp": {
- "command": "/Users/youruser/miniforge3/bin/geo-mcp",
- "env": {
- "CONFIG_PATH": "/Users/youruser/.geo-mcp/config.json"
- }
- }
- }
- }
- ```
+### 1. Search with Natural Language
-3. **(Optional) Use a Conda Environment:**
- - Activate your conda env and run `which geo-mcp` to get the correct path.
- - Use that path in your Claude config as above.
+```
+User: Find Human RNA-seq datasets
-4. **Restart Claude Desktop** after updating the config.
+AI: I'll search for Human RNA-seq datasets in GEO.
+[Uses geo_search_series with term="Human RNA-seq"]
----
+Results:
+- GSE319287: "TPD52 Inhibits Aldosterone Synthesis..." (6 samples)
+- GSE213095: "Positive feedback between cDC1s and CD8+ T cells..." (46 samples)
+- GSE320065: "Transcriptomic and Functional Responses of Human Airway Cells..." (56 samples)
+```
-## Troubleshooting
-- If you see `command not found: geo-mcp`, make sure you installed with the correct Python/conda environment and that its `bin` directory is in your PATH.
-- If the config file is missing, it will be auto-created on first run, or you can copy the template from `geo_mcp_server/config_template.json`.
+### 2. Download Processed Data
----
+```
+User: Download the metadata for GSE12345
-## Usage
+AI: I'll download the SOFT file and series matrix for GSE12345.
+[Uses geo_download_series with geo_id="GSE12345", file_types=["soft", "matrix"]]
+
+Results:
+✓ Downloaded GSE12345_family.soft.gz (1.2 MB)
+✓ Downloaded GSE12345_series_matrix.txt.gz (5.6 MB)
+Location: ~/geo_downloads/gse/GSE12345/
+```
-### MCP Server (stdio mode)
-For use with MCP clients like Claude Desktop:
+### 3. Find and Download Raw Sequencing Data (Safe Workflow)
-```bash
-cd geo_mcp_server
-python main.py --mode stdio
+**Step 1: Get SRA accessions**
```
+User: Get the SRA run accessions for GSE272467
-### HTTP Server (localhost:8000)
-For HTTP API access:
+AI: I'll query the SRA information from this GEO Series.
+[Uses sra_query_from_geo with gse_id="GSE272467"]
-```bash
-# Option 1: Using the main script
-cd geo_mcp_server
-python main.py --mode http --host localhost --port 8000
+Results:
+- Total samples: 4
+- Samples with SRA data: 4
+- Total SRA runs: 4
+- All SRA accessions: ["SRR29864801", "SRR29864802", "SRR29864803", "SRR29864804"]
+```
-# Option 2: Using the convenience script
-python run_server.py
+**Step 2: Estimate size (recommended)**
```
+User: How large are these files?
-### HTTP API Endpoints
+AI: Let me estimate the download sizes.
+[Uses sra_estimate_size with sra_ids=["SRR29864801"]]
-Once the HTTP server is running on localhost:8000, you can access:
+Results:
+- SRA size: ~76 MB
+- Estimated FASTQ size: ~190 MB
+- Read count: 7,178,576
+- Warning: Small file (< 100 MB)
+```
-- **Root**: `GET /` - Server status
-- **Health Check**: `GET /health` - Health check endpoint
-- **List Tools**: `GET /tools` - List all available tools
-- **Call Tool**: `POST /tools/call` - Execute a tool with arguments
-- **API Documentation**: `GET /docs` - Interactive API documentation (Swagger UI)
+**Step 3: Download and convert**
+```
+User: Download and convert SRR29864801 to FASTQ
-### Example HTTP API Usage
+AI: I'll download the SRA file and convert it to FASTQ format.
+[Uses sra_download_and_convert with sra_id="SRR29864801", dry_run=False]
+
+Results:
+✓ Downloaded SRR29864801.sra (76 MB)
+✓ Converted to FASTQ
+ - SRR29864801_1.fastq (660 KB, 5000 reads)
+ - SRR29864801_2.fastq (660 KB, 5000 reads)
+Location: ~/geo_downloads/sra/SRR29864801/
+```
+### 4. Safety Constraints in Action
+
+```
+User: Download SRR1234567
+
+AI: First, let me estimate the size before downloading.
+[Uses sra_estimate_size with sra_ids=["SRR1234567"]]
+
+Results:
+- SRA size: ~2.5 GB
+- Estimated FASTQ size: ~6.25 GB
+- Warning: LARGE FILE (1-5 GB)
+
+⚠️ This is a large download that requires explicit output directory.
+Please provide output_dir parameter to proceed.
+
+User: Download to /data/sra
+
+AI:
+[Uses sra_download_and_convert with
+ sra_id="SRR1234567",
+ dry_run=False,
+ output_dir="/data/sra"]
+
+✓ Download complete!
+```
+
+### 5. Check SRA Toolkit
+
+```
+User: Do I have sra-toolkit installed?
+
+AI: Let me check your sra-toolkit installation.
+[Uses sra_check_toolkit]
+
+Results:
+✓ prefetch: available (version 3.3.0)
+✓ fastq-dump: available (version 3.3.0)
+✓ fasterq-dump: available (version 3.3.0)
+✓ vdb-validate: available (version 3.3.0)
+
+All tools are installed and ready to use!
+```
+
+## SRA Download Methods
+
+### Method 1: Using sra_download_and_convert (Recommended)
+
+Integrated workflow with safety features:
+```python
+# Step 1: Estimate size (dry-run)
+sra_estimate_size(sra_ids=["SRR1234567"])
+
+# Step 2: Download and convert based on size
+# Small file (<1GB)
+sra_download_and_convert(sra_id="SRR1234567", dry_run=False)
+
+# Medium file (1-5GB) - requires output_dir
+sra_download_and_convert(
+ sra_id="SRR1234567",
+ dry_run=False,
+ output_dir="/path/to/output"
+)
+
+# Large file (>5GB) - requires confirmation
+sra_download_and_convert(
+ sra_id="SRR1234567",
+ dry_run=False,
+ output_dir="/path/to/output",
+ confirm_large=True
+)
+```
+
+### Method 2: Using SRA Toolkit Manually
+
+1. **Install sra-toolkit**: Follow instructions at https://github.com/ncbi/sra-tools
+
+2. **Download and convert**:
```bash
-# List available tools
-curl http://localhost:8000/tools
-
-# Search GEO Profiles
-curl -X POST http://localhost:8000/tools/call \
- -H "Content-Type: application/json" \
- -d '{
- "name": "search_geo_profiles",
- "arguments": {
- "term": "cancer",
- "retmax": 5
- }
- }'
-
-# Search GEO Datasets
-curl -X POST http://localhost:8000/tools/call \
- -H "Content-Type: application/json" \
- -d '{
- "name": "search_geo_datasets",
- "arguments": {
- "term": "breast cancer",
- "retmax": 10
- }
- }'
+# Download SRA file
+prefetch SRR1234567
+
+# Convert to FASTQ (3-way split for paired-end)
+fastq-dump --split-3 SRR1234567
```
-## Available Tools
+### Method 3: Direct HTTP Download (Small Files Only)
+
+For small files or when sra-toolkit is not available:
+```bash
+# Using wget
+wget https://sra-downloadb.be-md.ncbi.nlm.nih.gov/sos2/sra-pub-run-11/SRR1234567/SRR1234567.1
-This MCP server provides access to all major GEO databases through the following tools:
+# Using curl
+curl -o SRR1234567.sra https://sra-downloadb.be-md.ncbi.nlm.nih.gov/sos2/sra-pub-run-11/SRR1234567/SRR1234567.1
+```
-### Search Tools
+## Project Structure
-- **`search_geo_profiles`** - Search gene expression profiles across different biological contexts
- - *Example searches*: "cancer", "breast cancer", "p53", "apoptosis"
-
-- **`search_geo_datasets`** - Search curated gene expression datasets
- - *Example searches*: "diabetes", "Alzheimer's disease", "drug response", "tissue specific"
-
-- **`search_geo_series`** - Search original submitter-supplied gene expression series
- - *Example searches*: "GSE12345", "microarray", "RNA-seq", "time course"
-
-- **`search_geo_samples`** - Search individual gene expression samples
- - *Example searches*: "GSM123456", "human", "mouse", "tumor", "normal"
-
-- **`search_geo_platforms`** - Search microarray platform definitions
- - *Example searches*: "Affymetrix", "Illumina", "Agilent", "GPL96"
+```
+geo_mcp_server/
+├── geomcp_sra/
+│ ├── __init__.py
+│ ├── config.py # Configuration management
+│ ├── geo_search.py # GEO search functionality (E-Utilities)
+│ ├── geo_download.py # GEO data download
+│ └── sra_handler.py # SRA query, size estimation, download & convert
+├── server.py # Main MCP server with 18 tools
+├── config.json # Configuration template
+├── pyproject.toml # Project dependencies
+├── requirements.txt # Python dependencies
+├── README.md # This file
+└── SKILL.md # Skill documentation
+```
-### Search Parameters
+## Comparison with Original GEOmcp
-Each tool accepts:
-- **`term`** (required): Search term or query string
-- **`retmax`** (optional, default: 20): Maximum number of results to return
+| Feature | GEOmcp (Original) | This Project (geo-mcp-server) |
+|---------|-------------------|---------------------------|
+| GEO Search | ✓ | ✓ (Enhanced with natural language) |
+| SOFT Download | ✓ | ✓ |
+| Matrix Download | ✓ | ✓ |
+| Supplementary Files | ✓ | ✓ |
+| **SRA Query** | ✗ | **✓** |
+| **SRR Mapping** | ✗ | **✓** |
+| **Size Estimation** | ✗ | **✓ (Dry-run mode)** |
+| **Download & Convert** | ✗ | **✓ (Integrated workflow)** |
+| **Safety Constraints** | ✗ | **✓ (>1GB, >5GB checks)** |
+| Tool Count | 11 | **18** |
-### Example usage
-For now just chat with claude desktop and it will use the tools automatically if it fits the context.
+## Configuration Options
-**User:** find a small brain dataset
+### Full Config File Reference
+
+>>>>>>> ad562a4 (initialize files, commit to branch Test)
+```json
+{
+ "base_url": "https://eutils.ncbi.nlm.nih.gov/entrez/eutils",
+ "email": "your_email@example.com",
+ "api_key": "YOUR_NCBI_API_KEY (optional but recommended)",
+ "download_dir": "~/geo_downloads",
+ "max_file_size_mb": 5000,
+ "max_total_downloads_mb": 10000,
+ "max_concurrent_downloads": 3,
+ "download_timeout_seconds": 300,
+ "allowed_download_paths": ["~/geo_downloads", "/tmp/geo_downloads"],
+ "sra_toolkit_path": "/path/to/sra-toolkit/bin (optional)"
+}
+```
-**Assistant:** I'll help you find a small brain dataset from the GEO database. Let me search for brain-related datasets with a maximum of one result.
+## Troubleshooting
-**Assistant (system):** *search_geo_datasets*
+### Email not configured
+```
+Error: Email is required for NCBI E-utilities.
+```
+**Solution**: Edit `~/.geo-mcp/config.json` and add your email address.
-**Assistant:** I found a brain-related dataset for you:
+### SRA toolkit not found
+```
+fasterq-dump not found. Please install sra-toolkit.
+```
+**Solution**: Install sra-toolkit from https://github.com/ncbi/sra-tools and set `sra_toolkit_path` in config.
-- **Dataset:** GSE290848
-- **Title:** Maternal Stress Triggers Early-Life Eczema via Fetal Mast Cell Reprogramming [10x Genomics Multiome ATAC + Gene Expression]
-- **Species:** Mouse (*Mus musculus*)
-- **Samples:** 8
-- **Data type:** ATAC-seq & gene expression (10x Genomics Multiome)
-- **Publication date:** 21 Jun 2025
+### Rate limiting
+```
+Error: Rate limit exceeded
+```
+**Solution**: Add an NCBI API key to your config for higher rate limits (10 req/s vs 3 req/s).
-This small dataset explores how prenatal stress affects neuro-immune circuits and mast-cell development.
+### Large file safety error
+```
+SAFETY CHECK: File size is ~2.5 GB. Large downloads require an explicit output directory.
+```
+**Solution**: Provide `output_dir` parameter for files >1GB, or both `output_dir` and `confirm_large=True` for files >5GB.
-Would you like me to download this dataset or search for others?
+## References
----
+- [GEO Home](https://www.ncbi.nlm.nih.gov/geo/)
+- [SRA Home](https://www.ncbi.nlm.nih.gov/sra)
+- [NCBI E-Utilities](https://www.ncbi.nlm.nih.gov/books/NBK25501/)
+- [SRA Toolkit Documentation](https://github.com/ncbi/sra-tools/wiki)
+- [MCP Documentation](https://modelcontextprotocol.io/)
-**User:** download GSE290848
+## License
-**Assistant:** I'll download the GSE290848 dataset for you.
+MIT License - See LICENSE file for details.
-**Assistant (system):** *download_geo_data*
+## Contributing
-**Assistant:** Download complete.
+Contributions are welcome! Please feel free to submit issues or pull requests.
-**Downloaded files**
+### Contributing SRA Support Back to Original GEOmcp
-- `GSE290848_family.soft.gz` — series, platform & sample info
-- `GSE290848_metadata.xml` — detailed study metadata
+This project implements the [enhancement request](https://github.com/MCPmed/GEOmcp/issues/1) for SRA raw data support with the following safety features as recommended by maintainers:
+- Safe by default (dry-run mode)
+- Size estimation before download
+- Explicit output directory requirement for large files
+- Confirmation for very large files (>5GB)
-**Location:** `/Users/matthiasflo/Documents/2025/GEO_MCP/geo_mcp_server/downloads/gse/GSE290848`
-**Total size:** 0.01 MB
+## Acknowledgments
-The dataset is ready for analysis. Let me know if you’d like to explore it further.
+- Original [GEOmcp](https://github.com/MCPmed/GEOmcp) project for the foundation
+- NCBI for providing the GEO and SRA databases
+- MCP team for the Model Context Protocol
diff --git a/SKILL.md b/SKILL.md
new file mode 100644
index 0000000..f1e08d8
--- /dev/null
+++ b/SKILL.md
@@ -0,0 +1,245 @@
+---
+name: geo-mcp-sra
+description: MCP server for accessing GEO (Gene Expression Omnibus) data with comprehensive SRA (Sequence Read Archive) raw sequencing support. Enables natural language search, metadata download, size estimation with dry-run mode, and safe FASTQ downloads with prefetch/fastq-dump integration.
+---
+
+# GEO MCP Server with SRA Support
+
+This skill provides a Model Context Protocol (MCP) server for accessing NCBI's GEO and SRA databases programmatically with enhanced safety features for large file downloads.
+
+## Capabilities
+
+### GEO Data Access
+- Search GEO databases (GSE, GSM, GPL, GDS, Profiles) using natural language
+- Download SOFT format metadata files
+- Download series matrix files
+- Download supplementary processed data
+
+### SRA Raw Sequencing Data (with Safety Features)
+- Query SRA Run accessions from GEO Series
+- Map GSM samples to SRR run accessions
+- **Estimate download sizes** (dry-run mode)
+- **Download & convert** with integrated prefetch + fastq-dump workflow
+- **Safety constraints**: Size warnings, explicit output directory, confirmation for large files
+
+## Installation
+
+```bash
+cd /path/to/geo_mcp_server
+pip install -e .
+```
+
+## Configuration
+
+1. Create config file:
+```bash
+python3 server.py --init
+```
+
+2. Edit `~/.geo-mcp/config.json`:
+```json
+{
+ "email": "your_email@example.com",
+ "api_key": "YOUR_NCBI_API_KEY (optional but recommended)",
+ "download_dir": "~/geo_downloads",
+ "sra_toolkit_path": "/path/to/sra-toolkit/bin (optional)"
+}
+```
+
+> **Note:** NCBI requires an email address. API key provides higher rate limits (10 req/s vs 3 req/s).
+
+## Usage with Claude Desktop
+
+Add to `~/.config/claude-desktop/config.json`:
+
+```json
+{
+ "mcpServers": {
+ "geo_mcp": {
+ "command": "python3",
+ "args": ["/path/to/geo_mcp_server/server.py"],
+ "env": {
+ "CONFIG_PATH": "/home/username/.geo-mcp/config.json"
+ }
+ }
+ }
+}
+```
+
+## Available Tools (18 Total)
+
+### Search Tools (Natural Language Support)
+
+All search tools support natural language queries like "Human RNA-seq", "mouse brain single cell", "breast cancer transcriptome".
+
+| Tool | Description | Example Query |
+|------|-------------|---------------|
+| `geo_search` | Universal GEO search | "cancer RNA-seq" |
+| `geo_search_series` | Search GSE records | "Human RNA-seq" |
+| `geo_search_samples` | Search GSM records | "HeLa cell line" |
+| `geo_search_platforms` | Search GPL records | "Illumina HiSeq" |
+| `geo_search_datasets` | Search GDS records | "breast cancer" |
+| `geo_search_profiles` | Search GEO Profiles | "p53 expression" |
+
+### GEO Download Tools
+
+| Tool | Description |
+|------|-------------|
+| `geo_download_series` | Download GSE data (SOFT, matrix, supplementary) |
+| `geo_download_sample` | Download GSM supplementary files |
+| `geo_get_download_status` | Check download status |
+| `geo_list_downloads` | List downloaded datasets |
+| `geo_cleanup_downloads` | Clean up files |
+
+### SRA Tools
+
+| Tool | Description | Safety Features |
+|------|-------------|-----------------|
+| `sra_query_from_geo` | Get SRA accessions from GEO Series | - |
+| `sra_get_metadata` | Get SRA run metadata | - |
+| `sra_estimate_size` | **Estimate sizes (dry-run)** | Shows warnings for >1GB, >5GB |
+| `sra_generate_download_commands` | Generate download commands | - |
+| `sra_check_toolkit` | Check sra-toolkit installation | - |
+| `sra_download` | Direct HTTP download | Small files only |
+| `sra_download_and_convert` | **Download & convert to FASTQ** | dry_run=True default, size checks |
+
+## Safety Features
+
+### Default Safe Behavior
+
+All SRA downloads default to **dry-run mode** (`dry_run=True`):
+
+```python
+# This only estimates size, does NOT download
+sra_download_and_convert(sra_id="SRR1234567")
+```
+
+### Size-Based Safety Constraints
+
+| File Size | Required Parameters |
+|-----------|---------------------|
+| < 1 GB | `dry_run=False` |
+| 1-5 GB | `dry_run=False` + `output_dir="/path"` |
+| > 5 GB | `dry_run=False` + `output_dir="/path"` + `confirm_large=True` |
+
+### Safety Check Examples
+
+**Error for >1GB without output_dir:**
+```
+SAFETY CHECK: File size is ~2.5 GB. Large downloads require an explicit
+output directory. Please provide output_dir parameter.
+Tip: Run with dry_run=True first to see size estimates.
+```
+
+**Error for >5GB without confirmation:**
+```
+SAFETY CHECK: File size is ~6.2 GB (>5GB). This is a VERY LARGE download
+that will consume significant disk space and time.
+To proceed, set confirm_large=True.
+```
+
+## Example Workflows
+
+### Workflow 1: Search with Natural Language
+
+```python
+# Search for Human RNA-seq datasets
+geo_search_series(term="Human RNA-seq", retmax=10)
+
+# Search for specific tissue + disease
+geo_search_series(term="mouse brain Alzheimer's", retmax=5)
+```
+
+### Workflow 2: Safe SRA Download
+
+**Step 1: Always estimate first**
+```python
+sra_estimate_size(sra_ids=["SRR1234567"])
+# Returns: SRA size, FASTQ estimate, read count, safety warnings
+```
+
+**Step 2: Download based on size**
+
+Small file (<1GB):
+```python
+sra_download_and_convert(
+ sra_id="SRR1234567",
+ dry_run=False,
+ split_3=True, # Properly handle paired-end
+ check_refseq=False # Skip refseq to save space
+)
+```
+
+Medium file (1-5GB):
+```python
+sra_download_and_convert(
+ sra_id="SRR1234567",
+ dry_run=False,
+ output_dir="/data/sra", # Required!
+ split_3=True
+)
+```
+
+Large file (>5GB):
+```python
+sra_download_and_convert(
+ sra_id="SRR1234567",
+ dry_run=False,
+ output_dir="/data/sra", # Required
+ confirm_large=True, # Required
+ split_3=True
+)
+```
+
+### Workflow 3: Complete Analysis Pipeline
+
+```python
+# 1. Search for datasets
+results = geo_search_series(term="GLOR2 m6A", retmax=5)
+
+# 2. Get SRA accessions for a dataset
+sra_info = sra_query_from_geo(gse_id="GSE272467")
+# Returns: 4 SRR accessions
+
+# 3. Estimate sizes
+sizes = sra_estimate_size(sra_ids=sra_info["all_sra_accessions"])
+# Shows: ~76 MB each, total ~304 MB
+
+# 4. Download and convert
+for sra_id in sra_info["all_sra_accessions"]:
+ sra_download_and_convert(
+ sra_id=sra_id,
+ dry_run=False,
+ split_3=True,
+ check_refseq=False
+ )
+```
+
+## Architecture
+
+```
+geo_mcp_server/
+├── geomcp_sra/
+│ ├── config.py # Configuration management
+│ ├── geo_search.py # NCBI E-Utilities search
+│ ├── geo_download.py # FTP/HTTP downloads
+│ └── sra_handler.py # SRA query, size estimation, download & convert
+├── server.py # MCP server with 18 tools (FastMCP)
+├── config.json # Config template
+└── pyproject.toml # Project metadata
+```
+
+## Dependencies
+
+- `mcp>=1.9.0` - MCP Python SDK
+- `httpx>=0.27.0` - Async HTTP client
+- `aiofiles>=23.0.0` - Async file operations
+- `pydantic>=2.0.0` - Input validation
+
+## References
+
+- [GEO Documentation](https://www.ncbi.nlm.nih.gov/geo/info/)
+- [SRA Documentation](https://www.ncbi.nlm.nih.gov/sra/docs/)
+- [SRA Toolkit](https://github.com/ncbi/sra-tools)
+- [MCP Specification](https://modelcontextprotocol.io/)
+- [Original GEOmcp Issue #1 - SRA Support](https://github.com/MCPmed/GEOmcp/issues/1)
diff --git a/__pycache__/server.cpython-312.pyc b/__pycache__/server.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8646bebd9f56dfb62d7d69c08bd032461f7ff7d1
GIT binary patch
literal 31226
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
literal 0
HcmV?d00001
diff --git a/__pycache__/server.cpython-313.pyc b/__pycache__/server.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ef9e707a3c2df96757109357dcead75a4ca91285
GIT binary patch
literal 36166
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
K)v<-CJ^nB0d_F$_
literal 0
HcmV?d00001
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..3251bd4
--- /dev/null
+++ b/config.json
@@ -0,0 +1,17 @@
+{
+ "base_url": "https://eutils.ncbi.nlm.nih.gov/entrez/eutils",
+ "sra_base_url": "https://trace.ncbi.nlm.nih.gov/Traces/sra",
+ "email": "your_email@example.com",
+ "api_key": "",
+ "retmax": 20,
+ "download_dir": "./downloads",
+ "max_file_size_mb": 5000,
+ "max_total_downloads_mb": 50000,
+ "max_concurrent_downloads": 3,
+ "download_timeout_seconds": 300,
+ "sra_toolkit_path": "",
+ "allowed_download_paths": [
+ "./downloads",
+ "/tmp/geo_downloads"
+ ]
+}
diff --git a/geomcp_sra/__init__.py b/geomcp_sra/__init__.py
new file mode 100644
index 0000000..1597189
--- /dev/null
+++ b/geomcp_sra/__init__.py
@@ -0,0 +1,10 @@
+"""
+GEO MCP Server with SRA Support
+
+An enhanced MCP server for accessing GEO (Gene Expression Omnibus) data
+through NCBI E-Utils API, with additional support for SRA (Sequence Read Archive)
+raw data download capabilities.
+"""
+
+__version__ = "0.2.0"
+__author__ = "GEO MCP Contributors"
diff --git a/geomcp_sra/__pycache__/__init__.cpython-313.pyc b/geomcp_sra/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cb57390858e61bc76a73f45eb3886afe9ff63662
GIT binary patch
literal 467
zcmXw0!Ab)$5Z!HSm6T#Z@hAf#SkP|qstC1|(t}#Mcn;|%b_3gFon%|>Nk77yKj0rp
z@#YUG{Q;8}=aBF+Gw;2btm<_VxH#T>mxo~xe0%U84zFX?aMxQ92N=X5hH(i?lXA1N
z_#*w@9o%$>5DT0Mgt@dS#G?+xMV@Q4gme@Ll`@qGzAiMI!Uv7Ol0+CI)dW1tNna=d
zy{8=gqgHS?RdQUICU9mMu_@|elEQ8GdH}t%dn+>oo#Ehgqscgz)^)KA%tji#gtu}M
zi^oDZ127VdLkE*o&P0$%FbOC>C4W0^T3VOnId)oz`)+Kc`F8M|6pbe60}
zbK5L0w<+a1p>$cJ)D7=VJ3uI9g-tb5`Vp-B`j!{bRN06}H_TXpk@FKd&S)YuohCWm
zti;1LLKaafm9&($^5^BwJO)Jj_3dY
literal 0
HcmV?d00001
diff --git a/geomcp_sra/__pycache__/config.cpython-312.pyc b/geomcp_sra/__pycache__/config.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0941b064bea2614f60934e8d5d67be00ae67a336
GIT binary patch
literal 5719
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
literal 0
HcmV?d00001
diff --git a/geomcp_sra/__pycache__/config.cpython-313.pyc b/geomcp_sra/__pycache__/config.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a906d0d092fed1f8ddf4d8934e4966cafda7cb43
GIT binary patch
literal 5846
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 tG?VsWOX6_5oFkA5y;ecY5Pw83~B
zEsGs<1_JT{MQPcz>Q~wl@%xAgl~
zIh?Z8@L#6hu{5pJH{K(Yb$eHGdry3O&$2YJ{m28HovV~&gKb^|dzkX->xQd_lxu6!
zwJYx0m1<~RscVR86Lnix8k(bnOS|GN2XB5i(a;BA!)1emtaAH3EmQ@cHrT6@wx+nP
zDQVjhw{1z-w%w<6`l=a4%2YnrIotWK_N5wH-n#te9Pc>1d?3+r9HeWh1nD+b&OZgxRn%WUcJ)}QWoNRbGv3mfYHI(>
z-EZ$k+s5HU<4!bg*p?>IsL`HiItmiDfH^}B<_s-Vmyv@snM!EkirG4EeeKLWxfJ1t
zRDd7(&;ebN2>cj_kiZWqz>nwP3(JAR%jlX-7XpZUZomvLL9+o6c`>)8DCGW>Tjas?
zE-iF$l>2lcM=O8}8XUa?$3WH#UnMJktndUWTM9e$2Vx;F1Uq
z3bt0dO{n(Rg8B>d&1~KdpG{Wj_#E~
zXs^5Q*gm1HI9_;c_k^}SL4IYf@1Hn3McP~$9IuEp4`zv*YKA88ND}_d0l(K10AKff
zctniSUke-M?TSTo#EpB0eBh-n81KR31bpII?^y6c&J`XZ(xbo%mA(k4&^`rAiUvuA
zOMEDZsz_U)DOv9vkra#s*Nd(e{e+8x@AHm3)}8m1Kz~m~6muQ)Fv$(12m1Y?_ltsFnA9GG`^9oJF$GQrTB;e9^i9J
zFh%fZtv12BUAq0nBll%$d1t0fBR4M$WGJ{rnN_@HtO`h~1E&^9+Omqbj8Q8uk4iHX
z+!m#)c+1%8<)u+mhJxE->Eh7Rmc?`L0y2Qd%yTr=zU`iRkG%Y@-k6cY9jmlvlo(S{
zj=F_jz!(`M0DFa|XjO}`{SvCFEmaRzlWtnBxob3K}P?
z+`KrjRQv9!RgB&%ZIo*;8E#8k$ZdIR?D&b;vnON6Pky|26*KM)&`om9qH4+Xu0BIS
zbh&hSD0bqx<#QiH$G~&ud77$ggijUjDK|k2P4@W%vz-|^#6hwW+kEY8MFw-$2=+h?
zDg2<~P`b*<^n#yM!OvTK!L)27>>E$ZM!8@hEeUeO>dtzAGOYxkJ53z*&ap35d-&g9+spnJAb}}H
zaXk>g(GE?2N^STxRrE_rOa7~WNx^^pFR7ycN?HFK)tsQ3e@W?nNg4hJRrx?6q17{!
T4=A`j)Lc@~n)?)nq}~4yy~ai|
literal 0
HcmV?d00001
diff --git a/geomcp_sra/__pycache__/geo_download.cpython-313.pyc b/geomcp_sra/__pycache__/geo_download.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..255e72249b505426cdc0805d103505147b306da0
GIT binary patch
literal 20411
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 | |