@kinginsun/mcp-drugsea 0.1.0 → 0.2.0

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
@@ -2,11 +2,11 @@
2
2
 
3
3
  MCP (Model Context Protocol) stdio server for [DrugSea / Yaohai](https://db.drugsea.cn) pharmaceutical databases.
4
4
 
5
- The server forwards tool calls to `https://api2.drugsea.cn` with header `X-Yaohai-Api-Key`. It covers:
5
+ The server forwards tool calls to **`https://db3.drugsea.cn/api`** with personal user token auth (`Authorization: Bearer ysk_…`). It covers:
6
6
 
7
7
  - **yaohai-*** — cross-database catalog / search / detail / global / smart-search (`POST /g/mcp/yaohai/*`)
8
- - **product-cn-*** — already-marketed China products (`GET /product/cn/...`)
9
- - **reg-cn-*** — CDE registration / review pipeline (`GET /b/drugreg/cn/...` and facet prefix `/b/es/drugreg/cn/list`)
8
+ - **product-cn-*** — already-marketed China products (search/detail via MCP on db3; facets via GET)
9
+ - **reg-cn-*** — CDE registration / review pipeline (search/detail via MCP on db3; facets via GET)
10
10
 
11
11
  **GitHub:** [github.com/kinginsun/mcp-drugsea](https://github.com/kinginsun/mcp-drugsea)
12
12
 
@@ -24,25 +24,22 @@ npx -y @kinginsun/mcp-drugsea
24
24
 
25
25
  ## Configuration
26
26
 
27
- ### `YAOHAI_MCP_API_KEY` (required)
27
+ ### `YAOHAI_MCP_TOKEN` (required)
28
28
 
29
- The server accepts either:
29
+ Authentication uses **personal user tokens only** (`ysk_` + 32 hex chars). The legacy shared `X-Yaohai-Api-Key` header is **not supported**.
30
30
 
31
31
  | Credential | Format | HTTP header |
32
32
  |------------|--------|-------------|
33
- | Shared MCP key | opaque string (server env `YAOHAI_MCP_API_KEY`) | `X-Yaohai-Api-Key` |
34
33
  | Personal user token | `ysk_` + 32 hex chars | `Authorization: Bearer ysk_…` |
35
34
 
36
- This client auto-selects the header from the value shape. You may set `YAOHAI_MCP_TOKEN` instead of `YAOHAI_MCP_API_KEY` for a user token.
37
-
38
- **Note:** Production MCP with personal `ysk_` tokens is deployed at **`https://db3.drugsea.cn/api/g/mcp/*`**. Legacy `api2.drugsea.cn` accepts only the shared `X-Yaohai-Api-Key`. On db3, direct GET list/facet routes return encrypted payloads; this client auto-routes `product-cn-search` / `reg-cn-search` / detail through MCP POST when the base URL contains `db3.drugsea.cn`.
39
-
40
- Obtain a key from the DrugSea / Yaohai operator, then:
35
+ Obtain a token from DrugSea / Yaohai (user account settings), then:
41
36
 
42
37
  ```bash
43
- export YAOHAI_MCP_API_KEY=your_api_key_here
38
+ export YAOHAI_MCP_TOKEN=ysk_your_token_here
44
39
  ```
45
40
 
41
+ On db3, direct GET list routes may return encrypted payloads; this client auto-routes `product-cn-search` / `reg-cn-search` / detail through MCP POST when the base URL contains `db3.drugsea.cn`.
42
+
46
43
  ### Optional
47
44
 
48
45
  | Variable | Default | Description |
@@ -60,7 +57,7 @@ export YAOHAI_MCP_API_KEY=your_api_key_here
60
57
  "command": "npx",
61
58
  "args": ["-y", "@kinginsun/mcp-drugsea"],
62
59
  "env": {
63
- "YAOHAI_MCP_API_KEY": "your_api_key_here"
60
+ "YAOHAI_MCP_TOKEN": "ysk_your_token_here"
64
61
  }
65
62
  }
66
63
  }
@@ -76,7 +73,7 @@ export YAOHAI_MCP_API_KEY=your_api_key_here
76
73
  "command": "npx",
77
74
  "args": ["-y", "@kinginsun/mcp-drugsea"],
78
75
  "env": {
79
- "YAOHAI_MCP_API_KEY": "your_api_key_here"
76
+ "YAOHAI_MCP_TOKEN": "ysk_your_token_here"
80
77
  }
81
78
  }
82
79
  }
@@ -99,7 +96,7 @@ If `total > 20`, summarize in chat (about 5–10 sample rows) instead of pasting
99
96
 
100
97
  xlsx export is not implemented in this MCP (v1 returns JSON samples only).
101
98
 
102
- `product-cn-*` and `reg-cn-*` list/facet/detail calls use the same GET routes as the website. Some API2 deployments IP-allowlist those paths and respond with `非法IP地址`. The `yaohai-*` tools use `POST /g/mcp/yaohai/*`, which is the MCP-keyed surface and is not subject to that list GET allowlist.
99
+ `product-cn-*` and `reg-cn-*` list/facet/detail calls use the same routes as the website where applicable. Some deployments IP-allowlist direct GET paths. The `yaohai-*` tools use `POST /g/mcp/yaohai/*` with Bearer token auth.
103
100
 
104
101
  ## Tools
105
102
 
@@ -143,17 +140,17 @@ xlsx export is not implemented in this MCP (v1 returns JSON samples only).
143
140
 
144
141
  ```bash
145
142
  echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
146
- | YAOHAI_MCP_API_KEY=your_key node dist/index.js
143
+ | YAOHAI_MCP_TOKEN=ysk_your_token_here node dist/index.js
147
144
  ```
148
145
 
149
146
  ```bash
150
147
  echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"yaohai-catalog","arguments":{"q":"医保"}}}' \
151
- | YAOHAI_MCP_API_KEY=your_key node dist/index.js
148
+ | YAOHAI_MCP_TOKEN=ysk_your_token_here node dist/index.js
152
149
  ```
153
150
 
154
151
  ```bash
155
152
  echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"product-cn-search","arguments":{"query":{"drug_name":"阿司匹林"},"limit":3}}}' \
156
- | YAOHAI_MCP_API_KEY=your_key node dist/index.js
153
+ | YAOHAI_MCP_TOKEN=ysk_your_token_here node dist/index.js
157
154
  ```
158
155
 
159
156
  ## Requirements
package/dist/api.js CHANGED
@@ -2,12 +2,35 @@ import http from "node:http";
2
2
  import https from "node:https";
3
3
  import { URL } from "node:url";
4
4
  import { normalizeRecord, parseFacetList } from "./normalize.js";
5
- export class MissingApiKeyError extends Error {
6
- constructor() {
7
- super("Set YAOHAI_MCP_API_KEY (shared key) or YAOHAI_MCP_TOKEN (ysk_… user token)");
8
- this.name = "MissingApiKeyError";
5
+ export class MissingTokenError extends Error {
6
+ constructor(message) {
7
+ super(message ??
8
+ "Set YAOHAI_MCP_TOKEN to your personal DrugSea token (ysk_ + 32 hex chars)");
9
+ this.name = "MissingTokenError";
9
10
  }
10
11
  }
12
+ /** @deprecated Use MissingTokenError */
13
+ export const MissingApiKeyError = MissingTokenError;
14
+ const USER_TOKEN_RE = /^ysk_[0-9a-f]{32}$/i;
15
+ export function getUserToken() {
16
+ const token = process.env.YAOHAI_MCP_TOKEN?.trim() || "";
17
+ if (!token) {
18
+ throw new MissingTokenError();
19
+ }
20
+ if (!USER_TOKEN_RE.test(token)) {
21
+ throw new MissingTokenError("YAOHAI_MCP_TOKEN must be a personal user token: ysk_ + 32 hex chars");
22
+ }
23
+ return token;
24
+ }
25
+ /** @deprecated Use getUserToken */
26
+ export const getApiKey = getUserToken;
27
+ export function getAuthHeaders(extra = {}) {
28
+ const token = getUserToken();
29
+ return {
30
+ ...extra,
31
+ Authorization: `Bearer ${token}`,
32
+ };
33
+ }
11
34
  export class ApiError extends Error {
12
35
  status;
13
36
  raw;
@@ -18,27 +41,6 @@ export class ApiError extends Error {
18
41
  this.raw = raw;
19
42
  }
20
43
  }
21
- export function getApiKey() {
22
- const token = process.env.YAOHAI_MCP_TOKEN?.trim() || "";
23
- const key = process.env.YAOHAI_MCP_API_KEY?.trim() || "";
24
- const value = token || key;
25
- if (!value) {
26
- throw new MissingApiKeyError();
27
- }
28
- return value;
29
- }
30
- /** Shared server key → X-Yaohai-Api-Key; user token ysk_… → Authorization Bearer. */
31
- export function getAuthHeaders(extra = {}) {
32
- const credential = getApiKey();
33
- const headers = { ...extra };
34
- if (credential.startsWith("ysk_")) {
35
- headers.Authorization = `Bearer ${credential}`;
36
- }
37
- else {
38
- headers["X-Yaohai-Api-Key"] = credential;
39
- }
40
- return headers;
41
- }
42
44
  export function getBaseUrl() {
43
45
  return (process.env.YAOHAI_BASE_URL || "https://db3.drugsea.cn/api").replace(/\/$/, "");
44
46
  }
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextpro
5
5
  import { clampLimit, clampOffset, fetchDetail, fetchFacets, listSearch, mcpDbDetail, mcpDbSearch, prefersMcpListApi, yaohaiPost, } from "./api.js";
6
6
  import { ATC_HINT, PRODUCT_CN_COMMON_FIELDS, PRODUCT_CN_DETAIL_PATH, PRODUCT_CN_FACET_FIELDS, PRODUCT_CN_FACET_PREFIX, PRODUCT_CN_VIEW_TYPES, REG_CN_COMMON_FIELDS, REG_CN_DETAIL_PATH, REG_CN_FACET_FIELDS, REG_CN_FACET_PREFIX, REG_CN_VIEW_TYPES, applyProductCnDefaults, applyRegCnDefaults, productCnSearchPath, regCnSearchPath, } from "./fields.js";
7
7
  import { EmptyObjectSchema, ProductCnDetailSchema, ProductCnFacetsSchema, ProductCnSearchSchema, RegCnDetailSchema, RegCnFacetsSchema, RegCnSearchSchema, YaohaiCatalogSchema, YaohaiDetailSchema, YaohaiGlobalSearchSchema, YaohaiSearchSchema, YaohaiSmartSearchSchema, } from "./types.js";
8
- const PACKAGE_VERSION = "0.1.0";
8
+ const PACKAGE_VERSION = "0.2.0";
9
9
  const YAOHAI_LIMIT_MAX = 50;
10
10
  const YAOHAI_LIMIT_DEFAULT = 10;
11
11
  const CN_LIMIT_MAX = 100;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinginsun/mcp-drugsea",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for DrugSea / Yaohai pharmaceutical databases: cross-db search, China marketed products (product_cn), and CDE registration review (reg_cn).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",