omophub-mcp 1.0.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +265 -0
  3. package/dist/client/api.d.ts +10 -0
  4. package/dist/client/api.d.ts.map +1 -0
  5. package/dist/client/api.js +168 -0
  6. package/dist/client/api.js.map +1 -0
  7. package/dist/client/types.d.ts +86 -0
  8. package/dist/client/types.d.ts.map +1 -0
  9. package/dist/client/types.js +2 -0
  10. package/dist/client/types.js.map +1 -0
  11. package/dist/formatters/index.d.ts +26 -0
  12. package/dist/formatters/index.d.ts.map +1 -0
  13. package/dist/formatters/index.js +197 -0
  14. package/dist/formatters/index.js.map +1 -0
  15. package/dist/health.d.ts +3 -0
  16. package/dist/health.d.ts.map +1 -0
  17. package/dist/health.js +34 -0
  18. package/dist/health.js.map +1 -0
  19. package/dist/index.d.ts +9 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +75 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/prompts/index.d.ts +3 -0
  24. package/dist/prompts/index.d.ts.map +1 -0
  25. package/dist/prompts/index.js +56 -0
  26. package/dist/prompts/index.js.map +1 -0
  27. package/dist/resources/index.d.ts +4 -0
  28. package/dist/resources/index.d.ts.map +1 -0
  29. package/dist/resources/index.js +86 -0
  30. package/dist/resources/index.js.map +1 -0
  31. package/dist/server.d.ts +3 -0
  32. package/dist/server.d.ts.map +1 -0
  33. package/dist/server.js +31 -0
  34. package/dist/server.js.map +1 -0
  35. package/dist/tools/concepts.d.ts +4 -0
  36. package/dist/tools/concepts.d.ts.map +1 -0
  37. package/dist/tools/concepts.js +89 -0
  38. package/dist/tools/concepts.js.map +1 -0
  39. package/dist/tools/hierarchy.d.ts +4 -0
  40. package/dist/tools/hierarchy.d.ts.map +1 -0
  41. package/dist/tools/hierarchy.js +98 -0
  42. package/dist/tools/hierarchy.js.map +1 -0
  43. package/dist/tools/index.d.ts +6 -0
  44. package/dist/tools/index.d.ts.map +1 -0
  45. package/dist/tools/index.js +6 -0
  46. package/dist/tools/index.js.map +1 -0
  47. package/dist/tools/mappings.d.ts +4 -0
  48. package/dist/tools/mappings.d.ts.map +1 -0
  49. package/dist/tools/mappings.js +39 -0
  50. package/dist/tools/mappings.js.map +1 -0
  51. package/dist/tools/search.d.ts +4 -0
  52. package/dist/tools/search.d.ts.map +1 -0
  53. package/dist/tools/search.js +68 -0
  54. package/dist/tools/search.js.map +1 -0
  55. package/dist/tools/vocabularies.d.ts +4 -0
  56. package/dist/tools/vocabularies.d.ts.map +1 -0
  57. package/dist/tools/vocabularies.js +45 -0
  58. package/dist/tools/vocabularies.js.map +1 -0
  59. package/dist/utils/auth.d.ts +2 -0
  60. package/dist/utils/auth.d.ts.map +1 -0
  61. package/dist/utils/auth.js +9 -0
  62. package/dist/utils/auth.js.map +1 -0
  63. package/dist/utils/cache.d.ts +15 -0
  64. package/dist/utils/cache.d.ts.map +1 -0
  65. package/dist/utils/cache.js +52 -0
  66. package/dist/utils/cache.js.map +1 -0
  67. package/dist/utils/errors.d.ts +10 -0
  68. package/dist/utils/errors.d.ts.map +1 -0
  69. package/dist/utils/errors.js +95 -0
  70. package/dist/utils/errors.js.map +1 -0
  71. package/dist/utils/logger.d.ts +18 -0
  72. package/dist/utils/logger.d.ts.map +1 -0
  73. package/dist/utils/logger.js +24 -0
  74. package/dist/utils/logger.js.map +1 -0
  75. package/dist/version.d.ts +2 -0
  76. package/dist/version.d.ts.map +1 -0
  77. package/dist/version.js +5 -0
  78. package/dist/version.js.map +1 -0
  79. package/package.json +70 -0
@@ -0,0 +1,197 @@
1
+ function conceptLine(c, index) {
2
+ const prefix = index !== undefined ? `${index + 1}. ` : '';
3
+ const std = c.standard_concept === 'S'
4
+ ? ' [Standard]'
5
+ : c.standard_concept === 'C'
6
+ ? ' [Classification]'
7
+ : '';
8
+ return `${prefix}**${c.concept_name}** (ID: ${c.concept_id})\n ${c.vocabulary_id} | ${c.domain_id} | Code: ${c.concept_code}${std}`;
9
+ }
10
+ export function formatConceptList(response, query) {
11
+ const results = response.data;
12
+ const pagination = response.meta?.pagination;
13
+ const total = pagination?.total_items ?? results.length;
14
+ const page = pagination?.page ?? 1;
15
+ const totalPages = pagination?.total_pages ?? 1;
16
+ if (results.length === 0) {
17
+ return {
18
+ text: `No concepts found for "${query}". Try broader search terms or different vocabulary filters.`,
19
+ json: JSON.stringify({ results: [], total, page, total_pages: totalPages, query }),
20
+ };
21
+ }
22
+ const lines = results.map((r, i) => conceptLine(r, i));
23
+ const header = `Found ${total} concept${total !== 1 ? 's' : ''} for "${query}" (showing page ${page} of ${totalPages}):`;
24
+ let text = `${header}\n\n${lines.join('\n\n')}`;
25
+ if (pagination?.has_next) {
26
+ text += `\n\n→ Use page=${page + 1} to see more results.`;
27
+ }
28
+ return {
29
+ text,
30
+ json: JSON.stringify({
31
+ results: results.map((r) => ({
32
+ concept_id: r.concept_id,
33
+ concept_name: r.concept_name,
34
+ vocabulary_id: r.vocabulary_id,
35
+ domain_id: r.domain_id,
36
+ concept_code: r.concept_code,
37
+ concept_class_id: r.concept_class_id,
38
+ standard_concept: r.standard_concept,
39
+ })),
40
+ total,
41
+ page,
42
+ total_pages: totalPages,
43
+ query,
44
+ }),
45
+ };
46
+ }
47
+ export function formatConcept(concept) {
48
+ const std = concept.standard_concept === 'S'
49
+ ? 'Standard'
50
+ : concept.standard_concept === 'C'
51
+ ? 'Classification'
52
+ : 'Non-standard';
53
+ const lines = [
54
+ `**${concept.concept_name}**`,
55
+ '',
56
+ `| Field | Value |`,
57
+ `|-------|-------|`,
58
+ `| Concept ID | ${concept.concept_id} |`,
59
+ `| Vocabulary | ${concept.vocabulary_id} |`,
60
+ `| Domain | ${concept.domain_id} |`,
61
+ `| Concept Class | ${concept.concept_class_id} |`,
62
+ `| Concept Code | ${concept.concept_code} |`,
63
+ `| Standard Status | ${std} |`,
64
+ ];
65
+ if (concept.valid_start_date)
66
+ lines.push(`| Valid From | ${concept.valid_start_date} |`);
67
+ if (concept.valid_end_date)
68
+ lines.push(`| Valid To | ${concept.valid_end_date} |`);
69
+ if (concept.invalid_reason)
70
+ lines.push(`| Invalid Reason | ${concept.invalid_reason} |`);
71
+ if (concept.synonyms && concept.synonyms.length > 0) {
72
+ lines.push(`| Synonyms | ${concept.synonyms.join(', ')} |`);
73
+ }
74
+ return {
75
+ text: lines.join('\n'),
76
+ json: JSON.stringify(concept),
77
+ };
78
+ }
79
+ export function formatMappings(response, conceptId) {
80
+ const data = response.data;
81
+ const mappings = data.mappings;
82
+ if (!mappings || mappings.length === 0) {
83
+ return {
84
+ text: `No mappings found for concept ${conceptId} (${data.source_concept?.concept_name || 'unknown'}).`,
85
+ json: JSON.stringify({
86
+ source_concept_id: conceptId,
87
+ source_concept_name: data.source_concept?.concept_name,
88
+ mapped: false,
89
+ mappings: [],
90
+ }),
91
+ };
92
+ }
93
+ const source = data.source_concept;
94
+ const header = `Mappings for **${source?.concept_name || `Concept ${conceptId}`}** (${source?.vocabulary_id || 'unknown'} → targets):`;
95
+ const lines = mappings.map((m, i) => `${i + 1}. **${m.concept_name}** (ID: ${m.concept_id})\n ${m.vocabulary_id} | Code: ${m.concept_code} | Relationship: ${m.relationship_id}`);
96
+ return {
97
+ text: `${header}\n\n${lines.join('\n\n')}`,
98
+ json: JSON.stringify({
99
+ source_concept_id: conceptId,
100
+ source_concept_name: source?.concept_name,
101
+ mapped: true,
102
+ total_mappings: data.total_mappings ?? mappings.length,
103
+ mappings: mappings.map((m) => ({
104
+ concept_id: m.concept_id,
105
+ concept_name: m.concept_name,
106
+ vocabulary_id: m.vocabulary_id,
107
+ concept_code: m.concept_code,
108
+ relationship_id: m.relationship_id,
109
+ standard_concept: m.standard_concept,
110
+ })),
111
+ }),
112
+ };
113
+ }
114
+ export function formatHierarchy(response, direction) {
115
+ const data = response.data;
116
+ const concept = data.concept;
117
+ const sections = [
118
+ `Hierarchy for **${concept.concept_name}** (ID: ${concept.concept_id}, ${concept.vocabulary_id}):`,
119
+ ];
120
+ const formatNodes = (nodes, label) => {
121
+ if (!nodes || nodes.length === 0)
122
+ return `\n**${label}:** None`;
123
+ const lines = nodes.map((n, i) => `${i + 1}. ${' '.repeat(Math.max(0, n.level ?? 0))}${n.concept_name} (ID: ${n.concept_id}, ${n.vocabulary_id})`);
124
+ return `\n**${label}** (${nodes.length}):\n${lines.join('\n')}`;
125
+ };
126
+ if (direction === 'up' || direction === 'both') {
127
+ sections.push(formatNodes(data.ancestors || [], 'Ancestors (broader terms)'));
128
+ }
129
+ if (direction === 'down' || direction === 'both') {
130
+ sections.push(formatNodes(data.descendants || [], 'Descendants (narrower terms)'));
131
+ }
132
+ const jsonData = {
133
+ concept_id: concept.concept_id,
134
+ concept_name: concept.concept_name,
135
+ vocabulary_id: concept.vocabulary_id,
136
+ direction,
137
+ };
138
+ if (direction === 'up' || direction === 'both') {
139
+ jsonData.ancestors = (data.ancestors || []).map((n) => ({
140
+ concept_id: n.concept_id,
141
+ concept_name: n.concept_name,
142
+ vocabulary_id: n.vocabulary_id,
143
+ level: n.level,
144
+ }));
145
+ jsonData.total_ancestors = data.total_ancestors ?? (data.ancestors || []).length;
146
+ }
147
+ if (direction === 'down' || direction === 'both') {
148
+ jsonData.descendants = (data.descendants || []).map((n) => ({
149
+ concept_id: n.concept_id,
150
+ concept_name: n.concept_name,
151
+ vocabulary_id: n.vocabulary_id,
152
+ level: n.level,
153
+ }));
154
+ jsonData.total_descendants = data.total_descendants ?? (data.descendants || []).length;
155
+ }
156
+ return {
157
+ text: sections.join('\n'),
158
+ json: JSON.stringify(jsonData),
159
+ };
160
+ }
161
+ export function formatVocabularyList(response, search) {
162
+ let vocabs = response.data;
163
+ if (search) {
164
+ const term = search.toLowerCase();
165
+ vocabs = vocabs.filter((v) => v.vocabulary_id.toLowerCase().includes(term) ||
166
+ v.vocabulary_name.toLowerCase().includes(term));
167
+ }
168
+ if (vocabs.length === 0) {
169
+ return {
170
+ text: search ? `No vocabularies found matching "${search}".` : 'No vocabularies available.',
171
+ json: JSON.stringify({ vocabularies: [], total: 0 }),
172
+ };
173
+ }
174
+ const lines = vocabs.map((v, i) => `${i + 1}. **${v.vocabulary_id}** — ${v.vocabulary_name}${v.concept_count != null ? ` (${v.concept_count.toLocaleString()} concepts)` : ''}${v.vocabulary_version ? ` [v${v.vocabulary_version}]` : ''}`);
175
+ const header = search
176
+ ? `Found ${vocabs.length} vocabularies matching "${search}":`
177
+ : `Available vocabularies (${vocabs.length}):`;
178
+ return {
179
+ text: `${header}\n\n${lines.join('\n')}`,
180
+ json: JSON.stringify({
181
+ vocabularies: vocabs.map((v) => ({
182
+ vocabulary_id: v.vocabulary_id,
183
+ vocabulary_name: v.vocabulary_name,
184
+ vocabulary_version: v.vocabulary_version,
185
+ concept_count: v.concept_count,
186
+ })),
187
+ total: vocabs.length,
188
+ }),
189
+ };
190
+ }
191
+ export function formatError(error) {
192
+ return {
193
+ text: error,
194
+ json: JSON.stringify({ error: true, message: error }),
195
+ };
196
+ }
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { createServer } from 'node:http';
2
+ export declare function startHealthServer(port: number): ReturnType<typeof createServer>;
3
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AA4BpF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAY/E"}
package/dist/health.js ADDED
@@ -0,0 +1,34 @@
1
+ import { createServer } from 'node:http';
2
+ import { logger } from './utils/logger.js';
3
+ import { VERSION } from './version.js';
4
+ const startTime = Date.now();
5
+ function handleRequest(req, res) {
6
+ if (req.method === 'GET' && req.url === '/health') {
7
+ const body = JSON.stringify({
8
+ status: 'ok',
9
+ version: VERSION,
10
+ uptime_seconds: Math.floor((Date.now() - startTime) / 1000),
11
+ });
12
+ res.writeHead(200, {
13
+ 'Content-Type': 'application/json',
14
+ 'Content-Length': Buffer.byteLength(body),
15
+ 'X-Content-Type-Options': 'nosniff',
16
+ 'Cache-Control': 'no-store',
17
+ });
18
+ res.end(body);
19
+ return;
20
+ }
21
+ res.writeHead(404, { 'Content-Type': 'application/json' });
22
+ res.end(JSON.stringify({ error: 'Not found' }));
23
+ }
24
+ export function startHealthServer(port) {
25
+ const server = createServer(handleRequest);
26
+ server.on('error', (err) => {
27
+ logger.error('Health server error', { error: String(err), port });
28
+ });
29
+ server.listen(port, () => {
30
+ logger.info(`Health endpoint listening on http://localhost:${String(port)}/health`);
31
+ });
32
+ return server;
33
+ }
34
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE7B,SAAS,aAAa,CAAC,GAAoB,EAAE,GAAmB;IAC9D,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,OAAO;YAChB,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;SAC5D,CAAC,CAAC;QAEH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,kBAAkB;YAClC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YACzC,wBAAwB,EAAE,SAAS;YACnC,eAAe,EAAE,UAAU;SAC5B,CAAC,CAAC;QACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACd,OAAO;IACT,CAAC;IAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAE3C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACzB,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACvB,MAAM,CAAC,IAAI,CAAC,iDAAiD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ export declare function parseArgs(argv: string[]): {
3
+ apiKey?: string;
4
+ baseUrl?: string;
5
+ healthPort?: number;
6
+ };
7
+ export declare function resolveHealthPort(cliPort?: number): number | undefined;
8
+ export declare function main(): Promise<void>;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAUA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAiBA;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYtE;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAsB1C"}
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from 'node:fs';
3
+ import url from 'node:url';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { startHealthServer } from './health.js';
6
+ import { createServer } from './server.js';
7
+ import { resolveApiKey } from './utils/auth.js';
8
+ import { logger } from './utils/logger.js';
9
+ export function parseArgs(argv) {
10
+ const result = {};
11
+ for (const arg of argv.slice(2)) {
12
+ if (arg.startsWith('--api-key=')) {
13
+ result.apiKey = arg.slice('--api-key='.length);
14
+ }
15
+ else if (arg.startsWith('--base-url=')) {
16
+ result.baseUrl = arg.slice('--base-url='.length);
17
+ }
18
+ else if (arg.startsWith('--health-port=')) {
19
+ const port = parseInt(arg.slice('--health-port='.length), 10);
20
+ if (!Number.isNaN(port) && port > 0 && port < 65536) {
21
+ result.healthPort = port;
22
+ }
23
+ }
24
+ }
25
+ return result;
26
+ }
27
+ export function resolveHealthPort(cliPort) {
28
+ if (cliPort !== undefined)
29
+ return cliPort;
30
+ const envPort = process.env.HEALTH_PORT;
31
+ if (envPort) {
32
+ const port = parseInt(envPort, 10);
33
+ if (!Number.isNaN(port) && port > 0 && port < 65536) {
34
+ return port;
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+ export async function main() {
40
+ const args = parseArgs(process.argv);
41
+ let apiKey;
42
+ try {
43
+ apiKey = resolveApiKey(args.apiKey);
44
+ }
45
+ catch (error) {
46
+ logger.error(error instanceof Error ? error.message : String(error));
47
+ process.exit(1);
48
+ }
49
+ const server = createServer(apiKey, args.baseUrl);
50
+ const transport = new StdioServerTransport();
51
+ logger.info('Starting OMOPHub MCP server (stdio transport)');
52
+ await server.connect(transport);
53
+ const healthPort = resolveHealthPort(args.healthPort);
54
+ if (healthPort !== undefined) {
55
+ startHealthServer(healthPort);
56
+ }
57
+ }
58
+ function isRunDirectly() {
59
+ if (!process.argv[1])
60
+ return false;
61
+ try {
62
+ return import.meta.url === url.pathToFileURL(realpathSync(process.argv[1])).href;
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ const isDirectRun = isRunDirectly();
69
+ if (isDirectRun) {
70
+ main().catch((error) => {
71
+ logger.error('Fatal error', { error: String(error) });
72
+ process.exit(1);
73
+ });
74
+ }
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerPrompts(server: McpServer): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqEvD"}
@@ -0,0 +1,56 @@
1
+ import { z } from 'zod';
2
+ export function registerPrompts(server) {
3
+ server.prompt('phenotype-concept-set', 'Build a concept set for a clinical phenotype definition. Guides the AI through searching for concepts, exploring hierarchies, and assembling a complete concept set.', {
4
+ condition: z
5
+ .string()
6
+ .describe('The clinical condition or phenotype to define (e.g., "Type 2 diabetes mellitus")'),
7
+ vocabularies: z
8
+ .string()
9
+ .optional()
10
+ .describe('Comma-separated vocabulary IDs to focus on (e.g., "SNOMED,ICD10CM"). Default: all'),
11
+ }, ({ condition, vocabularies }) => {
12
+ const vocabFilter = vocabularies ? ` Focus on these vocabularies: ${vocabularies}.` : '';
13
+ return {
14
+ messages: [
15
+ {
16
+ role: 'user',
17
+ content: {
18
+ type: 'text',
19
+ text: `Help me build a concept set for the clinical phenotype: "${condition}".${vocabFilter}
20
+
21
+ Please follow these steps:
22
+ 1. Use search_concepts to find the primary concept(s) for "${condition}"
23
+ 2. For the best-matching standard concept, use get_hierarchy with direction="down" to find all descendants
24
+ 3. Use map_concept to find cross-vocabulary mappings (especially SNOMED ↔ ICD-10-CM)
25
+ 4. Compile a final concept set table with: concept_id, concept_name, vocabulary_id, concept_code, and whether it's a primary concept or descendant
26
+
27
+ Present the final concept set in a clear table format that can be used in a cohort definition.`,
28
+ },
29
+ },
30
+ ],
31
+ };
32
+ });
33
+ server.prompt('code-lookup', 'Look up and validate a medical code. Resolves a vocabulary-specific code to its OMOP concept and shows mappings.', {
34
+ code: z.string().describe('The medical code to look up (e.g., "E11.9", "44054006", "4850")'),
35
+ vocabulary: z.string().describe('The vocabulary system (e.g., "ICD10CM", "SNOMED", "LOINC")'),
36
+ }, ({ code, vocabulary }) => {
37
+ return {
38
+ messages: [
39
+ {
40
+ role: 'user',
41
+ content: {
42
+ type: 'text',
43
+ text: `Look up and validate the medical code "${code}" from vocabulary "${vocabulary}".
44
+
45
+ Please:
46
+ 1. Use get_concept_by_code to resolve this code
47
+ 2. If found, use map_concept to show what it maps to in other vocabularies
48
+ 3. Use get_hierarchy with direction="up" to show where it sits in the hierarchy
49
+ 4. Summarize: Is this a standard concept? What are the key mappings? Any important notes about this code?`,
50
+ },
51
+ },
52
+ ],
53
+ };
54
+ });
55
+ }
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,MAAM,CACX,uBAAuB,EACvB,sKAAsK,EACtK;QACE,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,CACP,kFAAkF,CACnF;QACH,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,mFAAmF,CACpF;KACJ,EACD,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE;QAC9B,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,iCAAiC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAEzF,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,4DAA4D,SAAS,KAAK,WAAW;;;6DAG5C,SAAS;;;;;+FAKyB;qBAClF;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,aAAa,EACb,kHAAkH,EAClH;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;QAC5F,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;KAC9F,EACD,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,0CAA0C,IAAI,sBAAsB,UAAU;;;;;;0GAMQ;qBAC7F;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { OmopHubClient } from '../client/api.js';
3
+ export declare function registerResources(server: McpServer, client: OmopHubClient): void;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA2CtD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAoEhF"}
@@ -0,0 +1,86 @@
1
+ import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { vocabularyCache } from '../utils/cache.js';
3
+ const PAGE_SIZE = 100;
4
+ const CACHE_KEY = 'vocabularies:all';
5
+ async function fetchAllVocabularies(client, toolName) {
6
+ const all = [];
7
+ let page = 1;
8
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
9
+ while (true) {
10
+ const raw = await client.request('/vocabularies', { include_stats: true, page_size: PAGE_SIZE, page }, toolName);
11
+ const batch = raw.data.vocabularies;
12
+ all.push(...batch);
13
+ if (batch.length < PAGE_SIZE || !raw.meta?.pagination?.has_next)
14
+ break;
15
+ page++;
16
+ }
17
+ return all;
18
+ }
19
+ async function getCachedVocabularies(client, toolName) {
20
+ const cached = vocabularyCache.get(CACHE_KEY);
21
+ if (cached)
22
+ return cached.data;
23
+ const vocabs = await fetchAllVocabularies(client, toolName);
24
+ vocabularyCache.set(CACHE_KEY, { data: vocabs });
25
+ return vocabs;
26
+ }
27
+ export function registerResources(server, client) {
28
+ // Static resource: vocabulary catalog
29
+ server.resource('vocabulary-list', 'omophub://vocabularies', async (uri) => {
30
+ const vocabs = await getCachedVocabularies(client, 'resource:vocabulary-list');
31
+ const text = vocabs
32
+ .map((v) => `${v.vocabulary_id}: ${v.vocabulary_name}${v.concept_count != null ? ` (${v.concept_count.toLocaleString()} concepts)` : ''}`)
33
+ .join('\n');
34
+ return {
35
+ contents: [
36
+ {
37
+ uri: uri.href,
38
+ mimeType: 'text/plain',
39
+ text: `OMOP Vocabulary Catalog\n${'='.repeat(40)}\n\n${text}`,
40
+ },
41
+ ],
42
+ };
43
+ });
44
+ // Resource template: individual vocabulary details
45
+ const vocabularyTemplate = new ResourceTemplate('omophub://vocabularies/{vocabulary_id}', {
46
+ list: undefined,
47
+ });
48
+ server.resource('vocabulary-details', vocabularyTemplate, async (uri, variables) => {
49
+ const vocabularyId = String(variables.vocabulary_id);
50
+ const vocabs = await getCachedVocabularies(client, 'resource:vocabulary-details');
51
+ const vocab = vocabs.find((v) => v.vocabulary_id.toLowerCase() === vocabularyId.toLowerCase());
52
+ if (!vocab) {
53
+ return {
54
+ contents: [
55
+ {
56
+ uri: uri.href,
57
+ mimeType: 'text/plain',
58
+ text: `Vocabulary "${vocabularyId}" not found.`,
59
+ },
60
+ ],
61
+ };
62
+ }
63
+ const lines = [
64
+ `Vocabulary: ${vocab.vocabulary_id}`,
65
+ `Name: ${vocab.vocabulary_name}`,
66
+ vocab.vocabulary_version ? `Version: ${vocab.vocabulary_version}` : null,
67
+ vocab.vocabulary_reference ? `Reference: ${vocab.vocabulary_reference}` : null,
68
+ vocab.concept_count != null
69
+ ? `Total Concepts: ${vocab.concept_count.toLocaleString()}`
70
+ : null,
71
+ vocab.standard_concept_count != null
72
+ ? `Standard Concepts: ${vocab.standard_concept_count.toLocaleString()}`
73
+ : null,
74
+ ].filter(Boolean);
75
+ return {
76
+ contents: [
77
+ {
78
+ uri: uri.href,
79
+ mimeType: 'text/plain',
80
+ text: lines.join('\n'),
81
+ },
82
+ ],
83
+ };
84
+ });
85
+ }
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function createServer(apiKey: string, baseUrl?: string): McpServer;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CA4BxE"}
package/dist/server.js ADDED
@@ -0,0 +1,31 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { OmopHubClient } from './client/api.js';
3
+ import { registerPrompts } from './prompts/index.js';
4
+ import { registerResources } from './resources/index.js';
5
+ import { registerConceptTools, registerHierarchyTools, registerMappingTools, registerSearchTools, registerVocabularyTools, } from './tools/index.js';
6
+ import { logger } from './utils/logger.js';
7
+ import { VERSION } from './version.js';
8
+ export function createServer(apiKey, baseUrl) {
9
+ const server = new McpServer({
10
+ name: 'omophub',
11
+ version: VERSION,
12
+ description: 'Access OHDSI standardized medical vocabularies — search concepts, navigate hierarchies, and map between clinical coding systems like SNOMED CT, ICD-10, RxNorm, and LOINC.',
13
+ });
14
+ const client = new OmopHubClient(apiKey, baseUrl);
15
+ // Register all Phase 1 tools
16
+ registerSearchTools(server, client);
17
+ registerConceptTools(server, client);
18
+ registerMappingTools(server, client);
19
+ registerHierarchyTools(server, client);
20
+ registerVocabularyTools(server, client);
21
+ // Register resources and prompts
22
+ registerResources(server, client);
23
+ registerPrompts(server);
24
+ logger.info('OMOPHub MCP server initialized', {
25
+ tools: 6,
26
+ resources: 2,
27
+ prompts: 2,
28
+ });
29
+ return server;
30
+ }
31
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,OAAgB;IAC3D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;QAChB,WAAW,EACT,4KAA4K;KAC/K,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElD,6BAA6B;IAC7B,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,iCAAiC;IACjC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE;QAC5C,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;KACX,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { OmopHubClient } from '../client/api.js';
3
+ export declare function registerConceptTools(server: McpServer, client: OmopHubClient): void;
4
+ //# sourceMappingURL=concepts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concepts.d.ts","sourceRoot":"","sources":["../../src/tools/concepts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAiHnF"}