@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 Pubmed
1
+ # PubMed MCP Server
2
2
 
3
3
  [![TypeScript](https://img.shields.io/badge/TypeScript-^5.8.3-blue.svg)](https://www.typescriptlang.org/)
4
- [![Model Context Protocol SDK](https://img.shields.io/badge/MCP%20SDK-1.12.0-green.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
5
- [![MCP Spec Version](https://img.shields.io/badge/MCP%20Spec-2025--03--26-lightgrey.svg)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/changelog.mdx)
6
- [![Version](https://img.shields.io/badge/Version-1.0.13-blue.svg)](./CHANGELOG.md)
4
+ [![Model Context Protocol](https://img.shields.io/badge/MCP%20SDK-^1.12.1-green.svg)](https://modelcontextprotocol.io/)
5
+ [![Version](https://img.shields.io/badge/Version-1.0.16-blue.svg)](./CHANGELOG.md)
7
6
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
- [![Status](https://img.shields.io/badge/Status-Beta-orange.svg)](https://github.com/cyanheads/pubmed-mcp-server/issues)
7
+ [![Status](https://img.shields.io/badge/Status-Stable-green.svg)](https://github.com/cyanheads/pubmed-mcp-server/issues)
9
8
  [![GitHub](https://img.shields.io/github/stars/cyanheads/pubmed-mcp-server?style=social)](https://github.com/cyanheads/pubmed-mcp-server)
10
9
 
11
- **Unlock the power of biomedical literature for your AI agents with the PubMed MCP Server!**
10
+ **Empower your AI agents and research tools with seamless PubMed integration!**
12
11
 
13
- This server acts as a bridge, connecting your AI to NCBI's PubMed and E-utilities through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). It empowers language models to seamlessly search, retrieve, and analyze biomedical articles and data. Built with TypeScript and adhering to the **MCP 2025-03-26 specification**, it's designed for robustness and includes production-grade utilities.
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 (SVG) 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 an SVG. |
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
- ## Key Features Beyond Tools
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
- | Feature Category | Description |
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
- ## 🚀 Quick Start
97
+ ```bash
98
+ git clone https://github.com/cyanheads/pubmed-mcp-server.git
99
+ cd pubmed-mcp-server
100
+ ```
42
101
 
43
- Get the PubMed MCP server running in minutes:
102
+ 2. Install dependencies:
44
103
 
45
- 1. **Clone the repository:**
104
+ ```bash
105
+ npm install
106
+ ```
46
107
 
47
- ```bash
48
- git clone https://github.com/cyanheads/pubmed-mcp-server.git
49
- cd pubmed-mcp-server
50
- ```
108
+ 3. Build the project:
109
+ ```bash
110
+ npm run build
111
+ *or npm run rebuild*
112
+ ```
51
113
 
52
- 2. **Install dependencies:**
114
+ ## Configuration
53
115
 
54
- ```bash
55
- npm install
56
- ```
116
+ ### Environment Variables
57
117
 
58
- 3. **Configure Environment Variables (`.env` file):**
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
- ```env
62
- # REQUIRED FOR HTTP TRANSPORT
63
- MCP_AUTH_SECRET_KEY=generate_a_strong_random_32_plus_char_secret_key
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
- # RECOMMENDED FOR NCBI E-UTILITIES (for higher rate limits)
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
- For all options, see the [Configuration](#⚙️-configuration) section below or the [Developer Cheatsheet (.clinerules)](./.clinerules).
134
+ Add to your MCP client settings (e.g., `cline_mcp_settings.json`):
72
135
 
73
- New example files for each tool are available in the `examples/` directory (e.g., `examples/search_pubmed_articles_example.md`, `examples/generate_pubmed_chart_example_bar.svg`).
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
- 4. **Build the project:**
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
- ```bash
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
- 5. **Format the code (Optional but Recommended):**
156
+ The codebase follows a modular structure within the `src/` directory:
83
157
 
84
- ```bash
85
- npm run format
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
- 6. **Run the Server:**
175
+ For a detailed file tree, run `npm run tree` or see [docs/tree.md](docs/tree.md).
89
176
 
90
- - **Via Stdio (Default):** Many MCP host applications will run this automatically using `stdio`. To run manually for testing:
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
- ## ⚙️ Configuration
179
+ The PubMed MCP Server provides a comprehensive suite of tools for biomedical literature research, callable via the Model Context Protocol.
102
180
 
103
- ### Server Configuration (Environment Variables)
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
- Configure the PubMed MCP server's behavior using environment variables (typically in a `.env` file).
189
+ _Note: All tools support comprehensive error handling and return structured JSON responses._
106
190
 
107
- | Variable | Description | Default |
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
- **Note on HTTP Port Retries:** If the `MCP_HTTP_PORT` is busy, the server automatically tries the next port (up to 15 times).
193
+ Comprehensive usage examples are available in the [`examples/`](examples/) directory:
124
194
 
125
- **Security Note for HTTP Transport:** When using `MCP_TRANSPORT_TYPE=http`, authentication is **mandatory** as per the MCP specification. This server includes JWT-based authentication middleware. You **MUST** set a strong, unique `MCP_AUTH_SECRET_KEY` in your production environment.
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
- For a **comprehensive list of all available environment variables**, their descriptions, and default values, please review the configuration loader at `src/config/index.ts`.
201
+ ## Development
128
202
 
129
- ## 🏗️ Project Structure Overview
203
+ ### Build and Test
130
204
 
131
- The `src/` directory contains the core logic:
205
+ ```bash
206
+ # Build the project (compile TS to JS in dist/ and make executable)
207
+ npm run build
132
208
 
133
- - `config/`: Environment variable loading and package information.
134
- - `mcp-server/`: The heart of the PubMed MCP server.
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
- For a detailed file tree, run: `npm run tree` or see [Directory Tree](./docs/tree.md).
212
+ # Test the server locally using the MCP inspector tool (http transport)
213
+ npm run inspector:http
146
214
 
147
- ## 🧩 Extending with More PubMed Capabilities
215
+ # Clean build artifacts
216
+ npm run clean
148
217
 
149
- Adding new tools or resources is straightforward:
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
- 1. **Directory Setup**: Create a new directory under `src/mcp-server/tools/yourNewTool/` or `src/mcp-server/resources/yourNewResource/`.
152
- 2. **Implement Core Logic (`logic.ts`)**:
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
- ## 🌍 Learn More
227
+ # Start the server using stdio (default)
228
+ npm start
229
+ # Or explicitly:
230
+ npm run start:stdio
163
231
 
164
- - **[Model Context Protocol Official Site](https://modelcontextprotocol.io/)**
165
- - **[MCP Specification (2025-03-26)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/changelog.mdx)**
166
- - **[TypeScript SDK for MCP](https://github.com/modelcontextprotocol/typescript-sdk)**
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
- ## 📜 License
236
+ ## License
170
237
 
171
- This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.
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
- Empowering AI with PubMed | Built on the <a href="https://modelcontextprotocol.io/">Model Context Protocol</a>
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<["svg"]>>;
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: "svg";
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?: "svg" | undefined;
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("Type of chart to generate (e.g., 'bar', 'line', 'scatter')."),
10
- title: z.string().optional().describe("Title for the chart."),
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("Width of the chart in pixels."),
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("Height of the chart in pixels."),
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("Array of data objects to plot. Each object is a record (e.g., { category: 'A', amount: 28 })."),
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(["svg"])
31
- .default("svg")
32
- .describe("Specifies the desired output format for the generated chart. " +
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("Field name for the X-axis (e.g., 'category', 'date', 'metric1')."),
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("Field name for the Y-axis (e.g., 'amount', 'value', 'metric2')."),
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("Type of the X-axis field. Defaults appropriately for chart type if omitted (e.g., 'nominal' for bar, 'temporal' for line, 'quantitative' for scatter)."),
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("Type of the Y-axis field. Defaults to 'quantitative' if omitted."),
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 field name for color encoding."),
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("Type of the color field if provided. Defaults to 'nominal'."),
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 field name for creating multiple lines/series (typically for line charts)."),
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("Type of the series field if provided. Defaults to 'nominal'."),
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 point size in scatter plots."),
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("Type of the size field. Defaults to 'quantitative'."),
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 !== "svg") {
85
- const unsupportedFormatError = new McpError(BaseErrorCode.VALIDATION_ERROR, `Unsupported output format: ${input.outputFormat}. Currently, only 'svg' is supported.`, { requestedFormat: input.outputFormat });
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: "none",
207
+ renderer: "canvas", // Explicitly set renderer to 'canvas'
205
208
  });
206
- const svgString = await view.toSVG();
207
- const imageBuffer = Buffer.from(svgString, "utf-8");
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: [{ type: "text", text: dataUriSvg }],
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 image (SVG) from given input. " +
9
- "Supports different chart types like 'bar', 'line', and 'scatter'. " +
10
- "Provide data values and specify fields for axes and encoding. " +
11
- "The tool constructs a Vega-Lite specification internally and renders it as an SVG.", GeneratePubMedChartInputSchema.shape, async (validatedInput, mcpProvidedContext) => {
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.13",
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.1",
37
- "@modelcontextprotocol/sdk": "^1.12.0",
36
+ "@google/genai": "^1.3.0",
37
+ "@modelcontextprotocol/sdk": "^1.12.1",
38
38
  "@types/jsonwebtoken": "^9.0.9",
39
- "@types/node": "^22.15.21",
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.0",
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.4",
50
+ "ignore": "^7.0.5",
50
51
  "jsonwebtoken": "^9.0.2",
51
- "openai": "^4.103.0",
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.0",
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": "^17.7.2",
63
- "zod": "^3.25.28"
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.4"
98
+ "typedoc": "^0.28.5"
98
99
  }
99
100
  }