@cyanheads/pubchem-mcp-server 0.6.2 → 0.6.4

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.
Files changed (79) hide show
  1. package/AGENTS.md +371 -0
  2. package/CLAUDE.md +371 -0
  3. package/README.md +217 -87
  4. package/changelog/0.1.x/0.1.21.md +23 -0
  5. package/changelog/0.1.x/0.1.22.md +14 -0
  6. package/changelog/0.1.x/0.1.23.md +18 -0
  7. package/changelog/0.2.x/0.2.0.md +24 -0
  8. package/changelog/0.2.x/0.2.1.md +14 -0
  9. package/changelog/0.2.x/0.2.2.md +17 -0
  10. package/changelog/0.2.x/0.2.3.md +27 -0
  11. package/changelog/0.2.x/0.2.4.md +27 -0
  12. package/changelog/0.3.x/0.3.0.md +31 -0
  13. package/changelog/0.3.x/0.3.1.md +19 -0
  14. package/changelog/0.4.x/0.4.0.md +15 -0
  15. package/changelog/0.4.x/0.4.1.md +12 -0
  16. package/changelog/0.4.x/0.4.2.md +41 -0
  17. package/changelog/0.4.x/0.4.3.md +18 -0
  18. package/changelog/0.5.x/0.5.0.md +24 -0
  19. package/changelog/0.5.x/0.5.1.md +24 -0
  20. package/changelog/0.5.x/0.5.2.md +21 -0
  21. package/changelog/0.6.x/0.6.0.md +15 -0
  22. package/changelog/0.6.x/0.6.1.md +40 -0
  23. package/changelog/0.6.x/0.6.2.md +29 -0
  24. package/changelog/0.6.x/0.6.3.md +40 -0
  25. package/changelog/0.6.x/0.6.4.md +23 -0
  26. package/changelog/template.md +151 -0
  27. package/dist/index.js +4 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp-server/resources/definitions/assay.resource.js +1 -1
  30. package/dist/mcp-server/resources/definitions/assay.resource.js.map +1 -1
  31. package/dist/mcp-server/resources/definitions/compound-bioactivity.resource.js +1 -1
  32. package/dist/mcp-server/resources/definitions/compound-bioactivity.resource.js.map +1 -1
  33. package/dist/mcp-server/resources/definitions/compound-image.resource.js +1 -1
  34. package/dist/mcp-server/resources/definitions/compound-image.resource.js.map +1 -1
  35. package/dist/mcp-server/resources/definitions/compound-safety.resource.js +1 -1
  36. package/dist/mcp-server/resources/definitions/compound-safety.resource.js.map +1 -1
  37. package/dist/mcp-server/resources/definitions/compound-xrefs.resource.js +1 -1
  38. package/dist/mcp-server/resources/definitions/compound-xrefs.resource.js.map +1 -1
  39. package/dist/mcp-server/resources/definitions/compound.resource.js +1 -1
  40. package/dist/mcp-server/resources/definitions/compound.resource.js.map +1 -1
  41. package/dist/mcp-server/tools/definitions/get-bioactivity.tool.d.ts.map +1 -1
  42. package/dist/mcp-server/tools/definitions/get-bioactivity.tool.js +6 -2
  43. package/dist/mcp-server/tools/definitions/get-bioactivity.tool.js.map +1 -1
  44. package/dist/mcp-server/tools/definitions/get-compound-3d-structure.tool.d.ts +1 -0
  45. package/dist/mcp-server/tools/definitions/get-compound-3d-structure.tool.d.ts.map +1 -1
  46. package/dist/mcp-server/tools/definitions/get-compound-3d-structure.tool.js +6 -3
  47. package/dist/mcp-server/tools/definitions/get-compound-3d-structure.tool.js.map +1 -1
  48. package/dist/mcp-server/tools/definitions/get-compound-details.tool.js +1 -1
  49. package/dist/mcp-server/tools/definitions/get-compound-details.tool.js.map +1 -1
  50. package/dist/mcp-server/tools/definitions/get-compound-image.tool.d.ts +1 -0
  51. package/dist/mcp-server/tools/definitions/get-compound-image.tool.d.ts.map +1 -1
  52. package/dist/mcp-server/tools/definitions/get-compound-image.tool.js +4 -1
  53. package/dist/mcp-server/tools/definitions/get-compound-image.tool.js.map +1 -1
  54. package/dist/mcp-server/tools/definitions/get-compound-interactions.tool.d.ts.map +1 -1
  55. package/dist/mcp-server/tools/definitions/get-compound-interactions.tool.js +4 -1
  56. package/dist/mcp-server/tools/definitions/get-compound-interactions.tool.js.map +1 -1
  57. package/dist/mcp-server/tools/definitions/get-compound-safety.tool.js +1 -1
  58. package/dist/mcp-server/tools/definitions/get-compound-safety.tool.js.map +1 -1
  59. package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.d.ts.map +1 -1
  60. package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.js +5 -1
  61. package/dist/mcp-server/tools/definitions/get-compound-xrefs.tool.js.map +1 -1
  62. package/dist/mcp-server/tools/definitions/index.d.ts +4 -2
  63. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  64. package/dist/mcp-server/tools/definitions/search-assays.tool.d.ts.map +1 -1
  65. package/dist/mcp-server/tools/definitions/search-assays.tool.js +3 -0
  66. package/dist/mcp-server/tools/definitions/search-assays.tool.js.map +1 -1
  67. package/dist/mcp-server/tools/definitions/search-compounds.tool.d.ts +2 -2
  68. package/dist/mcp-server/tools/definitions/search-compounds.tool.d.ts.map +1 -1
  69. package/dist/mcp-server/tools/definitions/search-compounds.tool.js +8 -5
  70. package/dist/mcp-server/tools/definitions/search-compounds.tool.js.map +1 -1
  71. package/dist/mcp-server/tools/definitions/untrusted-text.d.ts.map +1 -1
  72. package/dist/mcp-server/tools/definitions/untrusted-text.js +8 -1
  73. package/dist/mcp-server/tools/definitions/untrusted-text.js.map +1 -1
  74. package/dist/services/pubchem/pubchem-client.d.ts.map +1 -1
  75. package/dist/services/pubchem/pubchem-client.js +51 -11
  76. package/dist/services/pubchem/pubchem-client.js.map +1 -1
  77. package/manifest.json +1 -1
  78. package/package.json +19 -9
  79. package/server.json +3 -3
package/README.md CHANGED
@@ -7,13 +7,13 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-0.6.2-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/pubchem-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/pubchem-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/pubchem-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-^1.4.0-f472b6.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.6.4-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/pubchem-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/pubchem-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/pubchem-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-^1.4.0-f472b6.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
14
14
  <div align="center">
15
15
 
16
- [![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/pubchem-mcp-server/releases/latest/download/pubchem-mcp-server.mcpb) [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=pubchem-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjeWFuaGVhZHMvcHViY2hlbS1tY3Atc2VydmVyIl19) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22pubchem-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40cyanheads/pubchem-mcp-server%22%5D%7D)
16
+ [![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/pubchem-mcp-server/releases/latest/download/pubchem-mcp-server.mcpb) [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=pubchem-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjeWFuaGVhZHMvcHViY2hlbS1tY3Atc2VydmVyIl19) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22pubchem-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40cyanheads%2Fpubchem-mcp-server%22%5D%7D)
17
17
 
18
18
  [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-67E8F9?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
19
19
 
@@ -27,12 +27,14 @@
27
27
 
28
28
  ---
29
29
 
30
- ## Tools
30
+ ## Overview
31
31
 
32
- Ten tools for querying PubChem's chemical information database:
32
+ Chemical compound and bioassay data from PubChem's PUG REST and PUG View APIs. Search compounds by identifier, formula, or structure; fetch physicochemical properties, safety data, bioactivity, interactions, cross-references, and 3D structures; find bioassays by biological target. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
33
33
 
34
- | Tool Name | Description |
35
- |:----------|:------------|
34
+ ### Tools
35
+
36
+ | Tool | Description |
37
+ |:---|:---|
36
38
  | `pubchem_search_compounds` | Search for compounds by name, SMILES, InChIKey, formula, substructure, superstructure, or 2D similarity. |
37
39
  | `pubchem_get_compound_details` | Get physicochemical properties, descriptions, synonyms, drug-likeness, and classification for compounds by CID. |
38
40
  | `pubchem_get_compound_image` | Fetch a 2D structure diagram (PNG) for a compound by CID. |
@@ -44,104 +46,174 @@ Ten tools for querying PubChem's chemical information database:
44
46
  | `pubchem_search_assays` | Find bioassays by biological target (gene symbol, protein, Gene ID, UniProt accession). |
45
47
  | `pubchem_get_summary` | Get summaries for PubChem entities: assays, genes, proteins, taxonomy. |
46
48
 
47
- ### `pubchem_search_compounds`
49
+ ### Resources
50
+
51
+ Compound and assay records are also exposed as URI-templated resources, backed by the same client methods as the tools; many MCP clients are tool-only and never surface resources.
52
+
53
+ | Resource | Description |
54
+ |:---|:---|
55
+ | `pubchem://compound/{cid}` | Core physicochemical properties (JSON). |
56
+ | `pubchem://compound/{cid}/safety` | GHS hazard classification (JSON). |
57
+ | `pubchem://compound/{cid}/image` | 2D structure diagram (PNG). |
58
+ | `pubchem://compound/{cid}/xrefs` | External cross-references (JSON). |
59
+ | `pubchem://compound/{cid}/bioactivity` | Bioassay activity profile (JSON). |
60
+ | `pubchem://assay/{aid}` | BioAssay summary (JSON). |
61
+
62
+ ## Capability reference
63
+
64
+ ### `pubchem_search_compounds` <sub>tool</sub>
65
+
66
+ - Five search strategies: identifier (name/SMILES/InChIKey, batched 1-25), formula (Hill notation, optional `allowOtherElements`), substructure/superstructure containment, or 2D Tanimoto similarity (threshold 70-100, default 90)
67
+ - Each strategy needs its own fields — identifier: `identifierType` + `identifiers`; formula: `formula`; substructure/superstructure/similarity: `query` + `queryType` — and a missing or blank one is rejected before the upstream call
68
+ - Caps at 200 CIDs per page (default 20); `offset` pages to a ceiling of 10,000 — identifier lookups resolve every match up front so paging is free, while formula/structure/similarity searches cost more upstream per deep page
69
+ - Optional `properties` hydration avoids a follow-up `pubchem_get_compound_details` call
70
+ - Identifier mode reports `unresolvedIdentifiers` for inputs that resolved to no CID, plus notices when multiple inputs collide on one CID
71
+ - Reports an exact `totalFound` when the full match set was observed, or a `totalFoundAtLeast` floor when a bounded upstream search saturated
72
+
73
+ ---
74
+
75
+ ### `pubchem_get_compound_details` <sub>tool</sub>
76
+
77
+ - Up to 100 CIDs per call; 27 available properties, defaulting to a core set of 14 (formula, weight, IUPAC name, SMILES forms, InChIKey, XLogP, TPSA, H-bond/rotatable-bond counts, heavy atom count, charge, complexity)
78
+ - Optional textual descriptions, paged via `descriptionOffset`/`maxDescriptions` (default 3, up to 20) — fetched only for the first 10 CIDs in the batch, remaining CIDs listed in `skippedCids`
79
+ - Optional synonyms for every found CID, paged via `synonymOffset`/`maxSynonyms` (default 20, up to 100)
80
+ - Optional drug-likeness assessment (Lipinski Rule of Five + Veber rules), computed from the returned properties at no extra latency
81
+ - Optional pharmacological classification (FDA classes/mechanisms, MeSH classes, ATC codes) — same 10-CID fan-out cap as descriptions
82
+ - Per-CID `found: false` distinguishes a nonexistent CID from a real compound PubChem simply has no data for
83
+
84
+ ---
85
+
86
+ ### `pubchem_get_compound_image` <sub>tool</sub>
87
+
88
+ - Single CID; `size` is `"small"` (100x100) or `"large"` (300x300, default)
89
+ - Returns base64-encoded PNG plus width/height
90
+ - Typed `cid_not_found` error when PubChem has no record for the CID
91
+
92
+ ---
48
93
 
49
- Search PubChem for chemical compounds across five search modes.
94
+ ### `pubchem_get_compound_3d_structure` <sub>tool</sub>
50
95
 
51
- - **Identifier lookup** — resolve compound names, SMILES, or InChIKeys to CIDs (batch up to 25)
52
- - **Formula search** — find compounds by molecular formula in Hill notation
53
- - **Substructure/superstructure** — find compounds containing or contained within a query structure
54
- - **2D similarity** — find structurally similar compounds by Tanimoto similarity (configurable threshold)
55
- - Caps at 200 CIDs per page; `offset` pages further, to a ceiling of 10,000. Identifier lookups page over the set already resolved; formula and structure searches widen their bounded upstream request to reach a page, so deep pages cost more upstream
56
- - Optionally hydrate results with properties to avoid a follow-up details call
96
+ - Single CID; `format="json"` (default) returns parsed atoms (element + x/y/z) and bonds, `format="sdf"` returns the raw V2000 SDF text
97
+ - `maxAtoms`/`maxBonds` cap the JSON preview (default 200 each); `atomCount`/`bondCount` always report the full totals, with any capping disclosed via enrichment
98
+ - `includeRawSdf` bypasses the default 500-line cap on the raw SDF text
99
+ - Optional `includeAlternateConformerIds` lists conformer IDs beyond the default
100
+ - Typed `no_3d_structure` error when PubChem has no computed 3D coordinates (large molecules, mixtures, some salts)
57
101
 
58
102
  ---
59
103
 
60
- ### `pubchem_get_compound_details`
104
+ ### `pubchem_get_compound_xrefs` <sub>tool</sub>
61
105
 
62
- Get detailed compound information by CID.
106
+ - Single CID; one or more `xrefTypes` — string IDs (`RegistryID`, `RN` for CAS numbers, `PatentID`) and numeric IDs (`PubMedID`, `GeneID`, `ProteinGI`, `TaxonomyID`)
107
+ - Paged per type: `maxPerType` up to 500 (default 50), with the same `offset` applied across every requested type
108
+ - Each type reports its own `totalAvailable` and `truncated` flag
109
+ - Empty-result notice distinguishes "this compound has none of the requested types" from a possibly-mistyped CID
63
110
 
64
- - Batches up to 100 CIDs in a single request
65
- - 27 available properties: molecular weight, SMILES, InChIKey, XLogP, TPSA, complexity, stereo counts, and more
66
- - 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
67
- - Optionally includes known synonyms (trade names, systematic names, registry numbers)
68
- - Synonyms and descriptions are paged: `synonymOffset` and `descriptionOffset` window every compound in the batch at the same position, reaching the entries past a page
69
- - Optionally computes drug-likeness assessment (Lipinski Rule of Five + Veber rules) from fetched properties
70
- - Optionally fetches pharmacological classification (FDA classes, mechanisms of action, MeSH classes, ATC codes)
111
+ ---
112
+
113
+ ### `pubchem_get_compound_safety` <sub>tool</sub>
114
+
115
+ - Batch of 1-25 CIDs
116
+ - Returns GHS signal word, pictograms, hazard statements (H-codes), and precautionary statements (P-codes), with source attribution
117
+ - Per-CID `status`: `ok`, `no_ghs_data` (compound exists, no deposited classification), or `cid_not_found` (no PubChem record at all) — kept distinct so a bad CID never reads as "no hazards on file"
118
+ - Precautionary statements carry a `decoded` flag — false for codes needing label-specific fill text or outside the decoder table; the code itself is still authoritative
71
119
 
72
120
  ---
73
121
 
74
- ### `pubchem_get_bioactivity`
122
+ ### `pubchem_get_bioactivity` <sub>tool</sub>
123
+
124
+ - Single CID; filter by `outcomeFilter` (`active`/`inactive`/`all`, default `all`) and/or `targetGeneId`/`targetAccession`
125
+ - Caps at 100 results per page (default 20); `offset` reaches the rest
126
+ - Reports `totalAssays`/`activeCount`/`inactiveCount` for the whole compound, plus `filteredCount`/`returnedCount` for the current page
127
+ - Notices distinguish "no bioactivity data at all" from "the filter excluded everything" from "offset past the end"
128
+
129
+ ---
75
130
 
76
- Get a compound's bioactivity profile from PubChem BioAssay.
131
+ ### `pubchem_get_compound_interactions` <sub>tool</sub>
77
132
 
78
- - Returns assay outcomes (Active/Inactive/Inconclusive), target info (protein accessions, NCBI Gene IDs), and quantitative values (IC50, EC50, Ki)
79
- - Filter by outcome and/or a specific molecular target (NCBI Gene ID or protein accession)
80
- - Caps at 100 results per page; `offset` reaches the rest (well-studied compounds may have thousands)
133
+ - Single CID; one or more `kinds` — `drug-drug` (DrugBank), `drug-food`, `target` (binding/activity from BindingDB, ChEMBL, and others); default `["drug-drug"]`
134
+ - `maxEntries` per kind per page (1-50, default 10); `offset` counts source records rather than returned entries, capped at 2,147,483,646
135
+ - Each kind pages independently — `paging[]` reports per-kind `totalRecords`/`nextOffset`/`truncated`; the top-level `nextOffset` is populated only when exactly one requested kind still has records left
136
+ - A kind that fails to retrieve is named in `failedKinds` without failing the kinds that succeeded
81
137
 
82
138
  ---
83
139
 
84
- ### `pubchem_get_summary`
140
+ ### `pubchem_search_assays` <sub>tool</sub>
85
141
 
86
- Get descriptive summaries for four PubChem entity types.
142
+ - Search by `targetType`: `genesymbol`/`proteinname` (text), `geneid` (NCBI Gene ID), `proteinaccession` (UniProt)
143
+ - Caps at 200 AIDs per page (default 50); `offset` pages to the total found
144
+ - Rejects a blank `targetQuery` and a non-numeric `geneid` query before the upstream call
145
+ - Reports `totalFound` across all pages and distinguishes "no match" from "offset past the end"
87
146
 
88
- - Assays (AID), genes (Gene ID), proteins (UniProt accession), taxonomy (Tax ID)
89
- - Up to 10 entities per call
90
- - Type-specific field extraction for clean, structured output
147
+ ---
148
+
149
+ ### `pubchem_get_summary` <sub>tool</sub>
150
+
151
+ - `entityType`: `assay` (AID), `gene` (NCBI Gene ID), `protein` (UniProt accession), or `taxonomy` (Tax ID); up to 10 identifiers per call
152
+ - Per-identifier `found` flag; populated fields depend on `entityType` (taxonomy includes an ordered `lineage`, gene includes `symbol`/`taxonomy`)
153
+ - Notice reports how many identifiers were not found and which ID type `entityType` expects
91
154
 
92
155
  ---
93
156
 
94
- ### `pubchem_get_compound_interactions`
157
+ ### `pubchem://compound/{cid}` <sub>resource</sub>
158
+
159
+ - Core physicochemical properties (the same default 14-property set as `pubchem_get_compound_details`), as `application/json`
160
+ - Throws a typed not-found when the CID doesn't exist in PubChem
161
+ - Use `pubchem_get_compound_details` to select specific properties or add descriptions, synonyms, drug-likeness, and classification
162
+
163
+ ---
95
164
 
96
- Get a compound's interaction data by CID.
165
+ ### `pubchem://compound/{cid}/safety` <sub>resource</sub>
97
166
 
98
- - Drug-drug interactions (DrugBank), drug-food interactions, and chemical-target binding/activity (BindingDB, ChEMBL, and others)
99
- - Select which interaction kinds to fetch and cap entries per kind
100
- - Paged per kind: each reports its source-record total and its own `nextOffset`, and `offset` reaches the records past a page
101
- - Each entry carries its originating source — coverage is richest for approved drugs
167
+ - GHS hazard classification as `application/json`
168
+ - `status` (`ok`/`no_ghs_data`/`cid_not_found`) is the only signal distinguishing a bad CID from a compound with no deposited classification — a resource read has no notice surface
102
169
 
103
170
  ---
104
171
 
105
- ### `pubchem_get_compound_3d_structure`
172
+ ### `pubchem://compound/{cid}/image` <sub>resource</sub>
106
173
 
107
- Get a compound's default 3D conformer by CID.
174
+ - 2D structure diagram, 300x300 PNG, returned as a base64 blob
175
+ - Use `pubchem_get_compound_image` for the 100x100 size option
108
176
 
109
- - `format="json"` returns parsed atoms (element + x/y/z) and bonds for direct reasoning; `format="sdf"` returns raw V2000 SDF for passthrough to docking or rendering
110
- - `maxAtoms`/`maxBonds` bound the atom/bond preview and `includeRawSdf` opts into a large raw SDF past the safe line cap; `atomCount`/`bondCount` always report the totals and any capping is disclosed
111
- - Optionally lists alternate conformer IDs
112
- - Returns a typed not-found when PubChem has no computed 3D coordinates (large molecules, mixtures, some salts)
177
+ ---
113
178
 
114
- ## Resources
179
+ ### `pubchem://compound/{cid}/xrefs` <sub>resource</sub>
115
180
 
116
- Compound and assay records are also exposed as URI-templated MCP resources, backed by the same client methods as the tools:
181
+ - Focused default set — `RN` (CAS), `RegistryID`, `PubMedID` — up to 25 IDs per type, as `application/json`
182
+ - Use `pubchem_get_compound_xrefs` for the full set of xref types, a higher per-type cap, and offset paging
117
183
 
118
- | URI Template | Returns |
119
- |:-------------|:--------|
120
- | `pubchem://compound/{cid}` | Core physicochemical properties (JSON). |
121
- | `pubchem://compound/{cid}/safety` | GHS hazard classification (JSON). |
122
- | `pubchem://compound/{cid}/image` | 2D structure diagram (PNG). |
123
- | `pubchem://compound/{cid}/xrefs` | External cross-references (JSON). |
124
- | `pubchem://compound/{cid}/bioactivity` | Bioassay activity profile (JSON). |
125
- | `pubchem://assay/{aid}` | BioAssay summary (JSON). |
184
+ ---
126
185
 
127
- ## Features
186
+ ### `pubchem://compound/{cid}/bioactivity` <sub>resource</sub>
187
+
188
+ - Up to 25 assays as `application/json`, plus `totalAssays`/`activeCount` for the whole compound
189
+ - Use `pubchem_get_bioactivity` to filter by outcome or target, raise the cap, or page with offset
128
190
 
129
- Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core):
191
+ ---
192
+
193
+ ### `pubchem://assay/{aid}` <sub>resource</sub>
194
+
195
+ - BioAssay summary as `application/json` — name, description, source, protocol, substance counts
196
+ - Throws a typed not-found when the AID doesn't exist
130
197
 
131
- - Declarative tool definitions — single file per tool, framework handles registration and validation
132
- - Unified error handling across all tools
133
- - Pluggable auth (`none`, `jwt`, `oauth`)
134
- - Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
135
- - Structured logging with optional OpenTelemetry tracing
136
- - Runs locally (stdio/HTTP) or containerized via Docker
198
+ ## Features
199
+
200
+ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): stdio and Streamable HTTP transports, pluggable auth (`none` / `jwt` / `oauth`), swappable storage (`in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`), structured logging with optional OpenTelemetry tracing.
137
201
 
138
202
  PubChem-specific:
139
203
 
140
- - Rate-limited client for PUG REST and PUG View APIs (5 req/s with automatic queuing)
141
- - Retry with exponential backoff on 5xx errors and network failures
142
- - All tools are read-only and idempotent — no API keys required
204
+ - Covers both PUG REST (search, properties, cross-references, safety, bioactivity, interactions) and PUG View (textual descriptions, pharmacological classification) endpoints
205
+ - Rate-limited client (5 req/s) with automatic request queuing, and retry with exponential backoff on 5xx errors and network failures
206
+ - Hand-rolled V2000 SDF parser for 3D conformer atoms and bonds; drug-likeness (Lipinski/Veber) computed from already-fetched properties, adding no extra latency
207
+ - All tools are read-only and idempotent — no API keys required, PubChem's API is freely accessible
208
+
209
+ Agent-friendly output:
143
210
 
144
- ## Getting Started
211
+ - Discriminated output contracts — per-CID `status` (`ok` / `no_ghs_data` / `cid_not_found`) and `found` flags let callers branch on data instead of matching an error string
212
+ - Graceful partial failure — batch tools return per-item results alongside `unresolvedIdentifiers`, `skippedCids`, and `failedKinds` rather than failing the whole call
213
+ - Response shaping — truncation disclosure (`truncated`, `shown`/`cap`, `nextOffset`) on every capped list, plus a `totalFoundAtLeast` floor in place of a count when an upstream search saturates
214
+ - Typed error reasons — validation and not-found failures declare a `reason` (e.g. `cid_not_found`, `missing_identifier_args`, `invalid_cid_query`) with actionable recovery text, not generic messages
215
+
216
+ ## Getting started
145
217
 
146
218
  ### Public Hosted Instance
147
219
 
@@ -160,7 +232,7 @@ A public instance is available at `https://pubchem.caseyjhand.com/mcp` — no in
160
232
 
161
233
  ### Self-Hosted / Local
162
234
 
163
- Add to your MCP client config (e.g., `claude_desktop_config.json`):
235
+ Add the following to your MCP client configuration file.
164
236
 
165
237
  ```json
166
238
  {
@@ -177,9 +249,48 @@ Add to your MCP client config (e.g., `claude_desktop_config.json`):
177
249
  }
178
250
  ```
179
251
 
252
+ Or with npx (no Bun required):
253
+
254
+ ```json
255
+ {
256
+ "mcpServers": {
257
+ "pubchem-mcp-server": {
258
+ "type": "stdio",
259
+ "command": "npx",
260
+ "args": ["-y", "@cyanheads/pubchem-mcp-server@latest"],
261
+ "env": {
262
+ "MCP_TRANSPORT_TYPE": "stdio"
263
+ }
264
+ }
265
+ }
266
+ }
267
+ ```
268
+
269
+ Or with Docker:
270
+
271
+ ```json
272
+ {
273
+ "mcpServers": {
274
+ "pubchem-mcp-server": {
275
+ "type": "stdio",
276
+ "command": "docker",
277
+ "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/pubchem-mcp-server:latest"]
278
+ }
279
+ }
280
+ }
281
+ ```
282
+
283
+ For Streamable HTTP, set the transport and start the server:
284
+
285
+ ```sh
286
+ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
287
+ # Server listens at http://localhost:3010/mcp
288
+ ```
289
+
180
290
  ### Prerequisites
181
291
 
182
- - [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+)
292
+ - [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
293
+ - No API keys required — PubChem's API is freely accessible.
183
294
 
184
295
  ### Installation
185
296
 
@@ -189,73 +300,92 @@ Add to your MCP client config (e.g., `claude_desktop_config.json`):
189
300
  git clone https://github.com/cyanheads/pubchem-mcp-server.git
190
301
  ```
191
302
 
192
- 1. **Navigate into the directory:**
303
+ 2. **Navigate into the directory:**
193
304
 
194
305
  ```sh
195
306
  cd pubchem-mcp-server
196
307
  ```
197
308
 
198
- 1. **Install dependencies:**
309
+ 3. **Install dependencies:**
199
310
 
200
311
  ```sh
201
312
  bun install
202
313
  ```
203
314
 
204
- ## Configuration
315
+ 4. **Configure environment (optional):**
205
316
 
206
- No API keys are required — PubChem's API is freely accessible.
317
+ ```sh
318
+ cp .env.example .env
319
+ # edit .env to override transport, session mode, storage, or logging defaults
320
+ ```
321
+
322
+ ## Configuration
207
323
 
208
324
  | Variable | Description | Default |
209
325
  |:---------|:------------|:--------|
210
326
  | `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
211
- | `MCP_HTTP_PORT` | Port for HTTP server. | `3000` (`3010` in Docker) |
212
- | `MCP_SESSION_MODE` | `stateless`, `stateful`, or `auto`. The example and Docker use `stateless`; no multi-round-trip input is needed. | `auto` (resolves to `stateful`) |
213
- | `MCP_HTTP_HOST` | Host for HTTP server. | `localhost` |
327
+ | `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
328
+ | `MCP_HTTP_HOST` | Host for HTTP server. | `127.0.0.1` |
329
+ | `MCP_SESSION_MODE` | `stateless`, `stateful`, or `auto`. PubChem needs no multi-round-trip input, so the server declares `stateless`; the example and Docker set it to match. | `stateless` |
214
330
  | `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
215
331
  | `MCP_LOG_LEVEL` | Log level (RFC 5424). | `info` |
216
332
  | `STORAGE_PROVIDER_TYPE` | Storage backend. | `in-memory` |
217
333
  | `OTEL_ENABLED` | Enable OpenTelemetry. | `false` |
218
334
 
219
- ## Running the Server
335
+ See [`.env.example`](./.env.example) for the full list of optional overrides.
336
+
337
+ ## Running the server
220
338
 
221
- ### Local Development
339
+ ### Local development
222
340
 
223
341
  - **Build and run:**
224
342
 
225
343
  ```sh
344
+ # One-time build
226
345
  bun run rebuild
227
- bun run start:stdio # or start:http
346
+
347
+ # Run the built server
348
+ bun run start:stdio
349
+ # or
350
+ bun run start:http
228
351
  ```
229
352
 
230
353
  - **Run checks and tests:**
231
354
 
232
355
  ```sh
233
- bun run devcheck # Lints, formats, type-checks
234
- bun run test # Runs test suite
356
+ bun run devcheck # Lint, format, typecheck, security
357
+ bun run test # Vitest test suite
358
+ bun run lint:mcp # Validate MCP definitions against spec
235
359
  ```
236
360
 
237
361
  ### Docker
238
362
 
239
363
  ```sh
240
364
  docker build -t pubchem-mcp-server .
241
- docker run -p 3010:3010 pubchem-mcp-server
365
+ docker run --rm -p 3010:3010 pubchem-mcp-server
242
366
  ```
243
367
 
244
- ## Project Structure
368
+ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/pubchem-mcp-server`. OpenTelemetry peer dependencies are installed by default — build with `--build-arg OTEL_ENABLED=false` to omit them.
369
+
370
+ ## Project structure
245
371
 
246
372
  | Directory | Purpose |
247
373
  |:----------|:--------|
374
+ | `src/index.ts` | `createApp()` entry point — registers tools/resources and inits the PubChem client. |
248
375
  | `src/mcp-server/tools/definitions/` | Tool definitions (`*.tool.ts`). |
249
- | `src/services/pubchem/` | PubChem API client with rate limiting and response parsing. |
376
+ | `src/mcp-server/resources/definitions/` | Resource definitions (`*.resource.ts`). |
377
+ | `src/services/pubchem/` | PubChem API client — rate limiting, retry, and response/SDF parsing. |
250
378
  | `scripts/` | Build, clean, devcheck, and tree generation scripts. |
379
+ | `tests/` | Unit and integration tests. |
251
380
 
252
- ## Development Guide
381
+ ## Development guide
253
382
 
254
383
  See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
255
384
 
256
385
  - Handlers throw, framework catches — no `try/catch` in tool logic
257
- - Use `ctx.log` for domain-specific logging
258
- - Register new tools in the `index.ts` barrel file
386
+ - Use `ctx.log` for request-scoped logging
387
+ - Wrap external API calls: validate the raw PubChem response → normalize to a domain type → return the output schema; never fabricate missing fields
388
+ - Register new tools and resources in the `index.ts` barrel files
259
389
 
260
390
  ## Contributing
261
391
 
@@ -0,0 +1,23 @@
1
+ ---
2
+ summary: "mcp-ts-core ^0.9.6 → ^0.9.13: HTTP body cap, session-init gate, quieter 4xx logs, GET /mcp keywords; httpErrorFromResponse adoption; keyword additions"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.21 — 2026-05-28
8
+
9
+ ## Changed
10
+
11
+ - **`@cyanheads/mcp-ts-core`** `^0.9.6 → ^0.9.13` — adopted across seven patch releases:
12
+ - **`MCP_HTTP_MAX_BODY_BYTES`** (0.9.13) — configurable inbound body cap; oversized requests rejected with 413 before the SDK parses the body. Default 1 MiB; set to `0` to disable.
13
+ - **HTTP session-init gate** (0.9.10) — stateful HTTP mode now rejects non-`initialize` requests without an `Mcp-Session-Id` header with HTTP 400.
14
+ - **`httpErrorHandler` log-level split** (0.9.10) — 401, 403, 400, 404 responses downgraded to `warning`; stack traces removed from expected client errors.
15
+ - **`GET /mcp` keywords** (0.9.12) — `package.json` `keywords` now surfaced on the HTTP status endpoint alongside name/version/description.
16
+ - 0.9.7–0.9.9, 0.9.11 — skill refreshes, `git-wrapup` skill, fuzz pre-parse fixes, `code-simplifier` skill, `biome` lint adjustment.
17
+ - **`pubchem-client.ts`** — `httpStatusToErrorCode` + manual `McpError` construction replaced with `httpErrorFromResponse` (framework util that classifies by status and body). Both `fetchJson` and `fetchBinary` error paths updated; fault message passed as `data.fault` alongside `data.url`.
18
+ - **`package.json` keywords** — added `typescript`, `bun`, `stdio`, `streamable-http` (surfaces on `GET /mcp` endpoint via 0.9.12 framework support).
19
+ - **`@biomejs/biome`** `^2.4.15 → ^2.4.16`.
20
+
21
+ ## Skills
22
+
23
+ - **Skills synced** from `@cyanheads/mcp-ts-core@0.9.13` — refreshed `api-canvas`, `api-config`, `design-mcp-server`, `polish-docs-meta`, `release-and-publish`, `report-issue-framework`; added `code-simplifier`, `git-wrapup`; removed `migrate-mcp-ts-template`.
@@ -0,0 +1,14 @@
1
+ ---
2
+ summary: "Enrichment adoption: search_compounds and search_assays surface search-type/target echoes, true upstream totals, and empty-result guidance via a typed enrichment block"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.22 — 2026-05-30
8
+
9
+ ## Changed
10
+
11
+ - **`pubchem_search_compounds`** — `searchType` and `totalFound` moved from `output` to a typed `enrichment` block; `output` now contains only `results`. Both fields reach `structuredContent` and `content[]` automatically via `ctx.enrich()`; an empty-result `notice` is appended when no compounds match.
12
+ - **`pubchem_search_assays`** — `targetType`, `targetQuery`, and `totalFound` moved from `output` to `enrichment`; `output` now contains only `aids`. An empty-result `notice` is appended when no assays match, suggesting alternative `targetType` values or `pubchem_get_summary` for entity lookups.
13
+ - **`@cyanheads/mcp-ts-core`** `^0.9.13 → ^0.9.16` — skill refreshes, `enrichment` contract support, and associated framework patches.
14
+ - **Skills synced** from `@cyanheads/mcp-ts-core@0.9.16`.
@@ -0,0 +1,18 @@
1
+ ---
2
+ summary: "Typed cid_not_found error on get_compound_image; enrichment for get_bioactivity, get_compound_safety, and get_summary"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.23 — 2026-06-01
8
+
9
+ ## Added
10
+
11
+ - **`pubchem_get_compound_image`** — a 404 for a missing CID now returns a typed `cid_not_found` (`NotFound`) error carrying `data.reason: 'cid_not_found'` and a recovery hint, instead of a bare not-found with a null reason. The other six CID tools surface absence as a structured success response and need no error contract. ([#17](https://github.com/cyanheads/pubchem-mcp-server/issues/17))
12
+ - **`pubchem_get_bioactivity`** — enrichment block with `outcomeFilter` echo, `filteredCount` (matching the filter) and `returnedCount` (after the `maxResults` cap), plus a notice distinguishing no-data from filter-excluded results. ([#19](https://github.com/cyanheads/pubchem-mcp-server/issues/19))
13
+ - **`pubchem_get_compound_safety`** — enrichment notice pointing to `pubchem_get_compound_details` when no GHS data is on file. ([#19](https://github.com/cyanheads/pubchem-mcp-server/issues/19))
14
+ - **`pubchem_get_summary`** — enrichment with `requestedCount`, `foundCount`, and a per-miss notice. ([#19](https://github.com/cyanheads/pubchem-mcp-server/issues/19))
15
+
16
+ ## Changed
17
+
18
+ - **`vitest`** `^4.1.7 → ^4.1.8`.
@@ -0,0 +1,24 @@
1
+ ---
2
+ summary: "interactions and 3D structure tools, URI-templated resources, target filter for bioactivity, batch safety"
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.0 — 2026-06-01
8
+
9
+ ## Added
10
+
11
+ - **`pubchem_get_compound_interactions`** — drug-drug, drug-food, and chemical-target interactions with per-entry source attribution ([#12](https://github.com/cyanheads/pubchem-mcp-server/issues/12)). Drug-drug and target interactions fetched from PubChem's SDQ external tables (`drugbankddi`, `consolidatedcompoundtarget`); drug-food interactions from PUG-View inline. `severity` is not normalized across sources — reported faithfully from source prose.
12
+ - **`pubchem_get_compound_3d_structure`** — 3D conformer as parsed JSON atoms/bonds (`format: 'json'`, default) or raw SDF text (`format: 'sdf'`), with optional alternate conformer IDs ([#15](https://github.com/cyanheads/pubchem-mcp-server/issues/15)). Returns `notFound` for compounds without computed 3D coordinates.
13
+ - **URI-templated MCP resources** — six resources backed by existing `PubChemClient` methods, no new API calls ([#14](https://github.com/cyanheads/pubchem-mcp-server/issues/14)):
14
+ - `pubchem://compound/{cid}` — compound properties
15
+ - `pubchem://compound/{cid}/safety` — GHS classification
16
+ - `pubchem://compound/{cid}/image` — 2D structure diagram (PNG)
17
+ - `pubchem://compound/{cid}/xrefs` — external database cross-references
18
+ - `pubchem://compound/{cid}/bioactivity` — assay activity
19
+ - `pubchem://assay/{aid}` — assay entity summary
20
+ - **`targetGeneId` / `targetAccession` filters** on `pubchem_get_bioactivity` input — pure client-side filter on existing `BioactivityRow` fields; both echoed in enrichment when set ([#9](https://github.com/cyanheads/pubchem-mcp-server/issues/9)).
21
+
22
+ ## Changed
23
+
24
+ - **`pubchem_get_compound_safety` input is now `cids` (array, 1–25)** — replaces the single `cid: number` parameter; output is now `results[]` with one entry per CID ([#13](https://github.com/cyanheads/pubchem-mcp-server/issues/13)). **Breaking:** callers must update to pass an array.
@@ -0,0 +1,14 @@
1
+ ---
2
+ summary: "interactions target source, per-kind isolation, fetch resilience for image and 3D structure"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.1 — 2026-06-02
8
+
9
+ ## Fixed
10
+
11
+ - **`pubchem_get_compound_interactions` (`target` kind)** — now returns chemical–target binding and activity for the requested compound, sourced from PubChem's CID-keyed `bioactivity` collection (BindingDB, ChEMBL, and others). Previously queried a gene-indexed collection whose compound filter was silently ignored, causing every compound to return the same unrelated compound's records ([#20](https://github.com/cyanheads/pubchem-mcp-server/issues/20)).
12
+ - **`pubchem_get_compound_interactions` (per-kind isolation)** — a failure in one requested interaction kind no longer discards the kinds that succeeded. Successful kinds are returned and unavailable kinds are reported via a `failedKinds` notice (`Promise.allSettled` per-kind isolation) ([#21](https://github.com/cyanheads/pubchem-mcp-server/issues/21)).
13
+ - **`pubchem_get_compound_image` and `pubchem_get_compound_3d_structure`** — image and 3D-structure fetches now retry once on transient upstream 5xx errors and surface a clear `PubChem request timed out (30s)` message on timeout instead of a raw abort error, matching the JSON fetch path ([#16](https://github.com/cyanheads/pubchem-mcp-server/issues/16)).
14
+ - **SDQ-backed interaction fetches** — PubChem's occasional malformed JSON now returns a contextful error instead of an opaque `Failed to parse JSON`.
@@ -0,0 +1,17 @@
1
+ ---
2
+ summary: "adopt @cyanheads/mcp-ts-core 0.9.21 — per-request log context fix, secret scrubbing in fetch errors, fail-fast retries"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.2 — 2026-06-02
8
+
9
+ ## Changed
10
+
11
+ - **`@cyanheads/mcp-ts-core`** `^0.9.16 → ^0.9.21` — adopts three framework fixes: per-request logs and traces now carry fresh request/trace/span IDs instead of the frozen boot context (HTTP transport); `fetchWithTimeout` strips query-string secrets (e.g. `?api_key=`) from error messages and logs; `withRetry` fails fast on non-retryable errors and `ctx.fail` auto-populates the `retryable` flag.
12
+ - **`release:github` script** — new `scripts/release-github.ts` added to `package.json`; creates a GitHub Release from the annotated tag with correct title formatting.
13
+ - **`devcheck`** — adds Open-Indexed Interfaces and Skill Versions checks from framework 0.9.21 skill sync.
14
+
15
+ ## Dependencies
16
+
17
+ - `@cyanheads/mcp-ts-core` `^0.9.16 → ^0.9.21`
@@ -0,0 +1,27 @@
1
+ ---
2
+ summary: "adopt @cyanheads/mcp-ts-core ^0.10.6 — truncation disclosure on capped searches, explicit createApp identity, MCPB bundle-content hardening"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.3 — 2026-06-12
8
+
9
+ ## Added
10
+
11
+ - **Truncation disclosure** — `pubchem_search_compounds`, `pubchem_search_assays`, and `pubchem_get_bioactivity` now emit `truncated`/`shown`/`cap` via `ctx.enrich.truncated()` when results are capped at `maxResults`, so callers know more matches exist beyond what was returned.
12
+ - **`scripts/clean-mcpb.ts`** — post-pack bundle cleaner wired into the `bundle` script: runs `mcpb clean`, then strips dependency-shipped agent-doc entries (`skills/`, `.claude/`, `.agents/`, `SKILL.md`) nested under `node_modules/` that root-anchored `.mcpbignore` patterns cannot reach.
13
+ - **Dockerfile `HEALTHCHECK`** — bun-native `fetch` against `/healthz` (slim image ships no curl/wget), plus an `org.opencontainers.image.version` OCI label sourced from the `APP_VERSION` build arg.
14
+
15
+ ## Changed
16
+
17
+ - **`createApp()`** — sets explicit `name` and `title` to `pubchem-mcp-server`, pinning the served identity to the repo name on every surface instead of relying on the scoped-package fallback.
18
+ - **`scripts/lint-packaging.ts`** — adds bundle-content and identity guards: `.mcpbignore` dev-dir exclusion and anchoring (unanchored patterns also strip `node_modules/…/skills/`), critical-runtime-path protection, a post-bundle `node_modules` agent-doc scan, and a `createApp()`/manifest `display_name` identity check against the unscoped package name.
19
+ - **`scripts/check-framework-antipatterns.ts`** — adds rule 4 flagging `z.coerce.boolean()` on env flags (`Boolean("false")` is `true`, so the flag can't be disabled via env — use `z.stringbool()`); comment-line matches are now skipped so JSDoc naming an antipattern no longer false-positives.
20
+ - **`.mcpbignore`** — root dev-dir patterns anchored with a leading `/` so they no longer match nested runtime paths under `node_modules/`.
21
+
22
+ ## Dependencies
23
+
24
+ - `@cyanheads/mcp-ts-core` `^0.9.21 → ^0.10.6`
25
+ - `@biomejs/biome` `^2.4.16 → ^2.5.0`
26
+ - `@types/node` `^25.9.1 → ^25.9.3`
27
+ - `packageManager` `bun@1.3.2 → bun@1.3.11`
@@ -0,0 +1,27 @@
1
+ ---
2
+ summary: "adopt @cyanheads/mcp-ts-core ^0.10.9 — check-dependency-specifiers devcheck step, plugin-manifest packaging lint, fresh-scaffold devcheck guards, vendored skill re-sync"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.4 — 2026-06-20
8
+
9
+ ## Added
10
+
11
+ - **`scripts/check-dependency-specifiers.ts`** — new devcheck step (`Dependency Specifiers`, `--no-dep-specifiers`) rejecting floating specifiers (`latest`, `*`, pre-release dist-tags) in `package.json`'s dependency sections and `bun.lock`'s `workspaces` map, catching the case where `bun update --latest` writes a literal `latest` dist-tag into the lock and lets a later `bun install` re-resolve past an intentional version hold. ([cyanheads/mcp-ts-core#246](https://github.com/cyanheads/mcp-ts-core/issues/246))
12
+ - **Plugin marketplace manifest checks in `scripts/lint-packaging.ts`** — check 10 validates `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, and `.codex-plugin/mcp.json`: non-empty descriptions, display fields carry the unscoped machine name, and the `npx -y` install arg carries the full scoped package name. Gated by the new `devcheck.config.json` `packaging.pluginManifests` flag (default on). ([cyanheads/mcp-ts-core#240](https://github.com/cyanheads/mcp-ts-core/issues/240))
13
+
14
+ ## Changed
15
+
16
+ - **Fresh-scaffold devcheck guards** — `scripts/build-changelog.ts`, `scripts/devcheck.ts`, and `scripts/check-framework-antipatterns.ts` skip git-dependent checks when `.git` is absent; `scripts/check-skill-versions.ts` guards against a `SKILL.md` deleted from the worktree. ([cyanheads/mcp-ts-core#237](https://github.com/cyanheads/mcp-ts-core/issues/237), [#242](https://github.com/cyanheads/mcp-ts-core/issues/242), [#243](https://github.com/cyanheads/mcp-ts-core/issues/243))
17
+ - **Vendored skills re-synced** to mcp-ts-core 0.10.7–0.10.9 — `metadata.version` bumps across `api-auth`, `api-errors`, `api-services`, `api-telemetry`, `field-test`, `report-issue-local`, `tool-defs-analysis`, plus body updates to `git-wrapup`, `orchestrations`, `api-context`, and others. ([cyanheads/mcp-ts-core#238](https://github.com/cyanheads/mcp-ts-core/issues/238))
18
+
19
+ ## Removed
20
+
21
+ - **`skills/references/{formatting,parsing,security}.md`** — stray framework reference docs vendored in error; removed.
22
+
23
+ ## Dependencies
24
+
25
+ - `@cyanheads/mcp-ts-core` `^0.10.6 → ^0.10.9`
26
+ - `@types/node` `^25.9.3 → ^26.0.0`
27
+ - `vitest` `^4.1.8 → ^4.1.9`