@cyanheads/protein-mcp-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/AGENTS.md +416 -0
  2. package/CLAUDE.md +416 -0
  3. package/Dockerfile +121 -0
  4. package/LICENSE +201 -0
  5. package/README.md +321 -0
  6. package/changelog/0.1.x/0.1.0.md +21 -0
  7. package/changelog/template.md +127 -0
  8. package/dist/config/server-config.d.ts +27 -0
  9. package/dist/config/server-config.d.ts.map +1 -0
  10. package/dist/config/server-config.js +110 -0
  11. package/dist/config/server-config.js.map +1 -0
  12. package/dist/index.d.ts +9 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +53 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/mcp-server/resources/definitions/af-summary.resource.d.ts +29 -0
  17. package/dist/mcp-server/resources/definitions/af-summary.resource.d.ts.map +1 -0
  18. package/dist/mcp-server/resources/definitions/af-summary.resource.js +61 -0
  19. package/dist/mcp-server/resources/definitions/af-summary.resource.js.map +1 -0
  20. package/dist/mcp-server/resources/definitions/index.d.ts +7 -0
  21. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
  22. package/dist/mcp-server/resources/definitions/index.js +7 -0
  23. package/dist/mcp-server/resources/definitions/index.js.map +1 -0
  24. package/dist/mcp-server/resources/definitions/pdb-summary.resource.d.ts +31 -0
  25. package/dist/mcp-server/resources/definitions/pdb-summary.resource.d.ts.map +1 -0
  26. package/dist/mcp-server/resources/definitions/pdb-summary.resource.js +68 -0
  27. package/dist/mcp-server/resources/definitions/pdb-summary.resource.js.map +1 -0
  28. package/dist/mcp-server/tools/definitions/_schemas.d.ts +31 -0
  29. package/dist/mcp-server/tools/definitions/_schemas.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/definitions/_schemas.js +82 -0
  31. package/dist/mcp-server/tools/definitions/_schemas.js.map +1 -0
  32. package/dist/mcp-server/tools/definitions/analyze-collection.tool.d.ts +61 -0
  33. package/dist/mcp-server/tools/definitions/analyze-collection.tool.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/definitions/analyze-collection.tool.js +115 -0
  35. package/dist/mcp-server/tools/definitions/analyze-collection.tool.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/compare-structures.tool.d.ts +49 -0
  37. package/dist/mcp-server/tools/definitions/compare-structures.tool.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/compare-structures.tool.js +168 -0
  39. package/dist/mcp-server/tools/definitions/compare-structures.tool.js.map +1 -0
  40. package/dist/mcp-server/tools/definitions/find-similar.tool.d.ts +67 -0
  41. package/dist/mcp-server/tools/definitions/find-similar.tool.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/definitions/find-similar.tool.js +274 -0
  43. package/dist/mcp-server/tools/definitions/find-similar.tool.js.map +1 -0
  44. package/dist/mcp-server/tools/definitions/get-annotations.tool.d.ts +58 -0
  45. package/dist/mcp-server/tools/definitions/get-annotations.tool.d.ts.map +1 -0
  46. package/dist/mcp-server/tools/definitions/get-annotations.tool.js +180 -0
  47. package/dist/mcp-server/tools/definitions/get-annotations.tool.js.map +1 -0
  48. package/dist/mcp-server/tools/definitions/get-structure.tool.d.ts +78 -0
  49. package/dist/mcp-server/tools/definitions/get-structure.tool.d.ts.map +1 -0
  50. package/dist/mcp-server/tools/definitions/get-structure.tool.js +365 -0
  51. package/dist/mcp-server/tools/definitions/get-structure.tool.js.map +1 -0
  52. package/dist/mcp-server/tools/definitions/index.d.ts +12 -0
  53. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  54. package/dist/mcp-server/tools/definitions/index.js +12 -0
  55. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  56. package/dist/mcp-server/tools/definitions/search-structures.tool.d.ts +71 -0
  57. package/dist/mcp-server/tools/definitions/search-structures.tool.d.ts.map +1 -0
  58. package/dist/mcp-server/tools/definitions/search-structures.tool.js +216 -0
  59. package/dist/mcp-server/tools/definitions/search-structures.tool.js.map +1 -0
  60. package/dist/mcp-server/tools/definitions/track-ligands.tool.d.ts +59 -0
  61. package/dist/mcp-server/tools/definitions/track-ligands.tool.d.ts.map +1 -0
  62. package/dist/mcp-server/tools/definitions/track-ligands.tool.js +195 -0
  63. package/dist/mcp-server/tools/definitions/track-ligands.tool.js.map +1 -0
  64. package/dist/services/alignment/alignment-service.d.ts +56 -0
  65. package/dist/services/alignment/alignment-service.d.ts.map +1 -0
  66. package/dist/services/alignment/alignment-service.js +129 -0
  67. package/dist/services/alignment/alignment-service.js.map +1 -0
  68. package/dist/services/alphafold/alphafold-service.d.ts +57 -0
  69. package/dist/services/alphafold/alphafold-service.d.ts.map +1 -0
  70. package/dist/services/alphafold/alphafold-service.js +84 -0
  71. package/dist/services/alphafold/alphafold-service.js.map +1 -0
  72. package/dist/services/beacons/beacons-service.d.ts +52 -0
  73. package/dist/services/beacons/beacons-service.d.ts.map +1 -0
  74. package/dist/services/beacons/beacons-service.js +63 -0
  75. package/dist/services/beacons/beacons-service.js.map +1 -0
  76. package/dist/services/foldseek/foldseek-service.d.ts +71 -0
  77. package/dist/services/foldseek/foldseek-service.d.ts.map +1 -0
  78. package/dist/services/foldseek/foldseek-service.js +131 -0
  79. package/dist/services/foldseek/foldseek-service.js.map +1 -0
  80. package/dist/services/rcsb/facets.d.ts +50 -0
  81. package/dist/services/rcsb/facets.d.ts.map +1 -0
  82. package/dist/services/rcsb/facets.js +59 -0
  83. package/dist/services/rcsb/facets.js.map +1 -0
  84. package/dist/services/rcsb/rcsb-service.d.ts +81 -0
  85. package/dist/services/rcsb/rcsb-service.d.ts.map +1 -0
  86. package/dist/services/rcsb/rcsb-service.js +473 -0
  87. package/dist/services/rcsb/rcsb-service.js.map +1 -0
  88. package/dist/services/rcsb/types.d.ts +150 -0
  89. package/dist/services/rcsb/types.d.ts.map +1 -0
  90. package/dist/services/rcsb/types.js +8 -0
  91. package/dist/services/rcsb/types.js.map +1 -0
  92. package/dist/services/shared/async.d.ts +41 -0
  93. package/dist/services/shared/async.d.ts.map +1 -0
  94. package/dist/services/shared/async.js +64 -0
  95. package/dist/services/shared/async.js.map +1 -0
  96. package/dist/services/shared/http.d.ts +54 -0
  97. package/dist/services/shared/http.d.ts.map +1 -0
  98. package/dist/services/shared/http.js +115 -0
  99. package/dist/services/shared/http.js.map +1 -0
  100. package/dist/services/shared/identifiers.d.ts +12 -0
  101. package/dist/services/shared/identifiers.d.ts.map +1 -0
  102. package/dist/services/shared/identifiers.js +23 -0
  103. package/dist/services/shared/identifiers.js.map +1 -0
  104. package/dist/services/uniprot/uniprot-service.d.ts +65 -0
  105. package/dist/services/uniprot/uniprot-service.d.ts.map +1 -0
  106. package/dist/services/uniprot/uniprot-service.js +146 -0
  107. package/dist/services/uniprot/uniprot-service.js.map +1 -0
  108. package/package.json +106 -0
  109. package/server.json +99 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @fileoverview protein_search_structures — federated search across experimental
3
+ * (PDB) and predicted (computed model) structures via RCSB Search v2, with
4
+ * optional metadata enrichment of the experimental page and an optional facet
5
+ * breakdown for instant corpus orientation.
6
+ * @module mcp-server/tools/definitions/search-structures.tool
7
+ */
8
+ import { tool, z } from '@cyanheads/mcp-ts-core';
9
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
10
+ import { getServerConfig } from '../../../config/server-config.js';
11
+ import { buildFacetSpec, FACET_DIMENSION_NAMES } from '../../../services/rcsb/facets.js';
12
+ import { getRcsbService } from '../../../services/rcsb/rcsb-service.js';
13
+ import { entryIdOf } from '../../../services/shared/identifiers.js';
14
+ import { facetDimensionSchema, renderFacets, toFacetOutput } from './_schemas.js';
15
+ const CONTENT_TYPE_MAP = {
16
+ experimental: ['experimental'],
17
+ predicted: ['computational'],
18
+ all: ['experimental', 'computational'],
19
+ };
20
+ /** A computed-model identifier (AlphaFold / ModelArchive) vs an experimental PDB entry. */
21
+ function isPredictedId(id) {
22
+ return /^(AF|MA)_/i.test(id);
23
+ }
24
+ /** Pull a UniProt accession out of a computed-model identifier when present (`AF_AFP69905F1` → `P69905`). */
25
+ function accessionFromCsm(id) {
26
+ return /AF_AF([A-Z0-9]+?)F\d+$/i.exec(id)?.[1]?.toUpperCase();
27
+ }
28
+ export const searchStructures = tool('protein_search_structures', {
29
+ title: 'protein-mcp-server: search structures',
30
+ description: 'Search experimental (PDB) and predicted (computed-model) protein structures by free text, ' +
31
+ 'protein sequence (triggers an mmseqs2 similarity search), and/or organism, method, and ' +
32
+ 'resolution filters. Returns ranked hits; the experimental page is enriched with title, method, ' +
33
+ 'resolution, and organism. Chain hit IDs into protein_get_structure. Optionally returns a facet ' +
34
+ 'breakdown (counts by method / organism / release year / …) alongside the hits at no extra call.',
35
+ annotations: { readOnlyHint: true, openWorldHint: true },
36
+ errors: [
37
+ {
38
+ reason: 'no_criteria',
39
+ code: JsonRpcErrorCode.InvalidParams,
40
+ when: 'No query, sequence, or organism was provided — nothing to search on.',
41
+ recovery: 'Provide a free-text query, a protein sequence, or an organism name (filters alone are not enough).',
42
+ },
43
+ ],
44
+ input: z.object({
45
+ query: z
46
+ .string()
47
+ .optional()
48
+ .describe('Free-text query (protein name, gene, keyword, PDB title terms).'),
49
+ sequence: z
50
+ .string()
51
+ .optional()
52
+ .describe('One-letter amino-acid sequence; triggers an RCSB mmseqs2 sequence-similarity search.'),
53
+ organism: z
54
+ .string()
55
+ .optional()
56
+ .describe('Filter by source organism scientific name (e.g. "Homo sapiens").'),
57
+ method: z
58
+ .string()
59
+ .optional()
60
+ .describe('Filter by experimental method (e.g. "X-RAY DIFFRACTION", "ELECTRON MICROSCOPY").'),
61
+ max_resolution: z
62
+ .number()
63
+ .positive()
64
+ .optional()
65
+ .describe('Maximum resolution in Å (lower is sharper); applies to experimental structures.'),
66
+ min_identity: z
67
+ .number()
68
+ .min(0)
69
+ .max(1)
70
+ .optional()
71
+ .describe('Minimum sequence identity (0–1) for a sequence search. Default 0.'),
72
+ max_evalue: z
73
+ .number()
74
+ .positive()
75
+ .optional()
76
+ .describe('Maximum E-value for a sequence search. Default 1.'),
77
+ content_type: z
78
+ .enum(['experimental', 'predicted', 'all'])
79
+ .default('all')
80
+ .describe('Which structure universe to search: experimental (PDB), predicted (computed models), or all.'),
81
+ facets: z
82
+ .array(z.enum(FACET_DIMENSION_NAMES))
83
+ .optional()
84
+ .describe('Optional dimensions to summarize as a facet breakdown alongside the hits.'),
85
+ limit: z.number().int().min(1).max(100).default(25).describe('Maximum hits to return (1–100).'),
86
+ }),
87
+ output: z.object({
88
+ hits: z
89
+ .array(z
90
+ .object({
91
+ id: z.string().describe('Structure identifier (PDB entry ID or computed-model ID).'),
92
+ source: z
93
+ .enum(['experimental', 'predicted'])
94
+ .describe('Which universe the hit came from.'),
95
+ score: z.number().optional().describe('RCSB relevance score.'),
96
+ uniprotAccession: z
97
+ .string()
98
+ .optional()
99
+ .describe('UniProt accession parsed from a computed-model ID, when available.'),
100
+ title: z.string().optional().describe('Structure title (enriched experimental hits).'),
101
+ method: z
102
+ .string()
103
+ .optional()
104
+ .describe('Experimental method(s) (enriched experimental hits).'),
105
+ resolution: z
106
+ .number()
107
+ .optional()
108
+ .describe('Resolution in Å (enriched experimental hits).'),
109
+ organism: z
110
+ .string()
111
+ .optional()
112
+ .describe('Primary source organism (enriched experimental hits).'),
113
+ })
114
+ .describe('A ranked structure hit with optional enrichment metadata.'))
115
+ .describe('Ranked structure hits.'),
116
+ facets: z
117
+ .array(facetDimensionSchema)
118
+ .optional()
119
+ .describe('Optional facet breakdown when requested.'),
120
+ }),
121
+ enrichment: {
122
+ totalCount: z.number().describe('Total matches upstream before pagination.'),
123
+ effectiveQuery: z.string().optional().describe('Echoed text query for follow-up calls.'),
124
+ notice: z
125
+ .string()
126
+ .optional()
127
+ .describe('Advisory note (empty results, predicted-search caveats, truncation).'),
128
+ },
129
+ async handler(input, ctx) {
130
+ if (!input.query && !input.sequence && !input.organism) {
131
+ throw ctx.fail('no_criteria', 'Provide a query, sequence, or organism to search on.');
132
+ }
133
+ const cfg = getServerConfig();
134
+ const rcsb = getRcsbService();
135
+ const contentTypes = CONTENT_TYPE_MAP[input.content_type];
136
+ const facetSpecs = input.facets?.map((d) => buildFacetSpec(d));
137
+ const result = await rcsb.search({
138
+ ...(input.query ? { text: input.query } : {}),
139
+ ...(input.sequence ? { sequence: input.sequence } : {}),
140
+ ...(input.organism ? { organism: input.organism } : {}),
141
+ ...(input.method ? { method: input.method } : {}),
142
+ ...(typeof input.max_resolution === 'number'
143
+ ? { maxResolution: input.max_resolution }
144
+ : {}),
145
+ ...(typeof input.min_identity === 'number' ? { minIdentity: input.min_identity } : {}),
146
+ ...(typeof input.max_evalue === 'number' ? { maxEvalue: input.max_evalue } : {}),
147
+ // RCSB scopes by content type; multi-content searches just union both halves.
148
+ ...(contentTypes.length === 1 ? { contentType: contentTypes[0] } : {}),
149
+ limit: input.limit,
150
+ }, ctx, facetSpecs);
151
+ const experimentalIds = [
152
+ ...new Set(result.hits.filter((h) => !isPredictedId(h.id)).map((h) => entryIdOf(h.id))),
153
+ ];
154
+ const metaById = new Map();
155
+ if (experimentalIds.length > 0) {
156
+ for (const meta of await rcsb.getEntries(experimentalIds, ctx))
157
+ metaById.set(meta.id, meta);
158
+ }
159
+ const hits = result.hits.map((h) => toHit(h, metaById));
160
+ const facets = result.facets?.map((f) => toFacetOutput(f, cfg.facetBucketCap));
161
+ ctx.enrich.total(result.total);
162
+ if (input.query)
163
+ ctx.enrich.echo(input.query);
164
+ if (hits.length === 0) {
165
+ ctx.enrich.notice(input.content_type === 'predicted'
166
+ ? 'No predicted models matched. Predicted search covers computed models indexed by RCSB; try content_type "all".'
167
+ : 'No structures matched. Broaden the query, drop filters, or switch content_type.');
168
+ }
169
+ return { hits, ...(facets ? { facets } : {}) };
170
+ },
171
+ format: (result) => {
172
+ const lines = [`## Structure search — ${result.hits.length} hits`];
173
+ for (const h of result.hits) {
174
+ lines.push(`\n### ${h.id} _(${h.source})_`);
175
+ if (h.title)
176
+ lines.push(h.title);
177
+ const meta = [
178
+ h.method ? `**Method:** ${h.method}` : null,
179
+ typeof h.resolution === 'number' ? `**Resolution:** ${h.resolution} Å` : null,
180
+ h.organism ? `**Organism:** ${h.organism}` : null,
181
+ h.uniprotAccession ? `**UniProt:** ${h.uniprotAccession}` : null,
182
+ typeof h.score === 'number' ? `**Score:** ${h.score.toFixed(3)}` : null,
183
+ ].filter(Boolean);
184
+ if (meta.length > 0)
185
+ lines.push(meta.join(' | '));
186
+ }
187
+ if (result.facets && result.facets.length > 0) {
188
+ lines.push('\n## Facets');
189
+ lines.push(...renderFacets(result.facets));
190
+ }
191
+ return [{ type: 'text', text: lines.join('\n') }];
192
+ },
193
+ });
194
+ /** Build one output hit, folding in enrichment metadata when available. */
195
+ function toHit(hit, metaById) {
196
+ if (isPredictedId(hit.id)) {
197
+ const accession = accessionFromCsm(hit.id);
198
+ return {
199
+ id: hit.id,
200
+ source: 'predicted',
201
+ score: hit.score,
202
+ ...(accession ? { uniprotAccession: accession } : {}),
203
+ };
204
+ }
205
+ const meta = metaById.get(entryIdOf(hit.id));
206
+ return {
207
+ id: hit.id,
208
+ source: 'experimental',
209
+ score: hit.score,
210
+ ...(meta?.title ? { title: meta.title } : {}),
211
+ ...(meta?.methods && meta.methods.length > 0 ? { method: meta.methods.join(', ') } : {}),
212
+ ...(typeof meta?.resolution === 'number' ? { resolution: meta.resolution } : {}),
213
+ ...(meta?.organisms && meta.organisms.length > 0 ? { organism: meta.organisms[0] } : {}),
214
+ };
215
+ }
216
+ //# sourceMappingURL=search-structures.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-structures.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-structures.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @fileoverview protein_track_ligands — ligand discovery and binding-site
3
+ * analysis. Resolves a ligand name/formula to chemical component IDs, finds PDB
4
+ * entries bound to a ligand, or returns the protein residues lining a ligand's
5
+ * pocket in a structure (via RCSB `rcsb_target_neighbors`).
6
+ * @module mcp-server/tools/definitions/track-ligands.tool
7
+ */
8
+ import { z } from '@cyanheads/mcp-ts-core';
9
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
10
+ export declare const trackLigands: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
11
+ mode: z.ZodEnum<{
12
+ find_ligand: "find_ligand";
13
+ structures_with_ligand: "structures_with_ligand";
14
+ binding_site: "binding_site";
15
+ }>;
16
+ query: z.ZodOptional<z.ZodString>;
17
+ comp_id: z.ZodOptional<z.ZodString>;
18
+ pdb_id: z.ZodOptional<z.ZodString>;
19
+ limit: z.ZodDefault<z.ZodNumber>;
20
+ }, z.core.$strip>, z.ZodObject<{
21
+ mode: z.ZodEnum<{
22
+ find_ligand: "find_ligand";
23
+ structures_with_ligand: "structures_with_ligand";
24
+ binding_site: "binding_site";
25
+ }>;
26
+ ligands: z.ZodOptional<z.ZodArray<z.ZodObject<{
27
+ compId: z.ZodString;
28
+ name: z.ZodOptional<z.ZodString>;
29
+ formula: z.ZodOptional<z.ZodString>;
30
+ formulaWeight: z.ZodOptional<z.ZodNumber>;
31
+ smiles: z.ZodOptional<z.ZodString>;
32
+ inchikey: z.ZodOptional<z.ZodString>;
33
+ type: z.ZodOptional<z.ZodString>;
34
+ }, z.core.$strip>>>;
35
+ structures: z.ZodOptional<z.ZodArray<z.ZodObject<{
36
+ id: z.ZodString;
37
+ score: z.ZodOptional<z.ZodNumber>;
38
+ }, z.core.$strip>>>;
39
+ bindingSites: z.ZodOptional<z.ZodArray<z.ZodObject<{
40
+ ligandCompId: z.ZodString;
41
+ ligandAsymId: z.ZodOptional<z.ZodString>;
42
+ residues: z.ZodArray<z.ZodObject<{
43
+ residueCompId: z.ZodString;
44
+ asymId: z.ZodString;
45
+ seqId: z.ZodOptional<z.ZodNumber>;
46
+ distance: z.ZodOptional<z.ZodNumber>;
47
+ }, z.core.$strip>>;
48
+ }, z.core.$strip>>>;
49
+ }, z.core.$strip>, readonly [{
50
+ readonly reason: "not_found";
51
+ readonly code: JsonRpcErrorCode.NotFound;
52
+ readonly when: "No chemical component matched the name/formula, no structures contain the component, or the structure has no instance of the ligand.";
53
+ readonly recovery: "Use mode \"find_ligand\" to resolve a name to a component ID first, then confirm the ligand is present in the structure via protein_get_structure.";
54
+ }], {
55
+ readonly totalCount: z.ZodOptional<z.ZodNumber>;
56
+ readonly resolvedCompId: z.ZodOptional<z.ZodString>;
57
+ readonly notice: z.ZodOptional<z.ZodString>;
58
+ }>;
59
+ //# sourceMappingURL=track-ligands.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track-ligands.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/track-ligands.tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAqCjE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0KvB,CAAC"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @fileoverview protein_track_ligands — ligand discovery and binding-site
3
+ * analysis. Resolves a ligand name/formula to chemical component IDs, finds PDB
4
+ * entries bound to a ligand, or returns the protein residues lining a ligand's
5
+ * pocket in a structure (via RCSB `rcsb_target_neighbors`).
6
+ * @module mcp-server/tools/definitions/track-ligands.tool
7
+ */
8
+ import { tool, z } from '@cyanheads/mcp-ts-core';
9
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
10
+ import { getServerConfig } from '../../../config/server-config.js';
11
+ import { getRcsbService } from '../../../services/rcsb/rcsb-service.js';
12
+ import { mapWithConcurrency } from '../../../services/shared/async.js';
13
+ const chemCompSchema = z
14
+ .object({
15
+ compId: z.string().describe('Chemical component ID (e.g. STI, HEM).'),
16
+ name: z.string().optional().describe('Chemical name.'),
17
+ formula: z.string().optional().describe('Molecular formula.'),
18
+ formulaWeight: z.number().optional().describe('Formula weight in Da.'),
19
+ smiles: z.string().optional().describe('Isomeric SMILES.'),
20
+ inchikey: z.string().optional().describe('InChIKey.'),
21
+ type: z.string().optional().describe('Component type (e.g. non-polymer).'),
22
+ })
23
+ .describe('A resolved chemical component (ligand) and its identifiers.');
24
+ const bindingSiteSchema = z
25
+ .object({
26
+ ligandCompId: z.string().describe('Bound ligand chemical component ID.'),
27
+ ligandAsymId: z.string().optional().describe('Ligand instance chain (asym) ID.'),
28
+ residues: z
29
+ .array(z
30
+ .object({
31
+ residueCompId: z.string().describe('Interacting residue type (e.g. ASP).'),
32
+ asymId: z.string().describe('Chain ID the residue belongs to.'),
33
+ seqId: z.number().optional().describe('Residue sequence position.'),
34
+ distance: z.number().optional().describe('Contact distance to the ligand in Å.'),
35
+ })
36
+ .describe('A pocket residue in contact with the ligand.'))
37
+ .describe('Protein residues lining the pocket, nearest first.'),
38
+ })
39
+ .describe('A ligand instance and the protein residues lining its pocket.');
40
+ export const trackLigands = tool('protein_track_ligands', {
41
+ title: 'protein-mcp-server: track ligands',
42
+ description: 'Ligand discovery and binding-site analysis across the PDB. mode "find_ligand" resolves a name or ' +
43
+ 'formula to chemical component IDs with metadata (formula, weight, SMILES). mode ' +
44
+ '"structures_with_ligand" returns PDB entries containing a ligand (by exact component ID — get the ' +
45
+ 'ID from find_ligand first). mode "binding_site" returns the protein residues lining a ligand\'s ' +
46
+ 'pocket in a given structure, with contact distances. Binding sites are experimental-only ' +
47
+ '(computed from deposited coordinates; predicted models carry no bound ligands).',
48
+ annotations: { readOnlyHint: true, openWorldHint: true },
49
+ errors: [
50
+ {
51
+ reason: 'not_found',
52
+ code: JsonRpcErrorCode.NotFound,
53
+ when: 'No chemical component matched the name/formula, no structures contain the component, or the structure has no instance of the ligand.',
54
+ recovery: 'Use mode "find_ligand" to resolve a name to a component ID first, then confirm the ligand is present in the structure via protein_get_structure.',
55
+ },
56
+ ],
57
+ input: z.object({
58
+ mode: z
59
+ .enum(['find_ligand', 'structures_with_ligand', 'binding_site'])
60
+ .describe('Operation: resolve a ligand, find structures containing it, or analyze its binding site.'),
61
+ query: z.string().optional().describe('Ligand name or formula (mode find_ligand).'),
62
+ comp_id: z
63
+ .string()
64
+ .optional()
65
+ .describe('Exact chemical component ID (modes structures_with_ligand and binding_site).'),
66
+ pdb_id: z.string().optional().describe('PDB entry ID (mode binding_site).'),
67
+ limit: z
68
+ .number()
69
+ .int()
70
+ .min(1)
71
+ .max(100)
72
+ .default(25)
73
+ .describe('Maximum results to return (1–100).'),
74
+ }),
75
+ output: z.object({
76
+ mode: z
77
+ .enum(['find_ligand', 'structures_with_ligand', 'binding_site'])
78
+ .describe('Echoed mode.'),
79
+ ligands: z
80
+ .array(chemCompSchema)
81
+ .optional()
82
+ .describe('Resolved chemical components (find_ligand).'),
83
+ structures: z
84
+ .array(z
85
+ .object({
86
+ id: z.string().describe('PDB entry ID containing the ligand.'),
87
+ score: z.number().optional().describe('RCSB relevance score.'),
88
+ })
89
+ .describe('A PDB entry containing the ligand.'))
90
+ .optional()
91
+ .describe('PDB entries containing the ligand (structures_with_ligand).'),
92
+ bindingSites: z
93
+ .array(bindingSiteSchema)
94
+ .optional()
95
+ .describe('Binding-site residues (binding_site).'),
96
+ }),
97
+ enrichment: {
98
+ totalCount: z
99
+ .number()
100
+ .optional()
101
+ .describe('Total upstream matches before pagination (structures_with_ligand).'),
102
+ resolvedCompId: z.string().optional().describe('The chemical component ID used to query.'),
103
+ notice: z
104
+ .string()
105
+ .optional()
106
+ .describe('Advisory note when a mode-specific input is missing or absent.'),
107
+ },
108
+ async handler(input, ctx) {
109
+ const rcsb = getRcsbService();
110
+ const cfg = getServerConfig();
111
+ if (input.mode === 'find_ligand') {
112
+ if (!input.query)
113
+ throw ctx.fail('not_found', 'mode find_ligand requires a name or formula in "query".');
114
+ const ids = await rcsb.findChemComps(input.query, input.limit, ctx);
115
+ const ligands = (await mapWithConcurrency(ids, cfg.fanoutConcurrency, (id) => rcsb.getChemComp(id, ctx))).filter((c) => c != null);
116
+ if (ligands.length === 0) {
117
+ throw ctx.fail('not_found', `No chemical component matched "${input.query}".`, {
118
+ recovery: {
119
+ hint: `No ligand matched "${input.query}". Try the exact name, a synonym, or a formula.`,
120
+ },
121
+ });
122
+ }
123
+ return { mode: input.mode, ligands };
124
+ }
125
+ if (input.mode === 'structures_with_ligand') {
126
+ const compId = input.comp_id?.toUpperCase();
127
+ if (!compId)
128
+ throw ctx.fail('not_found', 'mode structures_with_ligand requires a "comp_id".');
129
+ const result = await rcsb.searchByLigand(compId, { limit: input.limit }, ctx);
130
+ if (result.hits.length === 0) {
131
+ throw ctx.fail('not_found', `No structures contain ligand ${compId}.`, {
132
+ recovery: {
133
+ hint: `No PDB entries contain ${compId}. Verify the component ID via mode find_ligand.`,
134
+ },
135
+ });
136
+ }
137
+ ctx.enrich.total(result.total);
138
+ ctx.enrich({ resolvedCompId: compId });
139
+ return {
140
+ mode: input.mode,
141
+ structures: result.hits.map((h) => ({ id: h.id, score: h.score })),
142
+ };
143
+ }
144
+ // binding_site
145
+ const compId = input.comp_id?.toUpperCase();
146
+ if (!input.pdb_id)
147
+ throw ctx.fail('not_found', 'mode binding_site requires a "pdb_id".');
148
+ const sites = await rcsb.getBindingSites(input.pdb_id, compId, ctx);
149
+ if (sites.length === 0) {
150
+ throw ctx.fail('not_found', `No binding-site contacts found in ${input.pdb_id.toUpperCase()}${compId ? ` for ligand ${compId}` : ''}.`, {
151
+ recovery: {
152
+ hint: `Confirm ${input.pdb_id.toUpperCase()} contains${compId ? ` ${compId}` : ' a ligand'} via protein_get_structure; binding sites are experimental-only.`,
153
+ },
154
+ });
155
+ }
156
+ if (compId)
157
+ ctx.enrich({ resolvedCompId: compId });
158
+ return { mode: input.mode, bindingSites: sites };
159
+ },
160
+ format: (result) => {
161
+ const lines = [`## protein_track_ligands — ${result.mode}`];
162
+ for (const l of result.ligands ?? []) {
163
+ lines.push(`\n### ${l.compId}${l.name ? ` — ${l.name}` : ''}`);
164
+ const parts = [
165
+ l.formula ? `**Formula:** ${l.formula}` : null,
166
+ typeof l.formulaWeight === 'number' ? `**Weight:** ${l.formulaWeight} Da` : null,
167
+ l.type ? `**Type:** ${l.type}` : null,
168
+ ].filter(Boolean);
169
+ if (parts.length > 0)
170
+ lines.push(parts.join(' | '));
171
+ if (l.smiles)
172
+ lines.push(`**SMILES:** ${l.smiles}`);
173
+ if (l.inchikey)
174
+ lines.push(`**InChIKey:** ${l.inchikey}`);
175
+ }
176
+ if (result.structures) {
177
+ lines.push(`\n**${result.structures.length} structures:**`);
178
+ lines.push(result.structures.map((s) => s.id).join(', '));
179
+ for (const s of result.structures) {
180
+ if (typeof s.score === 'number')
181
+ lines.push(`- ${s.id} (score ${s.score.toFixed(2)})`);
182
+ }
183
+ }
184
+ for (const site of result.bindingSites ?? []) {
185
+ lines.push(`\n### Ligand ${site.ligandCompId}${site.ligandAsymId ? ` (chain ${site.ligandAsymId})` : ''}`);
186
+ for (const r of site.residues) {
187
+ const pos = r.seqId != null ? `${r.residueCompId}${r.seqId}` : r.residueCompId;
188
+ const dist = r.distance != null ? ` — ${r.distance.toFixed(2)} Å` : '';
189
+ lines.push(`- ${pos} (chain ${r.asymId})${dist}`);
190
+ }
191
+ }
192
+ return [{ type: 'text', text: lines.join('\n') }];
193
+ },
194
+ });
195
+ //# sourceMappingURL=track-ligands.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track-ligands.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/track-ligands.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview RCSB Structural Comparison (alignment) service — wraps the hosted
3
+ * async pairwise alignment API (`/api/v1/structures/submit` → `/results?uuid=`).
4
+ * Native mode is `pairwise`; multi-structure comparison fans these out. Submit
5
+ * returns a bare UUID; the results poll returns 404 until the job is computed.
6
+ * Backs `protein_compare_structures`. No in-process alignment — edge-deployable.
7
+ * @module services/alignment/alignment-service
8
+ */
9
+ import type { Context } from '@cyanheads/mcp-ts-core';
10
+ import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
11
+ import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
12
+ import type { ServerConfig } from '../../config/server-config.js';
13
+ /** Alignment method name accepted by the RCSB Structural Comparison API. */
14
+ export type AlignmentMethod = 'tm-align' | 'fatcat-rigid' | 'fatcat-flexible';
15
+ /** One structure (+ optional chain) in a comparison. */
16
+ export interface CompareStructure {
17
+ asymId?: string;
18
+ entryId: string;
19
+ }
20
+ /** Scores for one aligned pair. */
21
+ export interface PairScores {
22
+ alignedResidues?: number;
23
+ rmsd?: number;
24
+ sequenceIdentity?: number;
25
+ tmScore?: number;
26
+ }
27
+ /** Outcome of one pairwise alignment. */
28
+ export type PairOutcome = {
29
+ status: 'complete';
30
+ uuid: string;
31
+ scores: PairScores;
32
+ } | {
33
+ status: 'computing';
34
+ uuid: string;
35
+ } | {
36
+ status: 'failed';
37
+ error: string;
38
+ };
39
+ export declare class AlignmentService {
40
+ private readonly submitUrl;
41
+ private readonly resultsUrl;
42
+ constructor(_config: AppConfig, _storage: StorageService, serverConfig: ServerConfig);
43
+ /** Submit a pairwise alignment job; returns the job UUID. */
44
+ submit(a: CompareStructure, b: CompareStructure, method: AlignmentMethod, ctx: Context): Promise<string>;
45
+ /**
46
+ * Run one pairwise alignment end-to-end: submit, then bounded-poll the result.
47
+ * Never throws — a submit/poll failure degrades to `{ status: 'failed' }` so
48
+ * one bad pair doesn't sink the whole comparison.
49
+ */
50
+ comparePair(a: CompareStructure, b: CompareStructure, method: AlignmentMethod, timeoutMs: number, ctx: Context): Promise<PairOutcome>;
51
+ /** Single poll of a job's results. 404 = still computing; a result body = ready. */
52
+ private pollResult;
53
+ }
54
+ export declare function initAlignmentService(config: AppConfig, storage: StorageService, serverConfig: ServerConfig): void;
55
+ export declare function getAlignmentService(): AlignmentService;
56
+ //# sourceMappingURL=alignment-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alignment-service.d.ts","sourceRoot":"","sources":["../../../src/services/alignment/alignment-service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI9D,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE9E,wDAAwD;AACxD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,yCAAyC;AACzC,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GACxD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY;IAKpF,6DAA6D;IACvD,MAAM,CACV,CAAC,EAAE,gBAAgB,EACnB,CAAC,EAAE,gBAAgB,EACnB,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;OAIG;IACG,WAAW,CACf,CAAC,EAAE,gBAAgB,EACnB,CAAC,EAAE,gBAAgB,EACnB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,WAAW,CAAC;IAuBvB,oFAAoF;YACtE,UAAU;CAazB;AAmDD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,YAAY,GACzB,IAAI,CAEN;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,CAItD"}