mcp-pubmed 0.2.0
A Model Context Protocol (MCP) server for searching PubMed data
License: MIT
Requires Python: >=3.8

# MCP-PubMed Server

A Model Context Protocol (MCP) server for searching PubMed data in a local Elasticsearch database.

## Features

- Semantic search for scientific literature from PubMed
- Filtering by DOI, section, and other metadata
- MCP tools and resources for AI assistants to access scientific literature

## Installation

```bash
# Clone the repository
git clone https://github.com/ddkang1/mcp-pubmed.git
cd mcp-pubmed

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -e .
```

## Usage

### Starting the Server

```bash
python run_mcp.py --port 8003
```

The server automatically suppresses error messages during shutdown for a cleaner experience.

#### Command-line Arguments

- `--port PORT`: Port to run the server on (default: 8000)
- `--transport TRANSPORT`: Transport protocol to use (sse or stdio) (default: sse)
- `--host HOST`: Host to bind to for SSE transport (default: 0.0.0.0)

### Running the Server

You can run the server in two ways:

#### Option 1: Direct Python

```bash
python run_mcp.py --port 8003
```

#### Option 2: Using uvx

```bash
# From GitHub repository
uvx --from git+https://github.com/ddkang1/mcp-pubmed mcp-pubmed --port 8003

# From local directory
uvx --from /path/to/mcp-pubmed mcp-pubmed --port 8003
```

Both methods now support clean termination with Ctrl+C and suppress error messages during shutdown.

#### Troubleshooting uvx

If you've made changes to the package and want uvx to use the latest version:

```bash
# Clean the uv cache
uv cache clean

# Then run the server again
uvx --from /path/to/mcp-pubmed mcp-pubmed --port 8003
```

If for any reason Ctrl+C doesn't work, you can still use the terminate_server.py utility as a backup method:

```bash
# In a separate terminal
./terminate_server.py --port 8003
```

### Terminating the Server

#### Normal termination

Press `Ctrl+C` twice to terminate the server gracefully.

#### Using the termination utility

If the server is stuck or you need to terminate it from another terminal:

```bash
./terminate_server.py --port 8003
```

This utility will:
1. Find the process listening on the specified port
2. Attempt to terminate it gracefully (equivalent to pressing Ctrl+C twice)
3. Offer to force kill the process if it doesn't terminate

## Server Configuration

The server connects to an Elasticsearch instance with the following default settings:

- Host: 10.130.51.210
- Port: 9200
- Index: passages
- Text field: text
- Embedding field: text_vector

## MCP Tools and Resources

### Tools

- `search_pubmed`: Search for scientific literature from PubMed
  - Parameters:
    - `question`: The scientific question to search for (for semantic search)
    - `keywords`: Comma-separated string of keywords for keyword-based search
    - `filters`: Optional filters to narrow down results
    - `excluded_sections`: List of section names to exclude from search results
    - `top_n`: Maximum number of passages to return (default: 10)
    - `min_score`: Minimum reranker score threshold for filtering results (default: 0.0)
  - Search Type Determination:
    - If both `question` and `keywords` are provided: Hybrid search
    - If only `question` is provided: Vector search
    - If only `keywords` is provided: Keyword search
  - Notes:
    - A `min_score` value of 0.0 means no filtering (all results are returned)
    - Higher `min_score` values (e.g., 0.7) will filter out less relevant results
    - For hybrid search without reranker, vector search gets ceiling(top_n/2) results and keyword search gets floor(top_n/2) results

### Resources

- `pubmed://search/{query}`: Search for scientific literature
- `pubmed://info`: Get information about the PubMed search service

## Testing

The project includes a comprehensive test suite to verify the functionality of the Elasticsearch connection and the BedrockCohereReranker.

### Running Tests

You can run the tests using pytest:

```bash
# Run all tests
python -m pytest

# Run specific test file
python -m pytest tests/test_elasticsearch.py

# Run tests with verbose output
python -m pytest -v
```

### Test Structure

- `tests/test_elasticsearch.py`: Tests for Elasticsearch connection and search functionality
  - Tests vector search, keyword search, and hybrid search with proper cutoff of both top_n and min_score
  - Verifies that connection management works correctly for multiple sequential searches

- `tests/test_reranker.py`: Tests for BedrockCohereReranker functionality
  - Verifies that the reranker correctly filters results based on top_n and min_score parameters
  - Tests various combinations of filtering parameters

## Troubleshooting

### Server won't terminate

If the server doesn't terminate properly with Ctrl+C:

1. Try pressing Ctrl+C twice
2. Use the terminate_server.py utility: `./terminate_server.py --port 8003`
3. As a last resort, find the process ID and kill it: `kill -9 <PID>`

## License

MIT