@cyanheads/pubmed-mcp-server 1.0.13 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
# PubMed MCP Server
|
|
1
|
+
# PubMed MCP Server
|
|
2
2
|
|
|
3
3
|
[](https://www.typescriptlang.org/)
|
|
4
|
-
[](./CHANGELOG.md)
|
|
4
|
+
[](https://modelcontextprotocol.io/)
|
|
5
|
+
[](./CHANGELOG.md)
|
|
7
6
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
|
-
[](https://github.com/cyanheads/pubmed-mcp-server/issues)
|
|
9
8
|
[](https://github.com/cyanheads/pubmed-mcp-server)
|
|
10
9
|
|
|
11
|
-
**
|
|
10
|
+
**Empower your AI agents and research tools with seamless PubMed integration!**
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
An MCP (Model Context Protocol) server providing comprehensive access to PubMed's biomedical literature database. Enables LLMs and AI agents to search, retrieve, analyze, and visualize scientific publications through NCBI's E-utilities API with advanced research workflow capabilities.
|
|
13
|
+
|
|
14
|
+
Built on the [`cyanheads/mcp-ts-template`](https://github.com/cyanheads/mcp-ts-template), this server follows a modular architecture with robust error handling, logging, and security features.
|
|
14
15
|
|
|
15
16
|
## 🚀 Core Capabilities: PubMed Tools 🛠️
|
|
16
17
|
|
|
@@ -22,156 +23,222 @@ This server equips your AI with specialized tools to interact with PubMed:
|
|
|
22
23
|
| [`fetch_pubmed_content`](./src/mcp-server/tools/fetchPubMedContent/) | Retrieves detailed information for PubMed articles. Can use a list of PMIDs or ESearch history (queryKey/webEnv) with pagination. (See [Example](./examples/fetch_pubmed_content_example.md)) | - Flexible `detailLevel`: `abstract_plus` (parsed details, optional MeSH/grant), `full_xml` (JSON representation of the PubMedArticle XML structure), `medline_text` (MEDLINE format), `citation_data` (minimal for citations).<br/>- Supports direct PMID list or `queryKey`/`webEnv` from ESearch history.<br/>- Supports `retstart`/`retmax` for pagination with history.<br/>- Uses NCBI EFetch. |
|
|
23
24
|
| [`get_pubmed_article_connections`](./src/mcp-server/tools/getPubMedArticleConnections/) | Finds related articles (cited by, similar, references) or formats citations for a PMID. (See [Ex.1](./examples/get_pubmed_article_connections_1.md), [Ex.2](./examples/get_pubmed_article_connections_2.md)) | - Uses NCBI ELink for relationships.<br/>- Uses NCBI EFetch for citation data (RIS, BibTeX, APA, MLA).<br/>- Filter by max related results. |
|
|
24
25
|
| [`pubmed_research_agent`](./src/mcp-server/tools/pubmedResearchAgent/) | Generates a standardized JSON research plan outline from component details. (See [Example](./examples/pubmed_research_agent_example.md)) | - Accepts granular inputs for all research phases.<br/>- Optionally embeds instructive prompts for agent execution.<br/>- Structures rough ideas into a formal, machine-readable plan for further processing. |
|
|
25
|
-
| [`generate_pubmed_chart`](./src/mcp-server/tools/generatePubMedChart/) | Generates a chart image (
|
|
26
|
+
| [`generate_pubmed_chart`](./src/mcp-server/tools/generatePubMedChart/) | Generates a chart image (PNG) from given input data. (See [Bar](./examples/generate_pubmed_chart_example_bar.svg), [Line](./examples/generate_pubmed_chart_example_line.svg), [Scatter](./examples/generate_pubmed_chart_example_scatter.svg)) | - Supports 'bar', 'line', and 'scatter' chart types.<br/>- Takes data values and field specifications for axes and encoding.<br/>- Constructs a Vega-Lite specification internally and renders it as a PNG. |
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
29
|
-
##
|
|
30
|
+
## Table of Contents
|
|
31
|
+
|
|
32
|
+
| [Overview](#overview) | [Features](#features) | [Installation](#installation) |
|
|
33
|
+
|
|
34
|
+
| [Configuration](#configuration) | [Project Structure](#project-structure) |
|
|
35
|
+
|
|
36
|
+
| [Tools](#tools) | [Resources](#resources) | [Development](#development) | [License](#license) |
|
|
37
|
+
|
|
38
|
+
## Overview
|
|
39
|
+
|
|
40
|
+
The PubMed MCP Server acts as a bridge, allowing applications (MCP Clients) that understand the Model Context Protocol (MCP) – like advanced AI assistants (LLMs), IDE extensions, or custom research tools – to interact directly and efficiently with PubMed's vast biomedical literature database.
|
|
41
|
+
|
|
42
|
+
Instead of complex API integration or manual searches, your tools can leverage this server to:
|
|
43
|
+
|
|
44
|
+
- **Automate research workflows**: Search literature, fetch full article metadata, track citations, and generate research plans programmatically.
|
|
45
|
+
- **Gain research insights**: Access detailed publication data, author information, journal details, MeSH terms, and citation networks without leaving the host application.
|
|
46
|
+
- **Integrate PubMed into AI-driven research**: Enable LLMs to conduct literature reviews, analyze research trends, and support evidence-based decision making.
|
|
47
|
+
- **Visualize research data**: Generate charts and visualizations from publication metadata and search results.
|
|
48
|
+
|
|
49
|
+
Built on the robust `mcp-ts-template`, this server provides a standardized, secure, and efficient way to expose PubMed functionality via the MCP standard. It achieves this by integrating with NCBI's E-utilities API, ensuring compliance with rate limits and providing comprehensive error handling.
|
|
50
|
+
|
|
51
|
+
> **Developer Note**: This repository includes a [.clinerules](.clinerules) file that serves as a developer cheat sheet for your LLM coding agent with quick reference for the codebase patterns, file locations, and code snippets.
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
### Core Utilities
|
|
56
|
+
|
|
57
|
+
Leverages the robust utilities provided by the `mcp-ts-template`:
|
|
58
|
+
|
|
59
|
+
- **Logging**: Structured, configurable logging (file rotation, console, MCP notifications) with sensitive data redaction.
|
|
60
|
+
- **Error Handling**: Centralized error processing, standardized error types (`McpError`), and automatic logging.
|
|
61
|
+
- **Configuration**: Environment variable loading (`dotenv`) with comprehensive validation.
|
|
62
|
+
- **Input Validation/Sanitization**: Uses `zod` for schema validation and custom sanitization logic.
|
|
63
|
+
- **Request Context**: Tracking and correlation of operations via unique request IDs.
|
|
64
|
+
- **Type Safety**: Strong typing enforced by TypeScript and Zod schemas.
|
|
65
|
+
- **HTTP Transport Option**: Built-in Express server with SSE, session management, CORS support, and JWT authentication.
|
|
66
|
+
- **Rate Limiting**: Built-in request queuing and delay management for NCBI API compliance.
|
|
67
|
+
|
|
68
|
+
### PubMed Integration
|
|
69
|
+
|
|
70
|
+
- **NCBI E-utilities Integration**: Comprehensive access to ESearch, EFetch, ELink, and ESummary APIs with automatic XML parsing.
|
|
71
|
+
- **Advanced Search Capabilities**: Complex query construction with date ranges, publication types, author filters, and MeSH term support.
|
|
72
|
+
- **Full Article Metadata**: Retrieve complete publication data including abstracts, authors, affiliations, journal information, DOIs, and citation data.
|
|
73
|
+
- **Citation Network Analysis**: Find related articles, citing articles, and reference lists through ELink integration.
|
|
74
|
+
- **Research Planning**: Generate structured research plans with automated literature search strategies.
|
|
75
|
+
- **Data Visualization**: Create PNG charts from publication metadata (bar charts, line graphs, scatter plots).
|
|
76
|
+
- **Multiple Output Formats**: Support for JSON, MEDLINE text, full XML, and formatted citations (RIS, BibTeX, APA, MLA).
|
|
77
|
+
- **Batch Processing**: Efficient handling of multiple PMIDs with pagination support.
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
### Prerequisites
|
|
82
|
+
|
|
83
|
+
- [Node.js (>=18.0.0)](https://nodejs.org/)
|
|
84
|
+
- [npm](https://www.npmjs.com/) (comes with Node.js)
|
|
85
|
+
- **NCBI API Key** (recommended for higher rate limits) - [Get one here](https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/)
|
|
86
|
+
|
|
87
|
+
### Install via npm (recommended)
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npm install @cyanheads/pubmed-mcp-server
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Alternatively Install from Source
|
|
30
94
|
|
|
31
|
-
|
|
32
|
-
| :----------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
-
| **🔌 MCP Compliant** | Fully functional server supporting `stdio` and `http` (SSE) transports. |
|
|
34
|
-
| **🚀 Production-Ready Utils** | Includes robust logging, error handling, ID generation, rate limiting, request context tracking, and input sanitization. |
|
|
35
|
-
| **🔒 Secure & Type-Safe** | Built with TypeScript & Zod for strong type checking and input validation. Manages NCBI API keys, implements rate limiting, and features JWT-based auth middleware for HTTP. |
|
|
36
|
-
| **⚙️ Advanced Error Handling** | Consistent error categorization, detailed logging, and centralized handling, including specific error types for NCBI interactions. |
|
|
37
|
-
| **📚 Well-Documented** | Comprehensive JSDoc comments, API references, and project specifications. |
|
|
38
|
-
| **🤖 Agent-Friendly** | Includes a `.clinerules` developer cheatsheet tailored for LLM coding agents using this server. |
|
|
39
|
-
| **🛠️ Developer Utilities** | Scripts for cleaning builds, setting executable permissions, generating directory trees, and fetching OpenAPI specifications. |
|
|
95
|
+
1. Clone the repository:
|
|
40
96
|
|
|
41
|
-
|
|
97
|
+
```bash
|
|
98
|
+
git clone https://github.com/cyanheads/pubmed-mcp-server.git
|
|
99
|
+
cd pubmed-mcp-server
|
|
100
|
+
```
|
|
42
101
|
|
|
43
|
-
|
|
102
|
+
2. Install dependencies:
|
|
44
103
|
|
|
45
|
-
|
|
104
|
+
```bash
|
|
105
|
+
npm install
|
|
106
|
+
```
|
|
46
107
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
108
|
+
3. Build the project:
|
|
109
|
+
```bash
|
|
110
|
+
npm run build
|
|
111
|
+
*or npm run rebuild*
|
|
112
|
+
```
|
|
51
113
|
|
|
52
|
-
|
|
114
|
+
## Configuration
|
|
53
115
|
|
|
54
|
-
|
|
55
|
-
npm install
|
|
56
|
-
```
|
|
116
|
+
### Environment Variables
|
|
57
117
|
|
|
58
|
-
|
|
59
|
-
Create a `.env` file in the project root. Key variables:
|
|
118
|
+
Configure the server using environment variables. These environmental variables are set within your MCP client config/settings (e.g. `claude_desktop_config.json` for Claude Desktop)
|
|
60
119
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
120
|
+
| Variable | Description | Default |
|
|
121
|
+
| ---------------------- | ---------------------------------------------------------------------------------------- | ------------------------------ |
|
|
122
|
+
| `MCP_TRANSPORT_TYPE` | Transport mechanism: `stdio` or `http`. | `stdio` |
|
|
123
|
+
| `MCP_HTTP_PORT` | Port for the HTTP server (if `MCP_TRANSPORT_TYPE=http`). | `3010` |
|
|
124
|
+
| `MCP_HTTP_HOST` | Host address for the HTTP server (if `MCP_TRANSPORT_TYPE=http`). | `127.0.0.1` |
|
|
125
|
+
| `MCP_ALLOWED_ORIGINS` | Comma-separated list of allowed origins for CORS (if `MCP_TRANSPORT_TYPE=http`). | (none) |
|
|
126
|
+
| `MCP_LOG_LEVEL` | Logging level (`debug`, `info`, `notice`, `warning`, `error`, `crit`, `alert`, `emerg`). | `debug` |
|
|
127
|
+
| `MCP_AUTH_SECRET_KEY` | **Required for HTTP transport.** Minimum 32-character secret key for JWT authentication. | (none) |
|
|
128
|
+
| `NCBI_API_KEY` | **Recommended.** Your NCBI API Key for higher rate limits and reliable access. | (none) |
|
|
129
|
+
| `NCBI_TOOL_IDENTIFIER` | Tool identifier for NCBI E-utility requests. | `@cyanheads/pubmed-mcp-server` |
|
|
130
|
+
| `LOGS_DIR` | Directory for log file storage. | `logs/` |
|
|
64
131
|
|
|
65
|
-
|
|
66
|
-
# NCBI_API_KEY=your_ncbi_api_key_here
|
|
67
|
-
# NCBI_ADMIN_EMAIL=your_email@example.com # Recommended if using an API key
|
|
68
|
-
# NCBI_TOOL_IDENTIFIER=@cyanheads/pubmed-mcp-server/1.0.13 # Optional: Tool identifier for NCBI (defaults to current version)
|
|
69
|
-
```
|
|
132
|
+
### MCP Client Settings
|
|
70
133
|
|
|
71
|
-
|
|
134
|
+
Add to your MCP client settings (e.g., `cline_mcp_settings.json`):
|
|
72
135
|
|
|
73
|
-
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"mcpServers": {
|
|
139
|
+
"pubmed-mcp-server": {
|
|
140
|
+
"command": "node",
|
|
141
|
+
"args": ["/path/to/your/pubmed-mcp-server/dist/index.js"],
|
|
142
|
+
"env": {
|
|
143
|
+
"NCBI_API_KEY": "your_ncbi_api_key_here"
|
|
144
|
+
},
|
|
145
|
+
"disabled": false,
|
|
146
|
+
"autoApprove": []
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
74
151
|
|
|
75
|
-
|
|
152
|
+
**Note**: You can see [mcp.json](mcp.json) for an example MCP client configuration file that includes the PubMed MCP Server.
|
|
76
153
|
|
|
77
|
-
|
|
78
|
-
npm run build
|
|
79
|
-
# Or use 'npm run rebuild' for a clean install (deletes node_modules, logs, dist)
|
|
80
|
-
```
|
|
154
|
+
## Project Structure
|
|
81
155
|
|
|
82
|
-
|
|
156
|
+
The codebase follows a modular structure within the `src/` directory:
|
|
83
157
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
158
|
+
```
|
|
159
|
+
src/
|
|
160
|
+
├── index.ts # Entry point: Initializes and starts the server
|
|
161
|
+
├── config/ # Configuration loading (env vars, package info)
|
|
162
|
+
│ └── index.ts
|
|
163
|
+
├── mcp-server/ # Core MCP server logic and capability registration
|
|
164
|
+
│ ├── server.ts # Server setup, capability registration
|
|
165
|
+
│ ├── transports/ # Transport handling (stdio, http)
|
|
166
|
+
│ ├── resources/ # MCP Resource implementations
|
|
167
|
+
│ └── tools/ # MCP Tool implementations (subdirs per tool)
|
|
168
|
+
├── services/ # External service integrations
|
|
169
|
+
│ ├── NCBI/ # NCBI E-utilities API client and parsing
|
|
170
|
+
│ └── llm-providers/ # LLM provider integrations (optional)
|
|
171
|
+
├── types-global/ # Shared TypeScript type definitions
|
|
172
|
+
└── utils/ # Common utility functions (logger, error handler, etc.)
|
|
173
|
+
```
|
|
87
174
|
|
|
88
|
-
|
|
175
|
+
For a detailed file tree, run `npm run tree` or see [docs/tree.md](docs/tree.md).
|
|
89
176
|
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
npm start
|
|
93
|
-
# or 'npm run start:stdio'
|
|
94
|
-
```
|
|
95
|
-
- **Via HTTP (SSE):** (Ensure `MCP_TRANSPORT_TYPE=http` and `MCP_AUTH_SECRET_KEY` are set in your `.env`)
|
|
96
|
-
```bash
|
|
97
|
-
npm run start:http
|
|
98
|
-
```
|
|
99
|
-
This starts an HTTP server (default: `http://127.0.0.1:3010`) using Server-Sent Events.
|
|
177
|
+
## Tools
|
|
100
178
|
|
|
101
|
-
|
|
179
|
+
The PubMed MCP Server provides a comprehensive suite of tools for biomedical literature research, callable via the Model Context Protocol.
|
|
102
180
|
|
|
103
|
-
|
|
181
|
+
| Tool Name | Description | Key Arguments |
|
|
182
|
+
| :------------------------------- | :--------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- |
|
|
183
|
+
| `search_pubmed_articles` | Searches PubMed for articles using queries, filters, and date ranges. | `queryTerm`, `maxResults?`, `sortBy?`, `dateRange?`, `filterByPublicationTypes?`, `fetchBriefSummaries?` |
|
|
184
|
+
| `fetch_pubmed_content` | Fetches detailed article information using PMIDs or search history. | `pmids?`, `queryKey?`, `webEnv?`, `detailLevel?`, `includeMeshTerms?`, `includeGrantInfo?` |
|
|
185
|
+
| `get_pubmed_article_connections` | Finds related articles, citations, and references for a given PMID. | `sourcePmid`, `relationshipType?`, `maxRelatedResults?`, `citationStyles?` |
|
|
186
|
+
| `pubmed_research_agent` | Generates structured research plans with literature search strategies. | `project_title_suggestion`, `primary_research_goal`, `research_keywords`, `organism_focus?`, `p1_*`, etc. |
|
|
187
|
+
| `generate_pubmed_chart` | Creates customizable PNG charts from structured publication data. | `chartType`, `dataValues`, `xField`, `yField`, `title?`, `colorField?`, `seriesField?`, `sizeField?` |
|
|
104
188
|
|
|
105
|
-
|
|
189
|
+
_Note: All tools support comprehensive error handling and return structured JSON responses._
|
|
106
190
|
|
|
107
|
-
|
|
108
|
-
| :---------------------- | :----------------------------------------------------------------------------------------------------- | :--------------------------------------- |
|
|
109
|
-
| `MCP_TRANSPORT_TYPE` | Server transport: `stdio` or `http`. | `stdio` |
|
|
110
|
-
| `MCP_HTTP_PORT` | Port for the HTTP server (if `MCP_TRANSPORT_TYPE=http`). | `3010` |
|
|
111
|
-
| `MCP_HTTP_HOST` | Host address for the HTTP server (if `MCP_TRANSPORT_TYPE=http`). | `127.0.0.1` |
|
|
112
|
-
| `MCP_ALLOWED_ORIGINS` | Comma-separated allowed origins for CORS (if `MCP_TRANSPORT_TYPE=http`). | (none) |
|
|
113
|
-
| `MCP_LOG_LEVEL` | Server logging level (`debug`, `info`, `warning`, `error`, etc.). | `debug` |
|
|
114
|
-
| `LOGS_DIR` | Directory for log files. | `logs/` (in project root) |
|
|
115
|
-
| `NODE_ENV` | Runtime environment (`development`, `production`). | `development` |
|
|
116
|
-
| `MCP_AUTH_SECRET_KEY` | **Required for HTTP transport.** Secret key (min 32 chars) for signing/verifying auth tokens (JWT). | (none - **MUST be set in production**) |
|
|
117
|
-
| `NCBI_API_KEY` | **Optional, but highly recommended.** Your NCBI API Key for higher rate limits (10/sec vs 3/sec). | (none) |
|
|
118
|
-
| `NCBI_ADMIN_EMAIL` | **Optional, but recommended if using an API key.** Your email for NCBI contact. | (none) |
|
|
119
|
-
| `NCBI_TOOL_IDENTIFIER` | Optional. Tool identifier sent to NCBI. | `@cyanheads/pubmed-mcp-server/<version>` |
|
|
120
|
-
| `NCBI_REQUEST_DELAY_MS` | Milliseconds to wait between NCBI requests. Dynamically set (e.g., 100ms with API key, 334ms without). | (see `src/config/index.ts`) |
|
|
121
|
-
| `NCBI_MAX_RETRIES` | Maximum number of retries for failed NCBI requests. | `3` |
|
|
191
|
+
## Examples
|
|
122
192
|
|
|
123
|
-
|
|
193
|
+
Comprehensive usage examples are available in the [`examples/`](examples/) directory:
|
|
124
194
|
|
|
125
|
-
|
|
195
|
+
- [Search PubMed Articles](examples/search_pubmed_articles_example.md)
|
|
196
|
+
- [Fetch Article Content](examples/fetch_pubmed_content_example.md)
|
|
197
|
+
- [Article Connections](examples/get_pubmed_article_connections_1.md)
|
|
198
|
+
- [Research Planning](examples/pubmed_research_agent_example.md)
|
|
199
|
+
- [Chart Generation](examples/) - Generated chart examples (bar, line, scatter) are available in the `examples/` directory.
|
|
126
200
|
|
|
127
|
-
|
|
201
|
+
## Development
|
|
128
202
|
|
|
129
|
-
|
|
203
|
+
### Build and Test
|
|
130
204
|
|
|
131
|
-
|
|
205
|
+
```bash
|
|
206
|
+
# Build the project (compile TS to JS in dist/ and make executable)
|
|
207
|
+
npm run build
|
|
132
208
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- `server.ts`: Initializes the server instance and registers all tools and resources.
|
|
136
|
-
- `resources/`: Implementations for MCP resources (e.g., server status, PubMed statistics).
|
|
137
|
-
- `tools/`: Implementations for MCP tools (like `searchPubMedArticles`, `fetchPubMedContent`, `getPubMedArticleConnections`).
|
|
138
|
-
- `transports/`: Handles `stdio` and `http` (SSE) communication, including authentication for HTTP.
|
|
139
|
-
- `services/`: Integrations with external services.
|
|
140
|
-
- `NCBI/ncbiService.ts`: Manages all interactions with NCBI E-utilities, including API calls, rate limiting, and response parsing.
|
|
141
|
-
- `llm-providers/`: (Optional) For integrating LLM capabilities directly within the server.
|
|
142
|
-
- `types-global/`: Shared TypeScript definitions, especially for errors and MCP types.
|
|
143
|
-
- `utils/`: A comprehensive suite of reusable utilities for logging, error handling, security, parsing, metrics, and more.
|
|
209
|
+
# Test the server locally using the MCP inspector tool (stdio transport)
|
|
210
|
+
npm run inspector
|
|
144
211
|
|
|
145
|
-
|
|
212
|
+
# Test the server locally using the MCP inspector tool (http transport)
|
|
213
|
+
npm run inspector:http
|
|
146
214
|
|
|
147
|
-
|
|
215
|
+
# Clean build artifacts
|
|
216
|
+
npm run clean
|
|
148
217
|
|
|
149
|
-
|
|
218
|
+
# Generate a file tree representation for documentation
|
|
219
|
+
npm run tree
|
|
220
|
+
|
|
221
|
+
# Clean build artifacts and then rebuild the project
|
|
222
|
+
npm run rebuild
|
|
150
223
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
- Define Zod schemas for input validation.
|
|
154
|
-
- Write the function that interacts with `src/services/NCBI/ncbiService.ts` (e.g., `ncbiService.eLink(...)`).
|
|
155
|
-
- Parse the NCBI response and format it according to MCP specifications (`CallToolResult` or `ReadResourceResult`).
|
|
156
|
-
3. **Register the Capability (`registration.ts`)**:
|
|
157
|
-
- For tools: `server.tool(name, description, zodSchemaShape, handlerFunction)`
|
|
158
|
-
- For resources: `server.resource(registrationName, template, metadata, handlerFunction)`
|
|
159
|
-
- Always wrap your logic in `ErrorHandler.tryCatch` for robust error management.
|
|
160
|
-
4. **Export and Integrate**: Export the registration function from your new directory's `index.ts` and call it within `src/mcp-server/server.ts`.
|
|
224
|
+
# Format code with Prettier
|
|
225
|
+
npm run format
|
|
161
226
|
|
|
162
|
-
|
|
227
|
+
# Start the server using stdio (default)
|
|
228
|
+
npm start
|
|
229
|
+
# Or explicitly:
|
|
230
|
+
npm run start:stdio
|
|
163
231
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- **[NCBI E-utilities Documentation](https://www.ncbi.nlm.nih.gov/books/NBK25501/)**
|
|
232
|
+
# Start the server using HTTP transport
|
|
233
|
+
npm run start:http
|
|
234
|
+
```
|
|
168
235
|
|
|
169
|
-
##
|
|
236
|
+
## License
|
|
170
237
|
|
|
171
|
-
This project is licensed under the Apache License 2.0
|
|
238
|
+
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
|
172
239
|
|
|
173
240
|
---
|
|
174
241
|
|
|
175
242
|
<div align="center">
|
|
176
|
-
|
|
243
|
+
Built with the <a href="https://modelcontextprotocol.io/">Model Context Protocol</a>
|
|
177
244
|
</div>
|
|
@@ -12,7 +12,7 @@ export declare const GeneratePubMedChartInputSchema: z.ZodObject<{
|
|
|
12
12
|
width: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
13
13
|
height: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
14
14
|
dataValues: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodAny>, "many">;
|
|
15
|
-
outputFormat: z.ZodDefault<z.ZodEnum<["
|
|
15
|
+
outputFormat: z.ZodDefault<z.ZodEnum<["png"]>>;
|
|
16
16
|
xField: z.ZodString;
|
|
17
17
|
yField: z.ZodString;
|
|
18
18
|
xFieldType: z.ZodOptional<z.ZodEnum<["nominal", "ordinal", "quantitative", "temporal"]>>;
|
|
@@ -26,7 +26,7 @@ export declare const GeneratePubMedChartInputSchema: z.ZodObject<{
|
|
|
26
26
|
}, "strip", z.ZodTypeAny, {
|
|
27
27
|
width: number;
|
|
28
28
|
height: number;
|
|
29
|
-
outputFormat: "
|
|
29
|
+
outputFormat: "png";
|
|
30
30
|
chartType: "bar" | "line" | "scatter";
|
|
31
31
|
dataValues: Record<string, any>[];
|
|
32
32
|
xField: string;
|
|
@@ -48,7 +48,7 @@ export declare const GeneratePubMedChartInputSchema: z.ZodObject<{
|
|
|
48
48
|
title?: string | undefined;
|
|
49
49
|
width?: number | undefined;
|
|
50
50
|
height?: number | undefined;
|
|
51
|
-
outputFormat?: "
|
|
51
|
+
outputFormat?: "png" | undefined;
|
|
52
52
|
xFieldType?: "nominal" | "ordinal" | "quantitative" | "temporal" | undefined;
|
|
53
53
|
yFieldType?: "nominal" | "ordinal" | "quantitative" | "temporal" | undefined;
|
|
54
54
|
colorField?: string | undefined;
|
|
@@ -6,71 +6,73 @@ import { logger, requestContextService, sanitizeInputForLogging, } from "../../.
|
|
|
6
6
|
export const GeneratePubMedChartInputSchema = z.object({
|
|
7
7
|
chartType: z
|
|
8
8
|
.enum(["bar", "line", "scatter"])
|
|
9
|
-
.describe("
|
|
10
|
-
title: z
|
|
9
|
+
.describe("Required. Specifies the type of chart to generate. Options: 'bar', 'line', 'scatter'."),
|
|
10
|
+
title: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Optional. The main title displayed above the chart. If omitted, no title is shown."),
|
|
11
14
|
width: z
|
|
12
15
|
.number()
|
|
13
16
|
.int()
|
|
14
17
|
.positive()
|
|
15
18
|
.optional()
|
|
16
19
|
.default(400)
|
|
17
|
-
.describe("
|
|
20
|
+
.describe("Optional. The width of the chart canvas in pixels. Must be a positive integer. Default: 400."),
|
|
18
21
|
height: z
|
|
19
22
|
.number()
|
|
20
23
|
.int()
|
|
21
24
|
.positive()
|
|
22
25
|
.optional()
|
|
23
26
|
.default(300)
|
|
24
|
-
.describe("
|
|
27
|
+
.describe("Optional. The height of the chart canvas in pixels. Must be a positive integer. Default: 300."),
|
|
25
28
|
dataValues: z
|
|
26
29
|
.array(z.record(z.string(), z.any()))
|
|
27
30
|
.min(1)
|
|
28
|
-
.describe("
|
|
31
|
+
.describe("Required. An array of data objects used to plot the chart. Each object represents a data point or bar, structured as key-value pairs (e.g., [{ 'year': '2020', 'articles': 150 }, { 'year': '2021', 'articles': 180 }]). Must contain at least one data object."),
|
|
29
32
|
outputFormat: z
|
|
30
|
-
.enum(["
|
|
31
|
-
.default("
|
|
32
|
-
.describe("Specifies the
|
|
33
|
-
"Currently, only 'svg' (Scalable Vector Graphics) is supported."),
|
|
33
|
+
.enum(["png"]) // Changed from svg to png
|
|
34
|
+
.default("png") // Changed default to png
|
|
35
|
+
.describe("Specifies the output format for the chart. Currently, only 'png' (Portable Network Graphics) is supported and is the default."),
|
|
34
36
|
xField: z
|
|
35
37
|
.string()
|
|
36
|
-
.describe("
|
|
38
|
+
.describe("Required. The name of the field in `dataValues` to be used for the X-axis (horizontal). This field determines the categories or values along the bottom of the chart (e.g., 'year', 'geneName', 'publicationCount')."),
|
|
37
39
|
yField: z
|
|
38
40
|
.string()
|
|
39
|
-
.describe("
|
|
41
|
+
.describe("Required. The name of the field in `dataValues` to be used for the Y-axis (vertical). This field determines the values plotted upwards on the chart (e.g., 'articles', 'expressionLevel', 'citationCount')."),
|
|
40
42
|
xFieldType: z
|
|
41
43
|
.enum(["nominal", "ordinal", "quantitative", "temporal"])
|
|
42
44
|
.optional()
|
|
43
|
-
.describe("
|
|
45
|
+
.describe("Optional. Specifies the data type of the X-axis field. Options: 'nominal' (categories), 'ordinal' (ordered categories), 'quantitative' (numerical), 'temporal' (dates/times). If omitted, a suitable default is chosen based on `chartType` (e.g., 'nominal' for bar charts, 'temporal' for line charts, 'quantitative' for scatter plots)."),
|
|
44
46
|
yFieldType: z
|
|
45
47
|
.enum(["nominal", "ordinal", "quantitative", "temporal"])
|
|
46
48
|
.optional()
|
|
47
|
-
.describe("
|
|
49
|
+
.describe("Optional. Specifies the data type of the Y-axis field. Options: 'nominal', 'ordinal', 'quantitative', 'temporal'. Defaults to 'quantitative' if omitted."),
|
|
48
50
|
// Optional fields for various chart types
|
|
49
51
|
colorField: z
|
|
50
52
|
.string()
|
|
51
53
|
.optional()
|
|
52
|
-
.describe("Optional
|
|
54
|
+
.describe("Optional. The name of the field in `dataValues` to use for color encoding. This can differentiate bars, lines, or points by color based on the values in this field (e.g., 'studyType', 'country')."),
|
|
53
55
|
colorFieldType: z
|
|
54
56
|
.enum(["nominal", "ordinal", "quantitative", "temporal"])
|
|
55
57
|
.optional()
|
|
56
|
-
.describe("
|
|
58
|
+
.describe("Optional. Specifies the data type of the `colorField`. Options: 'nominal', 'ordinal', 'quantitative', 'temporal'. Defaults to 'nominal' if `colorField` is provided and this is omitted."),
|
|
57
59
|
seriesField: z
|
|
58
60
|
.string()
|
|
59
61
|
.optional()
|
|
60
|
-
.describe("Optional
|
|
62
|
+
.describe("Optional. Primarily for line charts. The name of the field in `dataValues` used to create multiple distinct lines (series) on the same chart. Each unique value in this field will correspond to a separate line (e.g., 'drugName' to plot different drug efficacy trends). Often used with `colorField` implicitly or explicitly."),
|
|
61
63
|
seriesFieldType: z
|
|
62
64
|
.enum(["nominal", "ordinal", "quantitative", "temporal"])
|
|
63
65
|
.optional()
|
|
64
|
-
.describe("
|
|
66
|
+
.describe("Optional. Specifies the data type of the `seriesField`. Options: 'nominal', 'ordinal', 'quantitative', 'temporal'. Defaults to 'nominal' if `seriesField` is provided and this is omitted."),
|
|
65
67
|
// Scatter plot specific optional fields (can be expanded)
|
|
66
68
|
sizeField: z
|
|
67
69
|
.string()
|
|
68
70
|
.optional()
|
|
69
|
-
.describe("Optional field for encoding
|
|
71
|
+
.describe("Optional. For scatter plots. The name of the field in `dataValues` to use for encoding the size of the points. Larger values in this field will result in larger points on the scatter plot (e.g., 'sampleSize', 'effectMagnitude')."),
|
|
70
72
|
sizeFieldType: z
|
|
71
73
|
.enum(["quantitative", "ordinal"])
|
|
72
74
|
.optional()
|
|
73
|
-
.describe("
|
|
75
|
+
.describe("Optional. Specifies the data type of the `sizeField`. Options: 'quantitative', 'ordinal'. Defaults to 'quantitative' if `sizeField` is provided and this is omitted."),
|
|
74
76
|
// shapeField: z.string().optional().describe("Optional field for encoding point shape in scatter plots."), // Future enhancement
|
|
75
77
|
// shapeFieldType: z.enum(["nominal", "ordinal"]).optional().describe("Type of the shape field."), // Future enhancement
|
|
76
78
|
});
|
|
@@ -81,8 +83,9 @@ export async function generatePubMedChartLogic(input, parentRequestContext) {
|
|
|
81
83
|
input: sanitizeInputForLogging(input),
|
|
82
84
|
});
|
|
83
85
|
logger.info(`Executing 'generate_pubmed_chart'. Chart type: ${input.chartType}, Output format: ${input.outputFormat}`, operationContext);
|
|
84
|
-
if (input.outputFormat !== "
|
|
85
|
-
const unsupportedFormatError = new McpError(BaseErrorCode.VALIDATION_ERROR, `Unsupported output format: ${input.outputFormat}. Currently, only '
|
|
86
|
+
if (input.outputFormat !== "png") { // Changed from svg to png
|
|
87
|
+
const unsupportedFormatError = new McpError(BaseErrorCode.VALIDATION_ERROR, `Unsupported output format: ${input.outputFormat}. Currently, only 'png' is supported.`, // Changed message
|
|
88
|
+
{ requestedFormat: input.outputFormat });
|
|
86
89
|
logger.warning(unsupportedFormatError.message, operationContext);
|
|
87
90
|
return {
|
|
88
91
|
content: [
|
|
@@ -201,14 +204,24 @@ export async function generatePubMedChartLogic(input, parentRequestContext) {
|
|
|
201
204
|
}
|
|
202
205
|
const compiledVegaSpec = vegaLite.compile(vegaLiteSpec).spec;
|
|
203
206
|
const view = new vega.View(vega.parse(compiledVegaSpec), {
|
|
204
|
-
renderer: "
|
|
207
|
+
renderer: "canvas", // Explicitly set renderer to 'canvas'
|
|
205
208
|
});
|
|
206
|
-
const svgString = await view.toSVG();
|
|
207
|
-
|
|
209
|
+
// const svgString = await view.toSVG(); // Old SVG method
|
|
210
|
+
// New PNG method
|
|
211
|
+
// Initialize the view to ensure canvas is ready
|
|
212
|
+
await view.runAsync(); // Initialize and run the view
|
|
213
|
+
const canvas = await view.toCanvas(); // Render to canvas
|
|
214
|
+
// Cast to 'any' to access toBuffer, assuming it's a Node Canvas instance at runtime
|
|
215
|
+
const imageBuffer = await canvas.toBuffer("image/png"); // Get PNG buffer from canvas
|
|
208
216
|
const base64Data = imageBuffer.toString("base64");
|
|
209
|
-
const dataUriSvg = `data:image/svg+xml;base64,${base64Data}`;
|
|
210
217
|
return {
|
|
211
|
-
content: [
|
|
218
|
+
content: [
|
|
219
|
+
{
|
|
220
|
+
type: "image",
|
|
221
|
+
data: base64Data,
|
|
222
|
+
mimeType: "image/png", // Changed MIME type to image/png
|
|
223
|
+
},
|
|
224
|
+
],
|
|
212
225
|
isError: false,
|
|
213
226
|
};
|
|
214
227
|
}
|
|
@@ -5,10 +5,11 @@ export function registerGeneratePubMedChartTool(server) {
|
|
|
5
5
|
const operation = "registerGeneratePubMedChartTool";
|
|
6
6
|
const regContext = requestContextService.createRequestContext({ operation });
|
|
7
7
|
try {
|
|
8
|
-
server.tool("generate_pubmed_chart", "Generates a chart
|
|
9
|
-
"Supports
|
|
10
|
-
"
|
|
11
|
-
"
|
|
8
|
+
server.tool("generate_pubmed_chart", "Generates a customizable chart (SVG) from structured data. " +
|
|
9
|
+
"Supports 'bar', 'line', and 'scatter' plots. " +
|
|
10
|
+
"Requires data values and field mappings for axes. " +
|
|
11
|
+
"Optional parameters allow for titles, dimensions, and color/size/series encoding. " +
|
|
12
|
+
"Internally uses Vega-Lite to produce an SVG image.", GeneratePubMedChartInputSchema.shape, async (validatedInput, mcpProvidedContext) => {
|
|
12
13
|
const handlerRequestContext = requestContextService.createRequestContext({
|
|
13
14
|
parentRequestId: regContext.requestId,
|
|
14
15
|
operation: "generatePubMedChartToolHandler",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/pubmed-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "A Model Context Protocol (MCP) server enabling AI agents to intelligently search, retrieve, and analyze biomedical literature from PubMed via NCBI E-utilities. Built on the mcp-ts-template for robust, production-ready performance.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -33,34 +33,35 @@
|
|
|
33
33
|
"start:client-cli": "node dist/mcp-client/cli/mcp-client-cli.js"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@google/genai": "^1.0
|
|
37
|
-
"@modelcontextprotocol/sdk": "^1.12.
|
|
36
|
+
"@google/genai": "^1.3.0",
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
38
38
|
"@types/jsonwebtoken": "^9.0.9",
|
|
39
|
-
"@types/node": "^22.15.
|
|
39
|
+
"@types/node": "^22.15.29",
|
|
40
40
|
"@types/sanitize-html": "^2.16.0",
|
|
41
41
|
"@types/validator": "13.15.1",
|
|
42
42
|
"axios": "^1.9.0",
|
|
43
|
+
"canvas": "^3.1.0",
|
|
43
44
|
"chalk": "^5.4.1",
|
|
44
|
-
"chrono-node": "^2.8.
|
|
45
|
+
"chrono-node": "^2.8.2",
|
|
45
46
|
"cli-table3": "^0.6.5",
|
|
46
47
|
"dotenv": "^16.5.0",
|
|
47
48
|
"express": "^5.1.0",
|
|
48
49
|
"fast-xml-parser": "^5.2.3",
|
|
49
|
-
"ignore": "^7.0.
|
|
50
|
+
"ignore": "^7.0.5",
|
|
50
51
|
"jsonwebtoken": "^9.0.2",
|
|
51
|
-
"openai": "^
|
|
52
|
+
"openai": "^5.1.0",
|
|
52
53
|
"partial-json": "^0.1.7",
|
|
53
54
|
"sanitize-html": "^2.17.0",
|
|
54
55
|
"tiktoken": "^1.0.21",
|
|
55
56
|
"ts-node": "^10.9.2",
|
|
56
57
|
"typescript": "^5.8.3",
|
|
57
|
-
"validator": "13.15.
|
|
58
|
+
"validator": "13.15.15",
|
|
58
59
|
"vega": "^6.1.2",
|
|
59
60
|
"vega-lite": "^6.1.0",
|
|
60
61
|
"winston": "^3.17.0",
|
|
61
62
|
"winston-daily-rotate-file": "^5.0.0",
|
|
62
|
-
"yargs": "^
|
|
63
|
-
"zod": "^3.25.
|
|
63
|
+
"yargs": "^18.0.0",
|
|
64
|
+
"zod": "^3.25.50"
|
|
64
65
|
},
|
|
65
66
|
"keywords": [
|
|
66
67
|
"mcp",
|
|
@@ -94,6 +95,6 @@
|
|
|
94
95
|
"@types/js-yaml": "^4.0.9",
|
|
95
96
|
"js-yaml": "^4.1.0",
|
|
96
97
|
"prettier": "^3.5.3",
|
|
97
|
-
"typedoc": "^0.28.
|
|
98
|
+
"typedoc": "^0.28.5"
|
|
98
99
|
}
|
|
99
100
|
}
|