@kinginsun/mcp-drugsea 0.7.0 → 0.7.1

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/dist/api.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import http from "node:http";
2
2
  import https from "node:https";
3
3
  import { URL } from "node:url";
4
- import { normalizeRecord, parseFacetList } from "./normalize.js";
4
+ import { normalizeRecord, parseFacetList, stripMcpFields } from "./normalize.js";
5
5
  export class MissingTokenError extends Error {
6
6
  constructor(message) {
7
7
  super(message ??
@@ -239,11 +239,16 @@ export async function mcpDbSearch(opts) {
239
239
  if (item && typeof item === "object" && "fields" in item) {
240
240
  const row = item;
241
241
  const flat = normalizeRecord(row.fields);
242
- if (row.detail_url &&
243
- flat &&
242
+ if (flat &&
244
243
  typeof flat === "object" &&
245
244
  !Array.isArray(flat)) {
246
- return { ...flat, detail_url: row.detail_url };
245
+ const stripped = stripMcpFields(flat, {
246
+ dbname: opts.dbname,
247
+ });
248
+ if (row.detail_url) {
249
+ return { ...stripped, detail_url: row.detail_url };
250
+ }
251
+ return stripped;
247
252
  }
248
253
  return flat;
249
254
  }
@@ -270,7 +275,14 @@ export async function mcpDbDetail(dbname, id) {
270
275
  dbname,
271
276
  id,
272
277
  }));
273
- return { dbname, id, ...content };
278
+ const detail = Array.isArray(content.detail)
279
+ ? content.detail.map((row) => row && typeof row === "object"
280
+ ? stripMcpFields(row, { dbname, isDetail: true })
281
+ : row)
282
+ : content.detail && typeof content.detail === "object"
283
+ ? stripMcpFields(content.detail, { dbname, isDetail: true })
284
+ : content.detail;
285
+ return { dbname, id, ...content, detail };
274
286
  }
275
287
  export async function listSearch(opts) {
276
288
  const params = {
@@ -285,6 +297,13 @@ export async function listSearch(opts) {
285
297
  const raw = result.raw;
286
298
  const content = raw.content ?? result.content;
287
299
  const items = normalizeRecord(content);
300
+ if (Array.isArray(items)) {
301
+ for (const it of items) {
302
+ if (it && typeof it === "object") {
303
+ stripMcpFields(it, { dbname: opts.dbname });
304
+ }
305
+ }
306
+ }
288
307
  const totalRaw = raw.tnum;
289
308
  const total = typeof totalRaw === "number"
290
309
  ? totalRaw
@@ -301,14 +320,25 @@ export async function listSearch(opts) {
301
320
  query_applied: opts.query,
302
321
  };
303
322
  }
304
- export async function fetchDetail(path, id) {
323
+ export async function fetchDetail(path, id, dbname = "") {
305
324
  const result = await yaohaiGet(path, {});
306
325
  if (!result.ok) {
307
326
  throw new ApiError(result.error, result.status, result.raw);
308
327
  }
328
+ const detail = normalizeRecord(result.content);
329
+ if (Array.isArray(detail)) {
330
+ for (const it of detail) {
331
+ if (it && typeof it === "object") {
332
+ stripMcpFields(it, { dbname, isDetail: true });
333
+ }
334
+ }
335
+ }
336
+ else if (detail && typeof detail === "object") {
337
+ stripMcpFields(detail, { dbname, isDetail: true });
338
+ }
309
339
  return {
310
340
  id,
311
- detail: normalizeRecord(result.content),
341
+ detail,
312
342
  };
313
343
  }
314
344
  export async function fetchFacets(opts) {
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { ATC_HINT, PRODUCT_CN_COMMON_FIELDS, PRODUCT_CN_DETAIL_PATH, PRODUCT_CN_
7
7
  import { EmptyObjectSchema, ProductCnDetailSchema, ProductCnFacetsSchema, ProductCnSearchSchema, RegCnDetailSchema, RegCnFacetsSchema, RegCnSearchSchema, YaohaiCatalogSchema, YaohaiDetailSchema, YaohaiFacetsSchema, YaohaiGlobalSearchSchema, YaohaiSearchSchema, } from "./types.js";
8
8
  import { DBS_FACET_CATALOG } from "./dbs-facets.js";
9
9
  import { checkForUpdate, formatUpdateMessage, } from "./update-check.js";
10
- const PACKAGE_VERSION = "0.7.0";
10
+ const PACKAGE_VERSION = "0.7.1";
11
11
  const YAOHAI_LIMIT_MAX = 50;
12
12
  const YAOHAI_LIMIT_DEFAULT = 10;
13
13
  const CN_LIMIT_MAX = 100;
@@ -441,6 +441,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
441
441
  limit,
442
442
  offset,
443
443
  viewType,
444
+ dbname: "product_cn",
444
445
  });
445
446
  return ok(content);
446
447
  }
@@ -459,7 +460,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
459
460
  const validated = ProductCnDetailSchema.parse(args);
460
461
  const content = prefersMcpListApi()
461
462
  ? await mcpDbDetail("product_cn", validated.id)
462
- : await fetchDetail(`${PRODUCT_CN_DETAIL_PATH}/${encodeId(validated.id)}`, validated.id);
463
+ : await fetchDetail(`${PRODUCT_CN_DETAIL_PATH}/${encodeId(validated.id)}`, validated.id, "product_cn");
463
464
  return ok(content);
464
465
  }
465
466
  case "reg-cn-fields": {
@@ -490,6 +491,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
490
491
  limit,
491
492
  offset,
492
493
  viewType,
494
+ dbname: "reg_cn",
493
495
  });
494
496
  return ok(content);
495
497
  }
@@ -508,7 +510,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
508
510
  const validated = RegCnDetailSchema.parse(args);
509
511
  const content = prefersMcpListApi()
510
512
  ? await mcpDbDetail("reg_cn", validated.id)
511
- : await fetchDetail(`${REG_CN_DETAIL_PATH}/${encodeId(validated.id)}`, validated.id);
513
+ : await fetchDetail(`${REG_CN_DETAIL_PATH}/${encodeId(validated.id)}`, validated.id, "reg_cn");
512
514
  return ok(content);
513
515
  }
514
516
  default:
package/dist/normalize.js CHANGED
@@ -1,4 +1,53 @@
1
1
  /** Flatten DrugSea UI cell objects `{ text, title, url }` into plain values. */
2
+ /**
3
+ * Strip MCP-irrelevant fields from result rows (lists and details alike).
4
+ * These are internal join keys, ETL timestamps, request-echo flags, and the
5
+ * `related_drug_names` synonym dump (100+ pipe-separated aliases) — they cost
6
+ * tokens but carry no signal for an agent. Mirrors `yaohai_mcp_strip_fields`
7
+ * in the drugsea_api backend (`src/routes/ai_mcp/mcp.php`); the two layers are
8
+ * idempotent with each other.
9
+ */
10
+ const STRIP_ALWAYS = [
11
+ "related_drug_names",
12
+ // internal ids / join keys
13
+ "dp2_id", "gcid", "ProductID", "XUI", "DrugUID", "UniqueID", "es_index_key", "company_for_count",
14
+ // maintenance timestamps
15
+ "created_at", "updated_at", "in_sfda_updated_at",
16
+ // request-echo / internal flags
17
+ "rows_excluded", "has_new_data", "has_sms", "is_47", "linked_to_xui", "is_filing_ref_drug", "2018yizhi", "has_detail",
18
+ // raw change-log dump in product detail (semicolon-delimited ETL diffs)
19
+ "timeline",
20
+ ];
21
+ /** Stale index column that contradicts is_guojia_jicai (skill docs: ignore it). */
22
+ const STRIP_PRODUCT_CN = ["is_jicai"];
23
+ /** Backup / duplicate copies of conclusion / transact_status / slh. */
24
+ const STRIP_REG_CN = ["conclusion_bak", "orig_transact_status", "slh2"];
25
+ /** Labelled insert text: useless HTML blobs in list rows, informative in detail. */
26
+ const STRIP_PRODUCT_CN_LIST_ONLY = [
27
+ "indications",
28
+ "dosage_and_administration",
29
+ "pharmacological_and_toxicological",
30
+ ];
31
+ export function stripMcpFields(row, opts = {}) {
32
+ const { dbname = "", isDetail = false } = opts;
33
+ const strip = new Set(STRIP_ALWAYS);
34
+ if (dbname === "product_cn") {
35
+ for (const f of STRIP_PRODUCT_CN)
36
+ strip.add(f);
37
+ if (!isDetail) {
38
+ for (const f of STRIP_PRODUCT_CN_LIST_ONLY)
39
+ strip.add(f);
40
+ }
41
+ }
42
+ else if (dbname === "reg_cn") {
43
+ for (const f of STRIP_REG_CN)
44
+ strip.add(f);
45
+ }
46
+ for (const f of strip) {
47
+ delete row[f];
48
+ }
49
+ return row;
50
+ }
2
51
  function isPlainObject(v) {
3
52
  return v !== null && typeof v === "object" && !Array.isArray(v);
4
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinginsun/mcp-drugsea",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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",