@cyanheads/pubchem-mcp-server 0.4.3 → 0.5.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/README.md +5 -4
- package/dist/mcp-server/resources/definitions/compound-bioactivity.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/compound-bioactivity.resource.js.map +1 -1
- package/dist/mcp-server/resources/definitions/compound-xrefs.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/compound-xrefs.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-bioactivity.tool.d.ts +3 -0
- package/dist/mcp-server/tools/definitions/get-bioactivity.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-bioactivity.tool.js +41 -13
- package/dist/mcp-server/tools/definitions/get-bioactivity.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-compound-details.tool.d.ts +11 -1
- package/dist/mcp-server/tools/definitions/get-compound-details.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-compound-details.tool.js +147 -21
- package/dist/mcp-server/tools/definitions/get-compound-details.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.d.ts +3 -0
- package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.js +60 -16
- package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +22 -2
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-assays.tool.d.ts +3 -0
- package/dist/mcp-server/tools/definitions/search-assays.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-assays.tool.js +41 -16
- package/dist/mcp-server/tools/definitions/search-assays.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-compounds.tool.d.ts +2 -1
- package/dist/mcp-server/tools/definitions/search-compounds.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-compounds.tool.js +46 -18
- package/dist/mcp-server/tools/definitions/search-compounds.tool.js.map +1 -1
- package/dist/services/pubchem/pubchem-client.d.ts +26 -4
- package/dist/services/pubchem/pubchem-client.d.ts.map +1 -1
- package/dist/services/pubchem/pubchem-client.js +43 -15
- package/dist/services/pubchem/pubchem-client.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/pubchem-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/pubchem-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -62,8 +62,9 @@ Get detailed compound information by CID.
|
|
|
62
62
|
|
|
63
63
|
- Batches up to 100 CIDs in a single request
|
|
64
64
|
- 27 available properties: molecular weight, SMILES, InChIKey, XLogP, TPSA, complexity, stereo counts, and more
|
|
65
|
-
- Optionally includes textual descriptions (pharmacology, mechanism, therapeutic use) from PUG View
|
|
66
|
-
- Optionally includes
|
|
65
|
+
- Optionally includes textual descriptions (pharmacology, mechanism, therapeutic use) from PUG View — fetched for the first 10 CIDs of a batch, with the skipped CIDs named in the response
|
|
66
|
+
- Optionally includes known synonyms (trade names, systematic names, registry numbers)
|
|
67
|
+
- Synonyms and descriptions are paged: `synonymOffset` and `descriptionOffset` window every compound in the batch at the same position, reaching the entries past a page
|
|
67
68
|
- Optionally computes drug-likeness assessment (Lipinski Rule of Five + Veber rules) from fetched properties
|
|
68
69
|
- Optionally fetches pharmacological classification (FDA classes, mechanisms of action, MeSH classes, ATC codes)
|
|
69
70
|
|
|
@@ -75,7 +76,7 @@ Get a compound's bioactivity profile from PubChem BioAssay.
|
|
|
75
76
|
|
|
76
77
|
- Returns assay outcomes (Active/Inactive/Inconclusive), target info (protein accessions, NCBI Gene IDs), and quantitative values (IC50, EC50, Ki)
|
|
77
78
|
- Filter by outcome and/or a specific molecular target (NCBI Gene ID or protein accession)
|
|
78
|
-
- Caps at 100 results per
|
|
79
|
+
- Caps at 100 results per page; `offset` reaches the rest (well-studied compounds may have thousands)
|
|
79
80
|
|
|
80
81
|
---
|
|
81
82
|
|
|
@@ -8,7 +8,7 @@ import { getPubChemClient } from '../../../services/pubchem/pubchem-client.js';
|
|
|
8
8
|
const MAX_RESULTS = 25;
|
|
9
9
|
export const compoundBioactivityResource = resource('pubchem://compound/{cid}/bioactivity', {
|
|
10
10
|
name: 'pubchem-compound-bioactivity',
|
|
11
|
-
description: 'Bioassay activity profile for a PubChem compound by CID. Returns up to 25 assays; use pubchem_get_bioactivity to filter by outcome or molecular target and
|
|
11
|
+
description: 'Bioassay activity profile for a PubChem compound by CID. Returns up to 25 assays; use pubchem_get_bioactivity to filter by outcome or molecular target, raise the cap, and page through the rest with offset.',
|
|
12
12
|
mimeType: 'application/json',
|
|
13
13
|
params: z.object({
|
|
14
14
|
cid: z.coerce.number().int().positive().describe('PubChem Compound ID.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compound-bioactivity.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/compound-bioactivity.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,gGAAgG;AAChG,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,CAAC,MAAM,2BAA2B,GAAG,QAAQ,CAAC,sCAAsC,EAAE;IAC1F,IAAI,EAAE,8BAA8B;IACpC,WAAW,EACT
|
|
1
|
+
{"version":3,"file":"compound-bioactivity.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/compound-bioactivity.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,gGAAgG;AAChG,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,CAAC,MAAM,2BAA2B,GAAG,QAAQ,CAAC,sCAAsC,EAAE;IAC1F,IAAI,EAAE,8BAA8B;IACpC,WAAW,EACT,+MAA+M;IACjN,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACzE,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,MAAM;QAClB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;QACtE,OAAO;YACL,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,WAAW,EAAE,IAAI,CAAC,MAAM;YACxB,WAAW;YACX,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC;SACpC,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -9,7 +9,7 @@ const RESOURCE_XREF_TYPES = ['RN', 'RegistryID', 'PubMedID'];
|
|
|
9
9
|
const MAX_PER_TYPE = 25;
|
|
10
10
|
export const compoundXrefsResource = resource('pubchem://compound/{cid}/xrefs', {
|
|
11
11
|
name: 'pubchem-compound-xrefs',
|
|
12
|
-
description: 'External cross-references (CAS RN, registry IDs, PubMed) for a PubChem compound by CID, up to 25 per type. Use pubchem_get_compound_xrefs for the full set of xref types
|
|
12
|
+
description: 'External cross-references (CAS RN, registry IDs, PubMed) for a PubChem compound by CID, up to 25 per type. Use pubchem_get_compound_xrefs for the full set of xref types, a higher per-type cap, and to page through the rest with offset.',
|
|
13
13
|
mimeType: 'application/json',
|
|
14
14
|
params: z.object({
|
|
15
15
|
cid: z.coerce.number().int().positive().describe('PubChem Compound ID.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compound-xrefs.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/compound-xrefs.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,0FAA0F;AAC1F,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,CAAU,CAAC;AACtE,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC,gCAAgC,EAAE;IAC9E,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"compound-xrefs.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/compound-xrefs.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,0FAA0F;AAC1F,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,CAAU,CAAC;AACtE,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC,gCAAgC,EAAE;IAC9E,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EACT,4OAA4O;IAC9O,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACzE,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,MAAM;QAClB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,KAAK,GAA8E,EAAE,CAAC;QAC5F,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -13,6 +13,7 @@ export declare const getBioactivity: import("@cyanheads/mcp-ts-core").ToolDefini
|
|
|
13
13
|
}>>;
|
|
14
14
|
targetGeneId: z.ZodOptional<z.ZodNumber>;
|
|
15
15
|
targetAccession: z.ZodOptional<z.ZodString>;
|
|
16
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
16
17
|
maxResults: z.ZodDefault<z.ZodNumber>;
|
|
17
18
|
}, z.core.$strip>, z.ZodObject<{
|
|
18
19
|
cid: z.ZodNumber;
|
|
@@ -36,6 +37,8 @@ export declare const getBioactivity: import("@cyanheads/mcp-ts-core").ToolDefini
|
|
|
36
37
|
readonly targetFilter: z.ZodOptional<z.ZodString>;
|
|
37
38
|
readonly filteredCount: z.ZodNumber;
|
|
38
39
|
readonly returnedCount: z.ZodNumber;
|
|
40
|
+
readonly offset: z.ZodNumber;
|
|
41
|
+
readonly nextOffset: z.ZodOptional<z.ZodNumber>;
|
|
39
42
|
readonly truncated: z.ZodOptional<z.ZodBoolean>;
|
|
40
43
|
readonly shown: z.ZodOptional<z.ZodNumber>;
|
|
41
44
|
readonly cap: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-bioactivity.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-bioactivity.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAIjD,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"get-bioactivity.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-bioactivity.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAIjD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoPzB,CAAC"}
|
|
@@ -34,12 +34,18 @@ export const getBioactivity = tool('pubchem_get_bioactivity', {
|
|
|
34
34
|
.string()
|
|
35
35
|
.optional()
|
|
36
36
|
.describe('Filter to assays against this target protein accession (UniProt/GenBank), e.g. "P35354". Obtain accessions from pubchem_search_assays or the targetAccession field of an unfiltered result here.'),
|
|
37
|
+
offset: z
|
|
38
|
+
.number()
|
|
39
|
+
.int()
|
|
40
|
+
.min(0)
|
|
41
|
+
.default(0)
|
|
42
|
+
.describe('Zero-based index of the first assay to return, applied after the outcome and target filters. Pass the nextOffset from a previous call to read the following page. Default: 0.'),
|
|
37
43
|
maxResults: z
|
|
38
44
|
.number()
|
|
39
45
|
.min(1)
|
|
40
46
|
.max(100)
|
|
41
47
|
.default(20)
|
|
42
|
-
.describe('Max assay results to return (1-100). Well-studied compounds have thousands of records. Default: 20.'),
|
|
48
|
+
.describe('Max assay results to return per page (1-100). Well-studied compounds have thousands of records; use offset to reach the ones past this page. Default: 20.'),
|
|
43
49
|
}),
|
|
44
50
|
output: z.object({
|
|
45
51
|
cid: z.number().describe('PubChem Compound ID.'),
|
|
@@ -78,9 +84,14 @@ export const getBioactivity = tool('pubchem_get_bioactivity', {
|
|
|
78
84
|
.describe('Assay result entry.'))
|
|
79
85
|
.describe('Assay results matching the filter.'),
|
|
80
86
|
}),
|
|
81
|
-
// Agent-facing context — filter echo, the
|
|
82
|
-
//
|
|
83
|
-
//
|
|
87
|
+
// Agent-facing context — filter echo, the page boundary, and a notice distinguishing
|
|
88
|
+
// "no data" from "filter excluded everything". Reaches structuredContent and content[];
|
|
89
|
+
// keys disjoint from output (cid/totalAssays live there).
|
|
90
|
+
//
|
|
91
|
+
// Bounded-total convention: a reported total states only what the server actually
|
|
92
|
+
// observed, and pairs with an `…AtLeast` floor when the exact figure is unknowable.
|
|
93
|
+
// Every count here is exact and needs no such twin — PubChem's assay summary has no
|
|
94
|
+
// pagination of its own, so the full table is in hand before any filter runs.
|
|
84
95
|
enrichment: {
|
|
85
96
|
outcomeFilter: z.string().describe('Outcome filter applied: active, inactive, or all.'),
|
|
86
97
|
targetFilter: z
|
|
@@ -89,13 +100,15 @@ export const getBioactivity = tool('pubchem_get_bioactivity', {
|
|
|
89
100
|
.describe('Target filter applied (gene ID and/or protein accession), when set.'),
|
|
90
101
|
filteredCount: z
|
|
91
102
|
.number()
|
|
92
|
-
.describe('
|
|
93
|
-
returnedCount: z.number().describe('Assays returned
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
.describe('Exact number of assays matching the outcome and target filters, across all pages.'),
|
|
104
|
+
returnedCount: z.number().describe('Assays returned on this page.'),
|
|
105
|
+
offset: z.number().describe('Zero-based index of the first assay returned.'),
|
|
106
|
+
nextOffset: z
|
|
107
|
+
.number()
|
|
96
108
|
.optional()
|
|
97
|
-
.describe('
|
|
98
|
-
|
|
109
|
+
.describe('Offset to pass on the next call to continue past this page. Omitted when no further assays match.'),
|
|
110
|
+
truncated: z.boolean().optional().describe('True when matching assays remain past this page.'),
|
|
111
|
+
shown: z.number().optional().describe('Assays returned on this page.'),
|
|
99
112
|
cap: z.number().optional().describe('The maxResults cap that was applied.'),
|
|
100
113
|
notice: z
|
|
101
114
|
.string()
|
|
@@ -128,21 +141,29 @@ export const getBioactivity = tool('pubchem_get_bioactivity', {
|
|
|
128
141
|
if (input.targetAccession) {
|
|
129
142
|
filtered = filtered.filter((r) => r.targetAccession === input.targetAccession);
|
|
130
143
|
}
|
|
131
|
-
|
|
144
|
+
// Offset is applied client-side: PubChem's assay summary endpoint accepts no
|
|
145
|
+
// offset/start/limit/page parameter, so getAssaySummary already holds every row.
|
|
146
|
+
const results = filtered.slice(input.offset, input.offset + input.maxResults);
|
|
147
|
+
const nextOffset = input.offset + results.length;
|
|
148
|
+
const hasMore = nextOffset < filtered.length;
|
|
132
149
|
ctx.log.info('Bioactivity fetched', {
|
|
133
150
|
cid: input.cid,
|
|
134
151
|
total: allRows.length,
|
|
135
152
|
active: activeCount,
|
|
136
153
|
filtered: filtered.length,
|
|
154
|
+
offset: input.offset,
|
|
137
155
|
returned: results.length,
|
|
138
156
|
});
|
|
139
157
|
ctx.enrich({
|
|
140
158
|
outcomeFilter: input.outcomeFilter,
|
|
141
159
|
filteredCount: filtered.length,
|
|
142
160
|
returnedCount: results.length,
|
|
161
|
+
offset: input.offset,
|
|
143
162
|
});
|
|
144
163
|
if (targetLabel)
|
|
145
164
|
ctx.enrich({ targetFilter: targetLabel });
|
|
165
|
+
if (hasMore)
|
|
166
|
+
ctx.enrich({ nextOffset });
|
|
146
167
|
if (allRows.length === 0) {
|
|
147
168
|
ctx.enrich.notice(`No bioactivity data found for CID ${input.cid}. The compound may be uncharacterized, or verify the CID with pubchem_search_compounds.`);
|
|
148
169
|
}
|
|
@@ -151,8 +172,15 @@ export const getBioactivity = tool('pubchem_get_bioactivity', {
|
|
|
151
172
|
? `CID ${input.cid} has ${allRows.length} assay(s) but none match the target filter (${targetLabel})${input.outcomeFilter !== 'all' ? ` with outcomeFilter="${input.outcomeFilter}"` : ''}. Verify the target identifier appears in this compound's assays, or widen the filter.`
|
|
152
173
|
: `CID ${input.cid} has ${allRows.length} assay(s) but none match outcomeFilter="${input.outcomeFilter}". Use outcomeFilter="all" to see them.`);
|
|
153
174
|
}
|
|
154
|
-
else if (
|
|
155
|
-
ctx.enrich.
|
|
175
|
+
else if (results.length === 0) {
|
|
176
|
+
ctx.enrich.notice(`offset ${input.offset} is past the ${filtered.length} assay(s) matching the filter. Pass an offset below ${filtered.length}.`);
|
|
177
|
+
}
|
|
178
|
+
else if (hasMore) {
|
|
179
|
+
ctx.enrich.truncated({
|
|
180
|
+
shown: results.length,
|
|
181
|
+
cap: input.maxResults,
|
|
182
|
+
guidance: `Showing assays ${input.offset + 1}-${nextOffset} of ${filtered.length}. Pass offset=${nextOffset} for the next page.`,
|
|
183
|
+
});
|
|
156
184
|
}
|
|
157
185
|
return {
|
|
158
186
|
cid: input.cid,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-bioactivity.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-bioactivity.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,yBAAyB,EAAE;IAC5D,KAAK,EAAE,iBAAiB;IACxB,WAAW,EACT,kYAAkY;IACpY,WAAW,EAAE;QACX,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACpB;IACD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,GAAG,EAAE,CAAC;aACH,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,CAAC,8EAA8E,CAAC;QAC3F,aAAa,EAAE,CAAC;aACb,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;aACnC,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CACP,+JAA+J,CAChK;QACH,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CACP,2OAA2O,CAC5O;QACH,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,kMAAkM,CACnM;QACH,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CACP,
|
|
1
|
+
{"version":3,"file":"get-bioactivity.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-bioactivity.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,8 +10,10 @@ export declare const getCompoundDetails: import("@cyanheads/mcp-ts-core").ToolDe
|
|
|
10
10
|
[x: string]: string;
|
|
11
11
|
}>>>;
|
|
12
12
|
includeDescription: z.ZodDefault<z.ZodBoolean>;
|
|
13
|
+
descriptionOffset: z.ZodDefault<z.ZodNumber>;
|
|
13
14
|
maxDescriptions: z.ZodDefault<z.ZodNumber>;
|
|
14
15
|
includeSynonyms: z.ZodDefault<z.ZodBoolean>;
|
|
16
|
+
synonymOffset: z.ZodDefault<z.ZodNumber>;
|
|
15
17
|
maxSynonyms: z.ZodDefault<z.ZodNumber>;
|
|
16
18
|
includeDrugLikeness: z.ZodDefault<z.ZodBoolean>;
|
|
17
19
|
includeClassification: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -76,5 +78,13 @@ export declare const getCompoundDetails: import("@cyanheads/mcp-ts-core").ToolDe
|
|
|
76
78
|
meshClasses: z.ZodArray<z.ZodString>;
|
|
77
79
|
}, z.core.$strip>>;
|
|
78
80
|
}, z.core.$strip>>;
|
|
79
|
-
}, z.core.$strip>, undefined,
|
|
81
|
+
}, z.core.$strip>, undefined, {
|
|
82
|
+
readonly enrichedCids: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
83
|
+
readonly skippedCids: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
84
|
+
readonly synonymOffset: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
readonly nextSynonymOffset: z.ZodOptional<z.ZodNumber>;
|
|
86
|
+
readonly descriptionOffset: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
readonly nextDescriptionOffset: z.ZodOptional<z.ZodNumber>;
|
|
88
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
89
|
+
}>;
|
|
80
90
|
//# sourceMappingURL=get-compound-details.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-compound-details.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-compound-details.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"get-compound-details.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-compound-details.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAmHjD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAijB7B,CAAC"}
|
|
@@ -93,10 +93,16 @@ function computeDrugLikeness(properties) {
|
|
|
93
93
|
veber: { rotatableBonds, tpsa, violations: veberViolations },
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* PUG View is a per-CID endpoint, so descriptions and classification fan out one request per
|
|
98
|
+
* compound. The batch accepts up to 100 CIDs; this bounds that fan-out. CIDs past it come back
|
|
99
|
+
* without descriptions or classification — disclosed via enrichment (#40).
|
|
100
|
+
*/
|
|
101
|
+
const PUG_VIEW_CID_CAP = 10;
|
|
96
102
|
// ── Tool definition ────────────────────────────────────────────────────
|
|
97
103
|
export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
98
104
|
title: 'Get Compound Details',
|
|
99
|
-
description: 'Get detailed compound information by CID. Returns physicochemical properties (molecular weight, SMILES, InChIKey, XLogP, TPSA, etc.), optionally with a textual description (pharmacology, mechanism, therapeutic use),
|
|
105
|
+
description: 'Get detailed compound information by CID. Returns physicochemical properties (molecular weight, SMILES, InChIKey, XLogP, TPSA, etc.), optionally with a textual description (pharmacology, mechanism, therapeutic use), known synonyms, drug-likeness assessment (Lipinski/Veber rules), and/or pharmacological classification (FDA classes, MeSH classes, ATC codes). Accepts up to 100 CIDs per call.',
|
|
100
106
|
annotations: {
|
|
101
107
|
readOnlyHint: true,
|
|
102
108
|
idempotentHint: true,
|
|
@@ -115,25 +121,37 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
115
121
|
includeDescription: z
|
|
116
122
|
.boolean()
|
|
117
123
|
.default(false)
|
|
118
|
-
.describe(
|
|
124
|
+
.describe(`Include textual descriptions (pharmacology, mechanism, therapeutic use) attributed by source. Well-studied compounds have many overlapping summaries — paged via descriptionOffset/maxDescriptions. Fetched only for the first ${PUG_VIEW_CID_CAP} CIDs in the batch; remaining CIDs return without descriptions and are listed in the response's skippedCids.`),
|
|
125
|
+
descriptionOffset: z
|
|
126
|
+
.number()
|
|
127
|
+
.int()
|
|
128
|
+
.min(0)
|
|
129
|
+
.default(0)
|
|
130
|
+
.describe("Zero-based index of the first description to return within each compound's description list. The same offset is applied to every compound in the batch. Pass the nextDescriptionOffset from a previous call to read the following page. Default: 0."),
|
|
119
131
|
maxDescriptions: z
|
|
120
132
|
.number()
|
|
121
133
|
.int()
|
|
122
134
|
.min(1)
|
|
123
135
|
.max(20)
|
|
124
136
|
.default(3)
|
|
125
|
-
.describe('Max number of distinct description entries per compound (1-20). PubChem returns near-duplicate summaries from many depositors; duplicates are collapsed before this cap applies. Default: 3.'),
|
|
137
|
+
.describe('Max number of distinct description entries per compound per page (1-20). PubChem returns near-duplicate summaries from many depositors; duplicates are collapsed before this cap applies. Default: 3.'),
|
|
126
138
|
includeSynonyms: z
|
|
127
139
|
.boolean()
|
|
128
140
|
.default(false)
|
|
129
|
-
.describe('Fetch
|
|
141
|
+
.describe('Fetch known names and synonyms (trade names, systematic names, registry numbers), paged via synonymOffset/maxSynonyms. Fetched for every found CID in the batch. Slower for large CID lists.'),
|
|
142
|
+
synonymOffset: z
|
|
143
|
+
.number()
|
|
144
|
+
.int()
|
|
145
|
+
.min(0)
|
|
146
|
+
.default(0)
|
|
147
|
+
.describe("Zero-based index of the first synonym to return within each compound's synonym list. The same offset is applied to every compound in the batch. Pass the nextSynonymOffset from a previous call to read the following page. Default: 0."),
|
|
130
148
|
maxSynonyms: z
|
|
131
149
|
.number()
|
|
132
150
|
.int()
|
|
133
151
|
.min(1)
|
|
134
152
|
.max(100)
|
|
135
153
|
.default(20)
|
|
136
|
-
.describe('Max synonyms returned per compound (1-100). PubChem lists hundreds for common drugs;
|
|
154
|
+
.describe('Max synonyms returned per compound per page (1-100). PubChem lists hundreds for common drugs; use synonymOffset to reach the ones past this page. Default: 20.'),
|
|
137
155
|
includeDrugLikeness: z
|
|
138
156
|
.boolean()
|
|
139
157
|
.default(false)
|
|
@@ -141,7 +159,7 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
141
159
|
includeClassification: z
|
|
142
160
|
.boolean()
|
|
143
161
|
.default(false)
|
|
144
|
-
.describe(
|
|
162
|
+
.describe(`Include pharmacological classification: FDA Established Pharmacologic Classes, mechanisms of action, MeSH classes, and ATC codes. Fetched only for the first ${PUG_VIEW_CID_CAP} CIDs in the batch; remaining CIDs return without classification and are listed in the response's skippedCids.`),
|
|
145
163
|
}),
|
|
146
164
|
output: z.object({
|
|
147
165
|
compounds: z
|
|
@@ -165,16 +183,19 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
165
183
|
})
|
|
166
184
|
.describe('Description entry with optional source attribution.'))
|
|
167
185
|
.optional()
|
|
168
|
-
.describe('Textual descriptions, deduplicated
|
|
186
|
+
.describe('Textual descriptions on this page, deduplicated then windowed by descriptionOffset/maxDescriptions. Each entry carries optional source attribution. Empty when descriptionOffset runs past descriptionsTotal.'),
|
|
169
187
|
descriptionsTotal: z
|
|
170
188
|
.number()
|
|
171
189
|
.optional()
|
|
172
|
-
.describe('Total distinct descriptions available
|
|
173
|
-
synonyms: z
|
|
190
|
+
.describe('Total distinct descriptions available for this compound, across all pages. Larger than descriptions.length when more sources exist — raise maxDescriptions or page with descriptionOffset to see them.'),
|
|
191
|
+
synonyms: z
|
|
192
|
+
.array(z.string())
|
|
193
|
+
.optional()
|
|
194
|
+
.describe('Known names and synonyms on this page, windowed by synonymOffset/maxSynonyms. Empty when synonymOffset runs past synonymsTotal.'),
|
|
174
195
|
synonymsTotal: z
|
|
175
196
|
.number()
|
|
176
197
|
.optional()
|
|
177
|
-
.describe('Total synonyms available
|
|
198
|
+
.describe('Total synonyms available for this compound, across all pages. Larger than synonyms.length when more exist — raise maxSynonyms or page with synonymOffset to see them.'),
|
|
178
199
|
drugLikeness: drugLikenessSchema
|
|
179
200
|
.optional()
|
|
180
201
|
.describe('Drug-likeness assessment. lipinski.violations ≤ 1 and veber.violations = 0 → pass.'),
|
|
@@ -185,6 +206,54 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
185
206
|
.describe('Per-CID compound detail record.'))
|
|
186
207
|
.describe('Compound detail records.'),
|
|
187
208
|
}),
|
|
209
|
+
// Agent-facing context for the two things a per-compound record cannot say on its own:
|
|
210
|
+
// which CIDs the PUG View fan-out reached (#40), and where the synonym/description windows
|
|
211
|
+
// sit within each compound's full list (#38). Both are batch-wide — one offset and one cap
|
|
212
|
+
// apply to every compound — so they belong here rather than repeated per record. Reaches
|
|
213
|
+
// structuredContent and content[]; keys disjoint from output (compounds lives there).
|
|
214
|
+
//
|
|
215
|
+
// A full page is exactly maxSynonyms/maxDescriptions long, so one nextOffset serves every
|
|
216
|
+
// compound that still has entries left, whatever its individual total.
|
|
217
|
+
enrichment: {
|
|
218
|
+
enrichedCids: z
|
|
219
|
+
.array(z.number())
|
|
220
|
+
.optional()
|
|
221
|
+
.describe('CIDs whose descriptions and classification were fetched. Present only when the batch exceeded the per-call fan-out limit and other CIDs were skipped.'),
|
|
222
|
+
skippedCids: z
|
|
223
|
+
.array(z.number())
|
|
224
|
+
.optional()
|
|
225
|
+
.describe('CIDs found in PubChem whose descriptions and classification were NOT fetched because the batch exceeded the per-call fan-out limit. Their absence from a record means "not requested", not "PubChem has none" — re-request these CIDs in a follow-up call. Present only when CIDs were skipped.'),
|
|
226
|
+
synonymOffset: z
|
|
227
|
+
.number()
|
|
228
|
+
.optional()
|
|
229
|
+
.describe("Zero-based index of the first synonym returned within each compound's list. Present when includeSynonyms is true."),
|
|
230
|
+
nextSynonymOffset: z
|
|
231
|
+
.number()
|
|
232
|
+
.optional()
|
|
233
|
+
.describe('synonymOffset to pass on the next call to continue past this page. Omitted when no compound in the batch has further synonyms.'),
|
|
234
|
+
descriptionOffset: z
|
|
235
|
+
.number()
|
|
236
|
+
.optional()
|
|
237
|
+
.describe("Zero-based index of the first description returned within each compound's list. Present when includeDescription is true."),
|
|
238
|
+
nextDescriptionOffset: z
|
|
239
|
+
.number()
|
|
240
|
+
.optional()
|
|
241
|
+
.describe('descriptionOffset to pass on the next call to continue past this page. Omitted when no compound in the batch has further descriptions.'),
|
|
242
|
+
notice: z
|
|
243
|
+
.string()
|
|
244
|
+
.optional()
|
|
245
|
+
.describe('Recovery guidance covering the skipped CIDs, an offset that runs past every compound, and pages that remain. Absent when nothing was skipped or truncated.'),
|
|
246
|
+
},
|
|
247
|
+
// Both fields are optional, so `render` sees `number[] | undefined` at the type level; the
|
|
248
|
+
// framework only calls it for a populated field.
|
|
249
|
+
enrichmentTrailer: {
|
|
250
|
+
enrichedCids: {
|
|
251
|
+
render: (cids) => `**Descriptions/classification fetched for:** CID ${(cids ?? []).join(', ')}`,
|
|
252
|
+
},
|
|
253
|
+
skippedCids: {
|
|
254
|
+
render: (cids) => `**Descriptions/classification skipped for:** CID ${(cids ?? []).join(', ')}`,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
188
257
|
async handler(input, ctx) {
|
|
189
258
|
const client = getPubChemClient();
|
|
190
259
|
const requestedProps = input.properties ?? [...DEFAULT_PROPERTIES];
|
|
@@ -207,12 +276,14 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
207
276
|
return false;
|
|
208
277
|
return Object.keys(row).some((k) => k !== 'CID');
|
|
209
278
|
};
|
|
210
|
-
// PUG View calls (per-CID, capped
|
|
279
|
+
// PUG View calls (per-CID, capped) — skip CIDs that aren't in PubChem
|
|
211
280
|
const foundCids = input.cids.filter(isFound);
|
|
212
|
-
const viewCids = foundCids.slice(0,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
281
|
+
const viewCids = foundCids.slice(0, PUG_VIEW_CID_CAP);
|
|
282
|
+
const skippedViewCids = foundCids.slice(PUG_VIEW_CID_CAP);
|
|
283
|
+
const viewCapEngaged = (input.includeDescription || input.includeClassification) && skippedViewCids.length > 0;
|
|
284
|
+
if (viewCapEngaged) {
|
|
285
|
+
ctx.log.info('PUG View fetch capped', {
|
|
286
|
+
cap: PUG_VIEW_CID_CAP,
|
|
216
287
|
requested: foundCids.length,
|
|
217
288
|
fetching: viewCids.length,
|
|
218
289
|
});
|
|
@@ -251,12 +322,12 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
251
322
|
return compound;
|
|
252
323
|
const allDescs = descMap?.get(cid);
|
|
253
324
|
if (allDescs && allDescs.length > 0) {
|
|
254
|
-
compound.descriptions = allDescs.slice(
|
|
325
|
+
compound.descriptions = allDescs.slice(input.descriptionOffset, input.descriptionOffset + input.maxDescriptions);
|
|
255
326
|
compound.descriptionsTotal = allDescs.length;
|
|
256
327
|
}
|
|
257
328
|
const syns = synMap?.get(cid);
|
|
258
329
|
if (syns) {
|
|
259
|
-
compound.synonyms = syns.slice(
|
|
330
|
+
compound.synonyms = syns.slice(input.synonymOffset, input.synonymOffset + input.maxSynonyms);
|
|
260
331
|
compound.synonymsTotal = syns.length;
|
|
261
332
|
}
|
|
262
333
|
if (input.includeDrugLikeness)
|
|
@@ -266,6 +337,40 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
266
337
|
compound.classification = cls;
|
|
267
338
|
return compound;
|
|
268
339
|
});
|
|
340
|
+
const notices = [];
|
|
341
|
+
// #40 — the PUG View fan-out cap is otherwise invisible: a capped-out CID looks exactly
|
|
342
|
+
// like a compound PubChem has no description for.
|
|
343
|
+
if (viewCapEngaged) {
|
|
344
|
+
ctx.enrich({ enrichedCids: viewCids, skippedCids: skippedViewCids });
|
|
345
|
+
notices.push(`Descriptions and classification were fetched for the first ${viewCids.length} of ${foundCids.length} found CIDs (limit: ${PUG_VIEW_CID_CAP} per call). CID ${skippedViewCids.join(', ')} returned without them — re-request those CIDs in a follow-up call.`);
|
|
346
|
+
}
|
|
347
|
+
if (input.includeSynonyms) {
|
|
348
|
+
const page = listPage([...(synMap?.values() ?? [])].map((s) => s.length), input.synonymOffset, input.maxSynonyms);
|
|
349
|
+
ctx.enrich({ synonymOffset: input.synonymOffset });
|
|
350
|
+
if (page.hasMore)
|
|
351
|
+
ctx.enrich({ nextSynonymOffset: page.nextOffset });
|
|
352
|
+
if (page.allEmpty) {
|
|
353
|
+
notices.push(`synonymOffset ${input.synonymOffset} is past every compound in this batch — the longest synonym list has ${page.largestTotal} entries. Pass a synonymOffset below ${page.largestTotal}.`);
|
|
354
|
+
}
|
|
355
|
+
else if (page.hasMore) {
|
|
356
|
+
notices.push(`More synonyms remain — pass synonymOffset=${page.nextOffset} to continue.`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (input.includeDescription) {
|
|
360
|
+
const page = listPage([...(descMap?.values() ?? [])].map((d) => d.length), input.descriptionOffset, input.maxDescriptions);
|
|
361
|
+
ctx.enrich({ descriptionOffset: input.descriptionOffset });
|
|
362
|
+
if (page.hasMore)
|
|
363
|
+
ctx.enrich({ nextDescriptionOffset: page.nextOffset });
|
|
364
|
+
if (page.allEmpty) {
|
|
365
|
+
notices.push(`descriptionOffset ${input.descriptionOffset} is past every compound in this batch — the longest description list has ${page.largestTotal} entries. Pass a descriptionOffset below ${page.largestTotal}.`);
|
|
366
|
+
}
|
|
367
|
+
else if (page.hasMore) {
|
|
368
|
+
notices.push(`More descriptions remain — pass descriptionOffset=${page.nextOffset} to continue.`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// One notice field, so the sources are composed rather than overwriting one another.
|
|
372
|
+
if (notices.length > 0)
|
|
373
|
+
ctx.enrich.notice(notices.join(' '));
|
|
269
374
|
return { compounds };
|
|
270
375
|
},
|
|
271
376
|
format(result) {
|
|
@@ -391,7 +496,12 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
391
496
|
}
|
|
392
497
|
blocks.push(lines.join('\n'));
|
|
393
498
|
}
|
|
394
|
-
//
|
|
499
|
+
// An empty list with a non-zero total means the offset ran past this compound —
|
|
500
|
+
// distinct from having no descriptions at all, which omits the field entirely.
|
|
501
|
+
if (c.descriptions?.length === 0) {
|
|
502
|
+
blocks.push(`\n**Descriptions** (${c.descriptionsTotal ?? 0} total): none at this descriptionOffset`);
|
|
503
|
+
}
|
|
504
|
+
// Descriptions (with source attribution; windowed by descriptionOffset/maxDescriptions)
|
|
395
505
|
if (c.descriptions && c.descriptions.length > 0) {
|
|
396
506
|
const total = c.descriptionsTotal ?? c.descriptions.length;
|
|
397
507
|
const shown = c.descriptions.length;
|
|
@@ -409,15 +519,18 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
409
519
|
}
|
|
410
520
|
const more = total - shown;
|
|
411
521
|
if (more > 0) {
|
|
412
|
-
descLines.push(`_+${more} more description${more === 1 ? '' : 's'} from other sources —
|
|
522
|
+
descLines.push(`_+${more} more description${more === 1 ? '' : 's'} from other sources — raise maxDescriptions or page with descriptionOffset to see them._`);
|
|
413
523
|
}
|
|
414
524
|
blocks.push(descLines.join('\n\n'));
|
|
415
525
|
}
|
|
416
|
-
|
|
526
|
+
if (c.synonyms?.length === 0) {
|
|
527
|
+
blocks.push(`\n**Synonyms** (${c.synonymsTotal ?? 0} total): none at this synonymOffset`);
|
|
528
|
+
}
|
|
529
|
+
// Synonyms (windowed by synonymOffset/maxSynonyms in the handler; total reported)
|
|
417
530
|
if (c.synonyms && c.synonyms.length > 0) {
|
|
418
531
|
const total = c.synonymsTotal ?? c.synonyms.length;
|
|
419
532
|
const more = total - c.synonyms.length;
|
|
420
|
-
const suffix = more > 0 ? ` (+${more} more)` : '';
|
|
533
|
+
const suffix = more > 0 ? ` (+${more} more not on this page)` : '';
|
|
421
534
|
/**
|
|
422
535
|
* Pipe-separated: CAS-style inverted names ("Benzoic acid, 2-(acetyloxy)-") carry
|
|
423
536
|
* their own ", ", which would split one synonym into two. " | " is this formatter's
|
|
@@ -434,6 +547,19 @@ export const getCompoundDetails = tool('pubchem_get_compound_details', {
|
|
|
434
547
|
return [{ type: 'text', text: blocks.join('\n') }];
|
|
435
548
|
},
|
|
436
549
|
});
|
|
550
|
+
/**
|
|
551
|
+
* Batch-wide page state for one of the per-compound lists. `totals` holds each compound's
|
|
552
|
+
* full list length; a page is windowed at the same offset and cap for every compound.
|
|
553
|
+
*/
|
|
554
|
+
function listPage(totals, offset, cap) {
|
|
555
|
+
const largestTotal = totals.reduce((max, t) => Math.max(max, t), 0);
|
|
556
|
+
return {
|
|
557
|
+
allEmpty: largestTotal > 0 && totals.every((t) => t <= offset),
|
|
558
|
+
hasMore: totals.some((t) => t > offset + cap),
|
|
559
|
+
largestTotal,
|
|
560
|
+
nextOffset: offset + cap,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
437
563
|
function formatRules(rules) {
|
|
438
564
|
return rules
|
|
439
565
|
.map(([label, r]) => {
|