@omophub/omophub-mcp 1.3.0 → 1.4.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.
- package/README.md +12 -4
- package/dist/client/resolve.js +1 -1
- package/dist/client/resolve.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +4 -5
- package/dist/server.js.map +1 -1
- package/dist/tools/fhir.d.ts +4 -0
- package/dist/tools/fhir.d.ts.map +1 -0
- package/dist/tools/fhir.js +147 -0
- package/dist/tools/fhir.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/transports/http.d.ts +3 -2
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +126 -16
- package/dist/transports/http.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p>
|
|
4
4
|
<strong>Medical vocabularies for AI agents.</strong><br/>
|
|
5
|
-
Search, map, and navigate
|
|
5
|
+
Search, map, and navigate 10M+ OMOP concepts: SNOMED CT, ICD-10, RxNorm, LOINC, and more. Directly from Claude, Cursor, VS Code, or any MCP-compatible client.
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
8
|
<p>
|
|
@@ -147,7 +147,7 @@ Connect MCP clients to `/` or `/mcp`. Useful for centralized deployments where m
|
|
|
147
147
|
<details>
|
|
148
148
|
<summary><strong>Hosted (mcp.omophub.com)</strong></summary>
|
|
149
149
|
|
|
150
|
-
Connect directly to the OMOPHub-hosted MCP server
|
|
150
|
+
Connect directly to the OMOPHub-hosted MCP server - no installation required. Each client authenticates with their own API key via the `Authorization` header:
|
|
151
151
|
|
|
152
152
|
**Claude Code:**
|
|
153
153
|
```bash
|
|
@@ -189,7 +189,7 @@ claude mcp add omophub --transport http \
|
|
|
189
189
|
<summary><strong>Docker</strong></summary>
|
|
190
190
|
|
|
191
191
|
```bash
|
|
192
|
-
# HTTP mode (default in Docker)
|
|
192
|
+
# HTTP mode (default in Docker) - serves MCP on port 3100
|
|
193
193
|
docker run -e OMOPHUB_API_KEY=oh_your_key_here -p 3100:3100 omophub/omophub-mcp
|
|
194
194
|
|
|
195
195
|
# Stdio mode (for piping)
|
|
@@ -221,6 +221,8 @@ docker run -i -e OMOPHUB_API_KEY=oh_your_key_here omophub/omophub-mcp --transpor
|
|
|
221
221
|
| `semantic_search` | Search using natural language with neural embeddings (understands clinical meaning) |
|
|
222
222
|
| `find_similar_concepts` | Find concepts similar to a reference concept, name, or description |
|
|
223
223
|
| `explore_concept` | Get concept details, hierarchy, and cross-vocabulary mappings in one call |
|
|
224
|
+
| `fhir_resolve` | Resolve a FHIR coded value (system URI + code) to its OMOP standard concept and CDM target table |
|
|
225
|
+
| `fhir_resolve_codeable_concept` | Resolve a FHIR CodeableConcept — picks the best match per OHDSI vocabulary preference |
|
|
224
226
|
|
|
225
227
|
### Resources
|
|
226
228
|
|
|
@@ -258,6 +260,12 @@ docker run -i -e OMOPHUB_API_KEY=oh_your_key_here omophub/omophub-mcp --transpor
|
|
|
258
260
|
**Explore a concept →** `explore_concept`
|
|
259
261
|
> "Give me everything about SNOMED concept 201826"
|
|
260
262
|
|
|
263
|
+
**FHIR-to-OMOP resolution →** `fhir_resolve`
|
|
264
|
+
> "Resolve FHIR SNOMED code 44054006 to OMOP — what table does it go in?"
|
|
265
|
+
|
|
266
|
+
**CodeableConcept →** `fhir_resolve_codeable_concept`
|
|
267
|
+
> "This CodeableConcept has both SNOMED 44054006 and ICD-10 E11.9 — which should I use for OMOP?"
|
|
268
|
+
|
|
261
269
|
**Find similar →** `find_similar_concepts`
|
|
262
270
|
> "What concepts are similar to 'Type 2 diabetes mellitus'?"
|
|
263
271
|
|
|
@@ -297,7 +305,7 @@ In **HTTP mode**, the health endpoint is available at `/health` on the same port
|
|
|
297
305
|
```bash
|
|
298
306
|
npx @omophub/omophub-mcp --transport=http --port=3100 --api-key=oh_your_key
|
|
299
307
|
curl http://localhost:3100/health
|
|
300
|
-
# → {"status":"ok","version":"1.3.
|
|
308
|
+
# → {"status":"ok","version":"1.3.1","uptime_seconds":42}
|
|
301
309
|
```
|
|
302
310
|
|
|
303
311
|
In **stdio mode**, use `--health-port` for a standalone health endpoint:
|
package/dist/client/resolve.js
CHANGED
|
@@ -28,7 +28,7 @@ function pruneClientCache() {
|
|
|
28
28
|
*/
|
|
29
29
|
export function resolveClient(extra, defaultClient) {
|
|
30
30
|
const headers = extra?.requestInfo?.headers;
|
|
31
|
-
const rawHeader = headers?.
|
|
31
|
+
const rawHeader = headers?.authorization ?? headers?.Authorization;
|
|
32
32
|
if (!rawHeader)
|
|
33
33
|
return defaultClient;
|
|
34
34
|
const authHeader = Array.isArray(rawHeader) ? rawHeader[0] : rawHeader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/client/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AASzC,gEAAgE;AAChE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuD,CAAC;AACnF,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,SAAS,gBAAgB;IACvB,IAAI,WAAW,CAAC,IAAI,IAAI,kBAAkB;QAAE,OAAO;IACnD,MAAM,OAAO,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzF,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC;QAC1E,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAgB,EAAE,aAA4B;IAC1E,MAAM,OAAO,GAAG,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC;IAC5C,MAAM,SAAS,GAAG,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/client/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AASzC,gEAAgE;AAChE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuD,CAAC;AACnF,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,SAAS,gBAAgB;IACvB,IAAI,WAAW,CAAC,IAAI,IAAI,kBAAkB;QAAE,OAAO;IACnD,MAAM,OAAO,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzF,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC;QAC1E,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAgB,EAAE,aAA4B;IAC1E,MAAM,OAAO,GAAG,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC;IAC5C,MAAM,SAAS,GAAG,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,CAAC;IAEnE,IAAI,CAAC,SAAS;QAAE,OAAO,aAAa,CAAC;IAErC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,IAAI,CAAC,UAAU;QAAE,OAAO,aAAa,CAAC;IAEtC,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK;QAAE,OAAO,aAAa,CAAC;IAEjC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM;QAAE,OAAO,aAAa,CAAC;IAElC,cAAc;IACd,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,6EAA6E;IAC7E,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAChE,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1D,gBAAgB,EAAE,CAAC;IAEnB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAYA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAI7C,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;IACpB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAiCA;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYtE;AAED,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,aAAa,GAAG,aAAa,CAS5E;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAYpD;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAqC1C"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { realpathSync } from 'node:fs';
|
|
3
3
|
import url from 'node:url';
|
|
4
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { OmopHubClient } from './client/api.js';
|
|
5
6
|
import { startHealthServer } from './health.js';
|
|
6
7
|
import { createServer } from './server.js';
|
|
7
8
|
import { startHttpTransport } from './transports/http.js';
|
|
@@ -83,13 +84,14 @@ export async function main() {
|
|
|
83
84
|
if (!apiKey) {
|
|
84
85
|
logger.info('No default API key — hosted mode: all requests must include Authorization: Bearer header');
|
|
85
86
|
}
|
|
86
|
-
const
|
|
87
|
+
const defaultClient = new OmopHubClient(apiKey, args.baseUrl);
|
|
87
88
|
if (transportType === 'http') {
|
|
88
89
|
const port = resolvePort(args.port);
|
|
89
90
|
logger.info('Starting OMOPHub MCP server (http transport)');
|
|
90
|
-
await startHttpTransport(
|
|
91
|
+
await startHttpTransport(createServer, defaultClient, port);
|
|
91
92
|
}
|
|
92
93
|
else {
|
|
94
|
+
const server = createServer(defaultClient);
|
|
93
95
|
const transport = new StdioServerTransport();
|
|
94
96
|
logger.info('Starting OMOPHub MCP server (stdio transport)');
|
|
95
97
|
await server.connect(transport);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
|
|
2
|
+
import type { OmopHubClient } from './client/api.js';
|
|
3
|
+
export declare function createServer(client: OmopHubClient): McpServer;
|
|
3
4
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAiBrD,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CA8B7D"}
|
package/dist/server.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { OmopHubClient } from './client/api.js';
|
|
3
2
|
import { registerPrompts } from './prompts/index.js';
|
|
4
3
|
import { registerResources } from './resources/index.js';
|
|
5
|
-
import { registerConceptTools, registerExploreTools, registerHierarchyTools, registerMappingTools, registerSearchTools, registerSemanticSearchTools, registerSimilarTools, registerVocabularyTools, } from './tools/index.js';
|
|
4
|
+
import { registerConceptTools, registerExploreTools, registerFhirTools, registerHierarchyTools, registerMappingTools, registerSearchTools, registerSemanticSearchTools, registerSimilarTools, registerVocabularyTools, } from './tools/index.js';
|
|
6
5
|
import { logger } from './utils/logger.js';
|
|
7
6
|
import { VERSION } from './version.js';
|
|
8
|
-
export function createServer(
|
|
7
|
+
export function createServer(client) {
|
|
9
8
|
const server = new McpServer({
|
|
10
9
|
name: 'omophub',
|
|
11
10
|
version: VERSION,
|
|
12
11
|
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
12
|
});
|
|
14
|
-
const client = new OmopHubClient(apiKey, baseUrl);
|
|
15
13
|
// Register tools
|
|
16
14
|
registerSearchTools(server, client);
|
|
17
15
|
registerSemanticSearchTools(server, client);
|
|
@@ -21,11 +19,12 @@ export function createServer(apiKey, baseUrl) {
|
|
|
21
19
|
registerMappingTools(server, client);
|
|
22
20
|
registerHierarchyTools(server, client);
|
|
23
21
|
registerVocabularyTools(server, client);
|
|
22
|
+
registerFhirTools(server, client);
|
|
24
23
|
// Register resources and prompts
|
|
25
24
|
registerResources(server, client);
|
|
26
25
|
registerPrompts(server);
|
|
27
26
|
logger.info('OMOPHub MCP server initialized', {
|
|
28
|
-
tools:
|
|
27
|
+
tools: 11,
|
|
29
28
|
resources: 2,
|
|
30
29
|
prompts: 2,
|
|
31
30
|
});
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,2BAA2B,EAC3B,oBAAoB,EACpB,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,MAAqB;IAChD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;QAChB,WAAW,EACT,4KAA4K;KAC/K,CAAC,CAAC;IAEH,iBAAiB;IACjB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,2BAA2B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,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;IACxC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC,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,EAAE;QACT,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;KACX,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fhir.d.ts","sourceRoot":"","sources":["../../src/tools/fhir.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAiDtD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAsIhF"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolveClient } from '../client/resolve.js';
|
|
3
|
+
import { formatErrorForMcp } from '../utils/errors.js';
|
|
4
|
+
function formatResolution(res) {
|
|
5
|
+
const lines = [
|
|
6
|
+
`Resolved: ${res.standard_concept.concept_name} (ID: ${res.standard_concept.concept_id})`,
|
|
7
|
+
`Vocabulary: ${res.vocabulary_id ?? 'N/A'} | Type: ${res.mapping_type}`,
|
|
8
|
+
`Target table: ${res.target_table ?? 'unknown'} | Alignment: ${res.domain_resource_alignment}`,
|
|
9
|
+
];
|
|
10
|
+
if (res.similarity_score !== undefined) {
|
|
11
|
+
lines.push(`Similarity: ${res.similarity_score.toFixed(2)}`);
|
|
12
|
+
}
|
|
13
|
+
if (res.mapping_quality) {
|
|
14
|
+
lines.push(`Quality: ${res.mapping_quality}`);
|
|
15
|
+
}
|
|
16
|
+
if (res.recommendations && res.recommendations.length > 0) {
|
|
17
|
+
lines.push(`Recommendations (${res.recommendations.length}):`);
|
|
18
|
+
for (const rec of res.recommendations.slice(0, 5)) {
|
|
19
|
+
lines.push(` - ${rec.concept_name} (${rec.concept_id}) via ${rec.relationship_id}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return lines.join('\n');
|
|
23
|
+
}
|
|
24
|
+
export function registerFhirTools(server, client) {
|
|
25
|
+
server.tool('fhir_resolve', "Resolve a FHIR coded value (system URI + code) to its OMOP standard concept and CDM target table. Supports text-only input via semantic search fallback and optional Phoebe recommendations. Examples: system='http://snomed.info/sct' code='44054006' for Type 2 diabetes, or display='heart attack' for text-only resolution.", {
|
|
26
|
+
system: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('FHIR code system URI (e.g. http://snomed.info/sct, http://loinc.org)'),
|
|
30
|
+
code: z.string().optional().describe('Code value from the FHIR Coding'),
|
|
31
|
+
display: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Display text for semantic search fallback when code is unavailable'),
|
|
35
|
+
vocabulary_id: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Direct OMOP vocabulary_id (e.g. SNOMED, ICD10CM), bypasses URI resolution'),
|
|
39
|
+
resource_type: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe('FHIR resource type (Condition, Observation, MedicationRequest, Procedure, etc.)'),
|
|
43
|
+
include_recommendations: z
|
|
44
|
+
.boolean()
|
|
45
|
+
.optional()
|
|
46
|
+
.default(false)
|
|
47
|
+
.describe('Include Phoebe-recommended related concepts'),
|
|
48
|
+
include_quality: z
|
|
49
|
+
.boolean()
|
|
50
|
+
.optional()
|
|
51
|
+
.default(false)
|
|
52
|
+
.describe('Include mapping quality signal (high/medium/low/manual_review)'),
|
|
53
|
+
}, async (params, extra) => {
|
|
54
|
+
try {
|
|
55
|
+
const rc = resolveClient(extra, client);
|
|
56
|
+
const body = {};
|
|
57
|
+
if (params.system)
|
|
58
|
+
body.system = params.system;
|
|
59
|
+
if (params.code)
|
|
60
|
+
body.code = params.code;
|
|
61
|
+
if (params.display)
|
|
62
|
+
body.display = params.display;
|
|
63
|
+
if (params.vocabulary_id)
|
|
64
|
+
body.vocabulary_id = params.vocabulary_id;
|
|
65
|
+
if (params.resource_type)
|
|
66
|
+
body.resource_type = params.resource_type;
|
|
67
|
+
if (params.include_recommendations)
|
|
68
|
+
body.include_recommendations = true;
|
|
69
|
+
if (params.include_quality)
|
|
70
|
+
body.include_quality = true;
|
|
71
|
+
const response = await rc.post('/fhir/resolve', body, 'fhir_resolve');
|
|
72
|
+
const res = response.data?.resolution;
|
|
73
|
+
const text = res ? formatResolution(res) : 'Resolution failed — no data returned';
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{ type: 'text', text },
|
|
77
|
+
{ type: 'text', text: JSON.stringify(response, null, 2) },
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
const { text, json } = formatErrorForMcp(error, 'fhir_resolve');
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{ type: 'text', text },
|
|
86
|
+
{ type: 'text', text: json },
|
|
87
|
+
],
|
|
88
|
+
isError: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
server.tool('fhir_resolve_codeable_concept', 'Resolve a FHIR CodeableConcept with multiple codings. Picks the best match per OHDSI vocabulary preference (SNOMED > RxNorm > LOINC > CVX > ICD-10). Falls back to the text field via semantic search if no coding resolves.', {
|
|
93
|
+
coding: z
|
|
94
|
+
.array(z.object({
|
|
95
|
+
system: z.string().describe('FHIR code system URI'),
|
|
96
|
+
code: z.string().describe('Code value'),
|
|
97
|
+
display: z.string().optional().describe('Display text'),
|
|
98
|
+
}))
|
|
99
|
+
.min(1)
|
|
100
|
+
.max(20)
|
|
101
|
+
.describe('Array of FHIR Coding entries from the CodeableConcept'),
|
|
102
|
+
text: z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('CodeableConcept.text — semantic fallback if no coding resolves'),
|
|
106
|
+
resource_type: z.string().optional().describe('FHIR resource type'),
|
|
107
|
+
include_recommendations: z.boolean().optional().default(false),
|
|
108
|
+
include_quality: z.boolean().optional().default(false),
|
|
109
|
+
}, async (params, extra) => {
|
|
110
|
+
try {
|
|
111
|
+
const rc = resolveClient(extra, client);
|
|
112
|
+
const body = { coding: params.coding };
|
|
113
|
+
if (params.text)
|
|
114
|
+
body.text = params.text;
|
|
115
|
+
if (params.resource_type)
|
|
116
|
+
body.resource_type = params.resource_type;
|
|
117
|
+
if (params.include_recommendations)
|
|
118
|
+
body.include_recommendations = true;
|
|
119
|
+
if (params.include_quality)
|
|
120
|
+
body.include_quality = true;
|
|
121
|
+
const response = await rc.post('/fhir/resolve/codeable-concept', body, 'fhir_resolve_codeable_concept');
|
|
122
|
+
const best = response.data?.best_match?.resolution;
|
|
123
|
+
const altCount = response.data?.alternatives?.length ?? 0;
|
|
124
|
+
const text = best
|
|
125
|
+
? `Best match: ${best.standard_concept.concept_name} (${best.source_concept.vocabulary_id})\n` +
|
|
126
|
+
`Target table: ${best.target_table ?? 'unknown'} | Alternatives: ${altCount}`
|
|
127
|
+
: 'No resolution found — all codings failed to resolve';
|
|
128
|
+
return {
|
|
129
|
+
content: [
|
|
130
|
+
{ type: 'text', text },
|
|
131
|
+
{ type: 'text', text: JSON.stringify(response, null, 2) },
|
|
132
|
+
],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const { text, json } = formatErrorForMcp(error, 'fhir_resolve_codeable_concept');
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{ type: 'text', text },
|
|
140
|
+
{ type: 'text', text: json },
|
|
141
|
+
],
|
|
142
|
+
isError: true,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=fhir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fhir.js","sourceRoot":"","sources":["../../src/tools/fhir.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA0BvD,SAAS,gBAAgB,CAAC,GAAmB;IAC3C,MAAM,KAAK,GAAG;QACZ,aAAa,GAAG,CAAC,gBAAgB,CAAC,YAAY,SAAS,GAAG,CAAC,gBAAgB,CAAC,UAAU,GAAG;QACzF,eAAe,GAAG,CAAC,aAAa,IAAI,KAAK,YAAY,GAAG,CAAC,YAAY,EAAE;QACvE,iBAAiB,GAAG,CAAC,YAAY,IAAI,SAAS,iBAAiB,GAAG,CAAC,yBAAyB,EAAE;KAC/F,CAAC;IACF,IAAI,GAAG,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,oBAAoB,GAAG,CAAC,eAAe,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/D,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,YAAY,KAAK,GAAG,CAAC,UAAU,SAAS,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAqB;IACxE,MAAM,CAAC,IAAI,CACT,cAAc,EACd,iUAAiU,EACjU;QACE,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,sEAAsE,CAAC;QACnF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QACvE,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,oEAAoE,CAAC;QACjF,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,2EAA2E,CAAC;QACxF,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,iFAAiF,CAClF;QACH,uBAAuB,EAAE,CAAC;aACvB,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CAAC,6CAA6C,CAAC;QAC1D,eAAe,EAAE,CAAC;aACf,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CAAC,gEAAgE,CAAC;KAC9E,EACD,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACxC,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,IAAI,MAAM,CAAC,MAAM;gBAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC/C,IAAI,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACzC,IAAI,MAAM,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YAClD,IAAI,MAAM,CAAC,aAAa;gBAAE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;YACpE,IAAI,MAAM,CAAC,aAAa;gBAAE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;YACpE,IAAI,MAAM,CAAC,uBAAuB;gBAAE,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;YACxE,IAAI,MAAM,CAAC,eAAe;gBAAE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;YAExD,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,IAAI,CAAsB,eAAe,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;YAE3F,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;YACtC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,sCAAsC,CAAC;YAElF,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE;oBAC/B,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;iBACnE;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YAChE,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE;oBAC/B,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE;iBACtC;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,+BAA+B,EAC/B,8NAA8N,EAC9N;QACE,MAAM,EAAE,CAAC;aACN,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;YACP,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YACnD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;YACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;SACxD,CAAC,CACH;aACA,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,CAAC,uDAAuD,CAAC;QACpE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,gEAAgE,CAAC;QAC7E,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QACnE,uBAAuB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QAC9D,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;KACvD,EACD,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACxC,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;YAChE,IAAI,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACzC,IAAI,MAAM,CAAC,aAAa;gBAAE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;YACpE,IAAI,MAAM,CAAC,uBAAuB;gBAAE,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;YACxE,IAAI,MAAM,CAAC,eAAe;gBAAE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;YAExD,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,IAAI,CAC5B,gCAAgC,EAChC,IAAI,EACJ,+BAA+B,CAChC,CAAC;YAEF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC;YACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC,CAAC;YAC1D,MAAM,IAAI,GAAG,IAAI;gBACf,CAAC,CAAC,eAAe,IAAI,CAAC,gBAAgB,CAAC,YAAY,KAAK,IAAI,CAAC,cAAc,CAAC,aAAa,KAAK;oBAC5F,iBAAiB,IAAI,CAAC,YAAY,IAAI,SAAS,oBAAoB,QAAQ,EAAE;gBAC/E,CAAC,CAAC,qDAAqD,CAAC;YAE1D,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE;oBAC/B,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;iBACnE;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,iBAAiB,CAAC,KAAK,EAAE,+BAA+B,CAAC,CAAC;YACjF,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE;oBAC/B,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE;iBACtC;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { registerConceptTools } from './concepts.js';
|
|
2
2
|
export { registerExploreTools } from './explore.js';
|
|
3
|
+
export { registerFhirTools } from './fhir.js';
|
|
3
4
|
export { registerHierarchyTools } from './hierarchy.js';
|
|
4
5
|
export { registerMappingTools } from './mappings.js';
|
|
5
6
|
export { registerSearchTools } from './search.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/tools/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { registerConceptTools } from './concepts.js';
|
|
2
2
|
export { registerExploreTools } from './explore.js';
|
|
3
|
+
export { registerFhirTools } from './fhir.js';
|
|
3
4
|
export { registerHierarchyTools } from './hierarchy.js';
|
|
4
5
|
export { registerMappingTools } from './mappings.js';
|
|
5
6
|
export { registerSearchTools } from './search.js';
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type Server } from 'node:http';
|
|
2
2
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import type { OmopHubClient } from '../client/api.js';
|
|
3
4
|
/**
|
|
4
|
-
* Starts an HTTP server with
|
|
5
|
+
* Starts an HTTP server with per-session MCP transports on /
|
|
5
6
|
* and a health endpoint on /health.
|
|
6
7
|
*/
|
|
7
|
-
export declare function startHttpTransport(
|
|
8
|
+
export declare function startHttpTransport(serverFactory: (client: OmopHubClient) => McpServer, defaultClient: OmopHubClient, port: number): Promise<Server>;
|
|
8
9
|
//# sourceMappingURL=http.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"AACA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA4BtD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,SAAS,EACnD,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAgKjB"}
|
package/dist/transports/http.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { createServer } from 'node:http';
|
|
2
3
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
3
5
|
import { handleHealthRequest } from '../health.js';
|
|
4
6
|
import { logger } from '../utils/logger.js';
|
|
5
7
|
const CORS_HEADERS = {
|
|
@@ -13,42 +15,150 @@ function setCorsHeaders(res) {
|
|
|
13
15
|
res.setHeader(key, value);
|
|
14
16
|
}
|
|
15
17
|
}
|
|
18
|
+
// Active sessions — each client gets its own transport + server
|
|
19
|
+
const sessions = new Map();
|
|
20
|
+
const MAX_BODY_SIZE = 1_048_576; // 1 MB
|
|
21
|
+
const JSON_RPC_INTERNAL_ERROR = JSON.stringify({
|
|
22
|
+
jsonrpc: '2.0',
|
|
23
|
+
error: { code: -32603, message: 'Internal server error' },
|
|
24
|
+
id: null,
|
|
25
|
+
});
|
|
16
26
|
/**
|
|
17
|
-
* Starts an HTTP server with
|
|
27
|
+
* Starts an HTTP server with per-session MCP transports on /
|
|
18
28
|
* and a health endpoint on /health.
|
|
19
29
|
*/
|
|
20
|
-
export async function startHttpTransport(
|
|
21
|
-
const transport = new StreamableHTTPServerTransport({
|
|
22
|
-
sessionIdGenerator: undefined,
|
|
23
|
-
});
|
|
24
|
-
await mcpServer.connect(transport);
|
|
30
|
+
export async function startHttpTransport(serverFactory, defaultClient, port) {
|
|
25
31
|
const httpServer = createServer(async (req, res) => {
|
|
26
32
|
setCorsHeaders(res);
|
|
27
|
-
// Handle CORS preflight
|
|
28
33
|
if (req.method === 'OPTIONS') {
|
|
29
34
|
res.writeHead(204);
|
|
30
35
|
res.end();
|
|
31
36
|
return;
|
|
32
37
|
}
|
|
33
|
-
// Health endpoint
|
|
34
38
|
if (handleHealthRequest(req, res))
|
|
35
39
|
return;
|
|
36
|
-
// MCP endpoint (/ for hosted, /mcp for self-hosted backward compat)
|
|
37
40
|
const pathname = new URL(req.url ?? '/', 'http://localhost').pathname;
|
|
38
41
|
if (pathname === '/' || pathname === '/mcp') {
|
|
42
|
+
const rawSessionId = req.headers['mcp-session-id'];
|
|
43
|
+
const sessionId = Array.isArray(rawSessionId) ? rawSessionId[0] : rawSessionId;
|
|
44
|
+
// GET (SSE stream) and DELETE (session close) carry no body — route directly
|
|
45
|
+
if (req.method === 'GET' || req.method === 'DELETE') {
|
|
46
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
47
|
+
const transport = sessions.get(sessionId);
|
|
48
|
+
if (!transport)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
await transport.handleRequest(req, res);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
logger.error('MCP transport error', { error: String(error), sessionId });
|
|
55
|
+
if (!res.headersSent) {
|
|
56
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
57
|
+
res.end(JSON_RPC_INTERNAL_ERROR);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
63
|
+
res.end(JSON.stringify({
|
|
64
|
+
jsonrpc: '2.0',
|
|
65
|
+
error: { code: -32000, message: 'Bad Request: No valid session ID provided' },
|
|
66
|
+
id: null,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// POST — read body with size limit
|
|
72
|
+
const chunks = [];
|
|
73
|
+
let totalBytes = 0;
|
|
74
|
+
let aborted = false;
|
|
75
|
+
for await (const chunk of req) {
|
|
76
|
+
const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
77
|
+
totalBytes += buf.length;
|
|
78
|
+
if (totalBytes > MAX_BODY_SIZE) {
|
|
79
|
+
req.destroy();
|
|
80
|
+
res.writeHead(413, { 'Content-Type': 'application/json' });
|
|
81
|
+
res.end(JSON.stringify({
|
|
82
|
+
jsonrpc: '2.0',
|
|
83
|
+
error: { code: -32000, message: 'Payload too large' },
|
|
84
|
+
id: null,
|
|
85
|
+
}));
|
|
86
|
+
aborted = true;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
chunks.push(buf);
|
|
90
|
+
}
|
|
91
|
+
if (aborted)
|
|
92
|
+
return;
|
|
93
|
+
const body = Buffer.concat(chunks).toString();
|
|
94
|
+
let parsedBody;
|
|
39
95
|
try {
|
|
40
|
-
|
|
96
|
+
parsedBody = JSON.parse(body);
|
|
41
97
|
}
|
|
42
|
-
catch
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
98
|
+
catch {
|
|
99
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
100
|
+
res.end(JSON.stringify({
|
|
101
|
+
jsonrpc: '2.0',
|
|
102
|
+
error: { code: -32700, message: 'Parse error' },
|
|
103
|
+
id: null,
|
|
104
|
+
}));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Existing session
|
|
108
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
109
|
+
const transport = sessions.get(sessionId);
|
|
110
|
+
if (!transport)
|
|
111
|
+
return;
|
|
112
|
+
try {
|
|
113
|
+
await transport.handleRequest(req, res, parsedBody);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
logger.error('MCP transport error', { error: String(error), sessionId });
|
|
117
|
+
if (!res.headersSent) {
|
|
118
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
119
|
+
res.end(JSON_RPC_INTERNAL_ERROR);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// New session (initialize request)
|
|
125
|
+
if (!sessionId && isInitializeRequest(parsedBody)) {
|
|
126
|
+
const transport = new StreamableHTTPServerTransport({
|
|
127
|
+
sessionIdGenerator: () => randomUUID(),
|
|
128
|
+
onsessioninitialized: (id) => {
|
|
129
|
+
sessions.set(id, transport);
|
|
130
|
+
logger.info('MCP session created', { sessionId: id });
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
transport.onclose = () => {
|
|
134
|
+
if (transport.sessionId) {
|
|
135
|
+
sessions.delete(transport.sessionId);
|
|
136
|
+
logger.info('MCP session closed', { sessionId: transport.sessionId });
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const server = serverFactory(defaultClient);
|
|
140
|
+
await server.connect(transport);
|
|
141
|
+
try {
|
|
142
|
+
await transport.handleRequest(req, res, parsedBody);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
logger.error('MCP transport error (init)', { error: String(error) });
|
|
146
|
+
if (!res.headersSent) {
|
|
147
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
148
|
+
res.end(JSON_RPC_INTERNAL_ERROR);
|
|
149
|
+
}
|
|
47
150
|
}
|
|
151
|
+
return;
|
|
48
152
|
}
|
|
153
|
+
// Invalid request — no session and not an initialize
|
|
154
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
155
|
+
res.end(JSON.stringify({
|
|
156
|
+
jsonrpc: '2.0',
|
|
157
|
+
error: { code: -32000, message: 'Bad Request: No valid session ID provided' },
|
|
158
|
+
id: null,
|
|
159
|
+
}));
|
|
49
160
|
return;
|
|
50
161
|
}
|
|
51
|
-
// Not found
|
|
52
162
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
53
163
|
res.end(JSON.stringify({ error: 'Not found' }));
|
|
54
164
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,YAAY,GAA2B;IAC3C,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,4BAA4B;IAC5D,8BAA8B,EAAE,6CAA6C;IAC7E,+BAA+B,EAAE,gBAAgB;CAClD,CAAC;AAEF,SAAS,cAAc,CAAC,GAAmB;IACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,YAAY,GAA2B;IAC3C,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,4BAA4B;IAC5D,8BAA8B,EAAE,6CAA6C;IAC7E,+BAA+B,EAAE,gBAAgB;CAClD,CAAC;AAEF,SAAS,cAAc,CAAC,GAAmB;IACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyC,CAAC;AAElE,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,OAAO;AAExC,MAAM,uBAAuB,GAAG,IAAI,CAAC,SAAS,CAAC;IAC7C,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE;IACzD,EAAE,EAAE,IAAI;CACT,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,aAAmD,EACnD,aAA4B,EAC5B,IAAY;IAEZ,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,EAAE,GAAoB,EAAE,GAAmB,EAAE,EAAE;QAClF,cAAc,CAAC,GAAG,CAAC,CAAC;QAEpB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,IAAI,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC;YAAE,OAAO;QAE1C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC,QAAQ,CAAC;QACtE,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC5C,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;YACnD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;YAE/E,6EAA6E;YAC7E,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACpD,IAAI,SAAS,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBACzC,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;oBAC1C,IAAI,CAAC,SAAS;wBAAE,OAAO;oBACvB,IAAI,CAAC;wBACH,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;oBAC1C,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;wBACzE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;4BACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;4BAC3D,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;wBACnC,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;wBACb,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,2CAA2C,EAAE;wBAC7E,EAAE,EAAE,IAAI;qBACT,CAAC,CACH,CAAC;gBACJ,CAAC;gBACD,OAAO;YACT,CAAC;YAED,mCAAmC;YACnC,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,IAAI,UAAU,GAAG,CAAC,CAAC;YACnB,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;gBACnE,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC;gBACzB,IAAI,UAAU,GAAG,aAAa,EAAE,CAAC;oBAC/B,GAAG,CAAC,OAAO,EAAE,CAAC;oBACd,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;wBACb,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE;wBACrD,EAAE,EAAE,IAAI;qBACT,CAAC,CACH,CAAC;oBACF,OAAO,GAAG,IAAI,CAAC;oBACf,MAAM;gBACR,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;YACD,IAAI,OAAO;gBAAE,OAAO;YACpB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC9C,IAAI,UAAmB,CAAC;YACxB,IAAI,CAAC;gBACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;oBACb,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE;oBAC/C,EAAE,EAAE,IAAI;iBACT,CAAC,CACH,CAAC;gBACF,OAAO;YACT,CAAC;YAED,mBAAmB;YACnB,IAAI,SAAS,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzC,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC1C,IAAI,CAAC,SAAS;oBAAE,OAAO;gBACvB,IAAI,CAAC;oBACH,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;gBACtD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;oBACzE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;wBACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBAC3D,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;gBACD,OAAO;YACT,CAAC;YAED,mCAAmC;YACnC,IAAI,CAAC,SAAS,IAAI,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClD,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;oBAClD,kBAAkB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;oBACtC,oBAAoB,EAAE,CAAC,EAAE,EAAE,EAAE;wBAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;wBAC5B,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;oBACxD,CAAC;iBACF,CAAC,CAAC;gBAEH,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;oBACvB,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;wBACxB,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;wBACrC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC;oBACxE,CAAC;gBACH,CAAC,CAAC;gBAEF,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;gBAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAEhC,IAAI,CAAC;oBACH,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;gBACtD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBACrE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;wBACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBAC3D,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;gBACD,OAAO;YACT,CAAC;YAED,qDAAqD;YACrD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;gBACb,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,2CAA2C,EAAE;gBAC7E,EAAE,EAAE,IAAI;aACT,CAAC,CACH,CAAC;YACF,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QAC7B,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YAC3B,MAAM,CAAC,IAAI,CAAC,oDAAoD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChF,MAAM,CAAC,IAAI,CAAC,uCAAuC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1E,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omophub/omophub-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"mcpName": "io.github.OMOPHub/omophub-mcp",
|
|
5
|
-
"description": "MCP server for OHDSI OMOP standardized medical vocabularies
|
|
5
|
+
"description": "MCP server for OHDSI OMOP standardized medical vocabularies - search, lookup, map, and navigate concepts via AI agents",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"bin": {
|