Content
# pkdb-mcp
MCP Server for [PK-DB](https://pk-db.com) REST API - Serving Pharmacokinetic and Pharmacodynamic Data Platform.
[](https://python.org)
[](LICENSE)
[](https://docs.astral.sh/ruff)
[](https://pypi.org/project/pkdb-mcp/)
`pkdb-mcp` connects AI agents with PK-DB via the [Model Context Protocol](https://modelcontextprotocol.io). On startup, it fetches PK-DB's live OpenAPI document and dynamically registers an MCP tool for each API operation - no manual interface bindings required.
---
<!-- README-I18N:START -->
**English** | [中文](./README.md)
<!-- README-I18N:END -->
## Features
- **Dynamic Tool Generation** - Reads PK-DB's live Swagger/OpenAPI document, registering all operations as MCP tools with type signatures.
- **Fallback Specification** - If live document is unavailable, server falls back to a built-in specification file containing core public interfaces.
- **Auxiliary Tools** - Always available for operation discovery and ad-hoc requests.
- **Swagger 2.0 and OpenAPI 3.x** - Transparently parses both formats.
- **Binary Responses** - Automatically Base64-encodes binary payloads like ZIP, PDF, XLSX.
- **Multi-Transport Channels** - Supports `stdio`, `SSE`, and `streamable-http` MCP transports.
## What is PK-DB?
[PK-DB](https://pk-db.com) is a pharmacokinetic data management web platform. Pharmacokinetics describes drug absorption, distribution, metabolism, and excretion using mathematical models. PK-DB stores PK/PD study data, NCA results, population PK models, and related metadata. The platform provides a [REST API](https://pk-db.com/api/v1/swagger.json) for querying studies, compounds, subjects, observational data, and performing statistical analysis.
## How It Works
```mermaid
flowchart LR
A[AI Agent / MCP Client] -->|MCP Protocol| B[pkdb-mcp Server]
B -->|On startup| C[PK-DB OpenAPI Document]
B -->|At runtime| D[PK-DB REST API]
C -->|Dynamically registers| B
```
At runtime, the server performs the following steps:
1. Fetches OpenAPI document from configured URL
2. Parses each `path + method` operation into a standardized operation catalog
3. Registers an MCP tool for each operation with properly typed parameters
4. Forwards incoming tool calls to PK-DB REST API
5. Returns JSON, plain text, or Base64-encoded binary responses
> [!NOTE]
> If live document fetching fails and `PKDB_USE_FALLBACK_SPEC` is set to `true` (default), the server falls back to a built-in specification file containing core public interfaces. To strictly rely on live documents, set it to `false`.
## Requirements
- Python 3.13+
- [uv](https://docs.astral.sh/uv/)
## Installation
```bash
# Recommended: Run directly from PyPI (no local install needed)
uvx pkdb-mcp
```
Or install from source:
```bash
git clone https://github.com/lyjjl/pkdb-mcp.git
cd pkdb-mcp
uv sync --extra dev
```
## Usage
### Running as MCP Server
```bash
# Run directly from PyPI (recommended)
uvx pkdb-mcp
# Or run from local source directory
uv run pkdb-mcp
```
### Configuring Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"pkdb": {
"command": "uvx",
"args": ["pkdb-mcp"],
"env": {
"PKDB_API_BASE_URL": "https://pk-db.com/api/v1",
"PKDB_OPENAPI_URL": "https://pk-db.com/api/v1/swagger.json"
}
}
}
}
```
If using local cloned source directory:
```json
{
"mcpServers": {
"pkdb": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/pkdb-mcp", "run", "pkdb-mcp"],
"env": {
"PKDB_API_BASE_URL": "https://pk-db.com/api/v1",
"PKDB_OPENAPI_URL": "https://pk-db.com/api/v1/swagger.json"
}
}
}
}
```
### Configuring OpenCode
Add to `opencode.jsonc`:
```jsonc
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"pkdb": {
"type": "local",
"command": ["uvx", "pkdb-mcp"],
"enabled": true,
"environment": {
"PKDB_API_BASE_URL": "https://pk-db.com/api/v1",
"PKDB_OPENAPI_URL": "https://pk-db.com/api/v1/swagger.json",
},
},
},
}
```
If using local cloned source directory:
```jsonc
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"pkdb": {
"type": "local",
"command": [
"uv",
"--directory",
"/absolute/path/to/pkdb-mcp",
"run",
"pkdb-mcp",
],
"enabled": true,
"environment": {
"PKDB_API_BASE_URL": "https://pk-db.com/api/v1",
"PKDB_OPENAPI_URL": "https://pk-db.com/api/v1/swagger.json",
},
},
},
}
```
### Configuring Codex
Add to `~/.codex/config.toml`:
```toml
[mcp_servers.pkdb]
command = "uvx"
args = ["pkdb-mcp"]
[mcp_servers.pkdb.env]
PKDB_API_BASE_URL = "https://pk-db.com/api/v1"
PKDB_OPENAPI_URL = "https://pk-db.com/api/v1/swagger.json"
```
If using local cloned source directory:
```toml
[mcp_servers.pkdb]
command = "uv"
args = ["--directory", "/absolute/path/to/pkdb-mcp", "run", "pkdb-mcp"]
[mcp_servers.pkdb.env]
PKDB_API_BASE_URL = "https://pk-db.com/api/v1"
PKDB_OPENAPI_URL = "https://pk-db.com/api/v1/swagger.json"
```
> [!TIP]
> Set `PKDB_API_TOKEN` in the `env` block to access authenticated write/review endpoints. Do not store write-enabled tokens in shared config files.
## Configuration
All configuration options are environment variables prefixed with `PKDB_`:
| Variable | Default | Description |
| --- | --- | --- |
| `PKDB_API_BASE_URL` | `https://pk-db.com/api/v1` | REST API base URL |
| `PKDB_OPENAPI_URL` | `https://pk-db.com/api/v1/swagger.json` | OpenAPI document URL |
| `PKDB_API_TOKEN` | _(unset)_ | Optional token for authenticated endpoints |
| `PKDB_USE_FALLBACK_SPEC` | `true` | Whether to fall back to built-in spec if live document is unavailable |
| `PKDB_MCP_TRANSPORT` | `stdio` | MCP transport mode (`stdio`, `sse`, or `streamable-http`) |
| `PKDB_MCP_SERVER_NAME` | `pkdb-mcp` | MCP server name advertised to clients |
| `PKDB_HTTP_TIMEOUT_SECONDS` | `30` | HTTP request timeout (seconds) |
| `PKDB_PROXY` | _(unset)_ | Optional HTTP/SOCKS proxy URL (e.g., `http://proxy:8080`); SOCKS requires additional `socks` dependency |
The project includes `.env.example` as a sample environment configuration file.
## Tools
### Generated Interface Tools
Each OpenAPI operation is registered as a tool prefixed with `pkdb_`. For example, the `statistics_list` operation becomes:
```text
pkdb_statistics_list
```
Tool names are normalized to valid snake_case Python identifiers. Parameters are keyword-only, with types derived from the OpenAPI document. Optional parameters default to `None`, while required parameters have no default values. When upstream documentation does not provide an operation ID, the server derives one automatically from the HTTP method and path.
### Auxiliary Tools
The following tools are always available, regardless of loaded specifications:
| Tool | Purpose |
| --- | --- |
| `pkdb_list_operations` | Lists all loaded operations and their metadata. Supports `tag` and `search` filters. |
| `pkdb_describe_operation` | Displays an operation's parameters, request body, and full description. |
| `pkdb_raw_request` | Performs an arbitrary HTTP request to the PK-DB API. Useful for new interfaces added but not yet included in the current document. |
### Response Format
All tools return a JSON object with the following fields:
- `status_code` - HTTP status code
- `ok` - Whether the request was successful (2xx)
- `content_type` - Response content type
- `data` / `text` / `data_base64` - Response payload in corresponding format
Binary responses (ZIP, PDF, XLSX, etc.) are Base64-encoded and include an `encoding` field and `size_bytes` field.
## Architecture
```
src/pkdb_mcp/
├── __init__.py # Package metadata
├── __main__.py # Command-line entry point
├── server.py # FastMCP server factory
├── openapi.py # OpenAPI loading, parsing, and normalization
├── client.py # HTTP client for PK-DB operations
├── registry.py # MCP tool registration
├── settings.py # Environment variable-based configuration
├── errors.py # Domain-specific exceptions
├── types.py # JSON type aliases
└── specs/ # Built-in fallback specifications
```
The project intentionally remains lightweight: OpenAPI parsing, HTTP execution, MCP registration, and configuration have clear responsibilities, with no heavy frameworks besides MCP Python SDK, httpx, and pydantic.
## Development
```bash
# Format
uv run ruff format .
# Lint
uv run ruff check .
# Type check
uv run ty check
# Run tests
uv run pytest
```
### CI Pipeline
The project uses GitHub Actions - see [`.github/workflows/ci.yml`](.github/workflows/ci.yml). On each push and pull request, the CI pipeline runs ruff formatting, ruff linting, pytest testing, and ty type checking.