clinicaltrialsgov-mcp-server 1.2.1 → 1.3.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 +31 -8
- package/dist/index.js +633 -124
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<div align="center">
|
|
7
7
|
|
|
8
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE) [](https://github.com/cyanheads/clinicaltrialsgov-mcp-server/issues) [](https://www.typescriptlang.org/) [](https://bun.sh/) [](./vitest.config.ts)
|
|
9
9
|
|
|
10
10
|
</div>
|
|
11
11
|
|
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
|
|
14
14
|
## 🛠️ Tools Overview
|
|
15
15
|
|
|
16
|
-
This server provides
|
|
16
|
+
This server provides four powerful tools for accessing and analyzing clinical trial data from ClinicalTrials.gov:
|
|
17
17
|
|
|
18
|
-
| Tool Name | Description
|
|
19
|
-
| :------------------------------ |
|
|
20
|
-
| `clinicaltrials_search_studies` | Searches for clinical studies using
|
|
21
|
-
| `clinicaltrials_get_study` | Fetches one or more clinical studies by their NCT IDs
|
|
22
|
-
| `clinicaltrials_analyze_trends` | Performs statistical analysis on
|
|
18
|
+
| Tool Name | Description |
|
|
19
|
+
| :------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| `clinicaltrials_search_studies` | Searches for clinical studies using query terms, filters, pagination, and sorting. Now includes geographic filtering. |
|
|
21
|
+
| `clinicaltrials_get_study` | Fetches one or more clinical studies by their NCT IDs, returning either full data or concise summaries. |
|
|
22
|
+
| `clinicaltrials_analyze_trends` | Performs statistical analysis on up to 5000 studies, with new time-series analysis by year and month. |
|
|
23
|
+
| `clinicaltrials_compare_studies`| Performs a detailed side-by-side comparison of 2-5 clinical studies, highlighting commonalities and differences. |
|
|
23
24
|
|
|
24
25
|
### `clinicaltrials_search_studies`
|
|
25
26
|
|
|
@@ -85,6 +86,28 @@ This server provides three powerful tools for accessing and analyzing clinical t
|
|
|
85
86
|
|
|
86
87
|
📖 **[View detailed examples →](./examples/clinicaltrials_analyze_trends.md)**
|
|
87
88
|
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### `clinicaltrials_compare_studies`
|
|
92
|
+
|
|
93
|
+
**Compare and contrast multiple studies** to identify key similarities and differences.
|
|
94
|
+
|
|
95
|
+
**Key Features:**
|
|
96
|
+
|
|
97
|
+
- Side-by-side comparison of 2-5 studies by NCT ID
|
|
98
|
+
- Extracts and contrasts eligibility, design, interventions, outcomes, sponsors, and more
|
|
99
|
+
- Generates a summary of commonalities and differences
|
|
100
|
+
- Handles partial failures gracefully if some studies cannot be fetched
|
|
101
|
+
- Highly configurable to focus on specific fields of interest
|
|
102
|
+
|
|
103
|
+
**Example Use Cases:**
|
|
104
|
+
|
|
105
|
+
- "Compare the study design and eligibility criteria for NCT04516746 and NCT04516759"
|
|
106
|
+
- "What are the main differences in interventions and outcomes between these three leading Alzheimer's trials?"
|
|
107
|
+
- "Show me a side-by-side of sponsor and location data for these competitor studies"
|
|
108
|
+
|
|
109
|
+
📖 **[View detailed examples →](./examples/clinicaltrials_compare_studies.md)**
|
|
110
|
+
|
|
88
111
|
## ✨ Features
|
|
89
112
|
|
|
90
113
|
This server is built on the [`mcp-ts-template`](https://github.com/cyanheads/mcp-ts-template) and inherits its rich feature set:
|
|
@@ -158,7 +181,7 @@ All configuration is centralized and validated at startup in `src/config/index.t
|
|
|
158
181
|
| Variable | Description | Default |
|
|
159
182
|
| :---------------------- | :----------------------------------------------------------------------------- | :---------- |
|
|
160
183
|
| `MCP_TRANSPORT_TYPE` | The transport to use: `stdio` or `http`. | `http` |
|
|
161
|
-
| `MCP_HTTP_PORT` | The port for the HTTP server. | `
|
|
184
|
+
| `MCP_HTTP_PORT` | The port for the HTTP server. | `3017` |
|
|
162
185
|
| `MCP_AUTH_MODE` | Authentication mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
163
186
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv`, `r2`. | `in-memory` |
|
|
164
187
|
| `OTEL_ENABLED` | Set to `true` to enable OpenTelemetry. | `false` |
|
package/dist/index.js
CHANGED
|
@@ -117491,55 +117491,10 @@ var z = /* @__PURE__ */ Object.freeze({
|
|
|
117491
117491
|
quotelessJson,
|
|
117492
117492
|
ZodError
|
|
117493
117493
|
});
|
|
117494
|
-
|
|
117495
|
-
// src/types-global/errors.ts
|
|
117496
|
-
var JsonRpcErrorCode;
|
|
117497
|
-
((JsonRpcErrorCode2) => {
|
|
117498
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ParseError"] = -32700] = "ParseError";
|
|
117499
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidRequest"] = -32600] = "InvalidRequest";
|
|
117500
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["MethodNotFound"] = -32601] = "MethodNotFound";
|
|
117501
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidParams"] = -32602] = "InvalidParams";
|
|
117502
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InternalError"] = -32603] = "InternalError";
|
|
117503
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ServiceUnavailable"] = -32000] = "ServiceUnavailable";
|
|
117504
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["NotFound"] = -32001] = "NotFound";
|
|
117505
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Conflict"] = -32002] = "Conflict";
|
|
117506
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["RateLimited"] = -32003] = "RateLimited";
|
|
117507
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Timeout"] = -32004] = "Timeout";
|
|
117508
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Forbidden"] = -32005] = "Forbidden";
|
|
117509
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Unauthorized"] = -32006] = "Unauthorized";
|
|
117510
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ValidationError"] = -32007] = "ValidationError";
|
|
117511
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ConfigurationError"] = -32008] = "ConfigurationError";
|
|
117512
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InitializationFailed"] = -32009] = "InitializationFailed";
|
|
117513
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["DatabaseError"] = -32010] = "DatabaseError";
|
|
117514
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["SerializationError"] = -32070] = "SerializationError";
|
|
117515
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["UnknownError"] = -32099] = "UnknownError";
|
|
117516
|
-
})(JsonRpcErrorCode ||= {});
|
|
117517
|
-
|
|
117518
|
-
class McpError extends Error {
|
|
117519
|
-
code;
|
|
117520
|
-
data;
|
|
117521
|
-
constructor(code, message, data, options) {
|
|
117522
|
-
super(message, options);
|
|
117523
|
-
this.code = code;
|
|
117524
|
-
if (data) {
|
|
117525
|
-
this.data = data;
|
|
117526
|
-
}
|
|
117527
|
-
this.name = "McpError";
|
|
117528
|
-
Object.setPrototypeOf(this, McpError.prototype);
|
|
117529
|
-
if (Error.captureStackTrace) {
|
|
117530
|
-
Error.captureStackTrace(this, McpError);
|
|
117531
|
-
}
|
|
117532
|
-
}
|
|
117533
|
-
}
|
|
117534
|
-
var ErrorSchema = z.object({
|
|
117535
|
-
code: z.nativeEnum(JsonRpcErrorCode).describe("Standardized error code from JsonRpcErrorCode enum"),
|
|
117536
|
-
message: z.string().min(1, "Error message cannot be empty.").describe("Detailed human-readable error message"),
|
|
117537
|
-
data: z.record(z.string(), z.unknown()).optional().describe("Optional structured data providing more context about the error")
|
|
117538
|
-
}).describe("Schema for validating structured error objects, ensuring consistency in error reporting.");
|
|
117539
117494
|
// package.json
|
|
117540
117495
|
var package_default = {
|
|
117541
117496
|
name: "clinicaltrialsgov-mcp-server",
|
|
117542
|
-
version: "1.
|
|
117497
|
+
version: "1.3.0",
|
|
117543
117498
|
mcpName: "io.github.cyanheads/clinicaltrialsgov-mcp-server",
|
|
117544
117499
|
description: "ClinicalTrials.gov Model Context Protocol (MCP) Server that provides a suite of tools for interacting with the official ClinicalTrials.gov v2 API. Enables AI agents and LLMs to programmatically search, retrieve, and analyze clinical trial data.",
|
|
117545
117500
|
main: "dist/index.js",
|
|
@@ -117569,9 +117524,12 @@ var package_default = {
|
|
|
117569
117524
|
homepage: "https://github.com/cyanheads/clinicaltrialsgov-mcp-server#readme",
|
|
117570
117525
|
scripts: {
|
|
117571
117526
|
build: "bun build ./src/index.ts --outdir ./dist --target node",
|
|
117527
|
+
"build:worker": "bun build ./src/worker.ts --outdir ./dist --target bun --no-external",
|
|
117528
|
+
"deploy:dev": "MCP_TRANSPORT_TYPE=http bunx wrangler dev",
|
|
117529
|
+
"deploy:prod": "MCP_TRANSPORT_TYPE=http bunx wrangler deploy",
|
|
117572
117530
|
start: "bun ./dist/index.js",
|
|
117573
|
-
"start:stdio": "
|
|
117574
|
-
"start:http": "
|
|
117531
|
+
"start:stdio": "MCP_TRANSPORT_TYPE=stdio bun ./dist/index.js",
|
|
117532
|
+
"start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js",
|
|
117575
117533
|
dev: "bun --watch src/index.ts",
|
|
117576
117534
|
"dev:stdio": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
|
|
117577
117535
|
"dev:http": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
|
|
@@ -117586,6 +117544,7 @@ var package_default = {
|
|
|
117586
117544
|
tree: "bun run scripts/tree.ts",
|
|
117587
117545
|
"fetch-spec": "bun run scripts/fetch-openapi-spec.ts",
|
|
117588
117546
|
format: 'bun run prettier --write "**/*.{ts,js,json,md,html,css}"',
|
|
117547
|
+
prepare: "bunx husky",
|
|
117589
117548
|
inspector: "bunx mcp-inspector --config mcp.json --server clinicaltrialsgov-mcp-server",
|
|
117590
117549
|
"db:duckdb-example": "MCP_LOG_LEVEL=debug tsc && node dist/storage/duckdbExample.js",
|
|
117591
117550
|
test: "bun test --config vitest.config.ts",
|
|
@@ -117711,6 +117670,51 @@ var package_default = {
|
|
|
117711
117670
|
}
|
|
117712
117671
|
};
|
|
117713
117672
|
|
|
117673
|
+
// src/types-global/errors.ts
|
|
117674
|
+
var JsonRpcErrorCode;
|
|
117675
|
+
((JsonRpcErrorCode2) => {
|
|
117676
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ParseError"] = -32700] = "ParseError";
|
|
117677
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidRequest"] = -32600] = "InvalidRequest";
|
|
117678
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["MethodNotFound"] = -32601] = "MethodNotFound";
|
|
117679
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidParams"] = -32602] = "InvalidParams";
|
|
117680
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InternalError"] = -32603] = "InternalError";
|
|
117681
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ServiceUnavailable"] = -32000] = "ServiceUnavailable";
|
|
117682
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["NotFound"] = -32001] = "NotFound";
|
|
117683
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Conflict"] = -32002] = "Conflict";
|
|
117684
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["RateLimited"] = -32003] = "RateLimited";
|
|
117685
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Timeout"] = -32004] = "Timeout";
|
|
117686
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Forbidden"] = -32005] = "Forbidden";
|
|
117687
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Unauthorized"] = -32006] = "Unauthorized";
|
|
117688
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ValidationError"] = -32007] = "ValidationError";
|
|
117689
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ConfigurationError"] = -32008] = "ConfigurationError";
|
|
117690
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InitializationFailed"] = -32009] = "InitializationFailed";
|
|
117691
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["DatabaseError"] = -32010] = "DatabaseError";
|
|
117692
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["SerializationError"] = -32070] = "SerializationError";
|
|
117693
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["UnknownError"] = -32099] = "UnknownError";
|
|
117694
|
+
})(JsonRpcErrorCode ||= {});
|
|
117695
|
+
|
|
117696
|
+
class McpError extends Error {
|
|
117697
|
+
code;
|
|
117698
|
+
data;
|
|
117699
|
+
constructor(code, message, data, options) {
|
|
117700
|
+
super(message, options);
|
|
117701
|
+
this.code = code;
|
|
117702
|
+
if (data) {
|
|
117703
|
+
this.data = data;
|
|
117704
|
+
}
|
|
117705
|
+
this.name = "McpError";
|
|
117706
|
+
Object.setPrototypeOf(this, McpError.prototype);
|
|
117707
|
+
if (Error.captureStackTrace) {
|
|
117708
|
+
Error.captureStackTrace(this, McpError);
|
|
117709
|
+
}
|
|
117710
|
+
}
|
|
117711
|
+
}
|
|
117712
|
+
var ErrorSchema = z.object({
|
|
117713
|
+
code: z.nativeEnum(JsonRpcErrorCode).describe("Standardized error code from JsonRpcErrorCode enum"),
|
|
117714
|
+
message: z.string().min(1, "Error message cannot be empty.").describe("Detailed human-readable error message"),
|
|
117715
|
+
data: z.record(z.string(), z.unknown()).optional().describe("Optional structured data providing more context about the error")
|
|
117716
|
+
}).describe("Schema for validating structured error objects, ensuring consistency in error reporting.");
|
|
117717
|
+
|
|
117714
117718
|
// src/config/index.ts
|
|
117715
117719
|
var packageManifest = package_default;
|
|
117716
117720
|
var hasFileSystemAccess = typeof process !== "undefined" && typeof process.versions === "object" && process.versions !== null && typeof process.versions.node === "string";
|
|
@@ -117759,7 +117763,7 @@ var ConfigSchema = z.object({
|
|
|
117759
117763
|
}, z.enum(["development", "production", "testing"])).default("development"),
|
|
117760
117764
|
mcpTransportType: z.preprocess(emptyStringAsUndefined, z.enum(["stdio", "http"]).default("stdio")),
|
|
117761
117765
|
mcpSessionMode: z.preprocess(emptyStringAsUndefined, z.enum(["stateless", "stateful", "auto"]).default("auto")),
|
|
117762
|
-
mcpHttpPort: z.coerce.number().default(
|
|
117766
|
+
mcpHttpPort: z.coerce.number().default(3017),
|
|
117763
117767
|
mcpHttpHost: z.string().default("127.0.0.1"),
|
|
117764
117768
|
mcpHttpEndpointPath: z.string().default("/mcp"),
|
|
117765
117769
|
mcpHttpMaxPortRetries: z.coerce.number().default(15),
|
|
@@ -119520,7 +119524,7 @@ async function fetchWithTimeout(url, timeoutMs, context, options) {
|
|
|
119520
119524
|
|
|
119521
119525
|
// src/container/index.ts
|
|
119522
119526
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
119523
|
-
var
|
|
119527
|
+
var import_tsyringe22 = __toESM(require_cjs3(), 1);
|
|
119524
119528
|
|
|
119525
119529
|
// src/container/registrations/core.ts
|
|
119526
119530
|
var import_tsyringe9 = __toESM(require_cjs3(), 1);
|
|
@@ -119742,8 +119746,23 @@ class ClinicalTrialsGovProvider {
|
|
|
119742
119746
|
if (params.query) {
|
|
119743
119747
|
queryParams.set("query.term", params.query);
|
|
119744
119748
|
}
|
|
119745
|
-
|
|
119746
|
-
|
|
119749
|
+
const geoFilters = [];
|
|
119750
|
+
if (params.country) {
|
|
119751
|
+
geoFilters.push(`AREA[LocationCountry]${params.country}`);
|
|
119752
|
+
}
|
|
119753
|
+
if (params.state) {
|
|
119754
|
+
geoFilters.push(`AREA[LocationState]${params.state}`);
|
|
119755
|
+
}
|
|
119756
|
+
if (params.city) {
|
|
119757
|
+
geoFilters.push(`AREA[LocationCity]${params.city}`);
|
|
119758
|
+
}
|
|
119759
|
+
let combinedFilter = params.filter || "";
|
|
119760
|
+
if (geoFilters.length > 0) {
|
|
119761
|
+
const geoFilterExpression = geoFilters.join(" AND ");
|
|
119762
|
+
combinedFilter = combinedFilter ? `(${combinedFilter}) AND (${geoFilterExpression})` : geoFilterExpression;
|
|
119763
|
+
}
|
|
119764
|
+
if (combinedFilter) {
|
|
119765
|
+
queryParams.set("filter.advanced", combinedFilter);
|
|
119747
119766
|
}
|
|
119748
119767
|
if (params.pageSize) {
|
|
119749
119768
|
queryParams.set("pageSize", String(params.pageSize));
|
|
@@ -119754,6 +119773,9 @@ class ClinicalTrialsGovProvider {
|
|
|
119754
119773
|
if (params.sort) {
|
|
119755
119774
|
queryParams.set("sort", params.sort);
|
|
119756
119775
|
}
|
|
119776
|
+
if (params.fields && params.fields.length > 0) {
|
|
119777
|
+
queryParams.set("fields", params.fields.join(","));
|
|
119778
|
+
}
|
|
119757
119779
|
queryParams.set("countTotal", "true");
|
|
119758
119780
|
const url = `${BASE_URL}/studies?${queryParams.toString()}`;
|
|
119759
119781
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
@@ -126883,7 +126905,7 @@ var registerCoreServices = () => {
|
|
|
126883
126905
|
};
|
|
126884
126906
|
|
|
126885
126907
|
// src/container/registrations/mcp.ts
|
|
126886
|
-
var
|
|
126908
|
+
var import_tsyringe21 = __toESM(require_cjs3(), 1);
|
|
126887
126909
|
|
|
126888
126910
|
// src/mcp-server/resources/resource-registration.ts
|
|
126889
126911
|
var import_tsyringe10 = __toESM(require_cjs3(), 1);
|
|
@@ -130198,10 +130220,10 @@ var registerResources = (container3) => {
|
|
|
130198
130220
|
};
|
|
130199
130221
|
|
|
130200
130222
|
// src/mcp-server/server.ts
|
|
130201
|
-
var
|
|
130223
|
+
var import_tsyringe16 = __toESM(require_cjs3(), 1);
|
|
130202
130224
|
|
|
130203
130225
|
// src/mcp-server/tools/tool-registration.ts
|
|
130204
|
-
var
|
|
130226
|
+
var import_tsyringe15 = __toESM(require_cjs3(), 1);
|
|
130205
130227
|
|
|
130206
130228
|
// src/mcp-server/tools/definitions/clinicaltrials-analyze-trends.tool.ts
|
|
130207
130229
|
var import_tsyringe11 = __toESM(require_cjs3(), 1);
|
|
@@ -130247,7 +130269,7 @@ function withToolAuth(requiredScopes, logicFn) {
|
|
|
130247
130269
|
// src/mcp-server/tools/definitions/clinicaltrials-analyze-trends.tool.ts
|
|
130248
130270
|
var TOOL_NAME = "clinicaltrials_analyze_trends";
|
|
130249
130271
|
var TOOL_TITLE = "Analyze Clinical Trial Trends";
|
|
130250
|
-
var TOOL_DESCRIPTION = "Performs statistical analysis on clinical trial studies matching search criteria. Aggregates data by status, country, sponsor type, or
|
|
130272
|
+
var TOOL_DESCRIPTION = "Performs statistical analysis on clinical trial studies matching search criteria. Aggregates data by status, country, sponsor type, phase, year, or month. May fetch up to 5000 studies.";
|
|
130251
130273
|
var TOOL_ANNOTATIONS = {
|
|
130252
130274
|
readOnlyHint: true,
|
|
130253
130275
|
idempotentHint: true,
|
|
@@ -130259,7 +130281,9 @@ var AnalysisTypeSchema = z.enum([
|
|
|
130259
130281
|
"countByStatus",
|
|
130260
130282
|
"countByCountry",
|
|
130261
130283
|
"countBySponsorType",
|
|
130262
|
-
"countByPhase"
|
|
130284
|
+
"countByPhase",
|
|
130285
|
+
"countByYear",
|
|
130286
|
+
"countByMonth"
|
|
130263
130287
|
]);
|
|
130264
130288
|
var InputSchema = z.object({
|
|
130265
130289
|
query: z.string().optional().describe("General search query for conditions, interventions, sponsors, or other terms."),
|
|
@@ -130267,7 +130291,7 @@ var InputSchema = z.object({
|
|
|
130267
130291
|
analysisType: z.union([
|
|
130268
130292
|
AnalysisTypeSchema.describe("A single analysis type to perform."),
|
|
130269
130293
|
z.array(AnalysisTypeSchema).min(1).describe("An array of analysis types to perform.")
|
|
130270
|
-
]).describe("Specify one or more analysis types: countByStatus, countByCountry, countBySponsorType, or
|
|
130294
|
+
]).describe("Specify one or more analysis types: countByStatus, countByCountry, countBySponsorType, countByPhase, countByYear, or countByMonth.")
|
|
130271
130295
|
}).describe("Input parameters for analyzing clinical trial trends.");
|
|
130272
130296
|
var AnalysisResultSchema = z.object({
|
|
130273
130297
|
analysisType: AnalysisTypeSchema.describe("The type of analysis performed."),
|
|
@@ -130353,6 +130377,26 @@ async function analyzeTrendsLogic(input, appContext, _sdkContext) {
|
|
|
130353
130377
|
});
|
|
130354
130378
|
continue;
|
|
130355
130379
|
}
|
|
130380
|
+
case "countByYear": {
|
|
130381
|
+
const startDate = study.protocolSection?.statusModule?.startDateStruct?.date;
|
|
130382
|
+
if (startDate) {
|
|
130383
|
+
const year = startDate.substring(0, 4);
|
|
130384
|
+
results[year] = (results[year] ?? 0) + 1;
|
|
130385
|
+
} else {
|
|
130386
|
+
results["Unknown"] = (results["Unknown"] ?? 0) + 1;
|
|
130387
|
+
}
|
|
130388
|
+
continue;
|
|
130389
|
+
}
|
|
130390
|
+
case "countByMonth": {
|
|
130391
|
+
const startDate = study.protocolSection?.statusModule?.startDateStruct?.date;
|
|
130392
|
+
if (startDate && startDate.length >= 7) {
|
|
130393
|
+
const yearMonth = startDate.substring(0, 7);
|
|
130394
|
+
results[yearMonth] = (results[yearMonth] ?? 0) + 1;
|
|
130395
|
+
} else {
|
|
130396
|
+
results["Unknown"] = (results["Unknown"] ?? 0) + 1;
|
|
130397
|
+
}
|
|
130398
|
+
continue;
|
|
130399
|
+
}
|
|
130356
130400
|
}
|
|
130357
130401
|
if (key) {
|
|
130358
130402
|
results[key] = (results[key] ?? 0) + 1;
|
|
@@ -130413,16 +130457,472 @@ var analyzeTrendsTool = {
|
|
|
130413
130457
|
responseFormatter
|
|
130414
130458
|
};
|
|
130415
130459
|
|
|
130416
|
-
// src/mcp-server/tools/definitions/clinicaltrials-
|
|
130460
|
+
// src/mcp-server/tools/definitions/clinicaltrials-compare-studies.tool.ts
|
|
130417
130461
|
var import_tsyringe12 = __toESM(require_cjs3(), 1);
|
|
130418
|
-
var TOOL_NAME2 = "
|
|
130419
|
-
var TOOL_TITLE2 = "
|
|
130420
|
-
var TOOL_DESCRIPTION2 = "
|
|
130462
|
+
var TOOL_NAME2 = "clinicaltrials_compare_studies";
|
|
130463
|
+
var TOOL_TITLE2 = "Compare Clinical Studies";
|
|
130464
|
+
var TOOL_DESCRIPTION2 = "Performs side-by-side comparison of 2-5 clinical trial studies. Compares eligibility criteria, design, interventions, outcomes, sponsors, and other key aspects.";
|
|
130421
130465
|
var TOOL_ANNOTATIONS2 = {
|
|
130422
130466
|
readOnlyHint: true,
|
|
130423
130467
|
idempotentHint: true,
|
|
130424
130468
|
openWorldHint: true
|
|
130425
130469
|
};
|
|
130470
|
+
var ComparisonCategorySchema = z.enum([
|
|
130471
|
+
"eligibility",
|
|
130472
|
+
"design",
|
|
130473
|
+
"interventions",
|
|
130474
|
+
"outcomes",
|
|
130475
|
+
"sponsors",
|
|
130476
|
+
"locations",
|
|
130477
|
+
"status",
|
|
130478
|
+
"all"
|
|
130479
|
+
]);
|
|
130480
|
+
var InputSchema2 = z.object({
|
|
130481
|
+
nctIds: z.array(z.string().regex(/^[Nn][Cc][Tt]\d{8}$/, "NCT ID must be 8 digits")).min(2, "At least 2 NCT IDs are required for comparison.").max(5, "Maximum 5 NCT IDs allowed for comparison.").describe("An array of 2-5 NCT IDs to compare."),
|
|
130482
|
+
compareFields: z.union([
|
|
130483
|
+
ComparisonCategorySchema.describe("A single comparison category to analyze."),
|
|
130484
|
+
z.array(ComparisonCategorySchema).min(1).describe("An array of comparison categories to analyze.")
|
|
130485
|
+
]).default("all").describe("Specify which aspects to compare: eligibility, design, interventions, outcomes, sponsors, locations, status, or all.")
|
|
130486
|
+
}).describe("Input parameters for comparing clinical trial studies.");
|
|
130487
|
+
var StudyComparisonSchema = z.object({
|
|
130488
|
+
nctId: z.string().describe("The NCT identifier."),
|
|
130489
|
+
title: z.string().optional().describe("The study title."),
|
|
130490
|
+
eligibility: z.object({
|
|
130491
|
+
criteria: z.string().optional().describe("Eligibility criteria text."),
|
|
130492
|
+
sex: z.string().optional().describe("Sex requirement."),
|
|
130493
|
+
minimumAge: z.string().optional().describe("Minimum age."),
|
|
130494
|
+
healthyVolunteers: z.boolean().optional().describe("Accepts healthy volunteers."),
|
|
130495
|
+
stdAges: z.array(z.string()).optional().describe("Standard age groups.")
|
|
130496
|
+
}).optional().describe("Eligibility criteria details."),
|
|
130497
|
+
design: z.object({
|
|
130498
|
+
studyType: z.string().optional().describe("Type of study."),
|
|
130499
|
+
phases: z.array(z.string()).optional().describe("Trial phases."),
|
|
130500
|
+
allocation: z.string().optional().describe("Allocation method."),
|
|
130501
|
+
interventionModel: z.string().optional().describe("Intervention model."),
|
|
130502
|
+
primaryPurpose: z.string().optional().describe("Primary purpose."),
|
|
130503
|
+
masking: z.string().optional().describe("Masking/blinding approach.")
|
|
130504
|
+
}).optional().describe("Study design details."),
|
|
130505
|
+
interventions: z.array(z.object({
|
|
130506
|
+
type: z.string().optional().describe("Intervention type."),
|
|
130507
|
+
name: z.string().optional().describe("Intervention name."),
|
|
130508
|
+
description: z.string().optional().describe("Description.")
|
|
130509
|
+
})).optional().describe("List of interventions."),
|
|
130510
|
+
outcomes: z.object({
|
|
130511
|
+
primary: z.array(z.object({
|
|
130512
|
+
measure: z.string().optional().describe("Outcome measure."),
|
|
130513
|
+
timeFrame: z.string().optional().describe("Time frame.")
|
|
130514
|
+
})).optional().describe("Primary outcomes."),
|
|
130515
|
+
secondary: z.array(z.object({
|
|
130516
|
+
measure: z.string().optional().describe("Outcome measure."),
|
|
130517
|
+
timeFrame: z.string().optional().describe("Time frame.")
|
|
130518
|
+
})).optional().describe("Secondary outcomes.")
|
|
130519
|
+
}).optional().describe("Outcome measures."),
|
|
130520
|
+
sponsors: z.object({
|
|
130521
|
+
leadSponsor: z.object({
|
|
130522
|
+
name: z.string().optional().describe("Sponsor name."),
|
|
130523
|
+
class: z.string().optional().describe("Sponsor class.")
|
|
130524
|
+
}).optional().describe("Lead sponsor."),
|
|
130525
|
+
collaborators: z.array(z.object({
|
|
130526
|
+
name: z.string().optional().describe("Collaborator name."),
|
|
130527
|
+
class: z.string().optional().describe("Collaborator class.")
|
|
130528
|
+
})).optional().describe("Collaborators.")
|
|
130529
|
+
}).optional().describe("Sponsor information."),
|
|
130530
|
+
locations: z.object({
|
|
130531
|
+
totalCount: z.number().optional().describe("Total number of locations."),
|
|
130532
|
+
countries: z.array(z.string()).optional().describe("List of countries."),
|
|
130533
|
+
topCities: z.array(z.string()).optional().describe("Top cities by location count.")
|
|
130534
|
+
}).optional().describe("Location summary."),
|
|
130535
|
+
status: z.object({
|
|
130536
|
+
overallStatus: z.string().optional().describe("Overall status."),
|
|
130537
|
+
startDate: z.string().optional().describe("Start date."),
|
|
130538
|
+
completionDate: z.string().optional().describe("Completion date."),
|
|
130539
|
+
lastUpdateDate: z.string().optional().describe("Last update date.")
|
|
130540
|
+
}).optional().describe("Status and timeline information.")
|
|
130541
|
+
}).describe("Structured comparison data for a single study.");
|
|
130542
|
+
var OutputSchema2 = z.object({
|
|
130543
|
+
comparisons: z.array(StudyComparisonSchema).describe("Array of study comparisons."),
|
|
130544
|
+
summary: z.object({
|
|
130545
|
+
totalStudies: z.number().describe("Number of studies compared."),
|
|
130546
|
+
comparedFields: z.array(z.string()).describe("Fields that were compared."),
|
|
130547
|
+
commonalities: z.array(z.string()).optional().describe("Key commonalities found across studies."),
|
|
130548
|
+
differences: z.array(z.string()).optional().describe("Key differences found across studies.")
|
|
130549
|
+
}).describe("Summary of the comparison."),
|
|
130550
|
+
errors: z.array(z.object({
|
|
130551
|
+
nctId: z.string().describe("The NCT ID that failed."),
|
|
130552
|
+
error: z.string().describe("Error message.")
|
|
130553
|
+
})).optional().describe("Any errors encountered during comparison.")
|
|
130554
|
+
}).describe("Comparison results for clinical trial studies.");
|
|
130555
|
+
function extractEligibility(study) {
|
|
130556
|
+
const eligibility = study.protocolSection?.eligibilityModule;
|
|
130557
|
+
if (!eligibility)
|
|
130558
|
+
return;
|
|
130559
|
+
return {
|
|
130560
|
+
criteria: eligibility.eligibilityCriteria,
|
|
130561
|
+
sex: eligibility.sex,
|
|
130562
|
+
minimumAge: eligibility.minimumAge,
|
|
130563
|
+
healthyVolunteers: eligibility.healthyVolunteers,
|
|
130564
|
+
stdAges: eligibility.stdAges
|
|
130565
|
+
};
|
|
130566
|
+
}
|
|
130567
|
+
function extractDesign(study) {
|
|
130568
|
+
const design = study.protocolSection?.designModule;
|
|
130569
|
+
if (!design)
|
|
130570
|
+
return;
|
|
130571
|
+
return {
|
|
130572
|
+
studyType: design.studyType,
|
|
130573
|
+
phases: design.phases,
|
|
130574
|
+
allocation: design.designInfo?.allocation,
|
|
130575
|
+
interventionModel: design.designInfo?.interventionModel,
|
|
130576
|
+
primaryPurpose: design.designInfo?.primaryPurpose,
|
|
130577
|
+
masking: design.designInfo?.maskingInfo?.masking
|
|
130578
|
+
};
|
|
130579
|
+
}
|
|
130580
|
+
function extractInterventions(study) {
|
|
130581
|
+
const interventions = study.protocolSection?.armsInterventionsModule?.interventions;
|
|
130582
|
+
if (!interventions)
|
|
130583
|
+
return;
|
|
130584
|
+
return interventions.map((i) => ({
|
|
130585
|
+
type: i.type,
|
|
130586
|
+
name: i.name,
|
|
130587
|
+
description: i.description
|
|
130588
|
+
}));
|
|
130589
|
+
}
|
|
130590
|
+
function extractOutcomes(study) {
|
|
130591
|
+
const outcomes = study.protocolSection?.outcomesModule;
|
|
130592
|
+
if (!outcomes)
|
|
130593
|
+
return;
|
|
130594
|
+
return {
|
|
130595
|
+
primary: outcomes.primaryOutcomes?.map((o) => ({
|
|
130596
|
+
measure: o.measure,
|
|
130597
|
+
timeFrame: o.timeFrame
|
|
130598
|
+
})),
|
|
130599
|
+
secondary: outcomes.secondaryOutcomes?.map((o) => ({
|
|
130600
|
+
measure: o.measure,
|
|
130601
|
+
timeFrame: o.timeFrame
|
|
130602
|
+
}))
|
|
130603
|
+
};
|
|
130604
|
+
}
|
|
130605
|
+
function extractSponsors(study) {
|
|
130606
|
+
const sponsors = study.protocolSection?.sponsorCollaboratorsModule;
|
|
130607
|
+
if (!sponsors)
|
|
130608
|
+
return;
|
|
130609
|
+
return {
|
|
130610
|
+
leadSponsor: sponsors.leadSponsor ? {
|
|
130611
|
+
name: sponsors.leadSponsor.name,
|
|
130612
|
+
class: sponsors.leadSponsor.class
|
|
130613
|
+
} : undefined,
|
|
130614
|
+
collaborators: sponsors.collaborators?.map((c) => ({
|
|
130615
|
+
name: c.name,
|
|
130616
|
+
class: c.class
|
|
130617
|
+
}))
|
|
130618
|
+
};
|
|
130619
|
+
}
|
|
130620
|
+
function extractLocations(study) {
|
|
130621
|
+
const locations = study.protocolSection?.contactsLocationsModule?.locations;
|
|
130622
|
+
if (!locations || locations.length === 0)
|
|
130623
|
+
return;
|
|
130624
|
+
const countries = [
|
|
130625
|
+
...new Set(locations.map((l) => l.country).filter(Boolean))
|
|
130626
|
+
];
|
|
130627
|
+
const cityCount = {};
|
|
130628
|
+
locations.forEach((loc) => {
|
|
130629
|
+
if (loc.city) {
|
|
130630
|
+
cityCount[loc.city] = (cityCount[loc.city] ?? 0) + 1;
|
|
130631
|
+
}
|
|
130632
|
+
});
|
|
130633
|
+
const topCities = Object.entries(cityCount).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([city]) => city);
|
|
130634
|
+
return {
|
|
130635
|
+
totalCount: locations.length,
|
|
130636
|
+
countries,
|
|
130637
|
+
topCities
|
|
130638
|
+
};
|
|
130639
|
+
}
|
|
130640
|
+
function extractStatus(study) {
|
|
130641
|
+
const status = study.protocolSection?.statusModule;
|
|
130642
|
+
if (!status)
|
|
130643
|
+
return;
|
|
130644
|
+
return {
|
|
130645
|
+
overallStatus: status.overallStatus,
|
|
130646
|
+
startDate: status.startDateStruct?.date,
|
|
130647
|
+
completionDate: status.completionDateStruct?.date,
|
|
130648
|
+
lastUpdateDate: status.lastUpdatePostDateStruct?.date
|
|
130649
|
+
};
|
|
130650
|
+
}
|
|
130651
|
+
function createStudyComparison(study, compareFields) {
|
|
130652
|
+
const nctId = study.protocolSection?.identificationModule?.nctId ?? "Unknown";
|
|
130653
|
+
const title = study.protocolSection?.identificationModule?.officialTitle ?? study.protocolSection?.identificationModule?.briefTitle;
|
|
130654
|
+
const comparison = { nctId, title };
|
|
130655
|
+
const shouldInclude = (field) => compareFields.includes("all") || compareFields.includes(field);
|
|
130656
|
+
if (shouldInclude("eligibility")) {
|
|
130657
|
+
comparison.eligibility = extractEligibility(study);
|
|
130658
|
+
}
|
|
130659
|
+
if (shouldInclude("design")) {
|
|
130660
|
+
comparison.design = extractDesign(study);
|
|
130661
|
+
}
|
|
130662
|
+
if (shouldInclude("interventions")) {
|
|
130663
|
+
comparison.interventions = extractInterventions(study);
|
|
130664
|
+
}
|
|
130665
|
+
if (shouldInclude("outcomes")) {
|
|
130666
|
+
comparison.outcomes = extractOutcomes(study);
|
|
130667
|
+
}
|
|
130668
|
+
if (shouldInclude("sponsors")) {
|
|
130669
|
+
comparison.sponsors = extractSponsors(study);
|
|
130670
|
+
}
|
|
130671
|
+
if (shouldInclude("locations")) {
|
|
130672
|
+
comparison.locations = extractLocations(study);
|
|
130673
|
+
}
|
|
130674
|
+
if (shouldInclude("status")) {
|
|
130675
|
+
comparison.status = extractStatus(study);
|
|
130676
|
+
}
|
|
130677
|
+
return comparison;
|
|
130678
|
+
}
|
|
130679
|
+
function analyzeSummary(comparisons, compareFields) {
|
|
130680
|
+
const commonalities = [];
|
|
130681
|
+
const differences = [];
|
|
130682
|
+
if (compareFields.includes("all") || compareFields.includes("design")) {
|
|
130683
|
+
const allPhases = comparisons.map((c) => c.design?.phases).filter(Boolean);
|
|
130684
|
+
if (allPhases.length > 0) {
|
|
130685
|
+
const firstPhases = allPhases[0]?.join(",");
|
|
130686
|
+
const allSame = allPhases.every((p) => p?.join(",") === firstPhases);
|
|
130687
|
+
if (allSame && firstPhases) {
|
|
130688
|
+
commonalities.push(`All studies are in phase: ${firstPhases}`);
|
|
130689
|
+
} else {
|
|
130690
|
+
differences.push("Studies are in different trial phases");
|
|
130691
|
+
}
|
|
130692
|
+
}
|
|
130693
|
+
}
|
|
130694
|
+
if (compareFields.includes("all") || compareFields.includes("sponsors")) {
|
|
130695
|
+
const sponsors = comparisons.map((c) => c.sponsors?.leadSponsor?.name).filter(Boolean);
|
|
130696
|
+
const uniqueSponsors = [...new Set(sponsors)];
|
|
130697
|
+
if (uniqueSponsors.length === 1 && sponsors.length === comparisons.length) {
|
|
130698
|
+
commonalities.push(`All studies sponsored by: ${uniqueSponsors[0]}`);
|
|
130699
|
+
} else if (uniqueSponsors.length > 1) {
|
|
130700
|
+
differences.push(`Different lead sponsors: ${uniqueSponsors.join(", ")}`);
|
|
130701
|
+
}
|
|
130702
|
+
}
|
|
130703
|
+
if (compareFields.includes("all") || compareFields.includes("status")) {
|
|
130704
|
+
const statuses = comparisons.map((c) => c.status?.overallStatus).filter(Boolean);
|
|
130705
|
+
const uniqueStatuses = [...new Set(statuses)];
|
|
130706
|
+
if (uniqueStatuses.length === 1 && statuses.length === comparisons.length) {
|
|
130707
|
+
commonalities.push(`All studies have status: ${uniqueStatuses[0]}`);
|
|
130708
|
+
} else if (uniqueStatuses.length > 1) {
|
|
130709
|
+
differences.push(`Different statuses: ${uniqueStatuses.join(", ")}`);
|
|
130710
|
+
}
|
|
130711
|
+
}
|
|
130712
|
+
if (compareFields.includes("all") || compareFields.includes("locations")) {
|
|
130713
|
+
const allCountries = comparisons.map((c) => c.locations?.countries ?? []).filter((countries) => countries.length > 0);
|
|
130714
|
+
if (allCountries.length > 1) {
|
|
130715
|
+
const commonCountries = allCountries.reduce((acc, countries) => acc.filter((c) => countries.includes(c)));
|
|
130716
|
+
if (commonCountries.length > 0) {
|
|
130717
|
+
commonalities.push(`Common countries: ${commonCountries.slice(0, 5).join(", ")}`);
|
|
130718
|
+
}
|
|
130719
|
+
}
|
|
130720
|
+
}
|
|
130721
|
+
return {
|
|
130722
|
+
totalStudies: comparisons.length,
|
|
130723
|
+
comparedFields: compareFields,
|
|
130724
|
+
commonalities: commonalities.length > 0 ? commonalities : undefined,
|
|
130725
|
+
differences: differences.length > 0 ? differences : undefined
|
|
130726
|
+
};
|
|
130727
|
+
}
|
|
130728
|
+
async function compareStudiesLogic(input, appContext, _sdkContext) {
|
|
130729
|
+
logger.debug(`Executing compareStudiesLogic for NCT IDs: ${input.nctIds.join(", ")}`, {
|
|
130730
|
+
...appContext,
|
|
130731
|
+
toolInput: input
|
|
130732
|
+
});
|
|
130733
|
+
const provider = import_tsyringe12.container.resolve(ClinicalTrialsProvider);
|
|
130734
|
+
const compareFields = Array.isArray(input.compareFields) ? input.compareFields : [input.compareFields];
|
|
130735
|
+
const comparisons = [];
|
|
130736
|
+
const errors = [];
|
|
130737
|
+
const studyPromises = input.nctIds.map(async (nctId) => {
|
|
130738
|
+
try {
|
|
130739
|
+
const study = await provider.fetchStudy(nctId, appContext);
|
|
130740
|
+
logger.info(`Successfully fetched study ${nctId} for comparison`, {
|
|
130741
|
+
...appContext
|
|
130742
|
+
});
|
|
130743
|
+
return { nctId, study };
|
|
130744
|
+
} catch (error2) {
|
|
130745
|
+
const errorMessage = error2 instanceof McpError ? error2.message : "An unexpected error occurred";
|
|
130746
|
+
logger.warning(`Failed to fetch study ${nctId}: ${errorMessage}`, {
|
|
130747
|
+
...appContext,
|
|
130748
|
+
nctId,
|
|
130749
|
+
error: error2
|
|
130750
|
+
});
|
|
130751
|
+
errors.push({ nctId, error: errorMessage });
|
|
130752
|
+
return null;
|
|
130753
|
+
}
|
|
130754
|
+
});
|
|
130755
|
+
const results = await Promise.all(studyPromises);
|
|
130756
|
+
results.forEach((result2) => {
|
|
130757
|
+
if (result2) {
|
|
130758
|
+
const comparison = createStudyComparison(result2.study, compareFields);
|
|
130759
|
+
comparisons.push(comparison);
|
|
130760
|
+
}
|
|
130761
|
+
});
|
|
130762
|
+
if (comparisons.length < 2) {
|
|
130763
|
+
throw new McpError(-32007 /* ValidationError */, `Insufficient studies for comparison. Need at least 2, got ${comparisons.length}. ${errors.length > 0 ? `Errors: ${errors.map((e) => `${e.nctId}: ${e.error}`).join("; ")}` : ""}`, { errors, successfulFetches: comparisons.length });
|
|
130764
|
+
}
|
|
130765
|
+
const summary = analyzeSummary(comparisons, compareFields);
|
|
130766
|
+
logger.info(`Successfully compared ${comparisons.length} studies`, {
|
|
130767
|
+
...appContext,
|
|
130768
|
+
comparedFields: compareFields
|
|
130769
|
+
});
|
|
130770
|
+
const result = { comparisons, summary };
|
|
130771
|
+
if (errors.length > 0) {
|
|
130772
|
+
result.errors = errors;
|
|
130773
|
+
}
|
|
130774
|
+
return result;
|
|
130775
|
+
}
|
|
130776
|
+
function responseFormatter2(result) {
|
|
130777
|
+
const { comparisons, summary, errors } = result;
|
|
130778
|
+
const summaryParts = [
|
|
130779
|
+
`# Comparison of ${summary.totalStudies} Clinical Trials`,
|
|
130780
|
+
"",
|
|
130781
|
+
"## Studies",
|
|
130782
|
+
...comparisons.map((c) => `- **${c.nctId}**: ${c.title ?? "No title"}`),
|
|
130783
|
+
""
|
|
130784
|
+
];
|
|
130785
|
+
if (summary.commonalities && summary.commonalities.length > 0) {
|
|
130786
|
+
summaryParts.push("## Commonalities");
|
|
130787
|
+
summaryParts.push(...summary.commonalities.map((c) => `- ${c}`));
|
|
130788
|
+
summaryParts.push("");
|
|
130789
|
+
}
|
|
130790
|
+
if (summary.differences && summary.differences.length > 0) {
|
|
130791
|
+
summaryParts.push("## Key Differences");
|
|
130792
|
+
summaryParts.push(...summary.differences.map((d) => `- ${d}`));
|
|
130793
|
+
summaryParts.push("");
|
|
130794
|
+
}
|
|
130795
|
+
if (errors && errors.length > 0) {
|
|
130796
|
+
summaryParts.push("## Errors");
|
|
130797
|
+
summaryParts.push(...errors.map((e) => `- **${e.nctId}**: ${e.error}`));
|
|
130798
|
+
summaryParts.push("");
|
|
130799
|
+
}
|
|
130800
|
+
summaryParts.push("---");
|
|
130801
|
+
summaryParts.push("");
|
|
130802
|
+
const detailParts = ["## Detailed Comparison", ""];
|
|
130803
|
+
comparisons.forEach((comp, idx) => {
|
|
130804
|
+
if (idx > 0)
|
|
130805
|
+
detailParts.push("---", "");
|
|
130806
|
+
detailParts.push(`### ${comp.nctId}: ${comp.title ?? "No title"}`, "");
|
|
130807
|
+
if (comp.status) {
|
|
130808
|
+
detailParts.push("**Status:**");
|
|
130809
|
+
detailParts.push(`- Overall Status: ${comp.status.overallStatus ?? "N/A"}`);
|
|
130810
|
+
detailParts.push(`- Start Date: ${comp.status.startDate ?? "N/A"}`);
|
|
130811
|
+
detailParts.push(`- Completion Date: ${comp.status.completionDate ?? "N/A"}`);
|
|
130812
|
+
detailParts.push("");
|
|
130813
|
+
}
|
|
130814
|
+
if (comp.design) {
|
|
130815
|
+
detailParts.push("**Design:**");
|
|
130816
|
+
detailParts.push(`- Study Type: ${comp.design.studyType ?? "N/A"}`);
|
|
130817
|
+
detailParts.push(`- Phases: ${comp.design.phases?.join(", ") ?? "N/A"}`);
|
|
130818
|
+
detailParts.push(`- Allocation: ${comp.design.allocation ?? "N/A"}`);
|
|
130819
|
+
detailParts.push(`- Intervention Model: ${comp.design.interventionModel ?? "N/A"}`);
|
|
130820
|
+
detailParts.push(`- Primary Purpose: ${comp.design.primaryPurpose ?? "N/A"}`);
|
|
130821
|
+
detailParts.push(`- Masking: ${comp.design.masking ?? "N/A"}`);
|
|
130822
|
+
detailParts.push("");
|
|
130823
|
+
}
|
|
130824
|
+
if (comp.eligibility) {
|
|
130825
|
+
detailParts.push("**Eligibility:**");
|
|
130826
|
+
detailParts.push(`- Sex: ${comp.eligibility.sex ?? "N/A"}`);
|
|
130827
|
+
detailParts.push(`- Minimum Age: ${comp.eligibility.minimumAge ?? "N/A"}`);
|
|
130828
|
+
detailParts.push(`- Healthy Volunteers: ${comp.eligibility.healthyVolunteers ?? "N/A"}`);
|
|
130829
|
+
if (comp.eligibility.stdAges?.length) {
|
|
130830
|
+
detailParts.push(`- Age Groups: ${comp.eligibility.stdAges.join(", ")}`);
|
|
130831
|
+
}
|
|
130832
|
+
if (comp.eligibility.criteria) {
|
|
130833
|
+
detailParts.push(`- Criteria: ${comp.eligibility.criteria.substring(0, 200)}${comp.eligibility.criteria.length > 200 ? "..." : ""}`);
|
|
130834
|
+
}
|
|
130835
|
+
detailParts.push("");
|
|
130836
|
+
}
|
|
130837
|
+
if (comp.interventions && comp.interventions.length > 0) {
|
|
130838
|
+
detailParts.push("**Interventions:**");
|
|
130839
|
+
comp.interventions.forEach((int) => {
|
|
130840
|
+
detailParts.push(`- ${int.type ?? "Unknown"}: ${int.name ?? "N/A"}`);
|
|
130841
|
+
if (int.description) {
|
|
130842
|
+
detailParts.push(` ${int.description.substring(0, 150)}${int.description.length > 150 ? "..." : ""}`);
|
|
130843
|
+
}
|
|
130844
|
+
});
|
|
130845
|
+
detailParts.push("");
|
|
130846
|
+
}
|
|
130847
|
+
if (comp.outcomes) {
|
|
130848
|
+
if (comp.outcomes.primary && comp.outcomes.primary.length > 0) {
|
|
130849
|
+
detailParts.push("**Primary Outcomes:**");
|
|
130850
|
+
comp.outcomes.primary.forEach((out) => {
|
|
130851
|
+
detailParts.push(`- ${out.measure ?? "N/A"}`);
|
|
130852
|
+
if (out.timeFrame) {
|
|
130853
|
+
detailParts.push(` Time Frame: ${out.timeFrame}`);
|
|
130854
|
+
}
|
|
130855
|
+
});
|
|
130856
|
+
detailParts.push("");
|
|
130857
|
+
}
|
|
130858
|
+
if (comp.outcomes.secondary && comp.outcomes.secondary.length > 0) {
|
|
130859
|
+
detailParts.push("**Secondary Outcomes:**");
|
|
130860
|
+
comp.outcomes.secondary.slice(0, 3).forEach((out) => {
|
|
130861
|
+
detailParts.push(`- ${out.measure ?? "N/A"}`);
|
|
130862
|
+
});
|
|
130863
|
+
if (comp.outcomes.secondary.length > 3) {
|
|
130864
|
+
detailParts.push(` ...and ${comp.outcomes.secondary.length - 3} more`);
|
|
130865
|
+
}
|
|
130866
|
+
detailParts.push("");
|
|
130867
|
+
}
|
|
130868
|
+
}
|
|
130869
|
+
if (comp.sponsors) {
|
|
130870
|
+
detailParts.push("**Sponsors:**");
|
|
130871
|
+
if (comp.sponsors.leadSponsor) {
|
|
130872
|
+
detailParts.push(`- Lead: ${comp.sponsors.leadSponsor.name ?? "N/A"} (${comp.sponsors.leadSponsor.class ?? "N/A"})`);
|
|
130873
|
+
}
|
|
130874
|
+
if (comp.sponsors.collaborators && comp.sponsors.collaborators.length > 0) {
|
|
130875
|
+
detailParts.push(`- Collaborators: ${comp.sponsors.collaborators.length}`);
|
|
130876
|
+
comp.sponsors.collaborators.slice(0, 3).forEach((collab) => {
|
|
130877
|
+
detailParts.push(` - ${collab.name ?? "N/A"}`);
|
|
130878
|
+
});
|
|
130879
|
+
if (comp.sponsors.collaborators.length > 3) {
|
|
130880
|
+
detailParts.push(` ...and ${comp.sponsors.collaborators.length - 3} more`);
|
|
130881
|
+
}
|
|
130882
|
+
}
|
|
130883
|
+
detailParts.push("");
|
|
130884
|
+
}
|
|
130885
|
+
if (comp.locations) {
|
|
130886
|
+
detailParts.push("**Locations:**");
|
|
130887
|
+
detailParts.push(`- Total: ${comp.locations.totalCount ?? 0}`);
|
|
130888
|
+
if (comp.locations.countries?.length) {
|
|
130889
|
+
detailParts.push(`- Countries: ${comp.locations.countries.join(", ")}`);
|
|
130890
|
+
}
|
|
130891
|
+
if (comp.locations.topCities?.length) {
|
|
130892
|
+
detailParts.push(`- Top Cities: ${comp.locations.topCities.join(", ")}`);
|
|
130893
|
+
}
|
|
130894
|
+
detailParts.push("");
|
|
130895
|
+
}
|
|
130896
|
+
});
|
|
130897
|
+
return [
|
|
130898
|
+
{
|
|
130899
|
+
type: "text",
|
|
130900
|
+
text: [...summaryParts, ...detailParts].join(`
|
|
130901
|
+
`)
|
|
130902
|
+
}
|
|
130903
|
+
];
|
|
130904
|
+
}
|
|
130905
|
+
var compareStudiesTool = {
|
|
130906
|
+
name: TOOL_NAME2,
|
|
130907
|
+
title: TOOL_TITLE2,
|
|
130908
|
+
description: TOOL_DESCRIPTION2,
|
|
130909
|
+
inputSchema: InputSchema2,
|
|
130910
|
+
outputSchema: OutputSchema2,
|
|
130911
|
+
annotations: TOOL_ANNOTATIONS2,
|
|
130912
|
+
logic: withToolAuth(["tool:clinicaltrials:read"], compareStudiesLogic),
|
|
130913
|
+
responseFormatter: responseFormatter2
|
|
130914
|
+
};
|
|
130915
|
+
|
|
130916
|
+
// src/mcp-server/tools/definitions/clinicaltrials-get-study.tool.ts
|
|
130917
|
+
var import_tsyringe13 = __toESM(require_cjs3(), 1);
|
|
130918
|
+
var TOOL_NAME3 = "clinicaltrials_get_study";
|
|
130919
|
+
var TOOL_TITLE3 = "Get Clinical Study";
|
|
130920
|
+
var TOOL_DESCRIPTION3 = "Fetches one or more clinical trial studies from ClinicalTrials.gov by their NCT ID(s). Returns full study data or concise summaries.";
|
|
130921
|
+
var TOOL_ANNOTATIONS3 = {
|
|
130922
|
+
readOnlyHint: true,
|
|
130923
|
+
idempotentHint: true,
|
|
130924
|
+
openWorldHint: true
|
|
130925
|
+
};
|
|
130426
130926
|
var StudySummarySchema = z.object({
|
|
130427
130927
|
nctId: z.string().optional().describe("The NCT identifier of the study."),
|
|
130428
130928
|
title: z.string().optional().describe("The official title of the study."),
|
|
@@ -130435,14 +130935,14 @@ var StudySummarySchema = z.object({
|
|
|
130435
130935
|
})).optional().describe("List of interventions being tested."),
|
|
130436
130936
|
leadSponsor: z.string().optional().describe("The lead sponsor organization.")
|
|
130437
130937
|
}).passthrough().describe("Concise summary of a clinical trial study.");
|
|
130438
|
-
var
|
|
130938
|
+
var InputSchema3 = z.object({
|
|
130439
130939
|
nctIds: z.union([
|
|
130440
130940
|
z.string().regex(/^[Nn][Cc][Tt]\d{8}$/, "NCT ID must be 8 digits").describe('A single NCT ID (e.g., "NCT12345678").'),
|
|
130441
130941
|
z.array(z.string().regex(/^[Nn][Cc][Tt]\d{8}$/, "NCT ID must be 8 digits")).min(1, "At least one NCT ID is required.").max(5, "Maximum 5 NCT IDs allowed per request.").describe("An array of up to 5 NCT IDs.")
|
|
130442
130942
|
]).describe('A single NCT ID (e.g., "NCT12345678") or an array of up to 5 NCT IDs to fetch.'),
|
|
130443
130943
|
summaryOnly: z.boolean().default(false).describe("If true, returns concise summaries. If false (default), returns full study data.")
|
|
130444
130944
|
}).describe("Input parameters for fetching clinical trial studies.");
|
|
130445
|
-
var
|
|
130945
|
+
var OutputSchema3 = z.object({
|
|
130446
130946
|
studies: z.array(z.union([StudySchema, StudySummarySchema])).describe("Array of full study data or summaries."),
|
|
130447
130947
|
errors: z.array(z.object({
|
|
130448
130948
|
nctId: z.string().describe("The NCT ID that failed."),
|
|
@@ -130469,7 +130969,7 @@ async function getStudyLogic(input, appContext, _sdkContext) {
|
|
|
130469
130969
|
...appContext,
|
|
130470
130970
|
toolInput: input
|
|
130471
130971
|
});
|
|
130472
|
-
const provider =
|
|
130972
|
+
const provider = import_tsyringe13.container.resolve(ClinicalTrialsProvider);
|
|
130473
130973
|
const studies = [];
|
|
130474
130974
|
const errors = [];
|
|
130475
130975
|
const studyPromises = nctIds.map(async (nctId) => {
|
|
@@ -130502,7 +131002,7 @@ async function getStudyLogic(input, appContext, _sdkContext) {
|
|
|
130502
131002
|
}
|
|
130503
131003
|
return result;
|
|
130504
131004
|
}
|
|
130505
|
-
function
|
|
131005
|
+
function responseFormatter3(result) {
|
|
130506
131006
|
return [
|
|
130507
131007
|
{
|
|
130508
131008
|
type: "text",
|
|
@@ -130511,34 +131011,38 @@ function responseFormatter2(result) {
|
|
|
130511
131011
|
];
|
|
130512
131012
|
}
|
|
130513
131013
|
var getStudyTool = {
|
|
130514
|
-
name:
|
|
130515
|
-
title:
|
|
130516
|
-
description:
|
|
130517
|
-
inputSchema:
|
|
130518
|
-
outputSchema:
|
|
130519
|
-
annotations:
|
|
131014
|
+
name: TOOL_NAME3,
|
|
131015
|
+
title: TOOL_TITLE3,
|
|
131016
|
+
description: TOOL_DESCRIPTION3,
|
|
131017
|
+
inputSchema: InputSchema3,
|
|
131018
|
+
outputSchema: OutputSchema3,
|
|
131019
|
+
annotations: TOOL_ANNOTATIONS3,
|
|
130520
131020
|
logic: withToolAuth(["tool:clinicaltrials:read"], getStudyLogic),
|
|
130521
|
-
responseFormatter:
|
|
131021
|
+
responseFormatter: responseFormatter3
|
|
130522
131022
|
};
|
|
130523
131023
|
|
|
130524
131024
|
// src/mcp-server/tools/definitions/clinicaltrials-search-studies.tool.ts
|
|
130525
|
-
var
|
|
130526
|
-
var
|
|
130527
|
-
var
|
|
130528
|
-
var
|
|
130529
|
-
var
|
|
131025
|
+
var import_tsyringe14 = __toESM(require_cjs3(), 1);
|
|
131026
|
+
var TOOL_NAME4 = "clinicaltrials_search_studies";
|
|
131027
|
+
var TOOL_TITLE4 = "Search Clinical Trials";
|
|
131028
|
+
var TOOL_DESCRIPTION4 = "Searches for clinical trial studies from ClinicalTrials.gov using queries and filters. Supports pagination, sorting, and advanced filtering.";
|
|
131029
|
+
var TOOL_ANNOTATIONS4 = {
|
|
130530
131030
|
readOnlyHint: true,
|
|
130531
131031
|
idempotentHint: true,
|
|
130532
131032
|
openWorldHint: true
|
|
130533
131033
|
};
|
|
130534
|
-
var
|
|
131034
|
+
var InputSchema4 = z.object({
|
|
130535
131035
|
query: z.string().optional().describe("General search query for conditions, interventions, sponsors, or other terms."),
|
|
130536
131036
|
filter: z.string().optional().describe("Advanced filter expression using the ClinicalTrials.gov filter syntax."),
|
|
130537
131037
|
pageSize: z.number().int().min(1).max(200).default(10).describe("Number of studies to return per page (1-200). Defaults to 10."),
|
|
130538
131038
|
pageToken: z.string().optional().describe("Token for retrieving the next page of results."),
|
|
130539
|
-
sort: z.string().optional().describe('Sort order specification (e.g., "LastUpdateDate:desc", "EnrollmentCount").')
|
|
131039
|
+
sort: z.string().optional().describe('Sort order specification (e.g., "LastUpdateDate:desc", "EnrollmentCount").'),
|
|
131040
|
+
fields: z.array(z.string()).optional().describe('Specific fields to return (reduces payload size). Example: ["NCTId", "BriefTitle", "OverallStatus"].'),
|
|
131041
|
+
country: z.string().optional().describe('Filter studies by country (e.g., "United States", "Canada").'),
|
|
131042
|
+
state: z.string().optional().describe('Filter studies by state or province (e.g., "California", "Ontario").'),
|
|
131043
|
+
city: z.string().optional().describe('Filter studies by city (e.g., "New York", "Toronto").')
|
|
130540
131044
|
}).describe("Input parameters for searching clinical trial studies.");
|
|
130541
|
-
var
|
|
131045
|
+
var OutputSchema4 = z.object({
|
|
130542
131046
|
pagedStudies: PagedStudiesSchema
|
|
130543
131047
|
});
|
|
130544
131048
|
async function searchStudiesLogic(input, appContext, _sdkContext) {
|
|
@@ -130546,13 +131050,17 @@ async function searchStudiesLogic(input, appContext, _sdkContext) {
|
|
|
130546
131050
|
...appContext,
|
|
130547
131051
|
toolInput: input
|
|
130548
131052
|
});
|
|
130549
|
-
const provider =
|
|
131053
|
+
const provider = import_tsyringe14.container.resolve(ClinicalTrialsProvider);
|
|
130550
131054
|
const pagedStudies = await provider.listStudies({
|
|
130551
131055
|
...input.query && { query: input.query },
|
|
130552
131056
|
...input.filter && { filter: input.filter },
|
|
130553
131057
|
pageSize: input.pageSize,
|
|
130554
131058
|
...input.pageToken && { pageToken: input.pageToken },
|
|
130555
|
-
...input.sort && { sort: input.sort }
|
|
131059
|
+
...input.sort && { sort: input.sort },
|
|
131060
|
+
...input.fields && { fields: input.fields },
|
|
131061
|
+
...input.country && { country: input.country },
|
|
131062
|
+
...input.state && { state: input.state },
|
|
131063
|
+
...input.city && { city: input.city }
|
|
130556
131064
|
}, appContext);
|
|
130557
131065
|
logger.info(`Successfully searched studies: ${pagedStudies.studies?.length ?? 0} results`, {
|
|
130558
131066
|
...appContext,
|
|
@@ -130560,7 +131068,7 @@ async function searchStudiesLogic(input, appContext, _sdkContext) {
|
|
|
130560
131068
|
});
|
|
130561
131069
|
return { pagedStudies };
|
|
130562
131070
|
}
|
|
130563
|
-
function
|
|
131071
|
+
function responseFormatter4(result) {
|
|
130564
131072
|
const { pagedStudies } = result;
|
|
130565
131073
|
const studyCount = pagedStudies.studies?.length ?? 0;
|
|
130566
131074
|
const totalCount = pagedStudies.totalCount;
|
|
@@ -130593,19 +131101,20 @@ ${studyList}${moreStudies}${pagination}`
|
|
|
130593
131101
|
];
|
|
130594
131102
|
}
|
|
130595
131103
|
var searchStudiesTool = {
|
|
130596
|
-
name:
|
|
130597
|
-
title:
|
|
130598
|
-
description:
|
|
130599
|
-
inputSchema:
|
|
130600
|
-
outputSchema:
|
|
130601
|
-
annotations:
|
|
131104
|
+
name: TOOL_NAME4,
|
|
131105
|
+
title: TOOL_TITLE4,
|
|
131106
|
+
description: TOOL_DESCRIPTION4,
|
|
131107
|
+
inputSchema: InputSchema4,
|
|
131108
|
+
outputSchema: OutputSchema4,
|
|
131109
|
+
annotations: TOOL_ANNOTATIONS4,
|
|
130602
131110
|
logic: withToolAuth(["tool:clinicaltrials:read"], searchStudiesLogic),
|
|
130603
|
-
responseFormatter:
|
|
131111
|
+
responseFormatter: responseFormatter4
|
|
130604
131112
|
};
|
|
130605
131113
|
|
|
130606
131114
|
// src/mcp-server/tools/definitions/index.ts
|
|
130607
131115
|
var allToolDefinitions = [
|
|
130608
131116
|
analyzeTrendsTool,
|
|
131117
|
+
compareStudiesTool,
|
|
130609
131118
|
getStudyTool,
|
|
130610
131119
|
searchStudiesTool
|
|
130611
131120
|
];
|
|
@@ -130617,7 +131126,7 @@ var defaultResponseFormatter2 = (result) => [
|
|
|
130617
131126
|
function createMcpToolHandler({
|
|
130618
131127
|
toolName,
|
|
130619
131128
|
logic,
|
|
130620
|
-
responseFormatter:
|
|
131129
|
+
responseFormatter: responseFormatter5 = defaultResponseFormatter2
|
|
130621
131130
|
}) {
|
|
130622
131131
|
return async (input, callContext) => {
|
|
130623
131132
|
const sdkContext = callContext;
|
|
@@ -130634,7 +131143,7 @@ function createMcpToolHandler({
|
|
|
130634
131143
|
const result = await measureToolExecution(() => logic(input, appContext, sdkContext), { ...appContext, toolName }, input);
|
|
130635
131144
|
return {
|
|
130636
131145
|
structuredContent: result,
|
|
130637
|
-
content:
|
|
131146
|
+
content: responseFormatter5(result)
|
|
130638
131147
|
};
|
|
130639
131148
|
} catch (error2) {
|
|
130640
131149
|
const mcpError = ErrorHandler.handleError(error2, {
|
|
@@ -130705,15 +131214,15 @@ class ToolRegistry {
|
|
|
130705
131214
|
}
|
|
130706
131215
|
}
|
|
130707
131216
|
ToolRegistry = __legacyDecorateClassTS([
|
|
130708
|
-
|
|
130709
|
-
__legacyDecorateParamTS(0,
|
|
131217
|
+
import_tsyringe15.injectable(),
|
|
131218
|
+
__legacyDecorateParamTS(0, import_tsyringe15.injectAll(ToolDefinitions)),
|
|
130710
131219
|
__legacyMetadataTS("design:paramtypes", [
|
|
130711
131220
|
Array
|
|
130712
131221
|
])
|
|
130713
131222
|
], ToolRegistry);
|
|
130714
|
-
var registerTools = (
|
|
131223
|
+
var registerTools = (container7) => {
|
|
130715
131224
|
for (const tool of allToolDefinitions) {
|
|
130716
|
-
|
|
131225
|
+
container7.register(ToolDefinitions, { useValue: tool });
|
|
130717
131226
|
}
|
|
130718
131227
|
};
|
|
130719
131228
|
|
|
@@ -130745,9 +131254,9 @@ async function createMcpServerInstance() {
|
|
|
130745
131254
|
});
|
|
130746
131255
|
try {
|
|
130747
131256
|
logger.debug("Registering all MCP capabilities via registries...", context);
|
|
130748
|
-
const toolRegistry =
|
|
131257
|
+
const toolRegistry = import_tsyringe16.container.resolve(ToolRegistry);
|
|
130749
131258
|
await toolRegistry.registerAll(server);
|
|
130750
|
-
const resourceRegistry =
|
|
131259
|
+
const resourceRegistry = import_tsyringe16.container.resolve(ResourceRegistry);
|
|
130751
131260
|
await resourceRegistry.registerAll(server);
|
|
130752
131261
|
logger.info("All MCP capabilities registered successfully", context);
|
|
130753
131262
|
} catch (err) {
|
|
@@ -130762,7 +131271,7 @@ async function createMcpServerInstance() {
|
|
|
130762
131271
|
}
|
|
130763
131272
|
|
|
130764
131273
|
// src/mcp-server/transports/manager.ts
|
|
130765
|
-
var
|
|
131274
|
+
var import_tsyringe20 = __toESM(require_cjs3(), 1);
|
|
130766
131275
|
|
|
130767
131276
|
// node_modules/hono/dist/http-exception.js
|
|
130768
131277
|
var HTTPException = class extends Error {
|
|
@@ -133430,7 +133939,7 @@ var cors = (options) => {
|
|
|
133430
133939
|
import http from "http";
|
|
133431
133940
|
import { randomUUID } from "node:crypto";
|
|
133432
133941
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
133433
|
-
var
|
|
133942
|
+
var import_tsyringe19 = __toESM(require_cjs3(), 1);
|
|
133434
133943
|
|
|
133435
133944
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
133436
133945
|
var encoder = new TextEncoder;
|
|
@@ -134948,7 +135457,7 @@ function createRemoteJWKSet(url, options) {
|
|
|
134948
135457
|
return remoteJWKSet;
|
|
134949
135458
|
}
|
|
134950
135459
|
// src/mcp-server/transports/auth/strategies/jwtStrategy.ts
|
|
134951
|
-
var
|
|
135460
|
+
var import_tsyringe17 = __toESM(require_cjs3(), 1);
|
|
134952
135461
|
class JwtStrategy {
|
|
134953
135462
|
config;
|
|
134954
135463
|
logger;
|
|
@@ -135051,9 +135560,9 @@ class JwtStrategy {
|
|
|
135051
135560
|
}
|
|
135052
135561
|
}
|
|
135053
135562
|
JwtStrategy = __legacyDecorateClassTS([
|
|
135054
|
-
|
|
135055
|
-
__legacyDecorateParamTS(0,
|
|
135056
|
-
__legacyDecorateParamTS(1,
|
|
135563
|
+
import_tsyringe17.injectable(),
|
|
135564
|
+
__legacyDecorateParamTS(0, import_tsyringe17.inject(AppConfig)),
|
|
135565
|
+
__legacyDecorateParamTS(1, import_tsyringe17.inject(Logger2)),
|
|
135057
135566
|
__legacyMetadataTS("design:paramtypes", [
|
|
135058
135567
|
Object,
|
|
135059
135568
|
Object
|
|
@@ -135061,7 +135570,7 @@ JwtStrategy = __legacyDecorateClassTS([
|
|
|
135061
135570
|
], JwtStrategy);
|
|
135062
135571
|
|
|
135063
135572
|
// src/mcp-server/transports/auth/strategies/oauthStrategy.ts
|
|
135064
|
-
var
|
|
135573
|
+
var import_tsyringe18 = __toESM(require_cjs3(), 1);
|
|
135065
135574
|
class OauthStrategy {
|
|
135066
135575
|
config;
|
|
135067
135576
|
logger;
|
|
@@ -135178,9 +135687,9 @@ class OauthStrategy {
|
|
|
135178
135687
|
}
|
|
135179
135688
|
}
|
|
135180
135689
|
OauthStrategy = __legacyDecorateClassTS([
|
|
135181
|
-
|
|
135182
|
-
__legacyDecorateParamTS(0,
|
|
135183
|
-
__legacyDecorateParamTS(1,
|
|
135690
|
+
import_tsyringe18.injectable(),
|
|
135691
|
+
__legacyDecorateParamTS(0, import_tsyringe18.inject(AppConfig)),
|
|
135692
|
+
__legacyDecorateParamTS(1, import_tsyringe18.inject(Logger2)),
|
|
135184
135693
|
__legacyMetadataTS("design:paramtypes", [
|
|
135185
135694
|
Object,
|
|
135186
135695
|
Object
|
|
@@ -135188,8 +135697,8 @@ OauthStrategy = __legacyDecorateClassTS([
|
|
|
135188
135697
|
], OauthStrategy);
|
|
135189
135698
|
|
|
135190
135699
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
135191
|
-
|
|
135192
|
-
|
|
135700
|
+
import_tsyringe19.container.register(JwtStrategy, { useClass: JwtStrategy });
|
|
135701
|
+
import_tsyringe19.container.register(OauthStrategy, { useClass: OauthStrategy });
|
|
135193
135702
|
function createAuthStrategy() {
|
|
135194
135703
|
const context = requestContextService.createRequestContext({
|
|
135195
135704
|
operation: "createAuthStrategy",
|
|
@@ -135199,10 +135708,10 @@ function createAuthStrategy() {
|
|
|
135199
135708
|
switch (config.mcpAuthMode) {
|
|
135200
135709
|
case "jwt":
|
|
135201
135710
|
logger.debug("Resolving JWT strategy from container.", context);
|
|
135202
|
-
return
|
|
135711
|
+
return import_tsyringe19.container.resolve(JwtStrategy);
|
|
135203
135712
|
case "oauth":
|
|
135204
135713
|
logger.debug("Resolving OAuth strategy from container.", context);
|
|
135205
|
-
return
|
|
135714
|
+
return import_tsyringe19.container.resolve(OauthStrategy);
|
|
135206
135715
|
case "none":
|
|
135207
135716
|
logger.info("Authentication is disabled ('none' mode).", context);
|
|
135208
135717
|
return null;
|
|
@@ -135716,10 +136225,10 @@ class TransportManager {
|
|
|
135716
136225
|
}
|
|
135717
136226
|
}
|
|
135718
136227
|
TransportManager = __legacyDecorateClassTS([
|
|
135719
|
-
|
|
135720
|
-
__legacyDecorateParamTS(0,
|
|
135721
|
-
__legacyDecorateParamTS(1,
|
|
135722
|
-
__legacyDecorateParamTS(2,
|
|
136228
|
+
import_tsyringe20.injectable(),
|
|
136229
|
+
__legacyDecorateParamTS(0, import_tsyringe20.inject(AppConfig)),
|
|
136230
|
+
__legacyDecorateParamTS(1, import_tsyringe20.inject(Logger2)),
|
|
136231
|
+
__legacyDecorateParamTS(2, import_tsyringe20.inject(CreateMcpServerInstance)),
|
|
135723
136232
|
__legacyMetadataTS("design:paramtypes", [
|
|
135724
136233
|
typeof AppConfigType === "undefined" ? Object : AppConfigType,
|
|
135725
136234
|
Object,
|
|
@@ -135729,14 +136238,14 @@ TransportManager = __legacyDecorateClassTS([
|
|
|
135729
136238
|
|
|
135730
136239
|
// src/container/registrations/mcp.ts
|
|
135731
136240
|
var registerMcpServices = () => {
|
|
135732
|
-
|
|
135733
|
-
|
|
135734
|
-
registerTools(
|
|
135735
|
-
registerResources(
|
|
135736
|
-
|
|
136241
|
+
import_tsyringe21.container.registerSingleton(ToolRegistry);
|
|
136242
|
+
import_tsyringe21.container.registerSingleton(ResourceRegistry);
|
|
136243
|
+
registerTools(import_tsyringe21.container);
|
|
136244
|
+
registerResources(import_tsyringe21.container);
|
|
136245
|
+
import_tsyringe21.container.register(CreateMcpServerInstance, {
|
|
135737
136246
|
useValue: createMcpServerInstance
|
|
135738
136247
|
});
|
|
135739
|
-
|
|
136248
|
+
import_tsyringe21.container.registerSingleton(TransportManagerToken, TransportManager);
|
|
135740
136249
|
logger.info("MCP services and factories registered with the DI container.");
|
|
135741
136250
|
};
|
|
135742
136251
|
|
|
@@ -135750,7 +136259,7 @@ function composeContainer() {
|
|
|
135750
136259
|
registerMcpServices();
|
|
135751
136260
|
isContainerComposed = true;
|
|
135752
136261
|
}
|
|
135753
|
-
var container_default =
|
|
136262
|
+
var container_default = import_tsyringe22.container;
|
|
135754
136263
|
|
|
135755
136264
|
// src/index.ts
|
|
135756
136265
|
var config2;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clinicaltrialsgov-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"mcpName": "io.github.cyanheads/clinicaltrialsgov-mcp-server",
|
|
5
5
|
"description": "ClinicalTrials.gov Model Context Protocol (MCP) Server that provides a suite of tools for interacting with the official ClinicalTrials.gov v2 API. Enables AI agents and LLMs to programmatically search, retrieve, and analyze clinical trial data.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,9 +30,12 @@
|
|
|
30
30
|
"homepage": "https://github.com/cyanheads/clinicaltrialsgov-mcp-server#readme",
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "bun build ./src/index.ts --outdir ./dist --target node",
|
|
33
|
+
"build:worker": "bun build ./src/worker.ts --outdir ./dist --target bun --no-external",
|
|
34
|
+
"deploy:dev": "MCP_TRANSPORT_TYPE=http bunx wrangler dev",
|
|
35
|
+
"deploy:prod": "MCP_TRANSPORT_TYPE=http bunx wrangler deploy",
|
|
33
36
|
"start": "bun ./dist/index.js",
|
|
34
|
-
"start:stdio": "
|
|
35
|
-
"start:http": "
|
|
37
|
+
"start:stdio": "MCP_TRANSPORT_TYPE=stdio bun ./dist/index.js",
|
|
38
|
+
"start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js",
|
|
36
39
|
"dev": "bun --watch src/index.ts",
|
|
37
40
|
"dev:stdio": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
|
|
38
41
|
"dev:http": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
|
|
@@ -47,6 +50,7 @@
|
|
|
47
50
|
"tree": "bun run scripts/tree.ts",
|
|
48
51
|
"fetch-spec": "bun run scripts/fetch-openapi-spec.ts",
|
|
49
52
|
"format": "bun run prettier --write \"**/*.{ts,js,json,md,html,css}\"",
|
|
53
|
+
"prepare": "bunx husky",
|
|
50
54
|
"inspector": "bunx mcp-inspector --config mcp.json --server clinicaltrialsgov-mcp-server",
|
|
51
55
|
"db:duckdb-example": "MCP_LOG_LEVEL=debug tsc && node dist/storage/duckdbExample.js",
|
|
52
56
|
"test": "bun test --config vitest.config.ts",
|